diff options
author | Christian Grothoff <christian@grothoff.org> | 2013-10-26 12:36:51 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2013-10-26 12:36:51 +0000 |
commit | aeb922926c639ffdd992f96cd125e47bb0e2c301 (patch) | |
tree | 85097e40305035ad337f0c0e8dc0f95343dbed3a /src/util/service.c | |
parent | 7679eb4a51b8d0e9e4671dae00ca83c9f1b22de7 (diff) | |
download | gnunet-aeb922926c639ffdd992f96cd125e47bb0e2c301.tar.gz gnunet-aeb922926c639ffdd992f96cd125e47bb0e2c301.zip |
-moving code to parse IPv4/IPv6 subnet specifications to strings and making it part of the public API
Diffstat (limited to 'src/util/service.c')
-rw-r--r-- | src/util/service.c | 325 |
1 files changed, 10 insertions, 315 deletions
diff --git a/src/util/service.c b/src/util/service.c index 3ba20d64a..e7d4c1c6f 100644 --- a/src/util/service.c +++ b/src/util/service.c | |||
@@ -45,40 +45,6 @@ | |||
45 | /* ******************* access control ******************** */ | 45 | /* ******************* access control ******************** */ |
46 | 46 | ||
47 | /** | 47 | /** |
48 | * @brief IPV4 network in CIDR notation. | ||
49 | */ | ||
50 | struct IPv4NetworkSet | ||
51 | { | ||
52 | /** | ||
53 | * IPv4 address. | ||
54 | */ | ||
55 | struct in_addr network; | ||
56 | |||
57 | /** | ||
58 | * IPv4 netmask. | ||
59 | */ | ||
60 | struct in_addr netmask; | ||
61 | }; | ||
62 | |||
63 | /** | ||
64 | |||
65 | * @brief network in CIDR notation for IPV6. | ||
66 | */ | ||
67 | struct IPv6NetworkSet | ||
68 | { | ||
69 | /** | ||
70 | * IPv6 address. | ||
71 | */ | ||
72 | struct in6_addr network; | ||
73 | |||
74 | /** | ||
75 | * IPv6 netmask. | ||
76 | */ | ||
77 | struct in6_addr netmask; | ||
78 | }; | ||
79 | |||
80 | |||
81 | /** | ||
82 | * Start task that may speed up our system clock artificially | 48 | * Start task that may speed up our system clock artificially |
83 | * | 49 | * |
84 | * @param cfg configuration to use | 50 | * @param cfg configuration to use |
@@ -95,277 +61,6 @@ GNUNET_SPEEDUP_stop_ (void); | |||
95 | 61 | ||
96 | 62 | ||
97 | /** | 63 | /** |
98 | * Parse a network specification. The argument specifies | ||
99 | * a list of networks. The format is | ||
100 | * <tt>[network/netmask;]*</tt> (no whitespace, must be terminated | ||
101 | * with a semicolon). The network must be given in dotted-decimal | ||
102 | * notation. The netmask can be given in CIDR notation (/16) or | ||
103 | * in dotted-decimal (/255.255.0.0). | ||
104 | * | ||
105 | * @param routeList a string specifying the forbidden networks | ||
106 | * @return the converted list, NULL if the synatx is flawed | ||
107 | */ | ||
108 | static struct IPv4NetworkSet * | ||
109 | parse_ipv4_specification (const char *routeList) | ||
110 | { | ||
111 | unsigned int count; | ||
112 | unsigned int i; | ||
113 | unsigned int j; | ||
114 | unsigned int len; | ||
115 | int cnt; | ||
116 | unsigned int pos; | ||
117 | unsigned int temps[8]; | ||
118 | int slash; | ||
119 | struct IPv4NetworkSet *result; | ||
120 | |||
121 | if (NULL == routeList) | ||
122 | return NULL; | ||
123 | len = strlen (routeList); | ||
124 | if (0 == len) | ||
125 | return NULL; | ||
126 | count = 0; | ||
127 | for (i = 0; i < len; i++) | ||
128 | if (routeList[i] == ';') | ||
129 | count++; | ||
130 | result = GNUNET_malloc (sizeof (struct IPv4NetworkSet) * (count + 1)); | ||
131 | i = 0; | ||
132 | pos = 0; | ||
133 | while (i < count) | ||
134 | { | ||
135 | cnt = | ||
136 | SSCANF (&routeList[pos], "%u.%u.%u.%u/%u.%u.%u.%u;", &temps[0], | ||
137 | &temps[1], &temps[2], &temps[3], &temps[4], &temps[5], | ||
138 | &temps[6], &temps[7]); | ||
139 | if (8 == cnt) | ||
140 | { | ||
141 | for (j = 0; j < 8; j++) | ||
142 | if (temps[j] > 0xFF) | ||
143 | { | ||
144 | LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid format for IP: `%s'\n"), | ||
145 | &routeList[pos]); | ||
146 | GNUNET_free (result); | ||
147 | return NULL; | ||
148 | } | ||
149 | result[i].network.s_addr = | ||
150 | htonl ((temps[0] << 24) + (temps[1] << 16) + (temps[2] << 8) + | ||
151 | temps[3]); | ||
152 | result[i].netmask.s_addr = | ||
153 | htonl ((temps[4] << 24) + (temps[5] << 16) + (temps[6] << 8) + | ||
154 | temps[7]); | ||
155 | while (routeList[pos] != ';') | ||
156 | pos++; | ||
157 | pos++; | ||
158 | i++; | ||
159 | continue; | ||
160 | } | ||
161 | /* try second notation */ | ||
162 | cnt = | ||
163 | SSCANF (&routeList[pos], "%u.%u.%u.%u/%u;", &temps[0], &temps[1], | ||
164 | &temps[2], &temps[3], &slash); | ||
165 | if (5 == cnt) | ||
166 | { | ||
167 | for (j = 0; j < 4; j++) | ||
168 | if (temps[j] > 0xFF) | ||
169 | { | ||
170 | LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid format for IP: `%s'\n"), | ||
171 | &routeList[pos]); | ||
172 | GNUNET_free (result); | ||
173 | return NULL; | ||
174 | } | ||
175 | result[i].network.s_addr = | ||
176 | htonl ((temps[0] << 24) + (temps[1] << 16) + (temps[2] << 8) + | ||
177 | temps[3]); | ||
178 | if ((slash <= 32) && (slash >= 0)) | ||
179 | { | ||
180 | result[i].netmask.s_addr = 0; | ||
181 | while (slash > 0) | ||
182 | { | ||
183 | result[i].netmask.s_addr = | ||
184 | (result[i].netmask.s_addr >> 1) + 0x80000000; | ||
185 | slash--; | ||
186 | } | ||
187 | result[i].netmask.s_addr = htonl (result[i].netmask.s_addr); | ||
188 | while (';' != routeList[pos]) | ||
189 | pos++; | ||
190 | pos++; | ||
191 | i++; | ||
192 | continue; | ||
193 | } | ||
194 | else | ||
195 | { | ||
196 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
197 | _("Invalid network notation ('/%d' is not legal in IPv4 CIDR)."), | ||
198 | slash); | ||
199 | GNUNET_free (result); | ||
200 | return NULL; /* error */ | ||
201 | } | ||
202 | } | ||
203 | /* try third notation */ | ||
204 | slash = 32; | ||
205 | cnt = | ||
206 | SSCANF (&routeList[pos], "%u.%u.%u.%u;", &temps[0], &temps[1], | ||
207 | &temps[2], &temps[3]); | ||
208 | if (4 == cnt) | ||
209 | { | ||
210 | for (j = 0; j < 4; j++) | ||
211 | if (temps[j] > 0xFF) | ||
212 | { | ||
213 | LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid format for IP: `%s'\n"), | ||
214 | &routeList[pos]); | ||
215 | GNUNET_free (result); | ||
216 | return NULL; | ||
217 | } | ||
218 | result[i].network.s_addr = | ||
219 | htonl ((temps[0] << 24) + (temps[1] << 16) + (temps[2] << 8) + | ||
220 | temps[3]); | ||
221 | result[i].netmask.s_addr = 0; | ||
222 | while (slash > 0) | ||
223 | { | ||
224 | result[i].netmask.s_addr = (result[i].netmask.s_addr >> 1) + 0x80000000; | ||
225 | slash--; | ||
226 | } | ||
227 | result[i].netmask.s_addr = htonl (result[i].netmask.s_addr); | ||
228 | while (routeList[pos] != ';') | ||
229 | pos++; | ||
230 | pos++; | ||
231 | i++; | ||
232 | continue; | ||
233 | } | ||
234 | LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid format for IP: `%s'\n"), | ||
235 | &routeList[pos]); | ||
236 | GNUNET_free (result); | ||
237 | return NULL; /* error */ | ||
238 | } | ||
239 | if (pos < strlen (routeList)) | ||
240 | { | ||
241 | LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid format for IP: `%s'\n"), | ||
242 | &routeList[pos]); | ||
243 | GNUNET_free (result); | ||
244 | return NULL; /* oops */ | ||
245 | } | ||
246 | return result; /* ok */ | ||
247 | } | ||
248 | |||
249 | |||
250 | /** | ||
251 | * Parse a network specification. The argument specifies | ||
252 | * a list of networks. The format is | ||
253 | * <tt>[network/netmask;]*</tt> (no whitespace, must be terminated | ||
254 | * with a semicolon). The network must be given in colon-hex | ||
255 | * notation. The netmask must be given in CIDR notation (/16) or | ||
256 | * can be omitted to specify a single host. | ||
257 | * | ||
258 | * @param routeListX a string specifying the forbidden networks | ||
259 | * @return the converted list, NULL if the synatx is flawed | ||
260 | */ | ||
261 | static struct IPv6NetworkSet * | ||
262 | parse_ipv6_specification (const char *routeListX) | ||
263 | { | ||
264 | unsigned int count; | ||
265 | unsigned int i; | ||
266 | unsigned int len; | ||
267 | unsigned int pos; | ||
268 | int start; | ||
269 | int slash; | ||
270 | int ret; | ||
271 | char *routeList; | ||
272 | struct IPv6NetworkSet *result; | ||
273 | unsigned int bits; | ||
274 | unsigned int off; | ||
275 | int save; | ||
276 | |||
277 | if (NULL == routeListX) | ||
278 | return NULL; | ||
279 | len = strlen (routeListX); | ||
280 | if (0 == len) | ||
281 | return NULL; | ||
282 | routeList = GNUNET_strdup (routeListX); | ||
283 | count = 0; | ||
284 | for (i = 0; i < len; i++) | ||
285 | if (';' == routeList[i]) | ||
286 | count++; | ||
287 | if (';' != routeList[len - 1]) | ||
288 | { | ||
289 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
290 | _("Invalid network notation (does not end with ';': `%s')\n"), | ||
291 | routeList); | ||
292 | GNUNET_free (routeList); | ||
293 | return NULL; | ||
294 | } | ||
295 | |||
296 | result = GNUNET_malloc (sizeof (struct IPv6NetworkSet) * (count + 1)); | ||
297 | i = 0; | ||
298 | pos = 0; | ||
299 | while (i < count) | ||
300 | { | ||
301 | start = pos; | ||
302 | while (';' != routeList[pos]) | ||
303 | pos++; | ||
304 | slash = pos; | ||
305 | while ((slash >= start) && (routeList[slash] != '/')) | ||
306 | slash--; | ||
307 | if (slash < start) | ||
308 | { | ||
309 | memset (&result[i].netmask, 0xFF, sizeof (struct in6_addr)); | ||
310 | slash = pos; | ||
311 | } | ||
312 | else | ||
313 | { | ||
314 | routeList[pos] = '\0'; | ||
315 | ret = inet_pton (AF_INET6, &routeList[slash + 1], &result[i].netmask); | ||
316 | if (ret <= 0) | ||
317 | { | ||
318 | save = errno; | ||
319 | if ((1 != SSCANF (&routeList[slash + 1], "%u", &bits)) || (bits >= 128)) | ||
320 | { | ||
321 | if (0 == ret) | ||
322 | LOG (GNUNET_ERROR_TYPE_ERROR, _("Wrong format `%s' for netmask\n"), | ||
323 | &routeList[slash + 1]); | ||
324 | else | ||
325 | { | ||
326 | errno = save; | ||
327 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "inet_pton"); | ||
328 | } | ||
329 | GNUNET_free (result); | ||
330 | GNUNET_free (routeList); | ||
331 | return NULL; | ||
332 | } | ||
333 | off = 0; | ||
334 | while (bits > 8) | ||
335 | { | ||
336 | result[i].netmask.s6_addr[off++] = 0xFF; | ||
337 | bits -= 8; | ||
338 | } | ||
339 | while (bits > 0) | ||
340 | { | ||
341 | result[i].netmask.s6_addr[off] = | ||
342 | (result[i].netmask.s6_addr[off] >> 1) + 0x80; | ||
343 | bits--; | ||
344 | } | ||
345 | } | ||
346 | } | ||
347 | routeList[slash] = '\0'; | ||
348 | ret = inet_pton (AF_INET6, &routeList[start], &result[i].network); | ||
349 | if (ret <= 0) | ||
350 | { | ||
351 | if (0 == ret) | ||
352 | LOG (GNUNET_ERROR_TYPE_ERROR, _("Wrong format `%s' for network\n"), | ||
353 | &routeList[slash + 1]); | ||
354 | else | ||
355 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "inet_pton"); | ||
356 | GNUNET_free (result); | ||
357 | GNUNET_free (routeList); | ||
358 | return NULL; | ||
359 | } | ||
360 | pos++; | ||
361 | i++; | ||
362 | } | ||
363 | GNUNET_free (routeList); | ||
364 | return result; | ||
365 | } | ||
366 | |||
367 | |||
368 | /** | ||
369 | * Check if the given IP address is in the list of IP addresses. | 64 | * Check if the given IP address is in the list of IP addresses. |
370 | * | 65 | * |
371 | * @param list a list of networks | 66 | * @param list a list of networks |
@@ -373,7 +68,7 @@ parse_ipv6_specification (const char *routeListX) | |||
373 | * @return GNUNET_NO if the IP is not in the list, GNUNET_YES if it it is | 68 | * @return GNUNET_NO if the IP is not in the list, GNUNET_YES if it it is |
374 | */ | 69 | */ |
375 | static int | 70 | static int |
376 | check_ipv4_listed (const struct IPv4NetworkSet *list, const struct in_addr *add) | 71 | check_ipv4_listed (const struct GNUNET_STRINGS_IPv4NetworkPolicy *list, const struct in_addr *add) |
377 | { | 72 | { |
378 | unsigned int i; | 73 | unsigned int i; |
379 | 74 | ||
@@ -399,7 +94,7 @@ check_ipv4_listed (const struct IPv4NetworkSet *list, const struct in_addr *add) | |||
399 | * @return GNUNET_NO if the IP is not in the list, GNUNET_YES if it it is | 94 | * @return GNUNET_NO if the IP is not in the list, GNUNET_YES if it it is |
400 | */ | 95 | */ |
401 | static int | 96 | static int |
402 | check_ipv6_listed (const struct IPv6NetworkSet *list, const struct in6_addr *ip) | 97 | check_ipv6_listed (const struct GNUNET_STRINGS_IPv6NetworkPolicy *list, const struct in6_addr *ip) |
403 | { | 98 | { |
404 | unsigned int i; | 99 | unsigned int i; |
405 | unsigned int j; | 100 | unsigned int j; |
@@ -467,24 +162,24 @@ struct GNUNET_SERVICE_Context | |||
467 | /** | 162 | /** |
468 | * IPv4 addresses that are not allowed to connect. | 163 | * IPv4 addresses that are not allowed to connect. |
469 | */ | 164 | */ |
470 | struct IPv4NetworkSet *v4_denied; | 165 | struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_denied; |
471 | 166 | ||
472 | /** | 167 | /** |
473 | * IPv6 addresses that are not allowed to connect. | 168 | * IPv6 addresses that are not allowed to connect. |
474 | */ | 169 | */ |
475 | struct IPv6NetworkSet *v6_denied; | 170 | struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_denied; |
476 | 171 | ||
477 | /** | 172 | /** |
478 | * IPv4 addresses that are allowed to connect (if not | 173 | * IPv4 addresses that are allowed to connect (if not |
479 | * set, all are allowed). | 174 | * set, all are allowed). |
480 | */ | 175 | */ |
481 | struct IPv4NetworkSet *v4_allowed; | 176 | struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_allowed; |
482 | 177 | ||
483 | /** | 178 | /** |
484 | * IPv6 addresses that are allowed to connect (if not | 179 | * IPv6 addresses that are allowed to connect (if not |
485 | * set, all are allowed). | 180 | * set, all are allowed). |
486 | */ | 181 | */ |
487 | struct IPv6NetworkSet *v6_allowed; | 182 | struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_allowed; |
488 | 183 | ||
489 | /** | 184 | /** |
490 | * My (default) message handlers. Adjusted copy | 185 | * My (default) message handlers. Adjusted copy |
@@ -707,7 +402,7 @@ get_pid_file_name (struct GNUNET_SERVICE_Context *sctx) | |||
707 | * no ACL configured) | 402 | * no ACL configured) |
708 | */ | 403 | */ |
709 | static int | 404 | static int |
710 | process_acl4 (struct IPv4NetworkSet **ret, struct GNUNET_SERVICE_Context *sctx, | 405 | process_acl4 (struct GNUNET_STRINGS_IPv4NetworkPolicy **ret, struct GNUNET_SERVICE_Context *sctx, |
711 | const char *option) | 406 | const char *option) |
712 | { | 407 | { |
713 | char *opt; | 408 | char *opt; |
@@ -721,7 +416,7 @@ process_acl4 (struct IPv4NetworkSet **ret, struct GNUNET_SERVICE_Context *sctx, | |||
721 | GNUNET_CONFIGURATION_get_value_string (sctx->cfg, | 416 | GNUNET_CONFIGURATION_get_value_string (sctx->cfg, |
722 | sctx->service_name, | 417 | sctx->service_name, |
723 | option, &opt)); | 418 | option, &opt)); |
724 | if (NULL == (*ret = parse_ipv4_specification (opt))) | 419 | if (NULL == (*ret = GNUNET_STRINGS_parse_ipv4_policy (opt))) |
725 | { | 420 | { |
726 | LOG (GNUNET_ERROR_TYPE_WARNING, | 421 | LOG (GNUNET_ERROR_TYPE_WARNING, |
727 | _("Could not parse IPv4 network specification `%s' for `%s:%s'\n"), | 422 | _("Could not parse IPv4 network specification `%s' for `%s:%s'\n"), |
@@ -744,7 +439,7 @@ process_acl4 (struct IPv4NetworkSet **ret, struct GNUNET_SERVICE_Context *sctx, | |||
744 | * no ACL configured) | 439 | * no ACL configured) |
745 | */ | 440 | */ |
746 | static int | 441 | static int |
747 | process_acl6 (struct IPv6NetworkSet **ret, struct GNUNET_SERVICE_Context *sctx, | 442 | process_acl6 (struct GNUNET_STRINGS_IPv6NetworkPolicy **ret, struct GNUNET_SERVICE_Context *sctx, |
748 | const char *option) | 443 | const char *option) |
749 | { | 444 | { |
750 | char *opt; | 445 | char *opt; |
@@ -758,7 +453,7 @@ process_acl6 (struct IPv6NetworkSet **ret, struct GNUNET_SERVICE_Context *sctx, | |||
758 | GNUNET_CONFIGURATION_get_value_string (sctx->cfg, | 453 | GNUNET_CONFIGURATION_get_value_string (sctx->cfg, |
759 | sctx->service_name, | 454 | sctx->service_name, |
760 | option, &opt)); | 455 | option, &opt)); |
761 | if (NULL == (*ret = parse_ipv6_specification (opt))) | 456 | if (NULL == (*ret = GNUNET_STRINGS_parse_ipv6_policy (opt))) |
762 | { | 457 | { |
763 | LOG (GNUNET_ERROR_TYPE_WARNING, | 458 | LOG (GNUNET_ERROR_TYPE_WARNING, |
764 | _("Could not parse IPv6 network specification `%s' for `%s:%s'\n"), | 459 | _("Could not parse IPv6 network specification `%s' for `%s:%s'\n"), |