diff options
Diffstat (limited to 'src/transport/gnunet-nat-client.c')
-rw-r--r-- | src/transport/gnunet-nat-client.c | 138 |
1 files changed, 65 insertions, 73 deletions
diff --git a/src/transport/gnunet-nat-client.c b/src/transport/gnunet-nat-client.c index 0f7f041fb..fc88f8229 100644 --- a/src/transport/gnunet-nat-client.c +++ b/src/transport/gnunet-nat-client.c | |||
@@ -41,15 +41,22 @@ | |||
41 | #include <netinet/ip_icmp.h> | 41 | #include <netinet/ip_icmp.h> |
42 | #include <netinet/in.h> | 42 | #include <netinet/in.h> |
43 | 43 | ||
44 | #define DEBUG 0 | ||
45 | |||
46 | /** | ||
47 | * Number of UDP ports to keep open (typically >= 256) | ||
48 | */ | ||
49 | #define NUM_UDP_PORTS 256 | ||
50 | |||
44 | /** | 51 | /** |
45 | * Number of UDP ports to keep open. | 52 | * Number of ICMP replies to send per message received (typically >= 1024) |
46 | */ | 53 | */ |
47 | #define NUM_UDP_PORTS 512 | 54 | #define NUM_ICMP_REPLIES 1024 |
48 | 55 | ||
49 | /** | 56 | /** |
50 | * How often do we send our UDP messages to keep ports open? | 57 | * How often do we send our UDP messages to keep ports open? (typically < 100ms) |
51 | */ | 58 | */ |
52 | #define UDP_SEND_FREQUENCY_MS 500 | 59 | #define UDP_SEND_FREQUENCY_MS 50 |
53 | 60 | ||
54 | /** | 61 | /** |
55 | * Port we use for the dummy target. | 62 | * Port we use for the dummy target. |
@@ -61,7 +68,6 @@ | |||
61 | */ | 68 | */ |
62 | #define MAX_TRIES 10 | 69 | #define MAX_TRIES 10 |
63 | 70 | ||
64 | |||
65 | struct ip_packet | 71 | struct ip_packet |
66 | { | 72 | { |
67 | uint8_t vers_ihl; | 73 | uint8_t vers_ihl; |
@@ -76,14 +82,6 @@ struct ip_packet | |||
76 | uint32_t dst_ip; | 82 | uint32_t dst_ip; |
77 | }; | 83 | }; |
78 | 84 | ||
79 | struct icmp_packet | ||
80 | { | ||
81 | uint8_t type; | ||
82 | uint8_t code; | ||
83 | uint16_t checksum; | ||
84 | uint32_t reserved; | ||
85 | }; | ||
86 | |||
87 | struct udp_packet | 85 | struct udp_packet |
88 | { | 86 | { |
89 | uint16_t source_port; | 87 | uint16_t source_port; |
@@ -92,25 +90,17 @@ struct udp_packet | |||
92 | uint16_t checksum_aka_my_magic; | 90 | uint16_t checksum_aka_my_magic; |
93 | }; | 91 | }; |
94 | 92 | ||
95 | 93 | struct icmp_packet | |
96 | /** | ||
97 | * Structure of the data we tack on to the fake ICMP reply | ||
98 | * (last 4 bytes of the 64 bytes). | ||
99 | */ | ||
100 | struct extra_packet | ||
101 | { | 94 | { |
102 | /** | 95 | uint8_t type; |
103 | * if this is a reply to an icmp, what was the 'my_magic' | 96 | uint8_t code; |
104 | * value from the original icmp? | 97 | uint16_t checksum; |
105 | */ | 98 | uint32_t reserved; |
106 | uint16_t reply_port_magic; | 99 | struct ip_packet ip; |
107 | 100 | struct udp_packet udp; | |
108 | /** | ||
109 | * magic value of the sender of this icmp message. | ||
110 | */ | ||
111 | uint16_t my_magic; | ||
112 | }; | 101 | }; |
113 | 102 | ||
103 | |||
114 | static int udpsocks[NUM_UDP_PORTS]; | 104 | static int udpsocks[NUM_UDP_PORTS]; |
115 | 105 | ||
116 | static uint16_t udpports[NUM_UDP_PORTS]; | 106 | static uint16_t udpports[NUM_UDP_PORTS]; |
@@ -217,9 +207,8 @@ send_icmp (const struct in_addr *my_ip, | |||
217 | { | 207 | { |
218 | struct ip_packet ip_pkt; | 208 | struct ip_packet ip_pkt; |
219 | struct icmp_packet icmp_pkt; | 209 | struct icmp_packet icmp_pkt; |
220 | struct udp_packet udp_pkt; | ||
221 | struct sockaddr_in dst; | 210 | struct sockaddr_in dst; |
222 | char packet[sizeof (ip_pkt) + sizeof (icmp_pkt) + sizeof (udp_pkt)]; | 211 | char packet[sizeof (ip_pkt) + sizeof (icmp_pkt)]; |
223 | size_t off; | 212 | size_t off; |
224 | int err; | 213 | int err; |
225 | 214 | ||
@@ -233,7 +222,7 @@ send_icmp (const struct in_addr *my_ip, | |||
233 | ip_pkt.flags_frag_offset = 0; | 222 | ip_pkt.flags_frag_offset = 0; |
234 | ip_pkt.ttl = IPDEFTTL; | 223 | ip_pkt.ttl = IPDEFTTL; |
235 | ip_pkt.proto = IPPROTO_ICMP; | 224 | ip_pkt.proto = IPPROTO_ICMP; |
236 | ip_pkt.checksum = 0; /* maybe the kernel helps us out..? */ | 225 | ip_pkt.checksum = 0; |
237 | ip_pkt.src_ip = my_ip->s_addr; | 226 | ip_pkt.src_ip = my_ip->s_addr; |
238 | ip_pkt.dst_ip = other->s_addr; | 227 | ip_pkt.dst_ip = other->s_addr; |
239 | ip_pkt.checksum = htons(calc_checksum((uint16_t*)&ip_pkt, sizeof (ip_pkt))); | 228 | ip_pkt.checksum = htons(calc_checksum((uint16_t*)&ip_pkt, sizeof (ip_pkt))); |
@@ -243,40 +232,30 @@ send_icmp (const struct in_addr *my_ip, | |||
243 | /* icmp reply: time exceeded */ | 232 | /* icmp reply: time exceeded */ |
244 | memset(&icmp_pkt, 0, sizeof(icmp_pkt)); | 233 | memset(&icmp_pkt, 0, sizeof(icmp_pkt)); |
245 | icmp_pkt.type = ICMP_TIME_EXCEEDED; | 234 | icmp_pkt.type = ICMP_TIME_EXCEEDED; |
246 | icmp_pkt.code = ICMP_NET_UNREACH; | 235 | icmp_pkt.code = ICMP_HOST_UNREACH; |
247 | icmp_pkt.reserved = 0; | 236 | icmp_pkt.reserved = 0; |
248 | icmp_pkt.checksum = 0; | 237 | icmp_pkt.checksum = 0; |
249 | icmp_pkt.checksum = htons(calc_checksum((uint16_t*)&icmp_pkt, sizeof (icmp_pkt))); | ||
250 | memcpy (&packet[off], &icmp_pkt, sizeof (icmp_pkt)); | ||
251 | off += sizeof (icmp_pkt); | ||
252 | 238 | ||
253 | /* ip header of the presumably 'lost' udp packet */ | 239 | /* ip header of the presumably 'lost' udp packet */ |
254 | memset(&ip_pkt, 0, sizeof (ip_pkt)); | 240 | icmp_pkt.ip.vers_ihl = 0x45; |
255 | ip_pkt.vers_ihl = 0x45; | 241 | icmp_pkt.ip.tos = 0; |
256 | ip_pkt.tos = 0; | ||
257 | /* no idea why i need to shift the bits here, but not on ip_pkt->pkt_len... */ | 242 | /* no idea why i need to shift the bits here, but not on ip_pkt->pkt_len... */ |
258 | ip_pkt.pkt_len = (sizeof (ip_pkt) + sizeof (icmp_pkt)) << 8; | 243 | icmp_pkt.ip.pkt_len = (sizeof (ip_pkt) + sizeof (icmp_pkt)) << 8; |
259 | ip_pkt.id = 1; /* kernel sets proper value htons(ip_id_counter); */ | 244 | icmp_pkt.ip.id = 1; /* kernel sets proper value htons(ip_id_counter); */ |
260 | ip_pkt.flags_frag_offset = 0; | 245 | icmp_pkt.ip.flags_frag_offset = 0; |
261 | ip_pkt.ttl = 1; /* real TTL would be 1 on a time exceeded packet */ | 246 | icmp_pkt.ip.ttl = 1; /* real TTL would be 1 on a time exceeded packet */ |
262 | ip_pkt.proto = IPPROTO_UDP; | 247 | icmp_pkt.ip.proto = IPPROTO_UDP; |
263 | ip_pkt.src_ip = other->s_addr; | 248 | icmp_pkt.ip.src_ip = other->s_addr; |
264 | ip_pkt.dst_ip = dummy.s_addr; | 249 | icmp_pkt.ip.dst_ip = dummy.s_addr; |
265 | ip_pkt.checksum = 0; | 250 | icmp_pkt.ip.checksum = 0; |
266 | ip_pkt.checksum = htons(calc_checksum((uint16_t*)&ip_pkt, sizeof (ip_pkt))); | 251 | icmp_pkt.ip.checksum = htons(calc_checksum((uint16_t*)&icmp_pkt.ip, sizeof (icmp_pkt.ip))); |
267 | memcpy (&packet[off], &ip_pkt, sizeof (ip_pkt)); | 252 | icmp_pkt.udp.source_port = htons (target_port_number); |
268 | off += sizeof (ip_pkt); | 253 | icmp_pkt.udp.dst_port = htons (NAT_TRAV_PORT); |
269 | 254 | icmp_pkt.udp.mlen_aka_reply_port_magic = htons (source_port_number); | |
270 | memset(&udp_pkt, 0, sizeof (udp_pkt)); | 255 | icmp_pkt.udp.checksum_aka_my_magic = htons (target_port_number); |
271 | udp_pkt.source_port = htons (target_port_number); | 256 | icmp_pkt.checksum = htons(calc_checksum((uint16_t*)&icmp_pkt, sizeof (icmp_pkt))); |
272 | udp_pkt.dst_port = htons (NAT_TRAV_PORT); | 257 | memcpy (&packet[off], &icmp_pkt, sizeof (icmp_pkt)); |
273 | fprintf (stderr, | 258 | off += sizeof (icmp_pkt); |
274 | "** Generating ICMP with rpm %u\n", | ||
275 | target_port_number); | ||
276 | udp_pkt.mlen_aka_reply_port_magic = htons (source_port_number); | ||
277 | udp_pkt.checksum_aka_my_magic = htons (target_port_number); | ||
278 | memcpy (&packet[off], &udp_pkt, sizeof (udp_pkt)); | ||
279 | off += sizeof (udp_pkt); | ||
280 | 259 | ||
281 | memset (&dst, 0, sizeof (dst)); | 260 | memset (&dst, 0, sizeof (dst)); |
282 | dst.sin_family = AF_INET; | 261 | dst.sin_family = AF_INET; |
@@ -309,13 +288,13 @@ try_connect (const struct in_addr *my_ip, | |||
309 | 288 | ||
310 | fprintf (stderr, | 289 | fprintf (stderr, |
311 | "Sending %u ICMPs to `%s' with reply magic %u\n", | 290 | "Sending %u ICMPs to `%s' with reply magic %u\n", |
312 | NUM_UDP_PORTS, | 291 | NUM_ICMP_REPLIES, |
313 | inet_ntop (AF_INET, | 292 | inet_ntop (AF_INET, |
314 | other, | 293 | other, |
315 | sbuf, | 294 | sbuf, |
316 | sizeof (sbuf)), | 295 | sizeof (sbuf)), |
317 | port_magic); | 296 | port_magic); |
318 | for (i=0;i<NUM_UDP_PORTS;i++) | 297 | for (i=0;i<NUM_ICMP_REPLIES;i++) |
319 | send_icmp (my_ip, other, make_port(), port_magic); | 298 | send_icmp (my_ip, other, make_port(), port_magic); |
320 | } | 299 | } |
321 | 300 | ||
@@ -332,7 +311,6 @@ process_icmp_response (const struct in_addr *my_ip, | |||
332 | uint16_t local_port; | 311 | uint16_t local_port; |
333 | struct ip_packet ip_pkt; | 312 | struct ip_packet ip_pkt; |
334 | struct icmp_packet icmp_pkt; | 313 | struct icmp_packet icmp_pkt; |
335 | struct udp_packet udp_pkt; | ||
336 | size_t off; | 314 | size_t off; |
337 | 315 | ||
338 | have = read (s, buf, sizeof (buf)); | 316 | have = read (s, buf, sizeof (buf)); |
@@ -344,8 +322,7 @@ process_icmp_response (const struct in_addr *my_ip, | |||
344 | /* What now? */ | 322 | /* What now? */ |
345 | return; | 323 | return; |
346 | } | 324 | } |
347 | if (have != sizeof (struct ip_packet) *2 + sizeof (struct icmp_packet) + | 325 | if (have != sizeof (struct ip_packet) + sizeof (struct icmp_packet)) |
348 | sizeof (struct udp_packet)) | ||
349 | { | 326 | { |
350 | fprintf (stderr, | 327 | fprintf (stderr, |
351 | "Received ICMP message of unexpected size: %u bytes\n", | 328 | "Received ICMP message of unexpected size: %u bytes\n", |
@@ -357,9 +334,6 @@ process_icmp_response (const struct in_addr *my_ip, | |||
357 | off += sizeof (ip_pkt); | 334 | off += sizeof (ip_pkt); |
358 | memcpy (&icmp_pkt, &buf[off], sizeof (icmp_pkt)); | 335 | memcpy (&icmp_pkt, &buf[off], sizeof (icmp_pkt)); |
359 | off += sizeof (icmp_pkt); | 336 | off += sizeof (icmp_pkt); |
360 | off += sizeof (ip_pkt); | ||
361 | memcpy (&udp_pkt, &buf[off], sizeof (udp_pkt)); | ||
362 | off += sizeof (struct udp_packet); | ||
363 | 337 | ||
364 | if ( (ip_pkt.proto == IPPROTO_ICMP) && | 338 | if ( (ip_pkt.proto == IPPROTO_ICMP) && |
365 | (icmp_pkt.type == ICMP_DEST_UNREACH) && | 339 | (icmp_pkt.type == ICMP_DEST_UNREACH) && |
@@ -368,31 +342,43 @@ process_icmp_response (const struct in_addr *my_ip, | |||
368 | /* this is what is normal due to our UDP traffic */ | 342 | /* this is what is normal due to our UDP traffic */ |
369 | return; | 343 | return; |
370 | } | 344 | } |
345 | if ( (ip_pkt.proto == IPPROTO_ICMP) && | ||
346 | (icmp_pkt.type == ICMP_TIME_EXCEEDED) && | ||
347 | (icmp_pkt.code == ICMP_HOST_UNREACH) ) | ||
348 | { | ||
349 | /* this is what we might see on loopback: this is the format | ||
350 | we as the client send out (the host uses 'ICMP_NET_UNREACH'); | ||
351 | Ignore! */ | ||
352 | return; | ||
353 | } | ||
371 | if ( (ip_pkt.proto != IPPROTO_ICMP) || | 354 | if ( (ip_pkt.proto != IPPROTO_ICMP) || |
372 | (icmp_pkt.type != ICMP_TIME_EXCEEDED) || | 355 | (icmp_pkt.type != ICMP_TIME_EXCEEDED) || |
373 | (icmp_pkt.code != ICMP_NET_UNREACH) ) | 356 | (icmp_pkt.code != ICMP_NET_UNREACH) ) |
374 | { | 357 | { |
375 | /* Note the expected client response and not the normal network response */ | 358 | /* Note the expected client response and not the normal network response */ |
359 | #if DEBUG | ||
376 | fprintf (stderr, | 360 | fprintf (stderr, |
377 | "Received unexpected ICMP message contents (%u, %u, %u), ignoring\n", | 361 | "Received unexpected ICMP message contents (%u, %u, %u), ignoring\n", |
378 | ip_pkt.proto, | 362 | ip_pkt.proto, |
379 | icmp_pkt.type, | 363 | icmp_pkt.type, |
380 | icmp_pkt.code); | 364 | icmp_pkt.code); |
365 | #endif | ||
381 | return; | 366 | return; |
382 | } | 367 | } |
383 | memcpy(&sip, &ip_pkt.src_ip, sizeof (sip)); | 368 | memcpy(&sip, &ip_pkt.src_ip, sizeof (sip)); |
384 | reply_magic = ntohs (udp_pkt.checksum_aka_my_magic); | 369 | reply_magic = ntohs (icmp_pkt.udp.checksum_aka_my_magic); |
385 | my_magic = ntohs (udp_pkt.mlen_aka_reply_port_magic); | 370 | my_magic = ntohs (icmp_pkt.udp.mlen_aka_reply_port_magic); |
386 | local_port = ntohs (udp_pkt.source_port); | 371 | local_port = ntohs (icmp_pkt.udp.source_port); |
387 | if (my_magic == 0) | 372 | if (my_magic == 0) |
388 | { | 373 | { |
389 | #if 0 | 374 | #if DEBUG |
390 | /* we get these a lot during loopback testing... */ | 375 | /* we get these a lot during loopback testing... */ |
391 | fprintf (stderr, | 376 | fprintf (stderr, |
392 | "Received ICMP without hint as to which port worked, dropping\n"); | 377 | "Received ICMP without hint as to which port worked, dropping\n"); |
393 | #endif | 378 | #endif |
394 | return; | 379 | return; |
395 | } | 380 | } |
381 | #if DEBUG | ||
396 | fprintf (stderr, | 382 | fprintf (stderr, |
397 | "Received ICMP from `%s' with outgoing port %u, listen port %u and incoming for other peer %u\n", | 383 | "Received ICMP from `%s' with outgoing port %u, listen port %u and incoming for other peer %u\n", |
398 | inet_ntop (AF_INET, | 384 | inet_ntop (AF_INET, |
@@ -402,6 +388,7 @@ process_icmp_response (const struct in_addr *my_ip, | |||
402 | my_magic, | 388 | my_magic, |
403 | local_port, | 389 | local_port, |
404 | reply_magic); | 390 | reply_magic); |
391 | #endif | ||
405 | if (my_magic == 0) | 392 | if (my_magic == 0) |
406 | { | 393 | { |
407 | try_connect (my_ip, &sip, reply_magic); | 394 | try_connect (my_ip, &sip, reply_magic); |
@@ -417,6 +404,7 @@ process_icmp_response (const struct in_addr *my_ip, | |||
417 | my_magic, | 404 | my_magic, |
418 | local_port); | 405 | local_port); |
419 | /* technically, we're done here! */ | 406 | /* technically, we're done here! */ |
407 | exit (0); | ||
420 | } | 408 | } |
421 | } | 409 | } |
422 | 410 | ||
@@ -538,10 +526,12 @@ main (int argc, char *const *argv) | |||
538 | process_icmp_response (&external, icmpsock); | 526 | process_icmp_response (&external, icmpsock); |
539 | continue; | 527 | continue; |
540 | } | 528 | } |
529 | #if DEBUG | ||
541 | fprintf (stderr, | 530 | fprintf (stderr, |
542 | "Sending UDP message to %s:%u\n", | 531 | "Sending UDP message to %s:%u\n", |
543 | argv[3], | 532 | argv[3], |
544 | NAT_TRAV_PORT); | 533 | NAT_TRAV_PORT); |
534 | #endif | ||
545 | if (-1 == sendto (udpsocks[pos], | 535 | if (-1 == sendto (udpsocks[pos], |
546 | NULL, 0, 0, | 536 | NULL, 0, 0, |
547 | (struct sockaddr*) &dst, sizeof (dst))) | 537 | (struct sockaddr*) &dst, sizeof (dst))) |
@@ -553,10 +543,12 @@ main (int argc, char *const *argv) | |||
553 | udpsocks[pos] = make_udp_socket (&udpports[pos]); | 543 | udpsocks[pos] = make_udp_socket (&udpports[pos]); |
554 | } | 544 | } |
555 | p = make_port (); | 545 | p = make_port (); |
546 | #if DEBUG | ||
556 | fprintf (stderr, | 547 | fprintf (stderr, |
557 | "Sending fake ICMP message to %s:%u\n", | 548 | "Sending fake ICMP message to %s:%u\n", |
558 | argv[1], | 549 | argv[1], |
559 | p); | 550 | p); |
551 | #endif | ||
560 | send_icmp (&external, | 552 | send_icmp (&external, |
561 | &target, | 553 | &target, |
562 | p, | 554 | p, |