]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/inet_net_pton.c
pgindent run on all C files. Java run to follow. initdb/regression
[postgresql] / src / backend / utils / adt / inet_net_pton.c
1 /*
2  * Copyright (c) 1996 by Internet Software Consortium.
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
9  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
10  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
11  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
13  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
14  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
15  * SOFTWARE.
16  */
17
18 #if defined(LIBC_SCCS) && !defined(lint)
19 static const char rcsid[] = "$Id: inet_net_pton.c,v 1.13 2001/10/25 05:49:44 momjian Exp $";
20 #endif
21
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26
27 #include <assert.h>
28 #include <ctype.h>
29 #include <errno.h>
30
31 #include "postgres.h"
32 #include "utils/builtins.h"
33
34 #ifdef SPRINTF_CHAR
35 #define SPRINTF(x) strlen(sprintf/**/x)
36 #else
37 #define SPRINTF(x) ((size_t)sprintf x)
38 #endif
39
40 static int      inet_net_pton_ipv4(const char *src, u_char *dst);
41 static int      inet_cidr_pton_ipv4(const char *src, u_char *dst, size_t size);
42
43 /*
44  * static int
45  * inet_net_pton(af, src, dst, size)
46  *      convert network number from presentation to network format.
47  *      accepts hex octets, hex strings, decimal octets, and /CIDR.
48  *      "size" is in bytes and describes "dst".
49  * return:
50  *      number of bits, either imputed classfully or specified with /CIDR,
51  *      or -1 if some failure occurred (check errno).  ENOENT means it was
52  *      not a valid network specification.
53  * author:
54  *      Paul Vixie (ISC), June 1996
55  *
56  * Changes:
57  *      I added the inet_cidr_pton function (also from Paul) and changed
58  *      the names to reflect their current use.
59  *
60  */
61 int
62 inet_net_pton(int af, const char *src, void *dst, size_t size)
63 {
64         switch (af)
65         {
66                 case AF_INET:
67                         return size == -1 ?
68                                 inet_net_pton_ipv4(src, dst) :
69                                 inet_cidr_pton_ipv4(src, dst, size);
70                 default:
71                         errno = EAFNOSUPPORT;
72                         return (-1);
73         }
74 }
75
76 /*
77  * static int
78  * inet_cidr_pton_ipv4(src, dst, size)
79  *      convert IPv4 network number from presentation to network format.
80  *      accepts hex octets, hex strings, decimal octets, and /CIDR.
81  *      "size" is in bytes and describes "dst".
82  * return:
83  *      number of bits, either imputed classfully or specified with /CIDR,
84  *      or -1 if some failure occurred (check errno).  ENOENT means it was
85  *      not an IPv4 network specification.
86  * note:
87  *      network byte order assumed.  this means 192.5.5.240/28 has
88  *      0x11110000 in its fourth octet.
89  * author:
90  *      Paul Vixie (ISC), June 1996
91  */
92 static int
93 inet_cidr_pton_ipv4(const char *src, u_char *dst, size_t size)
94 {
95         static const char
96                                 xdigits[] = "0123456789abcdef",
97                                 digits[] = "0123456789";
98         int                     n,
99                                 ch,
100                                 tmp,
101                                 dirty,
102                                 bits;
103         const u_char *odst = dst;
104
105         ch = *src++;
106         if (ch == '0' && (src[0] == 'x' || src[0] == 'X')
107                 && isxdigit((unsigned char) src[1]))
108         {
109                 /* Hexadecimal: Eat nybble string. */
110                 if (size <= 0)
111                         goto emsgsize;
112                 dirty = 0;
113                 tmp = 0;
114                 src++;                                  /* skip x or X. */
115                 while ((ch = *src++) != '\0' && isxdigit((unsigned char) ch))
116                 {
117                         if (isupper((unsigned char) ch))
118                                 ch = tolower((unsigned char) ch);
119                         n = strchr(xdigits, ch) - xdigits;
120                         assert(n >= 0 && n <= 15);
121                         if (dirty == 0)
122                                 tmp = n;
123                         else
124                                 tmp = (tmp << 4) | n;
125                         if (++dirty == 2)
126                         {
127                                 if (size-- <= 0)
128                                         goto emsgsize;
129                                 *dst++ = (u_char) tmp;
130                                 dirty = 0;
131                         }
132                 }
133                 if (dirty)
134                 {                                               /* Odd trailing nybble? */
135                         if (size-- <= 0)
136                                 goto emsgsize;
137                         *dst++ = (u_char) (tmp << 4);
138                 }
139         }
140         else if (isdigit((unsigned char) ch))
141         {
142                 /* Decimal: eat dotted digit string. */
143                 for (;;)
144                 {
145                         tmp = 0;
146                         do
147                         {
148                                 n = strchr(digits, ch) - digits;
149                                 assert(n >= 0 && n <= 9);
150                                 tmp *= 10;
151                                 tmp += n;
152                                 if (tmp > 255)
153                                         goto enoent;
154                         } while ((ch = *src++) != '\0' &&
155                                          isdigit((unsigned char) ch));
156                         if (size-- <= 0)
157                                 goto emsgsize;
158                         *dst++ = (u_char) tmp;
159                         if (ch == '\0' || ch == '/')
160                                 break;
161                         if (ch != '.')
162                                 goto enoent;
163                         ch = *src++;
164                         if (!isdigit((unsigned char) ch))
165                                 goto enoent;
166                 }
167         }
168         else
169                 goto enoent;
170
171         bits = -1;
172         if (ch == '/' && isdigit((unsigned char) src[0]) && dst > odst)
173         {
174                 /* CIDR width specifier.  Nothing can follow it. */
175                 ch = *src++;                    /* Skip over the /. */
176                 bits = 0;
177                 do
178                 {
179                         n = strchr(digits, ch) - digits;
180                         assert(n >= 0 && n <= 9);
181                         bits *= 10;
182                         bits += n;
183                 } while ((ch = *src++) != '\0' && isdigit((unsigned char) ch));
184                 if (ch != '\0')
185                         goto enoent;
186                 if (bits > 32)
187                         goto emsgsize;
188         }
189
190         /* Firey death and destruction unless we prefetched EOS. */
191         if (ch != '\0')
192                 goto enoent;
193
194         /* If nothing was written to the destination, we found no address. */
195         if (dst == odst)
196                 goto enoent;
197         /* If no CIDR spec was given, infer width from net class. */
198         if (bits == -1)
199         {
200                 if (*odst >= 240)               /* Class E */
201                         bits = 32;
202                 else if (*odst >= 224)  /* Class D */
203                         bits = 4;
204                 else if (*odst >= 192)  /* Class C */
205                         bits = 24;
206                 else if (*odst >= 128)  /* Class B */
207                         bits = 16;
208                 else
209 /* Class A */
210                         bits = 8;
211                 /* If imputed mask is narrower than specified octets, widen. */
212                 if (bits >= 8 && bits < ((dst - odst) * 8))
213                         bits = (dst - odst) * 8;
214         }
215         /* Extend network to cover the actual mask. */
216         while (bits > ((dst - odst) * 8))
217         {
218                 if (size-- <= 0)
219                         goto emsgsize;
220                 *dst++ = '\0';
221         }
222         return (bits);
223
224 enoent:
225         errno = ENOENT;
226         return (-1);
227
228 emsgsize:
229         errno = EMSGSIZE;
230         return (-1);
231 }
232
233 /*
234  * int
235  * inet_net_pton(af, src, dst, *bits)
236  *      convert network address from presentation to network format.
237  *      accepts inet_pton()'s input for this "af" plus trailing "/CIDR".
238  *      "dst" is assumed large enough for its "af".  "bits" is set to the
239  *      /CIDR prefix length, which can have defaults (like /32 for IPv4).
240  * return:
241  *      -1 if an error occurred (inspect errno; ENOENT means bad format).
242  *      0 if successful conversion occurred.
243  * note:
244  *      192.5.5.1/28 has a nonzero host part, which means it isn't a network
245  *      as called for by inet_cidr_pton() but it can be a host address with
246  *      an included netmask.
247  * author:
248  *      Paul Vixie (ISC), October 1998
249  */
250 static int
251 inet_net_pton_ipv4(const char *src, u_char *dst)
252 {
253         static const char digits[] = "0123456789";
254         const u_char *odst = dst;
255         int                     n,
256                                 ch,
257                                 tmp,
258                                 bits;
259         size_t          size = 4;
260
261         /* Get the mantissa. */
262         while (ch = *src++, isdigit((unsigned char) ch))
263         {
264                 tmp = 0;
265                 do
266                 {
267                         n = strchr(digits, ch) - digits;
268                         assert(n >= 0 && n <= 9);
269                         tmp *= 10;
270                         tmp += n;
271                         if (tmp > 255)
272                                 goto enoent;
273                 } while ((ch = *src++) != '\0' && isdigit((unsigned char) ch));
274                 if (size-- == 0)
275                         goto emsgsize;
276                 *dst++ = (u_char) tmp;
277                 if (ch == '\0' || ch == '/')
278                         break;
279                 if (ch != '.')
280                         goto enoent;
281         }
282
283         /* Get the prefix length if any. */
284         bits = -1;
285         if (ch == '/' && isdigit((unsigned char) src[0]) && dst > odst)
286         {
287                 /* CIDR width specifier.  Nothing can follow it. */
288                 ch = *src++;                    /* Skip over the /. */
289                 bits = 0;
290                 do
291                 {
292                         n = strchr(digits, ch) - digits;
293                         assert(n >= 0 && n <= 9);
294                         bits *= 10;
295                         bits += n;
296                 } while ((ch = *src++) != '\0' && isdigit((unsigned char) ch));
297                 if (ch != '\0')
298                         goto enoent;
299                 if (bits > 32)
300                         goto emsgsize;
301         }
302
303         /* Firey death and destruction unless we prefetched EOS. */
304         if (ch != '\0')
305                 goto enoent;
306
307         /* Prefix length can default to /32 only if all four octets spec'd. */
308         if (bits == -1)
309         {
310                 if (dst - odst == 4)
311                         bits = 32;
312                 else
313                         goto enoent;
314         }
315
316         /* If nothing was written to the destination, we found no address. */
317         if (dst == odst)
318                 goto enoent;
319
320         /* If prefix length overspecifies mantissa, life is bad. */
321         if ((bits / 8) > (dst - odst))
322                 goto enoent;
323
324         /* Extend address to four octets. */
325         while (size-- > 0)
326                 *dst++ = 0;
327
328         return bits;
329
330 enoent:
331         errno = ENOENT;
332         return (-1);
333
334 emsgsize:
335         errno = EMSGSIZE;
336         return (-1);
337 }