Revert "integrate dnsparser and dnsstub and tun with libgnunetutil"
[oweals/gnunet.git] / src / tun / regex.c
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  */
42 void
43 GNUNET_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  */
63 void
64 GNUNET_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  */
88 static char *
89 nibble_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  */
146 static char *
147 num_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  */
185 static int
186 needs_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  */
227 static char *
228 compute_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  */
509 static char *
510 port_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  */
581 static char *
582 address_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  */
627 static char *
628 ipv4_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  */
660 static char *
661 ipv6_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  */
696 char *
697 GNUNET_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  */
748 char *
749 GNUNET_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  */
801 void
802 GNUNET_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  */
820 void
821 GNUNET_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 */