From 94229794b52dd866fe7d27ffbed20da18934087d Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 6 Feb 2010 23:13:26 +0000 Subject: [PATCH] stuff --- src/transport/gnunet-nat-client.c | 468 +++++------------------------- src/transport/gnunet-nat-server.c | 399 +++++-------------------- 2 files changed, 157 insertions(+), 710 deletions(-) diff --git a/src/transport/gnunet-nat-client.c b/src/transport/gnunet-nat-client.c index 0fce09e71..ba99c8816 100644 --- a/src/transport/gnunet-nat-client.c +++ b/src/transport/gnunet-nat-client.c @@ -20,16 +20,14 @@ /** * @file src/transport/gnunet-nat-client.c - * @brief Tool to help bypass NATs using ICMP method; must run as root (for now, later SUID will do) - * This code will work under GNU/Linux only (or maybe BSDs, but never W32) + * @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 */ - +#define _GNU_SOURCE #include #include #include -#include -#include #include #include #include @@ -37,37 +35,14 @@ #include #include #include -#include #include #include #include -#define DEBUG 1 - -/** - * Number of UDP ports to keep open (typically >= 256) - */ -#define NUM_UDP_PORTS 1024 - -/** - * Number of ICMP replies to send per message received (typically >= 1024) - */ -#define NUM_ICMP_REPLIES 10240 - /** - * How often do we send our UDP messages to keep ports open? (typically < 100ms) + * Must match IP given in the server. */ -#define UDP_SEND_FREQUENCY_MS 10 - -/** - * Port we use for the dummy target. - */ -#define NAT_TRAV_PORT 22223 - -/** - * How often do we retry to open and bind a UDP socket before giving up? - */ -#define MAX_TRIES 10 +#define DUMMY_IP "1.2.3.4" struct ip_packet { @@ -83,31 +58,14 @@ struct ip_packet uint32_t dst_ip; }; -struct udp_packet -{ - uint16_t source_port; - uint16_t dst_port; - uint16_t mlen_aka_reply_port_magic; - uint16_t checksum_aka_my_magic; -}; - struct icmp_packet { uint8_t type; uint8_t code; uint16_t checksum; uint32_t reserved; - struct ip_packet ip; - struct udp_packet udp; }; - - -static int udpsocks[NUM_UDP_PORTS]; - -static uint16_t udpports[NUM_UDP_PORTS]; -static int icmpsock; - static int rawsock; static struct in_addr dummy; @@ -115,63 +73,6 @@ static struct in_addr dummy; static struct in_addr target; -/** - * create a random port number that is not totally - * unlikely to be chosen by the nat box. - */ -static uint16_t make_port () -{ - return 1024 + ( (unsigned int)rand ()) % (63 * 1024 - 2); -} - - -/** - * create a fresh udp socket bound to a random local port. - */ -static int -make_udp_socket (uint16_t *port) -{ - int ret; - int tries; - struct sockaddr_in src; - - for (tries=0;tries= FD_SETSIZE) - { - fprintf (stderr, - "Socket number too large (%d > %u)\n", - ret, - (unsigned int) FD_SETSIZE); - close (ret); - return -1; - } - memset (&src, 0, sizeof (src)); - src.sin_family = AF_INET; - src.sin_port = htons (make_port ()); - if (0 != bind (ret, (struct sockaddr*) &src, sizeof (src))) - { - close (ret); - continue; - } - *port = ntohs (src.sin_port); - return ret; - } - fprintf (stderr, - "Error binding udp socket: %s\n", - strerror (errno)); - return -1; -} - - static uint16_t calc_checksum(const uint16_t *data, unsigned int bytes) @@ -188,76 +89,83 @@ calc_checksum(const uint16_t *data, } +static void +make_echo (const struct in_addr *src_ip, + struct icmp_packet *echo) +{ + memset(echo, 0, sizeof(struct icmp_packet)); + echo->type = ICMP_ECHO; + echo->code = 0; + echo->reserved = 0; + echo->checksum = 0; + echo->checksum = htons(calc_checksum((uint16_t*)echo, + sizeof (struct icmp_packet))); +} + + /** - * send an icmp message to the target. + * Send an ICMP message to the target. * - * @param my_ip source address (our ip address) + * @param my_ip source address * @param other target address - * @param target_port_number fake port number to put into icmp response - * as well as the icmpextradata as 'my_magic' - * @param source_port_number magic_number that enables the other peer to - * identify our port number ('reply in response to') to - * put in the data portion; 0 if we are initiating; - * goes into 'reply_port_magic' of the icmpextradata */ static void send_icmp (const struct in_addr *my_ip, - const struct in_addr *other, - uint16_t target_port_number, - uint16_t source_port_number) + const struct in_addr *other) { struct ip_packet ip_pkt; - struct icmp_packet icmp_pkt; + struct icmp_packet *icmp_pkt; + struct icmp_packet icmp_echo; struct sockaddr_in dst; - char packet[sizeof (ip_pkt) + sizeof (icmp_pkt)]; + char packet[sizeof (struct ip_packet)*2 + sizeof (struct icmp_packet)*2]; size_t off; int err; /* ip header: send to (known) ip address */ off = 0; memset(&ip_pkt, 0, sizeof(ip_pkt)); - ip_pkt.vers_ihl = 0x45;//|(pkt_len>>2);//5;//(ipversion << 4) | (iphdr_size >> 2); + ip_pkt.vers_ihl = 0x45; ip_pkt.tos = 0; ip_pkt.pkt_len = sizeof (packet); /* huh? */ - ip_pkt.id = 1; /* kernel will change anyway!? */ + ip_pkt.id = 1; ip_pkt.flags_frag_offset = 0; ip_pkt.ttl = IPDEFTTL; ip_pkt.proto = IPPROTO_ICMP; - ip_pkt.checksum = 0; + 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 (ip_pkt))); - memcpy (packet, &ip_pkt, sizeof (ip_pkt)); + ip_pkt.checksum = htons(calc_checksum((uint16_t*)&ip_pkt, sizeof (struct ip_packet))); + memcpy (packet, &ip_pkt, sizeof (struct ip_packet)); off += sizeof (ip_pkt); - /* icmp reply: time exceeded */ - memset(&icmp_pkt, 0, sizeof(icmp_pkt)); - icmp_pkt.type = ICMP_TIME_EXCEEDED; - icmp_pkt.code = ICMP_HOST_UNREACH; - icmp_pkt.reserved = 0; - icmp_pkt.checksum = 0; + icmp_pkt = (struct icmp_packet*) &packet[off]; + memset(icmp_pkt, 0, sizeof(struct icmp_packet)); + icmp_pkt->type = ICMP_TIME_EXCEEDED; + icmp_pkt->code = 0; + icmp_pkt->reserved = 0; + icmp_pkt->checksum = 0; + off += sizeof (struct icmp_packet); /* ip header of the presumably 'lost' udp packet */ - icmp_pkt.ip.vers_ihl = 0x45; - icmp_pkt.ip.tos = 0; - /* no idea why i need to shift the bits here, but not on ip_pkt->pkt_len... */ - icmp_pkt.ip.pkt_len = (sizeof (ip_pkt) + sizeof (icmp_pkt)) << 8; - icmp_pkt.ip.id = 1; /* kernel sets proper value htons(ip_id_counter); */ - icmp_pkt.ip.flags_frag_offset = 0; - icmp_pkt.ip.ttl = 1; /* real TTL would be 1 on a time exceeded packet */ - icmp_pkt.ip.proto = IPPROTO_UDP; - icmp_pkt.ip.src_ip = other->s_addr; - icmp_pkt.ip.dst_ip = dummy.s_addr; - icmp_pkt.ip.checksum = 0; - icmp_pkt.ip.checksum = htons(calc_checksum((uint16_t*)&icmp_pkt.ip, sizeof (icmp_pkt.ip))); - icmp_pkt.udp.source_port = htons (target_port_number); - icmp_pkt.udp.dst_port = htons (NAT_TRAV_PORT); - icmp_pkt.udp.mlen_aka_reply_port_magic = htons (source_port_number); - icmp_pkt.udp.checksum_aka_my_magic = htons (target_port_number); - icmp_pkt.checksum = htons(calc_checksum((uint16_t*)&icmp_pkt, sizeof (icmp_pkt))); - memcpy (&packet[off], &icmp_pkt, sizeof (icmp_pkt)); - off += sizeof (icmp_pkt); - + ip_pkt.vers_ihl = 0x45; + ip_pkt.tos = 0; + ip_pkt.pkt_len = (sizeof (struct ip_packet) + sizeof (struct icmp_packet)); + ip_pkt.id = 1; + 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_packet))); + memcpy (&packet[off], &ip_pkt, sizeof (struct ip_packet)); + off += sizeof (struct ip_packet); + make_echo (other, &icmp_echo); + memcpy (&packet[off], &icmp_echo, sizeof(struct icmp_packet)); + off += sizeof (struct icmp_packet); + icmp_pkt->checksum = htons(calc_checksum((uint16_t*)icmp_pkt, + sizeof (struct icmp_packet)*2 + sizeof(struct ip_packet))); + memset (&dst, 0, sizeof (dst)); dst.sin_family = AF_INET; dst.sin_addr = *other; @@ -266,176 +174,19 @@ send_icmp (const struct in_addr *my_ip, off, 0, (struct sockaddr*)&dst, sizeof(dst)); /* or sizeof 'struct sockaddr'? */ - if (err < 0) { - fprintf(stderr, - "sendto failed: %s\n", strerror(errno)); - } else if (err != off) - fprintf(stderr, - "Error: partial send of ICMP message\n"); -} - - -/** - * We discovered the IP address of the other peer. - * Try to connect back to it. - */ -static void -try_connect (const struct in_addr *my_ip, - const struct in_addr *other, - uint16_t port_magic) -{ - unsigned int i; - char sbuf [INET_ADDRSTRLEN]; - - fprintf (stderr, - "Sending %u ICMPs to `%s' with reply magic %u\n", - NUM_ICMP_REPLIES, - inet_ntop (AF_INET, - other, - sbuf, - sizeof (sbuf)), - port_magic); - for (i=0;i= FD_SETSIZE) - { - fprintf (stderr, - "Socket number too large (%d > %u)\n", - ret, - (unsigned int) FD_SETSIZE); - close (ret); - return -1; - } - return ret; -} - - static int make_raw_socket () { @@ -450,15 +201,6 @@ make_raw_socket () 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; - } if (setsockopt(ret, SOL_SOCKET, SO_BROADCAST, (char *)&one, sizeof(one)) == -1) fprintf(stderr, @@ -477,88 +219,34 @@ int main (int argc, char *const *argv) { struct in_addr external; - unsigned int i; - unsigned int pos; - fd_set rs; - struct timeval tv; - struct sockaddr_in dst; - uint16_t p; - - if (argc != 4) + uid_t uid; + + if (-1 == (rawsock = make_raw_socket())) + return 1; + uid = getuid (); + if (0 != setresuid (uid, uid, uid)) + fprintf (stderr, + "Failed to setresuid: %s\n", + strerror (errno)); + if (argc != 3) { fprintf (stderr, - "This program must be started with our IP, the targets external IP and the dummy IP address as arguments.\n"); + "This program must be started with our IP and the targets external IP as arguments.\n"); return 1; } if ( (1 != inet_pton (AF_INET, argv[1], &external)) || - (1 != inet_pton (AF_INET, argv[2], &target)) || - (1 != inet_pton (AF_INET, argv[3], &dummy)) ) + (1 != inet_pton (AF_INET, argv[2], &target)) ) { fprintf (stderr, "Error parsing IPv4 address: %s\n", strerror (errno)); return 1; } - srand (time(NULL)); - memset (&dst, 0, sizeof (dst)); - dst.sin_family = AF_INET; - dst.sin_port = htons (NAT_TRAV_PORT); - dst.sin_addr = dummy; - - if (-1 == (icmpsock = make_icmp_socket())) - return 1; - if (-1 == (rawsock = make_raw_socket())) - { - close (icmpsock); - return 1; - } - for (i=0;i #include #include @@ -42,37 +42,18 @@ #include #include -#define DEBUG 0 - -/** - * Number of UDP ports to keep open (typically >= 256). - */ -#define NUM_UDP_PORTS 256 - -/** - * Number of ICMP replies to send per message received (typically >= 1024) - */ -#define NUM_ICMP_REPLIES 1024 - /** - * How often do we send our UDP messages to keep ports open? (typically < 100ms) + * Must match IP given in the client. */ -#define UDP_SEND_FREQUENCY_MS 50 +#define DUMMY_IP "1.2.3.4" /** - * Port we use for the dummy target. + * How often do we send our ICMP messages to receive replies? */ -#define NAT_TRAV_PORT 2222 - -/** - * How often do we retry to open and bind a UDP socket before giving up? - */ -#define MAX_TRIES 10 - +#define ICMP_SEND_FREQUENCY_MS 500 struct ip_packet { - uint8_t vers_ihl; uint8_t tos; uint16_t pkt_len; @@ -85,112 +66,20 @@ struct ip_packet uint32_t dst_ip; }; - -struct udp_packet -{ - uint16_t source_port; - uint16_t dst_port; - uint16_t mlen_aka_reply_port_magic; - uint16_t checksum_aka_my_magic; -}; - - struct icmp_packet { uint8_t type; uint8_t code; uint16_t checksum; uint32_t reserved; - struct ip_packet ip; - struct udp_packet udp; -}; - - -/** - * Structure of the data we tack on to the fake ICMP reply - * (last 4 bytes of the 64 bytes). - */ -struct extra_packet -{ - /** - * if this is a reply to an icmp, what was the 'my_magic' - * value from the original icmp? - */ - uint16_t reply_port_magic; - - /** - * magic value of the sender of this icmp message. - */ - uint16_t my_magic; }; -static int udpsocks[NUM_UDP_PORTS]; -static uint16_t udpports[NUM_UDP_PORTS]; - static int icmpsock; static int rawsock; static struct in_addr dummy; - - -/** - * create a random port number that is not totally - * unlikely to be chosen by the nat box. - */ -static uint16_t make_port () -{ - return 1024 + ( (unsigned int)rand ()) % (63 * 1024 - 2); -} - - -/** - * create a fresh udp socket bound to a random local port. - */ -static int -make_udp_socket (uint16_t *port) -{ - int ret; - int tries; - struct sockaddr_in src; - - for (tries=0;tries= FD_SETSIZE) - { - fprintf (stderr, - "Socket number too large (%d > %u)\n", - ret, - (unsigned int) FD_SETSIZE); - close (ret); - return -1; - } - memset (&src, 0, sizeof (src)); - src.sin_family = AF_INET; - src.sin_port = htons (make_port ()); - if (0 != bind (ret, (struct sockaddr*) &src, sizeof (src))) - { - close (ret); - continue; - } - *port = ntohs (src.sin_port); - return ret; - } - fprintf (stderr, - "Error binding udp socket: %s\n", - strerror (errno)); - return -1; -} - static uint16_t calc_checksum(const uint16_t *data, @@ -208,144 +97,93 @@ calc_checksum(const uint16_t *data, } +static void +make_echo (const struct in_addr *src_ip, + struct icmp_packet *echo) +{ + memset(echo, 0, sizeof(struct icmp_packet)); + echo->type = ICMP_ECHO; + echo->code = 0; + echo->reserved = 0; + echo->checksum = 0; + echo->checksum = htons(calc_checksum((uint16_t*)echo, sizeof (struct icmp_packet))); +} + + /** - * send an icmp message to the target. + * Send an ICMP message to the dummy IP. * * @param my_ip source address (our ip address) - * @param other target address - * @param target_port_number fake port number to put into icmp response - * as well as the icmpextradata as 'my_magic' - * @param source_port_number magic_number that enables the other peer to - * identify our port number ('reply in response to') to - * put in the data portion; 0 if we are initiating; - * goes into 'reply_port_magic' of the icmpextradata */ static void -send_icmp (const struct in_addr *my_ip, - const struct in_addr *other, - uint16_t target_port_number, - uint16_t source_port_number) +send_icmp_echo (const struct in_addr *my_ip) { - struct ip_packet ip_pkt; - struct icmp_packet icmp_pkt; + struct icmp_packet icmp_echo; struct sockaddr_in dst; - char packet[sizeof (ip_pkt) + sizeof (icmp_pkt)]; size_t off; int err; + struct ip_packet ip_pkt; + struct icmp_packet icmp_pkt; + char packet[sizeof (ip_pkt) + sizeof (icmp_pkt)]; - /* ip header: send to (known) ip address */ off = 0; memset(&ip_pkt, 0, sizeof(ip_pkt)); - ip_pkt.vers_ihl = 0x45;//|(pkt_len>>2);//5;//(ipversion << 4) | (iphdr_size >> 2); + ip_pkt.vers_ihl = 0x45; ip_pkt.tos = 0; - ip_pkt.pkt_len = sizeof (packet); /* huh? */ - ip_pkt.id = 1; /* kernel will change anyway!? */ + ip_pkt.pkt_len = sizeof (packet); + ip_pkt.id = 1; ip_pkt.flags_frag_offset = 0; ip_pkt.ttl = IPDEFTTL; ip_pkt.proto = IPPROTO_ICMP; - ip_pkt.checksum = 0; /* maybe the kernel helps us out..? */ + ip_pkt.checksum = 0; ip_pkt.src_ip = my_ip->s_addr; - ip_pkt.dst_ip = other->s_addr; + ip_pkt.dst_ip = dummy.s_addr; ip_pkt.checksum = htons(calc_checksum((uint16_t*)&ip_pkt, sizeof (ip_pkt))); memcpy (packet, &ip_pkt, sizeof (ip_pkt)); off += sizeof (ip_pkt); - - /* icmp reply: time exceeded */ - memset(&icmp_pkt, 0, sizeof(icmp_pkt)); - icmp_pkt.type = ICMP_TIME_EXCEEDED; - icmp_pkt.code = ICMP_NET_UNREACH; - icmp_pkt.reserved = 0; - icmp_pkt.checksum = 0; - - /* ip header of the presumably 'lost' udp packet */ - icmp_pkt.ip.vers_ihl = 0x45; - icmp_pkt.ip.tos = 0; - /* no idea why i need to shift the bits here, but not on ip_pkt->pkt_len... */ - icmp_pkt.ip.pkt_len = (sizeof (ip_pkt) + sizeof (icmp_pkt)) << 8; - icmp_pkt.ip.id = 1; /* kernel sets proper value htons(ip_id_counter); */ - icmp_pkt.ip.flags_frag_offset = 0; - icmp_pkt.ip.ttl = 1; /* real TTL would be 1 on a time exceeded packet */ - icmp_pkt.ip.proto = IPPROTO_UDP; - icmp_pkt.ip.src_ip = other->s_addr; - icmp_pkt.ip.dst_ip = dummy.s_addr; - icmp_pkt.ip.checksum = 0; - icmp_pkt.ip.checksum = htons(calc_checksum((uint16_t*)&icmp_pkt.ip, sizeof (icmp_pkt.ip))); - icmp_pkt.udp.source_port = htons (target_port_number); - icmp_pkt.udp.dst_port = htons (NAT_TRAV_PORT); - icmp_pkt.udp.mlen_aka_reply_port_magic = htons (source_port_number); - icmp_pkt.udp.checksum_aka_my_magic = htons (target_port_number); - icmp_pkt.checksum = htons(calc_checksum((uint16_t*)&icmp_pkt, sizeof (icmp_pkt))); - memcpy (&packet[off], &icmp_pkt, sizeof (icmp_pkt)); - off += sizeof (icmp_pkt); + make_echo (my_ip, &icmp_echo); + memcpy (&packet[off], &icmp_echo, sizeof (icmp_echo)); + off += sizeof (icmp_echo); memset (&dst, 0, sizeof (dst)); dst.sin_family = AF_INET; - dst.sin_addr = *other; + dst.sin_addr = dummy; err = sendto(rawsock, - packet, - off, 0, + packet, off, 0, (struct sockaddr*)&dst, - sizeof(dst)); /* or sizeof 'struct sockaddr'? */ - if (err < 0) { - fprintf(stderr, - "sendto failed: %s\n", strerror(errno)); - } else if (err != off) - fprintf(stderr, - "Error: partial send of ICMP message\n"); -} - - -/** - * We discovered the IP address of the other peer. - * Try to connect back to it. - */ -static void -try_connect (const struct in_addr *my_ip, - const struct in_addr *other, - uint16_t port_magic) -{ - unsigned int i; -#if DEBUG - char sbuf [INET_ADDRSTRLEN]; - - fprintf (stderr, - "Sending %u ICMPs to `%s' with reply magic %u\n", - NUM_ICMP_REPLIES, - inet_ntop (AF_INET, - other, - sbuf, - sizeof (sbuf)), - port_magic); -#endif - for (i=0;i= FD_SETSIZE) - { - fprintf (stderr, - "Socket number too large (%d > %u)\n", - ret, - (unsigned int) FD_SETSIZE); - close (ret); - return -1; - } if (setsockopt(ret, SOL_SOCKET, SO_BROADCAST, (char *)&one, sizeof(one)) == -1) fprintf(stderr, @@ -487,72 +272,46 @@ int main (int argc, char *const *argv) { struct in_addr external; - unsigned int i; - unsigned int pos; fd_set rs; struct timeval tv; - struct sockaddr_in dst; - - if (argc != 3) + uid_t uid; + + if (-1 == (icmpsock = make_icmp_socket())) + return 1; + if (-1 == (rawsock = make_raw_socket())) + { + close (icmpsock); + return 1; + } + uid = getuid (); + if (0 != setresuid (uid, uid, uid)) + fprintf (stderr, + "Failed to setresuid: %s\n", + strerror (errno)); + if (argc != 2) { fprintf (stderr, - "This program must be started with our external IP and the dummy IP address as arguments.\n"); + "This program must be started with our external IP as the only argument.\n"); return 1; } - if ( (1 != inet_pton (AF_INET, argv[1], &external)) || - (1 != inet_pton (AF_INET, argv[2], &dummy)) ) + if (1 != inet_pton (AF_INET, argv[1], &external)) { fprintf (stderr, "Error parsing IPv4 address: %s\n", strerror (errno)); return 1; } - srand (time(NULL)); - memset (&dst, 0, sizeof (dst)); - dst.sin_family = AF_INET; - dst.sin_port = htons (NAT_TRAV_PORT); - dst.sin_addr = dummy; - - if (-1 == (icmpsock = make_icmp_socket())) - return 1; - if (-1 == (rawsock = make_raw_socket())) - { - close (icmpsock); - return 1; - } - for (i=0;i