GNUnet 0.21.1
gnunet-helper-nat-server.c File Reference
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/in.h>
Include dependency graph for gnunet-helper-nat-server.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 VERBOSE   0
 Should we print some debug output? More...
 
#define PACKET_ID   256
 Must match packet ID used by gnunet-helper-nat-client.c. More...
 
#define DUMMY_IP   "192.0.2.86"
 Must match IP given in the client. More...
 
#define NAT_TRAV_PORT   22225
 Port for UDP. More...
 
#define ICMP_SEND_FREQUENCY_MS   500
 How often do we send our ICMP messages to receive replies? 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_echo (const struct in_addr *my_ip)
 Send an ICMP message to the dummy IP. More...
 
static void send_udp ()
 Send a UDP message to the dummy IP. More...
 
static void process_icmp_response ()
 We've received an ICMP response. More...
 
static int setup_raw_socket ()
 Fully initialize the raw socket. More...
 
static int make_udp_socket (const struct in_addr *my_ip)
 Create a UDP socket for writing. More...
 
int main (int argc, char *const *argv)
 

Variables

static int icmpsock
 Socket we use to receive "fake" ICMP replies. More...
 
static int rawsock
 Socket we use to send our ICMP requests. More...
 
static int udpsock
 Socket we use to send our UDP requests. More...
 
static struct in_addr dummy
 Target "dummy" address. More...
 

Macro Definition Documentation

◆ _GNU_SOURCE

#define _GNU_SOURCE

Definition at line 50 of file gnunet-helper-nat-server.c.

◆ ICMP_TIME_EXCEEDED

#define ICMP_TIME_EXCEEDED   11

Definition at line 71 of file gnunet-helper-nat-server.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 83 of file gnunet-helper-nat-server.c.

◆ VERBOSE

#define VERBOSE   0

Should we print some debug output?

Definition at line 90 of file gnunet-helper-nat-server.c.

◆ PACKET_ID

#define PACKET_ID   256

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

Definition at line 95 of file gnunet-helper-nat-server.c.

◆ DUMMY_IP

#define DUMMY_IP   "192.0.2.86"

Must match IP given in the client.

Definition at line 100 of file gnunet-helper-nat-server.c.

◆ NAT_TRAV_PORT

#define NAT_TRAV_PORT   22225

Port for UDP.

Definition at line 105 of file gnunet-helper-nat-server.c.

◆ ICMP_SEND_FREQUENCY_MS

#define ICMP_SEND_FREQUENCY_MS   500

How often do we send our ICMP messages to receive replies?

Definition at line 110 of file gnunet-helper-nat-server.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 239 of file gnunet-helper-nat-server.c.

240{
241 uint32_t sum;
242 unsigned int i;
243
244 sum = 0;
245 for (i = 0; i < bytes / 2; i++)
246 sum += data[i];
247 sum = (sum & 0xffff) + (sum >> 16);
248 sum = htons (0xffff - sum);
249 return sum;
250}
static char * data
The data to insert into the dht.

References data, and consensus-simulation::sum.

Referenced by send_icmp_echo().

Here is the caller graph for this function:

◆ send_icmp_echo()

static void send_icmp_echo ( const struct in_addr *  my_ip)
static

Send an ICMP message to the dummy IP.

Parameters
my_ipsource address (our ip address)

Definition at line 259 of file gnunet-helper-nat-server.c.

