aboutsummaryrefslogtreecommitdiff
path: root/src/tun
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2013-10-26 14:34:39 +0000
committerChristian Grothoff <christian@grothoff.org>2013-10-26 14:34:39 +0000
commit0c9ca79b2eb820c3266e9117f3ba9179cbdc2ff1 (patch)
tree434cab0d8aa45a4edc2cf9bd91c89bf3f2d5061b /src/tun
parentaeb922926c639ffdd992f96cd125e47bb0e2c301 (diff)
downloadgnunet-0c9ca79b2eb820c3266e9117f3ba9179cbdc2ff1.tar.gz
gnunet-0c9ca79b2eb820c3266e9117f3ba9179cbdc2ff1.zip
-converting regular expressions of vpn/pt to non-binary format and adding proper policy parsing
Diffstat (limited to 'src/tun')
-rw-r--r--src/tun/regex.c428
-rw-r--r--src/tun/test_regex.c133
2 files changed, 444 insertions, 117 deletions
diff --git a/src/tun/regex.c b/src/tun/regex.c
index 87e75b511..3d3ebd8ba 100644
--- a/src/tun/regex.c
+++ b/src/tun/regex.c
@@ -21,6 +21,7 @@
21 * @file src/tun/regex.c 21 * @file src/tun/regex.c
22 * @brief functions to convert IP networks to regexes 22 * @brief functions to convert IP networks to regexes
23 * @author Maximilian Szengel 23 * @author Maximilian Szengel
24 * @author Christian Grothoff
24 */ 25 */
25#include "platform.h" 26#include "platform.h"
26#include "gnunet_util_lib.h" 27#include "gnunet_util_lib.h"
@@ -28,114 +29,311 @@
28 29
29 30
30/** 31/**
31 * Create a string with binary IP notation for the given 'addr' in 'str'. 32 * Create a regex in @a rxstr from the given @a ip and @a netmask.
32 * 33 *
33 * @param af address family of the given 'addr'. 34 * @param ip IPv4 representation.
34 * @param addr address that should be converted to a string. 35 * @param port destination port
35 * struct in_addr * for IPv4 and struct in6_addr * for IPv6. 36 * @param rxstr generated regex, must be at least #GNUNET_TUN_IPV4_REGEXLEN
36 * @param str string that will contain binary notation of 'addr'. Expected 37 * bytes long.
37 * to be at least 33 bytes long for IPv4 and 129 bytes long for IPv6. 38 */
39void
40GNUNET_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 */
60void
61GNUNET_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)?
38 */ 84 */
39static void 85static char *
40iptobinstr (const int af, const void *addr, char *str) 86nibble_to_regex (uint8_t value,
87 uint8_t mask)
41{ 88{
42 int i; 89 char *ret;
43 90
44 switch (af) 91 value &= mask;
92 switch (mask)
45 { 93 {
46 case AF_INET: 94 case 0:
47 { 95 return GNUNET_strdup ("."); /* wildcard */
48 uint32_t b = htonl (((struct in_addr *) addr)->s_addr); 96 case 8:
49 97 GNUNET_asprintf (&ret,
50 str[32] = '\0'; 98 "(%X|%X|%X|%X|%X|%X|%X|%X)",
51 str += 31; 99 value,
52 for (i = 31; i >= 0; i--) 100 value + 1,
53 { 101 value + 2,
54 *str = (b & 1) + '0'; 102 value + 3,
55 str--; 103 value + 4,
56 b >>= 1; 104 value + 5,
57 } 105 value + 6,
58 break; 106 value + 7);
59 } 107 return ret;
60 case AF_INET6: 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 */
143static char *
144num_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 */
184static char *
185port_to_regex (const struct GNUNET_STRINGS_PortPolicy *pp)
186{
187 char *reg;
188 char *ret;
189 char *tmp;
190 unsigned int i;
191
192 if ( (0 == pp->start_port) ||
193 ( (1 == pp->start_port) &&
194 (0xFFFF == pp->end_port) &&
195 (GNUNET_NO == pp->negate_portrange)) )
196 return GNUNET_strdup ("....");
197 if ( (pp->start_port == pp->end_port) &&
198 (GNUNET_NO == pp->negate_portrange))
199 {
200 GNUNET_asprintf (&ret,
201 "%04X",
202 pp->start_port);
203 return ret;
204 }
205 reg = NULL;
206 for (i=1;i<=0xFFFF;i++)
207 {
208 if ( ( (i >= pp->start_port) && (i <= pp->end_port) ) ^
209 (GNUNET_YES == pp->negate_portrange) )
61 { 210 {
62 struct in6_addr b = *(const struct in6_addr *) addr; 211 if (NULL == reg)
63 212 {
64 str[128] = '\0'; 213 GNUNET_asprintf (&tmp,
65 str += 127; 214 "%04X",
66 for (i = 127; i >= 0; i--) 215 i);
67 { 216 }
68 *str = (b.s6_addr[i / 8] & 1) + '0'; 217 else
69 str--; 218 {
70 b.s6_addr[i / 8] >>= 1; 219 GNUNET_asprintf (&tmp,
71 } 220 "%s|%04X",
72 break; 221 reg,
222 i);
223 GNUNET_free (reg);
224 }
225 reg = tmp;
73 } 226 }
74 } 227 }
228 GNUNET_asprintf (&ret,
229 "(%s)",
230 reg);
231 GNUNET_free (reg);
232 return ret;
75} 233}
76 234
77 235
78/** 236/**
79 * Get the ipv4 network prefix from the given 'netmask'. 237 * Convert an address (IPv4 or IPv6) to a regex.
80 * 238 *
81 * @param netmask netmask for which to get the prefix len. 239 * @param addr address
82 * 240 * @param mask network mask
83 * @return length of ipv4 prefix for 'netmask'. 241 * @param len number of bytes in @a addr and @a mask
242 * @return NULL on error, otherwise regex for the address
84 */ 243 */
85static unsigned int 244static char *
86ipv4netmasktoprefixlen (const char *netmask) 245address_to_regex (const void *addr,
246 const void *mask,
247 size_t len)
87{ 248{
88 struct in_addr a; 249 const uint16_t *a = addr;
89 unsigned int len; 250 const uint16_t *m = mask;
90 uint32_t t; 251 char *ret;
91 252 char *tmp;
92 if (1 != inet_pton (AF_INET, netmask, &a)) 253 char *reg;
93 return 0; 254 unsigned int i;
94 len = 32; 255
95 for (t = htonl (~a.s_addr); 0 != t; t >>= 1) 256 ret = NULL;
96 len--; 257 GNUNET_assert (1 != (len % 2));
97 return len; 258 for (i=0;i<len / 2;i++)
259 {
260 reg = num_to_regex (a[i], m[i]);
261 if (NULL == reg)
262 {
263 GNUNET_free_non_null (ret);
264 return NULL;
265 }
266 if (NULL == ret)
267 {
268 ret = reg;
269 }
270 else
271 {
272 GNUNET_asprintf (&tmp,
273 "%s%s",
274 ret, reg);
275 GNUNET_free (ret);
276 GNUNET_free (reg);
277 ret = tmp;
278 }
279 }
280 return ret;
98} 281}
99 282
100 283
101/** 284/**
102 * Create a regex in 'rxstr' from the given 'ip' and 'netmask'. 285 * Convert a single line of an IPv4 policy to a regular expression.
103 * 286 *
104 * @param ip IPv4 representation. 287 * @param v4 line to convert
105 * @param netmask netmask for the ip. 288 * @return NULL on error
106 * @param rxstr generated regex, must be at least GNUNET_REGEX_IPV4_REGEXLEN
107 * bytes long.
108 */ 289 */
109void 290static char *
110GNUNET_TUN_ipv4toregexsearch (const struct in_addr *ip, const char *netmask, 291ipv4_to_regex (const struct GNUNET_STRINGS_IPv4NetworkPolicy *v4)
111 char *rxstr)
112{ 292{
113 unsigned int pfxlen; 293 char *reg;
294 char *pp;
295 char *ret;
114 296
115 pfxlen = ipv4netmasktoprefixlen (netmask); 297 reg = address_to_regex (&v4->network,
116 iptobinstr (AF_INET, ip, rxstr); 298 &v4->netmask,
117 rxstr[pfxlen] = '\0'; 299 sizeof (struct in_addr));
118 if (pfxlen < 32) 300 if (NULL == reg)
119 strcat (rxstr, "(0|1)+"); 301 return NULL;
302 pp = port_to_regex (&v4->pp);
303 GNUNET_asprintf (&ret,
304 "4-%s-%s",
305 pp, reg);
306 GNUNET_free (pp);
307 GNUNET_free (reg);
308 return ret;
120} 309}
121 310
122 311
123/** 312/**
124 * Create a regex in 'rxstr' from the given 'ipv6' and 'prefixlen'. 313 * Convert a single line of an IPv4 policy to a regular expression.
125 * 314 *
126 * @param ipv6 IPv6 representation. 315 * @param v6 line to convert
127 * @param prefixlen length of the ipv6 prefix. 316 * @return NULL on error
128 * @param rxstr generated regex, must be at least GNUNET_REGEX_IPV6_REGEXLEN
129 * bytes long.
130 */ 317 */
131void 318static char *
132GNUNET_TUN_ipv6toregexsearch (const struct in6_addr *ipv6, unsigned int prefixlen, 319ipv6_to_regex (const struct GNUNET_STRINGS_IPv6NetworkPolicy *v6)
133 char *rxstr)
134{ 320{
135 iptobinstr (AF_INET6, ipv6, rxstr); 321 char *reg;
136 rxstr[prefixlen] = '\0'; 322 char *pp;
137 if (prefixlen < 128) 323 char *ret;
138 strcat (rxstr, "(0|1)+"); 324
325 reg = address_to_regex (&v6->network,
326 &v6->netmask,
327 sizeof (struct in6_addr));
328 if (NULL == reg)
329 return NULL;
330 pp = port_to_regex (&v6->pp);
331 GNUNET_asprintf (&ret,
332 "6-%s-%s",
333 pp, reg);
334 GNUNET_free (pp);
335 GNUNET_free (reg);
336 return ret;
139} 337}
140 338
141 339
@@ -151,8 +349,39 @@ GNUNET_TUN_ipv6toregexsearch (const struct in6_addr *ipv6, unsigned int prefixle
151char * 349char *
152GNUNET_TUN_ipv4policy2regex (const char *policy) 350GNUNET_TUN_ipv4policy2regex (const char *policy)
153{ 351{
154 // FIXME: do actual policy parsing here, see #2919 352 struct GNUNET_STRINGS_IPv4NetworkPolicy *np;
155 return GNUNET_strdup (policy); 353 char *reg;
354 char *tmp;
355 char *line;
356 unsigned int i;
357
358 np = GNUNET_STRINGS_parse_ipv4_policy (policy);
359 if (NULL == np)
360 return NULL;
361 reg = NULL;
362 for (i=0; 0 != np[i].network.s_addr; i++)
363 {
364 line = ipv4_to_regex (&np[i]);
365 if (NULL == line)
366 {
367 GNUNET_free_non_null (reg);
368 return NULL;
369 }
370 if (NULL == reg)
371 {
372 reg = line;
373 }
374 else
375 {
376 GNUNET_asprintf (&tmp,
377 "%s|(%s)",
378 reg, line);
379 GNUNET_free (reg);
380 GNUNET_free (line);
381 reg = tmp;
382 }
383 }
384 return reg;
156} 385}
157 386
158 387
@@ -160,7 +389,7 @@ GNUNET_TUN_ipv4policy2regex (const char *policy)
160 * Convert an exit policy to a regular expression. The exit policy 389 * Convert an exit policy to a regular expression. The exit policy
161 * specifies a set of subnets this peer is willing to serve as an 390 * specifies a set of subnets this peer is willing to serve as an
162 * exit for; the resulting regular expression will match the 391 * exit for; the resulting regular expression will match the
163 * IPv4 address strings as returned by 'GNUNET_TUN_ipv4toregexsearch'. 392 * IPv6 address strings as returned by 'GNUNET_TUN_ipv6toregexsearch'.
164 * 393 *
165 * @param policy exit policy specification 394 * @param policy exit policy specification
166 * @return regular expression, NULL on error 395 * @return regular expression, NULL on error
@@ -168,8 +397,41 @@ GNUNET_TUN_ipv4policy2regex (const char *policy)
168char * 397char *
169GNUNET_TUN_ipv6policy2regex (const char *policy) 398GNUNET_TUN_ipv6policy2regex (const char *policy)
170{ 399{
171 // FIXME: do actual policy parsing here, see #2919 400 struct in6_addr zero;
172 return GNUNET_strdup (policy); 401 struct GNUNET_STRINGS_IPv6NetworkPolicy *np;
402 char *reg;
403 char *tmp;
404 char *line;
405 unsigned int i;
406
407 np = GNUNET_STRINGS_parse_ipv6_policy (policy);
408 if (NULL == np)
409 return NULL;
410 reg = NULL;
411 memset (&zero, 0, sizeof (struct in6_addr));
412 for (i=0; 0 != memcmp (&zero, &np[i].network, sizeof (struct in6_addr)); i++)
413 {
414 line = ipv6_to_regex (&np[i]);
415 if (NULL == line)
416 {
417 GNUNET_free_non_null (reg);
418 return NULL;
419 }
420 if (NULL == reg)
421 {
422 reg = line;
423 }
424 else
425 {
426 GNUNET_asprintf (&tmp,
427 "%s|(%s)",
428 reg, line);
429 GNUNET_free (reg);
430 GNUNET_free (line);
431 reg = tmp;
432 }
433 }
434 return reg;
173} 435}
174 436
175 437
diff --git a/src/tun/test_regex.c b/src/tun/test_regex.c
index a0c3e99fd..341d8b9a0 100644
--- a/src/tun/test_regex.c
+++ b/src/tun/test_regex.c
@@ -27,8 +27,11 @@
27 27
28 28
29static int 29static int
30test_iptoregex (const char *ipv4, const char *netmask, const char *expectedv4, 30test_iptoregex (const char *ipv4,
31 const char *ipv6, unsigned int prefixlen, 31 uint16_t port,
32 const char *expectedv4,
33 const char *ipv6,
34 uint16_t port6,
32 const char *expectedv6) 35 const char *expectedv6)
33{ 36{
34 int error = 0; 37 int error = 0;
@@ -39,29 +42,82 @@ test_iptoregex (const char *ipv4, const char *netmask, const char *expectedv4,
39 char rxv6[GNUNET_TUN_IPV6_REGEXLEN]; 42 char rxv6[GNUNET_TUN_IPV6_REGEXLEN];
40 43
41 GNUNET_assert (1 == inet_pton (AF_INET, ipv4, &a)); 44 GNUNET_assert (1 == inet_pton (AF_INET, ipv4, &a));
42 GNUNET_TUN_ipv4toregexsearch (&a, netmask, rxv4); 45 GNUNET_TUN_ipv4toregexsearch (&a, port, rxv4);
43
44 46
45 if (0 != strcmp (rxv4, expectedv4)) 47 if (0 != strcmp (rxv4, expectedv4))
46 { 48 {
47 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Expected: %s but got: %s\n", 49 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
48 expectedv4, rxv4); 50 "Expected: %s but got: %s\n",
51 expectedv4,
52 rxv4);
49 error++; 53 error++;
50 } 54 }
51 55
52 GNUNET_assert (1 == inet_pton (AF_INET6, ipv6, &b)); 56 GNUNET_assert (1 == inet_pton (AF_INET6, ipv6, &b));
53 GNUNET_TUN_ipv6toregexsearch (&b, prefixlen, rxv6); 57 GNUNET_TUN_ipv6toregexsearch (&b, port6, rxv6);
54
55 if (0 != strcmp (rxv6, expectedv6)) 58 if (0 != strcmp (rxv6, expectedv6))
56 { 59 {
57 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Expected: %s but got: %s\n", 60 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
61 "Expected: %s but got: %s\n",
58 expectedv6, rxv6); 62 expectedv6, rxv6);
59 error++; 63 error++;
60 } 64 }
61
62 return error; 65 return error;
63} 66}
64 67
68
69static int
70test_policy4toregex (const char *policy,
71 const char *regex)
72{
73 char *r;
74 int ret;
75
76 ret = 0;
77 r = GNUNET_TUN_ipv4policy2regex (policy);
78 if (NULL == r)
79 {
80 GNUNET_break (0);
81 return 1;
82 }
83 if (0 != strcmp (regex, r))
84 {
85 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
86 "Expected: `%s' but got: `%s'\n",
87 regex, r);
88 ret = 2;
89 }
90 GNUNET_free (r);
91 return ret;
92}
93
94
95static int
96test_policy6toregex (const char *policy,
97 const char *regex)
98{
99 char *r;
100 int ret;
101
102 ret = 0;
103 r = GNUNET_TUN_ipv6policy2regex (policy);
104 if (NULL == r)
105 {
106 GNUNET_break (0);
107 return 1;
108 }
109 if (0 != strcmp (regex, r))
110 {
111 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
112 "Expected: `%s' but got: `%s'\n",
113 regex, r);
114 ret = 2;
115 }
116 GNUNET_free (r);
117 return ret;
118}
119
120
65int 121int
66main (int argc, char *argv[]) 122main (int argc, char *argv[])
67{ 123{
@@ -72,32 +128,41 @@ main (int argc, char *argv[])
72 error = 0; 128 error = 0;
73 129
74 error += 130 error +=
75 test_iptoregex ("192.0.0.0", "255.255.255.0", 131 test_iptoregex ("192.1.2.3", 2086,
76 "110000000000000000000000(0|1)+", "FFFF::0", 16, 132 "4-0826-C0010203",
77 "1111111111111111(0|1)+"); 133 "FFFF::1", 8080,
78 134 "6-1F90-FFFF0000000000000000000000000001");
79 error += 135 error +=
80 test_iptoregex ("187.238.225.0", "255.255.255.128", 136 test_iptoregex ("187.238.255.0", 80,
81 "1011101111101110111000010(0|1)+", "E1E1:73F9:51BE::0", 137 "4-0050-BBEEFF00",
82 49, 138 "E1E1:73F9:51BE::0", 49,
83 "1110000111100001011100111111100101010001101111100(0|1)+"); 139 "6-0031-E1E173F951BE00000000000000000000");
84
85 error += 140 error +=
86 test_iptoregex ("255.255.255.255", "255.255.255.255", 141 test_policy4toregex ("192.1.2.0/24:80;",
87 "11111111111111111111111111111111", 142 "4-0050-C00102..");
88 "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF", 128,
89 "11111111111111111111111111111111"
90 "11111111111111111111111111111111"
91 "11111111111111111111111111111111"
92 "11111111111111111111111111111111");
93
94 error += 143 error +=
95 test_iptoregex ("0.0.0.0", "255.255.255.255", 144 test_policy4toregex ("192.1.0.0/16;",
96 "00000000000000000000000000000000", "0::0", 128, 145 "4-....-C001....");
97 "00000000000000000000000000000000" 146 error +=
98 "00000000000000000000000000000000" 147 test_policy4toregex ("192.1.0.0/16:80-81;",
99 "00000000000000000000000000000000" 148 "4-(0050|0051)-C001....");
100 "00000000000000000000000000000000"); 149 error +=
101 150 test_policy4toregex ("192.1.0.0/8:!3-65535;",
151 "4-(0001|0002)-C0......");
152 error +=
153 test_policy6toregex ("E1E1::1;",
154 "6-....-E1E10000000000000000000000000001");
155 error +=
156 test_policy6toregex ("E1E1:ABCD::1/120;",
157 "6-....-E1E1ABCD0000000000000000000000..");
158 error +=
159 test_policy6toregex ("E1E1:ABCD::ABCD/126;",
160 "6-....-E1E1ABCD00000000000000000000ABC(C|D|E|F)");
161 error +=
162 test_policy6toregex ("E1E1:ABCD::ABCD/127;",
163 "6-....-E1E1ABCD00000000000000000000ABC(C|D)");
164 error +=
165 test_policy6toregex ("E1E1:ABCD::ABCD/128:80;",
166 "6-0050-E1E1ABCD00000000000000000000ABCD");
102 return error; 167 return error;
103} 168}