LCOV - code coverage report
Current view: top level - src/backend/utils/adt - inet_net_pton.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 191 266 71.8 %
Date: 2017-09-29 13:40:31 Functions: 6 6 100.0 %
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         337 :     switch (af)
      65             :     {
      66             :         case PGSQL_AF_INET:
      67         246 :             return size == -1 ?
      68         246 :                 inet_net_pton_ipv4(src, dst) :
      69             :                 inet_cidr_pton_ipv4(src, dst, size);
      70             :         case PGSQL_AF_INET6:
      71          91 :             return size == -1 ?
      72          91 :                 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         123 : 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         123 :                 tmp = 0,
     104             :                 dirty,
     105             :                 bits;
     106         123 :     const u_char *odst = dst;
     107             : 
     108         123 :     ch = *src++;
     109         123 :     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         123 :     else if (isdigit((unsigned char) ch))
     143             :     {
     144             :         /* Decimal: eat dotted digit string. */
     145             :         for (;;)
     146             :         {
     147         375 :             tmp = 0;
     148             :             do
     149             :             {
     150         714 :                 n = strchr(digits, ch) - digits;
     151         714 :                 assert(n >= 0 && n <= 9);
     152         714 :                 tmp *= 10;
     153         714 :                 tmp += n;
     154         714 :                 if (tmp > 255)
     155           0 :                     goto enoent;
     156        1382 :             } while ((ch = *src++) != '\0' &&
     157         714 :                      isdigit((unsigned char) ch));
     158         375 :             if (size-- <= 0U)
     159           0 :                 goto emsgsize;
     160         375 :             *dst++ = (u_char) tmp;
     161         375 :             if (ch == '\0' || ch == '/')
     162             :                 break;
     163         252 :             if (ch != '.')
     164           0 :                 goto enoent;
     165         252 :             ch = *src++;
     166         252 :             if (!isdigit((unsigned char) ch))
     167           0 :                 goto enoent;
     168         252 :         }
     169             :     }
     170             :     else
     171           0 :         goto enoent;
     172             : 
     173         123 :     bits = -1;
     174         123 :     if (ch == '/' && isdigit((unsigned char) src[0]) && dst > odst)
     175             :     {
     176             :         /* CIDR width specifier.  Nothing can follow it. */
     177          77 :         ch = *src++;            /* Skip over the /. */
     178          77 :         bits = 0;
     179             :         do
     180             :         {
     181         130 :             n = strchr(digits, ch) - digits;
     182         130 :             assert(n >= 0 && n <= 9);
     183         130 :             bits *= 10;
     184         130 :             bits += n;
     185         130 :         } while ((ch = *src++) != '\0' && isdigit((unsigned char) ch));
     186          77 :         if (ch != '\0')
     187           0 :             goto enoent;
     188          77 :         if (bits > 32)
     189           0 :             goto emsgsize;
     190             :     }
     191             : 
     192             :     /* Firey death and destruction unless we prefetched EOS. */
     193         123 :     if (ch != '\0')
     194           0 :         goto enoent;
     195             : 
     196             :     /* If nothing was written to the destination, we found no address. */
     197         123 :     if (dst == odst)
     198           0 :         goto enoent;
     199             :     /* If no CIDR spec was given, infer width from net class. */
     200         123 :     if (bits == -1)
     201             :     {
     202          46 :         if (*odst >= 240)        /* Class E */
     203          16 :             bits = 32;
     204          30 :         else if (*odst >= 224)   /* Class D */
     205           0 :             bits = 8;
     206          30 :         else if (*odst >= 192)   /* Class C */
     207           5 :             bits = 24;
     208          25 :         else if (*odst >= 128)   /* Class B */
     209           0 :             bits = 16;
     210             :         else
     211             :             /* Class A */
     212          25 :             bits = 8;
     213             :         /* If imputed mask is narrower than specified octets, widen. */
     214          46 :         if (bits < ((dst - odst) * 8))
     215          20 :             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          46 :         if (bits == 8 && *odst == 224)
     222           0 :             bits = 4;
     223             :     }
     224             :     /* Extend network to cover the actual mask. */
     225         254 :     while (bits > ((dst - odst) * 8))
     226             :     {
     227           8 :         if (size-- <= 0U)
     228           0 :             goto emsgsize;
     229           8 :         *dst++ = '\0';
     230             :     }
     231         123 :     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         123 : inet_net_pton_ipv4(const char *src, u_char *dst)
     261             : {
     262             :     static const char digits[] = "0123456789";
     263         123 :     const u_char *odst = dst;
     264             :     int         n,
     265             :                 ch,
     266             :                 tmp,
     267             :                 bits;
     268         123 :     size_t      size = 4;
     269             : 
     270             :     /* Get the mantissa. */
     271         563 :     while (ch = *src++, isdigit((unsigned char) ch))
     272             :     {
     273         440 :         tmp = 0;
     274             :         do
     275             :         {
     276         826 :             n = strchr(digits, ch) - digits;
     277         826 :             assert(n >= 0 && n <= 9);
     278         826 :             tmp *= 10;
     279         826 :             tmp += n;
     280         826 :             if (tmp > 255)
     281           0 :                 goto enoent;
     282         826 :         } while ((ch = *src++) != '\0' && isdigit((unsigned char) ch));
     283         440 :         if (size-- == 0)
     284           0 :             goto emsgsize;
     285         440 :         *dst++ = (u_char) tmp;
     286         440 :         if (ch == '\0' || ch == '/')
     287             :             break;
     288         317 :         if (ch != '.')
     289           0 :             goto enoent;
     290             :     }
     291             : 
     292             :     /* Get the prefix length if any. */
     293         123 :     bits = -1;
     294         123 :     if (ch == '/' && isdigit((unsigned char) src[0]) && dst > odst)
     295             :     {
     296             :         /* CIDR width specifier.  Nothing can follow it. */
     297          81 :         ch = *src++;            /* Skip over the /. */
     298          81 :         bits = 0;
     299             :         do
     300             :         {
     301         127 :             n = strchr(digits, ch) - digits;
     302         127 :             assert(n >= 0 && n <= 9);
     303         127 :             bits *= 10;
     304         127 :             bits += n;
     305         127 :         } while ((ch = *src++) != '\0' && isdigit((unsigned char) ch));
     306          81 :         if (ch != '\0')
     307           0 :             goto enoent;
     308          81 :         if (bits > 32)
     309           0 :             goto emsgsize;
     310             :     }
     311             : 
     312             :     /* Firey death and destruction unless we prefetched EOS. */
     313         123 :     if (ch != '\0')
     314           0 :         goto enoent;
     315             : 
     316             :     /* Prefix length can default to /32 only if all four octets spec'd. */
     317         123 :     if (bits == -1)
     318             :     {
     319          42 :         if (dst - odst == 4)
     320          42 :             bits = 32;
     321             :         else
     322           0 :             goto enoent;
     323             :     }
     324             : 
     325             :     /* If nothing was written to the destination, we found no address. */
     326         123 :     if (dst == odst)
     327           0 :         goto enoent;
     328             : 
     329             :     /* If prefix length overspecifies mantissa, life is bad. */
     330         123 :     if ((bits / 8) > (dst - odst))
     331           0 :         goto enoent;
     332             : 
     333             :     /* Extend address to four octets. */
     334         298 :     while (size-- > 0)
     335          52 :         *dst++ = 0;
     336             : 
     337         123 :     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          40 : getbits(const char *src, int *bitsp)
     350             : {
     351             :     static const char digits[] = "0123456789";
     352             :     int         n;
     353             :     int         val;
     354             :     char        ch;
     355             : 
     356          40 :     val = 0;
     357          40 :     n = 0;
     358         161 :     while ((ch = *src++) != '\0')
     359             :     {
     360             :         const char *pch;
     361             : 
     362          81 :         pch = strchr(digits, ch);
     363          81 :         if (pch != NULL)
     364             :         {
     365          81 :             if (n++ != 0 && val == 0)   /* no leading zeros */
     366           0 :                 return (0);
     367          81 :             val *= 10;
     368          81 :             val += (pch - digits);
     369          81 :             if (val > 128)       /* range */
     370           0 :                 return (0);
     371          81 :             continue;
     372             :         }
     373           0 :         return (0);
     374             :     }
     375          40 :     if (n == 0)
     376           0 :         return (0);
     377          40 :     *bitsp = val;
     378          40 :     return (1);
     379             : }
     380             : 
     381             : static int
     382           3 : getv4(const char *src, u_char *dst, int *bitsp)
     383             : {
     384             :     static const char digits[] = "0123456789";
     385           3 :     u_char     *odst = dst;
     386             :     int         n;
     387             :     u_int       val;
     388             :     char        ch;
     389             : 
     390           3 :     val = 0;
     391           3 :     n = 0;
     392          27 :     while ((ch = *src++) != '\0')
     393             :     {
     394             :         const char *pch;
     395             : 
     396          23 :         pch = strchr(digits, ch);
     397          23 :         if (pch != NULL)
     398             :         {
     399          12 :             if (n++ != 0 && val == 0)   /* no leading zeros */
     400           0 :                 return (0);
     401          12 :             val *= 10;
     402          12 :             val += (pch - digits);
     403          12 :             if (val > 255)       /* range */
     404           0 :                 return (0);
     405          12 :             continue;
     406             :         }
     407          11 :         if (ch == '.' || ch == '/')
     408             :         {
     409          11 :             if (dst - odst > 3) /* too many octets? */
     410           0 :                 return (0);
     411          11 :             *dst++ = val;
     412          11 :             if (ch == '/')
     413           2 :                 return (getbits(src, bitsp));
     414           9 :             val = 0;
     415           9 :             n = 0;
     416           9 :             continue;
     417             :         }
     418           0 :         return (0);
     419             :     }
     420           1 :     if (n == 0)
     421           0 :         return (0);
     422           1 :     if (dst - odst > 3)          /* too many octets? */
     423           0 :         return (0);
     424           1 :     *dst++ = val;
     425           1 :     return (1);
     426             : }
     427             : 
     428             : static int
     429          53 : inet_net_pton_ipv6(const char *src, u_char *dst)
     430             : {
     431          53 :     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          91 : 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          91 :     if (size < NS_IN6ADDRSZ)
     456           0 :         goto emsgsize;
     457             : 
     458          91 :     memset((tp = tmp), '\0', NS_IN6ADDRSZ);
     459          91 :     endp = tp + NS_IN6ADDRSZ;
     460          91 :     colonp = NULL;
     461             :     /* Leading :: requires some special handling. */
     462          91 :     if (*src == ':')
     463           3 :         if (*++src != ':')
     464           0 :             goto enoent;
     465          91 :     curtok = src;
     466          91 :     saw_xdigit = 0;
     467          91 :     val = 0;
     468          91 :     digits = 0;
     469          91 :     bits = -1;
     470        1663 :     while ((ch = *src++) != '\0')
     471             :     {
     472             :         const char *pch;
     473             : 
     474        1523 :         if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
     475         382 :             pch = strchr((xdigits = xdigits_u), ch);
     476        1523 :         if (pch != NULL)
     477             :         {
     478        1141 :             val <<= 4;
     479        1141 :             val |= (pch - xdigits);
     480        1141 :             if (++digits > 4)
     481           0 :                 goto enoent;
     482        1141 :             saw_xdigit = 1;
     483        1141 :             continue;
     484             :         }
     485         382 :         if (ch == ':')
     486             :         {
     487         341 :             curtok = src;
     488         341 :             if (!saw_xdigit)
     489             :             {
     490          92 :                 if (colonp)
     491           1 :                     goto enoent;
     492          91 :                 colonp = tp;
     493          91 :                 continue;
     494             :             }
     495         249 :             else if (*src == '\0')
     496           0 :                 goto enoent;
     497         249 :             if (tp + NS_INT16SZ > endp)
     498           0 :                 goto enoent;
     499         249 :             *tp++ = (u_char) (val >> 8) & 0xff;
     500         249 :             *tp++ = (u_char) val & 0xff;
     501         249 :             saw_xdigit = 0;
     502         249 :             digits = 0;
     503         249 :             val = 0;
     504         249 :             continue;
     505             :         }
     506          44 :         if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
     507           3 :             getv4(curtok, tp, &bits) > 0)
     508             :         {
     509           3 :             tp += NS_INADDRSZ;
     510           3 :             saw_xdigit = 0;
     511           3 :             break;              /* '\0' was seen by inet_pton4(). */
     512             :         }
     513          38 :         if (ch == '/' && getbits(src, &bits) > 0)
     514          38 :             break;
     515           0 :         goto enoent;
     516             :     }
     517          90 :     if (saw_xdigit)
     518             :     {
     519          69 :         if (tp + NS_INT16SZ > endp)
     520           0 :             goto enoent;
     521          69 :         *tp++ = (u_char) (val >> 8) & 0xff;
     522          69 :         *tp++ = (u_char) val & 0xff;
     523             :     }
     524          90 :     if (bits == -1)
     525          50 :         bits = 128;
     526             : 
     527          90 :     endp = tmp + 16;
     528             : 
     529          90 :     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          90 :         const int   n = tp - colonp;
     536             :         int         i;
     537             : 
     538          90 :         if (tp == endp)
     539           0 :             goto enoent;
     540         542 :         for (i = 1; i <= n; i++)
     541             :         {
     542         452 :             endp[-i] = colonp[n - i];
     543         452 :             colonp[n - i] = 0;
     544             :         }
     545          90 :         tp = endp;
     546             :     }
     547          90 :     if (tp != endp)
     548           0 :         goto enoent;
     549             : 
     550             :     /*
     551             :      * Copy out the result.
     552             :      */
     553          90 :     memcpy(dst, tmp, NS_IN6ADDRSZ);
     554             : 
     555          90 :     return (bits);
     556             : 
     557             : enoent:
     558           1 :     errno = ENOENT;
     559           1 :     return (-1);
     560             : 
     561             : emsgsize:
     562           0 :     errno = EMSGSIZE;
     563           0 :     return (-1);
     564             : }

Generated by: LCOV version 1.11