--- gvpe/src/vpn.C 2011/02/08 23:13:48 1.57 +++ gvpe/src/vpn.C 2022/10/06 03:03:09 1.70 @@ -1,6 +1,6 @@ /* vpn.C -- handle the protocol, encryption, handshaking etc. - Copyright (C) 2003-2008 Marc Lehmann + Copyright (C) 2003-2008,2010,2011,2013 Marc Lehmann This file is part of GVPE. @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -54,10 +55,38 @@ #include "util.h" #include "vpn.h" +using namespace std; + vpn network; // THE vpn (bad design...) ///////////////////////////////////////////////////////////////////////////// +// hopefully temporary workaround for rare buffer full conditions +// if it happens, usually instantly retrying or retrying ~5ms later +// is good enough with current network technologies/kernels + +static ssize_t +xsendto (int fd, const void *buf, size_t len, int flags, + const struct sockaddr *sa, socklen_t salen) +{ + ssize_t res; + + for (int retry = 0; retry <= 13; ++retry) // ~100ms + { + res = sendto (fd, buf, len, flags, sa, salen); + + if (res >= 0 || errno != ENOBUFS) + break; + + struct timespec ts = { 0, 1000 * retry }; + nanosleep (&ts, 0); + } + + return res; +} + +///////////////////////////////////////////////////////////////////////////// + static void inline set_tos (int fd, int &tos_prev, int tos) { @@ -77,7 +106,7 @@ // the tricky part is rounding to the cipher key blocksize int mtu = conf.mtu - ETH_OVERHEAD - VPE_OVERHEAD - MAX_OVERHEAD; mtu += ETH_OVERHEAD - 6 - 6; // now we have the data portion - mtu -= mtu % EVP_CIPHER_block_size (CIPHER); // round + mtu -= mtu % BLOCK_SIZE (CIPHER); // round mtu -= ETH_OVERHEAD - 6 - 6; // and get interface mtu again char *env; @@ -112,13 +141,7 @@ { script_init_env (); - char *filename; - asprintf (&filename, - "%s/%s", - confbase, - ::conf.script_if_up ? ::conf.script_if_up : "if-up"); - - return filename; + return conf.config_filename (::conf.script_if_up, "if-up"); } int @@ -237,9 +260,10 @@ #ifdef ICMP_FILTER { icmp_filter oval; - oval.data = 0xffffffff; + oval.data = 0; if (::conf.icmp_type < 32) - oval.data &= ~(1 << ::conf.icmp_type); + oval.data |= 1 << ::conf.icmp_type; + oval.data = ~oval.data; setsockopt (icmpv4_fd, SOL_RAW, ICMP_FILTER, &oval, sizeof oval); } @@ -394,10 +418,78 @@ } bool +vpn::drop_privileges () +{ + if (::conf.change_root) + { + if (!strcmp (::conf.change_root, "/")) + { + char dir [L_tmpnam]; + if (!tmpnam (dir)) + { + slog (L_CRIT, _("unable to create anonymous root path.")); + return false; + } + + if (mkdir (dir, 0700)) + { + slog (L_CRIT, _("unable to create anonymous root directory.")); + return false; + } + + if (chdir (dir)) + { + slog (L_CRIT, _("unable to change to anonymous root directory.")); + return false; + } + + if (rmdir (dir)) + slog (L_ERR, _("unable to remove anonymous root directory, continuing.")); + } + else + { + if (chdir (::conf.change_root)) + { + slog (L_CRIT, _("%s: unable to change to specified root directory."), ::conf.change_root); + return false; + } + } + + if (chroot (".")) + { + slog (L_CRIT, _("unable to set new root directory.")); + return false; + } + + if (chdir ("/")) + { + slog (L_CRIT, _("unable to set cwd to new root directory.")); + return false; + } + } + + if (::conf.change_gid) + if (setgid (::conf.change_gid)) + { + slog (L_CRIT, _("unable to change group id to %d."), ::conf.change_gid); + return false; + } + + if (::conf.change_uid) + if (setuid (::conf.change_uid)) + { + slog (L_CRIT, _("unable to change user id to %d."), ::conf.change_uid); + return false; + } + + return true; +} + +bool vpn::send_ipv4_packet (vpn_packet *pkt, const sockinfo &si, int tos) { set_tos (ipv4_fd, ipv4_tos, tos); - sendto (ipv4_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ()); + xsendto (ipv4_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ()); return true; } @@ -438,7 +530,7 @@ hdr->checksum = ipv4_checksum ((u16 *)hdr, pkt->len); set_tos (icmpv4_fd, icmpv4_tos, tos); - sendto (icmpv4_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ()); + xsendto (icmpv4_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ()); return true; } @@ -448,7 +540,7 @@ vpn::send_udpv4_packet (vpn_packet *pkt, const sockinfo &si, int tos) { set_tos (udpv4_fd, udpv4_tos, tos); - sendto (udpv4_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ()); + xsendto (udpv4_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ()); return true; } @@ -486,9 +578,6 @@ || pkt->typ () >= vpn_packet::PT_MAX) slog (L_WARN, _("(%s): received corrupted packet type %d (src %d, dst %d)."), (const char *)rsi, pkt->typ (), pkt->src (), pkt->dst ()); - else if (dst > conns.size ()) - slog (L_WARN, _("(%s): received corrupted packet type %d (src %d, dst %d)."), - (const char *)rsi, pkt->typ (), pkt->src (), pkt->dst ()); else { connection *c = conns[src - 1]; @@ -518,14 +607,14 @@ switch (si.prot) { case PROT_IPv4: - return send_ipv4_packet (pkt, si, tos); + return send_ipv4_packet (pkt, si, tos); case PROT_UDPv4: - return send_udpv4_packet (pkt, si, tos); + return send_udpv4_packet (pkt, si, tos); #if ENABLE_TCP case PROT_TCPv4: - return send_tcpv4_packet (pkt, si, tos); + return send_tcpv4_packet (pkt, si, tos); #endif #if ENABLE_ICMP case PROT_ICMPv4: @@ -533,7 +622,7 @@ #endif #if ENABLE_DNS case PROT_DNSv4: - return send_dnsv4_packet (pkt, si, tos); + return send_dnsv4_packet (pkt, si, tos); #endif default: slog (L_CRIT, _("%s: FATAL: trying to send packet with unsupported protocol."), (const char *)si); @@ -561,7 +650,7 @@ pkt->len = len; // raw sockets deliver the ipv4 header, but don't expect it on sends - pkt->skip_hdr (IP_OVERHEAD); + pkt->skip_hdr (pkt->ipv4_hdr_len ()); recv_vpn_packet (pkt, si); } @@ -608,7 +697,7 @@ { // raw sockets deliver the ipv4, but don't expect it on sends // this is slow, but... - pkt->skip_hdr (ICMP_OVERHEAD); + pkt->skip_hdr (pkt->ipv4_hdr_len () + (ICMP_OVERHEAD - IP_OVERHEAD)); recv_vpn_packet (pkt, si); } @@ -829,10 +918,10 @@ { connection *o = *i; - if (!o->is_direct - && o->si.valid () + if (o->si.valid () && c->si != o->si - && c == find_router_for (o)) + && c == find_router_for (o) + && !can_direct (THISNODE, o->conf)) { slog (L_DEBUG, _("%s: can now route packets via %s, re-keying connection."), o->conf->nodename, c->conf->nodename);