GNUnet 0.21.1
gnunet-helper-nat-client.c File Reference
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <stdint.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/in.h>
Include dependency graph for gnunet-helper-nat-client.c:

Go to the source code of this file.

Data Structures

struct  ip_header
 IPv4 header. More...
 
struct  icmp_ttl_exceeded_header
 Format of ICMP packet. More...
 
struct  icmp_echo_header
 
struct  udp_header
 Beginning of UDP packet. More...
 

Macros

#define _GNU_SOURCE
 
#define ICMP_TIME_EXCEEDED   11
 
#define GNUNET_memcpy(dst, src, n)
 Call memcpy() but check for n being 0 first. More...
 
#define DUMMY_IP   "192.0.2.86"
 Must match IP given in the server. More...
 
#define NAT_TRAV_PORT   22225
 
#define PACKET_ID   256
 Must match packet ID used by gnunet-helper-nat-server.c. More...
 

Functions

static uint16_t calc_checksum (const uint16_t *data, unsigned int bytes)
 CRC-16 for IP/ICMP headers. More...
 
static void send_icmp_udp (const struct in_addr *my_ip, const struct in_addr *other)
 Send an ICMP message to the target. More...
 
static void send_icmp (const struct in_addr *my_ip, const struct in_addr *other)
 Send an ICMP message to the target. More...
 
int main (int argc, char *const *argv)
 

Variables

static int rawsock
 Socket we use to send our fake ICMP replies. More...
 
static struct in_addr dummy
 Target "dummy" address of the packet we pretend to respond to. More...
 
static uint16_t port
 Our "source" port. More...
 

Macro Definition Documentation

◆ _GNU_SOURCE

#define _GNU_SOURCE

Definition at line 49 of file gnunet-helper-nat-client.c.

◆ ICMP_TIME_EXCEEDED

#define ICMP_TIME_EXCEEDED   11

Definition at line 67 of file gnunet-helper-nat-client.c.

◆ GNUNET_memcpy

#define GNUNET_memcpy (   dst,
  src,
 
)
Value:
do { if (0 != n) { (void) memcpy (dst, src, \
n); \
} } while (0)

Call memcpy() but check for n being 0 first.

In the latter case, it is now safe to pass NULL for src or dst. Unlike traditional memcpy(), returns nothing.

Parameters
dstdestination of the copy, may be NULL if n is zero
srcsource of the copy, may be NULL if n is zero
nnumber of bytes to copy

Definition at line 79 of file gnunet-helper-nat-client.c.

◆ DUMMY_IP

#define DUMMY_IP   "192.0.2.86"

Must match IP given in the server.

Definition at line 86 of file gnunet-helper-nat-client.c.

◆ NAT_TRAV_PORT

#define NAT_TRAV_PORT   22225

Definition at line 88 of file gnunet-helper-nat-client.c.

◆ PACKET_ID

#define PACKET_ID   256

Must match packet ID used by gnunet-helper-nat-server.c.

Definition at line 93 of file gnunet-helper-nat-client.c.

Function Documentation

◆ calc_checksum()

static uint16_t calc_checksum ( const uint16_t *  data,
unsigned int  bytes 
)
static

CRC-16 for IP/ICMP headers.

Parameters
datawhat to calculate the CRC over
bytesnumber of bytes in data (must be multiple of 2)
Returns
the CRC 16.

Definition at line 216 of file gnunet-helper-nat-client.c.

217{
218 uint32_t sum;
219 unsigned int i;
220
221 sum = 0;
222 for (i = 0; i < bytes / 2; i++)
223 sum += data[i];
224 sum = (sum & 0xffff) + (sum >> 16);
225 sum = htons (0xffff - sum);
226 return sum;
227}
static char * data
The data to insert into the dht.

References data, and consensus-simulation::sum.

Referenced by send_icmp(), and send_icmp_udp().

Here is the caller graph for this function:

◆ send_icmp_udp()

static void send_icmp_udp ( const struct in_addr *  my_ip,
const struct in_addr *  other 
)
static

