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