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/transport/gnunet-nat-client.c | |
parent | 0e66068912b62ffc503f4c6073e3a0317344559f (diff) | |
download | gnunet-94229794b52dd866fe7d27ffbed20da18934087d.tar.gz gnunet-94229794b52dd866fe7d27ffbed20da18934087d.zip |
stuff
Diffstat (limited to 'src/transport/gnunet-nat-client.c')
-rw-r--r-- | src/transport/gnunet-nat-client.c | 468 |
1 files changed, 78 insertions, 390 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 */ |