2 This file is part of GNUnet
3 (C) 2012, 2013 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
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"
32 * Create a regex in @a rxstr from the given @a ip and @a netmask.
34 * @param ip IPv4 representation.
35 * @param port destination port
36 * @param rxstr generated regex, must be at least #GNUNET_TUN_IPV4_REGEXLEN
40 GNUNET_TUN_ipv4toregexsearch (const struct in_addr *ip,
44 GNUNET_snprintf (rxstr,
45 GNUNET_TUN_IPV4_REGEXLEN,
53 * Create a regex in @a rxstr from the given @a ipv6 and @a prefixlen.
55 * @param ipv6 IPv6 representation.
56 * @param port destination port
57 * @param rxstr generated regex, must be at least #GNUNET_TUN_IPV6_REGEXLEN
61 GNUNET_TUN_ipv6toregexsearch (const struct in6_addr *ipv6,
67 addr = (const uint32_t *) ipv6;
68 GNUNET_snprintf (rxstr,
69 GNUNET_TUN_IPV6_REGEXLEN,
70 "6-%04X-%08X%08X%08X%08X",
80 * Convert the given 4-bit (!) number to a regex.
82 * @param value the value, only the lowest 4 bits will be looked at
83 * @param mask which bits in value are wildcards (any value)?
86 nibble_to_regex (uint8_t value,
95 return GNUNET_strdup ("."); /* wildcard */
97 GNUNET_asprintf (&ret,
98 "(%X|%X|%X|%X|%X|%X|%X|%X)",
109 GNUNET_asprintf (&ret,
117 GNUNET_asprintf (&ret,
123 GNUNET_asprintf (&ret,
128 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
138 * Convert the given 16-bit number to a regex.
140 * @param value the value
141 * @param mask which bits in value are wildcards (any value)?
144 num_to_regex (uint16_t value,
147 const uint8_t *v = (const uint8_t *) &value;
148 const uint8_t *m = (const uint8_t *) &mask;
155 a = nibble_to_regex (v[0] >> 4, m[0] >> 4);
156 b = nibble_to_regex (v[0] & 15, m[0] & 15);
157 c = nibble_to_regex (v[1] >> 4, m[1] >> 4);
158 d = nibble_to_regex (v[1] & 15, m[1] & 15);
164 GNUNET_asprintf (&ret,
167 GNUNET_free_non_null (a);
168 GNUNET_free_non_null (b);
169 GNUNET_free_non_null (c);
170 GNUNET_free_non_null (d);
176 * Do we need to put parents around the given argument?
178 * @param arg part of a regular expression
179 * @return #GNUNET_YES if we should parens,
183 needs_parens (const char *arg)
191 for (off=0;off<len;off++)
199 GNUNET_assert (op > 0);
215 * Compute port policy for the given range of
218 * @param start starting offset
219 * @param end end offset
220 * @param step increment level (power of 16)
221 * @param pp port policy to convert
222 * @return corresponding regex
225 compute_policy (unsigned int start,
228 const struct GNUNET_STRINGS_PortPolicy *pp)
231 char before[36]; /* 16 * 2 + 3 dots + 0-terminator */
232 char middlel[33]; /* 16 * 2 + 0-terminator */
233 char middleh[33]; /* 16 * 2 + 0-terminator */
234 char after[36]; /* 16 * 2 + 3 dots + 0-terminator */
235 char beforep[36+2]; /* 16 * 2 + 3 dots + 0-terminator + ()*/
236 char middlehp[33+2]; /* 16 * 2 + 0-terminator + () */
237 char middlelp[33+2]; /* 16 * 2 + 0-terminator + () */
238 char afterp[36+2]; /* 16 * 2 + 3 dots + 0-terminator + () */
248 unsigned int start_port;
249 unsigned int end_port;
251 GNUNET_assert (GNUNET_YES == pp->negate_portrange);
252 start_port = pp->start_port;
255 end_port = pp->end_port;
256 GNUNET_assert ((end - start) / step <= 0xF);
261 for (i=start;i<=end;i+=step)
263 GNUNET_snprintf (buf,
267 if (i / step < start_port / step)
268 strcat (before, buf);
269 else if (i / step > end_port / step)
271 else if (i / step == start_port / step)
272 strcat (middlel, buf);
273 else if (i / step == end_port / step)
274 strcat (middleh, buf);
276 if (strlen (before) > 0)
277 before[strlen (before)-1] = '\0';
278 if (strlen (middlel) > 0)
279 middlel[strlen (middlel)-1] = '\0';
280 if (strlen (middleh) > 0)
281 middleh[strlen (middleh)-1] = '\0';
282 if (strlen (after) > 0)
283 after[strlen (after)-1] = '\0';
284 if (needs_parens (before))
285 GNUNET_snprintf (beforep,
290 strcpy (beforep, before);
291 if (needs_parens (middlel))
292 GNUNET_snprintf (middlelp,
297 strcpy (middlelp, middlel);
298 if (needs_parens (middleh))
299 GNUNET_snprintf (middlehp,
304 strcpy (middlehp, middleh);
305 if (needs_parens (after))
306 GNUNET_snprintf (afterp,
311 strcpy (afterp, after);
313 for (xstep=step/16;xstep>0;xstep/=16)
317 if (strlen (middlel) > 0)
318 recl = compute_policy ((start_port / step) * step,
319 (start_port / step) * step + step - 1,
323 recl = GNUNET_strdup ("");
324 if (strlen (middleh) > 0)
325 rech = compute_policy ((end_port / step) * step,
326 (end_port / step) * step + step - 1,
330 rech = GNUNET_strdup ("");
334 recl = GNUNET_strdup ("");
335 rech = GNUNET_strdup ("");
341 if (needs_parens (recl))
342 GNUNET_asprintf (&reclp,
346 reclp = GNUNET_strdup (recl);
347 if (needs_parens (rech))
348 GNUNET_asprintf (&rechp,
352 rechp = GNUNET_strdup (rech);
354 if ( (strlen (middleh) > 0) &&
355 (strlen (rech) > 0) &&
356 (strlen (middlel) > 0) &&
357 (strlen (recl) > 0) )
359 GNUNET_asprintf (&middle,
366 else if ( (strlen (middleh) > 0) &&
367 (strlen (rech) > 0) )
369 GNUNET_asprintf (&middle,
374 else if ( (strlen (middlel) > 0) &&
375 (strlen (recl) > 0) )
377 GNUNET_asprintf (&middle,
384 middle = GNUNET_strdup ("");
386 if ( (strlen(before) > 0) &&
387 (strlen(after) > 0) )
389 if (strlen (dots) > 0)
391 if (strlen (middle) > 0)
392 GNUNET_asprintf (&ret,
398 GNUNET_asprintf (&ret,
406 if (strlen (middle) > 0)
407 GNUNET_asprintf (&ret,
413 GNUNET_asprintf (&ret,
418 GNUNET_asprintf (&ret,
424 else if (strlen (before) > 0)
426 if (strlen (dots) > 0)
428 if (strlen (middle) > 0)
429 GNUNET_asprintf (&ret,
434 GNUNET_asprintf (&ret,
440 if (strlen (middle) > 0)
441 GNUNET_asprintf (&ret,
446 GNUNET_asprintf (&ret,
451 else if (strlen (after) > 0)
453 if (strlen (dots) > 0)
455 if (strlen (middle) > 0)
456 GNUNET_asprintf (&ret,
461 GNUNET_asprintf (&ret,
467 if (strlen (middle) > 0)
468 GNUNET_asprintf (&ret,
473 GNUNET_asprintf (&ret,
478 else if (strlen (middle) > 0)
480 GNUNET_asprintf (&ret,
486 ret = GNUNET_strdup ("");
488 GNUNET_free (middle);
498 * Convert a port policy to a regular expression. Note: this is a
499 * very simplistic implementation, we might want to consider doing
500 * something more sophisiticated (resulting in smaller regular
501 * expressions) at a later time.
503 * @param pp port policy to convert
504 * @return NULL on error
507 port_to_regex (const struct GNUNET_STRINGS_PortPolicy *pp)
515 if ( (0 == pp->start_port) ||
516 ( (1 == pp->start_port) &&
517 (0xFFFF == pp->end_port) &&
518 (GNUNET_NO == pp->negate_portrange)) )
519 return GNUNET_strdup ("....");
520 if ( (pp->start_port == pp->end_port) &&
521 (GNUNET_NO == pp->negate_portrange))
523 GNUNET_asprintf (&ret,
528 if (pp->end_port < pp->start_port)
531 if (GNUNET_YES == pp->negate_portrange)
533 ret = compute_policy (0, 0xFFFF, 0x1000, pp);
537 cnt = pp->end_port - pp->start_port + 1;
538 reg = GNUNET_malloc (cnt * 5 + 1);
540 for (i=1;i<=0xFFFF;i++)
542 if ( (i >= pp->start_port) && (i <= pp->end_port) )
546 GNUNET_snprintf (pos,
553 GNUNET_snprintf (pos,
561 GNUNET_asprintf (&ret,
571 * Convert an address (IPv4 or IPv6) to a regex.
573 * @param addr address
574 * @param mask network mask
575 * @param len number of bytes in @a addr and @a mask
576 * @return NULL on error, otherwise regex for the address
579 address_to_regex (const void *addr,
583 const uint16_t *a = addr;
584 const uint16_t *m = mask;
591 GNUNET_assert (1 != (len % 2));
592 for (i=0;i<len / 2;i++)
594 reg = num_to_regex (a[i], m[i]);
597 GNUNET_free_non_null (ret);
606 GNUNET_asprintf (&tmp,
619 * Convert a single line of an IPv4 policy to a regular expression.
621 * @param v4 line to convert
622 * @return NULL on error
625 ipv4_to_regex (const struct GNUNET_STRINGS_IPv4NetworkPolicy *v4)
631 reg = address_to_regex (&v4->network,
633 sizeof (struct in_addr));
636 pp = port_to_regex (&v4->pp);
642 GNUNET_asprintf (&ret,
652 * Convert a single line of an IPv4 policy to a regular expression.
654 * @param v6 line to convert
655 * @return NULL on error
658 ipv6_to_regex (const struct GNUNET_STRINGS_IPv6NetworkPolicy *v6)
664 reg = address_to_regex (&v6->network,
666 sizeof (struct in6_addr));
669 pp = port_to_regex (&v6->pp);
675 GNUNET_asprintf (&ret,
685 * Convert an exit policy to a regular expression. The exit policy
686 * specifies a set of subnets this peer is willing to serve as an
687 * exit for; the resulting regular expression will match the
688 * IPv4 address strings as returned by 'GNUNET_TUN_ipv4toregexsearch'.
690 * @param policy exit policy specification
691 * @return regular expression, NULL on error
694 GNUNET_TUN_ipv4policy2regex (const char *policy)
696 struct GNUNET_STRINGS_IPv4NetworkPolicy *np;
702 np = GNUNET_STRINGS_parse_ipv4_policy (policy);
706 for (i=0; (0 == i) || (0 != np[i].network.s_addr); i++)
708 line = ipv4_to_regex (&np[i]);
711 GNUNET_free_non_null (reg);
721 GNUNET_asprintf (&tmp,
728 if (0 == np[i].network.s_addr)
737 * Convert an exit policy to a regular expression. The exit policy
738 * specifies a set of subnets this peer is willing to serve as an
739 * exit for; the resulting regular expression will match the
740 * IPv6 address strings as returned by #GNUNET_TUN_ipv6toregexsearch().
742 * @param policy exit policy specification
743 * @return regular expression, NULL on error
746 GNUNET_TUN_ipv6policy2regex (const char *policy)
748 struct in6_addr zero;
749 struct GNUNET_STRINGS_IPv6NetworkPolicy *np;
755 np = GNUNET_STRINGS_parse_ipv6_policy (policy);
759 memset (&zero, 0, sizeof (struct in6_addr));
760 for (i=0; (0 == i) || (0 != memcmp (&zero, &np[i].network, sizeof (struct in6_addr))); i++)
762 line = ipv6_to_regex (&np[i]);
765 GNUNET_free_non_null (reg);
775 GNUNET_asprintf (&tmp,
782 if (0 == memcmp (&zero, &np[i].network, sizeof (struct in6_addr)))
791 * Hash the service name of a hosted service to the
792 * hash code that is used to identify the service on
795 * @param service_name a string
796 * @param hc corresponding hash
799 GNUNET_TUN_service_name_to_hash (const char *service_name,
800 struct GNUNET_HashCode *hc)
802 GNUNET_CRYPTO_hash (service_name,
803 strlen (service_name),