static Iface_DEFUN incomingMsg(struct Message* msg, struct Pathfinder_pvt* pf) { struct Address addr; struct RouteHeader* hdr = (struct RouteHeader*) msg->bytes; Message_shift(msg, -(RouteHeader_SIZE + DataHeader_SIZE), NULL); Bits_memcpy(addr.ip6.bytes, hdr->ip6, 16); Bits_memcpy(addr.key, hdr->publicKey, 32); addr.protocolVersion = Endian_bigEndianToHost32(hdr->version_be); addr.padding = 0; addr.path = Endian_bigEndianToHost64(hdr->sh.label_be); //Log_debug(pf->log, "Incoming DHT"); struct DHTMessage dht = { .address = &addr, .binMessage = msg, .allocator = msg->alloc }; DHTModuleRegistry_handleIncoming(&dht, pf->registry); struct Message* nodeMsg = Message_new(0, 256, msg->alloc); Iface_CALL(sendNode, nodeMsg, &addr, 0xfffffff0u, pf); if (dht.pleaseRespond) { // what a beautiful hack, see incomingFromDHT return Iface_next(&pf->pub.eventIf, msg); } return NULL; } static Iface_DEFUN incomingFromEventIf(struct Message* msg, struct Iface* eventIf) { struct Pathfinder_pvt* pf = Identity_containerOf(eventIf, struct Pathfinder_pvt, pub.eventIf); enum PFChan_Core ev = Message_pop32(msg, NULL); if (Pathfinder_pvt_state_INITIALIZING == pf->state) { Assert_true(ev == PFChan_Core_CONNECT); return connected(pf, msg); } // Let the PF send another 128 path changes again because it's basically a new tick. pf->bestPathChanges = 0; switch (ev) { case PFChan_Core_SWITCH_ERR: return switchErr(msg, pf); case PFChan_Core_SEARCH_REQ: return searchReq(msg, pf); case PFChan_Core_PEER: return peer(msg, pf); case PFChan_Core_PEER_GONE: return peerGone(msg, pf); case PFChan_Core_SESSION: return session(msg, pf); case PFChan_Core_SESSION_ENDED: return sessionEnded(msg, pf); case PFChan_Core_DISCOVERED_PATH: return discoveredPath(msg, pf); case PFChan_Core_MSG: return incomingMsg(msg, pf); case PFChan_Core_PING: return handlePing(msg, pf); case PFChan_Core_PONG: return handlePong(msg, pf); case PFChan_Core_UNSETUP_SESSION: case PFChan_Core_LINK_STATE: case PFChan_Core_CTRL_MSG: return NULL; default:; } Assert_failure("unexpected event [%d]", ev); } static void sendEvent(struct Pathfinder_pvt* pf, enum PFChan_Pathfinder ev, void* data, int size) { struct Allocator* alloc = Allocator_child(pf->alloc); struct Message* msg = Message_new(0, 512+size, alloc); Message_push(msg, data, size, NULL); Message_push32(msg, ev, NULL); Iface_send(&pf->pub.eventIf, msg); Allocator_free(alloc); } static void init(void* vpf) { struct Pathfinder_pvt* pf = Identity_check((struct Pathfinder_pvt*) vpf); struct PFChan_Pathfinder_Connect conn = { .superiority_be = Endian_hostToBigEndian32(1), .version_be = Endian_hostToBigEndian32(Version_CURRENT_PROTOCOL) }; CString_strncpy(conn.userAgent, "Cjdns internal pathfinder", 64); sendEvent(pf, PFChan_Pathfinder_CONNECT, &conn, PFChan_Pathfinder_Connect_SIZE); } struct Pathfinder* Pathfinder_register(struct Allocator* allocator, struct Log* log, struct EventBase* base, struct Random* rand, struct Admin* admin) { struct Allocator* alloc = Allocator_child(allocator); struct Pathfinder_pvt* pf = Allocator_calloc(alloc, sizeof(struct Pathfinder_pvt), 1); Identity_set(pf); pf->alloc = alloc; pf->log = log; pf->base = base; pf->rand = rand; pf->admin = admin; pf->pub.eventIf.send = incomingFromEventIf; pf->dhtModule.context = pf; pf->dhtModule.handleOutgoing = incomingFromDHT; // This needs to be done asynchronously so the pf can be plumbed to the core Timeout_setTimeout(init, pf, 0, base, alloc); return &pf->pub; }
static Iface_DEFUN sendMessage(struct Message* msg, struct Iface* iface) { struct ETHInterface_pvt* ctx = Identity_containerOf(iface, struct ETHInterface_pvt, pub.generic.iface); struct Sockaddr* sa = (struct Sockaddr*) msg->bytes; Assert_true(msg->length >= Sockaddr_OVERHEAD); Assert_true(sa->addrLen <= ETHInterface_Sockaddr_SIZE); struct ETHInterface_Sockaddr sockaddr = { .generic = { .addrLen = 0 } }; Message_pop(msg, &sockaddr, sa->addrLen, NULL); struct sockaddr_ll addr; Bits_memcpy(&addr, &ctx->addrBase, sizeof(struct sockaddr_ll)); if (sockaddr.generic.flags & Sockaddr_flags_BCAST) { Bits_memset(addr.sll_addr, 0xff, 6); } else { Bits_memcpy(addr.sll_addr, sockaddr.mac, 6); } struct ETHInterface_Header hdr = { .version = ETHInterface_CURRENT_VERSION, .zero = 0, .length_be = Endian_hostToBigEndian16(msg->length + ETHInterface_Header_SIZE), .fc00_be = Endian_hostToBigEndian16(0xfc00) }; Message_push(msg, &hdr, ETHInterface_Header_SIZE, NULL); struct Except* eh = NULL; sendMessageInternal(msg, &addr, ctx, eh); return NULL; } static void handleEvent2(struct ETHInterface_pvt* context, struct Allocator* messageAlloc) { struct Message* msg = Message_new(MAX_PACKET_SIZE, PADDING, messageAlloc); 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(msg, 2, NULL); int rc = recvfrom(context->socket, msg->bytes, msg->length, 0, (struct sockaddr*) &addr, &addrLen); if (rc < ETHInterface_Header_SIZE) { Log_debug(context->logger, "Failed to receive eth frame"); return; } Assert_true(msg->length >= rc); msg->length = rc; //Assert_true(addrLen == SOCKADDR_LL_LEN); struct ETHInterface_Header hdr; Message_pop(msg, &hdr, ETHInterface_Header_SIZE, NULL); // here we could put a switch statement to handle different versions differently. if (hdr.version != ETHInterface_CURRENT_VERSION) { Log_debug(context->logger, "DROP unknown version"); return; } uint16_t reportedLength = Endian_bigEndianToHost16(hdr.length_be); reportedLength -= ETHInterface_Header_SIZE; if (msg->length != reportedLength) { if (msg->length < reportedLength) { Log_debug(context->logger, "DROP size field is larger than frame"); return; } msg->length = reportedLength; } if (hdr.fc00_be != Endian_hostToBigEndian16(0xfc00)) { Log_debug(context->logger, "DROP bad magic"); return; } struct ETHInterface_Sockaddr sockaddr = { .zero = 0 }; Bits_memcpy(sockaddr.mac, addr.sll_addr, 6); sockaddr.generic.addrLen = ETHInterface_Sockaddr_SIZE; if (addr.sll_pkttype == PACKET_BROADCAST) { sockaddr.generic.flags |= Sockaddr_flags_BCAST; } Message_push(msg, &sockaddr, ETHInterface_Sockaddr_SIZE, NULL); Assert_true(!((uintptr_t)msg->bytes % 4) && "Alignment fault"); Iface_send(&context->pub.generic.iface, msg); } static void handleEvent(void* vcontext) { struct ETHInterface_pvt* context = Identity_check((struct ETHInterface_pvt*) vcontext); struct Allocator* messageAlloc = Allocator_child(context->pub.generic.alloc); handleEvent2(context, messageAlloc); Allocator_free(messageAlloc); } List* ETHInterface_listDevices(struct Allocator* alloc, struct Except* eh) { List* out = List_new(alloc); #ifndef android struct ifaddrs* ifaddr = NULL; if (getifaddrs(&ifaddr) || ifaddr == NULL) { Except_throw(eh, "getifaddrs() -> errno:%d [%s]", errno, strerror(errno)); } for (struct ifaddrs* ifa = ifaddr; ifa; ifa = ifa->ifa_next) { if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_PACKET) { List_addString(out, String_new(ifa->ifa_name, alloc), alloc); } } freeifaddrs(ifaddr); #endif return out; } static int closeSocket(struct Allocator_OnFreeJob* j) { struct ETHInterface_pvt* ctx = Identity_check((struct ETHInterface_pvt*) j->userData); close(ctx->socket); return 0; } struct ETHInterface* ETHInterface_new(struct EventBase* eventBase, const char* bindDevice, struct Allocator* alloc, struct Except* exHandler, struct Log* logger) { struct ETHInterface_pvt* ctx = Allocator_calloc(alloc, sizeof(struct ETHInterface_pvt), 1); Identity_set(ctx); ctx->pub.generic.iface.send = sendMessage; ctx->pub.generic.alloc = alloc; ctx->logger = logger; struct ifreq ifr = { .ifr_ifindex = 0 }; ctx->socket = socket(AF_PACKET, SOCK_DGRAM, Ethernet_TYPE_CJDNS); if (ctx->socket == -1) { Except_throw(exHandler, "call to socket() failed. [%s]", strerror(errno)); } Allocator_onFree(alloc, closeSocket, ctx); CString_strncpy(ifr.ifr_name, bindDevice, IFNAMSIZ - 1); ctx->ifName = String_new(bindDevice, alloc); if (ioctl(ctx->socket, SIOCGIFINDEX, &ifr) == -1) { Except_throw(exHandler, "failed to find interface index [%s]", strerror(errno)); } ctx->ifindex = ifr.ifr_ifindex; if (ioctl(ctx->socket, SIOCGIFFLAGS, &ifr) < 0) { Except_throw(exHandler, "ioctl(SIOCGIFFLAGS) [%s]", strerror(errno)); } if (!((ifr.ifr_flags & IFF_UP) && (ifr.ifr_flags & IFF_RUNNING))) { Log_info(logger, "Bringing up interface [%s]", ifr.ifr_name); ifr.ifr_flags |= IFF_UP | IFF_RUNNING; if (ioctl(ctx->socket, SIOCSIFFLAGS, &ifr) < 0) { Except_throw(exHandler, "ioctl(SIOCSIFFLAGS) [%s]", strerror(errno)); } } ctx->addrBase = (struct sockaddr_ll) { .sll_family = AF_PACKET, .sll_protocol = Ethernet_TYPE_CJDNS, .sll_ifindex = ctx->ifindex, .sll_hatype = ARPHRD_ETHER, .sll_pkttype = PACKET_OTHERHOST, .sll_halen = ETH_ALEN }; if (bind(ctx->socket, (struct sockaddr*) &ctx->addrBase, sizeof(struct sockaddr_ll))) { Except_throw(exHandler, "call to bind() failed [%s]", strerror(errno)); } Socket_makeNonBlocking(ctx->socket); Event_socketRead(handleEvent, ctx, ctx->socket, eventBase, alloc, exHandler); return &ctx->pub; }