static void onPingResponse(struct SwitchPinger_Response* resp, void* onResponseContext) { if (SwitchPinger_Result_OK != resp->res) { return; } struct InterfaceController_Peer* ep = Identity_check((struct InterfaceController_Peer*) onResponseContext); struct InterfaceController_pvt* ic = ifcontrollerForPeer(ep); struct Address addr; Bits_memset(&addr, 0, sizeof(struct Address)); Bits_memcpyConst(addr.key, CryptoAuth_getHerPublicKey(ep->cryptoAuthIf), 32); addr.path = ep->switchLabel; addr.protocolVersion = resp->version; #ifdef Log_DEBUG uint8_t addrStr[60]; Address_print(addrStr, &addr); uint8_t key[56]; Base32_encode(key, 56, CryptoAuth_getHerPublicKey(ep->cryptoAuthIf), 32); #endif if (!Version_isCompatible(Version_CURRENT_PROTOCOL, resp->version)) { Log_debug(ic->logger, "got switch pong from node [%s] with incompatible version [%d]", key, resp->version); } else { Log_debug(ic->logger, "got switch pong from node [%s] with version [%d]", key, resp->version); } if (!ep->timeOfLastPing) { // We've never heard from this machine before (or we've since forgotten about it) // This is here because we want the tests to function without the janitor present. // Other than that, it just makes a slightly more synchronous/guaranteed setup. Router_sendGetPeers(ic->router, &addr, 0, 0, ic->allocator); } struct Node_Link* link = Router_linkForPath(ic->router, resp->label); if (!link || !Node_getBestParent(link->child)) { RumorMill_addNode(ic->rumorMill, &addr); } else { Log_debug(ic->logger, "link exists"); } ep->timeOfLastPing = Time_currentTimeMilliseconds(ic->eventBase); #ifdef Log_DEBUG // This will be false if it times out. //Assert_true(label == ep->switchLabel); uint8_t path[20]; AddrTools_printPath(path, resp->label); uint8_t sl[20]; AddrTools_printPath(sl, ep->switchLabel); Log_debug(ic->logger, "Received [%s] from lazy endpoint [%s] [%s]", SwitchPinger_resultString(resp->res)->bytes, path, sl); #endif }
static void onPingResponse(struct SwitchPinger_Response* resp, void* onResponseContext) { if (SwitchPinger_Result_OK != resp->res) { return; } struct Peer* ep = Identity_check((struct Peer*) onResponseContext); struct InterfaceController_pvt* ic = Identity_check(ep->ici->ic); ep->addr.protocolVersion = resp->version; if (Defined(Log_DEBUG)) { String* addr = Address_toString(&ep->addr, resp->ping->pingAlloc); if (!Version_isCompatible(Version_CURRENT_PROTOCOL, resp->version)) { Log_debug(ic->logger, "got switch pong from node [%s] with incompatible version", addr->bytes); } else if (ep->addr.path != resp->label) { uint8_t sl[20]; AddrTools_printPath(sl, resp->label); Log_debug(ic->logger, "got switch pong from node [%s] mismatch label [%s]", addr->bytes, sl); } else { Log_debug(ic->logger, "got switch pong from node [%s]", addr->bytes); } } if (!Version_isCompatible(Version_CURRENT_PROTOCOL, resp->version)) { return; } if (ep->state == InterfaceController_PeerState_ESTABLISHED) { sendPeer(0xffffffff, PFChan_Core_PEER, ep); } ep->timeOfLastPing = Time_currentTimeMilliseconds(ic->eventBase); if (Defined(Log_DEBUG)) { String* addr = Address_toString(&ep->addr, resp->ping->pingAlloc); Log_debug(ic->logger, "Received [%s] from lazy endpoint [%s]", SwitchPinger_resultString(resp->res)->bytes, addr->bytes); } }
/** * Expects [ struct LLAddress ][ beacon ] */ static Iface_DEFUN handleBeacon(struct Message* msg, struct InterfaceController_Iface_pvt* ici) { struct InterfaceController_pvt* ic = ici->ic; if (!ici->beaconState) { // accepting beacons disabled. Log_debug(ic->logger, "[%s] Dropping beacon because beaconing is disabled", ici->name->bytes); return NULL; } if (msg->length < Headers_Beacon_SIZE) { Log_debug(ic->logger, "[%s] Dropping runt beacon", ici->name->bytes); return NULL; } struct Sockaddr* lladdrInmsg = (struct Sockaddr*) msg->bytes; // clear the bcast flag lladdrInmsg->flags = 0; Message_shift(msg, -lladdrInmsg->addrLen, NULL); struct Headers_Beacon beacon; Message_pop(msg, &beacon, Headers_Beacon_SIZE, NULL); if (Defined(Log_DEBUG)) { char* content = Hex_print(&beacon, Headers_Beacon_SIZE, msg->alloc); Log_debug(ici->ic->logger, "RECV BEACON CONTENT[%s]", content); } struct Address addr; Bits_memset(&addr, 0, sizeof(struct Address)); Bits_memcpy(addr.key, beacon.publicKey, 32); addr.protocolVersion = Endian_bigEndianToHost32(beacon.version_be); Address_getPrefix(&addr); String* printedAddr = NULL; if (Defined(Log_DEBUG)) { printedAddr = Address_toString(&addr, msg->alloc); } if (addr.ip6.bytes[0] != 0xfc || !Bits_memcmp(ic->ca->publicKey, addr.key, 32)) { Log_debug(ic->logger, "handleBeacon invalid key [%s]", printedAddr->bytes); return NULL; } if (!Version_isCompatible(addr.protocolVersion, Version_CURRENT_PROTOCOL)) { if (Defined(Log_DEBUG)) { Log_debug(ic->logger, "[%s] DROP beacon from [%s] which was version [%d] " "our version is [%d] making them incompatable", ici->name->bytes, printedAddr->bytes, addr.protocolVersion, Version_CURRENT_PROTOCOL); } return NULL; } String* beaconPass = String_newBinary(beacon.password, Headers_Beacon_PASSWORD_LEN, msg->alloc); int epIndex = Map_EndpointsBySockaddr_indexForKey(&lladdrInmsg, &ici->peerMap); if (epIndex > -1) { // The password might have changed! struct Peer* ep = ici->peerMap.values[epIndex]; CryptoAuth_setAuth(beaconPass, NULL, ep->caSession); return NULL; } struct Allocator* epAlloc = Allocator_child(ici->alloc); struct Peer* ep = Allocator_calloc(epAlloc, sizeof(struct Peer), 1); struct Sockaddr* lladdr = Sockaddr_clone(lladdrInmsg, epAlloc); ep->alloc = epAlloc; ep->ici = ici; ep->lladdr = lladdr; int setIndex = Map_EndpointsBySockaddr_put(&lladdr, &ep, &ici->peerMap); ep->handle = ici->peerMap.handles[setIndex]; ep->isIncomingConnection = true; Bits_memcpy(&ep->addr, &addr, sizeof(struct Address)); Identity_set(ep); Allocator_onFree(epAlloc, closeInterface, ep); ep->peerLink = PeerLink_new(ic->eventBase, epAlloc); ep->caSession = CryptoAuth_newSession(ic->ca, epAlloc, beacon.publicKey, false, "outer"); CryptoAuth_setAuth(beaconPass, NULL, ep->caSession); ep->switchIf.send = sendFromSwitch; if (SwitchCore_addInterface(ic->switchCore, &ep->switchIf, epAlloc, &ep->addr.path)) { Log_debug(ic->logger, "handleBeacon() SwitchCore out of space"); Allocator_free(epAlloc); return NULL; } // We want the node to immedietly be pinged but we don't want it to appear unresponsive because // the pinger will only ping every (PING_INTERVAL * 8) so we set timeOfLastMessage to // (now - pingAfterMilliseconds - 1) so it will be considered a "lazy node". ep->timeOfLastMessage = Time_currentTimeMilliseconds(ic->eventBase) - ic->pingAfterMilliseconds - 1; Log_info(ic->logger, "Added peer [%s] from beacon", Address_toString(&ep->addr, msg->alloc)->bytes); // This should be safe because this is an outgoing request and we're sure the node will not // be relocated by moveEndpointIfNeeded() sendPeer(0xffffffff, PFChan_Core_PEER, ep); return NULL; }
static Iface_DEFUN handlePing(struct Message* msg, struct ControlHandler_pvt* ch, uint64_t label, uint8_t* labelStr, uint16_t messageType_be) { if (msg->length < handlePing_MIN_SIZE) { Log_info(ch->log, "DROP runt ping"); return NULL; } struct Control* ctrl = (struct Control*) msg->bytes; Message_shift(msg, -Control_Header_SIZE, NULL); // Ping and keyPing share version location struct Control_Ping* ping = (struct Control_Ping*) msg->bytes; uint32_t herVersion = Endian_bigEndianToHost32(ping->version_be); if (!Version_isCompatible(Version_CURRENT_PROTOCOL, herVersion)) { Log_debug(ch->log, "DROP ping from incompatible version [%d]", herVersion); return NULL; } if (messageType_be == Control_KEYPING_be) { Log_debug(ch->log, "got switch keyPing from [%s]", labelStr); if (msg->length < Control_KeyPing_HEADER_SIZE) { // min keyPing size is longer Log_debug(ch->log, "DROP runt keyPing"); return NULL; } if (msg->length > Control_KeyPing_MAX_SIZE) { Log_debug(ch->log, "DROP long keyPing"); return NULL; } if (ping->magic != Control_KeyPing_MAGIC) { Log_debug(ch->log, "DROP keyPing (bad magic)"); return NULL; } struct Control_KeyPing* keyPing = (struct Control_KeyPing*) msg->bytes; keyPing->magic = Control_KeyPong_MAGIC; ctrl->header.type_be = Control_KEYPONG_be; Bits_memcpy(keyPing->key, ch->myPublicKey, 32); } else if (messageType_be == Control_PING_be) { // Happens in benchmark. //Log_debug(ch->log, "got switch ping from [%s]", labelStr); if (ping->magic != Control_Ping_MAGIC) { Log_debug(ch->log, "DROP ping (bad magic)"); return NULL; } ping->magic = Control_Pong_MAGIC; ctrl->header.type_be = Control_PONG_be; } else { Assert_failure("2+2=5"); } ping->version_be = Endian_hostToBigEndian32(Version_CURRENT_PROTOCOL); Message_shift(msg, Control_Header_SIZE, NULL); ctrl->header.checksum_be = 0; ctrl->header.checksum_be = Checksum_engine(msg->bytes, msg->length); Message_shift(msg, RouteHeader_SIZE, NULL); struct RouteHeader* routeHeader = (struct RouteHeader*) msg->bytes; Bits_memset(routeHeader, 0, RouteHeader_SIZE); SwitchHeader_setVersion(&routeHeader->sh, SwitchHeader_CURRENT_VERSION); routeHeader->sh.label_be = Endian_hostToBigEndian64(label); routeHeader->flags |= RouteHeader_flags_CTRLMSG; return Iface_next(&ch->pub.coreIf, msg); }
static void handleBeacon(struct Message* msg, struct ETHInterface* context) { if (!context->beaconState) { // accepting beacons disabled. Log_debug(context->logger, "Dropping beacon because beaconing is disabled"); return; } struct sockaddr_ll addr; Bits_memcpyConst(&addr, &context->addrBase, sizeof(struct sockaddr_ll)); Message_pop(msg, addr.sll_addr, 8); if (msg->length < Headers_Beacon_SIZE) { // Oversize messages are ok because beacons may contain more information in the future. Log_debug(context->logger, "Dropping wrong size beacon, expected [%d] got [%d]", Headers_Beacon_SIZE, msg->length); return; } struct Headers_Beacon* beacon = (struct Headers_Beacon*) msg->bytes; uint32_t theirVersion = Endian_bigEndianToHost32(beacon->version_be); if (!Version_isCompatible(theirVersion, Version_CURRENT_PROTOCOL)) { #ifdef Log_DEBUG uint8_t mac[18]; AddrTools_printMac(mac, addr.sll_addr); Log_debug(context->logger, "Dropped beacon from [%s] which was version [%d] " "our version is [%d] making them incompatable", mac, theirVersion, Version_CURRENT_PROTOCOL); #endif return; } #ifdef Log_DEBUG uint8_t mac[18]; AddrTools_printMac(mac, addr.sll_addr); Log_debug(context->logger, "Got beacon from [%s]", mac); #endif String passStr = { .bytes = (char*) beacon->password, .len = Headers_Beacon_PASSWORD_LEN }; struct Interface* iface = MultiInterface_ifaceForKey(context->multiIface, addr.sll_addr); int ret = InterfaceController_registerPeer(context->ic, beacon->publicKey, &passStr, false, true, iface); if (ret != 0) { uint8_t mac[18]; AddrTools_printMac(mac, addr.sll_addr); Log_info(context->logger, "Got beacon from [%s] and registerPeer returned [%d]", mac, ret); } } static void sendBeacon(void* vcontext) { struct ETHInterface* context = Identity_cast((struct ETHInterface*) vcontext); if (context->beaconState != ETHInterface_beacon_ACCEPTING_AND_SENDING) { // beaconing disabled return; } struct { struct sockaddr_ll addr; struct Headers_Beacon beacon; } content; Bits_memcpyConst(&content.addr, &context->addrBase, sizeof(struct sockaddr_ll)); Bits_memset(content.addr.sll_addr, 0xff, 6); InterfaceController_populateBeacon(context->ic, &content.beacon); struct Message m = { .bytes=(uint8_t*)content.addr.sll_addr, .padding=0, .length=sizeof(struct Headers_Beacon) + 8 }; int ret; if ((ret = sendMessage(&m, &context->generic)) != 0) { Log_info(context->logger, "Got error [%d] sending beacon [%s]", ret, strerror(errno)); } } static void handleEvent(void* vcontext) { struct ETHInterface* context = Identity_cast((struct ETHInterface*) vcontext); struct Message message = { .bytes = context->messageBuff + PADDING, .padding = PADDING, .length = MAX_PACKET_SIZE }; struct sockaddr_ll addr; uint32_t addrLen = sizeof(struct sockaddr_ll); // Knock it out of alignment by 2 bytes so that it will be // aligned when the idAndPadding is shifted off. Message_shift(&message, 2); int rc = recvfrom(context->socket, message.bytes, message.length, 0, (struct sockaddr*) &addr, &addrLen); if (rc < 0) { Log_debug(context->logger, "Failed to receive eth frame"); return; } //Assert_true(addrLen == SOCKADDR_LL_LEN); // Pop the first 2 bytes of the message containing the node id and amount of padding. uint16_t idAndPadding_be; Message_pop(&message, &idAndPadding_be, 2); const uint16_t idAndPadding = Endian_bigEndianToHost16(idAndPadding_be); message.length = rc - 2 - ((idAndPadding & 7) * 8); const uint16_t id = idAndPadding >> 3; Message_push(&message, &id, 2); Message_push(&message, addr.sll_addr, 6); if (addr.sll_pkttype == PACKET_BROADCAST) { handleBeacon(&message, context); return; } /* Cut down on the noise uint8_t buff[sizeof(addr) * 2 + 1] = {0}; Hex_encode(buff, sizeof(buff), (uint8_t*)&addr, sizeof(addr)); Log_debug(context->logger, "Got ethernet frame from [%s]", buff); */ context->generic.receiveMessage(&message, &context->generic); } int ETHInterface_beginConnection(const char* macAddress, uint8_t cryptoKey[32], String* password, struct ETHInterface* ethIf) { Identity_check(ethIf); struct sockaddr_ll addr; Bits_memcpyConst(&addr, ðIf->addrBase, sizeof(struct sockaddr_ll)); if (AddrTools_parseMac(addr.sll_addr, (const uint8_t*)macAddress)) { return ETHInterface_beginConnection_BAD_MAC; } struct Interface* iface = MultiInterface_ifaceForKey(ethIf->multiIface, &addr); int ret = InterfaceController_registerPeer(ethIf->ic, cryptoKey, password, false, false, iface); if (ret) { Allocator_free(iface->allocator); switch(ret) { case InterfaceController_registerPeer_BAD_KEY: return ETHInterface_beginConnection_BAD_KEY; case InterfaceController_registerPeer_OUT_OF_SPACE: return ETHInterface_beginConnection_OUT_OF_SPACE; default: return ETHInterface_beginConnection_UNKNOWN_ERROR; } } return 0; } int ETHInterface_beacon(struct ETHInterface* ethIf, int* state) { Identity_check(ethIf); if (state) { ethIf->beaconState = *state; // Send out a beacon right away so we don't have to wait. if (ethIf->beaconState == ETHInterface_beacon_ACCEPTING_AND_SENDING) { sendBeacon(ethIf); } } return ethIf->beaconState; } struct ETHInterface* ETHInterface_new(struct EventBase* base, const char* bindDevice, struct Allocator* allocator, struct Except* exHandler, struct Log* logger, struct InterfaceController* ic) { struct ETHInterface* context = Allocator_clone(allocator, (&(struct ETHInterface) { .generic = { .sendMessage = sendMessage, .allocator = allocator }, .logger = logger, .ic = ic, .id = getpid() }));