--- gvpe/src/vpn.C 2005/04/08 16:48:16 1.36 +++ gvpe/src/vpn.C 2008/08/09 18:30:55 1.48 @@ -1,22 +1,32 @@ /* vpn.C -- handle the protocol, encryption, handshaking etc. - Copyright (C) 2003-2005 Marc Lehmann + Copyright (C) 2003-2008 Marc Lehmann This file is part of GVPE. - GVPE is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with gvpe; if not, write to the Free Software - Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + GVPE is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, see . + + Additional permission under GNU GPL version 3 section 7 + + If you modify this Program, or any covered work, by linking or + combining it with the OpenSSL project's OpenSSL library (or a modified + version of that library), containing parts covered by the terms of the + OpenSSL or SSLeay licenses, the licensors of this Program grant you + additional permission to convey the resulting work. Corresponding + Source for a non-source form of such a combination shall include the + source code for the parts of OpenSSL used as well as that of the + covered work. */ #include "config.h" @@ -48,6 +58,18 @@ ///////////////////////////////////////////////////////////////////////////// +static void inline +set_tos (int fd, int &tos_prev, int tos) +{ +#if defined(SOL_IP) && defined(IP_TOS) + if (tos_prev == tos) + return; + + tos_prev = tos; + setsockopt (fd, SOL_IP, IP_TOS, &tos, sizeof tos); +#endif +} + void vpn::script_init_env () { @@ -77,14 +99,16 @@ } } -const char *vpn::script_if_init () +inline const char * +vpn::script_if_init () { script_init_env (); return tap->if_up (); } -const char *vpn::script_if_up () +inline const char * +vpn::script_if_up () { script_init_env (); @@ -100,7 +124,8 @@ int vpn::setup () { - ipv4_fd = -1; + ipv4_tos = -1; + ipv4_fd = -1; if (THISNODE->protocols & PROT_IPv4 && ::conf.ip_proto) { @@ -110,6 +135,7 @@ return -1; fcntl (ipv4_fd, F_SETFL, O_NONBLOCK); + fcntl (ipv4_fd, F_SETFD, FD_CLOEXEC); #if defined(SOL_IP) && defined(IP_MTU_DISCOVER) // this I really consider a linux bug. I am neither connected @@ -129,10 +155,11 @@ exit (EXIT_FAILURE); } - ipv4_ev_watcher.start (ipv4_fd, EVENT_READ); + ipv4_ev_watcher.start (ipv4_fd, EV_READ); } - udpv4_fd = -1; + udpv4_tos = -1; + udpv4_fd = -1; if (THISNODE->protocols & PROT_UDPv4 && THISNODE->udp_port) { @@ -142,6 +169,7 @@ return -1; fcntl (udpv4_fd, F_SETFL, O_NONBLOCK); + fcntl (udpv4_fd, F_SETFD, FD_CLOEXEC); // standard daemon practise... { @@ -167,10 +195,11 @@ exit (EXIT_FAILURE); } - udpv4_ev_watcher.start (udpv4_fd, EVENT_READ); + udpv4_ev_watcher.start (udpv4_fd, EV_READ); } - icmpv4_fd = -1; + icmpv4_tos = -1; + icmpv4_fd = -1; #if ENABLE_ICMP if (THISNODE->protocols & PROT_ICMPv4) @@ -181,6 +210,7 @@ return -1; fcntl (icmpv4_fd, F_SETFL, O_NONBLOCK); + fcntl (icmpv4_fd, F_SETFD, FD_CLOEXEC); #ifdef ICMP_FILTER { @@ -211,7 +241,7 @@ exit (EXIT_FAILURE); } - icmpv4_ev_watcher.start (icmpv4_fd, EVENT_READ); + icmpv4_ev_watcher.start (icmpv4_fd, EV_READ); } #endif @@ -226,6 +256,7 @@ return -1; fcntl (tcpv4_fd, F_SETFL, O_NONBLOCK); + fcntl (tcpv4_fd, F_SETFD, FD_CLOEXEC); // standard daemon practise... { @@ -247,10 +278,13 @@ exit (EXIT_FAILURE); } - tcpv4_ev_watcher.start (tcpv4_fd, EVENT_READ); + tcpv4_ev_watcher.start (tcpv4_fd, EV_READ); } #endif + dnsv4_tos = -1; + dnsv4_fd = -1; + #if ENABLE_DNS if (THISNODE->protocols & PROT_DNSv4) { @@ -261,6 +295,9 @@ if (dnsv4_fd < 0) return -1; + fcntl (dnsv4_fd, F_SETFL, O_NONBLOCK); + fcntl (dnsv4_fd, F_SETFD, FD_CLOEXEC); + # if defined(SOL_IP) && defined(IP_MTU_DISCOVER) // this I really consider a linux bug. I am neither connected // nor do I fragment myself. Linux still sets DF and doesn't @@ -287,7 +324,7 @@ exit (EXIT_FAILURE); } - dnsv4_ev_watcher.start (dnsv4_fd, EVENT_READ); + dnsv4_ev_watcher.start (dnsv4_fd, EV_READ); } #endif @@ -304,21 +341,27 @@ exit (EXIT_FAILURE); } + fcntl (tap->fd, F_SETFD, FD_CLOEXEC); + + run_script_cb cb; + cb.set (this); + if (tap->if_up () && - !run_script (run_script_cb (this, &vpn::script_if_init), true)) + !run_script (cb, true)) { slog (L_ERR, _("interface initialization command '%s' failed, exiting."), tap->if_up ()); exit (EXIT_FAILURE); } - if (!run_script (run_script_cb (this, &vpn::script_if_up), true)) + cb.set (this); + if (!run_script (cb, true)) { slog (L_ERR, _("if-up command execution failed, exiting.")); exit (EXIT_FAILURE); } - tap_ev_watcher.start (tap->fd, EVENT_READ); + tap_ev_watcher.start (tap->fd, EV_READ); return 0; } @@ -326,9 +369,7 @@ bool vpn::send_ipv4_packet (vpn_packet *pkt, const sockinfo &si, int tos) { -#if defined(SOL_IP) && defined(IP_TOS) - setsockopt (ipv4_fd, SOL_IP, IP_TOS, &tos, sizeof tos); -#endif + set_tos (ipv4_fd, ipv4_tos, tos); sendto (ipv4_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ()); return true; @@ -361,10 +402,6 @@ bool vpn::send_icmpv4_packet (vpn_packet *pkt, const sockinfo &si, int tos) { -#if defined(SOL_IP) && defined(IP_TOS) - setsockopt (icmpv4_fd, SOL_IP, IP_TOS, &tos, sizeof tos); -#endif - pkt->unshift_hdr (4); icmp_header *hdr = (icmp_header *)&((*pkt)[0]); @@ -373,6 +410,7 @@ hdr->checksum = 0; 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 ()); return true; @@ -382,9 +420,7 @@ bool vpn::send_udpv4_packet (vpn_packet *pkt, const sockinfo &si, int tos) { -#if defined(SOL_IP) && defined(IP_TOS) - setsockopt (udpv4_fd, SOL_IP, IP_TOS, &tos, sizeof tos); -#endif + set_tos (udpv4_fd, udpv4_tos, tos); sendto (udpv4_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ()); return true; @@ -405,7 +441,7 @@ // we have to connect to all hosts... for (conns_vector::iterator c = conns.begin (); c != conns.end (); ++c) if ((*c)->conf != THISNODE) - (*c)->inject_data_packet (pkt, true); + (*c)->inject_data_packet (pkt); } } @@ -456,8 +492,10 @@ { case PROT_IPv4: return send_ipv4_packet (pkt, si, tos); + case PROT_UDPv4: return send_udpv4_packet (pkt, si, tos); + #if ENABLE_TCP case PROT_TCPv4: return send_tcpv4_packet (pkt, si, tos); @@ -470,7 +508,6 @@ case PROT_DNSv4: return send_dnsv4_packet (pkt, si, tos); #endif - default: slog (L_CRIT, _("%s: FATAL: trying to send packet with unsupported protocol"), (const char *)si); } @@ -478,10 +515,10 @@ return false; } -void -vpn::ipv4_ev (io_watcher &w, short revents) +inline void +vpn::ipv4_ev (ev::io &w, int revents) { - if (revents & EVENT_READ) + if (revents & EV_READ) { vpn_packet *pkt = new vpn_packet; struct sockaddr_in sa; @@ -519,10 +556,10 @@ } #if ENABLE_ICMP -void -vpn::icmpv4_ev (io_watcher &w, short revents) +inline void +vpn::icmpv4_ev (ev::io &w, int revents) { - if (revents & EVENT_READ) + if (revents & EV_READ) { vpn_packet *pkt = new vpn_packet; struct sockaddr_in sa; @@ -567,10 +604,10 @@ } #endif -void -vpn::udpv4_ev (io_watcher &w, short revents) +inline void +vpn::udpv4_ev (ev::io &w, int revents) { - if (revents & EVENT_READ) + if (revents & EV_READ) { vpn_packet *pkt = new vpn_packet; struct sockaddr_in sa; @@ -604,10 +641,10 @@ } } -void -vpn::tap_ev (io_watcher &w, short revents) +inline void +vpn::tap_ev (ev::io &w, int revents) { - if (revents & EVENT_READ) + if (revents & EV_READ) { /* process data */ tap_packet *pkt; @@ -646,8 +683,8 @@ abort (); } -void -vpn::event_cb (time_watcher &w) +inline void +vpn::event_cb (ev::timer &w, int) { if (events) { @@ -741,14 +778,12 @@ connectmode, conf->connectmode, (const char *)si, (int)prot_minor); slog (L_NOTICE, _(" ictx/octx %08lx/%08lx / oseqno %d / retry_cnt %d"), (long)ictx, (long)octx, (int)oseqno, (int)retry_cnt); - slog (L_NOTICE, _(" establish_conn %ld / rekey %ld / keepalive %ld"), - (long)(establish_connection.at), (long)(rekey.at), (long)(keepalive.at)); } void vpn::dump_status () { - slog (L_NOTICE, _("BEGIN status dump (%ld)"), (long)NOW); + slog (L_NOTICE, _("BEGIN status dump (%ld)"), (long)ev_now ()); for (conns_vector::iterator c = conns.begin (); c != conns.end (); ++c) (*c)->dump_status (); @@ -757,20 +792,20 @@ } vpn::vpn (void) -: event (this, &vpn::event_cb) -, udpv4_ev_watcher (this, &vpn::udpv4_ev) -, ipv4_ev_watcher (this, &vpn::ipv4_ev) +{ + event .set (this); + udpv4_ev_watcher .set (this); + ipv4_ev_watcher .set (this); #if ENABLE_TCP -, tcpv4_ev_watcher (this, &vpn::tcpv4_ev) + tcpv4_ev_watcher .set (this); #endif #if ENABLE_ICMP -, icmpv4_ev_watcher(this, &vpn::icmpv4_ev) + icmpv4_ev_watcher.set (this); #endif #if ENABLE_DNS -, dnsv4_ev_watcher (this, &vpn::dnsv4_ev) + dnsv4_ev_watcher .set (this); #endif -, tap_ev_watcher (this, &vpn::tap_ev) -{ + tap_ev_watcher .set (this); } vpn::~vpn ()