LCOV - code coverage report
Current view: top level - src/backend/utils/adt - inet_net_pton.c (source / functions) Hit Total Coverage
Test: PostgreSQL 12beta2 Lines: 188 263 71.5 %
Date: 2019-06-19 14:06:47 Functions: 6 7 85.7 %
Legend: Lines: hit not hit

          Line data    Source code
       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        2708 :     switch (af)
      65             :     {
      66             :         case PGSQL_AF_INET:
      67             :             return size == -1 ?
      68        2340 :                 inet_net_pton_ipv4(src, dst) :
      69             :                 inet_cidr_pton_ipv4(src, dst, size);
      70             :         case PGSQL_AF_INET6:
      71             :             return size == -1 ?
      72         368 :                 inet_net_pton_ipv6(src, dst) :
      73             :                 inet_cidr_pton_ipv6(src, dst, size);
      74             :         default:
      75           0 :             errno = EAFNOSUPPORT;
      76           0 :             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         558 : 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         558 :                 tmp = 0,
     104             :                 dirty,
     105             :                 bits;
     106         558 :     const u_char *odst = dst;
     107             : 
     108         558 :     ch = *src++;
     109         558 :     if (ch == '0' && (src[0] == 'x' || src[0] == 'X')
     110           0 :         && isxdigit((unsigned char) src[1]))
     111             :     {
     112             :         /* Hexadecimal: Eat nybble string. */
     113           0 :         if (size <= 0U)
     114           0 :             goto emsgsize;
     115           0 :         dirty = 0;
     116           0 :         src++;                  /* skip x or X. */
     117           0 :         while ((ch = *src++) != '\0' && isxdigit((unsigned char) ch))
     118             :         {
     119           0 :             if (isupper((unsigned char) ch))
     120           0 :                 ch = tolower((unsigned char) ch);
     121           0 :             n = strchr(xdigits, ch) - xdigits;
     122           0 :             assert(n >= 0 && n <= 15);
     123           0 :             if (dirty == 0)
     124           0 :                 tmp = n;
     125             :             else
     126           0 :                 tmp = (tmp << 4) | n;
     127           0 :             if (++dirty == 2)
     128             :             {
     129           0 :                 if (size-- <= 0U)
     130           0 :                     goto emsgsize;
     131           0 :                 *dst++ = (u_char) tmp;
     132           0 :                 dirty = 0;
     133             :             }
     134             :         }
     135           0 :         if (dirty)
     136             :         {                       /* Odd trailing nybble? */
     137           0 :             if (size-- <= 0U)
     138           0 :                 goto emsgsize;
     139           0 :             *dst++ = (u_char) (tmp << 4);
     140             :         }
     141             :     }
     142         558 :     else if (isdigit((unsigned char) ch))
     143             :     {
     144             :         /* Decimal: eat dotted digit string. */
     145             :         for (;;)
     146             :         {
     147        2970 :             tmp = 0;
     148             :             do
     149             :             {
     150        3356 :                 n = strchr(digits, ch) - digits;
     151        3356 :                 assert(n >= 0 && n <= 9);
     152        3356 :                 tmp *= 10;
     153        3356 :                 tmp += n;
     154        3356 :                 if (tmp > 255)
     155           0 :                     goto enoent;
     156        6496 :             } while ((ch = *src++) != '\0' &&
     157        3356 :                      isdigit((unsigned char) ch));
     158        1764 :             if (size-- <= 0U)
     159           0 :                 goto emsgsize;
     160        1764 :             *dst++ = (u_char) tmp;
     161        1764 :             if (ch == '\0' || ch == '/')
     162             :                 break;
     163        1206 :             if (ch != '.')
     164           0 :                 goto enoent;
     165        1206 :             ch = *src++;
     166        1206 :             if (!isdigit((unsigned char) ch))
     167           0 :                 goto enoent;
     168             :         }
     169             :     }
     170             :     else
     171           0 :         goto enoent;
     172             : 
     173         558 :     bits = -1;
     174         558 :     if (ch == '/' && isdigit((unsigned char) src[0]) && dst > odst)
     175             :     {
     176             :         /* CIDR width specifier.  Nothing can follow it. */
     177         342 :         ch = *src++;            /* Skip over the /. */
     178         342 :         bits = 0;
     179             :         do
     180             :         {
     181         588 :             n = strchr(digits, ch) - digits;
     182         588 :             assert(n >= 0 && n <= 9);
     183         588 :             bits *= 10;
     184         588 :             bits += n;
     185         588 :         } while ((ch = *src++) != '\0' && isdigit((unsigned char) ch));
     186         342 :         if (ch != '\0')
     187           0 :             goto enoent;
     188         342 :         if (bits > 32)
     189           0 :             goto emsgsize;
     190             :     }
     191             : 
     192             :     /* Fiery death and destruction unless we prefetched EOS. */
     193         558 :     if (ch != '\0')
     194           0 :         goto enoent;
     195             : 
     196             :     /* If nothing was written to the destination, we found no address. */
     197         558 :     if (dst == odst)
     198           0 :         goto enoent;
     199             :     /* If no CIDR spec was given, infer width from net class. */
     200         558 :     if (bits == -1)
     201             :     {
     202         216 :         if (*odst >= 240)        /* Class E */
     203          64 :             bits = 32;
     204         152 :         else if (*odst >= 224)   /* Class D */
     205           0 :             bits = 8;
     206         152 :         else if (*odst >= 192)   /* Class C */
     207          20 :             bits = 24;
     208         132 :         else if (*odst >= 128)   /* Class B */
     209           0 :             bits = 16;
     210             :         else
     211             :             /* Class A */
     212         132 :             bits = 8;
     213             :         /* If imputed mask is narrower than specified octets, widen. */
     214         216 :         if (bits < ((dst - odst) * 8))
     215         112 :             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         216 :         if (bits == 8 && *odst == 224)
     222           0 :             bits = 4;
     223             :     }
     224             :     /* Extend network to cover the actual mask. */
     225        1148 :     while (bits > ((dst - odst) * 8))
     226             :     {
     227          32 :         if (size-- <= 0U)
     228           0 :             goto emsgsize;
     229          32 :         *dst++ = '\0';
     230             :     }
     231         558 :     return bits;
     232             : 
     233             : enoent:
     234           0 :     errno = ENOENT;
     235           0 :     return -1;
     236             : 
     237             : emsgsize:
     238           0 :     errno = EMSGSIZE;
     239           0 :     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        1782 : inet_net_pton_ipv4(const char *src, u_char *dst)
     261             : {
     262             :     static const char digits[] = "0123456789";
     263        1782 :     const u_char *odst = dst;
     264             :     int         n,
     265             :                 ch,
     266             :                 tmp,
     267             :                 bits;
     268        1782 :     size_t      size = 4;
     269             : 
     270             :     /* Get the mantissa. */
     271        8702 :     while (ch = *src++, isdigit((unsigned char) ch))
     272             :     {
     273        6920 :         tmp = 0;
     274             :         do
     275             :         {
     276       16446 :             n = strchr(digits, ch) - digits;
     277       16446 :             assert(n >= 0 && n <= 9);
     278       16446 :             tmp *= 10;
     279       16446 :             tmp += n;
     280       16446 :             if (tmp > 255)
     281           0 :                 goto enoent;
     282       16446 :         } while ((ch = *src++) != '\0' && isdigit((unsigned char) ch));
     283        6920 :         if (size-- == 0)
     284           0 :             goto emsgsize;
     285        6920 :         *dst++ = (u_char) tmp;
     286        6920 :         if (ch == '\0' || ch == '/')
     287             :             break;
     288        5138 :         if (ch != '.')
     289           0 :             goto enoent;
     290             :     }
     291             : 
     292             :     /* Get the prefix length if any. */
     293        1782 :     bits = -1;
     294        1782 :     if (ch == '/' && isdigit((unsigned char) src[0]) && dst > odst)
     295             :     {
     296             :         /* CIDR width specifier.  Nothing can follow it. */
     297         362 :         ch = *src++;            /* Skip over the /. */
     298         362 :         bits = 0;
     299             :         do
     300             :         {
     301         568 :             n = strchr(digits, ch) - digits;
     302         568 :             assert(n >= 0 && n <= 9);
     303         568 :             bits *= 10;
     304         568 :             bits += n;
     305         568 :         } while ((ch = *src++) != '\0' && isdigit((unsigned char) ch));
     306         362 :         if (ch != '\0')
     307           0 :             goto enoent;
     308         362 :         if (bits > 32)
     309           0 :             goto emsgsize;
     310             :     }
     311             : 
     312             :     /* Fiery death and destruction unless we prefetched EOS. */
     313        1782 :     if (ch != '\0')
     314           0 :         goto enoent;
     315             : 
     316             :     /* Prefix length can default to /32 only if all four octets spec'd. */
     317        1782 :     if (bits == -1)
     318             :     {
     319        1420 :         if (dst - odst == 4)
     320        1420 :             bits = 32;
     321             :         else
     322           0 :             goto enoent;
     323             :     }
     324             : 
     325             :     /* If nothing was written to the destination, we found no address. */
     326        1782 :     if (dst == odst)
     327           0 :         goto enoent;
     328             : 
     329             :     /* If prefix length overspecifies mantissa, life is bad. */
     330        1782 :     if ((bits / 8) > (dst - odst))
     331           0 :         goto enoent;
     332             : 
     333             :     /* Extend address to four octets. */
     334        3772 :     while (size-- > 0)
     335         208 :         *dst++ = 0;
     336             : 
     337        1782 :     return bits;
     338             : 
     339             : enoent:
     340           0 :     errno = ENOENT;
     341           0 :     return -1;
     342             : 
     343             : emsgsize:
     344           0 :     errno = EMSGSIZE;
     345           0 :     return -1;
     346             : }
     347             : 
     348             : static int
     349         164 : getbits(const char *src, int *bitsp)
     350             : {
     351             :     static const char digits[] = "0123456789";
     352             :     int         n;
     353             :     int         val;
     354             :     char        ch;
     355             : 
     356         164 :     val = 0;
     357         164 :     n = 0;
     358         664 :     while ((ch = *src++) != '\0')
     359             :     {
     360             :         const char *pch;
     361             : 
     362         336 :         pch = strchr(digits, ch);
     363         336 :         if (pch != NULL)
     364             :         {
     365         336 :             if (n++ != 0 && val == 0)   /* no leading zeros */
     366           0 :                 return 0;
     367         336 :             val *= 10;
     368         336 :             val += (pch - digits);
     369         336 :             if (val > 128)       /* range */
     370           0 :                 return 0;
     371         336 :             continue;
     372             :         }
     373           0 :         return 0;
     374             :     }
     375         164 :     if (n == 0)
     376           0 :         return 0;
     377         164 :     *bitsp = val;
     378         164 :     return 1;
     379             : }
     380             : 
     381             : static int
     382          12 : getv4(const char *src, u_char *dst, int *bitsp)
     383             : {
     384             :     static const char digits[] = "0123456789";
     385          12 :     u_char     *odst = dst;
     386             :     int         n;
     387             :     u_int       val;
     388             :     char        ch;
     389             : 
     390          12 :     val = 0;
     391          12 :     n = 0;
     392         108 :     while ((ch = *src++) != '\0')
     393             :     {
     394             :         const char *pch;
     395             : 
     396          92 :         pch = strchr(digits, ch);
     397          92 :         if (pch != NULL)
     398             :         {
     399          48 :             if (n++ != 0 && val == 0)   /* no leading zeros */
     400           0 :                 return 0;
     401          48 :             val *= 10;
     402          48 :             val += (pch - digits);
     403          48 :             if (val > 255)       /* range */
     404           0 :                 return 0;
     405          48 :             continue;
     406             :         }
     407          44 :         if (ch == '.' || ch == '/')
     408             :         {
     409          44 :             if (dst - odst > 3) /* too many octets? */
     410           0 :                 return 0;
     411          44 :             *dst++ = val;
     412          44 :             if (ch == '/')
     413           8 :                 return getbits(src, bitsp);
     414          36 :             val = 0;
     415          36 :             n = 0;
     416          36 :             continue;
     417             :         }
     418           0 :         return 0;
     419             :     }
     420           4 :     if (n == 0)
     421           0 :         return 0;
     422           4 :     if (dst - odst > 3)          /* too many octets? */
     423           0 :         return 0;
     424           4 :     *dst++ = val;
     425           4 :     return 1;
     426             : }
     427             : 
     428             : static int
     429         216 : inet_net_pton_ipv6(const char *src, u_char *dst)
     430             : {
     431         216 :     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         368 : 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         368 :     if (size < NS_IN6ADDRSZ)
     456           0 :         goto emsgsize;
     457             : 
     458         368 :     memset((tp = tmp), '\0', NS_IN6ADDRSZ);
     459         368 :     endp = tp + NS_IN6ADDRSZ;
     460         368 :     colonp = NULL;
     461             :     /* Leading :: requires some special handling. */
     462         368 :     if (*src == ':')
     463          12 :         if (*++src != ':')
     464           0 :             goto enoent;
     465         368 :     curtok = src;
     466         368 :     saw_xdigit = 0;
     467         368 :     val = 0;
     468         368 :     digits = 0;
     469         368 :     bits = -1;
     470        6788 :     while ((ch = *src++) != '\0')
     471             :     {
     472             :         const char *pch;
     473             : 
     474        6224 :         if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
     475        1560 :             pch = strchr((xdigits = xdigits_u), ch);
     476        6224 :         if (pch != NULL)
     477             :         {
     478        4664 :             val <<= 4;
     479        4664 :             val |= (pch - xdigits);
     480        4664 :             if (++digits > 4)
     481           0 :                 goto enoent;
     482        4664 :             saw_xdigit = 1;
     483        4664 :             continue;
     484             :         }
     485        1560 :         if (ch == ':')
     486             :         {
     487        1392 :             curtok = src;
     488        1392 :             if (!saw_xdigit)
     489             :             {
     490         368 :                 if (colonp)
     491           4 :                     goto enoent;
     492         364 :                 colonp = tp;
     493         364 :                 continue;
     494             :             }
     495        1024 :             else if (*src == '\0')
     496           0 :                 goto enoent;
     497        1024 :             if (tp + NS_INT16SZ > endp)
     498           0 :                 goto enoent;
     499        1024 :             *tp++ = (u_char) (val >> 8) & 0xff;
     500        1024 :             *tp++ = (u_char) val & 0xff;
     501        1024 :             saw_xdigit = 0;
     502        1024 :             digits = 0;
     503        1024 :             val = 0;
     504        1024 :             continue;
     505             :         }
     506         180 :         if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
     507          12 :             getv4(curtok, tp, &bits) > 0)
     508             :         {
     509          12 :             tp += NS_INADDRSZ;
     510          12 :             saw_xdigit = 0;
     511          12 :             break;              /* '\0' was seen by inet_pton4(). */
     512             :         }
     513         156 :         if (ch == '/' && getbits(src, &bits) > 0)
     514         156 :             break;
     515           0 :         goto enoent;
     516             :     }
     517         364 :     if (saw_xdigit)
     518             :     {
     519         280 :         if (tp + NS_INT16SZ > endp)
     520           0 :             goto enoent;
     521         280 :         *tp++ = (u_char) (val >> 8) & 0xff;
     522         280 :         *tp++ = (u_char) val & 0xff;
     523             :     }
     524         364 :     if (bits == -1)
     525         200 :         bits = 128;
     526             : 
     527         364 :     endp = tmp + 16;
     528             : 
     529         364 :     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         360 :         const int   n = tp - colonp;
     536             :         int         i;
     537             : 
     538         360 :         if (tp == endp)
     539           0 :             goto enoent;
     540        2168 :         for (i = 1; i <= n; i++)
     541             :         {
     542        1808 :             endp[-i] = colonp[n - i];
     543        1808 :             colonp[n - i] = 0;
     544             :         }
     545         360 :         tp = endp;
     546             :     }
     547         364 :     if (tp != endp)
     548           0 :         goto enoent;
     549             : 
     550             :     /*
     551             :      * Copy out the result.
     552             :      */
     553         364 :     memcpy(dst, tmp, NS_IN6ADDRSZ);
     554             : 
     555         364 :     return bits;
     556             : 
     557             : enoent:
     558           4 :     errno = ENOENT;
     559           4 :     return -1;
     560             : 
     561             : emsgsize:
     562           0 :     errno = EMSGSIZE;
     563           0 :     return -1;
     564             : }

Generated by: LCOV version 1.13