diff options
author | Christian Grothoff <christian@grothoff.org> | 2011-06-27 20:22:33 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2011-06-27 20:22:33 +0000 |
commit | 436f9a3345ae1f9276593ad34d8606a5de8fceeb (patch) | |
tree | 8a1173c23815cf211c0c1ae91d35dc784043682c /src/transport | |
parent | 836d9e75481db1162d1c93c891f0be2d8f2766f4 (diff) |
moving NAT client/server to NAT library
Diffstat (limited to 'src/transport')
-rw-r--r-- | src/transport/Makefile.am | 31 | ||||
-rwxr-xr-x | src/transport/gnunet-nat-client-script.sh | 4 | ||||
-rw-r--r-- | src/transport/gnunet-nat-client-windows.c | 550 | ||||
-rw-r--r-- | src/transport/gnunet-nat-client.c | 527 | ||||
-rwxr-xr-x | src/transport/gnunet-nat-server-script.sh | 4 | ||||
-rw-r--r-- | src/transport/gnunet-nat-server-windows.c | 653 | ||||
-rw-r--r-- | src/transport/gnunet-nat-server.c | 651 |
7 files changed, 4 insertions, 2416 deletions
diff --git a/src/transport/Makefile.am b/src/transport/Makefile.am index e8ed46aad5..97c17d6151 100644 --- a/src/transport/Makefile.am +++ b/src/transport/Makefile.am @@ -2,15 +2,6 @@ INCLUDES = -I$(top_srcdir)/src/include plugindir = $(libdir)/gnunet -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 -endif if HAVE_MHD if HAVE_EXPERIMENTAL @@ -53,15 +44,6 @@ UNIX_QUOTA_TEST = test_quota_compliance_unix \ test_quota_compliance_unix_asymmetric_recv_constant endif -if LINUX -NATBIN = gnunet-nat-server gnunet-nat-client -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 -else -install-exec-hook: -endif - #noinst_PROGRAMS = ${check_PROGRAMS} lib_LTLIBRARIES = \ @@ -96,15 +78,12 @@ libgnunettransport_la_LDFLAGS = \ bin_PROGRAMS = \ gnunet-transport \ $(WLAN_BIN) \ - gnunet-service-transport $(NATBIN) \ + gnunet-service-transport \ $(WLAN_BIN_DUMMY) bin_SCRIPTS = \ gnunet-transport-certificate-creation -gnunet_nat_server_SOURCES = \ - $(NATSERVER) - gnunet_transport_wlan_helper_SOURCES = \ wlan/byteorder.h \ @@ -127,9 +106,6 @@ gnunet_transport_wlan_helper_LDADD = \ gnunet_transport_wlan_helper_dummy_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la -gnunet_nat_client_SOURCES = \ - $(NATCLIENT) - gnunet_transport_SOURCES = \ gnunet-transport.c gnunet_transport_LDADD = \ @@ -161,7 +137,6 @@ plugin_LTLIBRARIES = \ $(HTTPS_PLUGIN_LA) \ $(WLAN_PLUGIN_LA) \ libgnunet_plugin_transport_template.la -# TODO: add nat, etc. libgnunet_plugin_transport_tcp_la_SOURCES = \ plugin_transport_tcp.c @@ -197,6 +172,7 @@ libgnunet_plugin_transport_udp_la_LIBADD = \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/nat/libgnunetnat.la \ $(top_builddir)/src/util/libgnunetutil.la libgnunet_plugin_transport_udp_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) @@ -218,6 +194,7 @@ libgnunet_plugin_transport_http_la_LIBADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ @LIBCURL@ \ + $(top_builddir)/src/nat/libgnunetnat.la \ $(top_builddir)/src/util/libgnunetutil.la libgnunet_plugin_transport_http_la_LDFLAGS = \ $(GN_LIBMHD) \ @@ -234,6 +211,7 @@ libgnunet_plugin_transport_https_la_LIBADD = \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ @LIBCURL@ \ + $(top_builddir)/src/nat/libgnunetnat.la \ $(top_builddir)/src/util/libgnunetutil.la libgnunet_plugin_transport_https_la_LDFLAGS = \ $(GN_LIBMHD) \ @@ -277,7 +255,6 @@ check_PROGRAMS = \ $(WLAN_API_TEST) \ $(WLAN_REL_TEST) \ $(WLAN_UREL_TEST) -# TODO: add tests for nat, etc. if ENABLE_TEST_RUN TESTS = \ diff --git a/src/transport/gnunet-nat-client-script.sh b/src/transport/gnunet-nat-client-script.sh deleted file mode 100755 index 4e4ccafadc..0000000000 --- a/src/transport/gnunet-nat-client-script.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -IP=`ifconfig | grep inet | head -n1 | awk '{print $2}' | sed -e "s/addr://"` -echo "Using IP $IP, trying to connect to $1" -./gnunet-nat-client-udp $IP $1 diff --git a/src/transport/gnunet-nat-client-windows.c b/src/transport/gnunet-nat-client-windows.c deleted file mode 100644 index 2e7c8a86e4..0000000000 --- a/src/transport/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/transport/gnunet-nat-client-windows.c - * @brief Tool to help bypass NATs using ICMP method; must run as - * root (SUID will do) or administrator on W32 - * This code will work under GNU/Linux or 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 <winsock2.h> -#include <ws2tcpip.h> -#include <sys/time.h> -#include <sys/types.h> -#include <unistd.h> -#include <stdio.h> -#include <string.h> -#include <errno.h> -#include <stdlib.h> -#include <stdint.h> -#include <time.h> - - -#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<bytes/2;i++) - sum += data[i]; - sum = (sum & 0xffff) + (sum >> 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/transport/gnunet-nat-client.c b/src/transport/gnunet-nat-client.c deleted file mode 100644 index 3e35aa8f4f..0000000000 --- a/src/transport/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/transport/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 <sys/types.h> -#include <sys/socket.h> -#include <arpa/inet.h> -#include <sys/types.h> -#include <unistd.h> -#include <stdio.h> -#include <string.h> -#include <errno.h> -#include <stdlib.h> -#include <stdint.h> -#include <netinet/ip.h> -#include <netinet/ip_icmp.h> -#include <netinet/in.h> - -/** - * 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<bytes/2;i++) - sum += data[i]; - sum = (sum & 0xffff) + (sum >> 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) |