Send an ICMP message to the target.

Parameters
my_ipsource address
othertarget address

Definition at line 237 of file gnunet-helper-nat-client.c.

238{
239 char packet[sizeof(struct ip_header) * 2
240 + sizeof(struct icmp_ttl_exceeded_header)
241 + sizeof(struct udp_header)];
242 struct ip_header ip_pkt;
243 struct icmp_ttl_exceeded_header icmp_pkt;
244 struct udp_header udp_pkt;
245 struct sockaddr_in dst;
246 size_t off;
247 int err;
248
249 /* ip header: send to (known) ip address */
250 off = 0;
251 ip_pkt.vers_ihl = 0x45;
252 ip_pkt.tos = 0;
253 /* should this be BSD only? */
254#if defined(BSD) && defined(__FreeBSD__) && defined(__FreeBSD_kernel__)
255 ip_pkt.pkt_len = sizeof(packet); /* Workaround PR kern/21737 */
256#else
257 ip_pkt.pkt_len = htons (sizeof(packet));
258#endif
259 ip_pkt.id = htons (PACKET_ID);
260 ip_pkt.flags_frag_offset = 0;
261 ip_pkt.ttl = 128;
262 ip_pkt.proto = IPPROTO_ICMP;
263 ip_pkt.checksum = 0;
264 ip_pkt.src_ip = my_ip->s_addr;
265 ip_pkt.dst_ip = other->s_addr;
266 ip_pkt.checksum =
267 htons (calc_checksum ((uint16_t *) &ip_pkt, sizeof(struct ip_header)));
268 GNUNET_memcpy (&packet[off],
269 &ip_pkt,
270 sizeof(struct ip_header));
271 off += sizeof(struct ip_header);
272
273 icmp_pkt.type = ICMP_TIME_EXCEEDED;
274 icmp_pkt.code = 0;
275 icmp_pkt.checksum = 0;
276 icmp_pkt.unused = 0;
277 GNUNET_memcpy (&packet[off],
278 &icmp_pkt,
279 sizeof(struct icmp_ttl_exceeded_header));
280 off += sizeof(struct icmp_ttl_exceeded_header);
281
282 /* ip header of the presumably 'lost' udp packet */
283 ip_pkt.vers_ihl = 0x45;
284 ip_pkt.tos = 0;
285 ip_pkt.pkt_len =
286 htons (sizeof(struct ip_header) + sizeof(struct udp_header));
287 ip_pkt.id = htons (0);
288 ip_pkt.flags_frag_offset = 0;
289 ip_pkt.ttl = 128;
290 ip_pkt.proto = IPPROTO_UDP;
291 ip_pkt.checksum = 0;
292 ip_pkt.src_ip = other->s_addr;
293 ip_pkt.dst_ip = dummy.s_addr;
294 ip_pkt.checksum =
295 htons (calc_checksum ((uint16_t *) &ip_pkt, sizeof(struct ip_header)));
296 GNUNET_memcpy (&packet[off],
297 &ip_pkt,
298 sizeof(struct ip_header));
299 off += sizeof(struct ip_header);
300
301 /* build UDP header */
302 udp_pkt.src_port = htons (NAT_TRAV_PORT);
303 udp_pkt.dst_port = htons (NAT_TRAV_PORT);
304 udp_pkt.length = htons (port);
305 udp_pkt.crc = 0;
306 GNUNET_memcpy (&packet[off],
307 &udp_pkt,
308 sizeof(struct udp_header));
309 off += sizeof(struct udp_header);
310
311 /* set ICMP checksum */
312 icmp_pkt.checksum =
313 htons (calc_checksum
314 ((uint16_t *) &packet[sizeof(struct ip_header)],
315 sizeof(struct icmp_ttl_exceeded_header)
316 + sizeof(struct ip_header) + sizeof(struct udp_header)));
317 GNUNET_memcpy (&packet[sizeof(struct ip_header)],
318 &icmp_pkt,
319 sizeof(struct icmp_ttl_exceeded_header));
320
321 memset (&dst, 0, sizeof(dst));
322 dst.sin_family = AF_INET;
323#if HAVE_SOCKADDR_IN_SIN_LEN
324 dst.sin_len = sizeof(struct sockaddr_in);
325#endif
326 dst.sin_addr = *other;
327 err =
328 sendto (rawsock, packet, sizeof(packet), 0, (struct sockaddr *) &dst,
329 sizeof(dst));
330 if (err < 0)
331 {
332 fprintf (stderr, "sendto failed: %s\n", strerror (errno));
333 }
334 else if (sizeof(packet) != (size_t) err)
335 {
336 fprintf (stderr, "Error: partial send of ICMP message with size %lu\n",
337 (unsigned long) off);
338 }
339}
#define ICMP_TIME_EXCEEDED
static uint16_t calc_checksum(const uint16_t *data, unsigned int bytes)
CRC-16 for IP/ICMP headers.
#define NAT_TRAV_PORT
static uint16_t port
Our "source" port.
static int rawsock
Socket we use to send our fake ICMP replies.
static struct in_addr dummy
Target "dummy" address of the packet we pretend to respond to.
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
#define PACKET_ID
Must match packet ID used by gnunet-helper-nat-server.c.
Beginning of UDP packet.

