Support normal socket (non-NSP) name lookups in resolver (for testing)
[oweals/gnunet.git] / src / tun / regex.c
1 /*
2      This file is part of GNUnet
3      (C) 2012, 2013 Christian Grothoff (and other contributing authors)
4
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.
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      General Public License for more details.
14
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.
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 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_tun_lib.h"
29
30
31 /**
32  * Create a regex in @a rxstr from the given @a ip and @a netmask.
33  *
34  * @param ip IPv4 representation.
35  * @param port destination port
36  * @param rxstr generated regex, must be at least #GNUNET_TUN_IPV4_REGEXLEN
37  *              bytes long.
38  */
39 void
40 GNUNET_TUN_ipv4toregexsearch (const struct in_addr *ip,
41                               uint16_t port,
42                               char *rxstr)
43 {
44   GNUNET_snprintf (rxstr,
45                    GNUNET_TUN_IPV4_REGEXLEN,
46                    "4-%04X-%08X",
47                    (unsigned int) port,
48                    ntohl (ip->s_addr));
49 }
50
51
52 /**
53  * Create a regex in @a rxstr from the given @a ipv6 and @a prefixlen.
54  *
55  * @param ipv6 IPv6 representation.
56  * @param port destination port
57  * @param rxstr generated regex, must be at least #GNUNET_TUN_IPV6_REGEXLEN
58  *              bytes long.
59  */
60 void
61 GNUNET_TUN_ipv6toregexsearch (const struct in6_addr *ipv6,
62                               uint16_t port,
63                               char *rxstr)
64 {
65   const uint32_t *addr;
66
67   addr = (const uint32_t *) ipv6;
68   GNUNET_snprintf (rxstr,
69                    GNUNET_TUN_IPV6_REGEXLEN,
70                    "6-%04X-%08X%08X%08X%08X",
71                    (unsigned int) port,
72                    ntohl (addr[0]),
73                    ntohl (addr[1]),
74                    ntohl (addr[2]),
75                    ntohl (addr[3]));
76 }
77
78
79 /**
80  * Convert the given 4-bit (!) number to a regex.
81  *
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)?
84  */
85 static char *
86 nibble_to_regex (uint8_t value,
87                  uint8_t mask)
88 {
89   char *ret;
90
91   value &= mask;
92   switch (mask)
93   {
94   case 0:
95     return GNUNET_strdup ("."); /* wildcard */
96   case 8:
97     GNUNET_asprintf (&ret,
98                      "(%X|%X|%X|%X|%X|%X|%X|%X)",
99                      value,
100                      value + 1,
101                      value + 2,
102                      value + 3,
103                      value + 4,
104                      value + 5,
105                      value + 6,
106                      value + 7);
107     return ret;
108   case 12:
109     GNUNET_asprintf (&ret,
110                      "(%X|%X|%X|%X)",
111                      value,
112                      value + 1,
113                      value + 2,
114                      value + 3);
115     return ret;
116   case 14:
117     GNUNET_asprintf (&ret,
118                      "(%X|%X)",
119                      value,
120                      value + 1);
121     return ret;
122   case 15:
123     GNUNET_asprintf (&ret,
124                      "%X",
125                      value);
126     return ret;
127   default:
128     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
129                 _("Bad mask: %d\n"),
130                 mask);
131     GNUNET_break (0);
132     return NULL;
133   }
134 }
135
136
137 /**
138  * Convert the given 16-bit number to a regex.
139  *
140  * @param value the value
141  * @param mask which bits in value are wildcards (any value)?
142  */
143 static char *
144 num_to_regex (uint16_t value,
145               uint16_t mask)
146 {
147   const uint8_t *v = (const uint8_t *) &value;
148   const uint8_t *m = (const uint8_t *) &mask;
149   char *a;
150   char *b;
151   char *c;
152   char *d;
153   char *ret;
154
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);
159   ret = NULL;
160   if ( (NULL != a) &&
161        (NULL != b) &&
162        (NULL != c) &&
163        (NULL != d) )
164     GNUNET_asprintf (&ret,
165                      "%s%s%s%s",
166                      a, b, c, d);
167   GNUNET_free_non_null (a);
168   GNUNET_free_non_null (b);
169   GNUNET_free_non_null (c);
170   GNUNET_free_non_null (d);
171   return ret;
172 }
173
174
175 /**
176  * Convert a port policy to a regular expression.  Note: this is a
177  * very simplistic implementation, we might want to consider doing
178  * something more sophisiticated (resulting in smaller regular
179  * expressions) at a later time.
180  *
181  * @param pp port policy to convert
182  * @return NULL on error
183  */
184 static char *
185 port_to_regex (const struct GNUNET_STRINGS_PortPolicy *pp)
186 {
187   char *reg;
188   char *ret;
189   char *pos;
190   unsigned int i;
191   unsigned int cnt;
192
193   if ( (0 == pp->start_port) ||
194        ( (1 == pp->start_port) &&
195          (0xFFFF == pp->end_port) &&
196          (GNUNET_NO == pp->negate_portrange)) )
197     return GNUNET_strdup ("....");
198   if ( (pp->start_port == pp->end_port) &&
199        (GNUNET_NO == pp->negate_portrange))
200   {
201     GNUNET_asprintf (&ret,
202                      "%04X",
203                      pp->start_port);
204     return ret;
205   }
206   if (pp->end_port < pp->start_port)
207     return NULL;
208   cnt = pp->end_port - pp->start_port + 1;
209   if (GNUNET_YES == pp->negate_portrange)
210     cnt = 0xFFFF - cnt;
211   reg = GNUNET_malloc (cnt * 5 + 1);
212   pos = reg;
213   for (i=1;i<=0xFFFF;i++)
214   {
215     if ( ( (i >= pp->start_port) && (i <= pp->end_port) ) ^
216          (GNUNET_YES == pp->negate_portrange) )
217     {
218       if (pos == reg)
219       {
220         GNUNET_snprintf (pos,
221                          5,
222                          "%04X",
223                          i);
224       }
225       else
226       {
227         GNUNET_snprintf (pos,
228                          6,
229                          "|%04X",
230                          i);
231       }
232       pos += strlen (pos);
233     }
234   }
235   GNUNET_asprintf (&ret,
236                    "(%s)",
237                    reg);
238   GNUNET_free (reg);
239   return ret;
240 }
241
242
243 /**
244  * Convert an address (IPv4 or IPv6) to a regex.
245  *
246  * @param addr address
247  * @param mask network mask
248  * @param len number of bytes in @a addr and @a mask
249  * @return NULL on error, otherwise regex for the address
250  */
251 static char *
252 address_to_regex (const void *addr,
253                   const void *mask,
254                   size_t len)
255 {
256   const uint16_t *a = addr;
257   const uint16_t *m = mask;
258   char *ret;
259   char *tmp;
260   char *reg;
261   unsigned int i;
262
263   ret = NULL;
264   GNUNET_assert (1 != (len % 2));
265   for (i=0;i<len / 2;i++)
266   {
267     reg = num_to_regex (a[i], m[i]);
268     if (NULL == reg)
269     {
270       GNUNET_free_non_null (ret);
271       return NULL;
272     }
273     if (NULL == ret)
274     {
275       ret = reg;
276     }
277     else
278     {
279       GNUNET_asprintf (&tmp,
280                        "%s%s",
281                        ret, reg);
282       GNUNET_free (ret);
283       GNUNET_free (reg);
284       ret = tmp;
285     }
286   }
287   return ret;
288 }
289
290
291 /**
292  * Convert a single line of an IPv4 policy to a regular expression.
293  *
294  * @param v4 line to convert
295  * @return NULL on error
296  */
297 static char *
298 ipv4_to_regex (const struct GNUNET_STRINGS_IPv4NetworkPolicy *v4)
299 {
300   char *reg;
301   char *pp;
302   char *ret;
303
304   reg = address_to_regex (&v4->network,
305                           &v4->netmask,
306                           sizeof (struct in_addr));
307   if (NULL == reg)
308     return NULL;
309   pp = port_to_regex (&v4->pp);
310   if (NULL == pp)
311   {
312     GNUNET_free (reg);
313     return NULL;
314   }
315   GNUNET_asprintf (&ret,
316                    "4-%s-%s",
317                    pp, reg);
318   GNUNET_free (pp);
319   GNUNET_free (reg);
320   return ret;
321 }
322
323
324 /**
325  * Convert a single line of an IPv4 policy to a regular expression.
326  *
327  * @param v6 line to convert
328  * @return NULL on error
329  */
330 static char *
331 ipv6_to_regex (const struct GNUNET_STRINGS_IPv6NetworkPolicy *v6)
332 {
333   char *reg;
334   char *pp;
335   char *ret;
336
337   reg = address_to_regex (&v6->network,
338                           &v6->netmask,
339                           sizeof (struct in6_addr));
340   if (NULL == reg)
341     return NULL;
342   pp = port_to_regex (&v6->pp);
343   if (NULL == pp)
344   {
345     GNUNET_free (reg);
346     return NULL;
347   }
348   GNUNET_asprintf (&ret,
349                    "6-%s-%s",
350                    pp, reg);
351   GNUNET_free (pp);
352   GNUNET_free (reg);
353   return ret;
354 }
355
356
357 /**
358  * Convert an exit policy to a regular expression.  The exit policy
359  * specifies a set of subnets this peer is willing to serve as an
360  * exit for; the resulting regular expression will match the
361  * IPv4 address strings as returned by 'GNUNET_TUN_ipv4toregexsearch'.
362  *
363  * @param policy exit policy specification
364  * @return regular expression, NULL on error
365  */
366 char *
367 GNUNET_TUN_ipv4policy2regex (const char *policy)
368 {
369   struct GNUNET_STRINGS_IPv4NetworkPolicy *np;
370   char *reg;
371   char *tmp;
372   char *line;
373   unsigned int i;
374
375   np = GNUNET_STRINGS_parse_ipv4_policy (policy);
376   if (NULL == np)
377     return NULL;
378   reg = NULL;
379   for (i=0; (0 == i) || (0 != np[i].network.s_addr); i++)
380   {
381     line = ipv4_to_regex (&np[i]);
382     if (NULL == line)
383     {
384       GNUNET_free_non_null (reg);
385       GNUNET_free (np);
386       return NULL;
387     }
388     if (NULL == reg)
389     {
390       reg = line;
391     }
392     else
393     {
394       GNUNET_asprintf (&tmp,
395                        "%s|(%s)",
396                        reg, line);
397       GNUNET_free (reg);
398       GNUNET_free (line);
399       reg = tmp;
400     }
401     if (0 == np[i].network.s_addr)
402       break;
403   }
404   GNUNET_free (np);
405   return reg;
406 }
407
408
409 /**
410  * Convert an exit policy to a regular expression.  The exit policy
411  * specifies a set of subnets this peer is willing to serve as an
412  * exit for; the resulting regular expression will match the
413  * IPv6 address strings as returned by 'GNUNET_TUN_ipv6toregexsearch'.
414  *
415  * @param policy exit policy specification
416  * @return regular expression, NULL on error
417  */
418 char *
419 GNUNET_TUN_ipv6policy2regex (const char *policy)
420 {
421   struct in6_addr zero;
422   struct GNUNET_STRINGS_IPv6NetworkPolicy *np;
423   char *reg;
424   char *tmp;
425   char *line;
426   unsigned int i;
427
428   np = GNUNET_STRINGS_parse_ipv6_policy (policy);
429   if (NULL == np)
430     return NULL;
431   reg = NULL;
432   memset (&zero, 0, sizeof (struct in6_addr));
433   for (i=0; (0 == i) || (0 != memcmp (&zero, &np[i].network, sizeof (struct in6_addr))); i++)
434   {
435     line = ipv6_to_regex (&np[i]);
436     if (NULL == line)
437     {
438       GNUNET_free_non_null (reg);
439       GNUNET_free (np);
440       return NULL;
441     }
442     if (NULL == reg)
443     {
444       reg = line;
445     }
446     else
447     {
448       GNUNET_asprintf (&tmp,
449                        "%s|(%s)",
450                        reg, line);
451       GNUNET_free (reg);
452       GNUNET_free (line);
453       reg = tmp;
454     }
455     if (0 == memcmp (&zero, &np[i].network, sizeof (struct in6_addr)))
456       break;
457   }
458   GNUNET_free (np);
459   return reg;
460 }
461
462
463 /* end of regex.c */