--- gvpe/src/vpn.C 2003/04/02 03:25:17 1.1 +++ gvpe/src/vpn.C 2003/04/02 05:15:00 1.2 @@ -40,9 +40,16 @@ #include "util.h" #include "vpn.h" +#if ENABLE_TCP +# include +# include +# include +# include +#endif + ///////////////////////////////////////////////////////////////////////////// -const char *vpn::script_if_up (int) +const char *vpn::script_if_up () { // the tunnel device mtu should be the physical mtu - overhead // the tricky part is rounding to the cipher key blocksize @@ -73,10 +80,6 @@ int vpn::setup () { - sockinfo si; - - si.set (THISNODE); - udpv4_fd = -1; if (THISNODE->protocols & PROT_UDPv4) @@ -86,9 +89,11 @@ if (udpv4_fd < 0) return -1; + sockinfo si (THISNODE, PROT_UDPv4); + if (bind (udpv4_fd, si.sav4 (), si.salenv4 ())) { - slog (L_ERR, _("can't bind udpv4 to %s: %s"), (const char *)si, strerror (errno)); + slog (L_ERR, _("can't bind udpv4 on %s: %s"), (const char *)si, strerror (errno)); exit (1); } @@ -119,9 +124,11 @@ if (ipv4_fd < 0) return -1; + sockinfo si (THISNODE, PROT_IPv4); + if (bind (ipv4_fd, si.sav4 (), si.salenv4 ())) { - slog (L_ERR, _("can't bind ipv4 socket to %s: %s"), (const char *)si, strerror (errno)); + slog (L_ERR, _("can't bind ipv4 socket on %s: %s"), (const char *)si, strerror (errno)); exit (1); } @@ -138,6 +145,38 @@ ipv4_ev_watcher.start (ipv4_fd, POLLIN); } +#if ENABLE_TCP + if (THISNODE->protocols & PROT_TCPv4) + { + tcpv4_fd = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); + + if (tcpv4_fd < 0) + return -1; + + sockinfo si (THISNODE, PROT_TCPv4); + + if (bind (tcpv4_fd, si.sav4 (), si.salenv4 ())) + { + slog (L_ERR, _("can't bind tcpv4 on %s: %s"), (const char *)si, strerror (errno)); + exit (1); + } + + if (listen (tcpv4_fd, 5)) + { + slog (L_ERR, _("can't listen tcpv4 on %s: %s"), (const char *)si, strerror (errno)); + exit (1); + } + + // standard daemon practise... + { + int oval = 1; + setsockopt (tcpv4_fd, SOL_SOCKET, SO_REUSEADDR, &oval, sizeof oval); + } + + tcpv4_accept_watcher.start (tcpv4_fd, POLLIN); + } +#endif + tap = new tap_device (); if (!tap) //D this, of course, never catches { @@ -202,7 +241,7 @@ } void -vpn::udpv4_ev (short revents) +vpn::udpv4_ev (int fd, short revents) { if (revents & (POLLIN | POLLERR)) { @@ -211,7 +250,7 @@ socklen_t sa_len = sizeof (sa); int len; - len = recvfrom (udpv4_fd, &((*pkt)[0]), MAXSIZE, 0, (sockaddr *)&sa, &sa_len); + len = recvfrom (fd, &((*pkt)[0]), MAXSIZE, 0, (sockaddr *)&sa, &sa_len); sockinfo si(sa); @@ -245,7 +284,7 @@ } void -vpn::ipv4_ev (short revents) +vpn::ipv4_ev (int fd, short revents) { if (revents & (POLLIN | POLLERR)) { @@ -254,7 +293,7 @@ socklen_t sa_len = sizeof (sa); int len; - len = recvfrom (ipv4_fd, &((*pkt)[0]), MAXSIZE, 0, (sockaddr *)&sa, &sa_len); + len = recvfrom (fd, &((*pkt)[0]), MAXSIZE, 0, (sockaddr *)&sa, &sa_len); sockinfo si(sa, PROT_IPv4); @@ -291,8 +330,145 @@ } } +#if ENABLE_TCP + +struct tcp_info { + int fd; + bool ok; + io_watcher r; + + tcp_info (vpn *v) + : r(v, &vpn::tcpv4_ev) + { + fd = -1; + } + + ~tcp_info () { close (fd); } +}; + +typedef map tcp_si_map; +typedef map tcp_fd_map; // unneecssary if iom would be cooler +static tcp_si_map tcp_si; +static tcp_fd_map tcp_fd; + +void +vpn::send_tcpv4_packet (vpn_packet *pkt, const sockinfo &si, int tos) +{ + tcp_si_map::iterator info = tcp_si.find (si); + + if (info == tcp_si.end ()) + { + // woaw, the first lost packet ;) + tcp_info *i = new tcp_info (this); + + i->ok = false; + i->fd = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); + + if (i->fd >= 0) + { + fcntl (i->fd, F_SETFL, O_NONBLOCK); + + if (connect (i->fd, si.sav4 (), si.salenv4 ()) >= 0 + || errno == EINPROGRESS) + { + tcp_si.insert (tcp_si_map::value_type (si, i)); + tcp_fd.insert (tcp_fd_map::value_type (i->fd, i)); + return; + } + + delete i; + } + } + else + { + tcp_info *i = info->second; + + if (i->ok) + { + setsockopt (i->fd, SOL_IP, IP_TOS, &tos, sizeof tos); + + if (write (i->fd, (void *)pkt, pkt->len + sizeof (u32)) != pkt->len + sizeof (u32)) + { + // error, close socket, forget it and retry immediately + tcp_si.erase (info); + tcp_fd.erase (i->fd); + delete i; + + // tail recursion is... better than goto(?) + send_tcpv4_packet (pkt, si, tos); + } + } + } + +#if 0 + setsockopt (udpv4_fd, SOL_IP, IP_TOS, &tos, sizeof tos); + sendto (udpv4_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ()); +#endif +} + +void +vpn::tcpv4_accept (int fd, short revents) +{ + if (revents & (POLLIN | POLLERR)) + { + struct sockaddr_in sa; + socklen_t sa_len = sizeof (sa); + int len; + + fd = accept (fd, (sockaddr *)&sa, &sa_len); + + if (fd >= 0) + { + fcntl (fd, F_SETFL, O_NONBLOCK); + + sockinfo si(sa, PROT_TCPv4); + tcp_info *i = new tcp_info (this); + + i->fd = fd; + i->ok = true; + i->r.start (fd, POLLIN); + + tcp_si.insert (tcp_si_map::value_type (si, i)); + tcp_fd.insert (tcp_fd_map::value_type (fd, i)); + } + } +} + void -vpn::tap_ev (short revents) +vpn::tcpv4_ev (int fd, short revents) +{ + if (revents & (POLLIN | POLLERR)) + { + tcp_fd_map::iterator info = tcp_fd.find (fd); + + if (info != tcp_fd.end ()) + { + tcp_info *i = info->second; + + if (!i->ok) // not yet established + { + i->ok = true; + fcntl (i->fd, F_SETFL, 0); + } + + u32 len; + + if (sizeof (len) == read (fd, &len, sizeof (len))) + { + slog (L_ERR, "%d bytes received\n", len); + } + + //tcp_si.erase (i); + tcp_fd.erase (fd); + delete i; + } + } +} + +#endif + +void +vpn::tap_ev (int fd, short revents) { if (revents & POLLIN) { @@ -470,10 +646,13 @@ } vpn::vpn (void) -: udpv4_ev_watcher(this, &vpn::udpv4_ev) -, ipv4_ev_watcher(this, &vpn::ipv4_ev) -, tap_ev_watcher(this, &vpn::tap_ev) -, event(this, &vpn::event_cb) +: event(this, &vpn::event_cb) +, udpv4_ev_watcher(this, &vpn::udpv4_ev) +, ipv4_ev_watcher (this, &vpn::ipv4_ev) +, tap_ev_watcher (this, &vpn::tap_ev) +#if ENABLE_TCP +, tcpv4_accept_watcher(this, &vpn::tcpv4_accept) +#endif { }