aboutsummaryrefslogtreecommitdiff
path: root/src/util/regex.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/regex.c')
-rw-r--r--src/util/regex.c834
1 files changed, 834 insertions, 0 deletions
diff --git a/src/util/regex.c b/src/util/regex.c
new file mode 100644
index 000000000..7565a9eac
--- /dev/null
+++ b/src/util/regex.c
@@ -0,0 +1,834 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2012, 2013, 2015 GNUnet e.V.
4
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.
9
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.
14
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/>.
17*/
18/**
19 * @file src/tun/regex.c
20 * @brief functions to convert IP networks to regexes
21 * @author Maximilian Szengel
22 * @author Christian Grothoff
23 */
24#include "platform.h"
25#include "gnunet_util_lib.h"
26#include "gnunet_tun_lib.h"
27
28/**
29 * 'wildcard', matches all possible values (for HEX encoding).
30 */
31#define DOT "(0|1|2|3|4|5|6|7|8|9|A|B|C|D|E|F)"
32
33
34/**
35 * Create a regex in @a rxstr from the given @a ip and @a netmask.
36 *
37 * @param ip IPv4 representation.
38 * @param port destination port
39 * @param rxstr generated regex, must be at least #GNUNET_TUN_IPV4_REGEXLEN
40 * bytes long.
41 */
42void
43GNUNET_TUN_ipv4toregexsearch (const struct in_addr *ip,
44 uint16_t port,
45 char *rxstr)
46{
47 GNUNET_snprintf (rxstr,
48 GNUNET_TUN_IPV4_REGEXLEN,
49 "4-%04X-%08X",
50 (unsigned int) port,
51 ntohl (ip->s_addr));
52}
53
54
55/**
56 * Create a regex in @a rxstr from the given @a ipv6 and @a prefixlen.
57 *
58 * @param ipv6 IPv6 representation.
59 * @param port destination port
60 * @param rxstr generated regex, must be at least #GNUNET_TUN_IPV6_REGEXLEN
61 * bytes long.
62 */
63void
64GNUNET_TUN_ipv6toregexsearch (const struct in6_addr *ipv6,
65 uint16_t port,
66 char *rxstr)
67{
68 const uint32_t *addr;
69
70 addr = (const uint32_t *) ipv6;
71 GNUNET_snprintf (rxstr,
72 GNUNET_TUN_IPV6_REGEXLEN,
73 "6-%04X-%08X%08X%08X%08X",
74 (unsigned int) port,
75 ntohl (addr[0]),
76 ntohl (addr[1]),
77 ntohl (addr[2]),
78 ntohl (addr[3]));
79}
80
81
82/**
83 * Convert the given 4-bit (!) number to a regex.
84 *
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)?
87 */
88static char *
89nibble_to_regex (uint8_t value,
90 uint8_t mask)
91{
92 char *ret;
93
94 value &= mask;
95 switch (mask)
96 {
97 case 0:
98 return GNUNET_strdup (DOT);
99 case 8:
100 GNUNET_asprintf (&ret,
101 "(%X|%X|%X|%X|%X|%X|%X|%X)",
102 value,
103 value + 1,
104 value + 2,
105 value + 3,
106 value + 4,
107 value + 5,
108 value + 6,
109 value + 7);
110 return ret;
111 case 12:
112 GNUNET_asprintf (&ret,
113 "(%X|%X|%X|%X)",
114 value,
115 value + 1,
116 value + 2,
117 value + 3);
118 return ret;
119 case 14:
120 GNUNET_asprintf (&ret,
121 "(%X|%X)",
122 value,
123 value + 1);
124 return ret;
125 case 15:
126 GNUNET_asprintf (&ret,
127 "%X",
128 value);
129 return ret;
130 default:
131 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
132 _("Bad mask: %d\n"),
133 mask);
134 GNUNET_break (0);
135 return NULL;
136 }
137}
138
139
140/**
141 * Convert the given 16-bit number to a regex.
142 *
143 * @param value the value
144 * @param mask which bits in value are wildcards (any value)?
145 */
146static char *
147num_to_regex (uint16_t value,
148 uint16_t mask)
149{
150 const uint8_t *v = (const uint8_t *) &value;
151 const uint8_t *m = (const uint8_t *) &mask;
152 char *a;
153 char *b;
154 char *c;
155 char *d;
156 char *ret;
157
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);
162 ret = NULL;
163 if ( (NULL != a) &&
164 (NULL != b) &&
165 (NULL != c) &&
166 (NULL != d) )
167 GNUNET_asprintf (&ret,
168 "%s%s%s%s",
169 a, b, c, d);
170 GNUNET_free_non_null (a);
171 GNUNET_free_non_null (b);
172 GNUNET_free_non_null (c);
173 GNUNET_free_non_null (d);
174 return ret;
175}
176
177
178/**
179 * Do we need to put parents around the given argument?
180 *
181 * @param arg part of a regular expression
182 * @return #GNUNET_YES if we should parens,
183 * #GNUNET_NO if not
184 */
185static int
186needs_parens (const char *arg)
187{
188 size_t off;
189 size_t len;
190 unsigned int op;
191
192 op = 0;
193 len = strlen (arg);
194 for (off=0;off<len;off++)
195 {
196 switch (arg[off])
197 {
198 case '(':
199 op++;
200 break;
201 case ')':
202 GNUNET_assert (op > 0);
203 op--;
204 break;
205 case '|':
206 if (0 == op)
207 return GNUNET_YES;
208 break;
209 default:
210 break;
211 }
212 }
213 return GNUNET_NO;
214}
215
216
217/**
218 * Compute port policy for the given range of
219 * port numbers.
220 *
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
226 */
227static char *
228compute_policy (unsigned int start,
229 unsigned int end,
230 unsigned int step,
231 const struct GNUNET_STRINGS_PortPolicy *pp)
232{
233 unsigned int i;
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)];
243 char buf[3];
244 char *middle;
245 char *ret;
246 unsigned int xstep;
247 char *recl;
248 char *rech;
249 char *reclp;
250 char *rechp;
251 unsigned int start_port;
252 unsigned int end_port;
253
254 GNUNET_assert (GNUNET_YES == pp->negate_portrange);
255 start_port = pp->start_port;
256 if (1 == start_port)
257 start_port = 0;
258 end_port = pp->end_port;
259 GNUNET_assert ((end - start) / step <= 0xF);
260 before[0] = '\0';
261 middlel[0] = '\0';
262 middleh[0] = '\0';
263 after[0] = '\0';
264 for (i=start;i<=end;i+=step)
265 {
266 GNUNET_snprintf (buf,
267 sizeof (buf),
268 "%X|",
269 (i - start) / step);
270 if (i / step < start_port / step)
271 strcat (before, buf);
272 else if (i / step > end_port / step)
273 strcat (after, buf);
274 else if (i / step == start_port / step)
275 strcat (middlel, buf);
276 else if (i / step == end_port / step)
277 strcat (middleh, buf);
278 }
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,
289 sizeof (beforep),
290 "(%s)",
291 before);
292 else
293 strcpy (beforep, before);
294 if (needs_parens (middlel))
295 GNUNET_snprintf (middlelp,
296 sizeof (middlelp),
297 "(%s)",
298 middlel);
299 else
300 strcpy (middlelp, middlel);
301 if (needs_parens (middleh))
302 GNUNET_snprintf (middlehp,
303 sizeof (middlehp),
304 "(%s)",
305 middleh);
306 else
307 strcpy (middlehp, middleh);
308 if (needs_parens (after))
309 GNUNET_snprintf (afterp,
310 sizeof (afterp),
311 "(%s)",
312 after);
313 else
314 strcpy (afterp, after);
315 dots[0] = '\0';
316 for (xstep=step/16;xstep>0;xstep/=16)
317 strcat (dots, DOT);
318 if (step >= 16)
319 {
320 if (strlen (middlel) > 0)
321 recl = compute_policy ((start_port / step) * step,
322 (start_port / step) * step + step - 1,
323 step / 16,
324 pp);
325 else
326 recl = GNUNET_strdup ("");
327 if (strlen (middleh) > 0)
328 rech = compute_policy ((end_port / step) * step,
329 (end_port / step) * step + step - 1,
330 step / 16,
331 pp);
332 else
333 rech = GNUNET_strdup ("");
334 }
335 else
336 {
337 recl = GNUNET_strdup ("");
338 rech = GNUNET_strdup ("");
339 middlel[0] = '\0';
340 middlelp[0] = '\0';
341 middleh[0] = '\0';
342 middlehp[0] = '\0';
343 }
344 if (needs_parens (recl))
345 GNUNET_asprintf (&reclp,
346 "(%s)",
347 recl);
348 else
349 reclp = GNUNET_strdup (recl);
350 if (needs_parens (rech))
351 GNUNET_asprintf (&rechp,
352 "(%s)",
353 rech);
354 else
355 rechp = GNUNET_strdup (rech);
356
357 if ( (strlen (middleh) > 0) &&
358 (strlen (rech) > 0) &&
359 (strlen (middlel) > 0) &&
360 (strlen (recl) > 0) )
361 {
362 GNUNET_asprintf (&middle,
363 "%s%s|%s%s",
364 middlel,
365 reclp,
366 middleh,
367 rechp);
368 }
369 else if ( (strlen (middleh) > 0) &&
370 (strlen (rech) > 0) )
371 {
372 GNUNET_asprintf (&middle,
373 "%s%s",
374 middleh,
375 rechp);
376 }
377 else if ( (strlen (middlel) > 0) &&
378 (strlen (recl) > 0) )
379 {
380 GNUNET_asprintf (&middle,
381 "%s%s",
382 middlel,
383 reclp);
384 }
385 else
386 {
387 middle = GNUNET_strdup ("");
388 }
389 if ( (strlen(before) > 0) &&
390 (strlen(after) > 0) )
391 {
392 if (strlen (dots) > 0)
393 {
394 if (strlen (middle) > 0)
395 GNUNET_asprintf (&ret,
396 "(%s%s|%s|%s%s)",
397 beforep, dots,
398 middle,
399 afterp, dots);
400 else
401 GNUNET_asprintf (&ret,
402 "(%s|%s)%s",
403 beforep,
404 afterp,
405 dots);
406 }
407 else
408 {
409 if (strlen (middle) > 0)
410 GNUNET_asprintf (&ret,
411 "(%s|%s|%s)",
412 before,
413 middle,
414 after);
415 else if (1 == step)
416 GNUNET_asprintf (&ret,
417 "%s|%s",
418 before,
419 after);
420 else
421 GNUNET_asprintf (&ret,
422 "(%s|%s)",
423 before,
424 after);
425 }
426 }
427 else if (strlen (before) > 0)
428 {
429 if (strlen (dots) > 0)
430 {
431 if (strlen (middle) > 0)
432 GNUNET_asprintf (&ret,
433 "(%s%s|%s)",
434 beforep, dots,
435 middle);
436 else
437 GNUNET_asprintf (&ret,
438 "%s%s",
439 beforep, dots);
440 }
441 else
442 {
443 if (strlen (middle) > 0)
444 GNUNET_asprintf (&ret,
445 "(%s|%s)",
446 before,
447 middle);
448 else
449 GNUNET_asprintf (&ret,
450 "%s",
451 before);
452 }
453 }
454 else if (strlen (after) > 0)
455 {
456 if (strlen (dots) > 0)
457 {
458 if (strlen (middle) > 0)
459 GNUNET_asprintf (&ret,
460 "(%s|%s%s)",
461 middle,
462 afterp, dots);
463 else
464 GNUNET_asprintf (&ret,
465 "%s%s",
466 afterp, dots);
467 }
468 else
469 {
470 if (strlen (middle) > 0)
471 GNUNET_asprintf (&ret,
472 "%s|%s",
473 middle,
474 after);
475 else
476 GNUNET_asprintf (&ret,
477 "%s",
478 after);
479 }
480 }
481 else if (strlen (middle) > 0)
482 {
483 GNUNET_asprintf (&ret,
484 "%s",
485 middle);
486 }
487 else
488 {
489 ret = GNUNET_strdup ("");
490 }
491 GNUNET_free (middle);
492 GNUNET_free (reclp);
493 GNUNET_free (rechp);
494 GNUNET_free (recl);
495 GNUNET_free (rech);
496 return ret;
497}
498
499
500/**
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.
505 *
506 * @param pp port policy to convert
507 * @return NULL on error
508 */
509static char *
510port_to_regex (const struct GNUNET_STRINGS_PortPolicy *pp)
511{
512 char *reg;
513 char *ret;
514 char *pos;
515 unsigned int i;
516 unsigned int cnt;
517
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))
525 {
526 GNUNET_asprintf (&ret,
527 "%04X",
528 pp->start_port);
529 return ret;
530 }
531 if (pp->end_port < pp->start_port)
532 return NULL;
533
534 if (GNUNET_YES == pp->negate_portrange)
535 {
536 ret = compute_policy (0, 0xFFFF, 0x1000, pp);
537 }
538 else
539 {
540 cnt = pp->end_port - pp->start_port + 1;
541 reg = GNUNET_malloc (cnt * 5 + 1);
542 pos = reg;
543 for (i=1;i<=0xFFFF;i++)
544 {
545 if ( (i >= pp->start_port) && (i <= pp->end_port) )
546 {
547 if (pos == reg)
548 {
549 GNUNET_snprintf (pos,
550 5,
551 "%04X",
552 i);
553 }
554 else
555 {
556 GNUNET_snprintf (pos,
557 6,
558 "|%04X",
559 i);
560 }
561 pos += strlen (pos);
562 }
563 }
564 GNUNET_asprintf (&ret,
565 "(%s)",
566 reg);
567 GNUNET_free (reg);
568 }
569 return ret;
570}
571
572
573/**
574 * Convert an address (IPv4 or IPv6) to a regex.
575 *
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
580 */
581static char *
582address_to_regex (const void *addr,
583 const void *mask,
584 size_t len)
585{
586 const uint16_t *a = addr;
587 const uint16_t *m = mask;
588 char *ret;
589 char *tmp;
590 char *reg;
591 unsigned int i;
592
593 ret = NULL;
594 GNUNET_assert (1 != (len % 2));
595 for (i=0;i<len / 2;i++)
596 {
597 reg = num_to_regex (a[i], m[i]);
598 if (NULL == reg)
599 {
600 GNUNET_free_non_null (ret);
601 return NULL;
602 }
603 if (NULL == ret)
604 {
605 ret = reg;
606 }
607 else
608 {
609 GNUNET_asprintf (&tmp,
610 "%s%s",
611 ret, reg);
612 GNUNET_free (ret);
613 GNUNET_free (reg);
614 ret = tmp;
615 }
616 }
617 return ret;
618}
619
620
621/**
622 * Convert a single line of an IPv4 policy to a regular expression.
623 *
624 * @param v4 line to convert
625 * @return NULL on error
626 */
627static char *
628ipv4_to_regex (const struct GNUNET_STRINGS_IPv4NetworkPolicy *v4)
629{
630 char *reg;
631 char *pp;
632 char *ret;
633
634 reg = address_to_regex (&v4->network,
635 &v4->netmask,
636 sizeof (struct in_addr));
637 if (NULL == reg)
638 return NULL;
639 pp = port_to_regex (&v4->pp);
640 if (NULL == pp)
641 {
642 GNUNET_free (reg);
643 return NULL;
644 }
645 GNUNET_asprintf (&ret,
646 "4-%s-%s",
647 pp, reg);
648 GNUNET_free (pp);
649 GNUNET_free (reg);
650 return ret;
651}
652
653
654/**
655 * Convert a single line of an IPv4 policy to a regular expression.
656 *
657 * @param v6 line to convert
658 * @return NULL on error
659 */
660static char *
661ipv6_to_regex (const struct GNUNET_STRINGS_IPv6NetworkPolicy *v6)
662{
663 char *reg;
664 char *pp;
665 char *ret;
666
667 reg = address_to_regex (&v6->network,
668 &v6->netmask,
669 sizeof (struct in6_addr));
670 if (NULL == reg)
671 return NULL;
672 pp = port_to_regex (&v6->pp);
673 if (NULL == pp)
674 {
675 GNUNET_free (reg);
676 return NULL;
677 }
678 GNUNET_asprintf (&ret,
679 "6-%s-%s",
680 pp, reg);
681 GNUNET_free (pp);
682 GNUNET_free (reg);
683 return ret;
684}
685
686
687/**
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().
692 *
693 * @param policy exit policy specification
694 * @return regular expression, NULL on error
695 */
696char *
697GNUNET_TUN_ipv4policy2regex (const char *policy)
698{
699 struct GNUNET_STRINGS_IPv4NetworkPolicy *np;
700 char *reg;
701 char *tmp;
702 char *line;
703 unsigned int i;
704
705 np = GNUNET_STRINGS_parse_ipv4_policy (policy);
706 if (NULL == np)
707 return NULL;
708 reg = NULL;
709 for (i=0; (0 == i) || (0 != np[i].network.s_addr); i++)
710 {
711 line = ipv4_to_regex (&np[i]);
712 if (NULL == line)
713 {
714 GNUNET_free_non_null (reg);
715 GNUNET_free (np);
716 return NULL;
717 }
718 if (NULL == reg)
719 {
720 reg = line;
721 }
722 else
723 {
724 GNUNET_asprintf (&tmp,
725 "%s|(%s)",
726 reg, line);
727 GNUNET_free (reg);
728 GNUNET_free (line);
729 reg = tmp;
730 }
731 if (0 == np[i].network.s_addr)
732 break;
733 }
734 GNUNET_free (np);
735 return reg;
736}
737
738
739/**
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().
744 *
745 * @param policy exit policy specification
746 * @return regular expression, NULL on error
747 */
748char *
749GNUNET_TUN_ipv6policy2regex (const char *policy)
750{
751 struct in6_addr zero;
752 struct GNUNET_STRINGS_IPv6NetworkPolicy *np;
753 char *reg;
754 char *tmp;
755 char *line;
756 unsigned int i;
757
758 np = GNUNET_STRINGS_parse_ipv6_policy (policy);
759 if (NULL == np)
760 return NULL;
761 reg = NULL;
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++)
764 {
765 line = ipv6_to_regex (&np[i]);
766 if (NULL == line)
767 {
768 GNUNET_free_non_null (reg);
769 GNUNET_free (np);
770 return NULL;
771 }
772 if (NULL == reg)
773 {
774 reg = line;
775 }
776 else
777 {
778 GNUNET_asprintf (&tmp,
779 "%s|(%s)",
780 reg, line);
781 GNUNET_free (reg);
782 GNUNET_free (line);
783 reg = tmp;
784 }
785 if (0 == memcmp (&zero, &np[i].network, sizeof (struct in6_addr)))
786 break;
787 }
788 GNUNET_free (np);
789 return reg;
790}
791
792
793/**
794 * Hash the service name of a hosted service to the
795 * hash code that is used to identify the service on
796 * the network.
797 *
798 * @param service_name a string
799 * @param hc corresponding hash
800 */
801void
802GNUNET_TUN_service_name_to_hash (const char *service_name,
803 struct GNUNET_HashCode *hc)
804{
805 GNUNET_CRYPTO_hash (service_name,
806 strlen (service_name),
807 hc);
808}
809
810
811/**
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.
815 *
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
819 */
820void
821GNUNET_TUN_compute_service_cadet_port (const struct GNUNET_HashCode *desc,
822 uint16_t ip_port,
823 struct GNUNET_HashCode *cadet_port)
824{
825 uint16_t be_port = htons (ip_port);
826
827 *cadet_port = *desc;
828 GNUNET_memcpy (cadet_port,
829 &be_port,
830 sizeof (uint16_t));
831}
832
833
834/* end of regex.c */