diff options
author | Christian Grothoff <christian@grothoff.org> | 2010-02-06 23:13:26 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2010-02-06 23:13:26 +0000 |
commit | 94229794b52dd866fe7d27ffbed20da18934087d (patch) | |
tree | fbd0ea504a32b1eece19cbc8b5270a4536538195 /src | |
parent | 0e66068912b62ffc503f4c6073e3a0317344559f (diff) | |
download | gnunet-94229794b52dd866fe7d27ffbed20da18934087d.tar.gz gnunet-94229794b52dd866fe7d27ffbed20da18934087d.zip |
stuff
Diffstat (limited to 'src')
-rw-r--r-- | src/transport/gnunet-nat-client.c | 468 | ||||
-rw-r--r-- | src/transport/gnunet-nat-server.c | 399 |
2 files changed, 157 insertions, 710 deletions
diff --git a/src/transport/gnunet-nat-client.c b/src/transport/gnunet-nat-client.c index 0fce09e71..ba99c8816 100644 --- a/src/transport/gnunet-nat-client.c +++ b/src/transport/gnunet-nat-client.c | |||
@@ -20,16 +20,14 @@ | |||
20 | 20 | ||
21 | /** | 21 | /** |
22 | * @file src/transport/gnunet-nat-client.c | 22 | * @file src/transport/gnunet-nat-client.c |
23 | * @brief Tool to help bypass NATs using ICMP method; must run as root (for now, later SUID will do) | 23 | * @brief Tool to help bypass NATs using ICMP method; must run as root (SUID will do) |
24 | * This code will work under GNU/Linux only (or maybe BSDs, but never W32) | 24 | * This code will work under GNU/Linux only. |
25 | * @author Christian Grothoff | 25 | * @author Christian Grothoff |
26 | */ | 26 | */ |
27 | 27 | #define _GNU_SOURCE | |
28 | #include <sys/types.h> | 28 | #include <sys/types.h> |
29 | #include <sys/socket.h> | 29 | #include <sys/socket.h> |
30 | #include <arpa/inet.h> | 30 | #include <arpa/inet.h> |
31 | #include <sys/select.h> | ||
32 | #include <sys/time.h> | ||
33 | #include <sys/types.h> | 31 | #include <sys/types.h> |
34 | #include <unistd.h> | 32 | #include <unistd.h> |
35 | #include <stdio.h> | 33 | #include <stdio.h> |
@@ -37,37 +35,14 @@ | |||
37 | #include <errno.h> | 35 | #include <errno.h> |
38 | #include <stdlib.h> | 36 | #include <stdlib.h> |
39 | #include <stdint.h> | 37 | #include <stdint.h> |
40 | #include <time.h> | ||
41 | #include <netinet/ip.h> | 38 | #include <netinet/ip.h> |
42 | #include <netinet/ip_icmp.h> | 39 | #include <netinet/ip_icmp.h> |
43 | #include <netinet/in.h> | 40 | #include <netinet/in.h> |
44 | 41 | ||
45 | #define DEBUG 1 | ||
46 | |||
47 | /** | ||
48 | * Number of UDP ports to keep open (typically >= 256) | ||
49 | */ | ||
50 | #define NUM_UDP_PORTS 1024 | ||
51 | |||
52 | /** | ||
53 | * Number of ICMP replies to send per message received (typically >= 1024) | ||
54 | */ | ||
55 | #define NUM_ICMP_REPLIES 10240 | ||
56 | |||
57 | /** | 42 | /** |
58 | * How often do we send our UDP messages to keep ports open? (typically < 100ms) | 43 | * Must match IP given in the server. |
59 | */ | 44 | */ |
60 | #define UDP_SEND_FREQUENCY_MS 10 | 45 | #define DUMMY_IP "1.2.3.4" |
61 | |||
62 | /** | ||
63 | * Port we use for the dummy target. | ||
64 | */ | ||
65 | #define NAT_TRAV_PORT 22223 | ||
66 | |||
67 | /** | ||
68 | * How often do we retry to open and bind a UDP socket before giving up? | ||
69 | */ | ||
70 | #define MAX_TRIES 10 | ||
71 | 46 | ||
72 | struct ip_packet | 47 | struct ip_packet |
73 | { | 48 | { |
@@ -83,31 +58,14 @@ struct ip_packet | |||
83 | uint32_t dst_ip; | 58 | uint32_t dst_ip; |
84 | }; | 59 | }; |
85 | 60 | ||
86 | struct udp_packet | ||
87 | { | ||
88 | uint16_t source_port; | ||
89 | uint16_t dst_port; | ||
90 | uint16_t mlen_aka_reply_port_magic; | ||
91 | uint16_t checksum_aka_my_magic; | ||
92 | }; | ||
93 | |||
94 | struct icmp_packet | 61 | struct icmp_packet |
95 | { | 62 | { |
96 | uint8_t type; | 63 | uint8_t type; |
97 | uint8_t code; | 64 | uint8_t code; |
98 | uint16_t checksum; | 65 | uint16_t checksum; |
99 | uint32_t reserved; | 66 | uint32_t reserved; |
100 | struct ip_packet ip; | ||
101 | struct udp_packet udp; | ||
102 | }; | 67 | }; |
103 | |||
104 | |||
105 | static int udpsocks[NUM_UDP_PORTS]; | ||
106 | |||
107 | static uint16_t udpports[NUM_UDP_PORTS]; | ||
108 | 68 | ||
109 | static int icmpsock; | ||
110 | |||
111 | static int rawsock; | 69 | static int rawsock; |
112 | 70 | ||
113 | static struct in_addr dummy; | 71 | static struct in_addr dummy; |
@@ -115,63 +73,6 @@ static struct in_addr dummy; | |||
115 | static struct in_addr target; | 73 | static struct in_addr target; |
116 | 74 | ||
117 | 75 | ||
118 | /** | ||
119 | * create a random port number that is not totally | ||
120 | * unlikely to be chosen by the nat box. | ||
121 | */ | ||
122 | static uint16_t make_port () | ||
123 | { | ||
124 | return 1024 + ( (unsigned int)rand ()) % (63 * 1024 - 2); | ||
125 | } | ||
126 | |||
127 | |||
128 | /** | ||
129 | * create a fresh udp socket bound to a random local port. | ||
130 | */ | ||
131 | static int | ||
132 | make_udp_socket (uint16_t *port) | ||
133 | { | ||
134 | int ret; | ||
135 | int tries; | ||
136 | struct sockaddr_in src; | ||
137 | |||
138 | for (tries=0;tries<MAX_TRIES;tries++) | ||
139 | { | ||
140 | ret = socket (AF_INET, SOCK_DGRAM, 0); | ||
141 | if (-1 == ret) | ||
142 | { | ||
143 | fprintf (stderr, | ||
144 | "Error opening udp socket: %s\n", | ||
145 | strerror (errno)); | ||
146 | return -1; | ||
147 | } | ||
148 | if (ret >= FD_SETSIZE) | ||
149 | { | ||
150 | fprintf (stderr, | ||
151 | "Socket number too large (%d > %u)\n", | ||
152 | ret, | ||
153 | (unsigned int) FD_SETSIZE); | ||
154 | close (ret); | ||
155 | return -1; | ||
156 | } | ||
157 | memset (&src, 0, sizeof (src)); | ||
158 | src.sin_family = AF_INET; | ||
159 | src.sin_port = htons (make_port ()); | ||
160 | if (0 != bind (ret, (struct sockaddr*) &src, sizeof (src))) | ||
161 | { | ||
162 | close (ret); | ||
163 | continue; | ||
164 | } | ||
165 | *port = ntohs (src.sin_port); | ||
166 | return ret; | ||
167 | } | ||
168 | fprintf (stderr, | ||
169 | "Error binding udp socket: %s\n", | ||
170 | strerror (errno)); | ||
171 | return -1; | ||
172 | } | ||
173 | |||
174 | |||
175 | static uint16_t | 76 | static uint16_t |
176 | calc_checksum(const uint16_t *data, | 77 | calc_checksum(const uint16_t *data, |
177 | unsigned int bytes) | 78 | unsigned int bytes) |
@@ -188,76 +89,83 @@ calc_checksum(const uint16_t *data, | |||
188 | } | 89 | } |
189 | 90 | ||
190 | 91 | ||
92 | static void | ||
93 | make_echo (const struct in_addr *src_ip, | ||
94 | struct icmp_packet *echo) | ||
95 | { | ||
96 | memset(echo, 0, sizeof(struct icmp_packet)); | ||
97 | echo->type = ICMP_ECHO; | ||
98 | echo->code = 0; | ||
99 | echo->reserved = 0; | ||
100 | echo->checksum = 0; | ||
101 | echo->checksum = htons(calc_checksum((uint16_t*)echo, | ||
102 | sizeof (struct icmp_packet))); | ||
103 | } | ||
104 | |||
105 | |||
191 | /** | 106 | /** |
192 | * send an icmp message to the target. | 107 | * Send an ICMP message to the target. |
193 | * | 108 | * |
194 | * @param my_ip source address (our ip address) | 109 | * @param my_ip source address |
195 | * @param other target address | 110 | * @param other target address |
196 | * @param target_port_number fake port number to put into icmp response | ||
197 | * as well as the icmpextradata as 'my_magic' | ||
198 | * @param source_port_number magic_number that enables the other peer to | ||
199 | * identify our port number ('reply in response to') to | ||
200 | * put in the data portion; 0 if we are initiating; | ||
201 | * goes into 'reply_port_magic' of the icmpextradata | ||
202 | */ | 111 | */ |
203 | static void | 112 | static void |
204 | send_icmp (const struct in_addr *my_ip, | 113 | send_icmp (const struct in_addr *my_ip, |
205 | const struct in_addr *other, | 114 | const struct in_addr *other) |
206 | uint16_t target_port_number, | ||
207 | uint16_t source_port_number) | ||
208 | { | 115 | { |
209 | struct ip_packet ip_pkt; | 116 | struct ip_packet ip_pkt; |
210 | struct icmp_packet icmp_pkt; | 117 | struct icmp_packet *icmp_pkt; |
118 | struct icmp_packet icmp_echo; | ||
211 | struct sockaddr_in dst; | 119 | struct sockaddr_in dst; |
212 | char packet[sizeof (ip_pkt) + sizeof (icmp_pkt)]; | 120 | char packet[sizeof (struct ip_packet)*2 + sizeof (struct icmp_packet)*2]; |
213 | size_t off; | 121 | size_t off; |
214 | int err; | 122 | int err; |
215 | 123 | ||
216 | /* ip header: send to (known) ip address */ | 124 | /* ip header: send to (known) ip address */ |
217 | off = 0; | 125 | off = 0; |
218 | memset(&ip_pkt, 0, sizeof(ip_pkt)); | 126 | memset(&ip_pkt, 0, sizeof(ip_pkt)); |
219 | ip_pkt.vers_ihl = 0x45;//|(pkt_len>>2);//5;//(ipversion << 4) | (iphdr_size >> 2); | 127 | ip_pkt.vers_ihl = 0x45; |
220 | ip_pkt.tos = 0; | 128 | ip_pkt.tos = 0; |
221 | ip_pkt.pkt_len = sizeof (packet); /* huh? */ | 129 | ip_pkt.pkt_len = sizeof (packet); /* huh? */ |
222 | ip_pkt.id = 1; /* kernel will change anyway!? */ | 130 | ip_pkt.id = 1; |
223 | ip_pkt.flags_frag_offset = 0; | 131 | ip_pkt.flags_frag_offset = 0; |
224 | ip_pkt.ttl = IPDEFTTL; | 132 | ip_pkt.ttl = IPDEFTTL; |
225 | ip_pkt.proto = IPPROTO_ICMP; | 133 | ip_pkt.proto = IPPROTO_ICMP; |
226 | ip_pkt.checksum = 0; | 134 | ip_pkt.checksum = 0; |
227 | ip_pkt.src_ip = my_ip->s_addr; | 135 | ip_pkt.src_ip = my_ip->s_addr; |
228 | ip_pkt.dst_ip = other->s_addr; | 136 | ip_pkt.dst_ip = other->s_addr; |
229 | ip_pkt.checksum = htons(calc_checksum((uint16_t*)&ip_pkt, sizeof (ip_pkt))); | 137 | ip_pkt.checksum = htons(calc_checksum((uint16_t*)&ip_pkt, sizeof (struct ip_packet))); |
230 | memcpy (packet, &ip_pkt, sizeof (ip_pkt)); | 138 | memcpy (packet, &ip_pkt, sizeof (struct ip_packet)); |
231 | off += sizeof (ip_pkt); | 139 | off += sizeof (ip_pkt); |
232 | |||
233 | /* icmp reply: time exceeded */ | 140 | /* icmp reply: time exceeded */ |
234 | memset(&icmp_pkt, 0, sizeof(icmp_pkt)); | 141 | icmp_pkt = (struct icmp_packet*) &packet[off]; |
235 | icmp_pkt.type = ICMP_TIME_EXCEEDED; | 142 | memset(icmp_pkt, 0, sizeof(struct icmp_packet)); |
236 | icmp_pkt.code = ICMP_HOST_UNREACH; | 143 | icmp_pkt->type = ICMP_TIME_EXCEEDED; |
237 | icmp_pkt.reserved = 0; | 144 | icmp_pkt->code = 0; |
238 | icmp_pkt.checksum = 0; | 145 | icmp_pkt->reserved = 0; |
146 | icmp_pkt->checksum = 0; | ||
147 | off += sizeof (struct icmp_packet); | ||
239 | 148 | ||
240 | /* ip header of the presumably 'lost' udp packet */ | 149 | /* ip header of the presumably 'lost' udp packet */ |
241 | icmp_pkt.ip.vers_ihl = 0x45; | 150 | ip_pkt.vers_ihl = 0x45; |
242 | icmp_pkt.ip.tos = 0; | 151 | ip_pkt.tos = 0; |
243 | /* no idea why i need to shift the bits here, but not on ip_pkt->pkt_len... */ | 152 | ip_pkt.pkt_len = (sizeof (struct ip_packet) + sizeof (struct icmp_packet)); |
244 | icmp_pkt.ip.pkt_len = (sizeof (ip_pkt) + sizeof (icmp_pkt)) << 8; | 153 | ip_pkt.id = 1; |
245 | icmp_pkt.ip.id = 1; /* kernel sets proper value htons(ip_id_counter); */ | 154 | ip_pkt.flags_frag_offset = 0; |
246 | icmp_pkt.ip.flags_frag_offset = 0; | 155 | ip_pkt.ttl = 1; /* real TTL would be 1 on a time exceeded packet */ |
247 | icmp_pkt.ip.ttl = 1; /* real TTL would be 1 on a time exceeded packet */ | 156 | ip_pkt.proto = IPPROTO_ICMP; |
248 | icmp_pkt.ip.proto = IPPROTO_UDP; | 157 | ip_pkt.src_ip = other->s_addr; |
249 | icmp_pkt.ip.src_ip = other->s_addr; | 158 | ip_pkt.dst_ip = dummy.s_addr; |
250 | icmp_pkt.ip.dst_ip = dummy.s_addr; | 159 | ip_pkt.checksum = 0; |
251 | icmp_pkt.ip.checksum = 0; | 160 | ip_pkt.checksum = htons(calc_checksum((uint16_t*)&ip_pkt, sizeof (struct ip_packet))); |
252 | icmp_pkt.ip.checksum = htons(calc_checksum((uint16_t*)&icmp_pkt.ip, sizeof (icmp_pkt.ip))); | 161 | memcpy (&packet[off], &ip_pkt, sizeof (struct ip_packet)); |
253 | icmp_pkt.udp.source_port = htons (target_port_number); | 162 | off += sizeof (struct ip_packet); |
254 | icmp_pkt.udp.dst_port = htons (NAT_TRAV_PORT); | 163 | make_echo (other, &icmp_echo); |
255 | icmp_pkt.udp.mlen_aka_reply_port_magic = htons (source_port_number); | 164 | memcpy (&packet[off], &icmp_echo, sizeof(struct icmp_packet)); |
256 | icmp_pkt.udp.checksum_aka_my_magic = htons (target_port_number); | 165 | off += sizeof (struct icmp_packet); |
257 | icmp_pkt.checksum = htons(calc_checksum((uint16_t*)&icmp_pkt, sizeof (icmp_pkt))); | 166 | icmp_pkt->checksum = htons(calc_checksum((uint16_t*)icmp_pkt, |
258 | memcpy (&packet[off], &icmp_pkt, sizeof (icmp_pkt)); | 167 | sizeof (struct icmp_packet)*2 + sizeof(struct ip_packet))); |
259 | off += sizeof (icmp_pkt); | 168 | |
260 | |||
261 | memset (&dst, 0, sizeof (dst)); | 169 | memset (&dst, 0, sizeof (dst)); |
262 | dst.sin_family = AF_INET; | 170 | dst.sin_family = AF_INET; |
263 | dst.sin_addr = *other; | 171 | dst.sin_addr = *other; |
@@ -266,177 +174,20 @@ send_icmp (const struct in_addr *my_ip, | |||
266 | off, 0, | 174 | off, 0, |
267 | (struct sockaddr*)&dst, | 175 | (struct sockaddr*)&dst, |
268 | sizeof(dst)); /* or sizeof 'struct sockaddr'? */ | 176 | sizeof(dst)); /* or sizeof 'struct sockaddr'? */ |
269 | if (err < 0) { | 177 | if (err < 0) |
270 | fprintf(stderr, | ||
271 | "sendto failed: %s\n", strerror(errno)); | ||
272 | } else if (err != off) | ||
273 | fprintf(stderr, | ||
274 | "Error: partial send of ICMP message\n"); | ||
275 | } | ||
276 | |||
277 | |||
278 | /** | ||
279 | * We discovered the IP address of the other peer. | ||
280 | * Try to connect back to it. | ||
281 | */ | ||
282 | static void | ||
283 | try_connect (const struct in_addr *my_ip, | ||
284 | const struct in_addr *other, | ||
285 | uint16_t port_magic) | ||
286 | { | ||
287 | unsigned int i; | ||
288 | char sbuf [INET_ADDRSTRLEN]; | ||
289 | |||
290 | fprintf (stderr, | ||
291 | "Sending %u ICMPs to `%s' with reply magic %u\n", | ||
292 | NUM_ICMP_REPLIES, | ||
293 | inet_ntop (AF_INET, | ||
294 | other, | ||
295 | sbuf, | ||
296 | sizeof (sbuf)), | ||
297 | port_magic); | ||
298 | for (i=0;i<NUM_ICMP_REPLIES;i++) | ||
299 | send_icmp (my_ip, other, make_port(), port_magic); | ||
300 | } | ||
301 | |||
302 | |||
303 | static void | ||
304 | process_icmp_response (const struct in_addr *my_ip, | ||
305 | int s) | ||
306 | { | ||
307 | char buf[65536]; | ||
308 | ssize_t have; | ||
309 | struct in_addr sip; | ||
310 | uint16_t my_magic; | ||
311 | uint16_t reply_magic; | ||
312 | uint16_t local_port; | ||
313 | struct ip_packet ip_pkt; | ||
314 | struct icmp_packet icmp_pkt; | ||
315 | size_t off; | ||
316 | |||
317 | have = read (s, buf, sizeof (buf)); | ||
318 | if (have == -1) | ||
319 | { | ||
320 | fprintf (stderr, | ||
321 | "Error reading raw socket: %s\n", | ||
322 | strerror (errno)); | ||
323 | /* What now? */ | ||
324 | return; | ||
325 | } | ||
326 | if (have != sizeof (struct ip_packet) + sizeof (struct icmp_packet)) | ||
327 | { | ||
328 | fprintf (stderr, | ||
329 | "Received ICMP message of unexpected size: %u bytes\n", | ||
330 | (unsigned int) have); | ||
331 | return; | ||
332 | } | ||
333 | off = 0; | ||
334 | memcpy (&ip_pkt, &buf[off], sizeof (ip_pkt)); | ||
335 | off += sizeof (ip_pkt); | ||
336 | memcpy (&icmp_pkt, &buf[off], sizeof (icmp_pkt)); | ||
337 | off += sizeof (icmp_pkt); | ||
338 | |||
339 | if ( (ip_pkt.proto == IPPROTO_ICMP) && | ||
340 | (icmp_pkt.type == ICMP_DEST_UNREACH) && | ||
341 | (icmp_pkt.code == ICMP_HOST_UNREACH) ) | ||
342 | { | 178 | { |
343 | /* this is what is normal due to our UDP traffic */ | 179 | fprintf(stderr, |
344 | return; | 180 | "sendto failed: %s\n", strerror(errno)); |
345 | } | 181 | } |
346 | if ( (ip_pkt.proto == IPPROTO_ICMP) && | 182 | else if (err != off) |
347 | (icmp_pkt.type == ICMP_TIME_EXCEEDED) && | ||
348 | (icmp_pkt.code == ICMP_HOST_UNREACH) ) | ||
349 | { | 183 | { |
350 | /* this is what we might see on loopback: this is the format | 184 | fprintf(stderr, |
351 | we as the client send out (the host uses 'ICMP_NET_UNREACH'); | 185 | "Error: partial send of ICMP message\n"); |
352 | Ignore! */ | ||
353 | return; | ||
354 | } | ||
355 | if ( (ip_pkt.proto != IPPROTO_ICMP) || | ||
356 | (icmp_pkt.type != ICMP_TIME_EXCEEDED) || | ||
357 | (icmp_pkt.code != ICMP_NET_UNREACH) ) | ||
358 | { | ||
359 | /* Note the expected client response and not the normal network response */ | ||
360 | #if DEBUG | ||
361 | fprintf (stderr, | ||
362 | "Received unexpected ICMP message contents (%u, %u, %u), ignoring\n", | ||
363 | ip_pkt.proto, | ||
364 | icmp_pkt.type, | ||
365 | icmp_pkt.code); | ||
366 | #endif | ||
367 | return; | ||
368 | } | ||
369 | memcpy(&sip, &ip_pkt.src_ip, sizeof (sip)); | ||
370 | reply_magic = ntohs (icmp_pkt.udp.checksum_aka_my_magic); | ||
371 | my_magic = ntohs (icmp_pkt.udp.mlen_aka_reply_port_magic); | ||
372 | local_port = ntohs (icmp_pkt.udp.source_port); | ||
373 | if (my_magic == 0) | ||
374 | { | ||
375 | #if DEBUG | ||
376 | /* we get these a lot during loopback testing... */ | ||
377 | fprintf (stderr, | ||
378 | "Received ICMP without hint as to which port worked, dropping\n"); | ||
379 | #endif | ||
380 | return; | ||
381 | } | ||
382 | #if DEBUG | ||
383 | fprintf (stderr, | ||
384 | "Received ICMP from `%s' with outgoing port %u, listen port %u and incoming for other peer %u\n", | ||
385 | inet_ntop (AF_INET, | ||
386 | &sip, | ||
387 | buf, | ||
388 | sizeof (buf)), | ||
389 | my_magic, | ||
390 | local_port, | ||
391 | reply_magic); | ||
392 | #endif | ||
393 | if (my_magic == 0) | ||
394 | { | ||
395 | try_connect (my_ip, &sip, reply_magic); | ||
396 | } | ||
397 | else | ||
398 | { | ||
399 | send_icmp (my_ip, &target, my_magic, reply_magic); | ||
400 | printf ("%s:%u listen on %u\n", | ||
401 | inet_ntop (AF_INET, | ||
402 | &sip, | ||
403 | buf, | ||
404 | sizeof(buf)), | ||
405 | my_magic, | ||
406 | local_port); | ||
407 | /* technically, we're done here! */ | ||
408 | exit (0); | ||
409 | } | 186 | } |
410 | } | 187 | } |
411 | 188 | ||
412 | 189 | ||
413 | static int | 190 | static int |
414 | make_icmp_socket () | ||
415 | { | ||
416 | int ret; | ||
417 | |||
418 | ret = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); | ||
419 | if (-1 == ret) | ||
420 | { | ||
421 | fprintf (stderr, | ||
422 | "Error opening RAW socket: %s\n", | ||
423 | strerror (errno)); | ||
424 | return -1; | ||
425 | } | ||
426 | if (ret >= FD_SETSIZE) | ||
427 | { | ||
428 | fprintf (stderr, | ||
429 | "Socket number too large (%d > %u)\n", | ||
430 | ret, | ||
431 | (unsigned int) FD_SETSIZE); | ||
432 | close (ret); | ||
433 | return -1; | ||
434 | } | ||
435 | return ret; | ||
436 | } | ||
437 | |||
438 | |||
439 | static int | ||
440 | make_raw_socket () | 191 | make_raw_socket () |
441 | { | 192 | { |
442 | const int one = 1; | 193 | const int one = 1; |
@@ -450,15 +201,6 @@ make_raw_socket () | |||
450 | strerror (errno)); | 201 | strerror (errno)); |
451 | return -1; | 202 | return -1; |
452 | } | 203 | } |
453 | if (ret >= FD_SETSIZE) | ||
454 | { | ||
455 | fprintf (stderr, | ||
456 | "Socket number too large (%d > %u)\n", | ||
457 | ret, | ||
458 | (unsigned int) FD_SETSIZE); | ||
459 | close (ret); | ||
460 | return -1; | ||
461 | } | ||
462 | if (setsockopt(ret, SOL_SOCKET, SO_BROADCAST, | 204 | if (setsockopt(ret, SOL_SOCKET, SO_BROADCAST, |
463 | (char *)&one, sizeof(one)) == -1) | 205 | (char *)&one, sizeof(one)) == -1) |
464 | fprintf(stderr, | 206 | fprintf(stderr, |
@@ -477,88 +219,34 @@ int | |||
477 | main (int argc, char *const *argv) | 219 | main (int argc, char *const *argv) |
478 | { | 220 | { |
479 | struct in_addr external; | 221 | struct in_addr external; |
480 | unsigned int i; | 222 | uid_t uid; |
481 | unsigned int pos; | 223 | |
482 | fd_set rs; | 224 | if (-1 == (rawsock = make_raw_socket())) |
483 | struct timeval tv; | 225 | return 1; |
484 | struct sockaddr_in dst; | 226 | uid = getuid (); |
485 | uint16_t p; | 227 | if (0 != setresuid (uid, uid, uid)) |
486 | 228 | fprintf (stderr, | |
487 | if (argc != 4) | 229 | "Failed to setresuid: %s\n", |
230 | strerror (errno)); | ||
231 | if (argc != 3) | ||
488 | { | 232 | { |
489 | fprintf (stderr, | 233 | fprintf (stderr, |
490 | "This program must be started with our IP, the targets external IP and the dummy IP address as arguments.\n"); | 234 | "This program must be started with our IP and the targets external IP as arguments.\n"); |
491 | return 1; | 235 | return 1; |
492 | } | 236 | } |
493 | if ( (1 != inet_pton (AF_INET, argv[1], &external)) || | 237 | if ( (1 != inet_pton (AF_INET, argv[1], &external)) || |
494 | (1 != inet_pton (AF_INET, argv[2], &target)) || | 238 | (1 != inet_pton (AF_INET, argv[2], &target)) ) |
495 | (1 != inet_pton (AF_INET, argv[3], &dummy)) ) | ||
496 | { | 239 | { |
497 | fprintf (stderr, | 240 | fprintf (stderr, |
498 | "Error parsing IPv4 address: %s\n", | 241 | "Error parsing IPv4 address: %s\n", |
499 | strerror (errno)); | 242 | strerror (errno)); |
500 | return 1; | 243 | return 1; |
501 | } | 244 | } |
502 | srand (time(NULL)); | 245 | inet_pton (AF_INET, DUMMY_IP, &dummy); |
503 | memset (&dst, 0, sizeof (dst)); | 246 | send_icmp (&external, |
504 | dst.sin_family = AF_INET; | 247 | &target); |
505 | dst.sin_port = htons (NAT_TRAV_PORT); | 248 | close (rawsock); |
506 | dst.sin_addr = dummy; | ||
507 | |||
508 | if (-1 == (icmpsock = make_icmp_socket())) | ||
509 | return 1; | ||
510 | if (-1 == (rawsock = make_raw_socket())) | ||
511 | { | ||
512 | close (icmpsock); | ||
513 | return 1; | ||
514 | } | ||
515 | for (i=0;i<NUM_UDP_PORTS;i++) | ||
516 | udpsocks[i] = make_udp_socket (&udpports[i]); | ||
517 | pos = 0; | ||
518 | while (1) | ||
519 | { | ||
520 | FD_ZERO (&rs); | ||
521 | FD_SET (icmpsock, &rs); | ||
522 | tv.tv_sec = 0; | ||
523 | tv.tv_usec = UDP_SEND_FREQUENCY_MS * 1000; | ||
524 | select (icmpsock + 1, &rs, NULL, NULL, &tv); | ||
525 | /* FIXME: do I need my external IP here? */ | ||
526 | if (FD_ISSET (icmpsock, &rs)) | ||
527 | { | ||
528 | process_icmp_response (&external, icmpsock); | ||
529 | continue; | ||
530 | } | ||
531 | #if DEBUG | ||
532 | fprintf (stderr, | ||
533 | "Sending UDP message to %s:%u\n", | ||
534 | argv[3], | ||
535 | NAT_TRAV_PORT); | ||
536 | #endif | ||
537 | if (-1 == sendto (udpsocks[pos], | ||
538 | NULL, 0, 0, | ||
539 | (struct sockaddr*) &dst, sizeof (dst))) | ||
540 | { | ||
541 | fprintf (stderr, | ||
542 | "sendto failed: %s\n", | ||
543 | strerror (errno)); | ||
544 | close (udpsocks[pos]); | ||
545 | udpsocks[pos] = make_udp_socket (&udpports[pos]); | ||
546 | } | ||
547 | p = make_port (); | ||
548 | #if DEBUG | ||
549 | fprintf (stderr, | ||
550 | "Sending fake ICMP message to %s:%u\n", | ||
551 | argv[1], | ||
552 | p); | ||
553 | #endif | ||
554 | send_icmp (&external, | ||
555 | &target, | ||
556 | p, | ||
557 | 0); | ||
558 | pos = (pos+1) % NUM_UDP_PORTS; | ||
559 | } | ||
560 | return 0; | 249 | return 0; |
561 | } | 250 | } |
562 | 251 | ||
563 | |||
564 | /* end of gnunet-nat-client.c */ | 252 | /* end of gnunet-nat-client.c */ |
diff --git a/src/transport/gnunet-nat-server.c b/src/transport/gnunet-nat-server.c index 936726fb3..225c0af5f 100644 --- a/src/transport/gnunet-nat-server.c +++ b/src/transport/gnunet-nat-server.c | |||
@@ -20,11 +20,11 @@ | |||
20 | 20 | ||
21 | /** | 21 | /** |
22 | * @file src/transport/gnunet-nat-server.c | 22 | * @file src/transport/gnunet-nat-server.c |
23 | * @brief Tool to help bypass NATs using ICMP method; must run as root (for now, later SUID will do) | 23 | * @brief Tool to help bypass NATs using ICMP method; must run as root (SUID will do) |
24 | * This code will work under GNU/Linux only (or maybe BSDs, but never W32) | 24 | * This code will work under GNU/Linux only (or maybe BSDs, but never W32) |
25 | * @author Christian Grothoff | 25 | * @author Christian Grothoff |
26 | */ | 26 | */ |
27 | 27 | #define _GNU_SOURCE | |
28 | #include <sys/types.h> | 28 | #include <sys/types.h> |
29 | #include <sys/socket.h> | 29 | #include <sys/socket.h> |
30 | #include <arpa/inet.h> | 30 | #include <arpa/inet.h> |
@@ -42,37 +42,18 @@ | |||
42 | #include <netinet/ip_icmp.h> | 42 | #include <netinet/ip_icmp.h> |
43 | #include <netinet/in.h> | 43 | #include <netinet/in.h> |
44 | 44 | ||
45 | #define DEBUG 0 | ||
46 | |||
47 | /** | ||
48 | * Number of UDP ports to keep open (typically >= 256). | ||
49 | */ | ||
50 | #define NUM_UDP_PORTS 256 | ||
51 | |||
52 | /** | ||
53 | * Number of ICMP replies to send per message received (typically >= 1024) | ||
54 | */ | ||
55 | #define NUM_ICMP_REPLIES 1024 | ||
56 | |||
57 | /** | 45 | /** |
58 | * How often do we send our UDP messages to keep ports open? (typically < 100ms) | 46 | * Must match IP given in the client. |
59 | */ | 47 | */ |
60 | #define UDP_SEND_FREQUENCY_MS 50 | 48 | #define DUMMY_IP "1.2.3.4" |
61 | 49 | ||
62 | /** | 50 | /** |
63 | * Port we use for the dummy target. | 51 | * How often do we send our ICMP messages to receive replies? |
64 | */ | 52 | */ |
65 | #define NAT_TRAV_PORT 2222 | 53 | #define ICMP_SEND_FREQUENCY_MS 500 |
66 | |||
67 | /** | ||
68 | * How often do we retry to open and bind a UDP socket before giving up? | ||
69 | */ | ||
70 | #define MAX_TRIES 10 | ||
71 | |||
72 | 54 | ||
73 | struct ip_packet | 55 | struct ip_packet |
74 | { | 56 | { |
75 | |||
76 | uint8_t vers_ihl; | 57 | uint8_t vers_ihl; |
77 | uint8_t tos; | 58 | uint8_t tos; |
78 | uint16_t pkt_len; | 59 | uint16_t pkt_len; |
@@ -85,112 +66,20 @@ struct ip_packet | |||
85 | uint32_t dst_ip; | 66 | uint32_t dst_ip; |
86 | }; | 67 | }; |
87 | 68 | ||
88 | |||
89 | struct udp_packet | ||
90 | { | ||
91 | uint16_t source_port; | ||
92 | uint16_t dst_port; | ||
93 | uint16_t mlen_aka_reply_port_magic; | ||
94 | uint16_t checksum_aka_my_magic; | ||
95 | }; | ||
96 | |||
97 | |||
98 | struct icmp_packet | 69 | struct icmp_packet |
99 | { | 70 | { |
100 | uint8_t type; | 71 | uint8_t type; |
101 | uint8_t code; | 72 | uint8_t code; |
102 | uint16_t checksum; | 73 | uint16_t checksum; |
103 | uint32_t reserved; | 74 | uint32_t reserved; |
104 | struct ip_packet ip; | ||
105 | struct udp_packet udp; | ||
106 | }; | ||
107 | |||
108 | |||
109 | /** | ||
110 | * Structure of the data we tack on to the fake ICMP reply | ||
111 | * (last 4 bytes of the 64 bytes). | ||
112 | */ | ||
113 | struct extra_packet | ||
114 | { | ||
115 | /** | ||
116 | * if this is a reply to an icmp, what was the 'my_magic' | ||
117 | * value from the original icmp? | ||
118 | */ | ||
119 | uint16_t reply_port_magic; | ||
120 | |||
121 | /** | ||
122 | * magic value of the sender of this icmp message. | ||
123 | */ | ||
124 | uint16_t my_magic; | ||
125 | }; | 75 | }; |
126 | 76 | ||
127 | static int udpsocks[NUM_UDP_PORTS]; | ||
128 | 77 | ||
129 | static uint16_t udpports[NUM_UDP_PORTS]; | ||
130 | |||
131 | static int icmpsock; | 78 | static int icmpsock; |
132 | 79 | ||
133 | static int rawsock; | 80 | static int rawsock; |
134 | 81 | ||
135 | static struct in_addr dummy; | 82 | static struct in_addr dummy; |
136 | |||
137 | |||
138 | /** | ||
139 | * create a random port number that is not totally | ||
140 | * unlikely to be chosen by the nat box. | ||
141 | */ | ||
142 | static uint16_t make_port () | ||
143 | { | ||
144 | return 1024 + ( (unsigned int)rand ()) % (63 * 1024 - 2); | ||
145 | } | ||
146 | |||
147 | |||
148 | /** | ||
149 | * create a fresh udp socket bound to a random local port. | ||
150 | */ | ||
151 | static int | ||
152 | make_udp_socket (uint16_t *port) | ||
153 | { | ||
154 | int ret; | ||
155 | int tries; | ||
156 | struct sockaddr_in src; | ||
157 | |||
158 | for (tries=0;tries<MAX_TRIES;tries++) | ||
159 | { | ||
160 | ret = socket (AF_INET, SOCK_DGRAM, 0); | ||
161 | if (-1 == ret) | ||
162 | { | ||
163 | fprintf (stderr, | ||
164 | "Error opening udp socket: %s\n", | ||
165 | strerror (errno)); | ||
166 | return -1; | ||
167 | } | ||
168 | if (ret >= FD_SETSIZE) | ||
169 | { | ||
170 | fprintf (stderr, | ||
171 | "Socket number too large (%d > %u)\n", | ||
172 | ret, | ||
173 | (unsigned int) FD_SETSIZE); | ||
174 | close (ret); | ||
175 | return -1; | ||
176 | } | ||
177 | memset (&src, 0, sizeof (src)); | ||
178 | src.sin_family = AF_INET; | ||
179 | src.sin_port = htons (make_port ()); | ||
180 | if (0 != bind (ret, (struct sockaddr*) &src, sizeof (src))) | ||
181 | { | ||
182 | close (ret); | ||
183 | continue; | ||
184 | } | ||
185 | *port = ntohs (src.sin_port); | ||
186 | return ret; | ||
187 | } | ||
188 | fprintf (stderr, | ||
189 | "Error binding udp socket: %s\n", | ||
190 | strerror (errno)); | ||
191 | return -1; | ||
192 | } | ||
193 | |||
194 | 83 | ||
195 | static uint16_t | 84 | static uint16_t |
196 | calc_checksum(const uint16_t *data, | 85 | calc_checksum(const uint16_t *data, |
@@ -208,144 +97,93 @@ calc_checksum(const uint16_t *data, | |||
208 | } | 97 | } |
209 | 98 | ||
210 | 99 | ||
100 | static void | ||
101 | make_echo (const struct in_addr *src_ip, | ||
102 | struct icmp_packet *echo) | ||
103 | { | ||
104 | memset(echo, 0, sizeof(struct icmp_packet)); | ||
105 | echo->type = ICMP_ECHO; | ||
106 | echo->code = 0; | ||
107 | echo->reserved = 0; | ||
108 | echo->checksum = 0; | ||
109 | echo->checksum = htons(calc_checksum((uint16_t*)echo, sizeof (struct icmp_packet))); | ||
110 | } | ||
111 | |||
112 | |||
211 | /** | 113 | /** |
212 | * send an icmp message to the target. | 114 | * Send an ICMP message to the dummy IP. |
213 | * | 115 | * |
214 | * @param my_ip source address (our ip address) | 116 | * @param my_ip source address (our ip address) |
215 | * @param other target address | ||
216 | * @param target_port_number fake port number to put into icmp response | ||
217 | * as well as the icmpextradata as 'my_magic' | ||
218 | * @param source_port_number magic_number that enables the other peer to | ||
219 | * identify our port number ('reply in response to') to | ||
220 | * put in the data portion; 0 if we are initiating; | ||
221 | * goes into 'reply_port_magic' of the icmpextradata | ||
222 | */ | 117 | */ |
223 | static void | 118 | static void |
224 | send_icmp (const struct in_addr *my_ip, | 119 | send_icmp_echo (const struct in_addr *my_ip) |
225 | const struct in_addr *other, | ||
226 | uint16_t target_port_number, | ||
227 | uint16_t source_port_number) | ||
228 | { | 120 | { |
229 | struct ip_packet ip_pkt; | 121 | struct icmp_packet icmp_echo; |
230 | struct icmp_packet icmp_pkt; | ||
231 | struct sockaddr_in dst; | 122 | struct sockaddr_in dst; |
232 | char packet[sizeof (ip_pkt) + sizeof (icmp_pkt)]; | ||
233 | size_t off; | 123 | size_t off; |
234 | int err; | 124 | int err; |
125 | struct ip_packet ip_pkt; | ||
126 | struct icmp_packet icmp_pkt; | ||
127 | char packet[sizeof (ip_pkt) + sizeof (icmp_pkt)]; | ||
235 | 128 | ||
236 | /* ip header: send to (known) ip address */ | ||
237 | off = 0; | 129 | off = 0; |
238 | memset(&ip_pkt, 0, sizeof(ip_pkt)); | 130 | memset(&ip_pkt, 0, sizeof(ip_pkt)); |
239 | ip_pkt.vers_ihl = 0x45;//|(pkt_len>>2);//5;//(ipversion << 4) | (iphdr_size >> 2); | 131 | ip_pkt.vers_ihl = 0x45; |
240 | ip_pkt.tos = 0; | 132 | ip_pkt.tos = 0; |
241 | ip_pkt.pkt_len = sizeof (packet); /* huh? */ | 133 | ip_pkt.pkt_len = sizeof (packet); |
242 | ip_pkt.id = 1; /* kernel will change anyway!? */ | 134 | ip_pkt.id = 1; |
243 | ip_pkt.flags_frag_offset = 0; | 135 | ip_pkt.flags_frag_offset = 0; |
244 | ip_pkt.ttl = IPDEFTTL; | 136 | ip_pkt.ttl = IPDEFTTL; |
245 | ip_pkt.proto = IPPROTO_ICMP; | 137 | ip_pkt.proto = IPPROTO_ICMP; |
246 | ip_pkt.checksum = 0; /* maybe the kernel helps us out..? */ | 138 | ip_pkt.checksum = 0; |
247 | ip_pkt.src_ip = my_ip->s_addr; | 139 | ip_pkt.src_ip = my_ip->s_addr; |
248 | ip_pkt.dst_ip = other->s_addr; | 140 | ip_pkt.dst_ip = dummy.s_addr; |
249 | ip_pkt.checksum = htons(calc_checksum((uint16_t*)&ip_pkt, sizeof (ip_pkt))); | 141 | ip_pkt.checksum = htons(calc_checksum((uint16_t*)&ip_pkt, sizeof (ip_pkt))); |
250 | memcpy (packet, &ip_pkt, sizeof (ip_pkt)); | 142 | memcpy (packet, &ip_pkt, sizeof (ip_pkt)); |
251 | off += sizeof (ip_pkt); | 143 | off += sizeof (ip_pkt); |
252 | 144 | make_echo (my_ip, &icmp_echo); | |
253 | /* icmp reply: time exceeded */ | 145 | memcpy (&packet[off], &icmp_echo, sizeof (icmp_echo)); |
254 | memset(&icmp_pkt, 0, sizeof(icmp_pkt)); | 146 | off += sizeof (icmp_echo); |
255 | icmp_pkt.type = ICMP_TIME_EXCEEDED; | ||
256 | icmp_pkt.code = ICMP_NET_UNREACH; | ||
257 | icmp_pkt.reserved = 0; | ||
258 | icmp_pkt.checksum = 0; | ||
259 | |||
260 | /* ip header of the presumably 'lost' udp packet */ | ||
261 | icmp_pkt.ip.vers_ihl = 0x45; | ||
262 | icmp_pkt.ip.tos = 0; | ||
263 | /* no idea why i need to shift the bits here, but not on ip_pkt->pkt_len... */ | ||
264 | icmp_pkt.ip.pkt_len = (sizeof (ip_pkt) + sizeof (icmp_pkt)) << 8; | ||
265 | icmp_pkt.ip.id = 1; /* kernel sets proper value htons(ip_id_counter); */ | ||
266 | icmp_pkt.ip.flags_frag_offset = 0; | ||
267 | icmp_pkt.ip.ttl = 1; /* real TTL would be 1 on a time exceeded packet */ | ||
268 | icmp_pkt.ip.proto = IPPROTO_UDP; | ||
269 | icmp_pkt.ip.src_ip = other->s_addr; | ||
270 | icmp_pkt.ip.dst_ip = dummy.s_addr; | ||
271 | icmp_pkt.ip.checksum = 0; | ||
272 | icmp_pkt.ip.checksum = htons(calc_checksum((uint16_t*)&icmp_pkt.ip, sizeof (icmp_pkt.ip))); | ||
273 | icmp_pkt.udp.source_port = htons (target_port_number); | ||
274 | icmp_pkt.udp.dst_port = htons (NAT_TRAV_PORT); | ||
275 | icmp_pkt.udp.mlen_aka_reply_port_magic = htons (source_port_number); | ||
276 | icmp_pkt.udp.checksum_aka_my_magic = htons (target_port_number); | ||
277 | icmp_pkt.checksum = htons(calc_checksum((uint16_t*)&icmp_pkt, sizeof (icmp_pkt))); | ||
278 | memcpy (&packet[off], &icmp_pkt, sizeof (icmp_pkt)); | ||
279 | off += sizeof (icmp_pkt); | ||
280 | 147 | ||
281 | memset (&dst, 0, sizeof (dst)); | 148 | memset (&dst, 0, sizeof (dst)); |
282 | dst.sin_family = AF_INET; | 149 | dst.sin_family = AF_INET; |
283 | dst.sin_addr = *other; | 150 | dst.sin_addr = dummy; |
284 | err = sendto(rawsock, | 151 | err = sendto(rawsock, |
285 | packet, | 152 | packet, off, 0, |
286 | off, 0, | ||
287 | (struct sockaddr*)&dst, | 153 | (struct sockaddr*)&dst, |
288 | sizeof(dst)); /* or sizeof 'struct sockaddr'? */ | 154 | sizeof(dst)); |
289 | if (err < 0) { | 155 | if (err < 0) |
290 | fprintf(stderr, | 156 | { |
291 | "sendto failed: %s\n", strerror(errno)); | 157 | fprintf(stderr, |
292 | } else if (err != off) | 158 | "sendto failed: %s\n", strerror(errno)); |
293 | fprintf(stderr, | 159 | } |
294 | "Error: partial send of ICMP message\n"); | 160 | else if (err != off) |
295 | } | 161 | { |
296 | 162 | fprintf(stderr, | |
297 | 163 | "Error: partial send of ICMP message\n"); | |
298 | /** | 164 | } |
299 | * We discovered the IP address of the other peer. | ||
300 | * Try to connect back to it. | ||
301 | */ | ||
302 | static void | ||
303 | try_connect (const struct in_addr *my_ip, | ||
304 | const struct in_addr *other, | ||
305 | uint16_t port_magic) | ||
306 | { | ||
307 | unsigned int i; | ||
308 | #if DEBUG | ||
309 | char sbuf [INET_ADDRSTRLEN]; | ||
310 | |||
311 | fprintf (stderr, | ||
312 | "Sending %u ICMPs to `%s' with reply magic %u\n", | ||
313 | NUM_ICMP_REPLIES, | ||
314 | inet_ntop (AF_INET, | ||
315 | other, | ||
316 | sbuf, | ||
317 | sizeof (sbuf)), | ||
318 | port_magic); | ||
319 | #endif | ||
320 | for (i=0;i<NUM_ICMP_REPLIES;i++) | ||
321 | send_icmp (my_ip, other, make_port(), port_magic); | ||
322 | } | 165 | } |
323 | 166 | ||
324 | 167 | ||
325 | static void | 168 | static void |
326 | process_icmp_response (const struct in_addr *my_ip, | 169 | process_icmp_response () |
327 | int s) | ||
328 | { | 170 | { |
329 | char buf[65536]; | 171 | char buf[65536]; |
330 | ssize_t have; | 172 | ssize_t have; |
331 | struct in_addr sip; | 173 | struct in_addr sip; |
332 | uint16_t my_magic; | ||
333 | uint16_t reply_magic; | ||
334 | uint16_t local_port; | ||
335 | struct ip_packet ip_pkt; | 174 | struct ip_packet ip_pkt; |
336 | struct icmp_packet icmp_pkt; | 175 | struct icmp_packet icmp_pkt; |
337 | size_t off; | 176 | size_t off; |
338 | 177 | ||
339 | have = read (s, buf, sizeof (buf)); | 178 | have = read (icmpsock, buf, sizeof (buf)); |
340 | if (have == -1) | 179 | if (have == -1) |
341 | { | 180 | { |
342 | fprintf (stderr, | 181 | fprintf (stderr, |
343 | "Error reading raw socket: %s\n", | 182 | "Error reading raw socket: %s\n", |
344 | strerror (errno)); | 183 | strerror (errno)); |
345 | /* What now? */ | ||
346 | return; | 184 | return; |
347 | } | 185 | } |
348 | if (have != sizeof (struct ip_packet) + sizeof (struct icmp_packet)) | 186 | if (have != sizeof (struct ip_packet) *2 + sizeof (struct icmp_packet) * 2) |
349 | { | 187 | { |
350 | fprintf (stderr, | 188 | fprintf (stderr, |
351 | "Received ICMP message of unexpected size: %u bytes\n", | 189 | "Received ICMP message of unexpected size: %u bytes\n", |
@@ -357,66 +195,22 @@ process_icmp_response (const struct in_addr *my_ip, | |||
357 | off += sizeof (ip_pkt); | 195 | off += sizeof (ip_pkt); |
358 | memcpy (&icmp_pkt, &buf[off], sizeof (icmp_pkt)); | 196 | memcpy (&icmp_pkt, &buf[off], sizeof (icmp_pkt)); |
359 | off += sizeof (icmp_pkt); | 197 | off += sizeof (icmp_pkt); |
360 | |||
361 | if ( (ip_pkt.proto == IPPROTO_ICMP) && | ||
362 | (icmp_pkt.type == ICMP_DEST_UNREACH) && | ||
363 | (icmp_pkt.code == ICMP_HOST_UNREACH) ) | ||
364 | { | ||
365 | /* this is what is normal due to our UDP traffic */ | ||
366 | return; | ||
367 | } | ||
368 | if ( (ip_pkt.proto == IPPROTO_ICMP) && | ||
369 | (icmp_pkt.type == ICMP_TIME_EXCEEDED) && | ||
370 | (icmp_pkt.code == ICMP_NET_UNREACH) ) | ||
371 | { | ||
372 | /* this is what we might see on loopback: this is the format | ||
373 | we as the server send out (the client uses 'ICMP_HOST_UNREACH'); | ||
374 | Ignore! */ | ||
375 | return; | ||
376 | } | ||
377 | |||
378 | if ( (ip_pkt.proto != IPPROTO_ICMP) || | 198 | if ( (ip_pkt.proto != IPPROTO_ICMP) || |
379 | (icmp_pkt.type != ICMP_TIME_EXCEEDED) || | 199 | (icmp_pkt.type != ICMP_TIME_EXCEEDED) || |
380 | (icmp_pkt.code != ICMP_HOST_UNREACH) ) | 200 | (icmp_pkt.code != 0) ) |
381 | { | 201 | { |
382 | /* Note the expected client response and not the normal network response */ | 202 | /* maybe we got an actual reply back... */ |
383 | fprintf (stderr, | 203 | return; |
384 | "Received unexpected ICMP message contents (%u, %u, %u), ignoring\n", | ||
385 | ip_pkt.proto, | ||
386 | icmp_pkt.type, | ||
387 | icmp_pkt.code); | ||
388 | return; | ||
389 | } | 204 | } |
390 | memcpy(&sip, &ip_pkt.src_ip, sizeof (sip)); | 205 | memcpy(&sip, |
391 | reply_magic = ntohs (icmp_pkt.udp.checksum_aka_my_magic); | 206 | &ip_pkt.src_ip, |
392 | my_magic = ntohs (icmp_pkt.udp.mlen_aka_reply_port_magic); | 207 | sizeof (sip)); |
393 | local_port = ntohs (icmp_pkt.udp.source_port); | 208 | fprintf (stdout, |
394 | #if DEBUG | 209 | "%s\n", |
395 | fprintf (stderr, | ||
396 | "Received ICMP from `%s' with outgoing port %u, listen port %u and incoming port hint for other peer %u\n", | ||
397 | inet_ntop (AF_INET, | 210 | inet_ntop (AF_INET, |
398 | &sip, | 211 | &sip, |
399 | buf, | 212 | buf, |
400 | sizeof (buf)), | 213 | sizeof (buf))); |
401 | my_magic, | ||
402 | local_port, | ||
403 | reply_magic); | ||
404 | #endif | ||
405 | if (my_magic == 0) | ||
406 | { | ||
407 | try_connect (my_ip, &sip, reply_magic); | ||
408 | } | ||
409 | else | ||
410 | { | ||
411 | /* FIXME: should close 'local_port' */ | ||
412 | printf ("%s:%u listen on %u\n", | ||
413 | inet_ntop (AF_INET, | ||
414 | &sip, | ||
415 | buf, | ||
416 | sizeof(buf)), | ||
417 | my_magic, | ||
418 | local_port); | ||
419 | } | ||
420 | } | 214 | } |
421 | 215 | ||
422 | 216 | ||
@@ -460,15 +254,6 @@ make_raw_socket () | |||
460 | strerror (errno)); | 254 | strerror (errno)); |
461 | return -1; | 255 | return -1; |
462 | } | 256 | } |
463 | if (ret >= FD_SETSIZE) | ||
464 | { | ||
465 | fprintf (stderr, | ||
466 | "Socket number too large (%d > %u)\n", | ||
467 | ret, | ||
468 | (unsigned int) FD_SETSIZE); | ||
469 | close (ret); | ||
470 | return -1; | ||
471 | } | ||
472 | if (setsockopt(ret, SOL_SOCKET, SO_BROADCAST, | 257 | if (setsockopt(ret, SOL_SOCKET, SO_BROADCAST, |
473 | (char *)&one, sizeof(one)) == -1) | 258 | (char *)&one, sizeof(one)) == -1) |
474 | fprintf(stderr, | 259 | fprintf(stderr, |
@@ -487,72 +272,46 @@ int | |||
487 | main (int argc, char *const *argv) | 272 | main (int argc, char *const *argv) |
488 | { | 273 | { |
489 | struct in_addr external; | 274 | struct in_addr external; |
490 | unsigned int i; | ||
491 | unsigned int pos; | ||
492 | fd_set rs; | 275 | fd_set rs; |
493 | struct timeval tv; | 276 | struct timeval tv; |
494 | struct sockaddr_in dst; | 277 | uid_t uid; |
495 | 278 | ||
496 | if (argc != 3) | 279 | if (-1 == (icmpsock = make_icmp_socket())) |
280 | return 1; | ||
281 | if (-1 == (rawsock = make_raw_socket())) | ||
282 | { | ||
283 | close (icmpsock); | ||
284 | return 1; | ||
285 | } | ||
286 | uid = getuid (); | ||
287 | if (0 != setresuid (uid, uid, uid)) | ||
288 | fprintf (stderr, | ||
289 | "Failed to setresuid: %s\n", | ||
290 | strerror (errno)); | ||
291 | if (argc != 2) | ||
497 | { | 292 | { |
498 | fprintf (stderr, | 293 | fprintf (stderr, |
499 | "This program must be started with our external IP and the dummy IP address as arguments.\n"); | 294 | "This program must be started with our external IP as the only argument.\n"); |
500 | return 1; | 295 | return 1; |
501 | } | 296 | } |
502 | if ( (1 != inet_pton (AF_INET, argv[1], &external)) || | 297 | if (1 != inet_pton (AF_INET, argv[1], &external)) |
503 | (1 != inet_pton (AF_INET, argv[2], &dummy)) ) | ||
504 | { | 298 | { |
505 | fprintf (stderr, | 299 | fprintf (stderr, |
506 | "Error parsing IPv4 address: %s\n", | 300 | "Error parsing IPv4 address: %s\n", |
507 | strerror (errno)); | 301 | strerror (errno)); |
508 | return 1; | 302 | return 1; |
509 | } | 303 | } |
510 | srand (time(NULL)); | 304 | inet_pton (AF_INET, DUMMY_IP, &dummy); |
511 | memset (&dst, 0, sizeof (dst)); | ||
512 | dst.sin_family = AF_INET; | ||
513 | dst.sin_port = htons (NAT_TRAV_PORT); | ||
514 | dst.sin_addr = dummy; | ||
515 | |||
516 | if (-1 == (icmpsock = make_icmp_socket())) | ||
517 | return 1; | ||
518 | if (-1 == (rawsock = make_raw_socket())) | ||
519 | { | ||
520 | close (icmpsock); | ||
521 | return 1; | ||
522 | } | ||
523 | for (i=0;i<NUM_UDP_PORTS;i++) | ||
524 | udpsocks[i] = make_udp_socket (&udpports[i]); | ||
525 | pos = 0; | ||
526 | while (1) | 305 | while (1) |
527 | { | 306 | { |
528 | FD_ZERO (&rs); | 307 | FD_ZERO (&rs); |
529 | FD_SET (icmpsock, &rs); | 308 | FD_SET (icmpsock, &rs); |
530 | tv.tv_sec = 0; | 309 | tv.tv_sec = 0; |
531 | tv.tv_usec = UDP_SEND_FREQUENCY_MS * 1000; | 310 | tv.tv_usec = ICMP_SEND_FREQUENCY_MS * 1000; |
532 | select (icmpsock + 1, &rs, NULL, NULL, &tv); | 311 | select (icmpsock + 1, &rs, NULL, NULL, &tv); |
533 | /* FIXME: do I need my external IP here? */ | ||
534 | if (FD_ISSET (icmpsock, &rs)) | 312 | if (FD_ISSET (icmpsock, &rs)) |
535 | { | 313 | process_icmp_response (); |
536 | process_icmp_response (&external, icmpsock); | 314 | send_icmp_echo (&external); |
537 | continue; | ||
538 | } | ||
539 | #if DEBUG | ||
540 | fprintf (stderr, | ||
541 | "Sending UDP message to %s:%u\n", | ||
542 | argv[2], | ||
543 | NAT_TRAV_PORT); | ||
544 | #endif | ||
545 | if (-1 == sendto (udpsocks[pos], | ||
546 | NULL, 0, 0, | ||
547 | (struct sockaddr*) &dst, sizeof (dst))) | ||
548 | { | ||
549 | fprintf (stderr, | ||
550 | "sendto failed: %s\n", | ||
551 | strerror (errno)); | ||
552 | close (udpsocks[pos]); | ||
553 | udpsocks[pos] = make_udp_socket (&udpports[pos]); | ||
554 | } | ||
555 | pos = (pos+1) % NUM_UDP_PORTS; | ||
556 | } | 315 | } |
557 | return 0; | 316 | return 0; |
558 | } | 317 | } |