aboutsummaryrefslogtreecommitdiff
path: root/src/transport/gnunet-nat-client.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2010-08-20 13:35:18 +0000
committerChristian Grothoff <christian@grothoff.org>2010-08-20 13:35:18 +0000
commitf315048145045606a012cc737e892bcd06d39ea5 (patch)
treedb5707262e9029a86cd81cabff2349d6062c945b /src/transport/gnunet-nat-client.c
parentb9746a88c40f1a68544b1e576cb57b04cf864b4c (diff)
downloadgnunet-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.c218
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 */
65struct ip_packet 72struct 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 */
79struct icmp_packet 129struct 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
88struct icmp_echo_packet 140struct 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 */
97struct udp_packet 156struct 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 */
106static int rawsock; 168static int rawsock;
107 169
170/**
171 * Target "dummy" address of the packet we pretend to respond to.
172 */
108static struct in_addr dummy; 173static struct in_addr dummy;
109 174
110static uint32_t port; 175/**
176 * Our "source" port.
177 */
178static 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 */
112static uint16_t 188static uint16_t
113calc_checksum(const uint16_t *data, 189calc_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
128static void
129make_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 */
334static int 414static int
335make_raw_socket () 415make_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}