GNUnet  0.10.x
gnunet-helper-nat-server.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2010 GNUnet e.V.
4 
5  GNUnet is free software: you can redistribute it and/or modify it
6  under the terms of the GNU Affero General Public License as published
7  by the Free Software Foundation, either version 3 of the License,
8  or (at your option) any later version.
9 
10  GNUnet is distributed in the hope that it will be useful, but
11  WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Affero General Public License for more details.
14 
15  You should have received a copy of the GNU Affero General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  SPDX-License-Identifier: AGPL3.0-or-later
19 */
20 
45 #if HAVE_CONFIG_H
46 /* Just needed for HAVE_SOCKADDR_IN_SIN_LEN test macro! */
47 #include "gnunet_config.h"
48 #else
49 #define _GNU_SOURCE
50 #endif
51 #include <sys/types.h>
52 #include <sys/socket.h>
53 #include <arpa/inet.h>
54 #include <sys/select.h>
55 #include <sys/time.h>
56 #include <sys/types.h>
57 #include <unistd.h>
58 #include <stdio.h>
59 #include <string.h>
60 #include <errno.h>
61 #include <stdlib.h>
62 #include <stdint.h>
63 #include <time.h>
64 #include <netinet/ip.h>
65 #include <netinet/ip_icmp.h>
66 #include <netinet/in.h>
67 
68 /* The following constant is missing from FreeBSD 9.2 */
69 #ifndef ICMP_TIME_EXCEEDED
70 #define ICMP_TIME_EXCEEDED 11
71 #endif
72 
82 #define GNUNET_memcpy(dst,src,n) do { if (0 != n) { (void) memcpy (dst,src,n); } } while (0)
83 
87 #define VERBOSE 0
88 
92 #define PACKET_ID 256
93 
97 #define DUMMY_IP "192.0.2.86"
98 
102 #define NAT_TRAV_PORT 22225
103 
107 #define ICMP_SEND_FREQUENCY_MS 500
108 
112 struct ip_header
113 {
114 
118  uint8_t vers_ihl;
119 
123  uint8_t tos;
124 
128  uint16_t pkt_len;
129 
133  uint16_t id;
134 
138  uint16_t flags_frag_offset;
139 
143  uint8_t ttl;
144 
148  uint8_t proto;
149 
153  uint16_t checksum;
154 
158  uint32_t src_ip;
159 
163  uint32_t dst_ip;
164 };
165 
170 {
171  uint8_t type;
172 
173  uint8_t code;
174 
175  uint16_t checksum;
176 
177  uint32_t unused;
178 
179  /* followed by original payload */
180 };
181 
182 struct icmp_echo_header
183 {
184  uint8_t type;
185 
186  uint8_t code;
187 
188  uint16_t checksum;
189 
190  uint32_t reserved;
191 };
192 
193 
197 struct udp_header
198 {
199  uint16_t src_port;
200 
201  uint16_t dst_port;
202 
203  uint16_t length;
204 
205  uint16_t crc;
206 };
207 
211 static int icmpsock;
212 
216 static int rawsock;
217 
221 static int udpsock;
222 
226 static struct in_addr dummy;
227 
228 
236 static uint16_t
237 calc_checksum (const uint16_t * data, unsigned int bytes)
238 {
239  uint32_t sum;
240  unsigned int i;
241 
242  sum = 0;
243  for (i = 0; i < bytes / 2; i++)
244  sum += data[i];
245  sum = (sum & 0xffff) + (sum >> 16);
246  sum = htons (0xffff - sum);
247  return sum;
248 }
249 
250 
256 static void
257 send_icmp_echo (const struct in_addr *my_ip)
258 {
259  char packet[sizeof (struct ip_header) + sizeof (struct icmp_echo_header)];
260  struct icmp_echo_header icmp_echo;
261  struct ip_header ip_pkt;
262  struct sockaddr_in dst;
263  size_t off;
264  int err;
265 
266  off = 0;
267  ip_pkt.vers_ihl = 0x45;
268  ip_pkt.tos = 0;
269  ip_pkt.pkt_len = htons (sizeof (packet));
270  ip_pkt.id = htons (PACKET_ID);
271  ip_pkt.flags_frag_offset = 0;
272  ip_pkt.ttl = IPDEFTTL;
273  ip_pkt.proto = IPPROTO_ICMP;
274  ip_pkt.checksum = 0;
275  ip_pkt.src_ip = my_ip->s_addr;
276  ip_pkt.dst_ip = dummy.s_addr;
277  ip_pkt.checksum =
278  htons (calc_checksum ((uint16_t *) & ip_pkt,
279  sizeof (struct ip_header)));
280  GNUNET_memcpy (&packet[off],
281  &ip_pkt,
282  sizeof (struct ip_header));
283  off += sizeof (struct ip_header);
284 
285  icmp_echo.type = ICMP_ECHO;
286  icmp_echo.code = 0;
287  icmp_echo.checksum = 0;
288  icmp_echo.reserved = 0;
289  icmp_echo.checksum =
290  htons (calc_checksum
291  ((uint16_t *) & icmp_echo,
292  sizeof (struct icmp_echo_header)));
293  GNUNET_memcpy (&packet[off],
294  &icmp_echo,
295  sizeof (struct icmp_echo_header));
296  off += sizeof (struct icmp_echo_header);
297 
298  memset (&dst, 0, sizeof (dst));
299  dst.sin_family = AF_INET;
300 #if HAVE_SOCKADDR_IN_SIN_LEN
301  dst.sin_len = sizeof (struct sockaddr_in);
302 #endif
303  dst.sin_addr = dummy;
304  err = sendto (rawsock,
305  packet,
306  off,
307  0,
308  (struct sockaddr *) &dst,
309  sizeof (dst));
310  if (err < 0)
311  {
312 #if VERBOSE
313  fprintf (stderr,
314  "sendto failed: %s\n",
315  strerror (errno));
316 #endif
317  }
318  else if (sizeof (packet) != err)
319  {
320  fprintf (stderr,
321  "Error: partial send of ICMP message\n");
322  }
323 }
324 
325 
329 static void
331 {
332  struct sockaddr_in dst;
333  ssize_t err;
334 
335  memset (&dst, 0, sizeof (dst));
336  dst.sin_family = AF_INET;
337 #if HAVE_SOCKADDR_IN_SIN_LEN
338  dst.sin_len = sizeof (struct sockaddr_in);
339 #endif
340  dst.sin_addr = dummy;
341  dst.sin_port = htons (NAT_TRAV_PORT);
342  err = sendto (udpsock,
343  NULL,
344  0,
345  0,
346  (struct sockaddr *) &dst,
347  sizeof (dst));
348  if (err < 0)
349  {
350 #if VERBOSE
351  fprintf (stderr,
352  "sendto failed: %s\n",
353  strerror (errno));
354 #endif
355  }
356  else if (0 != err)
357  {
358  fprintf (stderr,
359  "Error: partial send of ICMP message\n");
360  }
361 }
362 
363 
367 static void
369 {
370  char buf[65536];
371  ssize_t have;
372  struct in_addr source_ip;
373  struct ip_header ip_pkt;
374  struct icmp_ttl_exceeded_header icmp_ttl;
375  struct icmp_echo_header icmp_echo;
376  struct udp_header udp_pkt;
377  size_t off;
378  uint16_t port;
379 
380  have = read (icmpsock, buf, sizeof (buf));
381  if (-1 == have)
382  {
383  fprintf (stderr,
384  "Error reading raw socket: %s\n",
385  strerror (errno));
386  return;
387  }
388 #if VERBOSE
389  fprintf (stderr,
390  "Received message of %u bytes\n",
391  (unsigned int) have);
392 #endif
393  if (have <
394  (ssize_t) (sizeof (struct ip_header) +
395  sizeof (struct icmp_ttl_exceeded_header) +
396  sizeof (struct ip_header)))
397  {
398  /* malformed */
399  return;
400  }
401  off = 0;
402  GNUNET_memcpy (&ip_pkt,
403  &buf[off],
404  sizeof (struct ip_header));
405  off += sizeof (struct ip_header);
406  GNUNET_memcpy (&icmp_ttl,
407  &buf[off],
408  sizeof (struct icmp_ttl_exceeded_header));
409  off += sizeof (struct icmp_ttl_exceeded_header);
410  if ((ICMP_TIME_EXCEEDED != icmp_ttl.type) || (0 != icmp_ttl.code))
411  {
412  /* different type than what we want */
413  return;
414  }
415  /* grab source IP of 1st IP header */
416  source_ip.s_addr = ip_pkt.src_ip;
417 
418  /* skip 2nd IP header */
419  GNUNET_memcpy (&ip_pkt,
420  &buf[off],
421  sizeof (struct ip_header));
422  off += sizeof (struct ip_header);
423 
424  switch (ip_pkt.proto)
425  {
426  case IPPROTO_ICMP:
427  if (have !=
428  (sizeof (struct ip_header) * 2 +
429  sizeof (struct icmp_ttl_exceeded_header) +
430  sizeof (struct icmp_echo_header)))
431  {
432  /* malformed */
433  return;
434  }
435  /* grab ICMP ECHO content */
436  GNUNET_memcpy (&icmp_echo,
437  &buf[off],
438  sizeof (struct icmp_echo_header));
439  port = (uint16_t) ntohl (icmp_echo.reserved);
440  break;
441  case IPPROTO_UDP:
442  if (have !=
443  (sizeof (struct ip_header) * 2 +
444  sizeof (struct icmp_ttl_exceeded_header) + sizeof (struct udp_header)))
445  {
446  /* malformed */
447  return;
448  }
449  /* grab UDP content */
450  GNUNET_memcpy (&udp_pkt,
451  &buf[off],
452  sizeof (struct udp_header));
453  port = ntohs (udp_pkt.length);
454  break;
455  default:
456  /* different type than what we want */
457  return;
458  }
459 
460  if (port == 0)
461  fprintf (stdout, "%s\n",
462  inet_ntop (AF_INET, &source_ip, buf, sizeof (buf)));
463  else
464  fprintf (stdout, "%s:%u\n",
465  inet_ntop (AF_INET, &source_ip, buf, sizeof (buf)),
466  (unsigned int) port);
467  fflush (stdout);
468 }
469 
470 
476 static int
478 {
479  const int one = 1;
480 
481  if (-1 ==
482  setsockopt (rawsock,
483  SOL_SOCKET,
484  SO_BROADCAST,
485  (char *) &one,
486  sizeof (one)))
487  {
488  fprintf (stderr,
489  "setsockopt failed: %s\n",
490  strerror (errno));
491  return -1;
492  }
493  if (-1 ==
494  setsockopt (rawsock,
495  IPPROTO_IP,
496  IP_HDRINCL,
497  (char *) &one,
498  sizeof (one)))
499  {
500  fprintf (stderr,
501  "setsockopt failed: %s\n",
502  strerror (errno));
503  return -1;
504  }
505  return 0;
506 }
507 
508 
515 static int
516 make_udp_socket (const struct in_addr *my_ip)
517 {
518  int ret;
519  struct sockaddr_in addr;
520 
521  ret = socket (AF_INET, SOCK_DGRAM, 0);
522  if (-1 == ret)
523  {
524  fprintf (stderr,
525  "Error opening UDP socket: %s\n",
526  strerror (errno));
527  return -1;
528  }
529  memset (&addr, 0, sizeof (addr));
530  addr.sin_family = AF_INET;
531 #if HAVE_SOCKADDR_IN_SIN_LEN
532  addr.sin_len = sizeof (struct sockaddr_in);
533 #endif
534  addr.sin_addr = *my_ip;
535  addr.sin_port = htons (NAT_TRAV_PORT);
536 
537  if (0 != bind (ret,
538  (struct sockaddr *) &addr,
539  sizeof (addr)))
540  {
541  fprintf (stderr,
542  "Error binding UDP socket to port %u: %s\n",
544  strerror (errno));
545  (void) close (ret);
546  return -1;
547  }
548  return ret;
549 }
550 
551 
552 int
553 main (int argc,
554  char *const *argv)
555 {
556  struct in_addr external;
557  fd_set rs;
558  struct timeval tv;
559  uid_t uid;
560  unsigned int alt;
561  int icmp_eno;
562  int raw_eno;
563  int global_ret;
564 
565  /* Create an ICMP raw socket for reading (we'll check errors later) */
566  icmpsock = socket (AF_INET,
567  SOCK_RAW,
568  IPPROTO_ICMP);
569  icmp_eno = errno;
570 
571  /* Create an (ICMP) raw socket for writing (we'll check errors later) */
572  rawsock = socket (AF_INET,
573  SOCK_RAW,
574  IPPROTO_RAW);
575  raw_eno = errno;
576  udpsock = -1;
577 
578  /* drop root rights */
579  uid = getuid ();
580 #ifdef HAVE_SETRESUID
581  if (0 != setresuid (uid, uid, uid))
582  {
583  fprintf (stderr,
584  "Failed to setresuid: %s\n",
585  strerror (errno));
586  global_ret = 1;
587  goto error_exit;
588  }
589 #else
590  if (0 != (setuid (uid) | seteuid (uid)))
591  {
592  fprintf (stderr,
593  "Failed to setuid: %s\n",
594  strerror (errno));
595  global_ret = 2;
596  goto error_exit;
597  }
598 #endif
599 
600  /* Now that we run without root rights, we can do error checking... */
601  if (2 != argc)
602  {
603  fprintf (stderr,
604  "This program must be started with our (internal NAT) IP as the only argument.\n");
605  global_ret = 3;
606  goto error_exit;
607  }
608  if (1 != inet_pton (AF_INET, argv[1], &external))
609  {
610  fprintf (stderr,
611  "Error parsing IPv4 address: %s\n",
612  strerror (errno));
613  global_ret = 4;
614  goto error_exit;
615  }
616  if (1 != inet_pton (AF_INET, DUMMY_IP, &dummy))
617  {
618  fprintf (stderr,
619  "Internal error converting dummy IP to binary.\n");
620  global_ret = 5;
621  goto error_exit;
622  }
623 
624  /* error checking icmpsock */
625  if (-1 == icmpsock)
626  {
627  fprintf (stderr,
628  "Error opening RAW socket: %s\n",
629  strerror (icmp_eno));
630  global_ret = 6;
631  goto error_exit;
632  }
633  if (icmpsock >= FD_SETSIZE)
634  {
635  /* this could happen if we were started with a large number of already-open
636  file descriptors... */
637  fprintf (stderr,
638  "Socket number too large (%d > %u)\n",
639  icmpsock,
640  (unsigned int) FD_SETSIZE);
641  global_ret = 7;
642  goto error_exit;
643  }
644 
645  /* error checking rawsock */
646  if (-1 == rawsock)
647  {
648  fprintf (stderr,
649  "Error opening RAW socket: %s\n",
650  strerror (raw_eno));
651  global_ret = 8;
652  goto error_exit;
653  }
654  /* no need to check 'rawsock' against FD_SETSIZE as it is never used
655  with 'select' */
656 
657  if (0 != setup_raw_socket ())
658  {
659  global_ret = 9;
660  goto error_exit;
661  }
662 
663  if (-1 == (udpsock = make_udp_socket (&external)))
664  {
665  global_ret = 10;
666  goto error_exit;
667  }
668 
669  alt = 0;
670  while (1)
671  {
672  FD_ZERO (&rs);
673  FD_SET (icmpsock, &rs);
674  tv.tv_sec = 0;
675  tv.tv_usec = ICMP_SEND_FREQUENCY_MS * 1000;
676  if (-1 == select (icmpsock + 1, &rs, NULL, NULL, &tv))
677  {
678  if (errno == EINTR)
679  continue;
680  fprintf (stderr,
681  "select failed: %s\n",
682  strerror (errno));
683  break;
684  }
685  if (1 == getppid ()) /* Check the parent process id, if 1 the parent has died, so we should die too */
686  break;
687  if (FD_ISSET (icmpsock, &rs))
688  {
690  continue;
691  }
692  if (0 == (++alt % 2))
693  send_icmp_echo (&external);
694  else
695  send_udp ();
696  }
697 
698  /* select failed (internal error or OS out of resources) */
699  global_ret = 11;
700 error_exit:
701  if (-1 != icmpsock)
702  (void) close (icmpsock);
703  if (-1 != rawsock)
704  (void) close (rawsock);
705  if (-1 != udpsock)
706  (void) close (udpsock);
707  return global_ret;
708 }
709 
710 
711 /* end of gnunet-helper-nat-server.c */
static void send_udp()
Send a UDP message to the dummy IP.
static int udpsock
Socket we use to send our UDP requests.
uint32_t src_ip
Source address.
uint16_t checksum
Header checksum.
#define PACKET_ID
Must match packet ID used by gnunet-helper-nat-client.c.
static int icmpsock
Socket we use to receive "fake" ICMP replies.
uint16_t id
Identification.
#define DUMMY_IP
Must match IP given in the client.
#define NAT_TRAV_PORT
Port for UDP.
static void process_icmp_response()
We&#39;ve received an ICMP response.
uint32_t dst_ip
Destination address.
uint8_t vers_ihl
Version (4 bits) + Internet header length (4 bits)
uint8_t tos
Type of service.
int main(int argc, char *const *argv)
static int ret
Final status code.
Definition: gnunet-arm.c:89
uint16_t pkt_len
Total length.
static void send_icmp_echo(const struct in_addr *my_ip)
Send an ICMP message to the dummy IP.
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
#define FD_SETSIZE
Definition: winproc.h:39
#define ICMP_TIME_EXCEEDED
uint16_t flags_frag_offset
Flags (3 bits) + Fragment offset (13 bits)
static int make_udp_socket(const struct in_addr *my_ip)
Create a UDP socket for writing.
static uint16_t calc_checksum(const uint16_t *data, unsigned int bytes)
CRC-16 for IP/ICMP headers.
static char buf[2048]
static struct in_addr dummy
Target "dummy" address.
uint8_t ttl
Time to live.
static int rawsock
Socket we use to send our ICMP requests.
static uint16_t port
Port number.
Definition: gnunet-bcd.c:79
static int inet_pton(int af, const char *cp, struct in_addr *buf)
Convert IPv4 address from text to binary form.
#define ICMP_SEND_FREQUENCY_MS
How often do we send our ICMP messages to receive replies?
enum GNUNET_TESTBED_UnderlayLinkModelType type
the type of this model
static unsigned long long reserved
How much space have we currently reserved?
Beginning of UDP packet.
static int setup_raw_socket()
Fully initialize the raw socket.
uint32_t data
The data value.
static int global_ret
Return value from main.