/* vim: set expandtab ts=4 sw=4: */ /* * You may redistribute this program 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 . */ #include "memory/Allocator.h" #include "net/ConverterV15.h" #include "util/Identity.h" #include "wire/SwitchHeader.h" #include "wire/DataHeader.h" #include "net/SessionManager.h" #include "wire/ContentType.h" #include "wire/Headers.h" #include "util/Checksum.h" #include "wire/RouteHeader.h" //#include "util/Hex.h" struct ConverterV15_pvt { struct ConverterV15 pub; struct SessionManager* sm; uint8_t myIp6[16]; struct Log* log; Identity }; /** * Incoming packet with a SessionManager header followed by a ContentHeader and then whatever * content. */ static Iface_DEFUN incomingFromUpperDistributorIf(struct Message* msg, struct Iface* upperDistributorIf) { struct ConverterV15_pvt* conv = Identity_containerOf(upperDistributorIf, struct ConverterV15_pvt, pub.upperDistributorIf); Assert_true(msg->length >= DataHeader_SIZE + RouteHeader_SIZE); struct RouteHeader* hdr = (struct RouteHeader*) msg->bytes; struct SessionManager_Session* sess = SessionManager_sessionForIp6(hdr->ip6, conv->sm); if (hdr->version_be && Endian_bigEndianToHost32(hdr->version_be) < 16) { // definitely old } else if (!hdr->version_be && sess && sess->version && sess->version < 16) { // session thinks it's old } else { // nothing is known about a node, fuckit, assume it's new ! return Iface_next(&conv->pub.sessionManagerIf, msg); } struct DataHeader* dh = (struct DataHeader*) &hdr[1]; enum ContentType type = DataHeader_getContentType(dh); if (type > 257) { Log_debug(conv->log, "DROP unconvertible type [%d]", type); return NULL; } // My fears, come alive, // in this place where I once died // demons dreamin', // Knowing I, // I just needed to // _RE_ALIGN_ Message_shift(msg, -(DataHeader_SIZE + RouteHeader_SIZE), NULL); if (type == ContentType_CJDHT) { // push a udp header and then an ip header and then checksum the udp Message_shift(msg, Headers_UDPHeader_SIZE, NULL); } if (type != ContentType_IPTUN) { Message_shift(msg, Headers_IP6Header_SIZE, NULL); } Message_shift(msg, RouteHeader_SIZE, NULL); Bits_memmove(msg->bytes, hdr, RouteHeader_SIZE); hdr = (struct RouteHeader*) msg->bytes; if (type == ContentType_IPTUN) { return Iface_next(&conv->pub.sessionManagerIf, msg); } struct Headers_IP6Header* ip6 = (struct Headers_IP6Header*) &hdr[1]; Bits_memset(ip6, 0, Headers_IP6Header_SIZE); Headers_setIpVersion(ip6); ip6->hopLimit = 42; ip6->nextHeader = type; ip6->payloadLength_be = Endian_hostToBigEndian16( msg->length - RouteHeader_SIZE - Headers_IP6Header_SIZE); Bits_memcpyConst(ip6->destinationAddr, hdr->ip6, 16); Bits_memcpyConst(ip6->sourceAddr, conv->myIp6, 16); if (type == ContentType_CJDHT) { struct Headers_UDPHeader* udp = (struct Headers_UDPHeader*) &ip6[1]; ip6->nextHeader = 17; ip6->hopLimit = 0; udp->srcPort_be = 0; udp->destPort_be = 0; udp->length_be = Endian_hostToBigEndian16(msg->length - RouteHeader_SIZE - Headers_IP6Header_SIZE - Headers_UDPHeader_SIZE); udp->checksum_be = 0; udp->checksum_be = Checksum_udpIp6(ip6->sourceAddr, (uint8_t*) udp, msg->length - RouteHeader_SIZE - Headers_IP6Header_SIZE); //Log_debug(conv->log, "Converted CJDHT->v15"); } //Log_debug(conv->log, "send [%s]", Hex_print(ip6, 32, msg->alloc)); return Iface_next(&conv->pub.sessionManagerIf, msg); } //// --------------- Incoming, convert v15 to v16 --------------- //// #define tryConvertDHT_OVERHEAD \ (RouteHeader_SIZE + Headers_IP6Header_SIZE + Headers_UDPHeader_SIZE) static inline bool tryConvertDHT(struct Message* msg) { if (msg->length < tryConvertDHT_OVERHEAD) { return false; } struct RouteHeader* bih = (struct RouteHeader*) msg->bytes; struct Headers_IP6Header* ip6 = (struct Headers_IP6Header*) &bih[1]; struct Headers_UDPHeader* udp = (struct Headers_UDPHeader*) &ip6[1]; if (udp->srcPort_be || udp->destPort_be) { return false; } Message_shift(msg, -tryConvertDHT_OVERHEAD, NULL); struct DataHeader dh = { .contentType_be = Endian_hostToBigEndian16(ContentType_CJDHT), .versionAndFlags = DataHeader_CURRENT_VERSION << 4 }; Message_push(msg, &dh, DataHeader_SIZE, NULL); Message_shift(msg, RouteHeader_SIZE, NULL); Bits_memmoveConst(msg->bytes, bih, RouteHeader_SIZE); return true; } /** * Incoming packet with a SessionManager header and under that either an ipv6 or ipv4 header * depending on whether it's destine for TUN/DHT or IpTunnel. */ static Iface_DEFUN incomingFromSessionManagerIf(struct Message* msg, struct Iface* sessionManagerIf) { struct ConverterV15_pvt* conv = Identity_containerOf(sessionManagerIf, struct ConverterV15_pvt, pub.sessionManagerIf); if (msg->length < RouteHeader_SIZE + DataHeader_SIZE) { Log_debug(conv->log, "DROP runt"); return NULL; } struct RouteHeader* bih = (struct RouteHeader*) msg->bytes; uint8_t* ipPtr = (uint8_t*) &bih[1]; //Log_debug(conv->log, "recv [%s]", Hex_print(ipPtr, 32, msg->alloc)); int ipVer = Headers_getIpVersion(ipPtr); if (ipVer == DataHeader_CURRENT_VERSION) { return Iface_next(&conv->pub.upperDistributorIf, msg); } if (ipVer == 0) { if (msg->length < RouteHeader_SIZE + Headers_IP6Header_SIZE) { Log_debug(conv->log, "DROP runt"); return NULL; } struct Headers_IP6Header* ip6 = (struct Headers_IP6Header*) ipPtr; if (ip6->sourceAddr[0] == 0xfc && ip6->destinationAddr[0] == 0xfc) { if (tryConvertDHT(msg)) { return Iface_next(&conv->pub.upperDistributorIf, msg); } } } else if (ipVer == 6) { if (msg->length < RouteHeader_SIZE + Headers_IP6Header_SIZE) { Log_debug(conv->log, "DROP runt"); return NULL; } struct Headers_IP6Header* ip6 = (struct Headers_IP6Header*) ipPtr; if (ip6->sourceAddr[0] == 0xfc && ip6->destinationAddr[0] == 0xfc) { Message_pop(msg, NULL, RouteHeader_SIZE + Headers_IP6Header_SIZE, NULL); struct DataHeader dh = { .contentType_be = Endian_hostToBigEndian16(ip6->nextHeader), .versionAndFlags = DataHeader_CURRENT_VERSION << 4 }; Message_push(msg, &dh, DataHeader_SIZE, NULL); Message_shift(msg, RouteHeader_SIZE, NULL); Bits_memmoveConst(msg->bytes, bih, RouteHeader_SIZE); return Iface_next(&conv->pub.upperDistributorIf, msg); } } else if (ipVer != 4) { Log_debug(conv->log, "DROP unknown packet ip version"); return NULL; } Message_shift(msg, DataHeader_SIZE, NULL); Bits_memmoveConst(msg->bytes, bih, RouteHeader_SIZE); bih = (struct RouteHeader*) msg->bytes; struct DataHeader* dh = (struct DataHeader*) &bih[1]; Bits_memset(dh, 0, DataHeader_SIZE); dh->contentType_be = Endian_hostToBigEndian16(ContentType_IPTUN); dh->versionAndFlags = DataHeader_CURRENT_VERSION << 4; return Iface_next(&conv->pub.upperDistributorIf, msg); } struct ConverterV15* ConverterV15_new(struct Allocator* allocator, struct Log* log, struct SessionManager* sm, uint8_t myIp6[16]) { struct Allocator* alloc = Allocator_child(allocator); struct ConverterV15_pvt* out = Allocator_calloc(alloc, sizeof(struct ConverterV15_pvt), 1); out->pub.upperDistributorIf.send = incomingFromUpperDistributorIf; out->pub.sessionManagerIf.send = incomingFromSessionManagerIf; out->log = log; out->sm = sm; Bits_memcpyConst(out->myIp6, myIp6, 16); Identity_set(out); return &out->pub; }