X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fnat%2Fgnunet-helper-nat-server.c;h=8c3df749d161314aea51e0aa0107df1bd863cdd9;hb=2105059516320800eaa8fff1196b58f29a50ba7c;hp=e57319d005df2e747c06052c9c889dbcf75dec1f;hpb=1f85e67c62031b79d7f9607f0ac4bcd1a5a04704;p=oweals%2Fgnunet.git diff --git a/src/nat/gnunet-helper-nat-server.c b/src/nat/gnunet-helper-nat-server.c index e57319d00..8c3df749d 100644 --- a/src/nat/gnunet-helper-nat-server.c +++ b/src/nat/gnunet-helper-nat-server.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - (C) 2010 Christian Grothoff (and other contributing authors) + Copyright (C) 2010 GNUnet e.V. GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -14,8 +14,8 @@ 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. + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ /** @@ -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! */ @@ -64,6 +65,11 @@ #include #include +/* The following constant is missing from FreeBSD 9.2 */ +#ifndef ICMP_TIME_EXCEEDED +#define ICMP_TIME_EXCEEDED 11 +#endif + /** * Should we print some debug output? */ @@ -366,6 +372,9 @@ process_icmp_response () /* different type than what we want */ return; } + /* grab source IP of 1st IP header */ + source_ip.s_addr = ip_pkt.src_ip; + /* skip 2nd IP header */ memcpy (&ip_pkt, &buf[off], sizeof (struct ip_header)); off += sizeof (struct ip_header); @@ -402,7 +411,6 @@ 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))); @@ -415,64 +423,28 @@ process_icmp_response () /** - * Create an ICMP raw socket for reading. + * Fully initialize the raw socket. * - * @return -1 on error + * @return -1 on error, 0 on success */ 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); - (void) close (ret); - return -1; - } - return ret; -} - - -/** - * Create an ICMP raw socket for writing. - * - * @return -1 on error - */ -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)); - (void) 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)); - (void) close (ret); return -1; } - return ret; + return 0; } @@ -491,7 +463,9 @@ make_udp_socket (const struct in_addr *my_ip) ret = socket (AF_INET, SOCK_DGRAM, 0); if (-1 == ret) { - fprintf (stderr, "Error opening UDP socket: %s\n", strerror (errno)); + fprintf (stderr, + "Error opening UDP socket: %s\n", + strerror (errno)); return -1; } memset (&addr, 0, sizeof (addr)); @@ -502,9 +476,13 @@ make_udp_socket (const struct in_addr *my_ip) addr.sin_addr = *my_ip; addr.sin_port = htons (NAT_TRAV_PORT); - if (0 != bind (ret, &addr, sizeof (addr))) + if (0 != bind (ret, + (struct sockaddr *) &addr, + sizeof (addr))) { - fprintf (stderr, "Error binding UDP socket to port %u: %s\n", NAT_TRAV_PORT, + fprintf (stderr, + "Error binding UDP socket to port %u: %s\n", + NAT_TRAV_PORT, strerror (errno)); (void) close (ret); return -1; @@ -521,56 +499,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) { - (void) 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)); - (void) close (icmpsock); - (void) close (rawsock); - 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)); - (void) close (icmpsock); - (void) close (rawsock); - return 6; + global_ret = 9; + goto error_exit; } -#endif + if (-1 == (udpsock = make_udp_socket (&external))) { - (void) close (icmpsock); - (void) close (rawsock); - return 7; + global_ret = 10; + goto error_exit; } + alt = 0; while (1) { @@ -594,11 +613,17 @@ main (int argc, char *const *argv) else send_udp (); } + /* select failed (internal error or OS out of resources) */ - (void) close (icmpsock); - (void) close (rawsock); - (void) 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; }