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