X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Ftransport%2Fgnunet-nat-server-windows.c;h=8cfad2ff297db6971d11f3c96d8bd070963232a2;hb=accae6c152eaacdf41b6069b88b3e5744ff06bba;hp=bd757299e91c52bc9518bdede6ffb0e6213efc24;hpb=65f5d92f4ee9abdcb40f7c0eb06062118976fefc;p=oweals%2Fgnunet.git diff --git a/src/transport/gnunet-nat-server-windows.c b/src/transport/gnunet-nat-server-windows.c index bd757299e..8cfad2ff2 100644 --- a/src/transport/gnunet-nat-server-windows.c +++ b/src/transport/gnunet-nat-server-windows.c @@ -38,6 +38,7 @@ * to the list): * * - Nathan Evans + * - Christian Grothoff */ #define _GNU_SOURCE @@ -64,6 +65,11 @@ */ #define DUMMY_IP "192.0.2.86" +/** + * Default Port + */ +#define NAT_TRAV_PORT 22225 + /** * TTL to use for our outgoing messages. */ @@ -71,7 +77,7 @@ #define ICMP_ECHO 8 -#define ICMP_TIME_EXCEEDED 11 /* Time Exceeded */ +#define ICMP_TIME_EXCEEDED 11 /** * How often do we send our ICMP messages to receive replies? @@ -81,64 +87,77 @@ /** * IPv4 header. */ -struct ip_packet +struct ip_header { /** - * Version (4 bits) + Internet header length (4 bits) + * Version (4 bits) + Internet header length (4 bits) */ - u_char vers_ihl; + uint8_t vers_ihl; /** * Type of service */ - u_char tos; + uint8_t tos; /** * Total length */ - u_short pkt_len; + uint16_t pkt_len; /** * Identification */ - u_short id; + uint16_t id; /** * Flags (3 bits) + Fragment offset (13 bits) */ - u_short flags_frag_offset; + uint16_t flags_frag_offset; /** * Time to live */ - u_char ttl; + uint8_t ttl; /** - * Protocol + * Protocol */ - u_char proto; + uint8_t proto; /** * Header checksum */ - u_short checksum; + uint16_t checksum; /** * Source address */ - u_long src_ip; + uint32_t src_ip; /** - * Destination address + * Destination address */ - u_long dst_ip; + uint32_t dst_ip; }; /** * Format of ICMP packet. */ -struct 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; @@ -152,13 +171,15 @@ struct icmp_packet /** * Beginning of UDP packet. */ -struct udp_packet +struct udp_header { uint16_t src_port; uint16_t dst_port; - uint32_t length; + uint16_t length; + + uint16_t crc; }; /** @@ -171,6 +192,11 @@ static SOCKET icmpsock; */ static SOCKET rawsock; +/** + * Socket we use to send our UDP requests. + */ +static SOCKET udpsock; + /** * Target "dummy" address. */ @@ -184,16 +210,16 @@ static struct in_addr dummy; * @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, +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; @@ -208,17 +234,17 @@ calc_checksum(const uint16_t *data, * @param buf where to write the address result * @return 1 on success */ -static int -inet_pton (int af, - const char *cp, +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(), + fprintf(stderr, + "Error %d handling address %s", + WSAGetLastError(), cp); return 0; } @@ -234,19 +260,17 @@ inet_pton (int af, static void send_icmp_echo (const struct in_addr *my_ip) { - struct icmp_packet icmp_echo; + 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; - struct ip_packet ip_pkt; - struct icmp_packet icmp_pkt; - char packet[sizeof (ip_pkt) + sizeof (icmp_pkt)]; off = 0; - memset(&ip_pkt, 0, sizeof(ip_pkt)); ip_pkt.vers_ihl = 0x45; ip_pkt.tos = 0; - ip_pkt.pkt_len = sizeof (packet); + ip_pkt.pkt_len = htons (sizeof (packet)); ip_pkt.id = htons (256); ip_pkt.flags_frag_offset = 0; ip_pkt.ttl = IPDEFTTL; @@ -254,34 +278,71 @@ send_icmp_echo (const struct in_addr *my_ip) 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 (ip_pkt))); - memcpy (packet, &ip_pkt, sizeof (ip_pkt)); - off += sizeof (ip_pkt); + 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_packet))); - memcpy (&packet[off], &icmp_echo, sizeof (icmp_echo)); - off += sizeof (icmp_echo); - + 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, + err = sendto(rawsock, packet, off, 0, (struct sockaddr*)&dst, sizeof(dst)); - if (err < 0) + 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 (err != off) + else if (0 != err) { fprintf(stderr, "Error: partial send of ICMP message\n"); @@ -297,13 +358,14 @@ process_icmp_response () { char buf[65536]; ssize_t have; - struct in_addr sip; - struct ip_packet ip_pkt; - struct icmp_packet icmp_pkt; - struct udp_packet udp_pkt; + 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; - int have_port; - uint32_t port; + uint16_t port; + DWORD ssize; have = read (icmpsock, buf, sizeof (buf)); if (have == -1) @@ -311,90 +373,92 @@ process_icmp_response () fprintf (stderr, "Error reading raw socket: %s\n", strerror (errno)); - return; + return; } - have_port = 0; #if VERBOSE fprintf (stderr, "Received message of %u bytes\n", (unsigned int) have); #endif - if (have == sizeof (struct ip_packet) *2 + sizeof (struct icmp_packet) * 2 + sizeof(uint32_t)) - { - have_port = 1; - } - else if (have != sizeof (struct ip_packet) *2 + sizeof (struct icmp_packet) * 2) + if (have < (ssize_t) (sizeof (struct ip_header) + sizeof (struct icmp_ttl_exceeded_header) + sizeof (struct ip_header))) { -#if VERBOSE - fprintf (stderr, - "Received ICMP message of unexpected size: %u bytes\n", - (unsigned int) have); -#endif + /* malformed */ return; } off = 0; - memcpy (&ip_pkt, &buf[off], sizeof (ip_pkt)); - off += sizeof (ip_pkt); - memcpy (&icmp_pkt, &buf[off], sizeof (icmp_pkt)); - off += sizeof (icmp_pkt); - if ( ((ip_pkt.proto != IPPROTO_ICMP) && (ip_pkt.proto != IPPROTO_UDP)) || - (icmp_pkt.type != ICMP_TIME_EXCEEDED) || - (icmp_pkt.code != 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) ) { - /* maybe we got an actual reply back... */ - return; + /* different type than what we want */ + return; } - memcpy(&sip, - &ip_pkt.src_ip, - sizeof (sip)); - memcpy (&ip_pkt, &buf[off], sizeof (ip_pkt)); - off += sizeof (ip_pkt); + /* skip 2nd IP header */ + memcpy (&ip_pkt, + &buf[off], + sizeof (struct ip_header)); + off += sizeof (struct ip_header); - if (have_port) + switch (ip_pkt.proto) { - memcpy(&port, - &buf[sizeof (struct ip_packet) *2 + sizeof (struct icmp_packet) * 2], - sizeof(uint32_t)); - port = ntohs(port); - DWORD ssize = sizeof(buf); - WSAAddressToString((LPSOCKADDR)&sip, - sizeof(sip), - NULL, - buf, - &ssize); - fprintf (stdout, - "%s:%d\n", - buf, - port); - } - else if (ip_pkt.proto == IPPROTO_UDP) - { - memcpy(&udp_pkt, - &buf[off], - sizeof(udp_pkt)); - DWORD ssize = sizeof(buf); - WSAAddressToString((LPSOCKADDR)&sip, - sizeof(sip), - NULL, - buf, - &ssize); - fprintf (stdout, - "%s:%d\n", - buf, - ntohs((uint16_t)udp_pkt.length)); + 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 - { - DWORD ssize = sizeof(buf); - WSAAddressToString((LPSOCKADDR)&sip, - sizeof(sip), - NULL, - buf, - &ssize); - fprintf (stdout, - "%s\n", - buf); - } + fprintf (stdout, + "%s:%u\n", + buf, + (unsigned int) port); fflush (stdout); } @@ -416,7 +480,7 @@ make_icmp_socket () "Error opening RAW socket: %s\n", strerror (errno)); return INVALID_SOCKET; - } + } return ret; } @@ -441,23 +505,23 @@ make_raw_socket () return INVALID_SOCKET; } - if (setsockopt(rawsock, - SOL_SOCKET, - SO_BROADCAST, - (char*)&bOptVal, bOptLen) != 0) + if (0 != setsockopt(rawsock, + SOL_SOCKET, + SO_BROADCAST, + (char*)&bOptVal, bOptLen)) { - fprintf(stderr, + fprintf(stderr, "Error setting SO_BROADCAST to ON: %s\n", strerror (errno)); closesocket(rawsock); return INVALID_SOCKET; } - if (setsockopt(rawsock, - IPPROTO_IP, - IP_HDRINCL, - (char*)&bOptVal, bOptLen) != 0) + if (0 != setsockopt(rawsock, + IPPROTO_IP, + IP_HDRINCL, + (char*)&bOptVal, bOptLen)) { - fprintf(stderr, + fprintf(stderr, "Error setting IP_HDRINCL to ON: %s\n", strerror (errno)); closesocket(rawsock); @@ -467,16 +531,56 @@ make_raw_socket () } +/** + * 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, +main (int argc, char *const *argv) { struct in_addr external; fd_set rs; struct timeval tv; WSADATA wsaData; + unsigned int alt; - if (argc != 2) + alt = 0; + if (2 != argc) { fprintf (stderr, "This program must be started with our (internal NAT) IP as the only argument.\n"); @@ -489,7 +593,7 @@ main (int argc, argv[1], strerror (errno)); return 1; } - if (1 != inet_pton (AF_INET, DUMMY_IP, &dummy)) + if (1 != inet_pton (AF_INET, DUMMY_IP, &dummy)) { fprintf (stderr, "Internal error converting dummy IP to binary.\n"); @@ -502,19 +606,25 @@ main (int argc, } if (INVALID_SOCKET == (icmpsock = make_icmp_socket())) { - return 3; + return 3; } if (INVALID_SOCKET == (make_raw_socket())) { closesocket (icmpsock); - return 3; + 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; + tv.tv_usec = ICMP_SEND_FREQUENCY_MS * 1000; if (-1 == select (icmpsock + 1, &rs, NULL, NULL, &tv)) { if (errno == EINTR) @@ -526,13 +636,17 @@ main (int argc, } if (FD_ISSET (icmpsock, &rs)) process_icmp_response (); - send_icmp_echo (&external); + 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; + return 4; }