260{
261 char packet[sizeof(struct ip_header) + sizeof(struct icmp_echo_header)];
262 struct icmp_echo_header icmp_echo;
263 struct ip_header ip_pkt;
264 struct sockaddr_in dst;
265 size_t off;
266 int err;
267
268 off = 0;
269 ip_pkt.vers_ihl = 0x45;
270 ip_pkt.tos = 0;
271 ip_pkt.pkt_len = htons (sizeof(packet));
272 ip_pkt.id = htons (PACKET_ID);
273 ip_pkt.flags_frag_offset = 0;
274 ip_pkt.ttl = IPDEFTTL;
275 ip_pkt.proto = IPPROTO_ICMP;
276 ip_pkt.checksum = 0;
277 ip_pkt.src_ip = my_ip->s_addr;
278 ip_pkt.dst_ip = dummy.s_addr;
279 ip_pkt.checksum =
280 htons (calc_checksum ((uint16_t *) &ip_pkt,
281 sizeof(struct ip_header)));
282 GNUNET_memcpy (&packet[off],
283 &ip_pkt,
284 sizeof(struct ip_header));
285 off += sizeof(struct ip_header);
286
287 icmp_echo.type = ICMP_ECHO;
288 icmp_echo.code = 0;
289 icmp_echo.checksum = 0;
290 icmp_echo.reserved = 0;
291 icmp_echo.checksum =
292 htons (calc_checksum
293 ((uint16_t *) &icmp_echo,
294 sizeof(struct icmp_echo_header)));
295 GNUNET_memcpy (&packet[off],
296 &icmp_echo,
297 sizeof(struct icmp_echo_header));
298 off += sizeof(struct icmp_echo_header);
299
300 memset (&dst, 0, sizeof(dst));
301 dst.sin_family = AF_INET;
302#if HAVE_SOCKADDR_IN_SIN_LEN
303 dst.sin_len = sizeof(struct sockaddr_in);
304#endif
305 dst.sin_addr = dummy;
306 err = sendto (rawsock,
307 packet,
308 off,
309 0,
310 (struct sockaddr *) &dst,
311 sizeof(dst));
312 if (err < 0)
313 {
314#if VERBOSE
315 fprintf (stderr,
316 "sendto failed: %s\n",
317 strerror (errno));
318#endif
319 }
320 else if (sizeof(packet) != err)
321 {
322 fprintf (stderr,
323 "Error: partial send of ICMP message\n");
324 }
325}
static uint16_t calc_checksum(const uint16_t *data, unsigned int bytes)
CRC-16 for IP/ICMP headers.
static int rawsock
Socket we use to send our ICMP requests.
static struct in_addr dummy
Target "dummy" address.
#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-client.c.
uint8_t vers_ihl
Version (4 bits) + Internet header length (4 bits)

References calc_checksum(), ip_header::checksum, icmp_echo_header::checksum, icmp_echo_header::code, ip_header::dst_ip, dummy, ip_header::flags_frag_offset, GNUNET_memcpy, ip_header::id, PACKET_ID, ip_header::pkt_len, ip_header::proto, rawsock, icmp_echo_header::reserved, ip_header::src_ip, ip_header::tos, ip_header::ttl, icmp_echo_header::type, 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_udp()

static void send_udp ( )
static

Send a UDP message to the dummy IP.

Definition at line 332 of file gnunet-helper-nat-server.c.

333{
334 struct sockaddr_in dst;
335 ssize_t err;
336
337 memset (&dst, 0, sizeof(dst));
338 dst.sin_family = AF_INET;
339#if HAVE_SOCKADDR_IN_SIN_LEN
340 dst.sin_len = sizeof(struct sockaddr_in);
341#endif
342 dst.sin_addr = dummy;
343 dst.sin_port = htons (NAT_TRAV_PORT);
344 err = sendto (udpsock,
345 NULL,
346 0,
347 0,
348 (struct sockaddr *) &dst,
349 sizeof(dst));
350 if (err < 0)
351 {
352#if VERBOSE
353 fprintf (stderr,
354 "sendto failed: %s\n",
355 strerror (errno));
356#endif
357 }
358 else if (0 != err)
359 {
360 fprintf (stderr,
361 "Error: partial send of ICMP message\n");
362 }
363}
#define NAT_TRAV_PORT
Port for UDP.
static int udpsock
Socket we use to send our UDP requests.

References dummy, NAT_TRAV_PORT, and udpsock.

Referenced by main().

Here is the caller graph for this function:

◆ process_icmp_response()

static void process_icmp_response ( )
static

We've received an ICMP response.

Process it.

Definition at line 370 of file gnunet-helper-nat-server.c.

