123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171 |
- /* 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 <https://www.gnu.org/licenses/>.
- */
- #include "interface/Iface.h"
- #include "memory/Allocator.h"
- #include "util/Identity.h"
- #include "net/TUNAdapter.h"
- #include "wire/DataHeader.h"
- #include "wire/RouteHeader.h"
- #include "wire/Headers.h"
- #include "interface/tuntap/TUNMessageType.h"
- #include "wire/Ethernet.h"
- #include "crypto/AddressCalc.h"
- #include "util/Defined.h"
- #include "util/AddrTools.h"
- #include "wire/Error.h"
- struct TUNAdapter_pvt
- {
- struct TUNAdapter pub;
- struct Log* log;
- uint8_t myIp6[16];
- Identity
- };
- static Iface_DEFUN incomingFromTunIf(Message_t* msg, struct Iface* tunIf)
- {
- struct TUNAdapter_pvt* ud = Identity_containerOf(tunIf, struct TUNAdapter_pvt, pub.tunIf);
- uint16_t ethertype = -1;
- Err(TUNMessageType_pop(ðertype, msg));
- int version = Headers_getIpVersion(Message_bytes(msg));
- if ((ethertype == Ethernet_TYPE_IP4 && version != 4)
- || (ethertype == Ethernet_TYPE_IP6 && version != 6))
- {
- Log_debug(ud->log, "DROP packet because ip version [%d] "
- "doesn't match ethertype [%u].", version, Endian_bigEndianToHost16(ethertype));
- return Error(msg, "INVALID");
- }
- if (ethertype == Ethernet_TYPE_IP4) {
- return Iface_next(&ud->pub.ipTunnelIf, msg);
- }
- if (ethertype != Ethernet_TYPE_IP6) {
- Log_debug(ud->log, "DROP packet unknown ethertype [%u]",
- Endian_bigEndianToHost16(ethertype));
- return Error(msg, "INVALID");
- }
- if (Message_getLength(msg) < Headers_IP6Header_SIZE) {
- Log_debug(ud->log, "DROP runt");
- return Error(msg, "RUNT");
- }
- struct Headers_IP6Header* header = (struct Headers_IP6Header*) Message_bytes(msg);
- if (!AddressCalc_validAddress(header->destinationAddr)) {
- return Iface_next(&ud->pub.ipTunnelIf, msg);
- }
- if (Bits_memcmp(header->sourceAddr, ud->myIp6, 16)) {
- if (Defined(Log_DEBUG)) {
- uint8_t expectedSource[40];
- AddrTools_printIp(expectedSource, ud->myIp6);
- uint8_t packetSource[40];
- AddrTools_printIp(packetSource, header->sourceAddr);
- Log_debug(ud->log,
- "DROP packet from [%s] because all messages must have source address [%s]",
- packetSource, expectedSource);
- }
- return Error(msg, "INVALID");
- }
- if (!Bits_memcmp(header->destinationAddr, ud->myIp6, 16)) {
- // I'm Gonna Sit Right Down and Write Myself a Letter
- Err(TUNMessageType_push(msg, ethertype));
- return Iface_next(tunIf, msg);
- }
- // first move the dest addr to the right place.
- #pragma GCC diagnostic push
- #ifdef __clang__
- #pragma GCC diagnostic ignored "-Wfortify-source"
- #endif
- Bits_memmove(header->destinationAddr - DataHeader_SIZE, header->destinationAddr, 16);
- #pragma GCC diagnostic pop
- Err(Message_eshift(msg, DataHeader_SIZE + RouteHeader_SIZE - Headers_IP6Header_SIZE));
- struct RouteHeader* rh = (struct RouteHeader*) Message_bytes(msg);
- struct DataHeader* dh = (struct DataHeader*) &rh[1];
- Bits_memset(dh, 0, DataHeader_SIZE);
- DataHeader_setContentType(dh, header->nextHeader);
- DataHeader_setVersion(dh, DataHeader_CURRENT_VERSION);
- // Other than the ipv6 addr at the end, everything is zeros right down the line.
- Bits_memset(rh, 0, RouteHeader_SIZE - 16);
- return Iface_next(&ud->pub.upperDistributorIf, msg);
- }
- static Iface_DEFUN sendToTunIf(Message_t* msg, struct TUNAdapter_pvt* ud)
- {
- if (!ud->pub.tunIf.connectedIf) {
- Log_debug(ud->log, "DROP message for tun because no device is defined");
- // Nothing inherently wrong with this message
- return NULL;
- }
- return Iface_next(&ud->pub.tunIf, msg);
- }
- static Iface_DEFUN incomingFromIpTunnelIf(Message_t* msg, struct Iface* ipTunnelIf)
- {
- struct TUNAdapter_pvt* ud =
- Identity_containerOf(ipTunnelIf, struct TUNAdapter_pvt, pub.ipTunnelIf);
- return sendToTunIf(msg, ud);
- }
- static Iface_DEFUN incomingFromUpperDistributorIf(Message_t* msg,
- struct Iface* upperDistributorIf)
- {
- struct TUNAdapter_pvt* ud =
- Identity_containerOf(upperDistributorIf, struct TUNAdapter_pvt, pub.upperDistributorIf);
- Assert_true(Message_getLength(msg) >= RouteHeader_SIZE + DataHeader_SIZE);
- struct RouteHeader* hdr = (struct RouteHeader*) Message_bytes(msg);
- struct DataHeader* dh = (struct DataHeader*) &hdr[1];
- enum ContentType type = DataHeader_getContentType(dh);
- Assert_true(type <= ContentType_IP6_MAX);
- // Shift ip address into destination slot.
- #pragma GCC diagnostic push
- #ifdef __clang__
- #pragma GCC diagnostic ignored "-Wfortify-source"
- #endif
- Bits_memmove(hdr->ip6 + DataHeader_SIZE - 16, hdr->ip6, 16);
- #pragma GCC diagnostic pop
- // put my address as destination.
- Bits_memcpy(&hdr->ip6[DataHeader_SIZE], ud->myIp6, 16);
- Err(Message_eshift(msg, Headers_IP6Header_SIZE - DataHeader_SIZE - RouteHeader_SIZE));
- struct Headers_IP6Header* ip6 = (struct Headers_IP6Header*) Message_bytes(msg);
- Bits_memset(ip6, 0, Headers_IP6Header_SIZE - 32);
- Headers_setIpVersion(ip6);
- ip6->payloadLength_be = Endian_bigEndianToHost16(Message_getLength(msg) - Headers_IP6Header_SIZE);
- ip6->nextHeader = type;
- ip6->hopLimit = 42;
- Err(TUNMessageType_push(msg, Ethernet_TYPE_IP6));
- return sendToTunIf(msg, ud);
- }
- struct TUNAdapter* TUNAdapter_new(struct Allocator* allocator, struct Log* log, uint8_t myIp6[16])
- {
- struct Allocator* alloc = Allocator_child(allocator);
- struct TUNAdapter_pvt* out = Allocator_calloc(alloc, sizeof(struct TUNAdapter_pvt), 1);
- out->pub.tunIf.send = incomingFromTunIf;
- out->pub.ipTunnelIf.send = incomingFromIpTunnelIf;
- out->pub.upperDistributorIf.send = incomingFromUpperDistributorIf;
- out->log = log;
- Identity_set(out);
- Bits_memcpy(out->myIp6, myIp6, 16);
- return &out->pub;
- }
|