GNUnet  0.11.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, \
83  n); \
84  } } while (0)
85 
89 #define VERBOSE 0
90 
94 #define PACKET_ID 256
95 
99 #define DUMMY_IP "192.0.2.86"
100 
104 #define NAT_TRAV_PORT 22225
105 
109 #define ICMP_SEND_FREQUENCY_MS 500
110 
114 struct ip_header
115 {
119  uint8_t vers_ihl;
120 
124  uint8_t tos;
125 
129  uint16_t pkt_len;
130 
134  uint16_t id;
135 
139  uint16_t flags_frag_offset;
140 
144  uint8_t ttl;
145 
149  uint8_t proto;
150 
154  uint16_t checksum;
155 
159  uint32_t src_ip;
160 
164  uint32_t dst_ip;
165 };
166 
171 {
172  uint8_t type;
173 
174  uint8_t code;
175 
176  uint16_t checksum;
177 
178  uint32_t unused;
179 
180  /* followed by original payload */
181 };
182 
183 struct icmp_echo_header
184 {
185  uint8_t type;
186 
187  uint8_t code;
188 
189  uint16_t checksum;
190 
191  uint32_t reserved;
192 };
193 
194 
198 struct udp_header
199 {
200  uint16_t src_port;
201 
202  uint16_t dst_port;
203 
204  uint16_t length;
205 
206  uint16_t crc;
207 };
208 
212 static int icmpsock;
213 
217 static int rawsock;
218 
222 static int udpsock;
223 
227 static struct in_addr dummy;
228 
229 
237 static uint16_t
238 calc_checksum (const uint16_t *data, unsigned int bytes)
239 {
240  uint32_t sum;
241  unsigned int i;
242 
243  sum = 0;
244  for (i = 0; i < bytes / 2; i++)
245  sum += data[i];
246  sum = (sum & 0xffff) + (sum >> 16);
247  sum = htons (0xffff - sum);
248  return sum;
249 }
250 
251 
257 static void
258 send_icmp_echo (const struct in_addr *my_ip)
259 {
260  char packet[sizeof(struct ip_header) + sizeof(struct icmp_echo_header)];
261  struct icmp_echo_header icmp_echo;
262  struct ip_header ip_pkt;
263  struct sockaddr_in dst;
264  size_t off;
265  int err;
266 
267  off = 0;
268  ip_pkt.vers_ihl = 0x45;
269  ip_pkt.tos = 0;
270  ip_pkt.pkt_len = htons (sizeof(packet));
271  ip_pkt.id = htons (PACKET_ID);
272  ip_pkt.flags_frag_offset = 0;
273  ip_pkt.ttl = IPDEFTTL;
274  ip_pkt.proto = IPPROTO_ICMP;
275  ip_pkt.checksum = 0;
276  ip_pkt.src_ip = my_ip->s_addr;
277  ip_pkt.dst_ip = dummy.s_addr;
278  ip_pkt.checksum =
279  htons (calc_checksum ((uint16_t *) &ip_pkt,
280  sizeof(struct ip_header)));
281  GNUNET_memcpy (&packet[off],
282  &ip_pkt,
283  sizeof(struct ip_header));
284  off += sizeof(struct ip_header);
285 
286  icmp_echo.type = ICMP_ECHO;
287  icmp_echo.code = 0;
288  icmp_echo.checksum = 0;
289  icmp_echo.reserved = 0;
290  icmp_echo.checksum =
291  htons (calc_checksum
292  ((uint16_t *) &icmp_echo,
293  sizeof(struct icmp_echo_header)));
294  GNUNET_memcpy (&packet[off],
295  &icmp_echo,
296  sizeof(struct icmp_echo_header));
297  off += sizeof(struct icmp_echo_header);
298 
299  memset (&dst, 0, sizeof(dst));
300  dst.sin_family = AF_INET;
301 #if HAVE_SOCKADDR_IN_SIN_LEN
302  dst.sin_len = sizeof(struct sockaddr_in);
303 #endif
304  dst.sin_addr = dummy;
305  err = sendto (rawsock,
306  packet,
307  off,
308  0,
309  (struct sockaddr *) &dst,
310  sizeof(dst));
311  if (err < 0)
312  {
313 #if VERBOSE
314  fprintf (stderr,
315  "sendto failed: %s\n",
316  strerror (errno));
317 #endif
318  }
319  else if (sizeof(packet) != err)
320  {
321  fprintf (stderr,
322  "Error: partial send of ICMP message\n");
323  }
324 }
325 
326 
330 static void
332 {
333  struct sockaddr_in dst;
334  ssize_t err;
335 
336  memset (&dst, 0, sizeof(dst));
337  dst.sin_family = AF_INET;
338 #if HAVE_SOCKADDR_IN_SIN_LEN
339  dst.sin_len = sizeof(struct sockaddr_in);
340 #endif
341  dst.sin_addr = dummy;
342  dst.sin_port = htons (NAT_TRAV_PORT);
343  err = sendto (udpsock,
344  NULL,
345  0,
346  0,
347  (struct sockaddr *) &dst,
348  sizeof(dst));
349  if (err < 0)
350  {
351 #if VERBOSE
352  fprintf (stderr,
353  "sendto failed: %s\n",
354  strerror (errno));
355 #endif
356  }
357  else if (0 != err)
358  {
359  fprintf (stderr,
360  "Error: partial send of ICMP message\n");
361  }
362 }
363 
364 
368 static void
370 {
371  char buf[65536];
372  ssize_t have;
373  struct in_addr source_ip;
374  struct ip_header ip_pkt;
375  struct icmp_ttl_exceeded_header icmp_ttl;
376  struct icmp_echo_header icmp_echo;
377  struct udp_header udp_pkt;
378  size_t off;
379  uint16_t port;
380 
381  have = read (icmpsock, buf, sizeof(buf));
382  if (-1 == have)
383  {
384  fprintf (stderr,
385  "Error reading raw socket: %s\n",
386  strerror (errno));
387  return;
388  }
389 #if VERBOSE
390  fprintf (stderr,
391  "Received message of %u bytes\n",
392  (unsigned int) have);
393 #endif
394  if (have <
395  (ssize_t) (sizeof(struct ip_header)
396  + sizeof(struct icmp_ttl_exceeded_header)
397  + sizeof(struct ip_header)))
398  {
399  /* malformed */
400  return;
401  }
402  off = 0;
403  GNUNET_memcpy (&ip_pkt,
404  &buf[off],
405  sizeof(struct ip_header));
406  off += sizeof(struct ip_header);
407  GNUNET_memcpy (&icmp_ttl,
408  &buf[off],
409  sizeof(struct icmp_ttl_exceeded_header));
410  off += sizeof(struct icmp_ttl_exceeded_header);
411  if ((ICMP_TIME_EXCEEDED != icmp_ttl.type) || (0 != icmp_ttl.code))
412  {
413  /* different type than what we want */
414  return;
415  }
416  /* grab source IP of 1st IP header */
417  source_ip.s_addr = ip_pkt.src_ip;
418 
419  /* skip 2nd IP header */
420  GNUNET_memcpy (&ip_pkt,
421  &buf[off],
422  sizeof(struct ip_header));
423  off += sizeof(struct ip_header);
424 
425  switch (ip_pkt.proto)
426  {
427  case IPPROTO_ICMP:
428  if (have !=
429  (sizeof(struct ip_header) * 2
430  + sizeof(struct icmp_ttl_exceeded_header)
431  + sizeof(struct icmp_echo_header)))
432  {
433  /* malformed */
434  return;
435  }
436  /* grab ICMP ECHO content */
437  GNUNET_memcpy (&icmp_echo,
438  &buf[off],
439  sizeof(struct icmp_echo_header));
440  port = (uint16_t) ntohl (icmp_echo.reserved);
441  break;
442 
443  case IPPROTO_UDP:
444  if (have !=
445  (sizeof(struct ip_header) * 2
446  + sizeof(struct icmp_ttl_exceeded_header) + sizeof(struct udp_header)))
447  {
448  /* malformed */
449  return;
450  }
451  /* grab UDP content */
452  GNUNET_memcpy (&udp_pkt,
453  &buf[off],
454  sizeof(struct udp_header));
455  port = ntohs (udp_pkt.length);
456  break;
457 
458  default:
459  /* different type than what we want */
460  return;
461  }
462 
463  if (port == 0)
464  fprintf (stdout, "%s\n",
465  inet_ntop (AF_INET, &source_ip, buf, sizeof(buf)));
466  else
467  fprintf (stdout, "%s:%u\n",
468  inet_ntop (AF_INET, &source_ip, buf, sizeof(buf)),
469  (unsigned int) port);
470  fflush (stdout);
471 }
472 
473 
479 static int
481 {
482  const int one = 1;
483 
484  if (-1 ==
485  setsockopt (rawsock,
486  SOL_SOCKET,
487  SO_BROADCAST,
488  (char *) &one,
489  sizeof(one)))
490  {
491  fprintf (stderr,
492  "setsockopt failed: %s\n",
493  strerror (errno));
494  return -1;
495  }
496  if (-1 ==
497  setsockopt (rawsock,
498  IPPROTO_IP,
499  IP_HDRINCL,
500  (char *) &one,
501  sizeof(one)))
502  {
503  fprintf (stderr,
504  "setsockopt failed: %s\n",
505  strerror (errno));
506  return -1;
507  }
508  return 0;
509 }
510 
511 
518 static int
519 make_udp_socket (const struct in_addr *my_ip)
520 {
521  int ret;
522  struct sockaddr_in addr;
523 
524  ret = socket (AF_INET, SOCK_DGRAM, 0);
525  if (-1 == ret)
526  {
527  fprintf (stderr,
528  "Error opening UDP socket: %s\n",
529  strerror (errno));
530  return -1;
531  }
532  memset (&addr, 0, sizeof(addr));
533  addr.sin_family = AF_INET;
534 #if HAVE_SOCKADDR_IN_SIN_LEN
535  addr.sin_len = sizeof(struct sockaddr_in);
536 #endif
537  addr.sin_addr = *my_ip;
538  addr.sin_port = htons (NAT_TRAV_PORT);
539 
540  if (0 != bind (ret,
541  (struct sockaddr *) &addr,
542  sizeof(addr)))
543  {
544  fprintf (stderr,
545  "Error binding UDP socket to port %u: %s\n",
547  strerror (errno));
548  (void) close (ret);
549  return -1;
550  }
551  return ret;
552 }
553 
554 
555 int
556 main (int argc,
557  char *const *argv)
558 {
559  struct in_addr external;
560  fd_set rs;
561  struct timeval tv;
562  uid_t uid;
563  unsigned int alt;
564  int icmp_eno;
565  int raw_eno;
566  int global_ret;
567 
568  /* Create an ICMP raw socket for reading (we'll check errors later) */
569  icmpsock = socket (AF_INET,
570  SOCK_RAW,
571  IPPROTO_ICMP);
572  icmp_eno = errno;
573 
574  /* Create an (ICMP) raw socket for writing (we'll check errors later) */
575  rawsock = socket (AF_INET,
576  SOCK_RAW,
577  IPPROTO_RAW);
578  raw_eno = errno;
579  udpsock = -1;
580 
581  /* drop root rights */
582  uid = getuid ();
583 #ifdef HAVE_SETRESUID
584  if (0 != setresuid (uid, uid, uid))
585  {
586  fprintf (stderr,
587  "Failed to setresuid: %s\n",
588  strerror (errno));
589  global_ret = 1;
590  goto error_exit;
591  }
592 #else
593  if (0 != (setuid (uid) | seteuid (uid)))
594  {
595  fprintf (stderr,
596  "Failed to setuid: %s\n",
597  strerror (errno));
598  global_ret = 2;
599  goto error_exit;
600  }
601 #endif
602 
603  /* Now that we run without root rights, we can do error checking... */
604  if (2 != argc)
605  {
606  fprintf (stderr,
607  "This program must be started with our (internal NAT) IP as the only argument.\n");
608  global_ret = 3;
609  goto error_exit;
610  }
611  if (1 != inet_pton (AF_INET, argv[1], &external))
612  {
613  fprintf (stderr,
614  "Error parsing IPv4 address: %s\n",
615  strerror (errno));
616  global_ret = 4;
617  goto error_exit;
618  }
619  if (1 != inet_pton (AF_INET, DUMMY_IP, &dummy))
620  {
621  fprintf (stderr,
622  "Internal error converting dummy IP to binary.\n");
623  global_ret = 5;
624  goto error_exit;
625  }
626 
627  /* error checking icmpsock */
628  if (-1 == icmpsock)
629  {
630  fprintf (stderr,
631  "Error opening RAW socket: %s\n",
632  strerror (icmp_eno));
633  global_ret = 6;
634  goto error_exit;
635  }
636  if (icmpsock >= FD_SETSIZE)
637  {
638  /* this could happen if we were started with a large number of already-open
639  file descriptors... */
640  fprintf (stderr,
641  "Socket number too large (%d > %u)\n",
642  icmpsock,
643  (unsigned int) FD_SETSIZE);
644  global_ret = 7;
645  goto error_exit;
646  }
647 
648  /* error checking rawsock */
649  if (-1 == rawsock)
650  {
651  fprintf (stderr,
652  "Error opening RAW socket: %s\n",
653  strerror (raw_eno));
654  global_ret = 8;
655  goto error_exit;
656  }
657  /* no need to check 'rawsock' against FD_SETSIZE as it is never used
658  with 'select' */
659 
660  if (0 != setup_raw_socket ())
661  {
662  global_ret = 9;
663  goto error_exit;
664  }
665 
666  if (-1 == (udpsock = make_udp_socket (&external)))
667  {
668  global_ret = 10;
669  goto error_exit;
670  }
671 
672  alt = 0;
673  while (1)
674  {
675  FD_ZERO (&rs);
676  FD_SET (icmpsock, &rs);
677  tv.tv_sec = 0;
678  tv.tv_usec = ICMP_SEND_FREQUENCY_MS * 1000;
679  if (-1 == select (icmpsock + 1, &rs, NULL, NULL, &tv))
680  {
681  if (errno == EINTR)
682  continue;
683  fprintf (stderr,
684  "select failed: %s\n",
685  strerror (errno));
686  break;
687  }
688  if (1 == getppid ()) /* Check the parent process id, if 1 the parent has died, so we should die too */
689  break;
690  if (FD_ISSET (icmpsock, &rs))
691  {
693  continue;
694  }
695  if (0 == (++alt % 2))
696  send_icmp_echo (&external);
697  else
698  send_udp ();
699  }
700 
701  /* select failed (internal error or OS out of resources) */
702  global_ret = 11;
703 error_exit:
704  if (-1 != icmpsock)
705  (void) close (icmpsock);
706  if (-1 != rawsock)
707  (void) close (rawsock);
708  if (-1 != udpsock)
709  (void) close (udpsock);
710  return global_ret;
711 }
712 
713 
714 /* 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.
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
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)
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 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 proto
Protocol.
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:81
#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.