371{
372 char buf[65536];
373 ssize_t have;
374 struct in_addr source_ip;
375 struct ip_header ip_pkt;
376 struct icmp_ttl_exceeded_header icmp_ttl;
377 struct icmp_echo_header icmp_echo;
378 struct udp_header udp_pkt;
379 size_t off;
380 uint16_t port;
381
382 have = read (icmpsock, buf, sizeof(buf));
383 if (-1 == have)
384 {
385 fprintf (stderr,
386 "Error reading raw socket: %s\n",
387 strerror (errno));
388 return;
389 }
390#if VERBOSE
391 fprintf (stderr,
392 "Received message of %u bytes\n",
393 (unsigned int) have);
394#endif
395 if (have <
396 (ssize_t) (sizeof(struct ip_header)
397 + sizeof(struct icmp_ttl_exceeded_header)
398 + sizeof(struct ip_header)))
399 {
400 /* malformed */
401 return;
402 }
403 off = 0;
404 GNUNET_memcpy (&ip_pkt,
405 &buf[off],
406 sizeof(struct ip_header));
407 off += sizeof(struct ip_header);
408 GNUNET_memcpy (&icmp_ttl,
409 &buf[off],
410 sizeof(struct icmp_ttl_exceeded_header));
411 off += sizeof(struct icmp_ttl_exceeded_header);
412 if ((ICMP_TIME_EXCEEDED != icmp_ttl.type) || (0 != icmp_ttl.code))
413 {
414 /* different type than what we want */
415 return;
416 }
417 /* grab source IP of 1st IP header */
418 source_ip.s_addr = ip_pkt.src_ip;
419
420 /* skip 2nd IP header */
421 GNUNET_memcpy (&ip_pkt,
422 &buf[off],
423 sizeof(struct ip_header));
424 off += sizeof(struct ip_header);
425
426 switch (ip_pkt.proto)
427 {
428 case IPPROTO_ICMP:
429 if (have !=
430 (sizeof(struct ip_header) * 2
431 + sizeof(struct icmp_ttl_exceeded_header)
432 + sizeof(struct icmp_echo_header)))
433 {
434 /* malformed */
435 return;
436 }
437 /* grab ICMP ECHO content */
438 GNUNET_memcpy (&icmp_echo,
439 &buf[off],
440 sizeof(struct icmp_echo_header));
441 port = (uint16_t) ntohl (icmp_echo.reserved);
442 break;
443
444 case IPPROTO_UDP:
445 if (have !=
446 (sizeof(struct ip_header) * 2
447 + sizeof(struct icmp_ttl_exceeded_header) + sizeof(struct udp_header)))
448 {
449 /* malformed */
450 return;
451 }
452 /* grab UDP content */
453 GNUNET_memcpy (&udp_pkt,
454 &buf[off],
455 sizeof(struct udp_header));
456 port = ntohs (udp_pkt.length);
457 break;
458
459 default:
460 /* different type than what we want */
461 return;
462 }
463
464 if (port == 0)
465 fprintf (stdout, "%s\n",
466 inet_ntop (AF_INET, &source_ip, buf, sizeof(buf)));
467 else
468 fprintf (stdout, "%s:%u\n",
469 inet_ntop (AF_INET, &source_ip, buf, sizeof(buf)),
470 (unsigned int) port);
471 fflush (stdout);
472}
static uint16_t port
Port number.
Definition: gnunet-bcd.c:147
#define ICMP_TIME_EXCEEDED
static int icmpsock
Socket we use to receive "fake" ICMP replies.
Beginning of UDP packet.

References icmp_ttl_exceeded_header::code, GNUNET_memcpy, ICMP_TIME_EXCEEDED, icmpsock, udp_header::length, port, ip_header::proto, icmp_echo_header::reserved, ip_header::src_ip, and icmp_ttl_exceeded_header::type.

Referenced by main().

Here is the caller graph for this function:

◆ setup_raw_socket()

static int setup_raw_socket ( )
static

Fully initialize the raw socket.

Returns
-1 on error, 0 on success

Definition at line 481 of file gnunet-helper-nat-server.c.

