"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 }