2 * decodenetnum - return a net number (this is crude, but careful)
7 #ifdef HAVE_SYS_SOCKET_H
8 #include <sys/socket.h>
10 #ifdef HAVE_NETINET_IN_H
11 #include <netinet/in.h>
15 #include "ntp_stdlib.h"
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
33 if (!(sval && isdigit(*(unsigned char*)sval)))
36 num = strtoul(sval, &ep, 10);
37 if (!*ep && num <= maxval)
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.
56 /* If the given string position points to the given char, advance the
57 * pointer and return the result. Otherwise, return NULL.
64 if (sp && *(unsigned char*)sp == ch)
70 * decodenetnum convert text IP address and port to sockaddr_u
72 * Returns FALSE (->0) for failure, TRUE (->1) for success.
80 /* Building a parser is more fun in Haskell, but here we go...
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.
91 char buf[64]; /* working copy of input */
93 unsigned int port=NTP_PORT, scope=0;
94 unsigned short afam=AF_UNSPEC;
96 /* copy input to working buffer with length check */
97 if (strlcpy(buf, num, sizeof(buf)) >= sizeof(buf))
100 /* Identify address family and possibly the port, if given. If
101 * this results in AF_UNSPEC, we will fail in the next step.
104 char * endp = strchr(++haddr, ']');
106 port = _num_or_dflt(_skip(_chop(endp), ':'),
108 afam = strchr(haddr, ':') ? AF_INET6 : AF_INET;
111 char *col = strchr(haddr, ':');
112 char *dot = strchr(haddr, '.');
114 /* no dot, no colon: bad! */
117 /* no colon, only dot: IPv4! */
119 } else if (!dot || col < dot) {
120 /* no dot or 1st colon before 1st dot: IPv6! */
123 /* 1st dot before 1st colon: must be IPv4 with port */
125 port = _num_or_dflt(_chop(col), 0xFFFFu, port);
129 /* Since we don't know about additional members in the address
130 * structures, we wipe the result buffer thoroughly:
132 memset(&netnum, 0, sizeof(netnum));
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
140 if (inet_pton(afam, haddr, &netnum.sa4.sin_addr) <= 0)
142 netnum.sa4.sin_port = htons((unsigned short)port);
146 scope = _num_or_dflt(_chop(strchr(haddr, '%')), 0xFFFFFFFFu, scope);
147 if (inet_pton(afam, haddr, &netnum.sa6.sin6_addr) <= 0)
149 netnum.sa6.sin6_port = htons((unsigned short)port);
150 netnum.sa6.sin6_scope_id = scope;
158 /* Collect the remaining pieces and feed the output, which was
159 * not touched so far:
161 netnum.sa.sa_family = afam;
162 memcpy(net, &netnum, sizeof(netnum));