482{
483 const int one = 1;
484
485 if (-1 ==
486 setsockopt (rawsock,
487 SOL_SOCKET,
488 SO_BROADCAST,
489 (char *) &one,
490 sizeof(one)))
491 {
492 fprintf (stderr,
493 "setsockopt failed: %s\n",
494 strerror (errno));
495 return -1;
496 }
497 if (-1 ==
498 setsockopt (rawsock,
499 IPPROTO_IP,
500 IP_HDRINCL,
501 (char *) &one,
502 sizeof(one)))
503 {
504 fprintf (stderr,
505 "setsockopt failed: %s\n",
506 strerror (errno));
507 return -1;
508 }
509 return 0;
510}

References rawsock.

Referenced by main().

Here is the caller graph for this function:

◆ make_udp_socket()

static int make_udp_socket ( const struct in_addr *  my_ip)
static

Create a UDP socket for writing.

Parameters
my_ipsource address (our ip address)
Returns
-1 on error

Definition at line 520 of file gnunet-helper-nat-server.c.

521{
522 int ret;
523 struct sockaddr_in addr;
524
525 ret = socket (AF_INET, SOCK_DGRAM, 0);
526 if (-1 == ret)
527 {
528 fprintf (stderr,
529 "Error opening UDP socket: %s\n",
530 strerror (errno));
531 return -1;
532 }
533 memset (&addr, 0, sizeof(addr));
534 addr.sin_family = AF_INET;
535#if HAVE_SOCKADDR_IN_SIN_LEN
536 addr.sin_len = sizeof(struct sockaddr_in);
537#endif
538 addr.sin_addr = *my_ip;
539 addr.sin_port = htons (NAT_TRAV_PORT);
540
541 if (0 != bind (ret,
542 (struct sockaddr *) &addr,
543 sizeof(addr)))
544 {
545 fprintf (stderr,
546 "Error binding UDP socket to port %u: %s\n",
548 strerror (errno));
549 (void) close (ret);
550 return -1;
551 }
552 return ret;
553}
static int ret
Final status code.
Definition: gnunet-arm.c:94

References NAT_TRAV_PORT, and ret.

Referenced by main().

Here is the caller graph for this function:

◆ main()

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

Definition at line 557 of file gnunet-helper-nat-server.c.

