void Server_setupUDPSockets(struct sockaddr_storage* addresses[2], struct pollfd* pollfds) { int val = 0; int sockets[2] = {-1, -1}; udpsocks = Memory_safeCalloc(nofServerSocks / 2, sizeof(int)); if (hasv4) { sockets[0] = socket(PF_INET, SOCK_DGRAM, 0); if (bind(sockets[0], (struct sockaddr *) addresses[0], sizeof (struct sockaddr_in)) < 0) { char *addressString = Util_addressToString(addresses[0]); Log_fatal("bind %s %d: %s", addressString, Util_addressToPort(addresses[0]), strerror(errno)); free(addressString); } val = 0xe0; if (setsockopt(sockets[0], IPPROTO_IP, IP_TOS, &val, sizeof(val)) < 0) Log_warn("Server: Failed to set TOS for UDP Socket"); val = 0x80; if (setsockopt(sockets[0], IPPROTO_IP, IP_TOS, &val, sizeof(val)) < 0) Log_warn("Server: Failed to set TOS for UDP Socket"); fcntl(sockets[0], F_SETFL, O_NONBLOCK); pollfds[(hasv6) ? 2 : 1].fd = sockets[0]; pollfds[(hasv6) ? 2 : 1].events = POLLIN | POLLHUP | POLLERR; udpsocks[0] = sockets[0]; } if (hasv6) { sockets[1] = socket(PF_INET6, SOCK_DGRAM, 0); if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(int)) != 0) Log_fatal("setsockopt IPv6: %s", strerror(errno)); if (bind(sockets[1], (struct sockaddr *) addresses[1], sizeof (struct sockaddr_in6)) < 0) { char *addressString = Util_addressToString(addresses[1]); Log_fatal("bind %s %d: %s", addressString, Util_addressToPort(addresses[1]), strerror(errno)); free(addressString); } val = 0xe0; if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof(val)) < 0) Log_warn("Server: Failed to set TOS for UDP Socket"); val = 0x80; if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof(val)) < 0) Log_warn("Server: Failed to set TOS for UDP Socket"); fcntl(sockets[1], F_SETFL, O_NONBLOCK); pollfds[(hasv4) ? 3 : 1].fd = sockets[1]; pollfds[(hasv4) ? 3 : 1].events = POLLIN | POLLHUP | POLLERR; udpsocks[(hasv4) ? 1 : 0] = sockets[1]; } }
static void installFilter(struct sock_fprog* filter, struct Log* logger, struct Except* eh) { struct sigaction sa = { .sa_sigaction = catchViolation, .sa_flags = SA_SIGINFO }; if (sigaction(SIGSYS, &sa, NULL)) { Log_warn(logger, "sigaction(SIGSYS) -> [%s]\n", strerror(errno)); } if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) { // don't worry about it. Log_warn(logger, "prctl(PR_SET_NO_NEW_PRIVS) -> [%s]\n", strerror(errno)); } if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, filter) == -1) { Except_throw(eh, "prctl(PR_SET_SECCOMP) -> [%s]\n", strerror(errno)); } }
static inline uint8_t incomingDHT(struct Message* message, struct Address* addr, struct Ducttape_pvt* context) { struct DHTMessage dht; Bits_memset(&dht, 0, sizeof(struct DHTMessage)); // TODO: These copies are not necessary at all. const uint32_t length = (message->length < DHTMessage_MAX_SIZE) ? message->length : DHTMessage_MAX_SIZE; Bits_memcpy(dht.bytes, message->bytes, length); dht.address = addr; uint8_t buffer[PER_MESSAGE_BUF_SZ]; dht.allocator = BufferAllocator_new(buffer, PER_MESSAGE_BUF_SZ); struct Jmp j; Jmp_try(j) { BufferAllocator_onOOM(dht.allocator, &j.handler); DHTModuleRegistry_handleIncoming(&dht, context->registry); } Jmp_catch { uint8_t printed[60]; Address_print(printed, addr); Log_warn(context->logger, "Parsing message from [%s] failed; out of memory.", printed); } // TODO: return something meaningful. return Error_NONE; }
static void rpcCall0(String* function, Dict* args, struct Context* ctx, struct Allocator* alloc, bool exitIfError) { struct AdminClient_Result* res = AdminClient_rpcCall(function, args, ctx->client, alloc); if (res->err) { Log_critical(ctx->logger, "Failed to make function call [%s], error: [%s]", AdminClient_errorString(res->err), function->bytes); die(res, ctx, alloc); } String* error = Dict_getString(res->responseDict, String_CONST("error")); if (error && !String_equals(error, String_CONST("none"))) { if (exitIfError) { Log_critical(ctx->logger, "Got error [%s] calling [%s]", error->bytes, function->bytes); die(res, ctx, alloc); } Log_warn(ctx->logger, "Got error [%s] calling [%s], ignoring.", error->bytes, function->bytes); } }
void setscheduler() { int rc; struct sched_param sp; sp.sched_priority = sched_get_priority_min(SCHED_RR); /* Should suffice */ Log_info("Setting SCHED_RR prio %d", sp.sched_priority); rc = sched_setscheduler(0, SCHED_RR, &sp); if (rc < 0) Log_warn("Failed to set scheduler: %s", strerror(errno)); }
// Called by the TUN device. static inline uint8_t ip6FromTun(struct Message* message, struct Interface* interface) { struct Context* context = (struct Context*) interface->receiverContext; if (!validIP6(message)) { Log_debug(context->logger, "dropped message from TUN because it was not valid IPv6.\n"); return Error_INVALID; } struct Headers_IP6Header* header = (struct Headers_IP6Header*) message->bytes; if (memcmp(header->sourceAddr, context->myAddr.ip6.bytes, 16)) { Log_warn(context->logger, "dropped message because only one address is allowed to be used " "and the source address was different.\n"); return Error_INVALID; } context->switchHeader = NULL; struct Node* bestNext = RouterModule_getBest(header->destinationAddr, context->routerModule); if (bestNext) { context->forwardTo = &bestNext->address; if (!memcmp(header->destinationAddr, bestNext->address.ip6.bytes, 16)) { // Direct send, skip the innermost layer of encryption. header->hopLimit = 0; #ifdef Log_DEBUG uint8_t nhAddr[60]; Address_print(nhAddr, &bestNext->address); Log_debug1(context->logger, "Forwarding data to %s (last hop)\n", nhAddr); #endif return sendToRouter(&bestNext->address, message, context); } } // Grab out the header so it doesn't get clobbered. struct Headers_IP6Header headerStore; memcpy(&headerStore, header, Headers_IP6Header_SIZE); context->ip6Header = &headerStore; // Shift over the content. Message_shift(message, -Headers_IP6Header_SIZE); struct Interface* session = SessionManager_getSession(headerStore.destinationAddr, NULL, context->sm); // This comes out at outgoingFromMe() context->layer = INNER_LAYER; return session->sendMessage(message, session); }
static int rpcCall0(String* function, Dict* args, struct Context* ctx, struct Allocator* alloc, Dict** resultP, bool exitIfError) { ctx->currentReqAlloc = Allocator_child(alloc); ctx->currentResult = NULL; struct AdminClient_Promise* promise = AdminClient_rpcCall(function, args, ctx->client, alloc); promise->callback = rpcCallback; promise->userData = ctx; EventBase_beginLoop(ctx->base); struct AdminClient_Result* res = ctx->currentResult; Assert_true(res); if (res->err) { Log_critical(ctx->logger, "Failed to make function call [%s], error: [%s]", AdminClient_errorString(res->err), function->bytes); die(res, ctx, alloc); } String* error = Dict_getString(res->responseDict, String_CONST("error")); int ret = 0; if (error && !String_equals(error, String_CONST("none"))) { if (exitIfError) { Log_critical(ctx->logger, "Got error [%s] calling [%s]", error->bytes, function->bytes); die(res, ctx, alloc); } Log_warn(ctx->logger, "Got error [%s] calling [%s], ignoring.", error->bytes, function->bytes); ret = 1; } if (resultP) { *resultP = res->responseDict; } else { Allocator_free(ctx->currentReqAlloc); } ctx->currentReqAlloc = NULL; return ret; }
static void receiveMessage2(struct Message* msg, struct Hermes* hermes, struct Allocator* tempAlloc) { #ifdef Log_KEYS char lastChr = msg->bytes[msg->length - 1]; msg->bytes[msg->length - 1] = '\0'; Log_keys(hermes->logger, "Got message from angel [%s%c]", msg->bytes, lastChr); msg->bytes[msg->length - 1] = lastChr; #else Log_debug(hermes->logger, "Got message from angel"); #endif Dict* d = NULL; char* err = BencMessageReader_readNoExcept(msg, tempAlloc, &d); if (err) { Log_warn(hermes->logger, "Failed to parse message from angel [%s]", err); return; } String* txid = Dict_getString(d, String_CONST("txid")); uint32_t handle; if (!txid || txid->len != 8 || 4 != Hex_decode((uint8_t*)&handle, 4, (uint8_t*)txid->bytes, 8)) { Log_warn(hermes->logger, "Message from angel; txid missing or unrecognized"); return; } int index = Map_RequestSet_indexForHandle(handle, &hermes->requestSet); if (index < 0) { Log_warn(hermes->logger, "Message from angel references nonexistant request"); return; } struct Request* req = Identity_check((struct Request*) hermes->requestSet.values[index]); req->onResponse(d, req->onResponseContext); Allocator_free(req->alloc); }
int SSLi_nonblockaccept( SSL_handle_t *session, bool_t * isSSLReady ) { int error; do { error = gnutls_handshake(*session); } while(error < GNUTLS_E_SUCCESS && !gnutls_error_is_fatal(error)); if ( error < GNUTLS_E_SUCCESS ) { Log_warn("TLS handshake failed with error %i (%s).", error, gnutls_strerror(error)); } if(isSSLReady) *isSSLReady = true; return error; }
void SSLi_init() { unsigned const bitCount = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, GNUTLS_SEC_PARAM_MEDIUM); gnutls_priority_init(&cipherCache, ciphers, NULL); initializeCertificate(); gnutls_dh_params_init(&dhParameters); Log_info("Generating Diffie-Hellman parameters (%i bits)", bitCount); int error = gnutls_dh_params_generate2(dhParameters, bitCount); if(!error) { Log_info("Successfully generated Diffie-Hellman parameters"); } else { Log_warn("Failed to generate Diffie-Hellman parameters: %s", gnutls_strerror(error)); } gnutls_certificate_set_dh_params(certificate, dhParameters); Log_info("Sucessfully initialized GNUTLS version %s", gnutls_check_version(NULL)); }
static void udpInterface(Dict* config, struct Context* ctx) { List* ifaces = Dict_getList(config, String_CONST("UDPInterface")); if (!ifaces) { ifaces = List_new(ctx->alloc); List_addDict(ifaces, Dict_getDict(config, String_CONST("UDPInterface")), ctx->alloc); } uint32_t count = List_size(ifaces); for (uint32_t i = 0; i < count; i++) { Dict *udp = List_getDict(ifaces, i); if (!udp) { continue; } // Setup the interface. String* bindStr = Dict_getString(udp, String_CONST("bind")); Dict* d = Dict_new(ctx->alloc); if (bindStr) { Dict_putString(d, String_CONST("bindAddress"), bindStr, ctx->alloc); } Dict* resp = NULL; rpcCall0(String_CONST("UDPInterface_new"), d, ctx, ctx->alloc, &resp, true); int ifNum = *(Dict_getInt(resp, String_CONST("interfaceNumber"))); // Make the connections. Dict* connectTo = Dict_getDict(udp, String_CONST("connectTo")); if (connectTo) { struct Dict_Entry* entry = *connectTo; struct Allocator* perCallAlloc = Allocator_child(ctx->alloc); while (entry != NULL) { String* key = (String*) entry->key; if (entry->val->type != Object_DICT) { Log_critical(ctx->logger, "interfaces.UDPInterface.connectTo: entry [%s] " "is not a dictionary type.", key->bytes); exit(-1); } Dict* all = entry->val->as.dictionary; Dict* value = Dict_new(perCallAlloc); String* pub_d = Dict_getString(all, String_CONST("publicKey")); String* pss_d = Dict_getString(all, String_CONST("password")); String* peerName_d = Dict_getString(all, String_CONST("peerName")); String* login_d = Dict_getString(all, String_CONST("login")); if ( !pub_d || !pss_d ) { const char * error_name = "(unknown)"; if ( !pub_d ) { error_name = "publicKey"; } if ( !pss_d ) { error_name = "password"; } Log_warn(ctx->logger, "Skipping peer: missing %s for peer [%s]", error_name, key->bytes); if (abort_if_invalid_ref) { Assert_failure("Invalid peer reference"); } else { entry = entry->next; continue; } } Dict_putString(value, String_CONST("publicKey"), pub_d, perCallAlloc); Dict_putString(value, String_CONST("password"), pss_d, perCallAlloc); Dict_putString(value, String_CONST("peerName"), peerName_d, perCallAlloc); Dict_putString(value, String_CONST("login"), login_d, perCallAlloc); Log_keys(ctx->logger, "Attempting to connect to node [%s].", key->bytes); key = String_clone(key, perCallAlloc); char* lastColon = CString_strrchr(key->bytes, ':'); if (!Sockaddr_parse(key->bytes, NULL)) { // it's a sockaddr, fall through } else if (lastColon) { // try it as a hostname. int port = atoi(lastColon+1); if (!port) { Log_critical(ctx->logger, "Couldn't get port number from [%s]", key->bytes); exit(-1); } *lastColon = '\0'; struct Sockaddr* adr = Sockaddr_fromName(key->bytes, perCallAlloc); if (adr != NULL) { Sockaddr_setPort(adr, port); key = String_new(Sockaddr_print(adr, perCallAlloc), perCallAlloc); } else { Log_warn(ctx->logger, "Failed to lookup hostname [%s]", key->bytes); entry = entry->next; continue; } } struct Allocator* child = Allocator_child(ctx->alloc); struct Message* msg = Message_new(0, AdminClient_MAX_MESSAGE_SIZE + 256, child); int r = BencMessageWriter_writeDictTry(value, msg, NULL); const int max_reference_size = 298; if (r != 0 || msg->length > max_reference_size) { Log_warn(ctx->logger, "Peer skipped:"); Log_warn(ctx->logger, "Too long peer reference for [%s]", key->bytes); if (abort_if_invalid_ref) { Assert_failure("Invalid peer reference"); } else { entry = entry->next; continue; } } Dict_putInt(value, String_CONST("interfaceNumber"), ifNum, perCallAlloc); Dict_putString(value, String_CONST("address"), key, perCallAlloc); rpcCall(String_CONST("UDPInterface_beginConnection"), value, ctx, perCallAlloc); entry = entry->next; } Allocator_free(perCallAlloc); } } }
int main (int argc, char**argv) { int ret = 0; int heartbeat_usec = 50000; //20Hz is ok by default uint64_t last_beat = 0; Log_info ("cloudvpn starting"); Log (0, "You are using CloudVPN, which is Free software."); Log (0, "For more information please see the GNU GPL license,"); Log (0, "which you should have received along with this program."); setup_sighandler (kill_cloudvpn); /* * initialization */ if (!config_parse (argc, argv) ) { Log_error ("failed to parse config, terminating."); ret = 1; goto failed_config; } if (!config_get_int ("heartbeat", heartbeat_usec) ) heartbeat_usec = 50000; Log_info ("heartbeat is set to %d usec", heartbeat_usec); timestamp_update(); //get initial timestamp status_init(); route_init(); squeue_init(); network_init(); if (poll_init() ) { Log_fatal ("poll initialization failed"); ret = 2; goto failed_poll; } if (do_memlock() ) { Log_fatal ("locking process to memory failed"); ret = 3; goto failed_poll; } if (comm_load() ) { Log_fatal ("failed to load comm data"); ret = 4; goto failed_poll; } if (comm_init() ) { Log_fatal ("communication initialization failed"); ret = 5; goto failed_comm; } if (gate_init() ) { Log_fatal ("gate initialization failed"); ret = 6; goto failed_gate; } if (do_chroot() ) { Log_fatal ("chrooting failed"); ret = 7; goto failed_sec; } if (do_switch_user() ) { Log_fatal ("user switch failed"); ret = 8; goto failed_sec; } /* * main loop */ Log_info ("initialization complete, entering main loop"); last_beat = 0; //update immediately. while (!g_terminate) { timestamp_update(); if ( (timestamp() - last_beat) < (unsigned int) heartbeat_usec) { //poll more stuff poll_wait_for_event (heartbeat_usec - timestamp() + last_beat); //send the results comm_flush_data(); gate_flush_data(); continue; } last_beat = timestamp(); gate_periodic_update(); comm_periodic_update(); route_periodic_update(); status_try_export(); } /* * deinitialization */ Log_info ("shutting down"); failed_sec: gate_shutdown(); failed_gate: comm_shutdown(); failed_comm: if (poll_deinit() ) Log_warn ("poll_deinit somehow failed!"); failed_poll: failed_config: if (!ret) Log_info ("cloudvpn exiting gracefully"); else Log_error ("cloudvpn exiting with code %d", ret); return ret; }
void Server_run() { int timeout = 1000, rc; struct pollfd *pollfds; int tcpsock, sockopt = 1; struct sockaddr_in sin; int val, clientcount; etimer_t janitorTimer; unsigned short port; in_addr_t inet_address; /* max clients + listen sock + udp sock + client connecting that will be disconnected */ pollfds = malloc((getIntConf(MAX_CLIENTS) + 3) * sizeof(struct pollfd)); if (pollfds == NULL) Log_fatal("out of memory"); /* Figure out bind address and port */ if (bindport != 0) port = htons(bindport); else port = htons(getIntConf(BINDPORT)); if (bindaddr != NULL && inet_addr(bindaddr) != -1) inet_address = inet_addr(bindaddr); else if (inet_addr(getStrConf(BINDADDR)) != -1) inet_address = inet_addr(getStrConf(BINDADDR)); else inet_address = inet_addr("0.0.0.0"); Log_info("Bind to %s:%hu", inet_address == 0 ? "*" : inet_ntoa(*((struct in_addr *)&inet_address)), ntohs(port)); /* Prepare TCP socket */ memset(&sin, 0, sizeof(sin)); tcpsock = socket(PF_INET, SOCK_STREAM, 0); if (tcpsock < 0) Log_fatal("socket"); if (setsockopt(tcpsock, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(int)) != 0) Log_fatal("setsockopt: %s", strerror(errno)); sin.sin_family = AF_INET; sin.sin_port = port; sin.sin_addr.s_addr = inet_address; rc = bind(tcpsock, (struct sockaddr *) &sin, sizeof (struct sockaddr_in)); if (rc < 0) Log_fatal("bind: %s", strerror(errno)); rc = listen(tcpsock, 3); if (rc < 0) Log_fatal("listen"); fcntl(tcpsock, F_SETFL, O_NONBLOCK); pollfds[LISTEN_SOCK].fd = tcpsock; pollfds[LISTEN_SOCK].events = POLLIN; /* Prepare UDP socket */ memset(&sin, 0, sizeof(sin)); udpsock = socket(PF_INET, SOCK_DGRAM, 0); sin.sin_family = AF_INET; sin.sin_port = port; sin.sin_addr.s_addr = inet_address; rc = bind(udpsock, (struct sockaddr *) &sin, sizeof (struct sockaddr_in)); if (rc < 0) Log_fatal("bind %d %s: %s", getIntConf(BINDPORT), getStrConf(BINDADDR), strerror(errno)); val = 0xe0; rc = setsockopt(udpsock, IPPROTO_IP, IP_TOS, &val, sizeof(val)); if (rc < 0) Log_warn("Server: Failed to set TOS for UDP Socket"); val = 0x80; rc = setsockopt(udpsock, IPPROTO_IP, IP_TOS, &val, sizeof(val)); if (rc < 0) Log_warn("Server: Failed to set TOS for UDP Socket"); fcntl(udpsock, F_SETFL, O_NONBLOCK); pollfds[UDP_SOCK].fd = udpsock; pollfds[UDP_SOCK].events = POLLIN | POLLHUP | POLLERR; Timer_init(&janitorTimer); Log_info("uMurmur version %s ('%s') protocol version %d.%d.%d", UMURMUR_VERSION, UMURMUR_CODENAME, PROTVER_MAJOR, PROTVER_MINOR, PROTVER_PATCH); Log_info("Visit http://code.google.com/p/umurmur/"); /* Main server loop */ while (!shutdown_server) { struct sockaddr_in remote; int i; pollfds[UDP_SOCK].revents = 0; pollfds[TCP_SOCK].revents = 0; clientcount = Client_getfds(&pollfds[2]); timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL; if (timeout <= 0) { Client_janitor(); Timer_restart(&janitorTimer); timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL; } rc = poll(pollfds, clientcount + 2, timeout); if (rc == 0) { /* Timeout */ /* Do maintenance */ Timer_restart(&janitorTimer); Client_janitor(); continue; } if (rc < 0) { if (errno == EINTR) /* signal */ continue; else Log_fatal("poll: error %d", errno); } if (pollfds[LISTEN_SOCK].revents) { /* New tcp connection */ int tcpfd, flag = 1; uint32_t addrlen; addrlen = sizeof(struct sockaddr_in); tcpfd = accept(pollfds[LISTEN_SOCK].fd, (struct sockaddr*)&remote, &addrlen); fcntl(tcpfd, F_SETFL, O_NONBLOCK); setsockopt(tcpfd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)); Log_debug("Connection from %s port %d\n", inet_ntoa(remote.sin_addr), ntohs(remote.sin_port)); if (Client_add(tcpfd, &remote) < 0) close(tcpfd); } if (pollfds[UDP_SOCK].revents) { Client_read_udp(); } for (i = 0; i < clientcount; i++) { if (pollfds[i + 2].revents & POLLIN) { Client_read_fd(pollfds[i + 2].fd); } if (pollfds[i + 2].revents & POLLOUT) { Client_write_fd(pollfds[i + 2].fd); } } } /* Disconnect clients */ Client_disconnect_all(); free(pollfds); }
int main(int argc, char** argv) { if (argc > 1 && !strcmp("--genconf", argv[argc-1])) { genconf(); return 0; } struct Allocator* alloc = MallocAllocator_new(1<<22); struct EventBase* base = EventBase_new(alloc); struct Writer* logWriter = FileWriter_new(stdout, alloc); struct Log* logger = WriterLog_new(logWriter, alloc); struct Random* rand = Random_new(alloc, logger, NULL); struct Reader* stdinReader = FileReader_new(stdin, alloc); Dict config; if (JsonBencSerializer_get()->parseDictionary(stdinReader, alloc, &config)) { Log_critical(logger, "Failed to parse configuration"); return -1; } Dict* dns = Dict_getDict(&config, String_CONST("dns")); if (!dns) { Log_critical(logger, "No DNS in configuration"); return -1; } struct Sockaddr_storage addr; Assert_true(!Sockaddr_parse("::", &addr)); struct AddrInterface* ifaceB = UDPAddrInterface_new(base, &addr.addr, alloc, NULL, logger); struct RainflyClient* client = RainflyClient_new(ifaceB, base, rand, logger); String* bind = Dict_getString(dns, String_CONST("bind")); Assert_true(!Sockaddr_parse(bind ? bind->bytes : "[::]:5353", &addr)); struct AddrInterface* iface = UDPAddrInterface_new(base, &addr.addr, alloc, NULL, logger); struct DNSServer* dnsServer = DNSServer_new(iface, logger, client); List* auth = Dict_getList(dns, String_CONST("authorities")); for (int i = 0; i < (int)List_size(auth); i++) { String* str = List_getString(auth, i); if (!str) { Log_warn(logger, "Element [%d] in [dns.authorities] list of wrong type", i); continue; } uint8_t key[32] = {0}; if (str->len < 52 || Base32_decode(key, 32, str->bytes, 52) != 32) { Log_warn(logger, "Failed to parse key [%s]", str->bytes); continue; } if (RainflyClient_addKey(client, key)) { Log_warn(logger, "Failed to add key to RainflyClient [%s]", str->bytes); } } List* servers = Dict_getList(dns, String_CONST("servers")); for (int i = 0; i < (int)List_size(servers); i++) { String* str = List_getString(servers, i); if (!str) { Log_warn(logger, "Element [%d] in [dns.servers] list of wrong type", i); continue; } struct Sockaddr_storage node; if (Sockaddr_parse(str->bytes, &node)) { Log_warn(logger, "Failed to parse server name [%s]", str->bytes); continue; } if (RainflyClient_addServer(client, &node.addr)) { Log_warn(logger, "Failed to add server to RainflyClient [%s]", str->bytes); } } List* legacy = Dict_getList(dns, String_CONST("legacy")); for (int i = 0; i < (int)List_size(legacy); i++) { String* str = List_getString(legacy, i); if (!str) { Log_warn(logger, "Element [%d] in [dns.legacy] list of wrong type", i); continue; } struct Sockaddr_storage node; if (Sockaddr_parse(str->bytes, &node)) { Log_warn(logger, "Failed to parse legacy server name [%s]", str->bytes); continue; } if (DNSServer_addServer(dnsServer, &node.addr)) { Log_warn(logger, "Failed to add server to DNSServer [%s]", str->bytes); } } EventBase_beginLoop(base); }
int main(int argc, char** argv) { #ifdef Log_KEYS fprintf(stderr, "Log_LEVEL = KEYS, EXPECT TO SEE PRIVATE KEYS IN YOUR LOGS!\n"); #endif Assert_true(argc > 0); struct Except* eh = NULL; // Allow it to allocate 4MB struct Allocator* allocator = MallocAllocator_new(1<<22); struct Random* rand = Random_new(allocator, eh); struct EventBase* eventBase = EventBase_new(allocator); if (argc == 2) { // one argument if (strcmp(argv[1], "--help") == 0) { return usage(argv[0]); } else if (strcmp(argv[1], "--genconf") == 0) { return genconf(rand); } else if (strcmp(argv[1], "--pidfile") == 0) { // Performed after reading the configuration } else if (strcmp(argv[1], "--reconf") == 0) { // Performed after reading the configuration } else if (strcmp(argv[1], "--bench") == 0) { return benchmark(); } else if (strcmp(argv[1], "--version") == 0) { //printf("Version ID: %s\n", RouterModule_gitVersion()); return 0; } else { fprintf(stderr, "%s: unrecognized option '%s'\n", argv[0], argv[1]); fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]); return -1; } } else if (argc > 2) { // more than one argument? fprintf(stderr, "%s: too many arguments\n", argv[0]); fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]); return -1; } if (isatty(STDIN_FILENO)) { // We were started from a terminal // The chances an user wants to type in a configuration // bij hand are pretty slim so we show him the usage return usage(argv[0]); } else { // We assume stdin is a configuration file and that we should // start routing } struct Reader* stdinReader = FileReader_new(stdin, allocator); Dict config; if (JsonBencSerializer_get()->parseDictionary(stdinReader, allocator, &config)) { fprintf(stderr, "Failed to parse configuration.\n"); return -1; } struct Writer* logWriter = FileWriter_new(stdout, allocator); struct Log* logger = WriterLog_new(logWriter, allocator); // --------------------- Setup Pipes to Angel --------------------- // int pipeToAngel[2]; int pipeFromAngel[2]; if (Pipe_createUniPipe(pipeToAngel) || Pipe_createUniPipe(pipeFromAngel)) { Except_raise(eh, -1, "Failed to create pipes to angel [%s]", Errno_getString()); } char pipeToAngelStr[8]; snprintf(pipeToAngelStr, 8, "%d", pipeToAngel[0]); char pipeFromAngelStr[8]; snprintf(pipeFromAngelStr, 8, "%d", pipeFromAngel[1]); char* args[] = { "angel", pipeToAngelStr, pipeFromAngelStr, NULL }; // --------------------- Spawn Angel --------------------- // String* corePath = Dict_getString(&config, String_CONST("corePath")); String* privateKey = Dict_getString(&config, String_CONST("privateKey")); if (!corePath) { corePath = getCorePath(allocator); if (!corePath) { Except_raise(eh, -1, "Can't find a usable cjdns core executable, " "try specifying the location in your cjdroute.conf"); } else { Log_warn(logger, "Cjdns core executable was not specified in cjdroute.conf, " "guessing its location."); } } if (!privateKey) { Except_raise(eh, -1, "Need to specify privateKey."); } Log_info(logger, "Forking angel to background."); Process_spawn(corePath->bytes, args); // --------------------- Get Admin --------------------- // Dict* configAdmin = Dict_getDict(&config, String_CONST("admin")); String* adminPass = Dict_getString(configAdmin, String_CONST("password")); String* adminBind = Dict_getString(configAdmin, String_CONST("bind")); if (!adminPass) { adminPass = String_newBinary(NULL, 32, allocator); Random_base32(rand, (uint8_t*) adminPass->bytes, 32); adminPass->len = strlen(adminPass->bytes); } if (!adminBind) { adminBind = String_new("127.0.0.1:0", allocator); } // --------------------- Get user for angel to setuid() ---------------------- // String* securityUser = NULL; List* securityConf = Dict_getList(&config, String_CONST("security")); for (int i = 0; i < List_size(securityConf); i++) { securityUser = Dict_getString(List_getDict(securityConf, i), String_CONST("setuser")); if (securityUser) { break; } } // --------------------- Pre-Configure Angel ------------------------- // Dict* preConf = Dict_new(allocator); Dict* adminPreConf = Dict_new(allocator); Dict_putDict(preConf, String_CONST("admin"), adminPreConf, allocator); Dict_putString(adminPreConf, String_CONST("core"), corePath, allocator); Dict_putString(preConf, String_CONST("privateKey"), privateKey, allocator); Dict_putString(adminPreConf, String_CONST("bind"), adminBind, allocator); Dict_putString(adminPreConf, String_CONST("pass"), adminPass, allocator); if (securityUser) { Dict_putString(adminPreConf, String_CONST("user"), securityUser, allocator); } #define CONFIG_BUFF_SIZE 1024 uint8_t buff[CONFIG_BUFF_SIZE] = {0}; struct Writer* toAngelWriter = ArrayWriter_new(buff, CONFIG_BUFF_SIZE - 1, allocator); if (StandardBencSerializer_get()->serializeDictionary(toAngelWriter, preConf)) { Except_raise(eh, -1, "Failed to serialize pre-configuration"); } write(pipeToAngel[1], buff, toAngelWriter->bytesWritten(toAngelWriter)); Log_keys(logger, "Sent [%s] to angel process.", buff); // --------------------- Get Response from Angel --------------------- // uint32_t amount = Waiter_getData(buff, CONFIG_BUFF_SIZE, pipeFromAngel[0], eventBase, eh); Dict responseFromAngel; struct Reader* responseFromAngelReader = ArrayReader_new(buff, amount, allocator); if (StandardBencSerializer_get()->parseDictionary(responseFromAngelReader, allocator, &responseFromAngel)) { Except_raise(eh, -1, "Failed to parse pre-configuration response [%s]", buff); } // --------------------- Get Admin Addr/Port/Passwd --------------------- // Dict* responseFromAngelAdmin = Dict_getDict(&responseFromAngel, String_CONST("admin")); adminBind = Dict_getString(responseFromAngelAdmin, String_CONST("bind")); struct sockaddr_storage adminAddr; Bits_memset(&adminAddr, 0, sizeof(struct sockaddr_storage)); int adminAddrLen = sizeof(struct sockaddr_storage); if (!adminBind) { Except_raise(eh, -1, "didn't get address and port back from angel"); } if (evutil_parse_sockaddr_port(adminBind->bytes, (struct sockaddr*) &adminAddr, &adminAddrLen)) { Except_raise(eh, -1, "Unable to parse [%s] as an ip address port, eg: 127.0.0.1:11234", adminBind->bytes); } // --------------------- Configuration ------------------------- // Configurator_config(&config, (uint8_t*)&adminAddr, adminAddrLen, adminPass, eventBase, logger, allocator); return 0; }
static int handleOutgoing(struct DHTMessage* dmessage, void* vcontext) { struct Ducttape* context = (struct Ducttape*) vcontext; struct Message message = { .length = dmessage->length, .bytes = (uint8_t*) dmessage->bytes, .padding = 512 }; Message_shift(&message, Headers_UDPHeader_SIZE); struct Headers_UDPHeader* uh = (struct Headers_UDPHeader*) message.bytes; uh->sourceAndDestPorts = 0; uh->length_be = Endian_hostToBigEndian16(dmessage->length); uh->checksum_be = 0; uint16_t payloadLength = message.length; Message_shift(&message, Headers_IP6Header_SIZE); struct Headers_IP6Header* header = (struct Headers_IP6Header*) message.bytes; header->versionClassAndFlowLabel = 0; header->flowLabelLow_be = 0; header->nextHeader = 17; header->hopLimit = 0; header->payloadLength_be = Endian_hostToBigEndian16(payloadLength); Bits_memcpyConst(header->sourceAddr, context->myAddr.ip6.bytes, Address_SEARCH_TARGET_SIZE); Bits_memcpyConst(header->destinationAddr, dmessage->address->ip6.bytes, Address_SEARCH_TARGET_SIZE); context->ip6Header = header; context->switchHeader = NULL; sendToRouter(dmessage->address, &message, context); return 0; } // Aligned on the beginning of the content. static inline bool isRouterTraffic(struct Message* message, struct Headers_IP6Header* ip6) { if (ip6->nextHeader != 17 || ip6->hopLimit != 0) { return false; } struct Headers_UDPHeader* uh = (struct Headers_UDPHeader*) message->bytes; return message->length >= Headers_UDPHeader_SIZE && uh->sourceAndDestPorts == 0 && (int) Endian_bigEndianToHost16(uh->length_be) == message->length - Headers_UDPHeader_SIZE; } /** * Message which is for us, message is aligned on the beginning of the content. * this is called from core() which calls through an interfaceMap. */ static inline uint8_t incomingForMe(struct Message* message, struct Ducttape* context, uint8_t herPubKey[32]) { struct Address addr; AddressCalc_addressForPublicKey(addr.ip6.bytes, herPubKey); if (memcmp(addr.ip6.bytes, context->ip6Header->sourceAddr, 16)) { #ifdef Log_DEBUG uint8_t keyAddr[40]; Address_printIp(keyAddr, &addr); Bits_memcpyConst(addr.ip6.bytes, context->ip6Header->sourceAddr, 16); uint8_t srcAddr[40]; Address_printIp(srcAddr, &addr); Log_debug2(context->logger, "Dropped packet because source address is not same as key.\n" " %s source addr\n" " %s hash of key\n", srcAddr, keyAddr); #endif return Error_INVALID; } if (message->length == 0) { #ifdef Log_WARN uint8_t keyAddr[40]; uint8_t ipv6Hex[80]; Address_printIp(keyAddr, &addr); Hex_encode(ipv6Hex, 80, (uint8_t*) context->ip6Header, 40); Log_warn2(context->logger, "Got ipv6 packet from %s which has no content!\nIPv6 Header: [%s]", keyAddr, ipv6Hex); #endif return Error_INVALID; } if (isRouterTraffic(message, context->ip6Header)) { // Shift off the UDP header. Message_shift(message, -Headers_UDPHeader_SIZE); addr.path = Endian_bigEndianToHost64(context->switchHeader->label_be); Bits_memcpyConst(addr.key, herPubKey, 32); return incomingDHT(message, &addr, context); } // RouterModule_addNode(&addr, context->routerModule); if (!context->routerIf) { Log_warn(context->logger, "Dropping message because there is no router interface configured.\n"); return Error_UNDELIVERABLE; } // Now write a message to the TUN device. // Need to move the ipv6 header forward up to the content because there's a crypto header // between the ipv6 header and the content which just got eaten. Message_shift(message, Headers_IP6Header_SIZE); uint16_t sizeDiff = message->bytes - (uint8_t*)context->ip6Header; if (sizeDiff) { context->ip6Header->payloadLength_be = Endian_hostToBigEndian16( Endian_bigEndianToHost16(context->ip6Header->payloadLength_be) - sizeDiff); memmove(message->bytes, context->ip6Header, Headers_IP6Header_SIZE); } context->routerIf->sendMessage(message, context->routerIf); return Error_NONE; } uint8_t Ducttape_injectIncomingForMe(struct Message* message, struct Ducttape* context, uint8_t herPublicKey[32]) { struct Headers_SwitchHeader sh; Bits_memcpyConst(&sh, message->bytes, Headers_SwitchHeader_SIZE); context->switchHeader = &sh; Message_shift(message, -Headers_SwitchHeader_SIZE); struct Headers_IP6Header ip6; Bits_memcpyConst(&ip6, message->bytes, Headers_IP6Header_SIZE); context->ip6Header = &ip6; Message_shift(message, -Headers_IP6Header_SIZE); return incomingForMe(message, context, herPublicKey); } /** * Send a message to another switch. * Switchheader will precede the message. */ static inline uint8_t sendToSwitch(struct Message* message, struct Headers_SwitchHeader* destinationSwitchHeader, struct Ducttape* context) { Message_shift(message, Headers_SwitchHeader_SIZE); struct Headers_SwitchHeader* switchHeaderLocation = (struct Headers_SwitchHeader*) message->bytes; if (destinationSwitchHeader != switchHeaderLocation) { memmove(message->bytes, destinationSwitchHeader, Headers_SwitchHeader_SIZE); } return context->switchInterface.receiveMessage(message, &context->switchInterface); }
static void onReply(Dict* msg, struct Address* src, struct MsgCore_Promise* prom) { struct Query* q = Identity_check((struct Query*) prom->userData); struct SupernodeHunter_pvt* snp = Identity_check(q->snp); // TODO(cjd): if we sent a message to a discovered node, we should drop them from the list // if we sent to one of snodeCandidates then we need to drop it from that list. if (!src) { String* addrStr = Address_toString(prom->target, prom->alloc); Log_debug(snp->log, "timeout sending to %s", addrStr->bytes); return; } String* addrStr = Address_toString(src, prom->alloc); Log_debug(snp->log, "Reply from %s", addrStr->bytes); int64_t* snodeRecvTime = Dict_getIntC(msg, "recvTime"); if (q->isGetRoute) { //struct Address_List* al = ReplySerializer_parse(src, msg, snp->log, false, prom->alloc); if (!snodeRecvTime) { Log_warn(snp->log, "getRoute reply with no timeStamp, bad snode"); return; } Log_debug(snp->log, "\n\nSupernode location confirmed [%s]\n\n", Address_toString(src, prom->alloc)->bytes); Bits_memcpy(&snp->pub.snodeAddr, src, Address_SIZE); if (snp->pub.snodeIsReachable) { // If while we were searching, the outside code declared that indeed the snode // is reachable, we will not try to change their snode. } else if (snp->pub.onSnodeChange) { snp->pub.snodeIsReachable = true; snp->pub.onSnodeChange( snp->pub.userData, &snp->pub.snodeAddr, q->sendTime, *snodeRecvTime); } else { Log_warn(snp->log, "onSnodeChange is not set"); } } struct Address_List* results = ReplySerializer_parse(src, msg, snp->log, true, prom->alloc); if (!results) { Log_debug(snp->log, "reply without nodes"); return; } for (int i = 0; i < results->length; i++) { if (!q->searchTar) { // This is a getPeers Log_debug(snp->log, "getPeers reply [%s]", Address_toString(&results->elems[i], prom->alloc)->bytes); if (Address_isSameIp(&results->elems[i], snp->myAddress)) { continue; } if (snp->nodes->length >= SupernodeHunter_pvt_nodes_MAX) { AddrSet_flush(snp->nodes); } AddrSet_add(snp->nodes, &results->elems[i]); } else { if (!Bits_memcmp(&results->elems[i].ip6.bytes, q->searchTar->ip6.bytes, 16)) { Log_debug(snp->log, "\n\nFound a supernode w000t [%s]\n\n", Address_toString(&results->elems[i], prom->alloc)->bytes); if (snp->snodeCandidates->length >= SupernodeHunter_pvt_snodeCandidates_MAX) { AddrSet_flush(snp->snodeCandidates); } AddrSet_add(snp->snodeCandidates, &results->elems[i]); } else { //Log_debug(snp->log, "findNode reply [%s] to discard", // Address_toString(&results->elems[i], prom->alloc)->bytes); } } } }
void Server_run() { int timeout = 1000, rc; struct pollfd *pollfds; int tcpsock, sockopt = 1; struct sockaddr_storage sin; int val, clientcount; etimer_t janitorTimer; const char *port; const char *addr; struct addrinfo hints, *res; bool_t enable_ipv6; /* max clients + listen sock + udp sock + client connecting that will be disconnected */ pollfds = malloc((getIntConf(MAX_CLIENTS) + 3) * sizeof(struct pollfd)); if (pollfds == NULL) Log_fatal("out of memory"); /* Figure out bind address and port */ if (bindport != 0) port = bindport; else port = getStrConf(BINDPORT); if (bindaddr != 0) addr = bindaddr; else addr = getStrConf(BINDADDR); /* Prepare TCP socket */ enable_ipv6 = getBoolConf(ENABLE_IPV6); if (enable_ipv6) { /* Test if supported */ int testsock = socket(AF_INET6, SOCK_STREAM, 0); if (testsock < 0 && errno == EAFNOSUPPORT) { Log_warn("IPv6 is not supported on this machine. Falling back to IPv4."); enable_ipv6 = false; } if (testsock > 0) close(testsock); } memset(&hints, 0, sizeof hints); if (enable_ipv6) { hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE | AI_V4MAPPED; hints.ai_protocol = 0; } else { /* IPv4 */ hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; hints.ai_protocol = 0; } rc = getaddrinfo(addr, port, &hints, &res); if (rc != 0) Log_fatal("getaddrinfo: %s", gai_strerror(rc)); Log_info("Bind to [%s]:%s", addr ? addr : "::" , port); tcpsock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (tcpsock < 0) Log_fatal("socket: %s", strerror(errno)); if (setsockopt(tcpsock, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(int)) != 0) Log_fatal("setsockopt: %s",strerror(errno)); rc = bind(tcpsock, res->ai_addr, res->ai_addrlen); if (rc < 0) Log_fatal("bind: %s", strerror(errno)); rc = listen(tcpsock, 3); if (rc < 0) Log_fatal("listen"); fcntl(tcpsock, F_SETFL, O_NONBLOCK); pollfds[LISTEN_SOCK].fd = tcpsock; pollfds[LISTEN_SOCK].events = POLLIN; freeaddrinfo(res); /* Prepare UDP socket */ memset(&hints, 0, sizeof hints); if (enable_ipv6) { hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_DGRAM; hints.ai_flags = AI_PASSIVE | AI_V4MAPPED; hints.ai_protocol = 0; } else { /* IPv4 */ hints.ai_family = AF_INET; hints.ai_socktype = SOCK_DGRAM; hints.ai_flags = AI_PASSIVE; hints.ai_protocol = 0; } rc = getaddrinfo(addr, port, &hints, &res); if (rc != 0) Log_fatal("getaddrinfo: %s", gai_strerror(rc)); udpsock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); rc = bind(udpsock, res->ai_addr, res->ai_addrlen); if (rc < 0) Log_fatal("bind %d %s: %s", bindport, bindaddr, strerror(errno)); val = 0xe0; rc = setsockopt(udpsock, IPPROTO_IP, IP_TOS, &val, sizeof(val)); if (rc < 0) Log_warn("Server: Failed to set TOS for UDP Socket"); val = 0x80; rc = setsockopt(udpsock, IPPROTO_IP, IP_TOS, &val, sizeof(val)); if (rc < 0) Log_warn("Server: Failed to set TOS for UDP Socket"); fcntl(udpsock, F_SETFL, O_NONBLOCK); listen(udpsock, 10); pollfds[UDP_SOCK].fd = udpsock; pollfds[UDP_SOCK].events = POLLIN | POLLHUP | POLLERR; freeaddrinfo(res); Timer_init(&janitorTimer); Log_info("uMurmur version %s ('%s') protocol version %d.%d.%d", UMURMUR_VERSION, UMURMUR_CODENAME, PROTVER_MAJOR, PROTVER_MINOR, PROTVER_PATCH); Log_info("Visit http://code.google.com/p/umurmur/"); /* Main server loop */ while (!shutdown_server) { struct sockaddr_storage remote; int i; pollfds[UDP_SOCK].revents = 0; pollfds[TCP_SOCK].revents = 0; clientcount = Client_getfds(&pollfds[2]); timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL; if (timeout <= 0) { Client_janitor(); Timer_restart(&janitorTimer); timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL; } rc = poll(pollfds, clientcount + 2, timeout); if (rc == 0) { /* Timeout */ /* Do maintenance */ Timer_restart(&janitorTimer); Client_janitor(); continue; } if (rc < 0) { if (errno == EINTR) /* signal */ continue; else Log_fatal("poll: error %d", errno); } if (pollfds[LISTEN_SOCK].revents) { /* New tcp connection */ int tcpfd, flag = 1; uint32_t addrlen; addrlen = sizeof(struct sockaddr_storage); tcpfd = accept(pollfds[LISTEN_SOCK].fd, (struct sockaddr*)&remote, &addrlen); fcntl(tcpfd, F_SETFL, O_NONBLOCK); setsockopt(tcpfd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)); Log_debug("Connection from %s port %d\n", inet_ntoa(remote.sin_addr), ntohs(remote.sin_port)); if (Client_add(tcpfd, &remote) < 0) close(tcpfd); } if (pollfds[UDP_SOCK].revents) { Client_read_udp(); } for (i = 0; i < clientcount; i++) { if (pollfds[i + 2].revents & POLLIN) { Client_read_fd(pollfds[i + 2].fd); } if (pollfds[i + 2].revents & POLLOUT) { Client_write_fd(pollfds[i + 2].fd); } } } /* Disconnect clients */ Client_disconnect_all(); free(pollfds); }
// Called by the TUN device. static inline uint8_t incomingFromTun(struct Message* message, struct Interface* iface) { struct Ducttape_pvt* context = Identity_cast((struct Ducttape_pvt*) iface->receiverContext); uint16_t ethertype = TUNMessageType_pop(message); struct Headers_IP6Header* header = (struct Headers_IP6Header*) message->bytes; int version = Headers_getIpVersion(message->bytes); if ((ethertype == Ethernet_TYPE_IP4 && version != 4) || (ethertype == Ethernet_TYPE_IP6 && version != 6)) { Log_warn(context->logger, "dropped packet because ip version [%d] " "doesn't match ethertype [%u].", version, Endian_bigEndianToHost16(ethertype)); return Error_INVALID; } if (ethertype != Ethernet_TYPE_IP6 || !AddressCalc_validAddress(header->sourceAddr)) { return context->ipTunnel->tunInterface.sendMessage(message, &context->ipTunnel->tunInterface); } if (Bits_memcmp(header->sourceAddr, context->myAddr.ip6.bytes, 16)) { uint8_t expectedSource[40]; AddrTools_printIp(expectedSource, context->myAddr.ip6.bytes); uint8_t packetSource[40]; AddrTools_printIp(packetSource, header->sourceAddr); Log_warn(context->logger, "dropped packet from [%s] because all messages must have source address [%s]", (char*) packetSource, (char*) expectedSource); return Error_INVALID; } if (!Bits_memcmp(header->destinationAddr, context->myAddr.ip6.bytes, 16)) { // I'm Gonna Sit Right Down and Write Myself a Letter TUNMessageType_push(message, ethertype); iface->sendMessage(message, iface); return Error_NONE; } struct Ducttape_MessageHeader* dtHeader = getDtHeader(message, true); struct Node* bestNext = RouterModule_lookup(header->destinationAddr, context->routerModule); struct SessionManager_Session* nextHopSession; if (bestNext) { nextHopSession = SessionManager_getSession(bestNext->address.ip6.bytes, bestNext->address.key, context->sm); bestNext->version = nextHopSession->version = (bestNext->version > nextHopSession->version) ? bestNext->version : nextHopSession->version; dtHeader->switchLabel = bestNext->address.path; dtHeader->nextHopReceiveHandle = Endian_bigEndianToHost32(nextHopSession->receiveHandle_be); if (!Bits_memcmp(header->destinationAddr, bestNext->address.ip6.bytes, 16)) { // Direct send, skip the innermost layer of encryption. #ifdef Log_DEBUG uint8_t nhAddr[60]; Address_print(nhAddr, &bestNext->address); Log_debug(context->logger, "Forwarding data to %s (last hop)\n", nhAddr); #endif return sendToRouter(message, dtHeader, nextHopSession, context); } // else { the message will need to be 3 layer encrypted but since we already did a lookup // of the best node to forward to, we can skip doing another lookup by storing a pointer // to that node in the context (bestNext). } else { #ifdef Log_WARN uint8_t thisAddr[40]; uint8_t destAddr[40]; AddrTools_printIp(thisAddr, context->myAddr.ip6.bytes); AddrTools_printIp(destAddr, header->destinationAddr); Log_warn(context->logger, "Dropped message from TUN because this node [%s] is closest to dest [%s]", thisAddr, destAddr); #endif return Error_UNDELIVERABLE; } #ifdef Log_DEBUG uint8_t destAddr[40]; AddrTools_printIp(destAddr, header->destinationAddr); uint8_t nhAddr[60]; Address_print(nhAddr, &bestNext->address); Log_debug(context->logger, "Sending to [%s] via [%s]", destAddr, nhAddr); #endif struct SessionManager_Session* session = SessionManager_getSession(header->destinationAddr, NULL, context->sm); // Copy the IP6 header back from where the CA header will be placed. // this is a mess. // We can't just copy the header to a safe place because the CryptoAuth // might buffer the message and send a connect-to-me packet and when the // hello packet comes in return, the CA will send the message and the header // needs to be in the message buffer. // // The CryptoAuth may send a 120 byte CA header and it might only send a 4 byte // nonce and 16 byte authenticator depending on its state. if (CryptoAuth_getState(&session->iface) < CryptoAuth_HANDSHAKE3) { // shift, copy, shift because shifting asserts that there is enough buffer space. Message_shift(message, Headers_CryptoAuth_SIZE + 4); Bits_memcpyConst(message->bytes, header, Headers_IP6Header_SIZE); Message_shift(message, -(Headers_IP6Header_SIZE + Headers_CryptoAuth_SIZE + 4)); // now push the receive handle *under* the CA header. Message_push(message, &session->receiveHandle_be, 4); debugHandles0(context->logger, session, "layer3 sending start message"); } else { // shift, copy, shift because shifting asserts that there is enough buffer space. Message_shift(message, 20); Bits_memmoveConst(message->bytes, header, Headers_IP6Header_SIZE); Message_shift(message, -(20 + Headers_IP6Header_SIZE)); debugHandles0(context->logger, session, "layer3 sending run message"); } // This comes out at outgoingFromCryptoAuth() then outgoingFromMe() dtHeader->receiveHandle = Endian_bigEndianToHost32(session->receiveHandle_be); dtHeader->layer = Ducttape_SessionLayer_INNER; return session->iface.sendMessage(message, &session->iface); }
static int handleOutgoing(struct DHTMessage* dmessage, void* vcontext) { struct Ducttape_pvt* context = Identity_cast((struct Ducttape_pvt*) vcontext); struct Message message = { .length = dmessage->length, .bytes = (uint8_t*) dmessage->bytes, .padding = 512, .capacity = DHTMessage_MAX_SIZE }; Message_shift(&message, Headers_UDPHeader_SIZE); struct Headers_UDPHeader* uh = (struct Headers_UDPHeader*) message.bytes; uh->sourceAndDestPorts = 0; uh->length_be = Endian_hostToBigEndian16(dmessage->length); uh->checksum_be = 0; uint16_t payloadLength = message.length; Message_shift(&message, Headers_IP6Header_SIZE); struct Headers_IP6Header* header = (struct Headers_IP6Header*) message.bytes; header->versionClassAndFlowLabel = 0; header->flowLabelLow_be = 0; header->nextHeader = 17; header->hopLimit = 0; header->payloadLength_be = Endian_hostToBigEndian16(payloadLength); Bits_memcpyConst(header->sourceAddr, context->myAddr.ip6.bytes, Address_SEARCH_TARGET_SIZE); Bits_memcpyConst(header->destinationAddr, dmessage->address->ip6.bytes, Address_SEARCH_TARGET_SIZE); #ifdef Log_DEBUG Assert_true(!((uintptr_t)dmessage->bytes % 4) || !"alignment fault"); #endif uh->checksum_be = Checksum_udpIp6(header->sourceAddr, (uint8_t*) uh, message.length - Headers_IP6Header_SIZE); struct Ducttape_MessageHeader* dtHeader = getDtHeader(&message, true); dtHeader->ip6Header = header; dtHeader->switchLabel = dmessage->address->path; struct SessionManager_Session* session = SessionManager_getSession(dmessage->address->ip6.bytes, dmessage->address->key, context->sm); if (session->version == Version_DEFAULT_ASSUMPTION && dmessage->replyTo) { int64_t* verPtr = Dict_getInt(dmessage->replyTo->asDict, String_CONST("p")); session->version = (verPtr) ? *verPtr : Version_DEFAULT_ASSUMPTION; } if (session->version == Version_DEFAULT_ASSUMPTION) { struct Node* n = RouterModule_getNode(dmessage->address->path, context->routerModule); if (n) { n->version = session->version = (n->version > session->version) ? n->version : session->version; } } sendToRouter(&message, dtHeader, session, context); return 0; } // Aligned on the beginning of the content. static inline bool isRouterTraffic(struct Message* message, struct Headers_IP6Header* ip6) { if (ip6->nextHeader != 17 || ip6->hopLimit != 0) { return false; } struct Headers_UDPHeader* uh = (struct Headers_UDPHeader*) message->bytes; return message->length >= Headers_UDPHeader_SIZE && uh->sourceAndDestPorts == 0 && (int) Endian_bigEndianToHost16(uh->length_be) == (message->length - Headers_UDPHeader_SIZE); } #define debugHandles(logger, session, message, ...) \ do { \ uint8_t ip[40]; \ AddrTools_printIp(ip, session->ip6); \ Log_debug(logger, "ver[%u] send[%d] recv[%u] ip[%s] " message, \ session->version, \ Endian_hostToBigEndian32(session->sendHandle_be), \ Endian_hostToBigEndian32(session->receiveHandle_be), \ ip, \ __VA_ARGS__); \ } while (0) //CHECKFILES_IGNORE expecting a ; #define debugHandles0(logger, session, message) \ debugHandles(logger, session, message "%s", "") #define debugHandlesAndLabel(logger, session, label, message, ...) \ do { \ uint8_t path[20]; \ AddrTools_printPath(path, label); \ debugHandles(logger, session, "path[%s] " message, path, __VA_ARGS__); \ } while (0) //CHECKFILES_IGNORE expecting a ; #define debugHandlesAndLabel0(logger, session, label, message) \ debugHandlesAndLabel(logger, session, label, "%s", message) /** * Message which is for us, message is aligned on the beginning of the content. * this is called from core() which calls through an interfaceMap. */ static inline uint8_t incomingForMe(struct Message* message, struct Ducttape_MessageHeader* dtHeader, struct SessionManager_Session* session, struct Ducttape_pvt* context, uint8_t herPublicKey[32]) { struct Address addr; Bits_memcpyConst(addr.ip6.bytes, session->ip6, 16); //AddressCalc_addressForPublicKey(addr.ip6.bytes, herPubKey); if (Bits_memcmp(addr.ip6.bytes, dtHeader->ip6Header->sourceAddr, 16)) { #ifdef Log_DEBUG uint8_t keyAddr[40]; Address_printIp(keyAddr, &addr); Bits_memcpyConst(addr.ip6.bytes, dtHeader->ip6Header->sourceAddr, 16); uint8_t srcAddr[40]; Address_printIp(srcAddr, &addr); Log_debug(context->logger, "Dropped packet because source address is not same as key.\n" " %s source addr\n" " %s hash of key\n", srcAddr, keyAddr); #endif return Error_INVALID; } if (isRouterTraffic(message, dtHeader->ip6Header)) { // Check the checksum. struct Headers_UDPHeader* uh = (struct Headers_UDPHeader*) message->bytes; if (Checksum_udpIp6(dtHeader->ip6Header->sourceAddr, (uint8_t*)uh, message->length)) { #ifdef Log_DEBUG uint8_t keyAddr[40]; Address_printIp(keyAddr, &addr); Log_debug(context->logger, "Router packet with incorrect checksum, from [%s]", keyAddr); #endif return Error_INVALID; } // Shift off the UDP header. Message_shift(message, -Headers_UDPHeader_SIZE); addr.path = Endian_bigEndianToHost64(dtHeader->switchHeader->label_be); Bits_memcpyConst(addr.key, herPublicKey, 32); return incomingDHT(message, &addr, context); } if (!context->userIf) { Log_warn(context->logger, "Dropping message because there is no router interface configured.\n"); return Error_UNDELIVERABLE; } // prevent router advertizement schenanigans if (dtHeader->ip6Header->hopLimit == 255) { dtHeader->ip6Header->hopLimit--; } // Now write a message to the TUN device. // Need to move the ipv6 header forward up to the content because there's a crypto header // between the ipv6 header and the content which just got eaten. Message_shift(message, Headers_IP6Header_SIZE); uint16_t sizeDiff = message->bytes - (uint8_t*)dtHeader->ip6Header; if (sizeDiff) { dtHeader->ip6Header->payloadLength_be = Endian_hostToBigEndian16( Endian_bigEndianToHost16(dtHeader->ip6Header->payloadLength_be) - sizeDiff); Bits_memmoveConst(message->bytes, dtHeader->ip6Header, Headers_IP6Header_SIZE); } TUNMessageType_push(message, Ethernet_TYPE_IP6); context->userIf->sendMessage(message, context->userIf); return Error_NONE; } uint8_t Ducttape_injectIncomingForMe(struct Message* message, struct Ducttape* dt, uint8_t herPublicKey[32]) { struct Ducttape_pvt* context = Identity_cast((struct Ducttape_pvt*)dt); struct Ducttape_MessageHeader* dtHeader = getDtHeader(message, true); struct Headers_SwitchHeader sh; Bits_memcpyConst(&sh, message->bytes, Headers_SwitchHeader_SIZE); dtHeader->switchHeader = &sh; Message_shift(message, -Headers_SwitchHeader_SIZE); struct Headers_IP6Header ip6; Bits_memcpyConst(&ip6, message->bytes, Headers_IP6Header_SIZE); dtHeader->ip6Header = &ip6; Message_shift(message, -Headers_IP6Header_SIZE); struct SessionManager_Session s; AddressCalc_addressForPublicKey(s.ip6, herPublicKey); s.version = Version_CURRENT_PROTOCOL; return incomingForMe(message, dtHeader, &s, context, herPublicKey); } /** * Send a message to another switch. * Switchheader will precede the message. */ static inline uint8_t sendToSwitch(struct Message* message, struct Ducttape_MessageHeader* dtHeader, struct SessionManager_Session* session, struct Ducttape_pvt* context) { uint64_t label = dtHeader->switchLabel; if (CryptoAuth_getState(&session->iface) >= CryptoAuth_HANDSHAKE3) { debugHandlesAndLabel0(context->logger, session, label, "layer2 sending run message"); uint32_t sendHandle_be = session->sendHandle_be; #ifdef Version_2_COMPAT if (session->version < 3) { sendHandle_be |= HANDLE_FLAG_BIT_be; } #endif Message_push(message, &sendHandle_be, 4); } else { debugHandlesAndLabel0(context->logger, session, label, "layer2 sending start message"); #ifdef Version_2_COMPAT if (session->version < 3) { Message_push(message, &session->receiveHandle_be, 4); } #endif } Message_shift(message, Headers_SwitchHeader_SIZE); Assert_true(message->bytes == (uint8_t*)dtHeader->switchHeader); return context->switchInterface.receiveMessage(message, &context->switchInterface); }
static void ethInterface(Dict* config, struct Context* ctx) { List* ifaces = Dict_getList(config, String_CONST("ETHInterface")); if (!ifaces) { ifaces = List_new(ctx->alloc); List_addDict(ifaces, Dict_getDict(config, String_CONST("ETHInterface")), ctx->alloc); } uint32_t count = List_size(ifaces); for (uint32_t i = 0; i < count; i++) { Dict *eth = List_getDict(ifaces, i); if (!eth) { continue; } String* deviceStr = Dict_getString(eth, String_CONST("bind")); if (!deviceStr || !String_equals(String_CONST("all"), deviceStr)) { continue; } Log_info(ctx->logger, "Setting up all ETHInterfaces..."); Dict* res = NULL; Dict* d = Dict_new(ctx->alloc); if (rpcCall0(String_CONST("ETHInterface_listDevices"), d, ctx, ctx->alloc, &res, false)) { Log_info(ctx->logger, "Getting device list failed"); break; } List* devs = Dict_getList(res, String_CONST("devices")); uint32_t devCount = List_size(devs); for (uint32_t j = 0; j < devCount; j++) { Dict* d = Dict_new(ctx->alloc); String* deviceName = List_getString(devs, j); // skip loopback... if (String_equals(String_CONST("lo"), deviceName)) { continue; } Dict_putString(d, String_CONST("bindDevice"), deviceName, ctx->alloc); Dict* resp; Log_info(ctx->logger, "Creating new ETHInterface [%s]", deviceName->bytes); if (rpcCall0(String_CONST("ETHInterface_new"), d, ctx, ctx->alloc, &resp, false)) { Log_warn(ctx->logger, "Failed to create ETHInterface."); continue; } int ifNum = *(Dict_getInt(resp, String_CONST("interfaceNumber"))); ethInterfaceSetBeacon(ifNum, eth, ctx); } return; } for (uint32_t i = 0; i < count; i++) { Dict *eth = List_getDict(ifaces, i); if (!eth) { continue; } // Setup the interface. String* deviceStr = Dict_getString(eth, String_CONST("bind")); Log_info(ctx->logger, "Setting up ETHInterface [%d].", i); Dict* d = Dict_new(ctx->alloc); if (deviceStr) { Log_info(ctx->logger, "Binding to device [%s].", deviceStr->bytes); Dict_putString(d, String_CONST("bindDevice"), deviceStr, ctx->alloc); } Dict* resp = NULL; if (rpcCall0(String_CONST("ETHInterface_new"), d, ctx, ctx->alloc, &resp, false)) { Log_warn(ctx->logger, "Failed to create ETHInterface."); continue; } int ifNum = *(Dict_getInt(resp, String_CONST("interfaceNumber"))); ethInterfaceSetBeacon(ifNum, eth, ctx); // Make the connections. Dict* connectTo = Dict_getDict(eth, String_CONST("connectTo")); if (connectTo) { Log_info(ctx->logger, "ETHInterface should connect to a specific node."); struct Dict_Entry* entry = *connectTo; while (entry != NULL) { String* key = (String*) entry->key; if (entry->val->type != Object_DICT) { Log_critical(ctx->logger, "interfaces.ETHInterface.connectTo: entry [%s] " "is not a dictionary type.", key->bytes); exit(-1); } Dict* value = entry->val->as.dictionary; Log_keys(ctx->logger, "Attempting to connect to node [%s].", key->bytes); struct Allocator* perCallAlloc = Allocator_child(ctx->alloc); // Turn the dict from the config into our RPC args dict by filling in all // the arguments, Dict_putString(value, String_CONST("macAddress"), key, perCallAlloc); Dict_putInt(value, String_CONST("interfaceNumber"), ifNum, perCallAlloc); rpcCall(String_CONST("ETHInterface_beginConnection"), value, ctx, perCallAlloc); Allocator_free(perCallAlloc); entry = entry->next; } } } }
static void udpInterface(Dict* config, struct Context* ctx) { List* ifaces = Dict_getList(config, String_CONST("UDPInterface")); if (!ifaces) { ifaces = List_addDict(ifaces, Dict_getDict(config, String_CONST("UDPInterface")), ctx->alloc); } uint32_t count = List_size(ifaces); for (uint32_t i = 0; i < count; i++) { Dict *udp = List_getDict(ifaces, i); if (!udp) { continue; } // Setup the interface. String* bindStr = Dict_getString(udp, String_CONST("bind")); Dict* d = Dict_new(ctx->alloc); if (bindStr) { Dict_putString(d, String_CONST("bindAddress"), bindStr, ctx->alloc); } rpcCall(String_CONST("UDPInterface_new"), d, ctx, ctx->alloc); // Make the connections. Dict* connectTo = Dict_getDict(udp, String_CONST("connectTo")); if (connectTo) { struct Dict_Entry* entry = *connectTo; struct Allocator* perCallAlloc = Allocator_child(ctx->alloc); while (entry != NULL) { String* key = (String*) entry->key; if (entry->val->type != Object_DICT) { Log_critical(ctx->logger, "interfaces.UDPInterface.connectTo: entry [%s] " "is not a dictionary type.", key->bytes); exit(-1); } Dict* value = entry->val->as.dictionary; Log_keys(ctx->logger, "Attempting to connect to node [%s].", key->bytes); key = String_clone(key, perCallAlloc); char* lastColon = strrchr(key->bytes, ':'); if (!Sockaddr_parse(key->bytes, NULL)) { // it's a sockaddr, fall through } else if (lastColon) { // try it as a hostname. int port = atoi(lastColon+1); if (!port) { Log_critical(ctx->logger, "Couldn't get port number from [%s]", key->bytes); exit(-1); } *lastColon = '\0'; struct Sockaddr* adr = Sockaddr_fromName(key->bytes, perCallAlloc); if (adr != NULL) { Sockaddr_setPort(adr, port); key = String_new(Sockaddr_print(adr, perCallAlloc), perCallAlloc); } else { Log_warn(ctx->logger, "Failed to lookup hostname [%s]", key->bytes); entry = entry->next; continue; } } Dict_putString(value, String_CONST("address"), key, perCallAlloc); rpcCall(String_CONST("UDPInterface_beginConnection"), value, ctx, perCallAlloc); entry = entry->next; } Allocator_free(perCallAlloc); } } }
int main(int argc, char** argv) { #ifdef Log_KEYS fprintf(stderr, "Log_LEVEL = KEYS, EXPECT TO SEE PRIVATE KEYS IN YOUR LOGS!\n"); #endif Crypto_init(); Assert_true(argc > 0); if (argc == 2) { // one argument if (strcmp(argv[1], "--help") == 0) { return usage(argv[0]); } else if (strcmp(argv[1], "--genconf") == 0) { return genconf(); } else if (strcmp(argv[1], "--pidfile") == 0) { // Performed after reading the configuration } else if (strcmp(argv[1], "--reconf") == 0) { // Performed after reading the configuration } else if (strcmp(argv[1], "--bench") == 0) { return benchmark(); } else if (strcmp(argv[1], "--version") == 0) { printf("Version ID: %s\n", RouterModule_gitVersion()); return 0; } else { fprintf(stderr, "%s: unrecognized option '%s'\n", argv[0], argv[1]); fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]); return -1; } } else if (argc > 2) { // more than one argument? fprintf(stderr, "%s: too many arguments\n", argv[0]); fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]); return -1; } if (isatty(STDIN_FILENO)) { // We were started from a terminal // The chances an user wants to type in a configuration // bij hand are pretty slim so we show him the usage return usage(argv[0]); } else { // We assume stdin is a configuration file and that we should // start routing } struct event_base* eventBase = event_base_new(); // Allow it to allocate 4MB struct Allocator* allocator = MallocAllocator_new(1<<22); struct Reader* reader = FileReader_new(stdin, allocator); Dict config; if (JsonBencSerializer_get()->parseDictionary(reader, allocator, &config)) { fprintf(stderr, "Failed to parse configuration.\n"); return -1; } // Logging. struct Writer* logwriter = FileWriter_new(stdout, allocator); struct Log* logger = &(struct Log) { .writer = logwriter }; // pid file String* pidFile = Dict_getString(&config, String_CONST("pidFile")); if (pidFile) { if (argc == 2 && strcmp(argv[1], "--pidfile") == 0) { printf("%s", pidFile->bytes); return 0; } Log_info(logger, "Writing pid of process to [%s].\n", pidFile->bytes); FILE* pf = fopen(pidFile->bytes, "w"); if (!pf) { Log_critical(logger, "Failed to open pid file [%s] for writing, errno=%d\n", pidFile->bytes, errno); return -1; } fprintf(pf, "%d", (int) getpid()); fclose(pf); } // re-configure if (argc == 2 && strcmp(argv[1], "--reconf") == 0) { reconf(eventBase, &config, logger, allocator); return 0; } // ca, needed for admin. struct Address myAddr; uint8_t privateKey[32]; parsePrivateKey(&config, &myAddr, privateKey); struct CryptoAuth* cryptoAuth = CryptoAuth_new(&config, allocator, privateKey, eventBase, logger); // Admin char* user = setUser(Dict_getList(&config, String_CONST("security"))); struct Admin* admin = newAdmin(&config, user, logger, eventBase, allocator); struct SwitchCore* switchCore = SwitchCore_new(logger, allocator); struct DHTModuleRegistry* registry = DHTModuleRegistry_new(allocator); ReplyModule_register(registry, allocator); // Router struct Interface* routerIf = NULL; Dict* routerConf = Dict_getDict(&config, String_CONST("router")); Dict* iface = Dict_getDict(routerConf, String_CONST("interface")); if (String_equals(Dict_getString(iface, String_CONST("type")), String_CONST("TUNInterface"))) { String* ifName = Dict_getString(iface, String_CONST("tunDevice")); char assignedTunName[TUNConfigurator_IFNAMSIZ]; void* tunPtr = TUNConfigurator_initTun(((ifName) ? ifName->bytes : NULL), assignedTunName, logger, AbortHandler_INSTANCE); struct Jmp jmp; Jmp_try(jmp) { TUNConfigurator_setIpAddress( assignedTunName, myAddr.ip6.bytes, 8, logger, &jmp.handler); } Jmp_catch { Log_warn(logger, "Unable to configure ip address [%s]", jmp.message); } struct TUNInterface* tun = TUNInterface_new(tunPtr, eventBase, allocator); routerIf = &tun->iface; }
static void ethInterface(Dict* config, struct Context* ctx) { List* ifaces = Dict_getList(config, String_CONST("ETHInterface")); if (!ifaces) { ifaces = List_addDict(ifaces, Dict_getDict(config, String_CONST("ETHInterface")), ctx->alloc); } uint32_t count = List_size(ifaces); for (uint32_t i = 0; i < count; i++) { Dict *eth = List_getDict(ifaces, i); if (!eth) { continue; } // Setup the interface. String* deviceStr = Dict_getString(eth, String_CONST("bind")); Log_info(ctx->logger, "Setting up ETHInterface [%d].", i); Dict* d = Dict_new(ctx->alloc); if (deviceStr) { Log_info(ctx->logger, "Binding to device [%s].", deviceStr->bytes); Dict_putString(d, String_CONST("bindDevice"), deviceStr, ctx->alloc); } if (rpcCall0(String_CONST("ETHInterface_new"), d, ctx, ctx->alloc, false)) { Log_warn(ctx->logger, "Failed to create ETHInterface."); continue; } // Make the connections. Dict* connectTo = Dict_getDict(eth, String_CONST("connectTo")); if (connectTo) { Log_info(ctx->logger, "ETHInterface should connect to a specific node."); struct Dict_Entry* entry = *connectTo; while (entry != NULL) { String* key = (String*) entry->key; if (entry->val->type != Object_DICT) { Log_critical(ctx->logger, "interfaces.ETHInterface.connectTo: entry [%s] " "is not a dictionary type.", key->bytes); exit(-1); } Dict* value = entry->val->as.dictionary; Log_keys(ctx->logger, "Attempting to connect to node [%s].", key->bytes); struct Allocator* perCallAlloc = Allocator_child(ctx->alloc); // Turn the dict from the config into our RPC args dict by filling in all // the arguments, Dict_putString(value, String_CONST("macAddress"), key, perCallAlloc); Dict_putInt(value, String_CONST("interfaceNumber"), i, perCallAlloc); rpcCall(String_CONST("ETHInterface_beginConnection"), value, ctx, perCallAlloc); Allocator_free(perCallAlloc); entry = entry->next; } } int64_t* beaconP = Dict_getInt(eth, String_CONST("beacon")); if (beaconP) { int64_t beacon = *beaconP; if (beacon > 3 || beacon < 0) { Log_error(ctx->logger, "interfaces.ETHInterface.beacon may only be 0, 1,or 2"); } else { // We can cast beacon to an int here because we know it's small enough Log_info(ctx->logger, "Setting beacon mode on ETHInterface to [%d].", (int) beacon); Dict d = Dict_CONST(String_CONST("interfaceNumber"), Int_OBJ(i), Dict_CONST(String_CONST("state"), Int_OBJ(beacon), NULL)); rpcCall(String_CONST("ETHInterface_beacon"), &d, ctx, ctx->alloc); } } } }
void NodeStore_addNode(struct NodeStore* store, struct Address* addr, const int64_t reachDifference) { Address_getPrefix(addr); if (memcmp(addr->ip6.bytes, store->thisNodeAddress, 16) == 0) { printf("got introduced to ourselves\n"); return; } if (addr->ip6.bytes[0] != 0xfc) { uint8_t address[60]; Address_print(address, addr); Log_critical1(store->logger, "tried to insert address %s which does not begin with 0xFC.\n", address); assert(false); } // TODO: maintain a sorted list. uint32_t pfx = Address_getPrefix(addr); if (store->size < store->capacity) { for (uint32_t i = 0; i < store->size; i++) { if (store->headers[i].addressPrefix == pfx && Address_isSameIp(&store->nodes[i].address, addr)) { int red = Address_checkRedundantRoute(&store->nodes[i].address, addr); if (red == 1) { #ifdef Log_DEBUG uint8_t nodeAddr[60]; Address_print(nodeAddr, &store->nodes[i].address); uint8_t newAddr[20]; Address_printNetworkAddress(newAddr, addr); Log_debug2(store->logger, "Found a better route to %s via %s\n", nodeAddr, newAddr); struct Node* n = NodeStore_getNodeByNetworkAddr(addr->networkAddress_be, store); if (n) { Log_warn(store->logger, "This route is probably invalid, giving up.\n"); continue; } #endif store->nodes[i].address.networkAddress_be = addr->networkAddress_be; } else if (red == 0 && store->nodes[i].address.networkAddress_be != addr->networkAddress_be) { // Completely different routes, store seperately. continue; } /*#ifdef Log_DEBUG uint32_t oldReach = store->headers[i].reach; #endif*/ adjustReach(&store->headers[i], reachDifference); /*#ifdef Log_DEBUG if (oldReach != store->headers[i].reach) { uint8_t nodeAddr[60]; Address_print(nodeAddr, addr); Log_debug3(store->logger, "Altering reach for node %s, old reach %u, new reach %u.\n", nodeAddr, oldReach, store->headers[i].reach); if (oldReach > store->headers[i].reach) { Log_debug(store->logger, "Reach was decreased!\n"); } } #endif*/ return; } #ifdef Log_DEBUG else if (store->headers[i].addressPrefix == pfx) { uint8_t realAddr[16]; AddressCalc_addressForPublicKey(realAddr, addr->key); assert(!memcmp(realAddr, addr->ip6.bytes, 16)); } #endif } #ifdef Log_DEBUG uint8_t nodeAddr[60]; Address_print(nodeAddr, addr); Log_debug2(store->logger, "Discovered node: %s reach %u\n", nodeAddr, reachDifference); #endif // Free space, regular insert. replaceNode(&store->nodes[store->size], &store->headers[store->size], addr); adjustReach(&store->headers[store->size], reachDifference); store->size++; return; } // The node whose reach OR distance is the least. // This means nodes who are close and have short reach will be removed uint32_t indexOfNodeToReplace = 0; uint32_t leastReachOrDistance = UINT32_MAX; for (uint32_t i = 0; i < store->size; i++) { uint32_t distance = store->headers[i].addressPrefix ^ pfx; if (distance == 0 && Address_isSame(&store->nodes[i].address, addr)) { // Node already exists adjustReach(&store->headers[store->size], reachDifference); return; } uint32_t reachOrDistance = store->headers[i].reach | distance; if (reachOrDistance < leastReachOrDistance) { leastReachOrDistance = reachOrDistance; indexOfNodeToReplace = i; } } replaceNode(&store->nodes[indexOfNodeToReplace], &store->headers[indexOfNodeToReplace], addr); adjustReach(&store->headers[indexOfNodeToReplace], reachDifference); }
/** * This is called as sendMessage() by the switch. * There is only one switch interface which sends all traffic. * message is aligned on the beginning of the switch header. */ static uint8_t incomingFromSwitch(struct Message* message, struct Interface* switchIf) { struct Context* context = switchIf->senderContext; struct Headers_SwitchHeader* switchHeader = (struct Headers_SwitchHeader*) message->bytes; Message_shift(message, -Headers_SwitchHeader_SIZE); // The label comes in reversed from the switch because the switch doesn't know that we aren't // another switch ready to parse more bits, bit reversing the label yields the source address. switchHeader->label_be = Bits_bitReverse64(switchHeader->label_be); if (Headers_getMessageType(switchHeader) == MessageType_CONTROL) { struct Control* ctrl = (struct Control*) (switchHeader + 1); if (ctrl->type_be == Control_ERROR_be) { if (memcmp(&ctrl->content.error.cause.label_be, &switchHeader->label_be, 8)) { Log_warn(context->logger, "Different label for cause than return packet, this shouldn't happen. " "Perhaps a packet was corrupted.\n"); return 0; } uint32_t errType_be = ctrl->content.error.errorType_be; if (errType_be == Endian_bigEndianToHost32(Error_MALFORMED_ADDRESS)) { Log_info(context->logger, "Got malformed-address error, removing route.\n"); RouterModule_brokenPath(switchHeader->label_be, context->routerModule); return 0; } Log_info1(context->logger, "Got error packet, error type: %d", Endian_bigEndianToHost32(errType_be)); } return 0; } uint8_t* herKey = extractPublicKey(message, switchHeader->label_be, context->logger); int herAddrIndex; if (herKey) { uint8_t herAddrStore[16]; AddressCalc_addressForPublicKey(herAddrStore, herKey); if (herAddrStore[0] != 0xFC) { Log_debug(context->logger, "Got message from peer whose address is not in fc00::/8 range.\n"); return 0; } herAddrIndex = AddressMapper_put(switchHeader->label_be, herAddrStore, &context->addrMap); } else { herAddrIndex = AddressMapper_indexOf(switchHeader->label_be, &context->addrMap); if (herAddrIndex == -1) { struct Node* n = RouterModule_getNode(switchHeader->label_be, context->routerModule); if (n) { herAddrIndex = AddressMapper_put(switchHeader->label_be, n->address.ip6.bytes, &context->addrMap); } else { #ifdef Log_DEBUG uint8_t switchAddr[20]; struct Address addr; addr.networkAddress_be = switchHeader->label_be; Address_printNetworkAddress(switchAddr, &addr); Log_debug1(context->logger, "Dropped traffic packet from unknown node. (%s)\n", &switchAddr); #endif return 0; } } } uint8_t* herAddr = context->addrMap.addresses[herAddrIndex]; // This is needed so that the priority and other information // from the switch header can be passed on properly. context->switchHeader = switchHeader; context->session = SessionManager_getSession(herAddr, herKey, context->sm); // This goes to incomingFromCryptoAuth() // then incomingFromRouter() then core() context->layer = OUTER_LAYER; context->session->receiveMessage(message, context->session); return 0; }