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/>.
19 * @file src/tun/regex.c
20 * @brief functions to convert IP networks to regexes
21 * @author Maximilian Szengel
22 * @author Christian Grothoff
25 #include "gnunet_util_lib.h"
26 #include "gnunet_tun_lib.h"
29 * 'wildcard', matches all possible values (for HEX encoding).
31 #define DOT "(0|1|2|3|4|5|6|7|8|9|A|B|C|D|E|F)"
35 * Create a regex in @a rxstr from the given @a ip and @a netmask.
37 * @param ip IPv4 representation.
38 * @param port destination port
39 * @param rxstr generated regex, must be at least #GNUNET_TUN_IPV4_REGEXLEN
43 GNUNET_TUN_ipv4toregexsearch (const struct in_addr *ip,
47 GNUNET_snprintf (rxstr,
48 GNUNET_TUN_IPV4_REGEXLEN,
56 * Create a regex in @a rxstr from the given @a ipv6 and @a prefixlen.
58 * @param ipv6 IPv6 representation.
59 * @param port destination port
60 * @param rxstr generated regex, must be at least #GNUNET_TUN_IPV6_REGEXLEN
64 GNUNET_TUN_ipv6toregexsearch (const struct in6_addr *ipv6,
70 addr = (const uint32_t *) ipv6;
71 GNUNET_snprintf (rxstr,
72 GNUNET_TUN_IPV6_REGEXLEN,
73 "6-%04X-%08X%08X%08X%08X",
83 * Convert the given 4-bit (!) number to a regex.
85 * @param value the value, only the lowest 4 bits will be looked at
86 * @param mask which bits in value are wildcards (any value)?
89 nibble_to_regex (uint8_t value,
98 return GNUNET_strdup (DOT);
100 GNUNET_asprintf (&ret,
101 "(%X|%X|%X|%X|%X|%X|%X|%X)",
112 GNUNET_asprintf (&ret,
120 GNUNET_asprintf (&ret,
126 GNUNET_asprintf (&ret,
131 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
141 * Convert the given 16-bit number to a regex.
143 * @param value the value
144 * @param mask which bits in value are wildcards (any value)?
147 num_to_regex (uint16_t value,
150 const uint8_t *v = (const uint8_t *) &value;
151 const uint8_t *m = (const uint8_t *) &mask;
158 a = nibble_to_regex (v[0] >> 4, m[0] >> 4);
159 b = nibble_to_regex (v[0] & 15, m[0] & 15);
160 c = nibble_to_regex (v[1] >> 4, m[1] >> 4);
161 d = nibble_to_regex (v[1] & 15, m[1] & 15);
167 GNUNET_asprintf (&ret,
170 GNUNET_free_non_null (a);
171 GNUNET_free_non_null (b);
172 GNUNET_free_non_null (c);
173 GNUNET_free_non_null (d);
179 * Do we need to put parents around the given argument?
181 * @param arg part of a regular expression
182 * @return #GNUNET_YES if we should parens,
186 needs_parens (const char *arg)
194 for (off=0;off<len;off++)
202 GNUNET_assert (op > 0);
218 * Compute port policy for the given range of
221 * @param start starting offset
222 * @param end end offset
223 * @param step increment level (power of 16)
224 * @param pp port policy to convert
225 * @return corresponding regex
228 compute_policy (unsigned int start,
231 const struct GNUNET_STRINGS_PortPolicy *pp)
234 char before[36]; /* 16 * 2 + 3 dots + 0-terminator */
235 char middlel[33]; /* 16 * 2 + 0-terminator */
236 char middleh[33]; /* 16 * 2 + 0-terminator */
237 char after[36]; /* 16 * 2 + 3 dots + 0-terminator */
238 char beforep[36+2]; /* 16 * 2 + 3 dots + 0-terminator + ()*/
239 char middlehp[33+2]; /* 16 * 2 + 0-terminator + () */
240 char middlelp[33+2]; /* 16 * 2 + 0-terminator + () */
241 char afterp[36+2]; /* 16 * 2 + 3 dots + 0-terminator + () */
242 char dots[5 * strlen (DOT)];
251 unsigned int start_port;
252 unsigned int end_port;
254 GNUNET_assert (GNUNET_YES == pp->negate_portrange);
255 start_port = pp->start_port;
258 end_port = pp->end_port;
259 GNUNET_assert ((end - start) / step <= 0xF);
264 for (i=start;i<=end;i+=step)
266 GNUNET_snprintf (buf,
270 if (i / step < start_port / step)
271 strcat (before, buf);
272 else if (i / step > end_port / step)
274 else if (i / step == start_port / step)
275 strcat (middlel, buf);
276 else if (i / step == end_port / step)
277 strcat (middleh, buf);
279 if (strlen (before) > 0)
280 before[strlen (before)-1] = '\0';
281 if (strlen (middlel) > 0)
282 middlel[strlen (middlel)-1] = '\0';
283 if (strlen (middleh) > 0)
284 middleh[strlen (middleh)-1] = '\0';
285 if (strlen (after) > 0)
286 after[strlen (after)-1] = '\0';
287 if (needs_parens (before))
288 GNUNET_snprintf (beforep,
293 strcpy (beforep, before);
294 if (needs_parens (middlel))
295 GNUNET_snprintf (middlelp,
300 strcpy (middlelp, middlel);
301 if (needs_parens (middleh))
302 GNUNET_snprintf (middlehp,
307 strcpy (middlehp, middleh);
308 if (needs_parens (after))
309 GNUNET_snprintf (afterp,
314 strcpy (afterp, after);
316 for (xstep=step/16;xstep>0;xstep/=16)
320 if (strlen (middlel) > 0)
321 recl = compute_policy ((start_port / step) * step,
322 (start_port / step) * step + step - 1,
326 recl = GNUNET_strdup ("");
327 if (strlen (middleh) > 0)
328 rech = compute_policy ((end_port / step) * step,
329 (end_port / step) * step + step - 1,
333 rech = GNUNET_strdup ("");
337 recl = GNUNET_strdup ("");
338 rech = GNUNET_strdup ("");
344 if (needs_parens (recl))
345 GNUNET_asprintf (&reclp,
349 reclp = GNUNET_strdup (recl);
350 if (needs_parens (rech))
351 GNUNET_asprintf (&rechp,
355 rechp = GNUNET_strdup (rech);
357 if ( (strlen (middleh) > 0) &&
358 (strlen (rech) > 0) &&
359 (strlen (middlel) > 0) &&
360 (strlen (recl) > 0) )
362 GNUNET_asprintf (&middle,
369 else if ( (strlen (middleh) > 0) &&
370 (strlen (rech) > 0) )
372 GNUNET_asprintf (&middle,
377 else if ( (strlen (middlel) > 0) &&
378 (strlen (recl) > 0) )
380 GNUNET_asprintf (&middle,
387 middle = GNUNET_strdup ("");
389 if ( (strlen(before) > 0) &&
390 (strlen(after) > 0) )
392 if (strlen (dots) > 0)
394 if (strlen (middle) > 0)
395 GNUNET_asprintf (&ret,
401 GNUNET_asprintf (&ret,
409 if (strlen (middle) > 0)
410 GNUNET_asprintf (&ret,
416 GNUNET_asprintf (&ret,
421 GNUNET_asprintf (&ret,
427 else if (strlen (before) > 0)
429 if (strlen (dots) > 0)
431 if (strlen (middle) > 0)
432 GNUNET_asprintf (&ret,
437 GNUNET_asprintf (&ret,
443 if (strlen (middle) > 0)
444 GNUNET_asprintf (&ret,
449 GNUNET_asprintf (&ret,
454 else if (strlen (after) > 0)
456 if (strlen (dots) > 0)
458 if (strlen (middle) > 0)
459 GNUNET_asprintf (&ret,
464 GNUNET_asprintf (&ret,
470 if (strlen (middle) > 0)
471 GNUNET_asprintf (&ret,
476 GNUNET_asprintf (&ret,
481 else if (strlen (middle) > 0)
483 GNUNET_asprintf (&ret,
489 ret = GNUNET_strdup ("");
491 GNUNET_free (middle);
501 * Convert a port policy to a regular expression. Note: this is a
502 * very simplistic implementation, we might want to consider doing
503 * something more sophisiticated (resulting in smaller regular
504 * expressions) at a later time.
506 * @param pp port policy to convert
507 * @return NULL on error
510 port_to_regex (const struct GNUNET_STRINGS_PortPolicy *pp)
518 if ( (0 == pp->start_port) ||
519 ( (1 == pp->start_port) &&
520 (0xFFFF == pp->end_port) &&
521 (GNUNET_NO == pp->negate_portrange)) )
522 return GNUNET_strdup (DOT DOT DOT DOT);
523 if ( (pp->start_port == pp->end_port) &&
524 (GNUNET_NO == pp->negate_portrange))
526 GNUNET_asprintf (&ret,
531 if (pp->end_port < pp->start_port)
534 if (GNUNET_YES == pp->negate_portrange)
536 ret = compute_policy (0, 0xFFFF, 0x1000, pp);
540 cnt = pp->end_port - pp->start_port + 1;
541 reg = GNUNET_malloc (cnt * 5 + 1);
543 for (i=1;i<=0xFFFF;i++)
545 if ( (i >= pp->start_port) && (i <= pp->end_port) )
549 GNUNET_snprintf (pos,
556 GNUNET_snprintf (pos,
564 GNUNET_asprintf (&ret,
574 * Convert an address (IPv4 or IPv6) to a regex.
576 * @param addr address
577 * @param mask network mask
578 * @param len number of bytes in @a addr and @a mask
579 * @return NULL on error, otherwise regex for the address
582 address_to_regex (const void *addr,
586 const uint16_t *a = addr;
587 const uint16_t *m = mask;
594 GNUNET_assert (1 != (len % 2));
595 for (i=0;i<len / 2;i++)
597 reg = num_to_regex (a[i], m[i]);
600 GNUNET_free_non_null (ret);
609 GNUNET_asprintf (&tmp,
622 * Convert a single line of an IPv4 policy to a regular expression.
624 * @param v4 line to convert
625 * @return NULL on error
628 ipv4_to_regex (const struct GNUNET_STRINGS_IPv4NetworkPolicy *v4)
634 reg = address_to_regex (&v4->network,
636 sizeof (struct in_addr));
639 pp = port_to_regex (&v4->pp);
645 GNUNET_asprintf (&ret,
655 * Convert a single line of an IPv4 policy to a regular expression.
657 * @param v6 line to convert
658 * @return NULL on error
661 ipv6_to_regex (const struct GNUNET_STRINGS_IPv6NetworkPolicy *v6)
667 reg = address_to_regex (&v6->network,
669 sizeof (struct in6_addr));
672 pp = port_to_regex (&v6->pp);
678 GNUNET_asprintf (&ret,
688 * Convert an exit policy to a regular expression. The exit policy
689 * specifies a set of subnets this peer is willing to serve as an
690 * exit for; the resulting regular expression will match the
691 * IPv4 address strings as returned by #GNUNET_TUN_ipv4toregexsearch().
693 * @param policy exit policy specification
694 * @return regular expression, NULL on error
697 GNUNET_TUN_ipv4policy2regex (const char *policy)
699 struct GNUNET_STRINGS_IPv4NetworkPolicy *np;
705 np = GNUNET_STRINGS_parse_ipv4_policy (policy);
709 for (i=0; (0 == i) || (0 != np[i].network.s_addr); i++)
711 line = ipv4_to_regex (&np[i]);
714 GNUNET_free_non_null (reg);
724 GNUNET_asprintf (&tmp,
731 if (0 == np[i].network.s_addr)
740 * Convert an exit policy to a regular expression. The exit policy
741 * specifies a set of subnets this peer is willing to serve as an
742 * exit for; the resulting regular expression will match the
743 * IPv6 address strings as returned by #GNUNET_TUN_ipv6toregexsearch().
745 * @param policy exit policy specification
746 * @return regular expression, NULL on error
749 GNUNET_TUN_ipv6policy2regex (const char *policy)
751 struct in6_addr zero;
752 struct GNUNET_STRINGS_IPv6NetworkPolicy *np;
758 np = GNUNET_STRINGS_parse_ipv6_policy (policy);
762 memset (&zero, 0, sizeof (struct in6_addr));
763 for (i=0; (0 == i) || (0 != memcmp (&zero, &np[i].network, sizeof (struct in6_addr))); i++)
765 line = ipv6_to_regex (&np[i]);
768 GNUNET_free_non_null (reg);
778 GNUNET_asprintf (&tmp,
785 if (0 == memcmp (&zero, &np[i].network, sizeof (struct in6_addr)))
794 * Hash the service name of a hosted service to the
795 * hash code that is used to identify the service on
798 * @param service_name a string
799 * @param hc corresponding hash
802 GNUNET_TUN_service_name_to_hash (const char *service_name,
803 struct GNUNET_HashCode *hc)
805 GNUNET_CRYPTO_hash (service_name,
806 strlen (service_name),
812 * Compute the CADET port given a service descriptor
813 * (returned from #GNUNET_TUN_service_name_to_hash) and
814 * a TCP/UDP port @a ip_port.
816 * @param desc service shared secret
817 * @param ip_port TCP/UDP port, use 0 for ICMP
818 * @param[out] cadet_port CADET port to use
821 GNUNET_TUN_compute_service_cadet_port (const struct GNUNET_HashCode *desc,
823 struct GNUNET_HashCode *cadet_port)
825 uint16_t be_port = htons (ip_port);
828 GNUNET_memcpy (cadet_port,