diff options
Diffstat (limited to 'src/transport/gnunet-nat-server.c')
-rw-r--r-- | src/transport/gnunet-nat-server.c | 399 |
1 files changed, 79 insertions, 320 deletions
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 | } |