2 This file is part of GNUnet
3 Copyright (C) 2012, 2013, 2015 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
21 * @file src/tun/regex.c
22 * @brief functions to convert IP networks to regexes
23 * @author Maximilian Szengel
24 * @author Christian Grothoff
27 #include "gnunet_util_lib.h"
28 #include "gnunet_tun_lib.h"
31 * 'wildcard', matches all possible values (for HEX encoding).
33 #define DOT "(0|1|2|3|4|5|6|7|8|9|A|B|C|D|E|F)"
37 * Create a regex in @a rxstr from the given @a ip and @a netmask.
39 * @param ip IPv4 representation.
40 * @param port destination port
41 * @param rxstr generated regex, must be at least #GNUNET_TUN_IPV4_REGEXLEN
45 GNUNET_TUN_ipv4toregexsearch (const struct in_addr *ip,
49 GNUNET_snprintf (rxstr,
50 GNUNET_TUN_IPV4_REGEXLEN,
58 * Create a regex in @a rxstr from the given @a ipv6 and @a prefixlen.
60 * @param ipv6 IPv6 representation.
61 * @param port destination port
62 * @param rxstr generated regex, must be at least #GNUNET_TUN_IPV6_REGEXLEN
66 GNUNET_TUN_ipv6toregexsearch (const struct in6_addr *ipv6,
72 addr = (const uint32_t *) ipv6;
73 GNUNET_snprintf (rxstr,
74 GNUNET_TUN_IPV6_REGEXLEN,
75 "6-%04X-%08X%08X%08X%08X",
85 * Convert the given 4-bit (!) number to a regex.
87 * @param value the value, only the lowest 4 bits will be looked at
88 * @param mask which bits in value are wildcards (any value)?
91 nibble_to_regex (uint8_t value,
100 return GNUNET_strdup (DOT);
103 GNUNET_asprintf (&ret,
104 "(%X|%X|%X|%X|%X|%X|%X|%X)",
116 GNUNET_asprintf (&ret,
125 GNUNET_asprintf (&ret,
132 GNUNET_asprintf (&ret,
138 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
139 _ ("Bad mask: %d\n"),
148 * Convert the given 16-bit number to a regex.
150 * @param value the value
151 * @param mask which bits in value are wildcards (any value)?
154 num_to_regex (uint16_t value,
157 const uint8_t *v = (const uint8_t *) &value;
158 const uint8_t *m = (const uint8_t *) &mask;
165 a = nibble_to_regex (v[0] >> 4, m[0] >> 4);
166 b = nibble_to_regex (v[0] & 15, m[0] & 15);
167 c = nibble_to_regex (v[1] >> 4, m[1] >> 4);
168 d = nibble_to_regex (v[1] & 15, m[1] & 15);
174 GNUNET_asprintf (&ret,
177 GNUNET_free_non_null (a);
178 GNUNET_free_non_null (b);
179 GNUNET_free_non_null (c);
180 GNUNET_free_non_null (d);
186 * Do we need to put parents around the given argument?
188 * @param arg part of a regular expression
189 * @return #GNUNET_YES if we should parens,
193 needs_parens (const char *arg)
201 for (off = 0; off < len; off++)
210 GNUNET_assert (op > 0);
228 * Compute port policy for the given range of
231 * @param start starting offset
232 * @param end end offset
233 * @param step increment level (power of 16)
234 * @param pp port policy to convert
235 * @return corresponding regex
238 compute_policy (unsigned int start,
241 const struct GNUNET_STRINGS_PortPolicy *pp)
244 char before[36]; /* 16 * 2 + 3 dots + 0-terminator */
245 char middlel[33]; /* 16 * 2 + 0-terminator */
246 char middleh[33]; /* 16 * 2 + 0-terminator */
247 char after[36]; /* 16 * 2 + 3 dots + 0-terminator */
248 char beforep[36 + 2]; /* 16 * 2 + 3 dots + 0-terminator + ()*/
249 char middlehp[33 + 2]; /* 16 * 2 + 0-terminator + () */
250 char middlelp[33 + 2]; /* 16 * 2 + 0-terminator + () */
251 char afterp[36 + 2]; /* 16 * 2 + 3 dots + 0-terminator + () */
252 char dots[5 * strlen (DOT)];
261 unsigned int start_port;
262 unsigned int end_port;
264 GNUNET_assert (GNUNET_YES == pp->negate_portrange);
265 start_port = pp->start_port;
268 end_port = pp->end_port;
269 GNUNET_assert ((end - start) / step <= 0xF);
274 for (i = start; i <= end; i += step)
276 GNUNET_snprintf (buf,
280 if (i / step < start_port / step)
281 strcat (before, buf);
282 else if (i / step > end_port / step)
284 else if (i / step == start_port / step)
285 strcat (middlel, buf);
286 else if (i / step == end_port / step)
287 strcat (middleh, buf);
289 if (strlen (before) > 0)
290 before[strlen (before) - 1] = '\0';
291 if (strlen (middlel) > 0)
292 middlel[strlen (middlel) - 1] = '\0';
293 if (strlen (middleh) > 0)
294 middleh[strlen (middleh) - 1] = '\0';
295 if (strlen (after) > 0)
296 after[strlen (after) - 1] = '\0';
297 if (needs_parens (before))
298 GNUNET_snprintf (beforep,
303 strcpy (beforep, before);
304 if (needs_parens (middlel))
305 GNUNET_snprintf (middlelp,
310 strcpy (middlelp, middlel);
311 if (needs_parens (middleh))
312 GNUNET_snprintf (middlehp,
317 strcpy (middlehp, middleh);
318 if (needs_parens (after))
319 GNUNET_snprintf (afterp,
324 strcpy (afterp, after);
326 for (xstep = step / 16; xstep > 0; xstep /= 16)
330 if (strlen (middlel) > 0)
331 recl = compute_policy ((start_port / step) * step,
332 (start_port / step) * step + step - 1,
336 recl = GNUNET_strdup ("");
337 if (strlen (middleh) > 0)
338 rech = compute_policy ((end_port / step) * step,
339 (end_port / step) * step + step - 1,
343 rech = GNUNET_strdup ("");
347 recl = GNUNET_strdup ("");
348 rech = GNUNET_strdup ("");
354 if (needs_parens (recl))
355 GNUNET_asprintf (&reclp,
359 reclp = GNUNET_strdup (recl);
360 if (needs_parens (rech))
361 GNUNET_asprintf (&rechp,
365 rechp = GNUNET_strdup (rech);
367 if ((strlen (middleh) > 0) &&
368 (strlen (rech) > 0) &&
369 (strlen (middlel) > 0) &&
372 GNUNET_asprintf (&middle,
379 else if ((strlen (middleh) > 0) &&
382 GNUNET_asprintf (&middle,
387 else if ((strlen (middlel) > 0) &&
390 GNUNET_asprintf (&middle,
397 middle = GNUNET_strdup ("");
399 if ((strlen (before) > 0) &&
400 (strlen (after) > 0))
402 if (strlen (dots) > 0)
404 if (strlen (middle) > 0)
405 GNUNET_asprintf (&ret,
411 GNUNET_asprintf (&ret,
419 if (strlen (middle) > 0)
420 GNUNET_asprintf (&ret,
426 GNUNET_asprintf (&ret,
431 GNUNET_asprintf (&ret,
437 else if (strlen (before) > 0)
439 if (strlen (dots) > 0)
441 if (strlen (middle) > 0)
442 GNUNET_asprintf (&ret,
447 GNUNET_asprintf (&ret,
453 if (strlen (middle) > 0)
454 GNUNET_asprintf (&ret,
459 GNUNET_asprintf (&ret,
464 else if (strlen (after) > 0)
466 if (strlen (dots) > 0)
468 if (strlen (middle) > 0)
469 GNUNET_asprintf (&ret,
474 GNUNET_asprintf (&ret,
480 if (strlen (middle) > 0)
481 GNUNET_asprintf (&ret,
486 GNUNET_asprintf (&ret,
491 else if (strlen (middle) > 0)
493 GNUNET_asprintf (&ret,
499 ret = GNUNET_strdup ("");
501 GNUNET_free (middle);
511 * Convert a port policy to a regular expression. Note: this is a
512 * very simplistic implementation, we might want to consider doing
513 * something more sophisiticated (resulting in smaller regular
514 * expressions) at a later time.
516 * @param pp port policy to convert
517 * @return NULL on error
520 port_to_regex (const struct GNUNET_STRINGS_PortPolicy *pp)
528 if ((0 == pp->start_port) ||
529 ((1 == pp->start_port) &&
530 (0xFFFF == pp->end_port) &&
531 (GNUNET_NO == pp->negate_portrange)))
532 return GNUNET_strdup (DOT DOT DOT DOT);
533 if ((pp->start_port == pp->end_port) &&
534 (GNUNET_NO == pp->negate_portrange))
536 GNUNET_asprintf (&ret,
541 if (pp->end_port < pp->start_port)
544 if (GNUNET_YES == pp->negate_portrange)
546 ret = compute_policy (0, 0xFFFF, 0x1000, pp);
550 cnt = pp->end_port - pp->start_port + 1;
551 reg = GNUNET_malloc (cnt * 5 + 1);
553 for (i = 1; i <= 0xFFFF; i++)
555 if ((i >= pp->start_port) && (i <= pp->end_port))
559 GNUNET_snprintf (pos,
566 GNUNET_snprintf (pos,
574 GNUNET_asprintf (&ret,
584 * Convert an address (IPv4 or IPv6) to a regex.
586 * @param addr address
587 * @param mask network mask
588 * @param len number of bytes in @a addr and @a mask
589 * @return NULL on error, otherwise regex for the address
592 address_to_regex (const void *addr,
596 const uint16_t *a = addr;
597 const uint16_t *m = mask;
604 GNUNET_assert (1 != (len % 2));
605 for (i = 0; i < len / 2; i++)
607 reg = num_to_regex (a[i], m[i]);
610 GNUNET_free_non_null (ret);
619 GNUNET_asprintf (&tmp,
632 * Convert a single line of an IPv4 policy to a regular expression.
634 * @param v4 line to convert
635 * @return NULL on error
638 ipv4_to_regex (const struct GNUNET_STRINGS_IPv4NetworkPolicy *v4)
644 reg = address_to_regex (&v4->network,
646 sizeof(struct in_addr));
649 pp = port_to_regex (&v4->pp);
655 GNUNET_asprintf (&ret,
665 * Convert a single line of an IPv4 policy to a regular expression.
667 * @param v6 line to convert
668 * @return NULL on error
671 ipv6_to_regex (const struct GNUNET_STRINGS_IPv6NetworkPolicy *v6)
677 reg = address_to_regex (&v6->network,
679 sizeof(struct in6_addr));
682 pp = port_to_regex (&v6->pp);
688 GNUNET_asprintf (&ret,
698 * Convert an exit policy to a regular expression. The exit policy
699 * specifies a set of subnets this peer is willing to serve as an
700 * exit for; the resulting regular expression will match the
701 * IPv4 address strings as returned by #GNUNET_TUN_ipv4toregexsearch().
703 * @param policy exit policy specification
704 * @return regular expression, NULL on error
707 GNUNET_TUN_ipv4policy2regex (const char *policy)
709 struct GNUNET_STRINGS_IPv4NetworkPolicy *np;
715 np = GNUNET_STRINGS_parse_ipv4_policy (policy);
719 for (i = 0; (0 == i) || (0 != np[i].network.s_addr); i++)
721 line = ipv4_to_regex (&np[i]);
724 GNUNET_free_non_null (reg);
734 GNUNET_asprintf (&tmp,
741 if (0 == np[i].network.s_addr)
750 * Convert an exit policy to a regular expression. The exit policy
751 * specifies a set of subnets this peer is willing to serve as an
752 * exit for; the resulting regular expression will match the
753 * IPv6 address strings as returned by #GNUNET_TUN_ipv6toregexsearch().
755 * @param policy exit policy specification
756 * @return regular expression, NULL on error
759 GNUNET_TUN_ipv6policy2regex (const char *policy)
761 struct in6_addr zero;
762 struct GNUNET_STRINGS_IPv6NetworkPolicy *np;
768 np = GNUNET_STRINGS_parse_ipv6_policy (policy);
772 memset (&zero, 0, sizeof(struct in6_addr));
773 for (i = 0; (0 == i) || (0 != memcmp (&zero, &np[i].network, sizeof(struct
777 line = ipv6_to_regex (&np[i]);
780 GNUNET_free_non_null (reg);
790 GNUNET_asprintf (&tmp,
797 if (0 == memcmp (&zero, &np[i].network, sizeof(struct in6_addr)))
806 * Hash the service name of a hosted service to the
807 * hash code that is used to identify the service on
810 * @param service_name a string
811 * @param hc corresponding hash
814 GNUNET_TUN_service_name_to_hash (const char *service_name,
815 struct GNUNET_HashCode *hc)
817 GNUNET_CRYPTO_hash (service_name,
818 strlen (service_name),
824 * Compute the CADET port given a service descriptor
825 * (returned from #GNUNET_TUN_service_name_to_hash) and
826 * a TCP/UDP port @a ip_port.
828 * @param desc service shared secret
829 * @param ip_port TCP/UDP port, use 0 for ICMP
830 * @param[out] cadet_port CADET port to use
833 GNUNET_TUN_compute_service_cadet_port (const struct GNUNET_HashCode *desc,
835 struct GNUNET_HashCode *cadet_port)
837 uint16_t be_port = htons (ip_port);
840 GNUNET_memcpy (cadet_port,