References calc_checksum(), ip_header::checksum, icmp_ttl_exceeded_header::checksum, icmp_ttl_exceeded_header::code, udp_header::crc, ip_header::dst_ip, udp_header::dst_port, dummy, ip_header::flags_frag_offset, GNUNET_memcpy, ICMP_TIME_EXCEEDED, ip_header::id, udp_header::length, NAT_TRAV_PORT, PACKET_ID, ip_header::pkt_len, port, ip_header::proto, rawsock, ip_header::src_ip, udp_header::src_port, ip_header::tos, ip_header::ttl, icmp_ttl_exceeded_header::type, icmp_ttl_exceeded_header::unused, and ip_header::vers_ihl.

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ send_icmp()

static void send_icmp ( const struct in_addr *  my_ip,
const struct in_addr *  other 
)
static

Send an ICMP message to the target.

Parameters
my_ipsource address
othertarget address

Definition at line 349 of file gnunet-helper-nat-client.c.

350{
351 struct ip_header ip_pkt;
352 struct icmp_ttl_exceeded_header icmp_ttl;
353 struct icmp_echo_header icmp_echo;
354 struct sockaddr_in dst;
355 char packet[sizeof(struct ip_header) * 2
356 + sizeof(struct icmp_ttl_exceeded_header)
357 + sizeof(struct icmp_echo_header)];
358 size_t off;
359 int err;
360
361 /* ip header: send to (known) ip address */
362 off = 0;
363 ip_pkt.vers_ihl = 0x45;
364 ip_pkt.tos = 0;
365#if defined(BSD) && defined(__FreeBSD__) && defined(__FreeBSD_kernel__)
366 ip_pkt.pkt_len = sizeof(packet); /* Workaround PR kern/21737 */
367#else
368 ip_pkt.pkt_len = htons (sizeof(packet));
369#endif
370 ip_pkt.id = htons (PACKET_ID);
371 ip_pkt.flags_frag_offset = 0;
372 ip_pkt.ttl = IPDEFTTL;
373 ip_pkt.proto = IPPROTO_ICMP;
374 ip_pkt.checksum = 0;
375 ip_pkt.src_ip = my_ip->s_addr;
376 ip_pkt.dst_ip = other->s_addr;
377 ip_pkt.checksum =
378 htons (calc_checksum ((uint16_t *) &ip_pkt, sizeof(struct ip_header)));
379 GNUNET_memcpy (&packet[off],
380 &ip_pkt,
381 sizeof(struct ip_header));
382 off = sizeof(ip_pkt);
383
384 /* icmp reply: time exceeded */
385 icmp_ttl.type = ICMP_TIME_EXCEEDED;
386 icmp_ttl.code = 0;
387 icmp_ttl.checksum = 0;
388 icmp_ttl.unused = 0;
389 GNUNET_memcpy (&packet[off],
390 &icmp_ttl,
391 sizeof(struct icmp_ttl_exceeded_header));
392 off += sizeof(struct icmp_ttl_exceeded_header);
393
394 /* ip header of the presumably 'lost' udp packet */
395 ip_pkt.vers_ihl = 0x45;
396 ip_pkt.tos = 0;
397 ip_pkt.pkt_len =
398 htons (sizeof(struct ip_header) + sizeof(struct icmp_echo_header));
399 ip_pkt.id = htons (PACKET_ID);
400 ip_pkt.flags_frag_offset = 0;
401 ip_pkt.ttl = 1; /* real TTL would be 1 on a time exceeded packet */
402 ip_pkt.proto = IPPROTO_ICMP;
403 ip_pkt.src_ip = other->s_addr;
404 ip_pkt.dst_ip = dummy.s_addr;
405 ip_pkt.checksum = 0;
406 ip_pkt.checksum =
407 htons (calc_checksum ((uint16_t *) &ip_pkt, sizeof(struct ip_header)));
408 GNUNET_memcpy (&packet[off],
409 &ip_pkt,
410 sizeof(struct ip_header));
411 off += sizeof(struct ip_header);
412
413 icmp_echo.type = ICMP_ECHO;
414 icmp_echo.code = 0;
415 icmp_echo.reserved = htonl (port);
416 icmp_echo.checksum = 0;
417 icmp_echo.checksum =
418 htons (calc_checksum
419 ((uint16_t *) &icmp_echo, sizeof(struct icmp_echo_header)));
420 GNUNET_memcpy (&packet[off],
421 &icmp_echo,
422 sizeof(struct icmp_echo_header));
423
424 /* no go back to calculate ICMP packet checksum */
425 off = sizeof(struct ip_header);
426 icmp_ttl.checksum =
427 htons (calc_checksum
428 ((uint16_t *) &packet[off],
429 sizeof(struct icmp_ttl_exceeded_header)
430 + sizeof(struct ip_header) + sizeof(struct icmp_echo_header)));
431 GNUNET_memcpy (&packet[off],
432 &icmp_ttl,
433 sizeof(struct icmp_ttl_exceeded_header));
434
435 /* prepare for transmission */
436 memset (&dst, 0, sizeof(dst));
437 dst.sin_family = AF_INET;
438#if HAVE_SOCKADDR_IN_SIN_LEN
439 dst.sin_len = sizeof(struct sockaddr_in);
440#endif
441 dst.sin_addr = *other;
442 err =
443 sendto (rawsock, packet, sizeof(packet), 0, (struct sockaddr *) &dst,
444 sizeof(dst));
445 if (err < 0)
446 {
447 fprintf (stderr, "sendto failed: %s\n", strerror (errno));
448 }
449 else if (sizeof(packet) != (size_t) err)
450 {
451 fprintf (stderr, "Error: partial send of ICMP message\n");
452 }
453}