559{
560 struct in_addr external;
561 fd_set rs;
562 struct timeval tv;
563 uid_t uid;
564 unsigned int alt;
565 int icmp_eno;
566 int raw_eno;
567 int global_ret;
568
569 /* Create an ICMP raw socket for reading (we'll check errors later) */
570 icmpsock = socket (AF_INET,
571 SOCK_RAW,
572 IPPROTO_ICMP);
573 icmp_eno = errno;
574
575 /* Create an (ICMP) raw socket for writing (we'll check errors later) */
576 rawsock = socket (AF_INET,
577 SOCK_RAW,
578 IPPROTO_RAW);
579 raw_eno = errno;
580 udpsock = -1;
581
582 /* drop root rights */
583 uid = getuid ();
584#ifdef HAVE_SETRESUID
585 if (0 != setresuid (uid, uid, uid))
586 {
587 fprintf (stderr,
588 "Failed to setresuid: %s\n",
589 strerror (errno));
590 global_ret = 1;
591 goto error_exit;
592 }
593#else
594 if (0 != (setuid (uid) | seteuid (uid)))
595 {
596 fprintf (stderr,
597 "Failed to setuid: %s\n",
598 strerror (errno));
599 global_ret = 2;
600 goto error_exit;
601 }
602#endif
603
604 /* Now that we run without root rights, we can do error checking... */
605 if (2 != argc)
606 {
607 fprintf (stderr,
608 "This program must be started with our (internal NAT) IP as the only argument.\n");
609 global_ret = 3;
610 goto error_exit;
611 }
612 if (1 != inet_pton (AF_INET, argv[1], &external))
613 {
614 fprintf (stderr,
615 "Error parsing IPv4 address: %s\n",
616 strerror (errno));
617 global_ret = 4;
618 goto error_exit;
619 }
620 if (1 != inet_pton (AF_INET, DUMMY_IP, &dummy))
621 {
622 fprintf (stderr,
623 "Internal error converting dummy IP to binary.\n");
624 global_ret = 5;
625 goto error_exit;
626 }
627
628 /* error checking icmpsock */
629 if (-1 == icmpsock)
630 {
631 fprintf (stderr,
632 "Error opening RAW socket: %s\n",
633 strerror (icmp_eno));
634 global_ret = 6;
635 goto error_exit;
636 }
637 if (icmpsock >= FD_SETSIZE)
638 {
639 /* this could happen if we were started with a large number of already-open
640 file descriptors... */
641 fprintf (stderr,
642 "Socket number too large (%d > %u)\n",
643 icmpsock,
644 (unsigned int) FD_SETSIZE);
645 global_ret = 7;
646 goto error_exit;
647 }
648
649 /* error checking rawsock */
650 if (-1 == rawsock)
651 {
652 fprintf (stderr,
653 "Error opening RAW socket: %s\n",
654 strerror (raw_eno));
655 global_ret = 8;
656 goto error_exit;
657 }
658 /* no need to check 'rawsock' against FD_SETSIZE as it is never used
659 with 'select' */
660
661 if (0 != setup_raw_socket ())
662 {
663 global_ret = 9;
664 goto error_exit;
665 }
666
667 if (-1 == (udpsock = make_udp_socket (&external)))
668 {
669 global_ret = 10;
670 goto error_exit;
671 }
672
673 alt = 0;
674 while (1)
675 {
676 FD_ZERO (&rs);
677 FD_SET (icmpsock, &rs);
678 tv.tv_sec = 0;
679 tv.tv_usec = ICMP_SEND_FREQUENCY_MS * 1000;
680 if (-1 == select (icmpsock + 1, &rs, NULL, NULL, &tv))
681 {
682 if (errno == EINTR)
683 continue;
684 fprintf (stderr,
685 "select failed: %s\n",
686 strerror (errno));
687 break;
688 }
689 if (1 == getppid ()) /* Check the parent process id, if 1 the parent has died, so we should die too */
690 break;
691 if (FD_ISSET (icmpsock, &rs))
692 {
694 continue;
695 }
696 if (0 == (++alt % 2))
697 send_icmp_echo (&external);
698 else
699 send_udp ();
700 }
701
702 /* select failed (internal error or OS out of resources) */
703 global_ret = 11;
704error_exit:
705 if (-1 != icmpsock)
706 (void) close (icmpsock);
707 if (-1 != rawsock)
708 (void) close (rawsock);
709 if (-1 != udpsock)
710 (void) close (udpsock);
711 return global_ret;
712}
static int global_ret
Global status value.
static void process_icmp_response()
We've received an ICMP response.
static void send_udp()
Send a UDP message to the dummy IP.
#define DUMMY_IP
Must match IP given in the client.
static int setup_raw_socket()
Fully initialize the raw socket.
#define ICMP_SEND_FREQUENCY_MS
How often do we send our ICMP messages to receive replies?
static int make_udp_socket(const struct in_addr *my_ip)
Create a UDP socket for writing.
static void send_icmp_echo(const struct in_addr *my_ip)
Send an ICMP message to the dummy IP.

References dummy, DUMMY_IP, global_ret, ICMP_SEND_FREQUENCY_MS, icmpsock, make_udp_socket(), process_icmp_response(), rawsock, send_icmp_echo(), send_udp(), setup_raw_socket(), and udpsock.

Here is the call graph for this function:

Variable Documentation

◆ icmpsock

int icmpsock
static

Socket we use to receive "fake" ICMP replies.

Definition at line 213 of file gnunet-helper-nat-server.c.

Referenced by main(), and process_icmp_response().

◆ rawsock

int rawsock
static

Socket we use to send our ICMP requests.

Definition at line 218 of file gnunet-helper-nat-server.c.

Referenced by main(), send_icmp_echo(), and setup_raw_socket().

◆ udpsock

int udpsock
static

Socket we use to send our UDP requests.

Definition at line 223 of file gnunet-helper-nat-server.c.

Referenced by main(), and send_udp().

◆ dummy

struct in_addr dummy
static

Target "dummy" address.

Definition at line 228 of file gnunet-helper-nat-server.c.

Referenced by main(), send_icmp_echo(), and send_udp().