X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fnat%2Fgnunet-helper-nat-server.c;h=d3c890b9815ad06e4253af206654ba85223f4e83;hb=f4d040c0f0dd2fef3d73b1f4532c76219f760f75;hp=f71c37fa8723f4686b2a84697aafd117c4f89acf;hpb=ac109f65ead8ae7aa01a99b100bebfac39d25ffa;p=oweals%2Fgnunet.git diff --git a/src/nat/gnunet-helper-nat-server.c b/src/nat/gnunet-helper-nat-server.c index f71c37fa8..d3c890b98 100644 --- a/src/nat/gnunet-helper-nat-server.c +++ b/src/nat/gnunet-helper-nat-server.c @@ -40,6 +40,7 @@ * - Christian Grothoff * - Nathan Evans * - Benjamin Kuperman (22 Aug 2010) + * - Jacob Appelbaum (19 Dec 2011) */ #if HAVE_CONFIG_H /* Just needed for HAVE_SOCKADDR_IN_SIN_LEN test macro! */ @@ -69,6 +70,11 @@ */ #define VERBOSE 0 +/** + * Must match packet ID used by gnunet-helper-nat-client.c + */ +#define PACKET_ID 256 + /** * Must match IP given in the client. */ @@ -245,7 +251,7 @@ send_icmp_echo (const struct in_addr *my_ip) ip_pkt.vers_ihl = 0x45; ip_pkt.tos = 0; ip_pkt.pkt_len = htons (sizeof (packet)); - ip_pkt.id = htons (256); + ip_pkt.id = htons (PACKET_ID); ip_pkt.flags_frag_offset = 0; ip_pkt.ttl = IPDEFTTL; ip_pkt.proto = IPPROTO_ICMP; @@ -354,7 +360,6 @@ process_icmp_response () 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)) @@ -398,6 +403,7 @@ process_icmp_response () return; } + source_ip.s_addr = ip_pkt.src_ip; if (port == 0) fprintf (stdout, "%s\n", inet_ntop (AF_INET, &source_ip, buf, sizeof (buf))); @@ -410,64 +416,28 @@ process_icmp_response () /** - * 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. + * Fully initialize the raw socket. * - * @return -1 on error + * @return -1 on error, 0 on success */ static int -make_raw_socket () +setup_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))) + setsockopt (rawsock, 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))) + setsockopt (rawsock, IPPROTO_IP, IP_HDRINCL, (char *) &one, sizeof (one))) { fprintf (stderr, "setsockopt failed: %s\n", strerror (errno)); - close (ret); return -1; } - return ret; + return 0; } @@ -501,7 +471,7 @@ make_udp_socket (const struct in_addr *my_ip) { fprintf (stderr, "Error binding UDP socket to port %u: %s\n", NAT_TRAV_PORT, strerror (errno)); - close (ret); + (void) close (ret); return -1; } return ret; @@ -516,52 +486,97 @@ main (int argc, char *const *argv) struct timeval tv; uid_t uid; unsigned int alt; + int icmp_eno; + int raw_eno; + int global_ret; + /* Create an ICMP raw socket for reading (we'll check errors later) */ + icmpsock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); + icmp_eno = errno; + + /* Create an (ICMP) raw socket for writing (we'll check errors later) */ + rawsock = socket (AF_INET, SOCK_RAW, IPPROTO_RAW); + raw_eno = errno; + udpsock = -1; + + /* drop root rights */ + uid = getuid (); +#ifdef HAVE_SETRESUID + if (0 != setresuid (uid, uid, uid)) + { + fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno)); + global_ret = 1; + goto error_exit; + } +#else + if (0 != (setuid (uid) | seteuid (uid))) + { + fprintf (stderr, "Failed to setuid: %s\n", strerror (errno)); + global_ret = 2; + goto error_exit; + } +#endif + + /* Now that we run without root rights, we can do error checking... */ if (2 != argc) { fprintf (stderr, "This program must be started with our (internal NAT) IP as the only argument.\n"); - return 1; + global_ret = 3; + goto error_exit; } if (1 != inet_pton (AF_INET, argv[1], &external)) { fprintf (stderr, "Error parsing IPv4 address: %s\n", strerror (errno)); - return 1; + global_ret = 4; + goto error_exit; } if (1 != inet_pton (AF_INET, DUMMY_IP, &dummy)) { fprintf (stderr, "Internal error converting dummy IP to binary.\n"); - return 2; + global_ret = 5; + goto error_exit; } - if (-1 == (icmpsock = make_icmp_socket ())) + + /* error checking icmpsock */ + if (-1 == icmpsock) { - return 3; + fprintf (stderr, "Error opening RAW socket: %s\n", strerror (icmp_eno)); + global_ret = 6; + goto error_exit; } - if (-1 == (rawsock = make_raw_socket ())) + if (icmpsock >= FD_SETSIZE) { - close (icmpsock); - return 4; + /* this could happen if we were started with a large number of already-open + file descriptors... */ + fprintf (stderr, "Socket number too large (%d > %u)\n", icmpsock, + (unsigned int) FD_SETSIZE); + global_ret = 7; + goto error_exit; } - uid = getuid (); -#ifdef HAVE_SETRESUID - if (0 != setresuid (uid, uid, uid)) + + /* error checking rawsock */ + if (-1 == rawsock) { - fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno)); - return 5; + fprintf (stderr, "Error opening RAW socket: %s\n", strerror (raw_eno)); + global_ret = 8; + goto error_exit; } -#else - if (0 != (setuid (uid) | seteuid (uid))) + /* no need to check 'rawsock' against FD_SETSIZE as it is never used + with 'select' */ + + if (0 != setup_raw_socket ()) { - fprintf (stderr, "Failed to setuid: %s\n", strerror (errno)); - return 6; + global_ret = 9; + goto error_exit; } -#endif + if (-1 == (udpsock = make_udp_socket (&external))) { - close (icmpsock); - close (rawsock); - return 7; + global_ret = 10; + goto error_exit; } + alt = 0; while (1) { @@ -585,11 +600,17 @@ main (int argc, char *const *argv) else send_udp (); } + /* select failed (internal error or OS out of resources) */ - close (icmpsock); - close (rawsock); - close (udpsock); - return 8; + global_ret = 11; +error_exit: + if (-1 != icmpsock) + (void) close (icmpsock); + if (-1 != rawsock) + (void) close (rawsock); + if (-1 != udpsock) + (void) close (udpsock); + return global_ret; }