From 11a2d8cd5b619a0fea63e766585c6ec4687a0707 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Fri, 1 Jul 2011 08:46:27 +0000 Subject: renaming gnunet-nat-server/client for consistency, other minor fixes --- HACKING | 9 + src/nat/Makefile.am | 28 +- src/nat/gnunet-helper-nat-client-windows.c | 550 ++++++++++++++++++++++++ src/nat/gnunet-helper-nat-client.c | 527 +++++++++++++++++++++++ src/nat/gnunet-helper-nat-server-windows.c | 653 +++++++++++++++++++++++++++++ src/nat/gnunet-helper-nat-server.c | 651 ++++++++++++++++++++++++++++ src/nat/gnunet-nat-client-windows.c | 550 ------------------------ src/nat/gnunet-nat-client.c | 527 ----------------------- src/nat/gnunet-nat-server-windows.c | 653 ----------------------------- src/nat/gnunet-nat-server.c | 631 ++-------------------------- src/nat/nat.c | 52 +-- src/topology/gnunet-daemon-topology.c | 2 +- src/transport/Makefile.am | 8 + 13 files changed, 2465 insertions(+), 2376 deletions(-) create mode 100644 src/nat/gnunet-helper-nat-client-windows.c create mode 100644 src/nat/gnunet-helper-nat-client.c create mode 100644 src/nat/gnunet-helper-nat-server-windows.c create mode 100644 src/nat/gnunet-helper-nat-server.c delete mode 100644 src/nat/gnunet-nat-client-windows.c delete mode 100644 src/nat/gnunet-nat-client.c delete mode 100644 src/nat/gnunet-nat-server-windows.c diff --git a/HACKING b/HACKING index 535d4498f..ecd9e6adb 100644 --- a/HACKING +++ b/HACKING @@ -14,6 +14,15 @@ include files: * gettext.h --- external library +binaries: +- gnunet-service-xxx: service process (has listen socket) +- gnunet-daemon-xxx: daemon process (no listen socket) +- gnunet-helper-xxx[-yyy]: SUID helper for module xxx +- gnunet-yyy: command-line tool for end-users +- libgnunet_plugin_xxx_yyy.so: plugin for API xxx +- libgnunetxxx.so: library for API xxx + + configuration: - paths (that are substituted in all filenames) are in PATHS (have as few as possible) - globals for the daemon are in [gnunetd] (for now, have as few as possible!) diff --git a/src/nat/Makefile.am b/src/nat/Makefile.am index a60b4b5f3..e8dadb240 100644 --- a/src/nat/Makefile.am +++ b/src/nat/Makefile.am @@ -2,36 +2,38 @@ INCLUDES = -I$(top_srcdir)/src/include if MINGW WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols - NATBIN = gnunet-nat-server gnunet-nat-client - NATSERVER = gnunet-nat-server-windows.c - NATCLIENT = gnunet-nat-client-windows.c -else - NATSERVER = gnunet-nat-server.c - NATCLIENT = gnunet-nat-client.c + NATBIN = gnunet-helper-nat-server gnunet-helper-nat-client + NATSERVER = gnunet-helper-nat-server-windows.c + NATCLIENT = gnunet-helper-nat-client-windows.c endif if LINUX -NATBIN = gnunet-nat-server gnunet-nat-client +NATBIN = gnunet-helper-nat-server gnunet-helper-nat-client +NATSERVER = gnunet-helper-nat-server.c +NATCLIENT = gnunet-helper-nat-client.c install-exec-hook: - chown root:root $(bindir)/gnunet-nat-server $(bindir)/gnunet-nat-client $(bindir)/gnunet-transport-wlan-helper || true - chmod u+s $(bindir)/gnunet-nat-server $(bindir)/gnunet-nat-client $(bindir)/gnunet-transport-wlan-helper || true + chown root:root $(bindir)/gnunet-helper-nat-server $(bindir)/gnunet-helper-nat-client || true + chmod u+s $(bindir)/gnunet-helper-nat-server $(bindir)/gnunet-helper-nat-client || true else install-exec-hook: endif bin_PROGRAMS = \ + gnunet-nat-server \ $(NATBIN) gnunet_nat_server_SOURCES = \ + gnunet-nat-server.c +gnunet_nat_server_LDADD = \ + $(top_builddir)/src/util/libgnunetutil.la + +gnunet_helper_nat_server_SOURCES = \ $(NATSERVER) -gnunet_nat_client_SOURCES = \ +gnunet_helper_nat_client_SOURCES = \ $(NATCLIENT) -if MINGW - WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols -endif if USE_COVERAGE AM_CFLAGS = -fprofile-arcs -ftest-coverage diff --git a/src/nat/gnunet-helper-nat-client-windows.c b/src/nat/gnunet-helper-nat-client-windows.c new file mode 100644 index 000000000..0717eecfe --- /dev/null +++ b/src/nat/gnunet-helper-nat-client-windows.c @@ -0,0 +1,550 @@ +/* + This file is part of GNUnet. + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file src/nat/gnunet-helper-nat-client-windows.c + * @brief Tool to help bypass NATs using ICMP method; must run as + * administrator on W32 + * This code is forx W32. + * @author Nathan Evans + * + * This program will send ONE ICMP message using RAW sockets + * to the IP address specified as the second argument. Since + * it uses RAW sockets, it must be installed SUID or run as 'root'. + * In order to keep the security risk of the resulting SUID binary + * minimal, the program ONLY opens the RAW socket with root + * privileges, then drops them and only then starts to process + * command line arguments. The code also does not link against + * any shared libraries (except libc) and is strictly minimal + * (except for checking for errors). The following list of people + * have reviewed this code and considered it safe since the last + * modification (if you reviewed it, please have your name added + * to the list): + * + * - Christian Grothoff + * - Nathan Evans + */ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define ICMP_ECHO 8 +#define IPDEFTTL 64 +#define ICMP_TIME_EXCEEDED 11 + +/** + * Must match IP given in the server. + */ +#define DUMMY_IP "192.0.2.86" + +#define NAT_TRAV_PORT 22225 + +/** + * IPv4 header. + */ +struct ip_header +{ + + /** + * Version (4 bits) + Internet header length (4 bits) + */ + uint8_t vers_ihl; + + /** + * Type of service + */ + uint8_t tos; + + /** + * Total length + */ + uint16_t pkt_len; + + /** + * Identification + */ + uint16_t id; + + /** + * Flags (3 bits) + Fragment offset (13 bits) + */ + uint16_t flags_frag_offset; + + /** + * Time to live + */ + uint8_t ttl; + + /** + * Protocol + */ + uint8_t proto; + + /** + * Header checksum + */ + uint16_t checksum; + + /** + * Source address + */ + uint32_t src_ip; + + /** + * Destination address + */ + uint32_t dst_ip; +}; + + +/** + * Format of ICMP packet. + */ +struct icmp_ttl_exceeded_header +{ + uint8_t type; + + uint8_t code; + + uint16_t checksum; + + uint32_t unused; + + /* followed by original payload */ +}; + +struct icmp_echo_header +{ + uint8_t type; + + uint8_t code; + + uint16_t checksum; + + uint32_t reserved; +}; + +/** + * Beginning of UDP packet. + */ +struct udp_header +{ + uint16_t src_port; + + uint16_t dst_port; + + uint16_t length; + + uint16_t crc; +}; + + +/** + * Socket we use to send our ICMP packets. + */ +static SOCKET rawsock; + +/** + * Target "dummy" address. + */ +static struct in_addr dummy; + +/** + * Port we are listening on (communicated to the server). + */ +static uint16_t port; + + + +/** + * Convert IPv4 address from text to binary form. + * + * @param af address family + * @param cp the address to print + * @param buf where to write the address result + * @return 1 on success + */ +static int +inet_pton (int af, + const char *cp, + struct in_addr *buf) +{ + buf->s_addr = inet_addr(cp); + if (buf->s_addr == INADDR_NONE) + { + fprintf(stderr, + "Error %d handling address %s", + WSAGetLastError(), + cp); + return 0; + } + return 1; +} + + +/** + * CRC-16 for IP/ICMP headers. + * + * @param data what to calculate the CRC over + * @param bytes number of bytes in data (must be multiple of 2) + * @return the CRC 16. + */ +static uint16_t +calc_checksum(const uint16_t *data, + unsigned int bytes) +{ + uint32_t sum; + unsigned int i; + + sum = 0; + for (i=0;i> 16); + sum = htons(0xffff - sum); + return sum; +} + + +/** + * Send an ICMP message to the target. + * + * @param my_ip source address + * @param other target address + */ +static void +send_icmp_udp (const struct in_addr *my_ip, + const struct in_addr *other) +{ + char packet[sizeof(struct ip_header) * 2 + + sizeof(struct icmp_ttl_exceeded_header) + + sizeof(struct udp_header)]; + struct ip_header ip_pkt; + struct icmp_ttl_exceeded_header icmp_pkt; + struct udp_header udp_pkt; + struct sockaddr_in dst; + size_t off; + int err; + + /* ip header: send to (known) ip address */ + off = 0; + ip_pkt.vers_ihl = 0x45; + ip_pkt.tos = 0; + ip_pkt.pkt_len = htons(sizeof (packet)); + ip_pkt.id = htons(256); + ip_pkt.flags_frag_offset = 0; + ip_pkt.ttl = 128; + ip_pkt.proto = IPPROTO_ICMP; + ip_pkt.checksum = 0; + ip_pkt.src_ip = my_ip->s_addr; + ip_pkt.dst_ip = other->s_addr; + ip_pkt.checksum = htons(calc_checksum((uint16_t*)&ip_pkt, + sizeof (struct ip_header))); + memcpy(&packet[off], + &ip_pkt, + sizeof(struct ip_header)); + off += sizeof(struct ip_header); + + icmp_pkt.type = ICMP_TIME_EXCEEDED; + icmp_pkt.code = 0; + icmp_pkt.checksum = 0; + icmp_pkt.unused = 0; + memcpy(&packet[off], + &icmp_pkt, + sizeof(struct icmp_ttl_exceeded_header)); + off += sizeof(struct icmp_ttl_exceeded_header); + + /* ip header of the presumably 'lost' udp packet */ + ip_pkt.vers_ihl = 0x45; + ip_pkt.tos = 0; + ip_pkt.pkt_len = htons(sizeof (struct ip_header) + + sizeof (struct udp_header)); + ip_pkt.id = htons(0); + ip_pkt.flags_frag_offset = 0; + ip_pkt.ttl = 128; + ip_pkt.proto = IPPROTO_UDP; + ip_pkt.checksum = 0; + ip_pkt.src_ip = other->s_addr; + ip_pkt.dst_ip = dummy.s_addr; + ip_pkt.checksum = htons(calc_checksum((uint16_t*)&ip_pkt, + sizeof (struct ip_header))); + memcpy(&packet[off], + &ip_pkt, + sizeof(struct ip_header)); + off += sizeof(struct ip_header); + + /* build UDP header */ + udp_pkt.src_port = htons(NAT_TRAV_PORT); + udp_pkt.dst_port = htons(NAT_TRAV_PORT); + udp_pkt.length = htons (port); + udp_pkt.crc = 0; + memcpy(&packet[off], + &udp_pkt, + sizeof(struct udp_header)); + off += sizeof(struct udp_header); + + /* no go back to calculate ICMP packet checksum */ + icmp_pkt.checksum = htons(calc_checksum((uint16_t*)&packet[off], + sizeof (struct icmp_ttl_exceeded_header) + + sizeof (struct ip_header) + + sizeof (struct udp_header))); + memcpy (&packet[sizeof (struct ip_header)], + &icmp_pkt, + sizeof (struct icmp_ttl_exceeded_header)); + + memset (&dst, 0, sizeof (dst)); + dst.sin_family = AF_INET; + dst.sin_addr = *other; + err = sendto(rawsock, + packet, + sizeof (packet), 0, + (struct sockaddr*)&dst, + sizeof(dst)); + if (err < 0) + { + fprintf(stderr, + "sendto failed: %s\n", strerror(errno)); + } + else if (sizeof (packet) != (size_t) err) + { + fprintf(stderr, + "Error: partial send of ICMP message\n"); + } +} + + +/** + * Send an ICMP message to the target. + * + * @param my_ip source address + * @param other target address + */ +static void +send_icmp (const struct in_addr *my_ip, + const struct in_addr *other) +{ + struct ip_header ip_pkt; + struct icmp_ttl_exceeded_header icmp_ttl; + struct icmp_echo_header icmp_echo; + struct sockaddr_in dst; + char packet[sizeof (struct ip_header) * 2 + + sizeof (struct icmp_ttl_exceeded_header) + + sizeof(struct icmp_echo_header)]; + size_t off; + int err; + + /* ip header: send to (known) ip address */ + off = 0; + ip_pkt.vers_ihl = 0x45; + ip_pkt.tos = 0; + ip_pkt.pkt_len = htons (sizeof (packet)); + ip_pkt.id = htons(256); + ip_pkt.flags_frag_offset = 0; + ip_pkt.ttl = IPDEFTTL; + ip_pkt.proto = IPPROTO_ICMP; + ip_pkt.checksum = 0; + ip_pkt.src_ip = my_ip->s_addr; + ip_pkt.dst_ip = other->s_addr; + ip_pkt.checksum = htons(calc_checksum((uint16_t*)&ip_pkt, + sizeof (struct ip_header))); + memcpy (&packet[off], + &ip_pkt, + sizeof (struct ip_header)); + off += sizeof (ip_pkt); + + /* icmp reply: time exceeded */ + icmp_ttl.type = ICMP_TIME_EXCEEDED; + icmp_ttl.code = 0; + icmp_ttl.checksum = 0; + icmp_ttl.unused = 0; + memcpy (&packet[off], + &icmp_ttl, + sizeof (struct icmp_ttl_exceeded_header)); + off += sizeof (struct icmp_ttl_exceeded_header); + + /* ip header of the presumably 'lost' udp packet */ + ip_pkt.vers_ihl = 0x45; + ip_pkt.tos = 0; + ip_pkt.pkt_len = htons(sizeof (struct ip_header) + sizeof (struct icmp_echo_header)); + ip_pkt.id = htons (256); + ip_pkt.flags_frag_offset = 0; + ip_pkt.ttl = 1; /* real TTL would be 1 on a time exceeded packet */ + ip_pkt.proto = IPPROTO_ICMP; + ip_pkt.src_ip = other->s_addr; + ip_pkt.dst_ip = dummy.s_addr; + ip_pkt.checksum = 0; + ip_pkt.checksum = htons(calc_checksum((uint16_t*)&ip_pkt, + sizeof (struct ip_header))); + memcpy (&packet[off], + &ip_pkt, + sizeof (struct ip_header)); + off += sizeof (struct ip_header); + + icmp_echo.type = ICMP_ECHO; + icmp_echo.code = 0; + icmp_echo.reserved = htonl(port); + icmp_echo.checksum = 0; + icmp_echo.checksum = htons(calc_checksum((uint16_t*) &icmp_echo, + sizeof (struct icmp_echo_header))); + memcpy (&packet[off], + &icmp_echo, + sizeof(struct icmp_echo_header)); + + /* no go back to calculate ICMP packet checksum */ + off = sizeof (struct ip_header); + icmp_ttl.checksum = htons(calc_checksum((uint16_t*) &packet[off], + sizeof (struct icmp_ttl_exceeded_header) + + sizeof (struct ip_header) + + sizeof (struct icmp_echo_header))); + memcpy (&packet[off], + &icmp_ttl, + sizeof (struct icmp_ttl_exceeded_header)); + + memset (&dst, 0, sizeof (dst)); + dst.sin_family = AF_INET; + dst.sin_addr = *other; + + err = sendto(rawsock, + packet, + sizeof (packet), 0, + (struct sockaddr*)&dst, + sizeof(dst)); + + if (err < 0) + { + fprintf(stderr, + "sendto failed: %s\n", strerror(errno)); + } + else if (sizeof (packet) != (size_t) err) + { + fprintf(stderr, + "Error: partial send of ICMP message\n"); + } +} + + +/** + * Create an ICMP raw socket. + * + * @return INVALID_SOCKET on error + */ +static SOCKET +make_raw_socket () +{ + DWORD bOptVal = TRUE; + int bOptLen = sizeof(bOptVal); + SOCKET ret; + + ret = socket (AF_INET, SOCK_RAW, IPPROTO_RAW); + if (INVALID_SOCKET == ret) + { + fprintf (stderr, + "Error opening RAW socket: %s\n", + strerror (errno)); + return INVALID_SOCKET; + } + if (0 != setsockopt(ret, SOL_SOCKET, SO_BROADCAST, (char*)&bOptVal, bOptLen)) + { + fprintf(stderr, + "Error setting SO_BROADCAST to ON: %s\n", + strerror (errno)); + closesocket(rawsock); + return INVALID_SOCKET; + } + + if (0 != setsockopt(ret, IPPROTO_IP, IP_HDRINCL, (char*)&bOptVal, bOptLen)) + { + fprintf(stderr, + "Error setting IP_HDRINCL to ON: %s\n", + strerror (errno)); + closesocket(rawsock); + return INVALID_SOCKET; + } + return ret; +} + + +int +main (int argc, char *const *argv) +{ + struct in_addr external; + struct in_addr target; + WSADATA wsaData; + + unsigned int p; + + if (argc != 4) + { + fprintf (stderr, + "This program must be started with our IP, the targets external IP, and our port as arguments.\n"); + return 1; + } + if ( (1 != inet_pton (AF_INET, argv[1], &external)) || + (1 != inet_pton (AF_INET, argv[2], &target)) ) + { + fprintf (stderr, + "Error parsing IPv4 address: %s\n", + strerror (errno)); + return 1; + } + if ( (1 != sscanf (argv[3], "%u", &p) ) || + (0 == p) || + (0xFFFF < p) ) + { + fprintf (stderr, + "Error parsing port value `%s'\n", + argv[3]); + return 1; + } + port = (uint16_t) p; + + if (0 != WSAStartup (MAKEWORD (2, 1), &wsaData)) + { + fprintf (stderr, "Failed to find Winsock 2.1 or better.\n"); + return 2; + } + if (1 != inet_pton (AF_INET, DUMMY_IP, &dummy)) + { + fprintf (stderr, + "Internal error converting dummy IP to binary.\n"); + return 2; + } + if (-1 == (rawsock = make_raw_socket())) + return 3; + send_icmp (&external, + &target); + send_icmp_udp (&external, + &target); + closesocket (rawsock); + WSACleanup (); + return 0; +} + +/* end of gnunet-helper-nat-client-windows.c */ diff --git a/src/nat/gnunet-helper-nat-client.c b/src/nat/gnunet-helper-nat-client.c new file mode 100644 index 000000000..10aa2f438 --- /dev/null +++ b/src/nat/gnunet-helper-nat-client.c @@ -0,0 +1,527 @@ +/* + This file is part of GNUnet. + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file src/nat/gnunet-helper-nat-client.c + * @brief Tool to help bypass NATs using ICMP method; must run as root (SUID will do) + * This code will work under GNU/Linux only. + * @author Christian Grothoff + * + * This program will send ONE ICMP message using RAW sockets + * to the IP address specified as the second argument. Since + * it uses RAW sockets, it must be installed SUID or run as 'root'. + * In order to keep the security risk of the resulting SUID binary + * minimal, the program ONLY opens the RAW socket with root + * privileges, then drops them and only then starts to process + * command line arguments. The code also does not link against + * any shared libraries (except libc) and is strictly minimal + * (except for checking for errors). The following list of people + * have reviewed this code and considered it safe since the last + * modification (if you reviewed it, please have your name added + * to the list): + * + * - Christian Grothoff + * - Nathan Evans + * - Benjamin Kuperman (22 Aug 2010) + */ +#if HAVE_CONFIG_H +/* Just needed for HAVE_SOCKADDR_IN_SIN_LEN test macro! */ +#include "gnunet_config.h" +#else +#define _GNU_SOURCE +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * Must match IP given in the server. + */ +#define DUMMY_IP "192.0.2.86" + +#define NAT_TRAV_PORT 22225 + +/** + * IPv4 header. + */ +struct ip_header +{ + + /** + * Version (4 bits) + Internet header length (4 bits) + */ + uint8_t vers_ihl; + + /** + * Type of service + */ + uint8_t tos; + + /** + * Total length + */ + uint16_t pkt_len; + + /** + * Identification + */ + uint16_t id; + + /** + * Flags (3 bits) + Fragment offset (13 bits) + */ + uint16_t flags_frag_offset; + + /** + * Time to live + */ + uint8_t ttl; + + /** + * Protocol + */ + uint8_t proto; + + /** + * Header checksum + */ + uint16_t checksum; + + /** + * Source address + */ + uint32_t src_ip; + + /** + * Destination address + */ + uint32_t dst_ip; +}; + +/** + * Format of ICMP packet. + */ +struct icmp_ttl_exceeded_header +{ + uint8_t type; + + uint8_t code; + + uint16_t checksum; + + uint32_t unused; + + /* followed by original payload */ +}; + +struct icmp_echo_header +{ + uint8_t type; + + uint8_t code; + + uint16_t checksum; + + uint32_t reserved; +}; + +/** + * Beginning of UDP packet. + */ +struct udp_header +{ + uint16_t src_port; + + uint16_t dst_port; + + uint16_t length; + + uint16_t crc; +}; + +/** + * Socket we use to send our fake ICMP replies. + */ +static int rawsock; + +/** + * Target "dummy" address of the packet we pretend to respond to. + */ +static struct in_addr dummy; + +/** + * Our "source" port. + */ +static uint16_t port; + + +/** + * CRC-16 for IP/ICMP headers. + * + * @param data what to calculate the CRC over + * @param bytes number of bytes in data (must be multiple of 2) + * @return the CRC 16. + */ +static uint16_t +calc_checksum (const uint16_t *data, + unsigned int bytes) +{ + uint32_t sum; + unsigned int i; + + sum = 0; + for (i=0;i> 16); + sum = htons(0xffff - sum); + return sum; +} + + +/** + * Send an ICMP message to the target. + * + * @param my_ip source address + * @param other target address + */ +static void +send_icmp_udp (const struct in_addr *my_ip, + const struct in_addr *other) +{ + char packet[sizeof(struct ip_header) * 2 + + sizeof(struct icmp_ttl_exceeded_header) + + sizeof(struct udp_header)]; + struct ip_header ip_pkt; + struct icmp_ttl_exceeded_header icmp_pkt; + struct udp_header udp_pkt; + struct sockaddr_in dst; + size_t off; + int err; + + /* ip header: send to (known) ip address */ + off = 0; + ip_pkt.vers_ihl = 0x45; + ip_pkt.tos = 0; + ip_pkt.pkt_len = htons (sizeof (packet)); + ip_pkt.id = htons(256); + ip_pkt.flags_frag_offset = 0; + ip_pkt.ttl = 128; + ip_pkt.proto = IPPROTO_ICMP; + ip_pkt.checksum = 0; + ip_pkt.src_ip = my_ip->s_addr; + ip_pkt.dst_ip = other->s_addr; + ip_pkt.checksum = htons(calc_checksum((uint16_t*)&ip_pkt, + sizeof (struct ip_header))); + memcpy(&packet[off], + &ip_pkt, + sizeof(struct ip_header)); + off += sizeof(struct ip_header); + + icmp_pkt.type = ICMP_TIME_EXCEEDED; + icmp_pkt.code = 0; + icmp_pkt.checksum = 0; + icmp_pkt.unused = 0; + memcpy(&packet[off], + &icmp_pkt, + sizeof(struct icmp_ttl_exceeded_header)); + off += sizeof(struct icmp_ttl_exceeded_header); + + /* ip header of the presumably 'lost' udp packet */ + ip_pkt.vers_ihl = 0x45; + ip_pkt.tos = 0; + ip_pkt.pkt_len = htons(sizeof (struct ip_header) + + sizeof (struct udp_header)); + ip_pkt.id = htons(0); + ip_pkt.flags_frag_offset = 0; + ip_pkt.ttl = 128; + ip_pkt.proto = IPPROTO_UDP; + ip_pkt.checksum = 0; + ip_pkt.src_ip = other->s_addr; + ip_pkt.dst_ip = dummy.s_addr; + ip_pkt.checksum = htons(calc_checksum((uint16_t*)&ip_pkt, + sizeof (struct ip_header))); + memcpy(&packet[off], + &ip_pkt, + sizeof(struct ip_header)); + off += sizeof(struct ip_header); + + /* build UDP header */ + udp_pkt.src_port = htons(NAT_TRAV_PORT); + udp_pkt.dst_port = htons(NAT_TRAV_PORT); + udp_pkt.length = htons (port); + udp_pkt.crc = 0; + memcpy(&packet[off], + &udp_pkt, + sizeof(struct udp_header)); + off += sizeof(struct udp_header); + + /* set ICMP checksum */ + icmp_pkt.checksum = htons(calc_checksum((uint16_t*)&packet[sizeof(struct ip_header)], + sizeof (struct icmp_ttl_exceeded_header) + + sizeof (struct ip_header) + + sizeof (struct udp_header))); + memcpy (&packet[sizeof(struct ip_header)], + &icmp_pkt, + sizeof (struct icmp_ttl_exceeded_header)); + + memset (&dst, 0, sizeof (dst)); + dst.sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + dst.sin_len = sizeof (struct sockaddr_in); +#endif + dst.sin_addr = *other; + err = sendto(rawsock, + packet, + sizeof (packet), 0, + (struct sockaddr*)&dst, + sizeof(dst)); + if (err < 0) + { + fprintf(stderr, + "sendto failed: %s\n", strerror(errno)); + } + else if (sizeof (packet) != (size_t) err) + { + fprintf(stderr, + "Error: partial send of ICMP message\n"); + } +} + + +/** + * Send an ICMP message to the target. + * + * @param my_ip source address + * @param other target address + */ +static void +send_icmp (const struct in_addr *my_ip, + const struct in_addr *other) +{ + struct ip_header ip_pkt; + struct icmp_ttl_exceeded_header icmp_ttl; + struct icmp_echo_header icmp_echo; + struct sockaddr_in dst; + char packet[sizeof (struct ip_header) * 2 + + sizeof (struct icmp_ttl_exceeded_header) + + sizeof (struct icmp_echo_header)]; + size_t off; + int err; + + /* ip header: send to (known) ip address */ + off = 0; + ip_pkt.vers_ihl = 0x45; + ip_pkt.tos = 0; + ip_pkt.pkt_len = htons (sizeof (packet)); + ip_pkt.id = htons (256); + ip_pkt.flags_frag_offset = 0; + ip_pkt.ttl = IPDEFTTL; + ip_pkt.proto = IPPROTO_ICMP; + ip_pkt.checksum = 0; + ip_pkt.src_ip = my_ip->s_addr; + ip_pkt.dst_ip = other->s_addr; + ip_pkt.checksum = htons(calc_checksum((uint16_t*)&ip_pkt, + sizeof (struct ip_header))); + memcpy (&packet[off], + &ip_pkt, + sizeof (struct ip_header)); + off = sizeof (ip_pkt); + + /* icmp reply: time exceeded */ + icmp_ttl.type = ICMP_TIME_EXCEEDED; + icmp_ttl.code = 0; + icmp_ttl.checksum = 0; + icmp_ttl.unused = 0; + memcpy (&packet[off], + &icmp_ttl, + sizeof (struct icmp_ttl_exceeded_header)); + off += sizeof (struct icmp_ttl_exceeded_header); + + /* ip header of the presumably 'lost' udp packet */ + ip_pkt.vers_ihl = 0x45; + ip_pkt.tos = 0; + ip_pkt.pkt_len = htons (sizeof (struct ip_header) + sizeof (struct icmp_echo_header)); + ip_pkt.id = htons (256); + ip_pkt.flags_frag_offset = 0; + ip_pkt.ttl = 1; /* real TTL would be 1 on a time exceeded packet */ + ip_pkt.proto = IPPROTO_ICMP; + ip_pkt.src_ip = other->s_addr; + ip_pkt.dst_ip = dummy.s_addr; + ip_pkt.checksum = 0; + ip_pkt.checksum = htons(calc_checksum((uint16_t*)&ip_pkt, + sizeof (struct ip_header))); + memcpy (&packet[off], + &ip_pkt, + sizeof (struct ip_header)); + off += sizeof (struct ip_header); + + icmp_echo.type = ICMP_ECHO; + icmp_echo.code = 0; + icmp_echo.reserved = htonl (port); + icmp_echo.checksum = 0; + icmp_echo.checksum = htons(calc_checksum((uint16_t*) &icmp_echo, + sizeof (struct icmp_echo_header))); + memcpy (&packet[off], + &icmp_echo, + sizeof(struct icmp_echo_header)); + + /* no go back to calculate ICMP packet checksum */ + off = sizeof (struct ip_header); + icmp_ttl.checksum = htons(calc_checksum((uint16_t*) &packet[off], + sizeof (struct icmp_ttl_exceeded_header) + + sizeof (struct ip_header) + + sizeof (struct icmp_echo_header))); + memcpy (&packet[off], + &icmp_ttl, + sizeof (struct icmp_ttl_exceeded_header)); + + /* prepare for transmission */ + memset (&dst, 0, sizeof (dst)); + dst.sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + dst.sin_len = sizeof (struct sockaddr_in); +#endif + dst.sin_addr = *other; + err = sendto(rawsock, + packet, + sizeof (packet), 0, + (struct sockaddr*)&dst, + sizeof(dst)); + if (err < 0) + { + fprintf(stderr, + "sendto failed: %s\n", strerror(errno)); + } + else if (sizeof (packet) != (size_t) err) + { + fprintf(stderr, + "Error: partial send of ICMP message\n"); + } +} + + +/** + * Create an ICMP raw socket for writing. + * + * @return -1 on error + */ +static int +make_raw_socket () +{ + const int one = 1; + int ret; + + ret = socket (AF_INET, SOCK_RAW, IPPROTO_RAW); + if (-1 == ret) + { + fprintf (stderr, + "Error opening RAW socket: %s\n", + strerror (errno)); + return -1; + } + if (0 != setsockopt(ret, SOL_SOCKET, SO_BROADCAST, + (char *)&one, sizeof(one))) + { + fprintf(stderr, + "setsockopt failed: %s\n", + strerror (errno)); + close (ret); + return -1; + } + if (0 != setsockopt(ret, IPPROTO_IP, IP_HDRINCL, + (char *)&one, sizeof(one))) + { + fprintf(stderr, + "setsockopt failed: %s\n", + strerror (errno)); + close (ret); + return -1; + } + return ret; +} + + +int +main (int argc, char *const *argv) +{ + struct in_addr external; + struct in_addr target; + uid_t uid; + unsigned int p; + + if (4 != argc) + { + fprintf (stderr, + "This program must be started with our IP, the targets external IP, and our port as arguments.\n"); + return 1; + } + if ( (1 != inet_pton (AF_INET, argv[1], &external)) || + (1 != inet_pton (AF_INET, argv[2], &target)) ) + { + fprintf (stderr, + "Error parsing IPv4 address: %s\n", + strerror (errno)); + return 1; + } + if ( (1 != sscanf (argv[3], "%u", &p) ) || + (0 == p) || + (0xFFFF < p) ) + { + fprintf (stderr, + "Error parsing port value `%s'\n", + argv[3]); + return 1; + } + port = (uint16_t) p; + if (1 != inet_pton (AF_INET, DUMMY_IP, &dummy)) + { + fprintf (stderr, + "Internal error converting dummy IP to binary.\n"); + return 2; + } + if (-1 == (rawsock = make_raw_socket())) + return 2; + uid = getuid (); + if (0 != setresuid (uid, uid, uid)) + { + fprintf (stderr, + "Failed to setresuid: %s\n", + strerror (errno)); + /* not critical, continue anyway */ + } + send_icmp (&external, + &target); + send_icmp_udp (&external, + &target); + close (rawsock); + return 0; +} + +/* end of gnunet-helper-nat-client.c */ diff --git a/src/nat/gnunet-helper-nat-server-windows.c b/src/nat/gnunet-helper-nat-server-windows.c new file mode 100644 index 000000000..7a607c62d --- /dev/null +++ b/src/nat/gnunet-helper-nat-server-windows.c @@ -0,0 +1,653 @@ +/* + This file is part of GNUnet. + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file src/nat/gnunet-helper-nat-server-windows.c + * @brief Windows tool to help bypass NATs using ICMP method + * This code will work under W32 only + * @author Christian Grothoff + * + * This program will send ONE ICMP message every 500 ms RAW sockets + * to a DUMMY IP address and also listens for ICMP replies. Since + * it uses RAW sockets, it must be run as an administrative user. + * In order to keep the security risk of the resulting binary + * minimal, the program ONLY opens the two RAW sockets with administrative + * privileges, then drops them and only then starts to process + * command line arguments. The code also does not link against + * any shared libraries (except libc) and is strictly minimal + * (except for checking for errors). The following list of people + * have reviewed this code and considered it safe since the last + * modification (if you reviewed it, please have your name added + * to the list): + * + * - Nathan Evans + * - Christian Grothoff + */ +#define _GNU_SOURCE + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * Should we print some debug output? + */ +#define VERBOSE 0 + +/** + * Must match IP given in the client. + */ +#define DUMMY_IP "192.0.2.86" + +/** + * Default Port + */ +#define NAT_TRAV_PORT 22225 + +/** + * TTL to use for our outgoing messages. + */ +#define IPDEFTTL 64 + +#define ICMP_ECHO 8 + +#define ICMP_TIME_EXCEEDED 11 + +/** + * How often do we send our ICMP messages to receive replies? + */ +#define ICMP_SEND_FREQUENCY_MS 500 + +/** + * IPv4 header. + */ +struct ip_header +{ + + /** + * Version (4 bits) + Internet header length (4 bits) + */ + uint8_t vers_ihl; + + /** + * Type of service + */ + uint8_t tos; + + /** + * Total length + */ + uint16_t pkt_len; + + /** + * Identification + */ + uint16_t id; + + /** + * Flags (3 bits) + Fragment offset (13 bits) + */ + uint16_t flags_frag_offset; + + /** + * Time to live + */ + uint8_t ttl; + + /** + * Protocol + */ + uint8_t proto; + + /** + * Header checksum + */ + uint16_t checksum; + + /** + * Source address + */ + uint32_t src_ip; + + /** + * Destination address + */ + uint32_t dst_ip; +}; + +/** + * Format of ICMP packet. + */ +struct icmp_ttl_exceeded_header +{ + uint8_t type; + + uint8_t code; + + uint16_t checksum; + + uint32_t unused; + + /* followed by original payload */ +}; + +struct icmp_echo_header +{ + uint8_t type; + + uint8_t code; + + uint16_t checksum; + + uint32_t reserved; +}; + +/** + * Beginning of UDP packet. + */ +struct udp_header +{ + uint16_t src_port; + + uint16_t dst_port; + + uint16_t length; + + uint16_t crc; +}; + +/** + * Socket we use to receive "fake" ICMP replies. + */ +static SOCKET icmpsock; + +/** + * Socket we use to send our ICMP requests. + */ +static SOCKET rawsock; + +/** + * Socket we use to send our UDP requests. + */ +static SOCKET udpsock; + +/** + * Target "dummy" address. + */ +static struct in_addr dummy; + + +/** + * CRC-16 for IP/ICMP headers. + * + * @param data what to calculate the CRC over + * @param bytes number of bytes in data (must be multiple of 2) + * @return the CRC 16. + */ +static uint16_t +calc_checksum(const uint16_t *data, + unsigned int bytes) +{ + uint32_t sum; + unsigned int i; + + sum = 0; + for (i=0;i> 16); + sum = htons(0xffff - sum); + return sum; +} + + +/** + * Convert IPv4 address from text to binary form. + * + * @param af address family + * @param cp the address to print + * @param buf where to write the address result + * @return 1 on success + */ +static int +inet_pton (int af, + const char *cp, + struct in_addr *buf) +{ + buf->s_addr = inet_addr(cp); + if (buf->s_addr == INADDR_NONE) + { + fprintf(stderr, + "Error %d handling address %s", + WSAGetLastError(), + cp); + return 0; + } + return 1; +} + + +/** + * Send an ICMP message to the dummy IP. + * + * @param my_ip source address (our ip address) + */ +static void +send_icmp_echo (const struct in_addr *my_ip) +{ + char packet[sizeof (struct ip_header) + sizeof (struct icmp_echo_header)]; + struct icmp_echo_header icmp_echo; + struct ip_header ip_pkt; + struct sockaddr_in dst; + size_t off; + int err; + + off = 0; + ip_pkt.vers_ihl = 0x45; + ip_pkt.tos = 0; + ip_pkt.pkt_len = htons (sizeof (packet)); + ip_pkt.id = htons (256); + ip_pkt.flags_frag_offset = 0; + ip_pkt.ttl = IPDEFTTL; + ip_pkt.proto = IPPROTO_ICMP; + ip_pkt.checksum = 0; + ip_pkt.src_ip = my_ip->s_addr; + ip_pkt.dst_ip = dummy.s_addr; + ip_pkt.checksum = htons(calc_checksum((uint16_t*)&ip_pkt, + sizeof (struct ip_header))); + memcpy (&packet[off], + &ip_pkt, + sizeof (struct ip_header)); + off += sizeof (struct ip_header); + + icmp_echo.type = ICMP_ECHO; + icmp_echo.code = 0; + icmp_echo.reserved = 0; + icmp_echo.checksum = 0; + icmp_echo.checksum = htons(calc_checksum((uint16_t*) &icmp_echo, + sizeof (struct icmp_echo_header))); + memcpy (&packet[off], + &icmp_echo, + sizeof (struct icmp_echo_header)); + off += sizeof (struct icmp_echo_header); + + memset (&dst, 0, sizeof (dst)); + dst.sin_family = AF_INET; + dst.sin_addr = dummy; + err = sendto(rawsock, + packet, off, 0, + (struct sockaddr*)&dst, + sizeof(dst)); + if (err < 0) + { +#if VERBOSE + fprintf(stderr, + "sendto failed: %s\n", strerror(errno)); +#endif + } + else if (err != off) + { + fprintf(stderr, + "Error: partial send of ICMP message\n"); + } +} + + +/** + * Send a UDP message to the dummy IP. + */ +static void +send_udp () +{ + struct sockaddr_in dst; + ssize_t err; + + memset (&dst, 0, sizeof (dst)); + dst.sin_family = AF_INET; + dst.sin_addr = dummy; + dst.sin_port = htons (NAT_TRAV_PORT); + err = sendto(udpsock, + NULL, 0, 0, + (struct sockaddr*)&dst, + sizeof(dst)); + if (err < 0) + { +#if VERBOSE + fprintf(stderr, + "sendto failed: %s\n", strerror(errno)); +#endif + } + else if (0 != err) + { + fprintf(stderr, + "Error: partial send of ICMP message\n"); + } +} + + +/** + * We've received an ICMP response. Process it. + */ +static void +process_icmp_response () +{ + char buf[65536]; + ssize_t have; + struct in_addr source_ip; + struct ip_header ip_pkt; + struct icmp_ttl_exceeded_header icmp_ttl; + struct icmp_echo_header icmp_echo; + struct udp_header udp_pkt; + size_t off; + uint16_t port; + DWORD ssize; + + have = read (icmpsock, buf, sizeof (buf)); + if (have == -1) + { + fprintf (stderr, + "Error reading raw socket: %s\n", + strerror (errno)); + return; + } +#if VERBOSE + fprintf (stderr, + "Received message of %u bytes\n", + (unsigned int) have); +#endif + if (have < (ssize_t) (sizeof (struct ip_header) + sizeof (struct icmp_ttl_exceeded_header) + sizeof (struct ip_header))) + { + /* malformed */ + return; + } + off = 0; + memcpy (&ip_pkt, + &buf[off], + sizeof (struct ip_header)); + off += sizeof (struct ip_header); + memcpy(&source_ip, + &ip_pkt.src_ip, + sizeof (source_ip)); + memcpy (&icmp_ttl, + &buf[off], + sizeof (struct icmp_ttl_exceeded_header)); + off += sizeof (struct icmp_ttl_exceeded_header); + if ( (ICMP_TIME_EXCEEDED != icmp_ttl.type) || + (0 != icmp_ttl.code) ) + { + /* different type than what we want */ + return; + } + /* skip 2nd IP header */ + memcpy (&ip_pkt, + &buf[off], + sizeof (struct ip_header)); + off += sizeof (struct ip_header); + + switch (ip_pkt.proto) + { + case IPPROTO_ICMP: + if (have != (sizeof (struct ip_header) * 2 + + sizeof (struct icmp_ttl_exceeded_header) + + sizeof (struct icmp_echo_header)) ) + { + /* malformed */ + return; + } + /* grab ICMP ECHO content */ + memcpy (&icmp_echo, + &buf[off], + sizeof (struct icmp_echo_header)); + port = (uint16_t) ntohl (icmp_echo.reserved); + break; + case IPPROTO_UDP: + if (have != (sizeof (struct ip_header) * 2 + + sizeof (struct icmp_ttl_exceeded_header) + + sizeof (struct udp_header)) ) + { + /* malformed */ + return; + } + /* grab UDP content */ + memcpy (&udp_pkt, + &buf[off], + sizeof (struct udp_header)); + port = ntohs (udp_pkt.length); + break; + default: + /* different type than what we want */ + return; + } + + ssize = sizeof(buf); + WSAAddressToString((LPSOCKADDR)&source_ip, + sizeof(source_ip), + NULL, + buf, + &ssize); + if (port == 0) + fprintf (stdout, + "%s\n", + buf); + else + fprintf (stdout, + "%s:%u\n", + buf, + (unsigned int) port); + fflush (stdout); +} + + +/** + * Create an ICMP raw socket for reading. + * + * @return INVALID_SOCKET on error + */ +static SOCKET +make_icmp_socket () +{ + SOCKET ret; + + ret = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); + if (INVALID_SOCKET == ret) + { + fprintf (stderr, + "Error opening RAW socket: %s\n", + strerror (errno)); + return INVALID_SOCKET; + } + return ret; +} + + +/** + * Create an ICMP raw socket for writing. + * + * @return INVALID_SOCKET on error + */ +static SOCKET +make_raw_socket () +{ + DWORD bOptVal = TRUE; + int bOptLen = sizeof(bOptVal); + + rawsock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); + if (INVALID_SOCKET == rawsock) + { + fprintf (stderr, + "Error opening RAW socket: %s\n", + strerror (errno)); + return INVALID_SOCKET; + } + + if (0 != setsockopt(rawsock, + SOL_SOCKET, + SO_BROADCAST, + (char*)&bOptVal, bOptLen)) + { + fprintf(stderr, + "Error setting SO_BROADCAST to ON: %s\n", + strerror (errno)); + closesocket(rawsock); + return INVALID_SOCKET; + } + if (0 != setsockopt(rawsock, + IPPROTO_IP, + IP_HDRINCL, + (char*)&bOptVal, bOptLen)) + { + fprintf(stderr, + "Error setting IP_HDRINCL to ON: %s\n", + strerror (errno)); + closesocket(rawsock); + return INVALID_SOCKET; + } + return rawsock; +} + + +/** + * Create a UDP socket for writing. + * + * @param my_ip source address (our ip address) + * @return INVALID_SOCKET on error + */ +static SOCKET +make_udp_socket (const struct in_addr *my_ip) +{ + SOCKET ret; + struct sockaddr_in addr; + + ret = socket (AF_INET, SOCK_DGRAM, 0); + if (INVALID_SOCKET == ret) + { + fprintf (stderr, + "Error opening UDP socket: %s\n", + strerror (errno)); + return INVALID_SOCKET; + } + memset (&addr, 0, sizeof (addr)); + addr.sin_family = AF_INET; + addr.sin_addr = *my_ip; + addr.sin_port = htons (NAT_TRAV_PORT); + if (0 != bind (ret, + (struct sockaddr *)&addr, + sizeof(addr))) + { + fprintf (stderr, + "Error binding UDP socket to port %u: %s\n", + NAT_TRAV_PORT, + strerror (errno)); + /* likely problematic, but not certain, try to continue */ + } + return ret; +} + + +int +main (int argc, + char *const *argv) +{ + struct in_addr external; + fd_set rs; + struct timeval tv; + WSADATA wsaData; + unsigned int alt; + + alt = 0; + if (2 != argc) + { + fprintf (stderr, + "This program must be started with our (internal NAT) IP as the only argument.\n"); + return 1; + } + if (1 != inet_pton (AF_INET, argv[1], &external)) + { + fprintf (stderr, + "Error parsing IPv4 address: %s, error %s\n", + argv[1], strerror (errno)); + return 1; + } + if (1 != inet_pton (AF_INET, DUMMY_IP, &dummy)) + { + fprintf (stderr, + "Internal error converting dummy IP to binary.\n"); + return 2; + } + if (WSAStartup (MAKEWORD (2, 1), &wsaData) != 0) + { + fprintf (stderr, "Failed to find Winsock 2.1 or better.\n"); + return 2; + } + if (INVALID_SOCKET == (icmpsock = make_icmp_socket())) + { + return 3; + } + if (INVALID_SOCKET == (make_raw_socket())) + { + closesocket (icmpsock); + return 3; + } + if (INVALID_SOCKET == (udpsock = make_udp_socket(&external))) + { + closesocket (icmpsock); + closesocket (rawsock); + return 3; + } + while (1) + { + FD_ZERO (&rs); + FD_SET (icmpsock, &rs); + tv.tv_sec = 0; + tv.tv_usec = ICMP_SEND_FREQUENCY_MS * 1000; + if (-1 == select (icmpsock + 1, &rs, NULL, NULL, &tv)) + { + if (errno == EINTR) + continue; + fprintf (stderr, + "select failed: %s\n", + strerror (errno)); + break; + } + if (FD_ISSET (icmpsock, &rs)) + process_icmp_response (); + if (0 == (++alt % 2)) + send_icmp_echo (&external); + else + send_udp (); + } + /* select failed (internal error or OS out of resources) */ + closesocket(icmpsock); + closesocket(rawsock); + closesocket(udpsock); + WSACleanup (); + return 4; +} + + +/* end of gnunet-helper-nat-server-windows.c */ diff --git a/src/nat/gnunet-helper-nat-server.c b/src/nat/gnunet-helper-nat-server.c new file mode 100644 index 000000000..945c98735 --- /dev/null +++ b/src/nat/gnunet-helper-nat-server.c @@ -0,0 +1,651 @@ +/* + This file is part of GNUnet. + (C) 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file src/nat/gnunet-helper-nat-server.c + * @brief Tool to help bypass NATs using ICMP method; must run as root (SUID will do) + * This code will work under GNU/Linux only (or maybe BSDs, but never W32) + * @author Christian Grothoff + * + * This program will send ONE ICMP message every 500 ms RAW sockets + * to a DUMMY IP address and also listens for ICMP replies. Since + * it uses RAW sockets, it must be installed SUID or run as 'root'. + * In order to keep the security risk of the resulting SUID binary + * minimal, the program ONLY opens the two RAW sockets with root + * privileges, then drops them and only then starts to process + * command line arguments. The code also does not link against + * any shared libraries (except libc) and is strictly minimal + * (except for checking for errors). The following list of people + * have reviewed this code and considered it safe since the last + * modification (if you reviewed it, please have your name added + * to the list): + * + * - Christian Grothoff + * - Nathan Evans + * - Benjamin Kuperman (22 Aug 2010) + */ +#if HAVE_CONFIG_H +/* Just needed for HAVE_SOCKADDR_IN_SIN_LEN test macro! */ +#include "gnunet_config.h" +#else +#define _GNU_SOURCE +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * Should we print some debug output? + */ +#define VERBOSE 0 + +/** + * Must match IP given in the client. + */ +#define DUMMY_IP "192.0.2.86" + +/** + * Port for UDP + */ +#define NAT_TRAV_PORT 22225 + +/** + * How often do we send our ICMP messages to receive replies? + */ +#define ICMP_SEND_FREQUENCY_MS 500 + +/** + * IPv4 header. + */ +struct ip_header +{ + + /** + * Version (4 bits) + Internet header length (4 bits) + */ + uint8_t vers_ihl; + + /** + * Type of service + */ + uint8_t tos; + + /** + * Total length + */ + uint16_t pkt_len; + + /** + * Identification + */ + uint16_t id; + + /** + * Flags (3 bits) + Fragment offset (13 bits) + */ + uint16_t flags_frag_offset; + + /** + * Time to live + */ + uint8_t ttl; + + /** + * Protocol + */ + uint8_t proto; + + /** + * Header checksum + */ + uint16_t checksum; + + /** + * Source address + */ + uint32_t src_ip; + + /** + * Destination address + */ + uint32_t dst_ip; +}; + +/** + * Format of ICMP packet. + */ +struct icmp_ttl_exceeded_header +{ + uint8_t type; + + uint8_t code; + + uint16_t checksum; + + uint32_t unused; + + /* followed by original payload */ +}; + +struct icmp_echo_header +{ + uint8_t type; + + uint8_t code; + + uint16_t checksum; + + uint32_t reserved; +}; + + +/** + * Beginning of UDP packet. + */ +struct udp_header +{ + uint16_t src_port; + + uint16_t dst_port; + + uint16_t length; + + uint16_t crc; +}; + +/** + * Socket we use to receive "fake" ICMP replies. + */ +static int icmpsock; + +/** + * Socket we use to send our ICMP requests. + */ +static int rawsock; + +/** + * Socket we use to send our UDP requests. + */ +static int udpsock; + +/** + * Target "dummy" address. + */ +static struct in_addr dummy; + + +/** + * CRC-16 for IP/ICMP headers. + * + * @param data what to calculate the CRC over + * @param bytes number of bytes in data (must be multiple of 2) + * @return the CRC 16. + */ +static uint16_t +calc_checksum(const uint16_t *data, + unsigned int bytes) +{ + uint32_t sum; + unsigned int i; + + sum = 0; + for (i=0;i> 16); + sum = htons(0xffff - sum); + return sum; +} + + +/** + * Send an ICMP message to the dummy IP. + * + * @param my_ip source address (our ip address) + */ +static void +send_icmp_echo (const struct in_addr *my_ip) +{ + char packet[sizeof (struct ip_header) + sizeof (struct icmp_echo_header)]; + struct icmp_echo_header icmp_echo; + struct ip_header ip_pkt; + struct sockaddr_in dst; + size_t off; + int err; + + off = 0; + ip_pkt.vers_ihl = 0x45; + ip_pkt.tos = 0; + ip_pkt.pkt_len = htons (sizeof (packet)); + ip_pkt.id = htons (256); + ip_pkt.flags_frag_offset = 0; + ip_pkt.ttl = IPDEFTTL; + ip_pkt.proto = IPPROTO_ICMP; + ip_pkt.checksum = 0; + ip_pkt.src_ip = my_ip->s_addr; + ip_pkt.dst_ip = dummy.s_addr; + ip_pkt.checksum = htons(calc_checksum((uint16_t*)&ip_pkt, + sizeof (struct ip_header))); + memcpy (&packet[off], + &ip_pkt, + sizeof (struct ip_header)); + off += sizeof (struct ip_header); + + icmp_echo.type = ICMP_ECHO; + icmp_echo.code = 0; + icmp_echo.checksum = 0; + icmp_echo.reserved = 0; + icmp_echo.checksum = htons(calc_checksum((uint16_t*)&icmp_echo, + sizeof (struct icmp_echo_header))); + memcpy (&packet[off], + &icmp_echo, + sizeof (struct icmp_echo_header)); + off += sizeof (struct icmp_echo_header); + + memset (&dst, 0, sizeof (dst)); + dst.sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + dst.sin_len = sizeof (struct sockaddr_in); +#endif + dst.sin_addr = dummy; + err = sendto(rawsock, + packet, off, 0, + (struct sockaddr*)&dst, + sizeof(dst)); + if (err < 0) + { +#if VERBOSE + fprintf(stderr, + "sendto failed: %s\n", strerror(errno)); +#endif + } + else if (sizeof (packet) != err) + { + fprintf(stderr, + "Error: partial send of ICMP message\n"); + } +} + + +/** + * Send a UDP message to the dummy IP. + */ +static void +send_udp () +{ + struct sockaddr_in dst; + ssize_t err; + + memset (&dst, 0, sizeof (dst)); + dst.sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + dst.sin_len = sizeof (struct sockaddr_in); +#endif + dst.sin_addr = dummy; + dst.sin_port = htons (NAT_TRAV_PORT); + err = sendto(udpsock, + NULL, 0, 0, + (struct sockaddr*)&dst, + sizeof(dst)); + if (err < 0) + { +#if VERBOSE + fprintf(stderr, + "sendto failed: %s\n", strerror(errno)); +#endif + } + else if (0 != err) + { + fprintf(stderr, + "Error: partial send of ICMP message\n"); + } +} + + +/** + * We've received an ICMP response. Process it. + */ +static void +process_icmp_response () +{ + char buf[65536]; + ssize_t have; + struct in_addr source_ip; + struct ip_header ip_pkt; + struct icmp_ttl_exceeded_header icmp_ttl; + struct icmp_echo_header icmp_echo; + struct udp_header udp_pkt; + size_t off; + uint16_t port; + + have = read (icmpsock, buf, sizeof (buf)); + if (-1 == have) + { + fprintf (stderr, + "Error reading raw socket: %s\n", + strerror (errno)); + return; + } +#if VERBOSE + fprintf (stderr, + "Received message of %u bytes\n", + (unsigned int) have); +#endif + if (have < (ssize_t) (sizeof (struct ip_header) + sizeof (struct icmp_ttl_exceeded_header) + sizeof (struct ip_header))) + { + /* malformed */ + return; + } + off = 0; + memcpy (&ip_pkt, + &buf[off], + sizeof (struct ip_header)); + off += sizeof (struct ip_header); + memcpy(&source_ip, + &ip_pkt.src_ip, + sizeof (source_ip)); + memcpy (&icmp_ttl, + &buf[off], + sizeof (struct icmp_ttl_exceeded_header)); + off += sizeof (struct icmp_ttl_exceeded_header); + if ( (ICMP_TIME_EXCEEDED != icmp_ttl.type) || + (0 != icmp_ttl.code) ) + { + /* different type than what we want */ + return; + } + /* skip 2nd IP header */ + memcpy (&ip_pkt, + &buf[off], + sizeof (struct ip_header)); + off += sizeof (struct ip_header); + + switch (ip_pkt.proto) + { + case IPPROTO_ICMP: + if (have != (sizeof (struct ip_header) * 2 + + sizeof (struct icmp_ttl_exceeded_header) + + sizeof (struct icmp_echo_header)) ) + { + /* malformed */ + return; + } + /* grab ICMP ECHO content */ + memcpy (&icmp_echo, + &buf[off], + sizeof (struct icmp_echo_header)); + port = (uint16_t) ntohl (icmp_echo.reserved); + break; + case IPPROTO_UDP: + if (have != (sizeof (struct ip_header) * 2 + + sizeof (struct icmp_ttl_exceeded_header) + + sizeof (struct udp_header)) ) + { + /* malformed */ + return; + } + /* grab UDP content */ + memcpy (&udp_pkt, + &buf[off], + sizeof (struct udp_header)); + port = ntohs (udp_pkt.length); + break; + default: + /* different type than what we want */ + return; + } + + if (port == 0) + fprintf (stdout, + "%s\n", + inet_ntop (AF_INET, + &source_ip, + buf, + sizeof (buf))); + else + fprintf (stdout, + "%s:%u\n", + inet_ntop (AF_INET, + &source_ip, + buf, + sizeof (buf)), + (unsigned int) port); + fflush (stdout); +} + + +/** + * Create an ICMP raw socket for reading. + * + * @return -1 on error + */ +static int +make_icmp_socket () +{ + int ret; + + ret = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); + if (-1 == ret) + { + fprintf (stderr, + "Error opening RAW socket: %s\n", + strerror (errno)); + return -1; + } + if (ret >= FD_SETSIZE) + { + fprintf (stderr, + "Socket number too large (%d > %u)\n", + ret, + (unsigned int) FD_SETSIZE); + close (ret); + return -1; + } + return ret; +} + + +/** + * Create an ICMP raw socket for writing. + * + * @return -1 on error + */ +static int +make_raw_socket () +{ + const int one = 1; + int ret; + + ret = socket (AF_INET, SOCK_RAW, IPPROTO_RAW); + if (-1 == ret) + { + fprintf (stderr, + "Error opening RAW socket: %s\n", + strerror (errno)); + return -1; + } + if (-1 == setsockopt(ret, + SOL_SOCKET, + SO_BROADCAST, + (char *)&one, sizeof(one))) + { + fprintf(stderr, + "setsockopt failed: %s\n", + strerror (errno)); + close (ret); + return -1; + } + if (-1 == setsockopt(ret, + IPPROTO_IP, + IP_HDRINCL, + (char *)&one, sizeof(one))) + { + fprintf(stderr, + "setsockopt failed: %s\n", + strerror (errno)); + close (ret); + return -1; + } + return ret; +} + + +/** + * Create a UDP socket for writinging. + * + * @param my_ip source address (our ip address) + * @return -1 on error + */ +static int +make_udp_socket (const struct in_addr *my_ip) +{ + int ret; + struct sockaddr_in addr; + + ret = socket (AF_INET, SOCK_DGRAM, 0); + if (-1 == ret) + { + fprintf (stderr, + "Error opening UDP socket: %s\n", + strerror (errno)); + return -1; + } + memset (&addr, + 0, + sizeof (addr)); + addr.sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + addr.sin_len = sizeof (struct sockaddr_in); +#endif + addr.sin_addr = *my_ip; + addr.sin_port = htons (NAT_TRAV_PORT); + + if (0 != bind (ret, + &addr, + sizeof(addr))) + { + fprintf (stderr, + "Error binding UDP socket to port %u: %s\n", + NAT_TRAV_PORT, + strerror (errno)); + /* likely problematic, but not certain, try to continue */ + } + return ret; +} + + +int +main (int argc, + char *const *argv) +{ + struct in_addr external; + fd_set rs; + struct timeval tv; + uid_t uid; + unsigned int alt; + + if (2 != argc) + { + fprintf (stderr, + "This program must be started with our (internal NAT) IP as the only argument.\n"); + return 1; + } + if (1 != inet_pton (AF_INET, argv[1], &external)) + { + fprintf (stderr, + "Error parsing IPv4 address: %s\n", + strerror (errno)); + return 1; + } + if (1 != inet_pton (AF_INET, DUMMY_IP, &dummy)) + { + fprintf (stderr, + "Internal error converting dummy IP to binary.\n"); + return 2; + } + if (-1 == (icmpsock = make_icmp_socket())) + { + return 3; + } + if (-1 == (rawsock = make_raw_socket())) + { + close (icmpsock); + return 3; + } + uid = getuid (); + if (0 != setresuid (uid, uid, uid)) + { + fprintf (stderr, + "Failed to setresuid: %s\n", + strerror (errno)); + /* not critical, continue anyway */ + } + if (-1 == (udpsock = make_udp_socket(&external))) + { + close (icmpsock); + close (rawsock); + return 3; + } + alt = 0; + while (1) + { + FD_ZERO (&rs); + FD_SET (icmpsock, &rs); + tv.tv_sec = 0; + tv.tv_usec = ICMP_SEND_FREQUENCY_MS * 1000; + if (-1 == select (icmpsock + 1, &rs, NULL, NULL, &tv)) + { + if (errno == EINTR) + continue; + fprintf (stderr, + "select failed: %s\n", + strerror (errno)); + break; + } + if (1 == getppid()) /* Check the parent process id, if 1 the parent has died, so we should die too */ + break; + if (FD_ISSET (icmpsock, &rs)) + process_icmp_response (); + if (0 == (++alt % 2)) + send_icmp_echo (&external); + else + send_udp (); + } + /* select failed (internal error or OS out of resources) */ + close (icmpsock); + close (rawsock); + close (udpsock); + return 4; +} + + +/* end of gnunet-helper-nat-server.c */ diff --git a/src/nat/gnunet-nat-client-windows.c b/src/nat/gnunet-nat-client-windows.c deleted file mode 100644 index 2fe3643ac..000000000 --- a/src/nat/gnunet-nat-client-windows.c +++ /dev/null @@ -1,550 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2010 Christian Grothoff (and other contributing authors) - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. -*/ - -/** - * @file src/nat/gnunet-nat-client-windows.c - * @brief Tool to help bypass NATs using ICMP method; must run as - * administrator on W32 - * This code is forx W32. - * @author Nathan Evans - * - * This program will send ONE ICMP message using RAW sockets - * to the IP address specified as the second argument. Since - * it uses RAW sockets, it must be installed SUID or run as 'root'. - * In order to keep the security risk of the resulting SUID binary - * minimal, the program ONLY opens the RAW socket with root - * privileges, then drops them and only then starts to process - * command line arguments. The code also does not link against - * any shared libraries (except libc) and is strictly minimal - * (except for checking for errors). The following list of people - * have reviewed this code and considered it safe since the last - * modification (if you reviewed it, please have your name added - * to the list): - * - * - Christian Grothoff - * - Nathan Evans - */ -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#define ICMP_ECHO 8 -#define IPDEFTTL 64 -#define ICMP_TIME_EXCEEDED 11 - -/** - * Must match IP given in the server. - */ -#define DUMMY_IP "192.0.2.86" - -#define NAT_TRAV_PORT 22225 - -/** - * IPv4 header. - */ -struct ip_header -{ - - /** - * Version (4 bits) + Internet header length (4 bits) - */ - uint8_t vers_ihl; - - /** - * Type of service - */ - uint8_t tos; - - /** - * Total length - */ - uint16_t pkt_len; - - /** - * Identification - */ - uint16_t id; - - /** - * Flags (3 bits) + Fragment offset (13 bits) - */ - uint16_t flags_frag_offset; - - /** - * Time to live - */ - uint8_t ttl; - - /** - * Protocol - */ - uint8_t proto; - - /** - * Header checksum - */ - uint16_t checksum; - - /** - * Source address - */ - uint32_t src_ip; - - /** - * Destination address - */ - uint32_t dst_ip; -}; - - -/** - * Format of ICMP packet. - */ -struct icmp_ttl_exceeded_header -{ - uint8_t type; - - uint8_t code; - - uint16_t checksum; - - uint32_t unused; - - /* followed by original payload */ -}; - -struct icmp_echo_header -{ - uint8_t type; - - uint8_t code; - - uint16_t checksum; - - uint32_t reserved; -}; - -/** - * Beginning of UDP packet. - */ -struct udp_header -{ - uint16_t src_port; - - uint16_t dst_port; - - uint16_t length; - - uint16_t crc; -}; - - -/** - * Socket we use to send our ICMP packets. - */ -static SOCKET rawsock; - -/** - * Target "dummy" address. - */ -static struct in_addr dummy; - -/** - * Port we are listening on (communicated to the server). - */ -static uint16_t port; - - - -/** - * Convert IPv4 address from text to binary form. - * - * @param af address family - * @param cp the address to print - * @param buf where to write the address result - * @return 1 on success - */ -static int -inet_pton (int af, - const char *cp, - struct in_addr *buf) -{ - buf->s_addr = inet_addr(cp); - if (buf->s_addr == INADDR_NONE) - { - fprintf(stderr, - "Error %d handling address %s", - WSAGetLastError(), - cp); - return 0; - } - return 1; -} - - -/** - * CRC-16 for IP/ICMP headers. - * - * @param data what to calculate the CRC over - * @param bytes number of bytes in data (must be multiple of 2) - * @return the CRC 16. - */ -static uint16_t -calc_checksum(const uint16_t *data, - unsigned int bytes) -{ - uint32_t sum; - unsigned int i; - - sum = 0; - for (i=0;i> 16); - sum = htons(0xffff - sum); - return sum; -} - - -/** - * Send an ICMP message to the target. - * - * @param my_ip source address - * @param other target address - */ -static void -send_icmp_udp (const struct in_addr *my_ip, - const struct in_addr *other) -{ - char packet[sizeof(struct ip_header) * 2 + - sizeof(struct icmp_ttl_exceeded_header) + - sizeof(struct udp_header)]; - struct ip_header ip_pkt; - struct icmp_ttl_exceeded_header icmp_pkt; - struct udp_header udp_pkt; - struct sockaddr_in dst; - size_t off; - int err; - - /* ip header: send to (known) ip address */ - off = 0; - ip_pkt.vers_ihl = 0x45; - ip_pkt.tos = 0; - ip_pkt.pkt_len = htons(sizeof (packet)); - ip_pkt.id = htons(256); - ip_pkt.flags_frag_offset = 0; - ip_pkt.ttl = 128; - ip_pkt.proto = IPPROTO_ICMP; - ip_pkt.checksum = 0; - ip_pkt.src_ip = my_ip->s_addr; - ip_pkt.dst_ip = other->s_addr; - ip_pkt.checksum = htons(calc_checksum((uint16_t*)&ip_pkt, - sizeof (struct ip_header))); - memcpy(&packet[off], - &ip_pkt, - sizeof(struct ip_header)); - off += sizeof(struct ip_header); - - icmp_pkt.type = ICMP_TIME_EXCEEDED; - icmp_pkt.code = 0; - icmp_pkt.checksum = 0; - icmp_pkt.unused = 0; - memcpy(&packet[off], - &icmp_pkt, - sizeof(struct icmp_ttl_exceeded_header)); - off += sizeof(struct icmp_ttl_exceeded_header); - - /* ip header of the presumably 'lost' udp packet */ - ip_pkt.vers_ihl = 0x45; - ip_pkt.tos = 0; - ip_pkt.pkt_len = htons(sizeof (struct ip_header) + - sizeof (struct udp_header)); - ip_pkt.id = htons(0); - ip_pkt.flags_frag_offset = 0; - ip_pkt.ttl = 128; - ip_pkt.proto = IPPROTO_UDP; - ip_pkt.checksum = 0; - ip_pkt.src_ip = other->s_addr; - ip_pkt.dst_ip = dummy.s_addr; - ip_pkt.checksum = htons(calc_checksum((uint16_t*)&ip_pkt, - sizeof (struct ip_header))); - memcpy(&packet[off], - &ip_pkt, - sizeof(struct ip_header)); - off += sizeof(struct ip_header); - - /* build UDP header */ - udp_pkt.src_port = htons(NAT_TRAV_PORT); - udp_pkt.dst_port = htons(NAT_TRAV_PORT); - udp_pkt.length = htons (port); - udp_pkt.crc = 0; - memcpy(&packet[off], - &udp_pkt, - sizeof(struct udp_header)); - off += sizeof(struct udp_header); - - /* no go back to calculate ICMP packet checksum */ - icmp_pkt.checksum = htons(calc_checksum((uint16_t*)&packet[off], - sizeof (struct icmp_ttl_exceeded_header) + - sizeof (struct ip_header) + - sizeof (struct udp_header))); - memcpy (&packet[sizeof (struct ip_header)], - &icmp_pkt, - sizeof (struct icmp_ttl_exceeded_header)); - - memset (&dst, 0, sizeof (dst)); - dst.sin_family = AF_INET; - dst.sin_addr = *other; - err = sendto(rawsock, - packet, - sizeof (packet), 0, - (struct sockaddr*)&dst, - sizeof(dst)); - if (err < 0) - { - fprintf(stderr, - "sendto failed: %s\n", strerror(errno)); - } - else if (sizeof (packet) != (size_t) err) - { - fprintf(stderr, - "Error: partial send of ICMP message\n"); - } -} - - -/** - * Send an ICMP message to the target. - * - * @param my_ip source address - * @param other target address - */ -static void -send_icmp (const struct in_addr *my_ip, - const struct in_addr *other) -{ - struct ip_header ip_pkt; - struct icmp_ttl_exceeded_header icmp_ttl; - struct icmp_echo_header icmp_echo; - struct sockaddr_in dst; - char packet[sizeof (struct ip_header) * 2 + - sizeof (struct icmp_ttl_exceeded_header) + - sizeof(struct icmp_echo_header)]; - size_t off; - int err; - - /* ip header: send to (known) ip address */ - off = 0; - ip_pkt.vers_ihl = 0x45; - ip_pkt.tos = 0; - ip_pkt.pkt_len = htons (sizeof (packet)); - ip_pkt.id = htons(256); - ip_pkt.flags_frag_offset = 0; - ip_pkt.ttl = IPDEFTTL; - ip_pkt.proto = IPPROTO_ICMP; - ip_pkt.checksum = 0; - ip_pkt.src_ip = my_ip->s_addr; - ip_pkt.dst_ip = other->s_addr; - ip_pkt.checksum = htons(calc_checksum((uint16_t*)&ip_pkt, - sizeof (struct ip_header))); - memcpy (&packet[off], - &ip_pkt, - sizeof (struct ip_header)); - off += sizeof (ip_pkt); - - /* icmp reply: time exceeded */ - icmp_ttl.type = ICMP_TIME_EXCEEDED; - icmp_ttl.code = 0; - icmp_ttl.checksum = 0; - icmp_ttl.unused = 0; - memcpy (&packet[off], - &icmp_ttl, - sizeof (struct icmp_ttl_exceeded_header)); - off += sizeof (struct icmp_ttl_exceeded_header); - - /* ip header of the presumably 'lost' udp packet */ - ip_pkt.vers_ihl = 0x45; - ip_pkt.tos = 0; - ip_pkt.pkt_len = htons(sizeof (struct ip_header) + sizeof (struct icmp_echo_header)); - ip_pkt.id = htons (256); - ip_pkt.flags_frag_offset = 0; - ip_pkt.ttl = 1; /* real TTL would be 1 on a time exceeded packet */ - ip_pkt.proto = IPPROTO_ICMP; - ip_pkt.src_ip = other->s_addr; - ip_pkt.dst_ip = dummy.s_addr; - ip_pkt.checksum = 0; - ip_pkt.checksum = htons(calc_checksum((uint16_t*)&ip_pkt, - sizeof (struct ip_header))); - memcpy (&packet[off], - &ip_pkt, - sizeof (struct ip_header)); - off += sizeof (struct ip_header); - - icmp_echo.type = ICMP_ECHO; - icmp_echo.code = 0; - icmp_echo.reserved = htonl(port); - icmp_echo.checksum = 0; - icmp_echo.checksum = htons(calc_checksum((uint16_t*) &icmp_echo, - sizeof (struct icmp_echo_header))); - memcpy (&packet[off], - &icmp_echo, - sizeof(struct icmp_echo_header)); - - /* no go back to calculate ICMP packet checksum */ - off = sizeof (struct ip_header); - icmp_ttl.checksum = htons(calc_checksum((uint16_t*) &packet[off], - sizeof (struct icmp_ttl_exceeded_header) + - sizeof (struct ip_header) + - sizeof (struct icmp_echo_header))); - memcpy (&packet[off], - &icmp_ttl, - sizeof (struct icmp_ttl_exceeded_header)); - - memset (&dst, 0, sizeof (dst)); - dst.sin_family = AF_INET; - dst.sin_addr = *other; - - err = sendto(rawsock, - packet, - sizeof (packet), 0, - (struct sockaddr*)&dst, - sizeof(dst)); - - if (err < 0) - { - fprintf(stderr, - "sendto failed: %s\n", strerror(errno)); - } - else if (sizeof (packet) != (size_t) err) - { - fprintf(stderr, - "Error: partial send of ICMP message\n"); - } -} - - -/** - * Create an ICMP raw socket. - * - * @return INVALID_SOCKET on error - */ -static SOCKET -make_raw_socket () -{ - DWORD bOptVal = TRUE; - int bOptLen = sizeof(bOptVal); - SOCKET ret; - - ret = socket (AF_INET, SOCK_RAW, IPPROTO_RAW); - if (INVALID_SOCKET == ret) - { - fprintf (stderr, - "Error opening RAW socket: %s\n", - strerror (errno)); - return INVALID_SOCKET; - } - if (0 != setsockopt(ret, SOL_SOCKET, SO_BROADCAST, (char*)&bOptVal, bOptLen)) - { - fprintf(stderr, - "Error setting SO_BROADCAST to ON: %s\n", - strerror (errno)); - closesocket(rawsock); - return INVALID_SOCKET; - } - - if (0 != setsockopt(ret, IPPROTO_IP, IP_HDRINCL, (char*)&bOptVal, bOptLen)) - { - fprintf(stderr, - "Error setting IP_HDRINCL to ON: %s\n", - strerror (errno)); - closesocket(rawsock); - return INVALID_SOCKET; - } - return ret; -} - - -int -main (int argc, char *const *argv) -{ - struct in_addr external; - struct in_addr target; - WSADATA wsaData; - - unsigned int p; - - if (argc != 4) - { - fprintf (stderr, - "This program must be started with our IP, the targets external IP, and our port as arguments.\n"); - return 1; - } - if ( (1 != inet_pton (AF_INET, argv[1], &external)) || - (1 != inet_pton (AF_INET, argv[2], &target)) ) - { - fprintf (stderr, - "Error parsing IPv4 address: %s\n", - strerror (errno)); - return 1; - } - if ( (1 != sscanf (argv[3], "%u", &p) ) || - (0 == p) || - (0xFFFF < p) ) - { - fprintf (stderr, - "Error parsing port value `%s'\n", - argv[3]); - return 1; - } - port = (uint16_t) p; - - if (0 != WSAStartup (MAKEWORD (2, 1), &wsaData)) - { - fprintf (stderr, "Failed to find Winsock 2.1 or better.\n"); - return 2; - } - if (1 != inet_pton (AF_INET, DUMMY_IP, &dummy)) - { - fprintf (stderr, - "Internal error converting dummy IP to binary.\n"); - return 2; - } - if (-1 == (rawsock = make_raw_socket())) - return 3; - send_icmp (&external, - &target); - send_icmp_udp (&external, - &target); - closesocket (rawsock); - WSACleanup (); - return 0; -} - -/* end of gnunet-nat-client-windows.c */ diff --git a/src/nat/gnunet-nat-client.c b/src/nat/gnunet-nat-client.c deleted file mode 100644 index 5f54f729b..000000000 --- a/src/nat/gnunet-nat-client.c +++ /dev/null @@ -1,527 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2010 Christian Grothoff (and other contributing authors) - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. -*/ - -/** - * @file src/nat/gnunet-nat-client.c - * @brief Tool to help bypass NATs using ICMP method; must run as root (SUID will do) - * This code will work under GNU/Linux only. - * @author Christian Grothoff - * - * This program will send ONE ICMP message using RAW sockets - * to the IP address specified as the second argument. Since - * it uses RAW sockets, it must be installed SUID or run as 'root'. - * In order to keep the security risk of the resulting SUID binary - * minimal, the program ONLY opens the RAW socket with root - * privileges, then drops them and only then starts to process - * command line arguments. The code also does not link against - * any shared libraries (except libc) and is strictly minimal - * (except for checking for errors). The following list of people - * have reviewed this code and considered it safe since the last - * modification (if you reviewed it, please have your name added - * to the list): - * - * - Christian Grothoff - * - Nathan Evans - * - Benjamin Kuperman (22 Aug 2010) - */ -#if HAVE_CONFIG_H -/* Just needed for HAVE_SOCKADDR_IN_SIN_LEN test macro! */ -#include "gnunet_config.h" -#else -#define _GNU_SOURCE -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * Must match IP given in the server. - */ -#define DUMMY_IP "192.0.2.86" - -#define NAT_TRAV_PORT 22225 - -/** - * IPv4 header. - */ -struct ip_header -{ - - /** - * Version (4 bits) + Internet header length (4 bits) - */ - uint8_t vers_ihl; - - /** - * Type of service - */ - uint8_t tos; - - /** - * Total length - */ - uint16_t pkt_len; - - /** - * Identification - */ - uint16_t id; - - /** - * Flags (3 bits) + Fragment offset (13 bits) - */ - uint16_t flags_frag_offset; - - /** - * Time to live - */ - uint8_t ttl; - - /** - * Protocol - */ - uint8_t proto; - - /** - * Header checksum - */ - uint16_t checksum; - - /** - * Source address - */ - uint32_t src_ip; - - /** - * Destination address - */ - uint32_t dst_ip; -}; - -/** - * Format of ICMP packet. - */ -struct icmp_ttl_exceeded_header -{ - uint8_t type; - - uint8_t code; - - uint16_t checksum; - - uint32_t unused; - - /* followed by original payload */ -}; - -struct icmp_echo_header -{ - uint8_t type; - - uint8_t code; - - uint16_t checksum; - - uint32_t reserved; -}; - -/** - * Beginning of UDP packet. - */ -struct udp_header -{ - uint16_t src_port; - - uint16_t dst_port; - - uint16_t length; - - uint16_t crc; -}; - -/** - * Socket we use to send our fake ICMP replies. - */ -static int rawsock; - -/** - * Target "dummy" address of the packet we pretend to respond to. - */ -static struct in_addr dummy; - -/** - * Our "source" port. - */ -static uint16_t port; - - -/** - * CRC-16 for IP/ICMP headers. - * - * @param data what to calculate the CRC over - * @param bytes number of bytes in data (must be multiple of 2) - * @return the CRC 16. - */ -static uint16_t -calc_checksum (const uint16_t *data, - unsigned int bytes) -{ - uint32_t sum; - unsigned int i; - - sum = 0; - for (i=0;i> 16); - sum = htons(0xffff - sum); - return sum; -} - - -/** - * Send an ICMP message to the target. - * - * @param my_ip source address - * @param other target address - */ -static void -send_icmp_udp (const struct in_addr *my_ip, - const struct in_addr *other) -{ - char packet[sizeof(struct ip_header) * 2 + - sizeof(struct icmp_ttl_exceeded_header) + - sizeof(struct udp_header)]; - struct ip_header ip_pkt; - struct icmp_ttl_exceeded_header icmp_pkt; - struct udp_header udp_pkt; - struct sockaddr_in dst; - size_t off; - int err; - - /* ip header: send to (known) ip address */ - off = 0; - ip_pkt.vers_ihl = 0x45; - ip_pkt.tos = 0; - ip_pkt.pkt_len = htons (sizeof (packet)); - ip_pkt.id = htons(256); - ip_pkt.flags_frag_offset = 0; - ip_pkt.ttl = 128; - ip_pkt.proto = IPPROTO_ICMP; - ip_pkt.checksum = 0; - ip_pkt.src_ip = my_ip->s_addr; - ip_pkt.dst_ip = other->s_addr; - ip_pkt.checksum = htons(calc_checksum((uint16_t*)&ip_pkt, - sizeof (struct ip_header))); - memcpy(&packet[off], - &ip_pkt, - sizeof(struct ip_header)); - off += sizeof(struct ip_header); - - icmp_pkt.type = ICMP_TIME_EXCEEDED; - icmp_pkt.code = 0; - icmp_pkt.checksum = 0; - icmp_pkt.unused = 0; - memcpy(&packet[off], - &icmp_pkt, - sizeof(struct icmp_ttl_exceeded_header)); - off += sizeof(struct icmp_ttl_exceeded_header); - - /* ip header of the presumably 'lost' udp packet */ - ip_pkt.vers_ihl = 0x45; - ip_pkt.tos = 0; - ip_pkt.pkt_len = htons(sizeof (struct ip_header) + - sizeof (struct udp_header)); - ip_pkt.id = htons(0); - ip_pkt.flags_frag_offset = 0; - ip_pkt.ttl = 128; - ip_pkt.proto = IPPROTO_UDP; - ip_pkt.checksum = 0; - ip_pkt.src_ip = other->s_addr; - ip_pkt.dst_ip = dummy.s_addr; - ip_pkt.checksum = htons(calc_checksum((uint16_t*)&ip_pkt, - sizeof (struct ip_header))); - memcpy(&packet[off], - &ip_pkt, - sizeof(struct ip_header)); - off += sizeof(struct ip_header); - - /* build UDP header */ - udp_pkt.src_port = htons(NAT_TRAV_PORT); - udp_pkt.dst_port = htons(NAT_TRAV_PORT); - udp_pkt.length = htons (port); - udp_pkt.crc = 0; - memcpy(&packet[off], - &udp_pkt, - sizeof(struct udp_header)); - off += sizeof(struct udp_header); - - /* set ICMP checksum */ - icmp_pkt.checksum = htons(calc_checksum((uint16_t*)&packet[sizeof(struct ip_header)], - sizeof (struct icmp_ttl_exceeded_header) + - sizeof (struct ip_header) + - sizeof (struct udp_header))); - memcpy (&packet[sizeof(struct ip_header)], - &icmp_pkt, - sizeof (struct icmp_ttl_exceeded_header)); - - memset (&dst, 0, sizeof (dst)); - dst.sin_family = AF_INET; -#if HAVE_SOCKADDR_IN_SIN_LEN - dst.sin_len = sizeof (struct sockaddr_in); -#endif - dst.sin_addr = *other; - err = sendto(rawsock, - packet, - sizeof (packet), 0, - (struct sockaddr*)&dst, - sizeof(dst)); - if (err < 0) - { - fprintf(stderr, - "sendto failed: %s\n", strerror(errno)); - } - else if (sizeof (packet) != (size_t) err) - { - fprintf(stderr, - "Error: partial send of ICMP message\n"); - } -} - - -/** - * Send an ICMP message to the target. - * - * @param my_ip source address - * @param other target address - */ -static void -send_icmp (const struct in_addr *my_ip, - const struct in_addr *other) -{ - struct ip_header ip_pkt; - struct icmp_ttl_exceeded_header icmp_ttl; - struct icmp_echo_header icmp_echo; - struct sockaddr_in dst; - char packet[sizeof (struct ip_header) * 2 + - sizeof (struct icmp_ttl_exceeded_header) + - sizeof (struct icmp_echo_header)]; - size_t off; - int err; - - /* ip header: send to (known) ip address */ - off = 0; - ip_pkt.vers_ihl = 0x45; - ip_pkt.tos = 0; - ip_pkt.pkt_len = htons (sizeof (packet)); - ip_pkt.id = htons (256); - ip_pkt.flags_frag_offset = 0; - ip_pkt.ttl = IPDEFTTL; - ip_pkt.proto = IPPROTO_ICMP; - ip_pkt.checksum = 0; - ip_pkt.src_ip = my_ip->s_addr; - ip_pkt.dst_ip = other->s_addr; - ip_pkt.checksum = htons(calc_checksum((uint16_t*)&ip_pkt, - sizeof (struct ip_header))); - memcpy (&packet[off], - &ip_pkt, - sizeof (struct ip_header)); - off = sizeof (ip_pkt); - - /* icmp reply: time exceeded */ - icmp_ttl.type = ICMP_TIME_EXCEEDED; - icmp_ttl.code = 0; - icmp_ttl.checksum = 0; - icmp_ttl.unused = 0; - memcpy (&packet[off], - &icmp_ttl, - sizeof (struct icmp_ttl_exceeded_header)); - off += sizeof (struct icmp_ttl_exceeded_header); - - /* ip header of the presumably 'lost' udp packet */ - ip_pkt.vers_ihl = 0x45; - ip_pkt.tos = 0; - ip_pkt.pkt_len = htons (sizeof (struct ip_header) + sizeof (struct icmp_echo_header)); - ip_pkt.id = htons (256); - ip_pkt.flags_frag_offset = 0; - ip_pkt.ttl = 1; /* real TTL would be 1 on a time exceeded packet */ - ip_pkt.proto = IPPROTO_ICMP; - ip_pkt.src_ip = other->s_addr; - ip_pkt.dst_ip = dummy.s_addr; - ip_pkt.checksum = 0; - ip_pkt.checksum = htons(calc_checksum((uint16_t*)&ip_pkt, - sizeof (struct ip_header))); - memcpy (&packet[off], - &ip_pkt, - sizeof (struct ip_header)); - off += sizeof (struct ip_header); - - icmp_echo.type = ICMP_ECHO; - icmp_echo.code = 0; - icmp_echo.reserved = htonl (port); - icmp_echo.checksum = 0; - icmp_echo.checksum = htons(calc_checksum((uint16_t*) &icmp_echo, - sizeof (struct icmp_echo_header))); - memcpy (&packet[off], - &icmp_echo, - sizeof(struct icmp_echo_header)); - - /* no go back to calculate ICMP packet checksum */ - off = sizeof (struct ip_header); - icmp_ttl.checksum = htons(calc_checksum((uint16_t*) &packet[off], - sizeof (struct icmp_ttl_exceeded_header) + - sizeof (struct ip_header) + - sizeof (struct icmp_echo_header))); - memcpy (&packet[off], - &icmp_ttl, - sizeof (struct icmp_ttl_exceeded_header)); - - /* prepare for transmission */ - memset (&dst, 0, sizeof (dst)); - dst.sin_family = AF_INET; -#if HAVE_SOCKADDR_IN_SIN_LEN - dst.sin_len = sizeof (struct sockaddr_in); -#endif - dst.sin_addr = *other; - err = sendto(rawsock, - packet, - sizeof (packet), 0, - (struct sockaddr*)&dst, - sizeof(dst)); - if (err < 0) - { - fprintf(stderr, - "sendto failed: %s\n", strerror(errno)); - } - else if (sizeof (packet) != (size_t) err) - { - fprintf(stderr, - "Error: partial send of ICMP message\n"); - } -} - - -/** - * Create an ICMP raw socket for writing. - * - * @return -1 on error - */ -static int -make_raw_socket () -{ - const int one = 1; - int ret; - - ret = socket (AF_INET, SOCK_RAW, IPPROTO_RAW); - if (-1 == ret) - { - fprintf (stderr, - "Error opening RAW socket: %s\n", - strerror (errno)); - return -1; - } - if (0 != setsockopt(ret, SOL_SOCKET, SO_BROADCAST, - (char *)&one, sizeof(one))) - { - fprintf(stderr, - "setsockopt failed: %s\n", - strerror (errno)); - close (ret); - return -1; - } - if (0 != setsockopt(ret, IPPROTO_IP, IP_HDRINCL, - (char *)&one, sizeof(one))) - { - fprintf(stderr, - "setsockopt failed: %s\n", - strerror (errno)); - close (ret); - return -1; - } - return ret; -} - - -int -main (int argc, char *const *argv) -{ - struct in_addr external; - struct in_addr target; - uid_t uid; - unsigned int p; - - if (4 != argc) - { - fprintf (stderr, - "This program must be started with our IP, the targets external IP, and our port as arguments.\n"); - return 1; - } - if ( (1 != inet_pton (AF_INET, argv[1], &external)) || - (1 != inet_pton (AF_INET, argv[2], &target)) ) - { - fprintf (stderr, - "Error parsing IPv4 address: %s\n", - strerror (errno)); - return 1; - } - if ( (1 != sscanf (argv[3], "%u", &p) ) || - (0 == p) || - (0xFFFF < p) ) - { - fprintf (stderr, - "Error parsing port value `%s'\n", - argv[3]); - return 1; - } - port = (uint16_t) p; - if (1 != inet_pton (AF_INET, DUMMY_IP, &dummy)) - { - fprintf (stderr, - "Internal error converting dummy IP to binary.\n"); - return 2; - } - if (-1 == (rawsock = make_raw_socket())) - return 2; - uid = getuid (); - if (0 != setresuid (uid, uid, uid)) - { - fprintf (stderr, - "Failed to setresuid: %s\n", - strerror (errno)); - /* not critical, continue anyway */ - } - send_icmp (&external, - &target); - send_icmp_udp (&external, - &target); - close (rawsock); - return 0; -} - -/* end of gnunet-nat-client.c */ diff --git a/src/nat/gnunet-nat-server-windows.c b/src/nat/gnunet-nat-server-windows.c deleted file mode 100644 index 6c4c7d7a1..000000000 --- a/src/nat/gnunet-nat-server-windows.c +++ /dev/null @@ -1,653 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2010 Christian Grothoff (and other contributing authors) - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. -*/ - -/** - * @file src/nat/gnunet-nat-server-windows.c - * @brief Windows tool to help bypass NATs using ICMP method - * This code will work under W32 only - * @author Christian Grothoff - * - * This program will send ONE ICMP message every 500 ms RAW sockets - * to a DUMMY IP address and also listens for ICMP replies. Since - * it uses RAW sockets, it must be run as an administrative user. - * In order to keep the security risk of the resulting binary - * minimal, the program ONLY opens the two RAW sockets with administrative - * privileges, then drops them and only then starts to process - * command line arguments. The code also does not link against - * any shared libraries (except libc) and is strictly minimal - * (except for checking for errors). The following list of people - * have reviewed this code and considered it safe since the last - * modification (if you reviewed it, please have your name added - * to the list): - * - * - Nathan Evans - * - Christian Grothoff - */ -#define _GNU_SOURCE - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * Should we print some debug output? - */ -#define VERBOSE 0 - -/** - * Must match IP given in the client. - */ -#define DUMMY_IP "192.0.2.86" - -/** - * Default Port - */ -#define NAT_TRAV_PORT 22225 - -/** - * TTL to use for our outgoing messages. - */ -#define IPDEFTTL 64 - -#define ICMP_ECHO 8 - -#define ICMP_TIME_EXCEEDED 11 - -/** - * How often do we send our ICMP messages to receive replies? - */ -#define ICMP_SEND_FREQUENCY_MS 500 - -/** - * IPv4 header. - */ -struct ip_header -{ - - /** - * Version (4 bits) + Internet header length (4 bits) - */ - uint8_t vers_ihl; - - /** - * Type of service - */ - uint8_t tos; - - /** - * Total length - */ - uint16_t pkt_len; - - /** - * Identification - */ - uint16_t id; - - /** - * Flags (3 bits) + Fragment offset (13 bits) - */ - uint16_t flags_frag_offset; - - /** - * Time to live - */ - uint8_t ttl; - - /** - * Protocol - */ - uint8_t proto; - - /** - * Header checksum - */ - uint16_t checksum; - - /** - * Source address - */ - uint32_t src_ip; - - /** - * Destination address - */ - uint32_t dst_ip; -}; - -/** - * Format of ICMP packet. - */ -struct icmp_ttl_exceeded_header -{ - uint8_t type; - - uint8_t code; - - uint16_t checksum; - - uint32_t unused; - - /* followed by original payload */ -}; - -struct icmp_echo_header -{ - uint8_t type; - - uint8_t code; - - uint16_t checksum; - - uint32_t reserved; -}; - -/** - * Beginning of UDP packet. - */ -struct udp_header -{ - uint16_t src_port; - - uint16_t dst_port; - - uint16_t length; - - uint16_t crc; -}; - -/** - * Socket we use to receive "fake" ICMP replies. - */ -static SOCKET icmpsock; - -/** - * Socket we use to send our ICMP requests. - */ -static SOCKET rawsock; - -/** - * Socket we use to send our UDP requests. - */ -static SOCKET udpsock; - -/** - * Target "dummy" address. - */ -static struct in_addr dummy; - - -/** - * CRC-16 for IP/ICMP headers. - * - * @param data what to calculate the CRC over - * @param bytes number of bytes in data (must be multiple of 2) - * @return the CRC 16. - */ -static uint16_t -calc_checksum(const uint16_t *data, - unsigned int bytes) -{ - uint32_t sum; - unsigned int i; - - sum = 0; - for (i=0;i> 16); - sum = htons(0xffff - sum); - return sum; -} - - -/** - * Convert IPv4 address from text to binary form. - * - * @param af address family - * @param cp the address to print - * @param buf where to write the address result - * @return 1 on success - */ -static int -inet_pton (int af, - const char *cp, - struct in_addr *buf) -{ - buf->s_addr = inet_addr(cp); - if (buf->s_addr == INADDR_NONE) - { - fprintf(stderr, - "Error %d handling address %s", - WSAGetLastError(), - cp); - return 0; - } - return 1; -} - - -/** - * Send an ICMP message to the dummy IP. - * - * @param my_ip source address (our ip address) - */ -static void -send_icmp_echo (const struct in_addr *my_ip) -{ - char packet[sizeof (struct ip_header) + sizeof (struct icmp_echo_header)]; - struct icmp_echo_header icmp_echo; - struct ip_header ip_pkt; - struct sockaddr_in dst; - size_t off; - int err; - - off = 0; - ip_pkt.vers_ihl = 0x45; - ip_pkt.tos = 0; - ip_pkt.pkt_len = htons (sizeof (packet)); - ip_pkt.id = htons (256); - ip_pkt.flags_frag_offset = 0; - ip_pkt.ttl = IPDEFTTL; - ip_pkt.proto = IPPROTO_ICMP; - ip_pkt.checksum = 0; - ip_pkt.src_ip = my_ip->s_addr; - ip_pkt.dst_ip = dummy.s_addr; - ip_pkt.checksum = htons(calc_checksum((uint16_t*)&ip_pkt, - sizeof (struct ip_header))); - memcpy (&packet[off], - &ip_pkt, - sizeof (struct ip_header)); - off += sizeof (struct ip_header); - - icmp_echo.type = ICMP_ECHO; - icmp_echo.code = 0; - icmp_echo.reserved = 0; - icmp_echo.checksum = 0; - icmp_echo.checksum = htons(calc_checksum((uint16_t*) &icmp_echo, - sizeof (struct icmp_echo_header))); - memcpy (&packet[off], - &icmp_echo, - sizeof (struct icmp_echo_header)); - off += sizeof (struct icmp_echo_header); - - memset (&dst, 0, sizeof (dst)); - dst.sin_family = AF_INET; - dst.sin_addr = dummy; - err = sendto(rawsock, - packet, off, 0, - (struct sockaddr*)&dst, - sizeof(dst)); - if (err < 0) - { -#if VERBOSE - fprintf(stderr, - "sendto failed: %s\n", strerror(errno)); -#endif - } - else if (err != off) - { - fprintf(stderr, - "Error: partial send of ICMP message\n"); - } -} - - -/** - * Send a UDP message to the dummy IP. - */ -static void -send_udp () -{ - struct sockaddr_in dst; - ssize_t err; - - memset (&dst, 0, sizeof (dst)); - dst.sin_family = AF_INET; - dst.sin_addr = dummy; - dst.sin_port = htons (NAT_TRAV_PORT); - err = sendto(udpsock, - NULL, 0, 0, - (struct sockaddr*)&dst, - sizeof(dst)); - if (err < 0) - { -#if VERBOSE - fprintf(stderr, - "sendto failed: %s\n", strerror(errno)); -#endif - } - else if (0 != err) - { - fprintf(stderr, - "Error: partial send of ICMP message\n"); - } -} - - -/** - * We've received an ICMP response. Process it. - */ -static void -process_icmp_response () -{ - char buf[65536]; - ssize_t have; - struct in_addr source_ip; - struct ip_header ip_pkt; - struct icmp_ttl_exceeded_header icmp_ttl; - struct icmp_echo_header icmp_echo; - struct udp_header udp_pkt; - size_t off; - uint16_t port; - DWORD ssize; - - have = read (icmpsock, buf, sizeof (buf)); - if (have == -1) - { - fprintf (stderr, - "Error reading raw socket: %s\n", - strerror (errno)); - return; - } -#if VERBOSE - fprintf (stderr, - "Received message of %u bytes\n", - (unsigned int) have); -#endif - if (have < (ssize_t) (sizeof (struct ip_header) + sizeof (struct icmp_ttl_exceeded_header) + sizeof (struct ip_header))) - { - /* malformed */ - return; - } - off = 0; - memcpy (&ip_pkt, - &buf[off], - sizeof (struct ip_header)); - off += sizeof (struct ip_header); - memcpy(&source_ip, - &ip_pkt.src_ip, - sizeof (source_ip)); - memcpy (&icmp_ttl, - &buf[off], - sizeof (struct icmp_ttl_exceeded_header)); - off += sizeof (struct icmp_ttl_exceeded_header); - if ( (ICMP_TIME_EXCEEDED != icmp_ttl.type) || - (0 != icmp_ttl.code) ) - { - /* different type than what we want */ - return; - } - /* skip 2nd IP header */ - memcpy (&ip_pkt, - &buf[off], - sizeof (struct ip_header)); - off += sizeof (struct ip_header); - - switch (ip_pkt.proto) - { - case IPPROTO_ICMP: - if (have != (sizeof (struct ip_header) * 2 + - sizeof (struct icmp_ttl_exceeded_header) + - sizeof (struct icmp_echo_header)) ) - { - /* malformed */ - return; - } - /* grab ICMP ECHO content */ - memcpy (&icmp_echo, - &buf[off], - sizeof (struct icmp_echo_header)); - port = (uint16_t) ntohl (icmp_echo.reserved); - break; - case IPPROTO_UDP: - if (have != (sizeof (struct ip_header) * 2 + - sizeof (struct icmp_ttl_exceeded_header) + - sizeof (struct udp_header)) ) - { - /* malformed */ - return; - } - /* grab UDP content */ - memcpy (&udp_pkt, - &buf[off], - sizeof (struct udp_header)); - port = ntohs (udp_pkt.length); - break; - default: - /* different type than what we want */ - return; - } - - ssize = sizeof(buf); - WSAAddressToString((LPSOCKADDR)&source_ip, - sizeof(source_ip), - NULL, - buf, - &ssize); - if (port == 0) - fprintf (stdout, - "%s\n", - buf); - else - fprintf (stdout, - "%s:%u\n", - buf, - (unsigned int) port); - fflush (stdout); -} - - -/** - * Create an ICMP raw socket for reading. - * - * @return INVALID_SOCKET on error - */ -static SOCKET -make_icmp_socket () -{ - SOCKET ret; - - ret = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); - if (INVALID_SOCKET == ret) - { - fprintf (stderr, - "Error opening RAW socket: %s\n", - strerror (errno)); - return INVALID_SOCKET; - } - return ret; -} - - -/** - * Create an ICMP raw socket for writing. - * - * @return INVALID_SOCKET on error - */ -static SOCKET -make_raw_socket () -{ - DWORD bOptVal = TRUE; - int bOptLen = sizeof(bOptVal); - - rawsock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); - if (INVALID_SOCKET == rawsock) - { - fprintf (stderr, - "Error opening RAW socket: %s\n", - strerror (errno)); - return INVALID_SOCKET; - } - - if (0 != setsockopt(rawsock, - SOL_SOCKET, - SO_BROADCAST, - (char*)&bOptVal, bOptLen)) - { - fprintf(stderr, - "Error setting SO_BROADCAST to ON: %s\n", - strerror (errno)); - closesocket(rawsock); - return INVALID_SOCKET; - } - if (0 != setsockopt(rawsock, - IPPROTO_IP, - IP_HDRINCL, - (char*)&bOptVal, bOptLen)) - { - fprintf(stderr, - "Error setting IP_HDRINCL to ON: %s\n", - strerror (errno)); - closesocket(rawsock); - return INVALID_SOCKET; - } - return rawsock; -} - - -/** - * Create a UDP socket for writing. - * - * @param my_ip source address (our ip address) - * @return INVALID_SOCKET on error - */ -static SOCKET -make_udp_socket (const struct in_addr *my_ip) -{ - SOCKET ret; - struct sockaddr_in addr; - - ret = socket (AF_INET, SOCK_DGRAM, 0); - if (INVALID_SOCKET == ret) - { - fprintf (stderr, - "Error opening UDP socket: %s\n", - strerror (errno)); - return INVALID_SOCKET; - } - memset (&addr, 0, sizeof (addr)); - addr.sin_family = AF_INET; - addr.sin_addr = *my_ip; - addr.sin_port = htons (NAT_TRAV_PORT); - if (0 != bind (ret, - (struct sockaddr *)&addr, - sizeof(addr))) - { - fprintf (stderr, - "Error binding UDP socket to port %u: %s\n", - NAT_TRAV_PORT, - strerror (errno)); - /* likely problematic, but not certain, try to continue */ - } - return ret; -} - - -int -main (int argc, - char *const *argv) -{ - struct in_addr external; - fd_set rs; - struct timeval tv; - WSADATA wsaData; - unsigned int alt; - - alt = 0; - if (2 != argc) - { - fprintf (stderr, - "This program must be started with our (internal NAT) IP as the only argument.\n"); - return 1; - } - if (1 != inet_pton (AF_INET, argv[1], &external)) - { - fprintf (stderr, - "Error parsing IPv4 address: %s, error %s\n", - argv[1], strerror (errno)); - return 1; - } - if (1 != inet_pton (AF_INET, DUMMY_IP, &dummy)) - { - fprintf (stderr, - "Internal error converting dummy IP to binary.\n"); - return 2; - } - if (WSAStartup (MAKEWORD (2, 1), &wsaData) != 0) - { - fprintf (stderr, "Failed to find Winsock 2.1 or better.\n"); - return 2; - } - if (INVALID_SOCKET == (icmpsock = make_icmp_socket())) - { - return 3; - } - if (INVALID_SOCKET == (make_raw_socket())) - { - closesocket (icmpsock); - return 3; - } - if (INVALID_SOCKET == (udpsock = make_udp_socket(&external))) - { - closesocket (icmpsock); - closesocket (rawsock); - return 3; - } - while (1) - { - FD_ZERO (&rs); - FD_SET (icmpsock, &rs); - tv.tv_sec = 0; - tv.tv_usec = ICMP_SEND_FREQUENCY_MS * 1000; - if (-1 == select (icmpsock + 1, &rs, NULL, NULL, &tv)) - { - if (errno == EINTR) - continue; - fprintf (stderr, - "select failed: %s\n", - strerror (errno)); - break; - } - if (FD_ISSET (icmpsock, &rs)) - process_icmp_response (); - if (0 == (++alt % 2)) - send_icmp_echo (&external); - else - send_udp (); - } - /* select failed (internal error or OS out of resources) */ - closesocket(icmpsock); - closesocket(rawsock); - closesocket(udpsock); - WSACleanup (); - return 4; -} - - -/* end of gnunet-nat-server-windows.c */ diff --git a/src/nat/gnunet-nat-server.c b/src/nat/gnunet-nat-server.c index ffc570146..c1f1be668 100644 --- a/src/nat/gnunet-nat-server.c +++ b/src/nat/gnunet-nat-server.c @@ -20,49 +20,12 @@ /** * @file src/nat/gnunet-nat-server.c - * @brief Tool to help bypass NATs using ICMP method; must run as root (SUID will do) - * This code will work under GNU/Linux only (or maybe BSDs, but never W32) + * @brief Daemon to run on 'gnunet.org' to help test NAT traversal code * @author Christian Grothoff * - * This program will send ONE ICMP message every 500 ms RAW sockets - * to a DUMMY IP address and also listens for ICMP replies. Since - * it uses RAW sockets, it must be installed SUID or run as 'root'. - * In order to keep the security risk of the resulting SUID binary - * minimal, the program ONLY opens the two RAW sockets with root - * privileges, then drops them and only then starts to process - * command line arguments. The code also does not link against - * any shared libraries (except libc) and is strictly minimal - * (except for checking for errors). The following list of people - * have reviewed this code and considered it safe since the last - * modification (if you reviewed it, please have your name added - * to the list): - * - * - Christian Grothoff - * - Nathan Evans - * - Benjamin Kuperman (22 Aug 2010) */ -#if HAVE_CONFIG_H -/* Just needed for HAVE_SOCKADDR_IN_SIN_LEN test macro! */ -#include "gnunet_config.h" -#else -#define _GNU_SOURCE -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "platform.h" +#include "gnunet_util_lib.h" /** * Should we print some debug output? @@ -70,581 +33,37 @@ #define VERBOSE 0 /** - * Must match IP given in the client. - */ -#define DUMMY_IP "192.0.2.86" - -/** - * Port for UDP - */ -#define NAT_TRAV_PORT 22225 - -/** - * How often do we send our ICMP messages to receive replies? - */ -#define ICMP_SEND_FREQUENCY_MS 500 - -/** - * IPv4 header. - */ -struct ip_header -{ - - /** - * Version (4 bits) + Internet header length (4 bits) - */ - uint8_t vers_ihl; - - /** - * Type of service - */ - uint8_t tos; - - /** - * Total length - */ - uint16_t pkt_len; - - /** - * Identification - */ - uint16_t id; - - /** - * Flags (3 bits) + Fragment offset (13 bits) - */ - uint16_t flags_frag_offset; - - /** - * Time to live - */ - uint8_t ttl; - - /** - * Protocol - */ - uint8_t proto; - - /** - * Header checksum - */ - uint16_t checksum; - - /** - * Source address - */ - uint32_t src_ip; - - /** - * Destination address - */ - uint32_t dst_ip; -}; - -/** - * Format of ICMP packet. - */ -struct icmp_ttl_exceeded_header -{ - uint8_t type; - - uint8_t code; - - uint16_t checksum; - - uint32_t unused; - - /* followed by original payload */ -}; - -struct icmp_echo_header -{ - uint8_t type; - - uint8_t code; - - uint16_t checksum; - - uint32_t reserved; -}; - - -/** - * Beginning of UDP packet. - */ -struct udp_header -{ - uint16_t src_port; - - uint16_t dst_port; - - uint16_t length; - - uint16_t crc; -}; - -/** - * Socket we use to receive "fake" ICMP replies. - */ -static int icmpsock; - -/** - * Socket we use to send our ICMP requests. - */ -static int rawsock; - -/** - * Socket we use to send our UDP requests. - */ -static int udpsock; - -/** - * Target "dummy" address. - */ -static struct in_addr dummy; - - -/** - * CRC-16 for IP/ICMP headers. - * - * @param data what to calculate the CRC over - * @param bytes number of bytes in data (must be multiple of 2) - * @return the CRC 16. - */ -static uint16_t -calc_checksum(const uint16_t *data, - unsigned int bytes) -{ - uint32_t sum; - unsigned int i; - - sum = 0; - for (i=0;i> 16); - sum = htons(0xffff - sum); - return sum; -} - - -/** - * Send an ICMP message to the dummy IP. + * Main function that will be run. * - * @param my_ip source address (our ip address) - */ -static void -send_icmp_echo (const struct in_addr *my_ip) -{ - char packet[sizeof (struct ip_header) + sizeof (struct icmp_echo_header)]; - struct icmp_echo_header icmp_echo; - struct ip_header ip_pkt; - struct sockaddr_in dst; - size_t off; - int err; - - off = 0; - ip_pkt.vers_ihl = 0x45; - ip_pkt.tos = 0; - ip_pkt.pkt_len = htons (sizeof (packet)); - ip_pkt.id = htons (256); - ip_pkt.flags_frag_offset = 0; - ip_pkt.ttl = IPDEFTTL; - ip_pkt.proto = IPPROTO_ICMP; - ip_pkt.checksum = 0; - ip_pkt.src_ip = my_ip->s_addr; - ip_pkt.dst_ip = dummy.s_addr; - ip_pkt.checksum = htons(calc_checksum((uint16_t*)&ip_pkt, - sizeof (struct ip_header))); - memcpy (&packet[off], - &ip_pkt, - sizeof (struct ip_header)); - off += sizeof (struct ip_header); - - icmp_echo.type = ICMP_ECHO; - icmp_echo.code = 0; - icmp_echo.checksum = 0; - icmp_echo.reserved = 0; - icmp_echo.checksum = htons(calc_checksum((uint16_t*)&icmp_echo, - sizeof (struct icmp_echo_header))); - memcpy (&packet[off], - &icmp_echo, - sizeof (struct icmp_echo_header)); - off += sizeof (struct icmp_echo_header); - - memset (&dst, 0, sizeof (dst)); - dst.sin_family = AF_INET; -#if HAVE_SOCKADDR_IN_SIN_LEN - dst.sin_len = sizeof (struct sockaddr_in); -#endif - dst.sin_addr = dummy; - err = sendto(rawsock, - packet, off, 0, - (struct sockaddr*)&dst, - sizeof(dst)); - if (err < 0) - { -#if VERBOSE - fprintf(stderr, - "sendto failed: %s\n", strerror(errno)); -#endif - } - else if (sizeof (packet) != err) - { - fprintf(stderr, - "Error: partial send of ICMP message\n"); - } -} - - -/** - * Send a UDP message to the dummy IP. - */ -static void -send_udp () -{ - struct sockaddr_in dst; - ssize_t err; - - memset (&dst, 0, sizeof (dst)); - dst.sin_family = AF_INET; -#if HAVE_SOCKADDR_IN_SIN_LEN - dst.sin_len = sizeof (struct sockaddr_in); -#endif - dst.sin_addr = dummy; - dst.sin_port = htons (NAT_TRAV_PORT); - err = sendto(udpsock, - NULL, 0, 0, - (struct sockaddr*)&dst, - sizeof(dst)); - if (err < 0) - { -#if VERBOSE - fprintf(stderr, - "sendto failed: %s\n", strerror(errno)); -#endif - } - else if (0 != err) - { - fprintf(stderr, - "Error: partial send of ICMP message\n"); - } -} - - -/** - * We've received an ICMP response. Process it. + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param c configuration */ static void -process_icmp_response () -{ - char buf[65536]; - ssize_t have; - struct in_addr source_ip; - struct ip_header ip_pkt; - struct icmp_ttl_exceeded_header icmp_ttl; - struct icmp_echo_header icmp_echo; - struct udp_header udp_pkt; - size_t off; - uint16_t port; - - have = read (icmpsock, buf, sizeof (buf)); - if (-1 == have) - { - fprintf (stderr, - "Error reading raw socket: %s\n", - strerror (errno)); - return; - } -#if VERBOSE - fprintf (stderr, - "Received message of %u bytes\n", - (unsigned int) have); -#endif - if (have < (ssize_t) (sizeof (struct ip_header) + sizeof (struct icmp_ttl_exceeded_header) + sizeof (struct ip_header))) - { - /* malformed */ - return; - } - off = 0; - memcpy (&ip_pkt, - &buf[off], - sizeof (struct ip_header)); - off += sizeof (struct ip_header); - memcpy(&source_ip, - &ip_pkt.src_ip, - sizeof (source_ip)); - memcpy (&icmp_ttl, - &buf[off], - sizeof (struct icmp_ttl_exceeded_header)); - off += sizeof (struct icmp_ttl_exceeded_header); - if ( (ICMP_TIME_EXCEEDED != icmp_ttl.type) || - (0 != icmp_ttl.code) ) - { - /* different type than what we want */ - return; - } - /* skip 2nd IP header */ - memcpy (&ip_pkt, - &buf[off], - sizeof (struct ip_header)); - off += sizeof (struct ip_header); - - switch (ip_pkt.proto) - { - case IPPROTO_ICMP: - if (have != (sizeof (struct ip_header) * 2 + - sizeof (struct icmp_ttl_exceeded_header) + - sizeof (struct icmp_echo_header)) ) - { - /* malformed */ - return; - } - /* grab ICMP ECHO content */ - memcpy (&icmp_echo, - &buf[off], - sizeof (struct icmp_echo_header)); - port = (uint16_t) ntohl (icmp_echo.reserved); - break; - case IPPROTO_UDP: - if (have != (sizeof (struct ip_header) * 2 + - sizeof (struct icmp_ttl_exceeded_header) + - sizeof (struct udp_header)) ) - { - /* malformed */ - return; - } - /* grab UDP content */ - memcpy (&udp_pkt, - &buf[off], - sizeof (struct udp_header)); - port = ntohs (udp_pkt.length); - break; - default: - /* different type than what we want */ - return; - } - - if (port == 0) - fprintf (stdout, - "%s\n", - inet_ntop (AF_INET, - &source_ip, - buf, - sizeof (buf))); - else - fprintf (stdout, - "%s:%u\n", - inet_ntop (AF_INET, - &source_ip, - buf, - sizeof (buf)), - (unsigned int) port); - fflush (stdout); -} - - -/** - * Create an ICMP raw socket for reading. - * - * @return -1 on error - */ -static int -make_icmp_socket () -{ - int ret; - - ret = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); - if (-1 == ret) - { - fprintf (stderr, - "Error opening RAW socket: %s\n", - strerror (errno)); - return -1; - } - if (ret >= FD_SETSIZE) - { - fprintf (stderr, - "Socket number too large (%d > %u)\n", - ret, - (unsigned int) FD_SETSIZE); - close (ret); - return -1; - } - return ret; -} - - -/** - * Create an ICMP raw socket for writing. - * - * @return -1 on error - */ -static int -make_raw_socket () -{ - const int one = 1; - int ret; - - ret = socket (AF_INET, SOCK_RAW, IPPROTO_RAW); - if (-1 == ret) - { - fprintf (stderr, - "Error opening RAW socket: %s\n", - strerror (errno)); - return -1; - } - if (-1 == setsockopt(ret, - SOL_SOCKET, - SO_BROADCAST, - (char *)&one, sizeof(one))) - { - fprintf(stderr, - "setsockopt failed: %s\n", - strerror (errno)); - close (ret); - return -1; - } - if (-1 == setsockopt(ret, - IPPROTO_IP, - IP_HDRINCL, - (char *)&one, sizeof(one))) - { - fprintf(stderr, - "setsockopt failed: %s\n", - strerror (errno)); - close (ret); - return -1; - } - return ret; -} - - -/** - * Create a UDP socket for writinging. - * - * @param my_ip source address (our ip address) - * @return -1 on error - */ -static int -make_udp_socket (const struct in_addr *my_ip) +run (void *cls, + char *const *args, + const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle * c) { - int ret; - struct sockaddr_in addr; - - ret = socket (AF_INET, SOCK_DGRAM, 0); - if (-1 == ret) - { - fprintf (stderr, - "Error opening UDP socket: %s\n", - strerror (errno)); - return -1; - } - memset (&addr, - 0, - sizeof (addr)); - addr.sin_family = AF_INET; -#if HAVE_SOCKADDR_IN_SIN_LEN - addr.sin_len = sizeof (struct sockaddr_in); -#endif - addr.sin_addr = *my_ip; - addr.sin_port = htons (NAT_TRAV_PORT); - - if (0 != bind (ret, - &addr, - sizeof(addr))) - { - fprintf (stderr, - "Error binding UDP socket to port %u: %s\n", - NAT_TRAV_PORT, - strerror (errno)); - /* likely problematic, but not certain, try to continue */ - } - return ret; } int -main (int argc, - char *const *argv) +main (int argc, char *const argv[]) { - struct in_addr external; - fd_set rs; - struct timeval tv; - uid_t uid; - unsigned int alt; - - if (2 != argc) - { - fprintf (stderr, - "This program must be started with our (internal NAT) IP as the only argument.\n"); - return 1; - } - if (1 != inet_pton (AF_INET, argv[1], &external)) - { - fprintf (stderr, - "Error parsing IPv4 address: %s\n", - strerror (errno)); - return 1; - } - if (1 != inet_pton (AF_INET, DUMMY_IP, &dummy)) - { - fprintf (stderr, - "Internal error converting dummy IP to binary.\n"); - return 2; - } - if (-1 == (icmpsock = make_icmp_socket())) - { - return 3; - } - if (-1 == (rawsock = make_raw_socket())) - { - close (icmpsock); - return 3; - } - uid = getuid (); - if (0 != setresuid (uid, uid, uid)) - { - fprintf (stderr, - "Failed to setresuid: %s\n", - strerror (errno)); - /* not critical, continue anyway */ - } - if (-1 == (udpsock = make_udp_socket(&external))) - { - close (icmpsock); - close (rawsock); - return 3; - } - alt = 0; - while (1) - { - FD_ZERO (&rs); - FD_SET (icmpsock, &rs); - tv.tv_sec = 0; - tv.tv_usec = ICMP_SEND_FREQUENCY_MS * 1000; - if (-1 == select (icmpsock + 1, &rs, NULL, NULL, &tv)) - { - if (errno == EINTR) - continue; - fprintf (stderr, - "select failed: %s\n", - strerror (errno)); - break; - } - if (1 == getppid()) /* Check the parent process id, if 1 the parent has died, so we should die too */ - break; - if (FD_ISSET (icmpsock, &rs)) - process_icmp_response (); - if (0 == (++alt % 2)) - send_icmp_echo (&external); - else - send_udp (); - } - /* select failed (internal error or OS out of resources) */ - close (icmpsock); - close (rawsock); - close (udpsock); - return 4; + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + if (GNUNET_OK != + GNUNET_PROGRAM_run (argc, argv, + "gnunet-nat-server", + _("GNUnet NAT traversal test helper daemon"), + options, + &run, NULL)) + return 1; + return 0; } diff --git a/src/nat/nat.c b/src/nat/nat.c index 48d7faf9c..418c619e3 100644 --- a/src/nat/nat.c +++ b/src/nat/nat.c @@ -160,12 +160,12 @@ struct GNUNET_NAT_Handle struct GNUNET_RESOLVER_RequestHandle *hostname_dns; /** - * stdout pipe handle for the gnunet-nat-server process + * stdout pipe handle for the gnunet-helper-nat-server process */ struct GNUNET_DISK_PipeHandle *server_stdout; /** - * stdout file handle (for reading) for the gnunet-nat-server process + * stdout file handle (for reading) for the gnunet-helper-nat-server process */ const struct GNUNET_DISK_FileHandle *server_stdout_handle; @@ -180,12 +180,12 @@ struct GNUNET_NAT_Handle struct LocalAddressList *lal_tail; /** - * How long do we wait for restarting a crashed gnunet-nat-server? + * How long do we wait for restarting a crashed gnunet-helper-nat-server? */ struct GNUNET_TIME_Relative server_retry_delay; /** - * ID of select gnunet-nat-server stdout read task + * ID of select gnunet-helper-nat-server stdout read task */ GNUNET_SCHEDULER_TaskIdentifier server_read_task; @@ -266,7 +266,7 @@ struct GNUNET_NAT_Handle int enable_nat_client; /** - * Should we run the gnunet-nat-server? + * Should we run the gnunet-helper-nat-server? */ int enable_nat_server; @@ -299,7 +299,7 @@ struct GNUNET_NAT_Handle /** - * Try to start the gnunet-nat-server (if it is not + * Try to start the gnunet-helper-nat-server (if it is not * already running). * * @param h handle to NAT @@ -380,7 +380,7 @@ add_to_address_list_as_is (struct GNUNET_NAT_Handle *h, * Add the given address to the list of 'local' addresses, thereby * making it a 'legal' address for this peer to have. Set the * port number in the process to the advertised port and possibly - * also to zero (if we have the gnunet-nat-server). + * also to zero (if we have the gnunet-helper-nat-server). * * @param plugin the plugin * @param src where did the local address originate from? @@ -773,7 +773,7 @@ check_gnunet_nat_binary (const char *binary) /** - * Task that restarts the gnunet-nat-server process after a crash + * Task that restarts the gnunet-helper-nat-server process after a crash * after a certain delay. * * @param cls the 'struct GNUNET_NAT_Handle' @@ -793,7 +793,7 @@ restart_nat_server (void *cls, /** - * We have been notified that gnunet-nat-server has written something to stdout. + * We have been notified that gnunet-helper-nat-server has written something to stdout. * Handle the output, then reschedule this function to be called again once * more is available. * @@ -870,10 +870,10 @@ nat_server_read (void *cls, (1 != sscanf (port_start, "%d", &port)) || (-1 == inet_pton(AF_INET, mybuf, &sin_addr.sin_addr)) ) { - /* should we restart gnunet-nat-server? */ + /* should we restart gnunet-helper-nat-server? */ GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "nat", - _("gnunet-nat-server generated malformed address `%s'\n"), + _("gnunet-helper-nat-server generated malformed address `%s'\n"), mybuf); h->server_read_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, @@ -886,7 +886,7 @@ nat_server_read (void *cls, #if DEBUG_NAT GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "nat", - "gnunet-nat-server read: %s:%d\n", + "gnunet-helper-nat-server read: %s:%d\n", mybuf, port); #endif h->reversal_callback (h->callback_cls, @@ -901,7 +901,7 @@ nat_server_read (void *cls, /** - * Try to start the gnunet-nat-server (if it is not + * Try to start the gnunet-helper-nat-server (if it is not * already running). * * @param h handle to NAT @@ -920,14 +920,14 @@ start_gnunet_nat_server (struct GNUNET_NAT_Handle *h) GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "nat" "Starting %s at `%s'\n", - "gnunet-nat-server", + "gnunet-helper-nat-server", h->internal_address); #endif /* Start the server process */ h->server_proc = GNUNET_OS_start_process (NULL, h->server_stdout, - "gnunet-nat-server", - "gnunet-nat-server", + "gnunet-helper-nat-server", + "gnunet-helper-nat-server", h->internal_address, NULL); if (h->server_proc == NULL) @@ -935,7 +935,7 @@ start_gnunet_nat_server (struct GNUNET_NAT_Handle *h) GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "nat", _("Failed to start %s\n"), - "gnunet-nat-server"); + "gnunet-helper-nat-server"); GNUNET_DISK_pipe_close (h->server_stdout); h->server_stdout = NULL; } @@ -1180,20 +1180,20 @@ GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg, /* Test for SUID binaries */ if ( (h->behind_nat == GNUNET_YES) && (GNUNET_YES == h->enable_nat_server) && - (GNUNET_YES != check_gnunet_nat_binary("gnunet-nat-server")) ) + (GNUNET_YES != check_gnunet_nat_binary("gnunet-helper-nat-server")) ) { h->enable_nat_server = GNUNET_NO; GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Configuration requires `%s', but binary is not installed properly (SUID bit not set). Option disabled.\n"), - "gnunet-nat-server"); + "gnunet-helper-nat-server"); } if ( (GNUNET_YES == h->enable_nat_client) && - (GNUNET_YES != check_gnunet_nat_binary("gnunet-nat-client")) ) + (GNUNET_YES != check_gnunet_nat_binary("gnunet-helper-nat-client")) ) { h->enable_nat_client = GNUNET_NO; GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Configuration requires `%s', but binary is not installed properly (SUID bit not set). Option disabled.\n"), - "gnunet-nat-client"); + "gnunet-helper-nat-client"); } start_gnunet_nat_server (h); @@ -1291,7 +1291,7 @@ GNUNET_NAT_unregister (struct GNUNET_NAT_Handle *h) /** * We learned about a peer (possibly behind NAT) so run the - * gnunet-nat-client to send dummy ICMP responses to cause + * gnunet-helper-nat-client to send dummy ICMP responses to cause * that peer to connect to us (connection reversal). * * @param h NAT handle for us (largely used for configuration) @@ -1330,22 +1330,22 @@ GNUNET_NAT_run_client (struct GNUNET_NAT_Handle *h, #if DEBUG_TCP_NAT GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "nat", - _("Running gnunet-nat-client %s %s %u\n"), + _("Running gnunet-helper-nat-client %s %s %u\n"), h->internal_address, inet4, (unsigned int) h->adv_port); #endif proc = GNUNET_OS_start_process (NULL, NULL, - "gnunet-nat-client", - "gnunet-nat-client", + "gnunet-helper-nat-client", + "gnunet-helper-nat-client", h->internal_address, inet4, port_as_string, NULL); if (NULL == proc) return; - /* we know that the gnunet-nat-client will terminate virtually + /* we know that the gnunet-helper-nat-client will terminate virtually instantly */ GNUNET_OS_process_wait (proc); GNUNET_OS_process_close (proc); diff --git a/src/topology/gnunet-daemon-topology.c b/src/topology/gnunet-daemon-topology.c index 35841567a..026297b65 100644 --- a/src/topology/gnunet-daemon-topology.c +++ b/src/topology/gnunet-daemon-topology.c @@ -1482,7 +1482,7 @@ main (int argc, char *const *argv) ret = (GNUNET_OK == GNUNET_PROGRAM_run (argc, argv, - "topology", + "gnunet-daemon-topology", _("GNUnet topology control (maintaining P2P mesh and F2F constraints)"), options, &run, NULL)) ? 0 : 1; diff --git a/src/transport/Makefile.am b/src/transport/Makefile.am index 123470a65..42488c7a0 100644 --- a/src/transport/Makefile.am +++ b/src/transport/Makefile.am @@ -36,6 +36,14 @@ if HAVE_EXPERIMENTAL endif endif +if LINUX +install-exec-hook: + chown root:root $(bindir)/gnunet-transport-wlan-helper || true + chmod u+s $(bindir)/gnunet-transport-wlan-helper || true +else +install-exec-hook: +endif + if !MINGW UNIX_PLUGIN_LA = libgnunet_plugin_transport_unix.la UNIX_PLUGIN_TEST = test_transport_api_unix -- cgit v1.2.3