--- gvpe/src/vpn.C 2008/08/10 01:34:36 1.49 +++ gvpe/src/vpn.C 2011/02/08 23:11:36 1.56 @@ -122,21 +122,43 @@ } int +vpn::setup_socket (u8 prot, int family, int type, int proto) +{ + int fd = socket (family, type, proto); + + if (fd < 0) + { + slog (L_ERR, _("unable to create %s socket: %s."), strprotocol (prot), strerror (errno)); + return fd; + } + + fcntl (fd, F_SETFL, O_NONBLOCK); + fcntl (fd, F_SETFD, FD_CLOEXEC); + +#ifdef SO_MARK + if (::conf.nfmark) + if (setsockopt (fd, SOL_SOCKET, SO_MARK, &::conf.nfmark, sizeof ::conf.nfmark)) + slog (L_WARN, _("unable to set nfmark on %s socket: %s"), strprotocol (prot), strerror (errno)); +#endif + + return fd; +} + +int vpn::setup () { + int success = 0; + ipv4_tos = -1; ipv4_fd = -1; if (THISNODE->protocols & PROT_IPv4 && ::conf.ip_proto) { - ipv4_fd = socket (PF_INET, SOCK_RAW, ::conf.ip_proto); + ipv4_fd = setup_socket (PROT_IPv4, PF_INET, SOCK_RAW, ::conf.ip_proto); if (ipv4_fd < 0) 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 // nor do I fragment myself. Linux still sets DF and doesn't @@ -152,25 +174,25 @@ if (bind (ipv4_fd, si.sav4 (), si.salenv4 ())) { slog (L_ERR, _("can't bind ipv4 socket on %s: %s, exiting."), (const char *)si, strerror (errno)); - exit (EXIT_FAILURE); + return -1; } ipv4_ev_watcher.start (ipv4_fd, EV_READ); + ++success; } + else + THISNODE->protocols &= ~PROT_IPv4; udpv4_tos = -1; udpv4_fd = -1; if (THISNODE->protocols & PROT_UDPv4 && THISNODE->udp_port) { - udpv4_fd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP); + udpv4_fd = setup_socket (PROT_UDPv4, PF_INET, SOCK_DGRAM, IPPROTO_UDP); if (udpv4_fd < 0) return -1; - fcntl (udpv4_fd, F_SETFL, O_NONBLOCK); - fcntl (udpv4_fd, F_SETFD, FD_CLOEXEC); - // standard daemon practise... { int oval = 1; @@ -192,11 +214,14 @@ if (bind (udpv4_fd, si.sav4 (), si.salenv4 ())) { slog (L_ERR, _("can't bind udpv4 on %s: %s, exiting."), (const char *)si, strerror (errno)); - exit (EXIT_FAILURE); + return -1; } udpv4_ev_watcher.start (udpv4_fd, EV_READ); + ++success; } + else + THISNODE->protocols &= ~PROT_UDPv4; icmpv4_tos = -1; icmpv4_fd = -1; @@ -204,14 +229,11 @@ #if ENABLE_ICMP if (THISNODE->protocols & PROT_ICMPv4) { - icmpv4_fd = socket (PF_INET, SOCK_RAW, IPPROTO_ICMP); + icmpv4_fd = setup_socket (PROT_ICMPv4, PF_INET, SOCK_RAW, IPPROTO_ICMP); if (icmpv4_fd < 0) return -1; - fcntl (icmpv4_fd, F_SETFL, O_NONBLOCK); - fcntl (icmpv4_fd, F_SETFD, FD_CLOEXEC); - #ifdef ICMP_FILTER { icmp_filter oval; @@ -238,10 +260,11 @@ if (bind (icmpv4_fd, si.sav4 (), si.salenv4 ())) { slog (L_ERR, _("can't bind icmpv4 on %s: %s, exiting."), (const char *)si, strerror (errno)); - exit (EXIT_FAILURE); + return -1; } icmpv4_ev_watcher.start (icmpv4_fd, EV_READ); + ++success; } #endif @@ -250,14 +273,11 @@ #if ENABLE_TCP if (THISNODE->protocols & PROT_TCPv4 && THISNODE->tcp_port) { - tcpv4_fd = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); + tcpv4_fd = setup_socket (PROT_TCPv4, PF_INET, SOCK_STREAM, IPPROTO_TCP); if (tcpv4_fd < 0) return -1; - fcntl (tcpv4_fd, F_SETFL, O_NONBLOCK); - fcntl (tcpv4_fd, F_SETFD, FD_CLOEXEC); - // standard daemon practise... { int oval = 1; @@ -269,17 +289,20 @@ if (bind (tcpv4_fd, si.sav4 (), si.salenv4 ())) { slog (L_ERR, _("can't bind tcpv4 on %s: %s, exiting."), (const char *)si, strerror (errno)); - exit (EXIT_FAILURE); + return -1; } if (listen (tcpv4_fd, 5)) { slog (L_ERR, _("can't listen tcpv4 on %s: %s, exiting."), (const char *)si, strerror (errno)); - exit (EXIT_FAILURE); + return -1; } tcpv4_ev_watcher.start (tcpv4_fd, EV_READ); + ++success; } + else + THISNODE->protocols &= ~PROT_TCPv4; #endif dnsv4_tos = -1; @@ -290,14 +313,11 @@ { dns_forwarder.set (::conf.dns_forw_host, ::conf.dns_forw_port, PROT_DNSv4); - dnsv4_fd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP); + dnsv4_fd = setup_socket (PROT_DNSv4, PF_INET, SOCK_DGRAM, IPPROTO_UDP); 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 @@ -321,15 +341,22 @@ if (bind (dnsv4_fd, si.sav4 (), si.salenv4 ())) { slog (L_ERR, _("can't bind dnsv4 on %s: %s, exiting."), (const char *)si, strerror (errno)); - exit (EXIT_FAILURE); + return -1; } dnsv4_ev_watcher.start (dnsv4_fd, EV_READ); + ++success; } #endif ///////////////////////////////////////////////////////////////////////////// + if (!success) + { + slog (L_ERR, _("no protocols enabled.")); + return -1; + } + reconnect_all (); ///////////////////////////////////////////////////////////////////////////// @@ -337,8 +364,8 @@ tap = new tap_device (); if (!tap) //D this, of course, never catches { - slog (L_ERR, _("cannot create network interface '%s', exiting."), conf.ifname); - exit (EXIT_FAILURE); + slog (L_ERR, _("cannot create network interface '%s'."), conf.ifname); + return -1; } fcntl (tap->fd, F_SETFD, FD_CLOEXEC); @@ -349,16 +376,16 @@ if (tap->if_up () && !run_script (cb, true)) { - slog (L_ERR, _("interface initialization command '%s' failed, exiting."), + slog (L_ERR, _("interface initialization command '%s' failed."), tap->if_up ()); - exit (EXIT_FAILURE); + return -1; } cb.set (this); if (!run_script (cb, true)) { - slog (L_ERR, _("if-up command execution failed, exiting.")); - exit (EXIT_FAILURE); + slog (L_ERR, _("if-up command execution failed.")); + return -1; } tap_ev_watcher.start (tap->fd, EV_READ); @@ -726,16 +753,15 @@ connection_init (); - for (configuration::node_vector::iterator i = conf.nodes.begin (); - i != conf.nodes.end (); ++i) - { - connection *conn = new connection (this, *i); - conns.push_back (conn); - conn->establish_connection (); - } + for (configuration::node_vector::iterator i = conf.nodes.begin (); i != conf.nodes.end (); ++i) + conns.push_back (new connection (this, *i)); + + for (conns_vector::iterator c = conns.begin (); c != conns.end (); ++c) + (*c)->establish_connection (); } -bool vpn::can_direct (conf_node *src, conf_node *dst) const +bool +vpn::can_direct (conf_node *src, conf_node *dst) const { return src != dst && src->may_direct (dst) @@ -746,11 +772,13 @@ // only works for indirect and routed connections: find a router // from THISNODE to dst -connection *vpn::find_router_for (const connection *dst) +connection * +vpn::find_router_for (const connection *dst) { connection *router = 0; - // first try to find a router with a direct connection + // first try to find a router with a direct connection, route there + // regardless of any other considerations. { u32 prio = 1; @@ -760,16 +788,11 @@ if (c->conf->routerprio > prio && c->conf != THISNODE - && c != dst - && can_direct (c->conf, dst->conf)) + && can_direct (c->conf, dst->conf) + && c->ictx && c->octx) { - if (c->ictx && c->octx) - { - prio = c->conf->routerprio; - router = c; - } - else - c->establish_connection (); + prio = c->conf->routerprio; + router = c; } } } @@ -777,33 +800,30 @@ if (router) return router; - // second try find the router with the highest priority higher than ours + // second try find the router with the highest priority, higher than ours { - u32 prio = 1; + u32 prio = THISNODE->routerprio ? THISNODE->routerprio : 1; for (conns_vector::iterator i = conns.begin (); i != conns.end (); ++i) { connection *c = *i; if (c->conf->routerprio > prio - && c->conf->routerprio > THISNODE->routerprio && c != dst - && c->conf != THISNODE) + && c->conf != THISNODE + && c->ictx && c->octx) { - if (c->ictx && c->octx) - { - prio = c->conf->routerprio; - router = c; - } - else - c->establish_connection (); + prio = c->conf->routerprio; + router = c; } } } + return router; } -void vpn::connection_established (connection *c) +void +vpn::connection_established (connection *c) { for (conns_vector::iterator i = conns.begin (); i != conns.end (); ++i) { @@ -821,18 +841,20 @@ } } -void vpn::send_connect_request (int id) +void +vpn::send_connect_request (connection *c) { - connection *c = find_router_for (conns[id]); + connection *r = find_router_for (c); - if (c) + if (r) { - slog (L_TRACE, _("%s: no way to connect, sending mediated connection request via %s."), - conns[id]->conf->nodename, c->conf->nodename); - c->send_connect_request (id); + slog (L_TRACE, _("%s: no address known, sending mediated connection request via %s."), + c->conf->nodename, r->conf->nodename); + r->send_connect_request (c->conf->id); } else - slog (L_DEBUG, _("%s: no way to connect and no router found: unable to connect."), conns[id]->conf->nodename); + slog (L_DEBUG, _("%s: no way to connect and no router found: unable to connect at this time."), + c->conf->nodename); } void