static uint8_t receiveMessage(struct Message* msg, struct Interface* iface) { struct Aligner_pvt* al = Identity_check((struct Aligner_pvt*)iface->receiverContext); alignMessage(msg, al->alignmentBytes); Interface_receiveMessage(&al->pub.generic, msg); return 0; }
static uint8_t receiveMessage(struct Message* message, struct Interface* iface) { struct AddrInterfaceAdapter_pvt* context = Identity_cast((struct AddrInterfaceAdapter_pvt*) iface->receiverContext); Message_push(message, context->pub.addr, context->pub.addr->addrLen, NULL); return Interface_receiveMessage(&context->pub.generic, message); }
// Incoming message which has passed through the cryptoauth and needs to be forwarded to the switch. static uint8_t receivedAfterCryptoAuth(struct Message* msg, struct Interface* cryptoAuthIf) { struct InterfaceController_Peer* ep = Identity_check((struct InterfaceController_Peer*) cryptoAuthIf->receiverContext); struct InterfaceController_pvt* ic = ifcontrollerForPeer(ep); // nonce added by the CryptoAuth session. Message_pop(msg, NULL, 4, NULL); ep->bytesIn += msg->length; int caState = CryptoAuth_getState(cryptoAuthIf); if (ep->state < InterfaceController_PeerState_ESTABLISHED) { // EP states track CryptoAuth states... ep->state = caState; if (caState == CryptoAuth_ESTABLISHED) { moveEndpointIfNeeded(ep, ic); } else { // prevent some kinds of nasty things which could be done with packet replay. // This is checking the message switch header and will drop it unless the label // directs it to *this* router. if (msg->length < 8 || msg->bytes[7] != 1) { Log_info(ic->logger, "DROP message because CA is not established."); return Error_NONE; } else { // When a "server" gets a new connection from a "client" the router doesn't // know about that client so if the client sends a packet to the server, the // server will be unable to handle it until the client has sent inter-router // communication to the server. Here we will ping the client so when the // server gets the ping response, it will insert the client into its table // and know its version. // prevent DoS by limiting the number of times this can be called per second // limit it to 7, this will affect innocent packets but it doesn't matter much // since this is mostly just an optimization and for keeping the tests happy. if ((ep->pingCount + 1) % 7) { sendPing(ep); } } } } else if (ep->state == InterfaceController_PeerState_UNRESPONSIVE && caState == CryptoAuth_ESTABLISHED) { ep->state = InterfaceController_PeerState_ESTABLISHED; } else { ep->timeOfLastMessage = Time_currentTimeMilliseconds(ic->eventBase); } Identity_check(ep); Assert_true(!(msg->capacity % 4)); return Interface_receiveMessage(&ep->switchIf, msg); }
static uint8_t receiveMessage(struct Message* message, struct Interface* iface) { struct TUNInterface_Illumos_pvt* ctx = Identity_check((struct TUNInterface_Illumos_pvt*)iface->receiverContext); if (message->length < 4) { return Error_NONE; } Message_shift(message, 4); ((uint16_t*) message->bytes)[0] = 0; ((uint16_t*) message->bytes)[1] = ethertypeForPacketType(message->bytes[4]); return Interface_receiveMessage(&ctx->generic, message); }
static uint8_t receiveMessage(struct Message* msg, struct Interface* iface) { struct SessionManager_Session_pvt* ss = Identity_check((struct SessionManager_Session_pvt*)iface->receiverContext); // nonce added by CryptoAuth Message_pop(msg, NULL, 4, NULL); uint64_t timeOfLastIn = ss->pub.timeOfLastIn; ss->pub.timeOfLastIn = Time_currentTimeMilliseconds(ss->sm->eventBase); int prevState = ss->pub.cryptoAuthState; ss->pub.cryptoAuthState = CryptoAuth_getState(ss->pub.internal); if ((ss->pub.timeOfLastIn - timeOfLastIn) > STATE_UPDATE_TIME || prevState != ss->pub.cryptoAuthState) { stateChange(ss, timeOfLastIn, ss->pub.timeOfLastOut, prevState); } return Interface_receiveMessage(&ss->sm->iface, msg); }
int main() { struct Allocator* mainAlloc = MallocAllocator_new(1<<20); struct Log* log = FileWriterLog_new(stdout, mainAlloc); struct Random* rand = Random_new(mainAlloc, log, NULL); struct Context* ctx = Allocator_malloc(mainAlloc, sizeof(struct Context)); Identity_set(ctx); struct Interface iface = { .sendMessage = NULL }; struct Interface* fi = FramingInterface_new(4096, &iface, mainAlloc); fi->receiveMessage = messageOut; fi->receiverContext = ctx; for (int i = 0; i < CYCLES; i++) { struct Allocator* alloc = Allocator_child(mainAlloc); // max frame size must be at least 5 so that at least 1 byte of data is sent. int maxFrameSize = ( Random_uint32(rand) % (MAX_FRAME_SZ - 1) ) + 1; int maxMessageSize = ( Random_uint32(rand) % (MAX_MSG_SZ - MIN_MSG_SZ) ) + MIN_MSG_SZ; Log_debug(log, "maxFrameSize[%d] maxMessageSize[%d]", maxFrameSize, maxMessageSize); ctx->alloc = alloc; ctx->messages = NULL; ctx->messageCount = 0; ctx->currentMessage = 0; // Create one huge message, then create lots of little frames inside of it // then split it up in random places and send the sections to the framing // interface. struct Message* msg = Message_new(WORK_BUFF_SZ, 0, alloc); Assert_true(WORK_BUFF_SZ == msg->length); Random_bytes(rand, msg->bytes, msg->length); Message_shift(msg, -WORK_BUFF_SZ, NULL); for (;;) { int len = Random_uint32(rand) % maxFrameSize; if (!len) { len++; } if (msg->padding < len + 4) { break; } Message_shift(msg, len, NULL); ctx->messageCount++; ctx->messages = Allocator_realloc(alloc, ctx->messages, ctx->messageCount * sizeof(char*)); struct Message* om = ctx->messages[ctx->messageCount-1] = Message_new(len, 0, alloc); Bits_memcpy(om->bytes, msg->bytes, len); Message_push32(msg, len, NULL); } do { int nextMessageSize = Random_uint32(rand) % maxMessageSize; if (!nextMessageSize) { nextMessageSize++; } if (nextMessageSize > msg->length) { nextMessageSize = msg->length; } struct Allocator* msgAlloc = Allocator_child(alloc); struct Message* m = Message_new(nextMessageSize, 0, msgAlloc); Message_pop(msg, m->bytes, nextMessageSize, NULL); Interface_receiveMessage(&iface, m); Allocator_free(msgAlloc); } while (msg->length); Assert_true(ctx->messageCount == ctx->currentMessage); Allocator_free(alloc); } return 0; }
static uint8_t sendMessage(struct Message* message, struct Interface* iface) { struct PacketHeaderToUDPAddrInterface_pvt* context = Identity_check((struct PacketHeaderToUDPAddrInterface_pvt*) iface); struct Sockaddr_storage ss; Message_pop(message, &ss, context->pub.addr->addrLen, NULL); struct Sockaddr* addr = &ss.addr; struct Headers_UDPHeader udp; udp.srcPort_be = Endian_hostToBigEndian16(Sockaddr_getPort(context->pub.addr)); udp.destPort_be = Endian_hostToBigEndian16(Sockaddr_getPort(addr)); udp.length_be = Endian_hostToBigEndian16(message->length + Headers_UDPHeader_SIZE); udp.checksum_be = 0; Message_push(message, &udp, sizeof(struct Headers_UDPHeader), NULL); struct Headers_IP6Header ip = { .nextHeader = 17, .hopLimit = 255, }; ip.payloadLength_be = Endian_hostToBigEndian16(message->length); Headers_setIpVersion(&ip); uint8_t* addrPtr = NULL; Assert_true(Sockaddr_getAddress(addr, &addrPtr) == 16); Bits_memcpyConst(ip.destinationAddr, addrPtr, 16); Assert_true(Sockaddr_getAddress(context->pub.addr, &addrPtr) == 16); Bits_memcpyConst(ip.sourceAddr, addrPtr, 16); uint16_t checksum = Checksum_udpIp6(ip.sourceAddr, message->bytes, message->length); ((struct Headers_UDPHeader*)message->bytes)->checksum_be = checksum; Message_push(message, &ip, sizeof(struct Headers_IP6Header), NULL); return Interface_sendMessage(context->wrapped, message); } static uint8_t receiveMessage(struct Message* message, struct Interface* iface) { struct PacketHeaderToUDPAddrInterface_pvt* context = Identity_check((struct PacketHeaderToUDPAddrInterface_pvt*) iface->receiverContext); if (message->length < Headers_IP6Header_SIZE + Headers_UDPHeader_SIZE) { // runt return Error_NONE; } struct Headers_IP6Header* ip = (struct Headers_IP6Header*) message->bytes; // udp if (ip->nextHeader != 17) { return Error_NONE; } struct Allocator* alloc = Allocator_child(message->alloc); struct Sockaddr* addr = Sockaddr_clone(context->pub.addr, alloc); uint8_t* addrPtr = NULL; Assert_true(Sockaddr_getAddress(addr, &addrPtr) == 16); Bits_memcpyConst(addrPtr, ip->sourceAddr, 16); struct Headers_UDPHeader* udp = (struct Headers_UDPHeader*) (&ip[1]); Sockaddr_setPort(addr, Endian_bigEndianToHost16(udp->srcPort_be)); if (Sockaddr_getPort(context->pub.addr) != Endian_bigEndianToHost16(udp->destPort_be)) { // not the right port return Error_NONE; } Message_shift(message, -(Headers_IP6Header_SIZE + Headers_UDPHeader_SIZE), NULL); Message_push(message, addr, addr->addrLen, NULL); return Interface_receiveMessage(&context->pub.generic, message); } struct AddrInterface* PacketHeaderToUDPAddrInterface_new(struct Interface* toWrap, struct Allocator* alloc, struct Sockaddr* addr) { struct PacketHeaderToUDPAddrInterface_pvt* context = Allocator_malloc(alloc, sizeof(struct PacketHeaderToUDPAddrInterface_pvt)); Bits_memcpyConst(context, (&(struct PacketHeaderToUDPAddrInterface_pvt) { .pub = { .generic = { .sendMessage = sendMessage, .senderContext = context, .allocator = alloc } }, .wrapped = toWrap }), sizeof(struct PacketHeaderToUDPAddrInterface_pvt));
static int tryRouterSolicitation(struct Message* msg, struct Ethernet* eth, struct Headers_IP6Header* ip6, struct NDPServer_pvt* ns) { if (msg->length < NDPHeader_RouterSolicitation_SIZE) { return 0; } struct NDPHeader_RouterSolicitation* sol = (struct NDPHeader_RouterSolicitation*)msg->bytes; if (sol->oneThirtyThree != 133 || sol->zero != 0) { printf("wrong type/code for router solicitation\n"); return 0; } if (ns->pub.prefixLen < 1 || ns->pub.prefixLen > 128) { printf("address prefix not set\n"); return 0; } if (Bits_memcmp(ip6->destinationAddr, UNICAST_ADDR, 16) && Bits_memcmp(ip6->destinationAddr, ALL_ROUTERS, 16)) { printf("wrong address for router solicitation\n"); return 0; } // now we're committed. Message_shift(msg, -msg->length, NULL); // Prefix option struct NDPHeader_RouterAdvert_PrefixOpt prefix = { .three = 3, .four = 4, .bits = 0, .validLifetimeSeconds_be = 0xffffffffu, .preferredLifetimeSeconds_be = 0xffffffffu, .reservedTwo = 0 }; Bits_memcpyConst(prefix.prefix, ns->pub.advertisePrefix, 16); prefix.prefixLen = ns->pub.prefixLen; Message_push(msg, &prefix, sizeof(struct NDPHeader_RouterAdvert_PrefixOpt), NULL); // NDP message struct NDPHeader_RouterAdvert adv = { .oneThirtyFour = 134, .zero = 0, .checksum = 0, .currentHopLimit = 0, .bits = 0, .routerLifetime_be = Endian_hostToBigEndian16(10), .reachableTime_be = 0, .retransTime_be = 0 }; Message_push(msg, &adv, sizeof(struct NDPHeader_RouterAdvert), NULL); sendResponse(msg, eth, ip6, ns); return 1; } static int tryNeighborSolicitation(struct Message* msg, struct Ethernet* eth, struct Headers_IP6Header* ip6, struct NDPServer_pvt* ns) { if (msg->length < NDPHeader_RouterSolicitation_SIZE) { return 0; } struct NDPHeader_NeighborSolicitation* sol = (struct NDPHeader_NeighborSolicitation*)msg->bytes; if (sol->oneThirtyFive != 135 || sol->zero != 0) { printf("wrong type/code for neighbor solicitation\n"); return 0; } if (Bits_memcmp(ip6->destinationAddr, UNICAST_ADDR, 16) && Bits_memcmp(ip6->destinationAddr, MULTICAST_ADDR, 13)) { printf("wrong address for neighbor solicitation\n"); return 0; } // now we're committed. Message_shift(msg, -msg->length, NULL); struct NDPHeader_NeighborAdvert_MacOpt macOpt = { .two = 2, .one = 1 }; Bits_memcpyConst(macOpt.mac, eth->destAddr, 6); Message_push(msg, &macOpt, sizeof(struct NDPHeader_NeighborAdvert_MacOpt), NULL); struct NDPHeader_NeighborAdvert na = { .oneThirtySix = 136, .zero = 0, .checksum = 0, .bits = NDPHeader_NeighborAdvert_bits_ROUTER | NDPHeader_NeighborAdvert_bits_SOLICITED | NDPHeader_NeighborAdvert_bits_OVERRIDE }; Bits_memcpyConst(na.targetAddr, UNICAST_ADDR, 16); Message_push(msg, &na, sizeof(struct NDPHeader_NeighborAdvert), NULL); sendResponse(msg, eth, ip6, ns); return 1; } static uint8_t receiveMessage(struct Message* msg, struct Interface* iface) { struct NDPServer_pvt* ns = Identity_cast((struct NDPServer_pvt*)iface->receiverContext); if (msg->length < Ethernet_SIZE + Headers_IP6Header_SIZE) { return Interface_receiveMessage(&ns->pub.generic, msg); } struct Ethernet* eth = (struct Ethernet*) msg->bytes; struct Headers_IP6Header* ip6 = (struct Headers_IP6Header*) (ð[1]); if (eth->ethertype != Ethernet_TYPE_IP6 || ip6->nextHeader != 58 /* ICMPv6 */) { return Interface_receiveMessage(&ns->pub.generic, msg); } // store the eth and ip6 headers so they don't get clobbered struct Ethernet storedEth; Message_pop(msg, &storedEth, sizeof(struct Ethernet), NULL); struct Headers_IP6Header storedIp6; Message_pop(msg, &storedIp6, sizeof(struct Headers_IP6Header), NULL); if (!tryNeighborSolicitation(msg, &storedEth, &storedIp6, ns) && !tryRouterSolicitation(msg, &storedEth, &storedIp6, ns)) { Message_push(msg, &storedIp6, sizeof(struct Headers_IP6Header), NULL); Message_push(msg, &storedEth, sizeof(struct Ethernet), NULL); return Interface_receiveMessage(&ns->pub.generic, msg); } // responding happens in sendResponse.. return 0; } static uint8_t sendMessage(struct Message* msg, struct Interface* iface) { struct NDPServer_pvt* ns = Identity_cast((struct NDPServer_pvt*)iface); return Interface_sendMessage(ns->wrapped, msg); } struct NDPServer* NDPServer_new(struct Interface* external, struct Allocator* alloc) { struct NDPServer_pvt* out = Allocator_calloc(alloc, sizeof(struct NDPServer_pvt), 1); out->wrapped = external; Identity_set(out); InterfaceWrapper_wrap(external, sendMessage, receiveMessage, &out->pub.generic); return &out->pub; }