]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/inet_net_pton.c
Add support for EUI-64 MAC addresses as macaddr8
[postgresql] / src / backend / utils / adt / inet_net_pton.c
1 /*
2  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (c) 1996,1999 by Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  *
17  *        src/backend/utils/adt/inet_net_pton.c
18  */
19
20 #if defined(LIBC_SCCS) && !defined(lint)
21 static const char rcsid[] = "Id: inet_net_pton.c,v 1.4.2.3 2004/03/17 00:40:11 marka Exp $";
22 #endif
23
24 #include "postgres.h"
25
26 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
29 #include <assert.h>
30 #include <ctype.h>
31
32 #include "utils/builtins.h" /* pgrminclude ignore */    /* needed on some
33                                                                                                                  * platforms */
34 #include "utils/inet.h"
35
36
37 static int      inet_net_pton_ipv4(const char *src, u_char *dst);
38 static int      inet_cidr_pton_ipv4(const char *src, u_char *dst, size_t size);
39 static int      inet_net_pton_ipv6(const char *src, u_char *dst);
40 static int      inet_cidr_pton_ipv6(const char *src, u_char *dst, size_t size);
41
42
43 /*
44  * 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 PGSQL_AF_INET:
67                         return size == -1 ?
68                                 inet_net_pton_ipv4(src, dst) :
69                                 inet_cidr_pton_ipv4(src, dst, size);
70                 case PGSQL_AF_INET6:
71                         return size == -1 ?
72                                 inet_net_pton_ipv6(src, dst) :
73                                 inet_cidr_pton_ipv6(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  *      0b11110000 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 xdigits[] = "0123456789abcdef";
100         static const char digits[] = "0123456789";
101         int                     n,
102                                 ch,
103                                 tmp = 0,
104                                 dirty,
105                                 bits;
106         const u_char *odst = dst;
107
108         ch = *src++;
109         if (ch == '0' && (src[0] == 'x' || src[0] == 'X')
110                 && isxdigit((unsigned char) src[1]))
111         {
112                 /* Hexadecimal: Eat nybble string. */
113                 if (size <= 0U)
114                         goto emsgsize;
115                 dirty = 0;
116                 src++;                                  /* skip x or X. */
117                 while ((ch = *src++) != '\0' && isxdigit((unsigned char) ch))
118                 {
119                         if (isupper((unsigned char) ch))
120                                 ch = tolower((unsigned char) ch);
121                         n = strchr(xdigits, ch) - xdigits;
122                         assert(n >= 0 && n <= 15);
123                         if (dirty == 0)
124                                 tmp = n;
125                         else
126                                 tmp = (tmp << 4) | n;
127                         if (++dirty == 2)
128                         {
129                                 if (size-- <= 0U)
130                                         goto emsgsize;
131                                 *dst++ = (u_char) tmp;
132                                 dirty = 0;
133                         }
134                 }
135                 if (dirty)
136                 {                                               /* Odd trailing nybble? */
137                         if (size-- <= 0U)
138                                 goto emsgsize;
139                         *dst++ = (u_char) (tmp << 4);
140                 }
141         }
142         else if (isdigit((unsigned char) ch))
143         {
144                 /* Decimal: eat dotted digit string. */
145                 for (;;)
146                 {
147                         tmp = 0;
148                         do
149                         {
150                                 n = strchr(digits, ch) - digits;
151                                 assert(n >= 0 && n <= 9);
152                                 tmp *= 10;
153                                 tmp += n;
154                                 if (tmp > 255)
155                                         goto enoent;
156                         } while ((ch = *src++) != '\0' &&
157                                          isdigit((unsigned char) ch));
158                         if (size-- <= 0U)
159                                 goto emsgsize;
160                         *dst++ = (u_char) tmp;
161                         if (ch == '\0' || ch == '/')
162                                 break;
163                         if (ch != '.')
164                                 goto enoent;
165                         ch = *src++;
166                         if (!isdigit((unsigned char) ch))
167                                 goto enoent;
168                 }
169         }
170         else
171                 goto enoent;
172
173         bits = -1;
174         if (ch == '/' && isdigit((unsigned char) src[0]) && dst > odst)
175         {
176                 /* CIDR width specifier.  Nothing can follow it. */
177                 ch = *src++;                    /* Skip over the /. */
178                 bits = 0;
179                 do
180                 {
181                         n = strchr(digits, ch) - digits;
182                         assert(n >= 0 && n <= 9);
183                         bits *= 10;
184                         bits += n;
185                 } while ((ch = *src++) != '\0' && isdigit((unsigned char) ch));
186                 if (ch != '\0')
187                         goto enoent;
188                 if (bits > 32)
189                         goto emsgsize;
190         }
191
192         /* Firey death and destruction unless we prefetched EOS. */
193         if (ch != '\0')
194                 goto enoent;
195
196         /* If nothing was written to the destination, we found no address. */
197         if (dst == odst)
198                 goto enoent;
199         /* If no CIDR spec was given, infer width from net class. */
200         if (bits == -1)
201         {
202                 if (*odst >= 240)               /* Class E */
203                         bits = 32;
204                 else if (*odst >= 224)  /* Class D */
205                         bits = 8;
206                 else if (*odst >= 192)  /* Class C */
207                         bits = 24;
208                 else if (*odst >= 128)  /* Class B */
209                         bits = 16;
210                 else
211                         /* Class A */
212                         bits = 8;
213                 /* If imputed mask is narrower than specified octets, widen. */
214                 if (bits < ((dst - odst) * 8))
215                         bits = (dst - odst) * 8;
216
217                 /*
218                  * If there are no additional bits specified for a class D address
219                  * adjust bits to 4.
220                  */
221                 if (bits == 8 && *odst == 224)
222                         bits = 4;
223         }
224         /* Extend network to cover the actual mask. */
225         while (bits > ((dst - odst) * 8))
226         {
227                 if (size-- <= 0U)
228                         goto emsgsize;
229                 *dst++ = '\0';
230         }
231         return (bits);
232
233 enoent:
234         errno = ENOENT;
235         return (-1);
236
237 emsgsize:
238         errno = EMSGSIZE;
239         return (-1);
240 }
241
242 /*
243  * int
244  * inet_net_pton(af, src, dst, *bits)
245  *      convert network address from presentation to network format.
246  *      accepts inet_pton()'s input for this "af" plus trailing "/CIDR".
247  *      "dst" is assumed large enough for its "af".  "bits" is set to the
248  *      /CIDR prefix length, which can have defaults (like /32 for IPv4).
249  * return:
250  *      -1 if an error occurred (inspect errno; ENOENT means bad format).
251  *      0 if successful conversion occurred.
252  * note:
253  *      192.5.5.1/28 has a nonzero host part, which means it isn't a network
254  *      as called for by inet_cidr_pton() but it can be a host address with
255  *      an included netmask.
256  * author:
257  *      Paul Vixie (ISC), October 1998
258  */
259 static int
260 inet_net_pton_ipv4(const char *src, u_char *dst)
261 {
262         static const char digits[] = "0123456789";
263         const u_char *odst = dst;
264         int                     n,
265                                 ch,
266                                 tmp,
267                                 bits;
268         size_t          size = 4;
269
270         /* Get the mantissa. */
271         while (ch = *src++, isdigit((unsigned char) ch))
272         {
273                 tmp = 0;
274                 do
275                 {
276                         n = strchr(digits, ch) - digits;
277                         assert(n >= 0 && n <= 9);
278                         tmp *= 10;
279                         tmp += n;
280                         if (tmp > 255)
281                                 goto enoent;
282                 } while ((ch = *src++) != '\0' && isdigit((unsigned char) ch));
283                 if (size-- == 0)
284                         goto emsgsize;
285                 *dst++ = (u_char) tmp;
286                 if (ch == '\0' || ch == '/')
287                         break;
288                 if (ch != '.')
289                         goto enoent;
290         }
291
292         /* Get the prefix length if any. */
293         bits = -1;
294         if (ch == '/' && isdigit((unsigned char) src[0]) && dst > odst)
295         {
296                 /* CIDR width specifier.  Nothing can follow it. */
297                 ch = *src++;                    /* Skip over the /. */
298                 bits = 0;
299                 do
300                 {
301                         n = strchr(digits, ch) - digits;
302                         assert(n >= 0 && n <= 9);
303                         bits *= 10;
304                         bits += n;
305                 } while ((ch = *src++) != '\0' && isdigit((unsigned char) ch));
306                 if (ch != '\0')
307                         goto enoent;
308                 if (bits > 32)
309                         goto emsgsize;
310         }
311
312         /* Firey death and destruction unless we prefetched EOS. */
313         if (ch != '\0')
314                 goto enoent;
315
316         /* Prefix length can default to /32 only if all four octets spec'd. */
317         if (bits == -1)
318         {
319                 if (dst - odst == 4)
320                         bits = 32;
321                 else
322                         goto enoent;
323         }
324
325         /* If nothing was written to the destination, we found no address. */
326         if (dst == odst)
327                 goto enoent;
328
329         /* If prefix length overspecifies mantissa, life is bad. */
330         if ((bits / 8) > (dst - odst))
331                 goto enoent;
332
333         /* Extend address to four octets. */
334         while (size-- > 0)
335                 *dst++ = 0;
336
337         return bits;
338
339 enoent:
340         errno = ENOENT;
341         return (-1);
342
343 emsgsize:
344         errno = EMSGSIZE;
345         return (-1);
346 }
347
348 static int
349 getbits(const char *src, int *bitsp)
350 {
351         static const char digits[] = "0123456789";
352         int                     n;
353         int                     val;
354         char            ch;
355
356         val = 0;
357         n = 0;
358         while ((ch = *src++) != '\0')
359         {
360                 const char *pch;
361
362                 pch = strchr(digits, ch);
363                 if (pch != NULL)
364                 {
365                         if (n++ != 0 && val == 0)       /* no leading zeros */
366                                 return (0);
367                         val *= 10;
368                         val += (pch - digits);
369                         if (val > 128)          /* range */
370                                 return (0);
371                         continue;
372                 }
373                 return (0);
374         }
375         if (n == 0)
376                 return (0);
377         *bitsp = val;
378         return (1);
379 }
380
381 static int
382 getv4(const char *src, u_char *dst, int *bitsp)
383 {
384         static const char digits[] = "0123456789";
385         u_char     *odst = dst;
386         int                     n;
387         u_int           val;
388         char            ch;
389
390         val = 0;
391         n = 0;
392         while ((ch = *src++) != '\0')
393         {
394                 const char *pch;
395
396                 pch = strchr(digits, ch);
397                 if (pch != NULL)
398                 {
399                         if (n++ != 0 && val == 0)       /* no leading zeros */
400                                 return (0);
401                         val *= 10;
402                         val += (pch - digits);
403                         if (val > 255)          /* range */
404                                 return (0);
405                         continue;
406                 }
407                 if (ch == '.' || ch == '/')
408                 {
409                         if (dst - odst > 3) /* too many octets? */
410                                 return (0);
411                         *dst++ = val;
412                         if (ch == '/')
413                                 return (getbits(src, bitsp));
414                         val = 0;
415                         n = 0;
416                         continue;
417                 }
418                 return (0);
419         }
420         if (n == 0)
421                 return (0);
422         if (dst - odst > 3)                     /* too many octets? */
423                 return (0);
424         *dst++ = val;
425         return (1);
426 }
427
428 static int
429 inet_net_pton_ipv6(const char *src, u_char *dst)
430 {
431         return inet_cidr_pton_ipv6(src, dst, 16);
432 }
433
434 #define NS_IN6ADDRSZ 16
435 #define NS_INT16SZ 2
436 #define NS_INADDRSZ 4
437
438 static int
439 inet_cidr_pton_ipv6(const char *src, u_char *dst, size_t size)
440 {
441         static const char xdigits_l[] = "0123456789abcdef",
442                                 xdigits_u[] = "0123456789ABCDEF";
443         u_char          tmp[NS_IN6ADDRSZ],
444                            *tp,
445                            *endp,
446                            *colonp;
447         const char *xdigits,
448                            *curtok;
449         int                     ch,
450                                 saw_xdigit;
451         u_int           val;
452         int                     digits;
453         int                     bits;
454
455         if (size < NS_IN6ADDRSZ)
456                 goto emsgsize;
457
458         memset((tp = tmp), '\0', NS_IN6ADDRSZ);
459         endp = tp + NS_IN6ADDRSZ;
460         colonp = NULL;
461         /* Leading :: requires some special handling. */
462         if (*src == ':')
463                 if (*++src != ':')
464                         goto enoent;
465         curtok = src;
466         saw_xdigit = 0;
467         val = 0;
468         digits = 0;
469         bits = -1;
470         while ((ch = *src++) != '\0')
471         {
472                 const char *pch;
473
474                 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
475                         pch = strchr((xdigits = xdigits_u), ch);
476                 if (pch != NULL)
477                 {
478                         val <<= 4;
479                         val |= (pch - xdigits);
480                         if (++digits > 4)
481                                 goto enoent;
482                         saw_xdigit = 1;
483                         continue;
484                 }
485                 if (ch == ':')
486                 {
487                         curtok = src;
488                         if (!saw_xdigit)
489                         {
490                                 if (colonp)
491                                         goto enoent;
492                                 colonp = tp;
493                                 continue;
494                         }
495                         else if (*src == '\0')
496                                 goto enoent;
497                         if (tp + NS_INT16SZ > endp)
498                                 goto enoent;
499                         *tp++ = (u_char) (val >> 8) & 0xff;
500                         *tp++ = (u_char) val & 0xff;
501                         saw_xdigit = 0;
502                         digits = 0;
503                         val = 0;
504                         continue;
505                 }
506                 if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
507                         getv4(curtok, tp, &bits) > 0)
508                 {
509                         tp += NS_INADDRSZ;
510                         saw_xdigit = 0;
511                         break;                          /* '\0' was seen by inet_pton4(). */
512                 }
513                 if (ch == '/' && getbits(src, &bits) > 0)
514                         break;
515                 goto enoent;
516         }
517         if (saw_xdigit)
518         {
519                 if (tp + NS_INT16SZ > endp)
520                         goto enoent;
521                 *tp++ = (u_char) (val >> 8) & 0xff;
522                 *tp++ = (u_char) val & 0xff;
523         }
524         if (bits == -1)
525                 bits = 128;
526
527         endp = tmp + 16;
528
529         if (colonp != NULL)
530         {
531                 /*
532                  * Since some memmove()'s erroneously fail to handle overlapping
533                  * regions, we'll do the shift by hand.
534                  */
535                 const int       n = tp - colonp;
536                 int                     i;
537
538                 if (tp == endp)
539                         goto enoent;
540                 for (i = 1; i <= n; i++)
541                 {
542                         endp[-i] = colonp[n - i];
543                         colonp[n - i] = 0;
544                 }
545                 tp = endp;
546         }
547         if (tp != endp)
548                 goto enoent;
549
550         /*
551          * Copy out the result.
552          */
553         memcpy(dst, tmp, NS_IN6ADDRSZ);
554
555         return (bits);
556
557 enoent:
558         errno = ENOENT;
559         return (-1);
560
561 emsgsize:
562         errno = EMSGSIZE;
563         return (-1);
564 }