References calc_checksum(), ip_header::checksum, icmp_ttl_exceeded_header::checksum, icmp_echo_header::checksum, icmp_ttl_exceeded_header::code, icmp_echo_header::code, ip_header::dst_ip, dummy, ip_header::flags_frag_offset, GNUNET_memcpy, ICMP_TIME_EXCEEDED, ip_header::id, PACKET_ID, ip_header::pkt_len, port, ip_header::proto, rawsock, icmp_echo_header::reserved, ip_header::src_ip, ip_header::tos, ip_header::ttl, icmp_ttl_exceeded_header::type, icmp_echo_header::type, icmp_ttl_exceeded_header::unused, and ip_header::vers_ihl.

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ main()

int main ( int  argc,
char *const *  argv 
)

Definition at line 457 of file gnunet-helper-nat-client.c.

458{
459 const int one = 1;
460 struct in_addr external;
461 struct in_addr target;
462 uid_t uid;
463 unsigned int p;
464 int raw_eno;
465 int global_ret;
466
467 /* Create an ICMP raw socket for writing (only operation that requires root) */
468 rawsock = socket (AF_INET, SOCK_RAW, IPPROTO_RAW);
469 raw_eno = errno; /* for later error checking */
470
471 /* now drop root privileges */
472 uid = getuid ();
473#ifdef HAVE_SETRESUID
474 if (0 != setresuid (uid, uid, uid))
475 {
476 fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno));
477 global_ret = 1;
478 goto cleanup;
479 }
480#else
481 if (0 != (setuid (uid) | seteuid (uid)))
482 {
483 fprintf (stderr, "Failed to setuid: %s\n", strerror (errno));
484 global_ret = 2;
485 goto cleanup;
486 }
487#endif
488 if (-1 == rawsock)
489 {
490 fprintf (stderr, "Error opening RAW socket: %s\n", strerror (raw_eno));
491 global_ret = 3;
492 goto cleanup;
493 }
494 if (0 !=
495 setsockopt (rawsock, SOL_SOCKET, SO_BROADCAST, (char *) &one,
496 sizeof(one)))
497 {
498 fprintf (stderr, "setsockopt failed: %s\n", strerror (errno));
499 global_ret = 4;
500 goto cleanup;
501 }
502 if (0 !=
503 setsockopt (rawsock, IPPROTO_IP, IP_HDRINCL, (char *) &one, sizeof(one)))
504 {
505 fprintf (stderr, "setsockopt failed: %s\n", strerror (errno));
506 global_ret = 5;
507 goto cleanup;
508 }
509
510 if (4 != argc)
511 {
512 fprintf (stderr,
513 "This program must be started with our IP, the targets external IP, and our port as arguments.\n");
514 global_ret = 6;
515 goto cleanup;
516 }
517 if ((1 != inet_pton (AF_INET, argv[1], &external)) ||
518 (1 != inet_pton (AF_INET, argv[2], &target)))
519 {
520 fprintf (stderr, "Error parsing IPv4 address: %s\n", strerror (errno));
521 global_ret = 7;
522 goto cleanup;
523 }
524 if ((1 != sscanf (argv[3], "%u", &p)) || (0 == p) || (0xFFFF < p))
525 {
526 fprintf (stderr, "Error parsing port value `%s'\n", argv[3]);
527 global_ret = 8;
528 goto cleanup;
529 }
530 port = (uint16_t) p;
531 if (1 != inet_pton (AF_INET, DUMMY_IP, &dummy))
532 {
533 fprintf (stderr, "Internal error converting dummy IP to binary.\n");
534 global_ret = 9;
535 goto cleanup;
536 }
537 send_icmp (&external, &target);
538 send_icmp_udp (&external, &target);
539 global_ret = 0;
540cleanup:
541 if (-1 != rawsock)
542 (void) close (rawsock);
543 return global_ret;
544}
static int global_ret
Global status value.
static void cleanup(void *cls)
Disconnect and shutdown.
Definition: gnunet-did.c:131
static void send_icmp_udp(const struct in_addr *my_ip, const struct in_addr *other)
Send an ICMP message to the target.
#define DUMMY_IP
Must match IP given in the server.
static void send_icmp(const struct in_addr *my_ip, const struct in_addr *other)
Send an ICMP message to the target.
static struct GNUNET_OS_Process * p
Helper process we started.
Definition: gnunet-uri.c:38

References cleanup(), dummy, DUMMY_IP, global_ret, p, port, rawsock, send_icmp(), and send_icmp_udp().

Here is the call graph for this function:

Variable Documentation

◆ rawsock

int rawsock
static

Socket we use to send our fake ICMP replies.

Definition at line 195 of file gnunet-helper-nat-client.c.

Referenced by main(), send_icmp(), and send_icmp_udp().

◆ dummy

◆ port

uint16_t port
static

Our "source" port.

Definition at line 205 of file gnunet-helper-nat-client.c.

Referenced by main(), send_icmp(), and send_icmp_udp().