diff options
author | Christian Grothoff <christian@grothoff.org> | 2010-08-20 13:35:18 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2010-08-20 13:35:18 +0000 |
commit | f315048145045606a012cc737e892bcd06d39ea5 (patch) | |
tree | db5707262e9029a86cd81cabff2349d6062c945b /src/transport/gnunet-nat-client.c | |
parent | b9746a88c40f1a68544b1e576cb57b04cf864b4c (diff) | |
download | gnunet-f315048145045606a012cc737e892bcd06d39ea5.tar.gz gnunet-f315048145045606a012cc737e892bcd06d39ea5.zip |
more code cleanup
Diffstat (limited to 'src/transport/gnunet-nat-client.c')
-rw-r--r-- | src/transport/gnunet-nat-client.c | 218 |
1 files changed, 161 insertions, 57 deletions
diff --git a/src/transport/gnunet-nat-client.c b/src/transport/gnunet-nat-client.c index da70016b7..ddb59bc84 100644 --- a/src/transport/gnunet-nat-client.c +++ b/src/transport/gnunet-nat-client.c | |||
@@ -41,6 +41,10 @@ | |||
41 | * - Nathan Evans | 41 | * - Nathan Evans |
42 | */ | 42 | */ |
43 | #define _GNU_SOURCE | 43 | #define _GNU_SOURCE |
44 | #if HAVE_CONFIG_H | ||
45 | /* Just needed for HAVE_SOCKADDR_IN_SIN_LEN test macro! */ | ||
46 | #include "gnunet_config.h" | ||
47 | #endif | ||
44 | #include <sys/types.h> | 48 | #include <sys/types.h> |
45 | #include <sys/socket.h> | 49 | #include <sys/socket.h> |
46 | #include <arpa/inet.h> | 50 | #include <arpa/inet.h> |
@@ -62,38 +66,93 @@ | |||
62 | 66 | ||
63 | #define NAT_TRAV_PORT 22225 | 67 | #define NAT_TRAV_PORT 22225 |
64 | 68 | ||
69 | /** | ||
70 | * IPv4 header. | ||
71 | */ | ||
65 | struct ip_packet | 72 | struct ip_packet |
66 | { | 73 | { |
74 | |||
75 | /** | ||
76 | * Version (4 bits) + Internet header length (4 bits) | ||
77 | */ | ||
67 | uint8_t vers_ihl; | 78 | uint8_t vers_ihl; |
79 | |||
80 | /** | ||
81 | * Type of service | ||
82 | */ | ||
68 | uint8_t tos; | 83 | uint8_t tos; |
84 | |||
85 | /** | ||
86 | * Total length | ||
87 | */ | ||
69 | uint16_t pkt_len; | 88 | uint16_t pkt_len; |
89 | |||
90 | /** | ||
91 | * Identification | ||
92 | */ | ||
70 | uint16_t id; | 93 | uint16_t id; |
94 | |||
95 | /** | ||
96 | * Flags (3 bits) + Fragment offset (13 bits) | ||
97 | */ | ||
71 | uint16_t flags_frag_offset; | 98 | uint16_t flags_frag_offset; |
99 | |||
100 | /** | ||
101 | * Time to live | ||
102 | */ | ||
72 | uint8_t ttl; | 103 | uint8_t ttl; |
104 | |||
105 | /** | ||
106 | * Protocol | ||
107 | */ | ||
73 | uint8_t proto; | 108 | uint8_t proto; |
109 | |||
110 | /** | ||
111 | * Header checksum | ||
112 | */ | ||
74 | uint16_t checksum; | 113 | uint16_t checksum; |
114 | |||
115 | /** | ||
116 | * Source address | ||
117 | */ | ||
75 | uint32_t src_ip; | 118 | uint32_t src_ip; |
119 | |||
120 | /** | ||
121 | * Destination address | ||
122 | */ | ||
76 | uint32_t dst_ip; | 123 | uint32_t dst_ip; |
77 | }; | 124 | }; |
78 | 125 | ||
126 | /** | ||
127 | * Format of ICMP packet. | ||
128 | */ | ||
79 | struct icmp_packet | 129 | struct icmp_packet |
80 | { | 130 | { |
81 | uint8_t type; | 131 | uint8_t type; |
132 | |||
82 | uint8_t code; | 133 | uint8_t code; |
134 | |||
83 | uint16_t checksum; | 135 | uint16_t checksum; |
84 | uint32_t reserved; | ||
85 | 136 | ||
137 | uint32_t reserved; | ||
86 | }; | 138 | }; |
87 | 139 | ||
88 | struct icmp_echo_packet | 140 | struct icmp_echo_packet |
89 | { | 141 | { |
90 | uint8_t type; | 142 | uint8_t type; |
143 | |||
91 | uint8_t code; | 144 | uint8_t code; |
145 | |||
92 | uint16_t checksum; | 146 | uint16_t checksum; |
147 | |||
93 | uint32_t reserved; | 148 | uint32_t reserved; |
149 | |||
94 | uint32_t data; | 150 | uint32_t data; |
95 | }; | 151 | }; |
96 | 152 | ||
153 | /** | ||
154 | * Beginning of UDP packet. | ||
155 | */ | ||
97 | struct udp_packet | 156 | struct udp_packet |
98 | { | 157 | { |
99 | uint16_t src_port; | 158 | uint16_t src_port; |
@@ -103,12 +162,29 @@ struct udp_packet | |||
103 | uint32_t length; | 162 | uint32_t length; |
104 | }; | 163 | }; |
105 | 164 | ||
165 | /** | ||
166 | * Socket we use to send our fake ICMP replies. | ||
167 | */ | ||
106 | static int rawsock; | 168 | static int rawsock; |
107 | 169 | ||
170 | /** | ||
171 | * Target "dummy" address of the packet we pretend to respond to. | ||
172 | */ | ||
108 | static struct in_addr dummy; | 173 | static struct in_addr dummy; |
109 | 174 | ||
110 | static uint32_t port; | 175 | /** |
176 | * Our "source" port. | ||
177 | */ | ||
178 | static uint16_t port; | ||
179 | |||
111 | 180 | ||
181 | /** | ||
182 | * CRC-16 for IP/ICMP headers. | ||
183 | * | ||
184 | * @param data what to calculate the CRC over | ||
185 | * @param bytes number of bytes in data (must be multiple of 2) | ||
186 | * @return the CRC 16. | ||
187 | */ | ||
112 | static uint16_t | 188 | static uint16_t |
113 | calc_checksum(const uint16_t *data, | 189 | calc_checksum(const uint16_t *data, |
114 | unsigned int bytes) | 190 | unsigned int bytes) |
@@ -125,21 +201,6 @@ calc_checksum(const uint16_t *data, | |||
125 | } | 201 | } |
126 | 202 | ||
127 | 203 | ||
128 | static void | ||
129 | make_echo (const struct in_addr *src_ip, | ||
130 | struct icmp_echo_packet *echo, uint32_t num) | ||
131 | { | ||
132 | memset(echo, 0, sizeof(struct icmp_echo_packet)); | ||
133 | echo->type = ICMP_ECHO; | ||
134 | echo->code = 0; | ||
135 | echo->reserved = 0; | ||
136 | echo->checksum = 0; | ||
137 | echo->data = htons(num); | ||
138 | echo->checksum = htons(calc_checksum((uint16_t*)echo, | ||
139 | sizeof (struct icmp_echo_packet))); | ||
140 | } | ||
141 | |||
142 | |||
143 | /** | 204 | /** |
144 | * Send an ICMP message to the target. | 205 | * Send an ICMP message to the target. |
145 | * | 206 | * |
@@ -206,11 +267,11 @@ send_icmp_udp (const struct in_addr *my_ip, | |||
206 | off += sizeof(ip_pkt); | 267 | off += sizeof(ip_pkt); |
207 | 268 | ||
208 | /* build UDP header */ | 269 | /* build UDP header */ |
209 | udp_pkt.src_port = htons(NAT_TRAV_PORT); /* FIXME: does this port matter? */ | 270 | udp_pkt.src_port = htons(NAT_TRAV_PORT); |
210 | udp_pkt.dst_port = htons(NAT_TRAV_PORT); | 271 | udp_pkt.dst_port = htons(NAT_TRAV_PORT); |
211 | 272 | ||
212 | memset(&udp_pkt.length, 0, sizeof(uint32_t)); | 273 | memset(&udp_pkt.length, 0, sizeof(uint32_t)); |
213 | udp_pkt.length = htonl(port); | 274 | udp_pkt.length = htons (port); |
214 | memcpy(&packet[off], &udp_pkt, sizeof(udp_pkt)); | 275 | memcpy(&packet[off], &udp_pkt, sizeof(udp_pkt)); |
215 | off += sizeof(udp_pkt); | 276 | off += sizeof(udp_pkt); |
216 | 277 | ||
@@ -253,7 +314,7 @@ send_icmp (const struct in_addr *my_ip, | |||
253 | const struct in_addr *other) | 314 | const struct in_addr *other) |
254 | { | 315 | { |
255 | struct ip_packet ip_pkt; | 316 | struct ip_packet ip_pkt; |
256 | struct icmp_packet *icmp_pkt; | 317 | struct icmp_packet icmp_pkt; |
257 | struct icmp_echo_packet icmp_echo; | 318 | struct icmp_echo_packet icmp_echo; |
258 | struct sockaddr_in dst; | 319 | struct sockaddr_in dst; |
259 | char packet[sizeof (struct ip_packet)*2 + sizeof (struct icmp_packet) + sizeof(struct icmp_echo_packet)]; | 320 | char packet[sizeof (struct ip_packet)*2 + sizeof (struct icmp_packet) + sizeof(struct icmp_echo_packet)]; |
@@ -262,8 +323,6 @@ send_icmp (const struct in_addr *my_ip, | |||
262 | int err; | 323 | int err; |
263 | 324 | ||
264 | /* ip header: send to (known) ip address */ | 325 | /* ip header: send to (known) ip address */ |
265 | off = 0; | ||
266 | memset(&ip_pkt, 0, sizeof(ip_pkt)); | ||
267 | ip_pkt.vers_ihl = 0x45; | 326 | ip_pkt.vers_ihl = 0x45; |
268 | ip_pkt.tos = 0; | 327 | ip_pkt.tos = 0; |
269 | ip_pkt.pkt_len = sizeof (packet); /* huh? */ | 328 | ip_pkt.pkt_len = sizeof (packet); /* huh? */ |
@@ -276,22 +335,22 @@ send_icmp (const struct in_addr *my_ip, | |||
276 | ip_pkt.dst_ip = other->s_addr; | 335 | ip_pkt.dst_ip = other->s_addr; |
277 | ip_pkt.checksum = htons(calc_checksum((uint16_t*)&ip_pkt, sizeof (struct ip_packet))); | 336 | ip_pkt.checksum = htons(calc_checksum((uint16_t*)&ip_pkt, sizeof (struct ip_packet))); |
278 | memcpy (packet, &ip_pkt, sizeof (struct ip_packet)); | 337 | memcpy (packet, &ip_pkt, sizeof (struct ip_packet)); |
279 | off += sizeof (ip_pkt); | 338 | off = sizeof (ip_pkt); |
280 | /* icmp reply: time exceeded */ | ||
281 | icmp_pkt = (struct icmp_packet*) &packet[off]; | ||
282 | memset(icmp_pkt, 0, sizeof(struct icmp_packet)); | ||
283 | icmp_pkt->type = ICMP_TIME_EXCEEDED; | ||
284 | icmp_pkt->code = 0; | ||
285 | icmp_pkt->reserved = 0; | ||
286 | icmp_pkt->checksum = 0; | ||
287 | 339 | ||
340 | /* icmp reply: time exceeded */ | ||
341 | icmp_pkt.type = ICMP_TIME_EXCEEDED; | ||
342 | icmp_pkt.code = 0; | ||
343 | icmp_pkt.reserved = 0; | ||
344 | icmp_pkt.checksum = 0; | ||
345 | memcpy (&packet[off], | ||
346 | &icmp_pkt, | ||
347 | sizeof (struct icmp_packet)); | ||
288 | off += sizeof (struct icmp_packet); | 348 | off += sizeof (struct icmp_packet); |
289 | 349 | ||
290 | /* ip header of the presumably 'lost' udp packet */ | 350 | /* ip header of the presumably 'lost' udp packet */ |
291 | ip_pkt.vers_ihl = 0x45; | 351 | ip_pkt.vers_ihl = 0x45; |
292 | ip_pkt.tos = 0; | 352 | ip_pkt.tos = 0; |
293 | ip_pkt.pkt_len = (sizeof (struct ip_packet) + sizeof (struct icmp_echo_packet)); | 353 | ip_pkt.pkt_len = (sizeof (struct ip_packet) + sizeof (struct icmp_echo_packet)); |
294 | |||
295 | ip_pkt.id = 1; | 354 | ip_pkt.id = 1; |
296 | ip_pkt.flags_frag_offset = 0; | 355 | ip_pkt.flags_frag_offset = 0; |
297 | ip_pkt.ttl = 1; /* real TTL would be 1 on a time exceeded packet */ | 356 | ip_pkt.ttl = 1; /* real TTL would be 1 on a time exceeded packet */ |
@@ -303,21 +362,37 @@ send_icmp (const struct in_addr *my_ip, | |||
303 | memcpy (&packet[off], &ip_pkt, sizeof (struct ip_packet)); | 362 | memcpy (&packet[off], &ip_pkt, sizeof (struct ip_packet)); |
304 | off += sizeof (struct ip_packet); | 363 | off += sizeof (struct ip_packet); |
305 | 364 | ||
306 | make_echo (other, &icmp_echo, port); | 365 | icmp_echo.type = ICMP_ECHO; |
307 | memcpy (&packet[off], &icmp_echo, sizeof(struct icmp_echo_packet)); | 366 | icmp_echo.code = 0; |
308 | off += sizeof (struct icmp_echo_packet); | 367 | icmp_echo.reserved = 0; |
309 | 368 | icmp_echo.checksum = 0; | |
310 | icmp_pkt->checksum = htons(calc_checksum((uint16_t*)icmp_pkt, | 369 | icmp_echo.data = htons(port); |
311 | sizeof (struct icmp_packet) + sizeof(struct ip_packet) + sizeof(struct icmp_echo_packet))); | 370 | icmp_echo.checksum = htons(calc_checksum((uint16_t*) &icmp_echo, |
312 | 371 | sizeof (struct icmp_echo_packet))); | |
372 | memcpy (&packet[off], | ||
373 | &icmp_echo, | ||
374 | sizeof(struct icmp_echo_packet)); | ||
375 | |||
376 | /* no go back to calculate ICMP packet checksum */ | ||
377 | off = sizeof (ip_pkt); | ||
378 | icmp_pkt.checksum = htons(calc_checksum(&packet[off], | ||
379 | sizeof (struct icmp_packet) + sizeof(struct ip_packet) + sizeof(struct icmp_echo_packet))); | ||
380 | memcpy (&packet[off], | ||
381 | &icmp_pkt, | ||
382 | sizeof (struct icmp_packet)); | ||
383 | |||
384 | /* prepare for transmission */ | ||
313 | memset (&dst, 0, sizeof (dst)); | 385 | memset (&dst, 0, sizeof (dst)); |
314 | dst.sin_family = AF_INET; | 386 | dst.sin_family = AF_INET; |
387 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
388 | dst.sin_len = sizeof (struct sockaddr_in); | ||
389 | #endif | ||
315 | dst.sin_addr = *other; | 390 | dst.sin_addr = *other; |
316 | err = sendto(rawsock, | 391 | err = sendto(rawsock, |
317 | packet, | 392 | packet, |
318 | off, 0, | 393 | off, 0, |
319 | (struct sockaddr*)&dst, | 394 | (struct sockaddr*)&dst, |
320 | sizeof(dst)); /* or sizeof 'struct sockaddr'? */ | 395 | sizeof(struct sockaddr_in)); |
321 | if (err < 0) | 396 | if (err < 0) |
322 | { | 397 | { |
323 | fprintf(stderr, | 398 | fprintf(stderr, |
@@ -331,6 +406,11 @@ send_icmp (const struct in_addr *my_ip, | |||
331 | } | 406 | } |
332 | 407 | ||
333 | 408 | ||
409 | /** | ||
410 | * Create an ICMP raw socket for writing. | ||
411 | * | ||
412 | * @return -1 on error | ||
413 | */ | ||
334 | static int | 414 | static int |
335 | make_raw_socket () | 415 | make_raw_socket () |
336 | { | 416 | { |
@@ -347,14 +427,22 @@ make_raw_socket () | |||
347 | } | 427 | } |
348 | if (setsockopt(ret, SOL_SOCKET, SO_BROADCAST, | 428 | if (setsockopt(ret, SOL_SOCKET, SO_BROADCAST, |
349 | (char *)&one, sizeof(one)) == -1) | 429 | (char *)&one, sizeof(one)) == -1) |
350 | fprintf(stderr, | 430 | { |
351 | "setsockopt failed: %s\n", | 431 | fprintf(stderr, |
352 | strerror (errno)); | 432 | "setsockopt failed: %s\n", |
433 | strerror (errno)); | ||
434 | close (ret); | ||
435 | return -1; | ||
436 | } | ||
353 | if (setsockopt(ret, IPPROTO_IP, IP_HDRINCL, | 437 | if (setsockopt(ret, IPPROTO_IP, IP_HDRINCL, |
354 | (char *)&one, sizeof(one)) == -1) | 438 | (char *)&one, sizeof(one)) == -1) |
355 | fprintf(stderr, | 439 | { |
356 | "setsockopt failed: %s\n", | 440 | fprintf(stderr, |
357 | strerror (errno)); | 441 | "setsockopt failed: %s\n", |
442 | strerror (errno)); | ||
443 | close (ret); | ||
444 | return -1; | ||
445 | } | ||
358 | return ret; | 446 | return ret; |
359 | } | 447 | } |
360 | 448 | ||
@@ -365,14 +453,7 @@ main (int argc, char *const *argv) | |||
365 | struct in_addr external; | 453 | struct in_addr external; |
366 | struct in_addr target; | 454 | struct in_addr target; |
367 | uid_t uid; | 455 | uid_t uid; |
368 | 456 | unsigned int p; | |
369 | if (-1 == (rawsock = make_raw_socket())) | ||
370 | return 1; | ||
371 | uid = getuid (); | ||
372 | if (0 != setresuid (uid, uid, uid)) | ||
373 | fprintf (stderr, | ||
374 | "Failed to setresuid: %s\n", | ||
375 | strerror (errno)); | ||
376 | 457 | ||
377 | if (argc != 4) | 458 | if (argc != 4) |
378 | { | 459 | { |
@@ -380,8 +461,6 @@ main (int argc, char *const *argv) | |||
380 | "This program must be started with our IP, the targets external IP, and our port as arguments.\n"); | 461 | "This program must be started with our IP, the targets external IP, and our port as arguments.\n"); |
381 | return 1; | 462 | return 1; |
382 | } | 463 | } |
383 | port = atoi(argv[3]); | ||
384 | |||
385 | if ( (1 != inet_pton (AF_INET, argv[1], &external)) || | 464 | if ( (1 != inet_pton (AF_INET, argv[1], &external)) || |
386 | (1 != inet_pton (AF_INET, argv[2], &target)) ) | 465 | (1 != inet_pton (AF_INET, argv[2], &target)) ) |
387 | { | 466 | { |
@@ -390,11 +469,36 @@ main (int argc, char *const *argv) | |||
390 | strerror (errno)); | 469 | strerror (errno)); |
391 | return 1; | 470 | return 1; |
392 | } | 471 | } |
393 | if (1 != inet_pton (AF_INET, DUMMY_IP, &dummy)) abort (); | 472 | if ( (1 != sscanf (argv[3], "%u", &p) ) || |
473 | (p == 0) || | ||
474 | (p > 0xFFFF) ) | ||
475 | { | ||
476 | fprintf (stderr, | ||
477 | "Error parsing port value `%s'\n", | ||
478 | argv[3]); | ||
479 | return 1; | ||
480 | } | ||
481 | port = (uint16_t) p; | ||
482 | if (1 != inet_pton (AF_INET, DUMMY_IP, &dummy)) | ||
483 | { | ||
484 | fprintf (stderr, | ||
485 | "Internal error converting dummy IP to binary.\n"); | ||
486 | return 2; | ||
487 | } | ||
488 | if (-1 == (rawsock = make_raw_socket())) | ||
489 | return 2; | ||
490 | uid = getuid (); | ||
491 | if (0 != setresuid (uid, uid, uid)) | ||
492 | { | ||
493 | fprintf (stderr, | ||
494 | "Failed to setresuid: %s\n", | ||
495 | strerror (errno)); | ||
496 | /* not critical, continue anyway */ | ||
497 | } | ||
394 | send_icmp (&external, | 498 | send_icmp (&external, |
395 | &target); | 499 | &target); |
396 | send_icmp_udp (&external, | 500 | send_icmp_udp (&external, |
397 | &target); | 501 | &target); |
398 | close (rawsock); | 502 | close (rawsock); |
399 | return 0; | 503 | return 0; |
400 | } | 504 | } |