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);
102 GNUNET_asprintf (&ret,
103 "(%X|%X|%X|%X|%X|%X|%X|%X)",
114 GNUNET_asprintf (&ret,
122 GNUNET_asprintf (&ret,
128 GNUNET_asprintf (&ret,
133 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
143 * Convert the given 16-bit number to a regex.
145 * @param value the value
146 * @param mask which bits in value are wildcards (any value)?
149 num_to_regex (uint16_t value,
152 const uint8_t *v = (const uint8_t *) &value;
153 const uint8_t *m = (const uint8_t *) &mask;
160 a = nibble_to_regex (v[0] >> 4, m[0] >> 4);
161 b = nibble_to_regex (v[0] & 15, m[0] & 15);
162 c = nibble_to_regex (v[1] >> 4, m[1] >> 4);
163 d = nibble_to_regex (v[1] & 15, m[1] & 15);
169 GNUNET_asprintf (&ret,
172 GNUNET_free_non_null (a);
173 GNUNET_free_non_null (b);
174 GNUNET_free_non_null (c);
175 GNUNET_free_non_null (d);
181 * Do we need to put parents around the given argument?
183 * @param arg part of a regular expression
184 * @return #GNUNET_YES if we should parens,
188 needs_parens (const char *arg)
196 for (off=0;off<len;off++)
204 GNUNET_assert (op > 0);
220 * Compute port policy for the given range of
223 * @param start starting offset
224 * @param end end offset
225 * @param step increment level (power of 16)
226 * @param pp port policy to convert
227 * @return corresponding regex
230 compute_policy (unsigned int start,
233 const struct GNUNET_STRINGS_PortPolicy *pp)
236 char before[36]; /* 16 * 2 + 3 dots + 0-terminator */
237 char middlel[33]; /* 16 * 2 + 0-terminator */
238 char middleh[33]; /* 16 * 2 + 0-terminator */
239 char after[36]; /* 16 * 2 + 3 dots + 0-terminator */
240 char beforep[36+2]; /* 16 * 2 + 3 dots + 0-terminator + ()*/
241 char middlehp[33+2]; /* 16 * 2 + 0-terminator + () */
242 char middlelp[33+2]; /* 16 * 2 + 0-terminator + () */
243 char afterp[36+2]; /* 16 * 2 + 3 dots + 0-terminator + () */
244 char dots[5 * strlen (DOT)];
253 unsigned int start_port;
254 unsigned int end_port;
256 GNUNET_assert (GNUNET_YES == pp->negate_portrange);
257 start_port = pp->start_port;
260 end_port = pp->end_port;
261 GNUNET_assert ((end - start) / step <= 0xF);
266 for (i=start;i<=end;i+=step)
268 GNUNET_snprintf (buf,
272 if (i / step < start_port / step)
273 strcat (before, buf);
274 else if (i / step > end_port / step)
276 else if (i / step == start_port / step)
277 strcat (middlel, buf);
278 else if (i / step == end_port / step)
279 strcat (middleh, buf);
281 if (strlen (before) > 0)
282 before[strlen (before)-1] = '\0';
283 if (strlen (middlel) > 0)
284 middlel[strlen (middlel)-1] = '\0';
285 if (strlen (middleh) > 0)
286 middleh[strlen (middleh)-1] = '\0';
287 if (strlen (after) > 0)
288 after[strlen (after)-1] = '\0';
289 if (needs_parens (before))
290 GNUNET_snprintf (beforep,
295 strcpy (beforep, before);
296 if (needs_parens (middlel))
297 GNUNET_snprintf (middlelp,
302 strcpy (middlelp, middlel);
303 if (needs_parens (middleh))
304 GNUNET_snprintf (middlehp,
309 strcpy (middlehp, middleh);
310 if (needs_parens (after))
311 GNUNET_snprintf (afterp,
316 strcpy (afterp, after);
318 for (xstep=step/16;xstep>0;xstep/=16)
322 if (strlen (middlel) > 0)
323 recl = compute_policy ((start_port / step) * step,
324 (start_port / step) * step + step - 1,
328 recl = GNUNET_strdup ("");
329 if (strlen (middleh) > 0)
330 rech = compute_policy ((end_port / step) * step,
331 (end_port / step) * step + step - 1,
335 rech = GNUNET_strdup ("");
339 recl = GNUNET_strdup ("");
340 rech = GNUNET_strdup ("");
346 if (needs_parens (recl))
347 GNUNET_asprintf (&reclp,
351 reclp = GNUNET_strdup (recl);
352 if (needs_parens (rech))
353 GNUNET_asprintf (&rechp,
357 rechp = GNUNET_strdup (rech);
359 if ( (strlen (middleh) > 0) &&
360 (strlen (rech) > 0) &&
361 (strlen (middlel) > 0) &&
362 (strlen (recl) > 0) )
364 GNUNET_asprintf (&middle,
371 else if ( (strlen (middleh) > 0) &&
372 (strlen (rech) > 0) )
374 GNUNET_asprintf (&middle,
379 else if ( (strlen (middlel) > 0) &&
380 (strlen (recl) > 0) )
382 GNUNET_asprintf (&middle,
389 middle = GNUNET_strdup ("");
391 if ( (strlen(before) > 0) &&
392 (strlen(after) > 0) )
394 if (strlen (dots) > 0)
396 if (strlen (middle) > 0)
397 GNUNET_asprintf (&ret,
403 GNUNET_asprintf (&ret,
411 if (strlen (middle) > 0)
412 GNUNET_asprintf (&ret,
418 GNUNET_asprintf (&ret,
423 GNUNET_asprintf (&ret,
429 else if (strlen (before) > 0)
431 if (strlen (dots) > 0)
433 if (strlen (middle) > 0)
434 GNUNET_asprintf (&ret,
439 GNUNET_asprintf (&ret,
445 if (strlen (middle) > 0)
446 GNUNET_asprintf (&ret,
451 GNUNET_asprintf (&ret,
456 else if (strlen (after) > 0)
458 if (strlen (dots) > 0)
460 if (strlen (middle) > 0)
461 GNUNET_asprintf (&ret,
466 GNUNET_asprintf (&ret,
472 if (strlen (middle) > 0)
473 GNUNET_asprintf (&ret,
478 GNUNET_asprintf (&ret,
483 else if (strlen (middle) > 0)
485 GNUNET_asprintf (&ret,
491 ret = GNUNET_strdup ("");
493 GNUNET_free (middle);
503 * Convert a port policy to a regular expression. Note: this is a
504 * very simplistic implementation, we might want to consider doing
505 * something more sophisiticated (resulting in smaller regular
506 * expressions) at a later time.
508 * @param pp port policy to convert
509 * @return NULL on error
512 port_to_regex (const struct GNUNET_STRINGS_PortPolicy *pp)
520 if ( (0 == pp->start_port) ||
521 ( (1 == pp->start_port) &&
522 (0xFFFF == pp->end_port) &&
523 (GNUNET_NO == pp->negate_portrange)) )
524 return GNUNET_strdup (DOT DOT DOT DOT);
525 if ( (pp->start_port == pp->end_port) &&
526 (GNUNET_NO == pp->negate_portrange))
528 GNUNET_asprintf (&ret,
533 if (pp->end_port < pp->start_port)
536 if (GNUNET_YES == pp->negate_portrange)
538 ret = compute_policy (0, 0xFFFF, 0x1000, pp);
542 cnt = pp->end_port - pp->start_port + 1;
543 reg = GNUNET_malloc (cnt * 5 + 1);
545 for (i=1;i<=0xFFFF;i++)
547 if ( (i >= pp->start_port) && (i <= pp->end_port) )
551 GNUNET_snprintf (pos,
558 GNUNET_snprintf (pos,
566 GNUNET_asprintf (&ret,
576 * Convert an address (IPv4 or IPv6) to a regex.
578 * @param addr address
579 * @param mask network mask
580 * @param len number of bytes in @a addr and @a mask
581 * @return NULL on error, otherwise regex for the address
584 address_to_regex (const void *addr,
588 const uint16_t *a = addr;
589 const uint16_t *m = mask;
596 GNUNET_assert (1 != (len % 2));
597 for (i=0;i<len / 2;i++)
599 reg = num_to_regex (a[i], m[i]);
602 GNUNET_free_non_null (ret);
611 GNUNET_asprintf (&tmp,
624 * Convert a single line of an IPv4 policy to a regular expression.
626 * @param v4 line to convert
627 * @return NULL on error
630 ipv4_to_regex (const struct GNUNET_STRINGS_IPv4NetworkPolicy *v4)
636 reg = address_to_regex (&v4->network,
638 sizeof (struct in_addr));
641 pp = port_to_regex (&v4->pp);
647 GNUNET_asprintf (&ret,
657 * Convert a single line of an IPv4 policy to a regular expression.
659 * @param v6 line to convert
660 * @return NULL on error
663 ipv6_to_regex (const struct GNUNET_STRINGS_IPv6NetworkPolicy *v6)
669 reg = address_to_regex (&v6->network,
671 sizeof (struct in6_addr));
674 pp = port_to_regex (&v6->pp);
680 GNUNET_asprintf (&ret,
690 * Convert an exit policy to a regular expression. The exit policy
691 * specifies a set of subnets this peer is willing to serve as an
692 * exit for; the resulting regular expression will match the
693 * IPv4 address strings as returned by #GNUNET_TUN_ipv4toregexsearch().
695 * @param policy exit policy specification
696 * @return regular expression, NULL on error
699 GNUNET_TUN_ipv4policy2regex (const char *policy)
701 struct GNUNET_STRINGS_IPv4NetworkPolicy *np;
707 np = GNUNET_STRINGS_parse_ipv4_policy (policy);
711 for (i=0; (0 == i) || (0 != np[i].network.s_addr); i++)
713 line = ipv4_to_regex (&np[i]);
716 GNUNET_free_non_null (reg);
726 GNUNET_asprintf (&tmp,
733 if (0 == np[i].network.s_addr)
742 * Convert an exit policy to a regular expression. The exit policy
743 * specifies a set of subnets this peer is willing to serve as an
744 * exit for; the resulting regular expression will match the
745 * IPv6 address strings as returned by #GNUNET_TUN_ipv6toregexsearch().
747 * @param policy exit policy specification
748 * @return regular expression, NULL on error
751 GNUNET_TUN_ipv6policy2regex (const char *policy)
753 struct in6_addr zero;
754 struct GNUNET_STRINGS_IPv6NetworkPolicy *np;
760 np = GNUNET_STRINGS_parse_ipv6_policy (policy);
764 memset (&zero, 0, sizeof (struct in6_addr));
765 for (i=0; (0 == i) || (0 != memcmp (&zero, &np[i].network, sizeof (struct in6_addr))); i++)
767 line = ipv6_to_regex (&np[i]);
770 GNUNET_free_non_null (reg);
780 GNUNET_asprintf (&tmp,
787 if (0 == memcmp (&zero, &np[i].network, sizeof (struct in6_addr)))
796 * Hash the service name of a hosted service to the
797 * hash code that is used to identify the service on
800 * @param service_name a string
801 * @param hc corresponding hash
804 GNUNET_TUN_service_name_to_hash (const char *service_name,
805 struct GNUNET_HashCode *hc)
807 GNUNET_CRYPTO_hash (service_name,
808 strlen (service_name),
814 * Compute the CADET port given a service descriptor
815 * (returned from #GNUNET_TUN_service_name_to_hash) and
816 * a TCP/UDP port @a ip_port.
818 * @param desc service shared secret
819 * @param ip_port TCP/UDP port, use 0 for ICMP
820 * @param[out] cadet_port CADET port to use
823 GNUNET_TUN_compute_service_cadet_port (const struct GNUNET_HashCode *desc,
825 struct GNUNET_HashCode *cadet_port)
827 uint16_t be_port = htons (ip_port);
830 GNUNET_memcpy (cadet_port,