"Fossies" - the Fresh Open Source Software Archive

Member "ntp-4.2.8p15/libntp/decodenetnum.c" (23 Jun 2020, 4027 Bytes) of package /linux/misc/ntp-4.2.8p15.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "decodenetnum.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 4.2.8p14_vs_4.2.8p15.

    1 /*
    2  * decodenetnum - return a net number (this is crude, but careful)
    3  */
    4 #include <config.h>
    5 #include <sys/types.h>
    6 #include <ctype.h>
    7 #ifdef HAVE_SYS_SOCKET_H
    8 #include <sys/socket.h>
    9 #endif
   10 #ifdef HAVE_NETINET_IN_H
   11 #include <netinet/in.h>
   12 #endif
   13 
   14 #include "ntp.h"
   15 #include "ntp_stdlib.h"
   16 
   17 
   18 /* If the given string position points to a decimal digit, parse the
   19  * number. If this is not possible, or the parsing did not consume the
   20  * whole string, or if the result exceeds the maximum value, return the
   21  * default value.
   22  */
   23 static unsigned long
   24 _num_or_dflt(
   25     char *      sval,
   26     unsigned long   maxval,
   27     unsigned long   defval
   28     )
   29 {
   30     char *      ep;
   31     unsigned long   num;
   32     
   33     if (!(sval && isdigit(*(unsigned char*)sval)))
   34         return defval;
   35     
   36     num = strtoul(sval, &ep, 10);
   37     if (!*ep && num <= maxval)
   38         return num;
   39     
   40     return defval;
   41 }
   42 
   43 /* If the given string position is not NULL and does not point to the
   44  * terminator, replace the character with NUL and advance the pointer.
   45  * Return the resulting position.
   46  */
   47 static inline char*
   48 _chop(
   49     char * sp)
   50 {
   51     if (sp && *sp)
   52         *sp++ = '\0';
   53     return sp;
   54 }
   55 
   56 /* If the given string position points to the given char, advance the
   57  * pointer and return the result. Otherwise, return NULL.
   58  */
   59 static inline char*
   60 _skip(
   61     char * sp,
   62     int    ch)
   63 {
   64     if (sp && *(unsigned char*)sp == ch)
   65         return (sp + 1);
   66     return NULL;
   67 }
   68 
   69 /*
   70  * decodenetnum     convert text IP address and port to sockaddr_u
   71  *
   72  * Returns FALSE (->0) for failure, TRUE (->1) for success.
   73  */
   74 int
   75 decodenetnum(
   76     const char *num,
   77     sockaddr_u *net
   78     )
   79 {
   80     /* Building a parser is more fun in Haskell, but here we go...
   81      *
   82      * This works through 'inet_pton()' taking the brunt of the
   83      * work, after some string manipulations to split off URI
   84      * brackets, ports and scope identifiers. The heuristics are
   85      * simple but must hold for all _VALID_ addresses. inet_pton()
   86      * will croak on bad ones later, but replicating the whole
   87      * parser logic to detect errors is wasteful.
   88      */
   89     
   90     sockaddr_u  netnum;
   91     char        buf[64];    /* working copy of input */
   92     char        *haddr=buf;
   93     unsigned int    port=NTP_PORT, scope=0;
   94     unsigned short  afam=AF_UNSPEC;
   95     
   96     /* copy input to working buffer with length check */
   97     if (strlcpy(buf, num, sizeof(buf)) >= sizeof(buf))
   98         return FALSE;
   99 
  100     /* Identify address family and possibly the port, if given.  If
  101      * this results in AF_UNSPEC, we will fail in the next step.
  102      */
  103     if (*haddr == '[') {
  104         char * endp = strchr(++haddr, ']');
  105         if (endp) {
  106             port = _num_or_dflt(_skip(_chop(endp), ':'),
  107                           0xFFFFu, port);
  108             afam = strchr(haddr, ':') ? AF_INET6 : AF_INET;
  109         }
  110     } else {
  111         char *col = strchr(haddr, ':');
  112         char *dot = strchr(haddr, '.');
  113         if (col == dot) {
  114             /* no dot, no colon: bad! */
  115             afam = AF_UNSPEC;
  116         } else if (!col) {
  117             /* no colon, only dot: IPv4! */
  118             afam = AF_INET;
  119         } else if (!dot || col < dot) {
  120             /* no dot or 1st colon before 1st dot: IPv6! */
  121             afam = AF_INET6;
  122         } else {
  123             /* 1st dot before 1st colon: must be IPv4 with port */
  124             afam = AF_INET;
  125             port = _num_or_dflt(_chop(col), 0xFFFFu, port);
  126         }
  127     }
  128 
  129     /* Since we don't know about additional members in the address
  130      * structures, we wipe the result buffer thoroughly:
  131      */  
  132     memset(&netnum, 0, sizeof(netnum));
  133 
  134     /* For AF_INET6, evaluate and remove any scope suffix. Have
  135      * inet_pton() do the real work for AF_INET and AF_INET6, bail
  136      * out otherwise:
  137      */
  138     switch (afam) {
  139     case AF_INET:
  140         if (inet_pton(afam, haddr, &netnum.sa4.sin_addr) <= 0)
  141             return FALSE;
  142         netnum.sa4.sin_port = htons((unsigned short)port);
  143         break;
  144 
  145     case AF_INET6:
  146         scope = _num_or_dflt(_chop(strchr(haddr, '%')), 0xFFFFFFFFu, scope);
  147         if (inet_pton(afam, haddr, &netnum.sa6.sin6_addr) <= 0)
  148             return FALSE;
  149         netnum.sa6.sin6_port = htons((unsigned short)port);
  150         netnum.sa6.sin6_scope_id = scope;
  151         break;
  152 
  153     case AF_UNSPEC:
  154     default:
  155         return FALSE;
  156     }
  157 
  158     /* Collect the remaining pieces and feed the output, which was
  159      * not touched so far:
  160      */
  161     netnum.sa.sa_family = afam;
  162     memcpy(net, &netnum, sizeof(netnum));
  163     return TRUE;
  164 }