--- gvpe/src/vpn.C 2011/09/16 18:01:27 1.60 +++ gvpe/src/vpn.C 2011/12/17 22:05:34 1.62 @@ -149,6 +149,42 @@ { int success = 0; +#if 1//D2 + ipv42_tos = -1; + ipv42_fd = -1; + + if (THISNODE->protocols & PROT_IPv42 && ::conf.ip_proto) + { + ipv42_fd = setup_socket (PROT_IPv42, PF_INET, SOCK_RAW, ::conf.ip2_proto); + + if (ipv42_fd < 0) + return -1; + +#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 + // fragment for me sometimes. + { + int oval = IP_PMTUDISC_DONT; + setsockopt (ipv42_fd, SOL_IP, IP_MTU_DISCOVER, &oval, sizeof oval); + } +#endif + + sockinfo si (THISNODE, PROT_IPv42); + + if (bind (ipv42_fd, si.sav4 (), si.salenv4 ())) + { + slog (L_ERR, _("can't bind ipv42 socket on %s: %s, exiting."), (const char *)si, strerror (errno)); + return -1; + } + + ipv42_ev_watcher.start (ipv42_fd, EV_READ); + ++success; + } + else + THISNODE->protocols &= ~PROT_IPv42; +#endif + ipv4_tos = -1; ipv4_fd = -1; @@ -402,6 +438,17 @@ return true; } +#if 1 //D +bool +vpn::send_ipv42_packet (vpn_packet *pkt, const sockinfo &si, int tos) +{ + set_tos (ipv42_fd, ipv42_tos, tos); + sendto (ipv42_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ()); + + return true; +} +#endif + static u16 ipv4_checksum (u16 *data, unsigned int len) { @@ -486,9 +533,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]; @@ -517,6 +561,11 @@ { switch (si.prot) { +#if 1//D2 + case PROT_IPv42: + return send_ipv42_packet (pkt, si, tos); +#endif + case PROT_IPv4: return send_ipv4_packet (pkt, si, tos); @@ -542,6 +591,48 @@ return false; } +#if 1//D2 +inline void +vpn::ipv42_ev (ev::io &w, int revents) +{ + if (revents & EV_READ) + { + vpn_packet *pkt = new vpn_packet; + struct sockaddr_in sa; + socklen_t sa_len = sizeof (sa); + int len; + + len = recvfrom (w.fd, &((*pkt)[0]), MAXSIZE, 0, (sockaddr *)&sa, &sa_len); + + sockinfo si(sa, PROT_IPv42); + + if (len > 0) + { + pkt->len = len; + + // raw sockets deliver the ipv4 header, but don't expect it on sends + pkt->skip_hdr (pkt->ipv4_hdr_len ()); + + recv_vpn_packet (pkt, si); + } + else + { + // probably ECONNRESET or somesuch + slog (L_DEBUG, _("%s: %s."), (const char *)si, strerror (errno)); + } + + delete pkt; + } + else + { + slog (L_ERR, + _("FATAL: unknown revents %08x in socket, exiting.\n"), + revents); + exit (EXIT_FAILURE); + } +} +#endif + inline void vpn::ipv4_ev (ev::io &w, int revents) { @@ -883,6 +974,9 @@ event .set (this); udpv4_ev_watcher .set (this); ipv4_ev_watcher .set (this); +#if 1//D2 + ipv42_ev_watcher .set (this); +#endif #if ENABLE_TCP tcpv4_ev_watcher .set (this); #endif