struct TAPDevice* TAPDevice_find(const char* preferredName, struct Except* eh, struct Allocator* alloc) { #define BUFF_SZ 0x100 char guid[BUFF_SZ] = {0}; char buff[BUFF_SZ] = {0}; if (preferredName != NULL) { snprintf(buff, sizeof(buff), "%s", preferredName); } if (get_device_guid(guid, sizeof(guid), buff, sizeof(buff), eh)) { return NULL; } struct TAPDevice* out = Allocator_malloc(alloc, sizeof(struct TAPDevice)); out->name = Allocator_malloc(alloc, CString_strlen(buff)+1); Bits_memcpy(out->name, buff, CString_strlen(buff)+1); snprintf(buff, sizeof(buff), USERMODEDEVICEDIR "%s" TAPSUFFIX, guid); out->path = Allocator_malloc(alloc, CString_strlen(buff)+1); Bits_memcpy(out->path, buff, CString_strlen(buff)+1); return out; }
static void onConnectionParent(struct Pipe* p, int status) { Assert_true(!status); struct Context* c = Identity_check((struct Context*) p->userData); struct Allocator* alloc = Allocator_child(c->alloc); uint8_t* bytes = Allocator_calloc(alloc, CString_strlen(MESSAGE) + 1, 1); Bits_memcpy(bytes, MESSAGE, CString_strlen(MESSAGE)); struct Message* m = Allocator_clone(alloc, (&(struct Message) { .length = CString_strlen(MESSAGE), .padding = 0, .capacity = CString_strlen(MESSAGE), .alloc = alloc, .bytes = bytes }));
static uint8_t responseWithIpCallback(struct Message* message, struct Interface* iface) { struct IpTunnel_PacketInfoHeader* pi = (struct IpTunnel_PacketInfoHeader*) message->bytes; Assert_true(!Bits_memcmp(nodeCjdnsIp6, pi->nodeIp6Addr, 16)); Assert_true(!Bits_memcmp(fakePubKey, pi->nodeKey, 32)); Message_shift(message, -IpTunnel_PacketInfoHeader_SIZE, NULL); struct Headers_IP6Header* ip = (struct Headers_IP6Header*) message->bytes; Assert_true(Headers_getIpVersion(ip) == 6); uint16_t length = Endian_bigEndianToHost16(ip->payloadLength_be); Assert_true(length + Headers_IP6Header_SIZE == message->length); Assert_true(ip->nextHeader == 17); Assert_true(Bits_isZero(ip->sourceAddr, 32)); Message_shift(message, -Headers_IP6Header_SIZE, NULL); struct Headers_UDPHeader* uh = (struct Headers_UDPHeader*) message->bytes; Assert_true(!Checksum_udpIp6(ip->sourceAddr, message->bytes, length)); Assert_true(uh->srcPort_be == 0); Assert_true(uh->destPort_be == 0); Assert_true(Endian_bigEndianToHost16(uh->length_be) + Headers_UDPHeader_SIZE == length); Message_shift(message, -Headers_UDPHeader_SIZE, NULL); char* expectedResponse = "d" "9:addresses" "d" "3:ip6" "16:\xfd\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1" "e" "4:txid" "4:abcd" "e"; Assert_true(message->length == (int32_t) CString_strlen(expectedResponse)); Assert_true(!Bits_memcmp(message->bytes, expectedResponse, message->length)); called = 1; return 0; }
static int calculateAuth(Dict* message, String* password, String* cookieStr, struct Allocator* alloc) { // Calculate the hash of the password. String* hashHex = String_newBinary(NULL, 64, alloc); uint8_t passAndCookie[64]; uint32_t cookie = (cookieStr != NULL) ? strtoll(cookieStr->bytes, NULL, 10) : 0; snprintf((char*) passAndCookie, 64, "%s%u", password->bytes, cookie); uint8_t hash[32]; crypto_hash_sha256(hash, passAndCookie, CString_strlen((char*) passAndCookie)); Hex_encode((uint8_t*)hashHex->bytes, 64, hash, 32); Dict_putString(message, String_new("hash", alloc), hashHex, alloc); Dict_putString(message, String_new("cookie", alloc), cookieStr, alloc); // serialize the message with the password hash struct Message* msg = Message_new(0, AdminClient_MAX_MESSAGE_SIZE, alloc); BencMessageWriter_write(message, msg, NULL); // calculate the hash of the message with the password hash crypto_hash_sha256(hash, msg->bytes, msg->length); // swap the hash of the message with the password hash into the location // where the password hash was. Hex_encode((uint8_t*)hashHex->bytes, 64, hash, 32); return 0; }
static int parseEmptyList() { char* test = "d" "2:hi" "le" "e"; struct Allocator* alloc = MallocAllocator_new(1<<20); struct Reader* reader = ArrayReader_new(test, CString_strlen(test), alloc); Dict d; int ret = StandardBencSerializer_get()->parseDictionary(reader, alloc, &d); char out[256]; struct Writer* w = ArrayWriter_new(out, 256, alloc); ret |= StandardBencSerializer_get()->serializeDictionary(w, &d); ret |= Bits_memcmp(test, out, CString_strlen(test)); Allocator_free(alloc); return ret; }
/** * Helper function for writing an integer into a writer in base 10 format. * * @param writer the place to write the integer to. * @param integer the number to write. */ static int32_t writeint64_t(struct Writer* writer, int64_t integer) { char buffer[32] = {0}; snprintf(buffer, 32, "%" PRId64, integer); return Writer_write(writer, buffer, CString_strlen(buffer)); }
static void sendMessage(struct TwoNodes* tn, char* message, struct TestFramework* from, struct TestFramework* to) { struct Message* msg; Message_STACK(msg, 64, 512); Bits_memcpy(msg->bytes, message, CString_strlen(message) + 1); msg->length = CString_strlen(message) + 1; TestFramework_craftIPHeader(msg, from->ip, to->ip); msg = Message_clone(msg, from->alloc); struct Iface* fromIf; if (from == tn->nodeA) { fromIf = &tn->tunA; } else if (from == tn->nodeB) { fromIf = &tn->tunB; } else { Assert_true(false); } TUNMessageType_push(msg, Ethernet_TYPE_IP6, NULL); Iface_send(fromIf, msg); if (to == tn->nodeA) { Assert_true(tn->messageFrom == TUNA); } else if (to == tn->nodeB) { Assert_true(tn->messageFrom == TUNB); } else { Assert_true(false); } TestFramework_assertLastMessageUnaltered(tn->nodeA); TestFramework_assertLastMessageUnaltered(tn->nodeB); tn->messageFrom = 0; }
char* ArchInfo_describe(enum ArchInfo ai, struct Allocator* alloc) { uint8_t flagBuff[archFlags_BUFF_SZ]; archFlags(ai, flagBuff); uint8_t buff[1024]; snprintf(buff, 1024, "%s %d-bit %sEndian %s", archStr(ai), ArchInfo_getBits(ai), ArchInfo_isBigEndian(ai) ? "Big" : "Little", flagBuff); int len = CString_strlen(buff); Assert_true(len < 1024); if (buff[len-1] == ' ') { buff[--len] = '\0'; } char* out = Allocator_malloc(alloc, len+1); Bits_memcpy(out, buff, len+1); return out; }
static Iface_DEFUN responseWithIpCallback(struct Message* message, struct Iface* iface) { struct RouteHeader* rh = (struct RouteHeader*) message->bytes; Assert_true(!Bits_memcmp(nodeCjdnsIp6, rh->ip6, 16)); Assert_true(!Bits_memcmp(fakePubKey, rh->publicKey, 32)); Message_shift(message, -(RouteHeader_SIZE + DataHeader_SIZE), NULL); struct Headers_IP6Header* ip = (struct Headers_IP6Header*) message->bytes; Assert_true(Headers_getIpVersion(ip) == 6); uint16_t length = Endian_bigEndianToHost16(ip->payloadLength_be); Assert_true(length + Headers_IP6Header_SIZE == message->length); Assert_true(ip->nextHeader == 17); Assert_true(Bits_isZero(ip->sourceAddr, 32)); Message_shift(message, -Headers_IP6Header_SIZE, NULL); struct Headers_UDPHeader* uh = (struct Headers_UDPHeader*) message->bytes; Assert_true(!Checksum_udpIp6(ip->sourceAddr, message->bytes, length)); Assert_true(uh->srcPort_be == 0); Assert_true(uh->destPort_be == 0); Assert_true(Endian_bigEndianToHost16(uh->length_be) + Headers_UDPHeader_SIZE == length); Message_shift(message, -Headers_UDPHeader_SIZE, NULL); // We can't check that the message is an exact match because the padding depends on the // alignment of the output but we can make sure the right content is there... // Message should start with "d0000" (with some number of zeros) char* expectedResponse = "9:addresses" "d" "3:ip6" "16:\xfd\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1" "9:ip6Prefix" "i128e" "e" "4:txid" "4:abcd" "e"; Assert_true(message->length >= (int32_t) CString_strlen(expectedResponse)); Assert_true(CString_strstr(message->bytes, expectedResponse)); called |= 2; return 0; }
static int is_tap_win32_dev(const char *guid) { HKEY netcard_key; LONG status; DWORD len; int i = 0; status = RegOpenKeyEx( HKEY_LOCAL_MACHINE, ADAPTER_KEY, 0, KEY_READ, &netcard_key); if (status != ERROR_SUCCESS) { return FALSE; } for (;;) { char enum_name[256]; char unit_string[256]; HKEY unit_key; char component_id_string[] = "ComponentId"; char component_id[256]; char net_cfg_instance_id_string[] = "NetCfgInstanceId"; char net_cfg_instance_id[256]; DWORD data_type; len = sizeof (enum_name); status = RegEnumKeyEx( netcard_key, i, enum_name, &len, NULL, NULL, NULL, NULL); if (status == ERROR_NO_MORE_ITEMS) { break; } else if (status != ERROR_SUCCESS) { return FALSE; } snprintf (unit_string, sizeof(unit_string), "%s\\%s", ADAPTER_KEY, enum_name); status = RegOpenKeyEx( HKEY_LOCAL_MACHINE, unit_string, 0, KEY_READ, &unit_key); if (status != ERROR_SUCCESS) { return FALSE; } else { len = sizeof (component_id); status = RegQueryValueEx( unit_key, component_id_string, NULL, &data_type, (uint8_t*)component_id, &len); if (!(status != ERROR_SUCCESS || data_type != REG_SZ)) { len = sizeof (net_cfg_instance_id); status = RegQueryValueEx( unit_key, net_cfg_instance_id_string, NULL, &data_type, (uint8_t*)net_cfg_instance_id, &len); if (status == ERROR_SUCCESS && data_type == REG_SZ) { if (!Bits_memcmp(component_id, "tap", CString_strlen("tap")) && !strcmp (net_cfg_instance_id, guid)) { RegCloseKey (unit_key); RegCloseKey (netcard_key); return TRUE; } } } RegCloseKey (unit_key); } ++i; } RegCloseKey (netcard_key); return FALSE; }
static int get_device_guid( char *name, int name_size, char *actual_name, int actual_name_size, struct Except* eh) { LONG status; HKEY control_net_key; DWORD len; WinFail_check(eh, ( RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &control_net_key) )); int stop = 0; for (int i = 0; !stop; i++) { char enum_name[256]; char connection_string[256]; HKEY connKey; char name_data[256]; DWORD name_type; const char name_string[] = "Name"; len = sizeof (enum_name); status = RegEnumKeyEx(control_net_key, i, enum_name, &len, NULL, NULL, NULL, NULL); if (status == ERROR_NO_MORE_ITEMS) { break; } else if (status != ERROR_SUCCESS) { WinFail_fail(eh, "RegEnumKeyEx() failed", status); } if (len != CString_strlen(NETWORK_ADAPTER_GUID)) { // extranious directory, eg: "Descriptions" continue; } snprintf(connection_string, sizeof(connection_string), "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, enum_name); WinFail_check(eh, ( RegOpenKeyEx(HKEY_LOCAL_MACHINE, connection_string, 0, KEY_READ, &connKey) )); // In Windows 10, some interface keys don't have names. We should keep // going and treat those interfaces as having empty string names. len = sizeof (name_data); status = RegQueryValueEx(connKey, name_string, NULL, &name_type, (uint8_t*)name_data, &len); if (status == ERROR_FILE_NOT_FOUND) { // The interface has no name. strncpy(name_data, "", sizeof (name_data)); } else if (status != ERROR_SUCCESS) { WinFail_fail(eh, "RegQueryValueEx() for interface name failed", status); } else { if (name_type != REG_SZ) { // Someone named an interface with a non-string WinFail_fail(eh, "RegQueryValueEx() name_type != REG_SZ", status); } } if (is_tap_win32_dev(enum_name)) { snprintf(name, name_size, "%s", enum_name); if (actual_name) { if (CString_strcmp(actual_name, "") != 0) { if (CString_strcmp(name_data, actual_name) != 0) { RegCloseKey (connKey); ++i; continue; } } else { snprintf(actual_name, actual_name_size, "%s", name_data); } } stop = 1; } RegCloseKey(connKey); } RegCloseKey (control_net_key); if (stop == 0) { return -1; } return 0; }
int main() { AddressCalc_addressForPublicKey(nodeCjdnsIp6, fakePubKey); struct Allocator* alloc = MallocAllocator_new(1<<20); struct Writer* w = FileWriter_new(stdout, alloc); struct Log* logger = WriterLog_new(w, alloc); struct Random* rand = Random_new(alloc, logger, NULL); struct EventBase* eb = EventBase_new(alloc); struct IpTunnel* ipTun = IpTunnel_new(logger, eb, alloc, rand, NULL); struct Sockaddr_storage ip6ToGive; Sockaddr_parse("fd01:0101:0101:0101:0101:0101:0101:0101", &ip6ToGive); IpTunnel_allowConnection(fakePubKey, &ip6ToGive.addr, NULL, ipTun); struct Message* message; Message_STACK(message, 64, 512); message->alloc = alloc; const char* requestForAddresses = "d" "1:q" "21:IpTunnel_getAddresses" "4:txid" "4:abcd" "e"; CString_strcpy((char*)message->bytes, requestForAddresses); message->length = CString_strlen(requestForAddresses); Message_shift(message, Headers_UDPHeader_SIZE, NULL); struct Headers_UDPHeader* uh = (struct Headers_UDPHeader*) message->bytes; uh->srcPort_be = 0; uh->destPort_be = 0; uh->length_be = Endian_hostToBigEndian16(message->length - Headers_UDPHeader_SIZE); uint16_t* checksum = &uh->checksum_be; *checksum = 0; uint32_t length = message->length; Message_shift(message, Headers_IP6Header_SIZE, NULL); struct Headers_IP6Header* ip = (struct Headers_IP6Header*) message->bytes; ip->versionClassAndFlowLabel = 0; ip->flowLabelLow_be = 0; ip->payloadLength_be = Endian_hostToBigEndian16(length); ip->nextHeader = 17; ip->hopLimit = 255; Bits_memset(ip->sourceAddr, 0, 32); Headers_setIpVersion(ip); Message_shift(message, IpTunnel_PacketInfoHeader_SIZE, NULL); struct IpTunnel_PacketInfoHeader* pi = (struct IpTunnel_PacketInfoHeader*) message->bytes; Bits_memcpyConst(pi->nodeIp6Addr, nodeCjdnsIp6, 16); Bits_memcpyConst(pi->nodeKey, fakePubKey, 32); *checksum = Checksum_udpIp6(ip->sourceAddr, (uint8_t*) uh, length); ipTun->nodeInterface.receiveMessage = responseWithIpCallback; ipTun->nodeInterface.sendMessage(message, &ipTun->nodeInterface); Assert_true(called); called = 0; // Now create a message for someone else. Message_shift(message, Headers_UDPHeader_SIZE + Headers_IP6Header_SIZE + IpTunnel_PacketInfoHeader_SIZE, NULL); Bits_memcpyConst(ip->sourceAddr, fakeIp6ToGive, 16); // This can't be zero. Bits_memset(ip->destinationAddr, 1, 16); ipTun->tunInterface.receiveMessage = messageToTun; ipTun->nodeInterface.sendMessage(message, &ipTun->nodeInterface); Assert_true(called); Allocator_free(alloc); return 0; }
int main(int argc, char** argv) { #ifdef Log_KEYS fprintf(stderr, "Log_LEVEL = KEYS, EXPECT TO SEE PRIVATE KEYS IN YOUR LOGS!\n"); #endif if (argc < 2) { // Fall through. } else if (!CString_strcmp("angel", argv[1])) { return AngelInit_main(argc, argv); } else if (!CString_strcmp("core", argv[1])) { return Core_main(argc, argv); } Assert_ifParanoid(argc > 0); struct Except* eh = NULL; // Allow it to allocate 8MB struct Allocator* allocator = MallocAllocator_new(1<<23); struct Random* rand = Random_new(allocator, NULL, eh); struct EventBase* eventBase = EventBase_new(allocator); if (argc == 2) { // one argument if ((CString_strcmp(argv[1], "--help") == 0) || (CString_strcmp(argv[1], "-h") == 0)) { return usage(allocator, argv[0]); } else if (CString_strcmp(argv[1], "--genconf") == 0) { return genconf(rand); } else if (CString_strcmp(argv[1], "--pidfile") == 0) { // deprecated fprintf(stderr, "'--pidfile' option is deprecated.\n"); return 0; } else if (CString_strcmp(argv[1], "--reconf") == 0) { // Performed after reading the configuration } else if (CString_strcmp(argv[1], "--bench") == 0) { return benchmark(); } else if ((CString_strcmp(argv[1], "--version") == 0) || (CString_strcmp(argv[1], "-v") == 0)) { printf("Cjdns protocol version: %d\n", Version_CURRENT_PROTOCOL); return 0; } else if (CString_strcmp(argv[1], "--cleanconf") == 0) { // Performed after reading configuration } else if (CString_strcmp(argv[1], "--nobg") == 0) { // Performed while reading configuration } 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 [%s]\n", argv[0], argv[1]); fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]); // because of '--pidfile $filename'? if (CString_strcmp(argv[1], "--pidfile") == 0) { fprintf(stderr, "\n'--pidfile' option is deprecated.\n"); } 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(allocator, 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; } if (argc == 2 && CString_strcmp(argv[1], "--cleanconf") == 0) { struct Writer* stdoutWriter = FileWriter_new(stdout, allocator); JsonBencSerializer_get()->serializeDictionary(stdoutWriter, &config); printf("\n"); return 0; } int forceNoBackground = 0; if (argc == 2 && CString_strcmp(argv[1], "--nobg") == 0) { forceNoBackground = 1; } struct Writer* logWriter = FileWriter_new(stdout, allocator); struct Log* logger = WriterLog_new(logWriter, allocator); // --------------------- 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 = CString_strlen(adminPass->bytes); } if (!adminBind) { Except_throw(eh, "You must specify admin.bind in the cjdroute.conf file."); } // --------------------- Welcome to cjdns ---------------------- // char* archInfo = ArchInfo_describe(ArchInfo_detect(), allocator); char* sysInfo = SysInfo_describe(SysInfo_detect(), allocator); Log_info(logger, "Cjdns %s %s", archInfo, sysInfo); // --------------------- Check for running instance --------------------- // Log_info(logger, "Checking for running instance..."); checkRunningInstance(allocator, eventBase, adminBind, adminPass, logger, eh); // --------------------- Setup Pipes to Angel --------------------- // char angelPipeName[64] = "client-angel-"; Random_base32(rand, (uint8_t*)angelPipeName+13, 31); Assert_ifParanoid(EventBase_eventCount(eventBase) == 0); struct Pipe* angelPipe = Pipe_named(angelPipeName, eventBase, eh, allocator); Assert_ifParanoid(EventBase_eventCount(eventBase) == 2); angelPipe->logger = logger; char* args[] = { "angel", angelPipeName, NULL }; // --------------------- Spawn Angel --------------------- // String* privateKey = Dict_getString(&config, String_CONST("privateKey")); char* corePath = Process_getPath(allocator); if (!corePath) { Except_throw(eh, "Can't find a usable cjdns core executable, " "make sure it is in the same directory as cjdroute"); } if (!privateKey) { Except_throw(eh, "Need to specify privateKey."); } Log_info(logger, "Forking angel to background."); Process_spawn(corePath, args, eventBase, allocator); // --------------------- Get user for angel to setuid() ---------------------- // String* securityUser = NULL; List* securityConf = Dict_getList(&config, String_CONST("security")); for (int i = 0; securityConf && i < List_size(securityConf); i++) { securityUser = Dict_getString(List_getDict(securityConf, i), String_CONST("setuser")); if (securityUser) { int64_t* ea = Dict_getInt(List_getDict(securityConf, i), String_CONST("exemptAngel")); if (ea && *ea) { securityUser = NULL; } 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"), String_new(corePath, allocator), 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); } Dict* logging = Dict_getDict(&config, String_CONST("logging")); if (logging) { Dict_putDict(preConf, String_CONST("logging"), logging, allocator); } struct Message* toAngelMsg = Message_new(0, 1024, allocator); BencMessageWriter_write(preConf, toAngelMsg, eh); Interface_sendMessage(&angelPipe->iface, toAngelMsg); Log_debug(logger, "Sent [%d] bytes to angel process", toAngelMsg->length); // --------------------- Get Response from Angel --------------------- // struct Message* fromAngelMsg = InterfaceWaiter_waitForData(&angelPipe->iface, eventBase, allocator, eh); Dict* responseFromAngel = BencMessageReader_read(fromAngelMsg, allocator, eh); // --------------------- Get Admin Addr/Port/Passwd --------------------- // Dict* responseFromAngelAdmin = Dict_getDict(responseFromAngel, String_CONST("admin")); adminBind = Dict_getString(responseFromAngelAdmin, String_CONST("bind")); if (!adminBind) { Except_throw(eh, "didn't get address and port back from angel"); } struct Sockaddr_storage adminAddr; if (Sockaddr_parse(adminBind->bytes, &adminAddr)) { Except_throw(eh, "Unable to parse [%s] as an ip address port, eg: 127.0.0.1:11234", adminBind->bytes); } // sanity check, Pipe_named() creates 2 events, see above. Assert_ifParanoid(EventBase_eventCount(eventBase) == 2); // --------------------- Configuration ------------------------- // Configurator_config(&config, &adminAddr.addr, adminPass, eventBase, logger, allocator); // --------------------- noBackground ------------------------ // int64_t* noBackground = Dict_getInt(&config, String_CONST("noBackground")); if (forceNoBackground || (noBackground && *noBackground)) { EventBase_beginLoop(eventBase); } //Allocator_free(allocator); return 0; }
static void testAddr(struct Context* ctx, char* addr4, int prefix4, int alloc4, char* addr6, int prefix6, int alloc6) { struct Allocator* alloc = Allocator_child(ctx->alloc); struct IpTunnel* ipTun = IpTunnel_new(ctx->log, ctx->base, alloc, ctx->rand, NULL); struct Sockaddr* sa4 = NULL; struct Sockaddr_storage ip6ToGive; struct Sockaddr_storage ip4ToGive; if (addr4) { Assert_true(!Sockaddr_parse(addr4, &ip4ToGive)); sa4 = &ip4ToGive.addr; Assert_true(Sockaddr_getFamily(sa4) == Sockaddr_AF_INET); } struct Sockaddr* sa6 = NULL; if (addr6) { Assert_true(!Sockaddr_parse(addr6, &ip6ToGive)); sa6 = &ip6ToGive.addr; Assert_true(Sockaddr_getFamily(sa6) == Sockaddr_AF_INET6); } IpTunnel_allowConnection(ctx->pubKey, sa6, prefix6, alloc6, sa4, prefix4, alloc4, ipTun); struct Message* msg = Message_new(64, 512, alloc); const char* requestForAddresses = "d" "1:q" "21:IpTunnel_getAddresses" "4:txid" "4:abcd" "e"; CString_strcpy(msg->bytes, requestForAddresses); msg->length = CString_strlen(requestForAddresses); Message_push(msg, NULL, Headers_UDPHeader_SIZE, NULL); struct Headers_UDPHeader* uh = (struct Headers_UDPHeader*) msg->bytes; uh->length_be = Endian_hostToBigEndian16(msg->length - Headers_UDPHeader_SIZE); uint16_t* checksum = &((struct Headers_UDPHeader*) msg->bytes)->checksum_be; *checksum = 0; uint32_t length = msg->length; // Because of old reasons, we need to have at least an empty IPv6 header Message_push(msg, NULL, Headers_IP6Header_SIZE, NULL); struct Headers_IP6Header* ip = (struct Headers_IP6Header*) msg->bytes; Headers_setIpVersion(ip); ip->payloadLength_be = Endian_hostToBigEndian16(msg->length - Headers_IP6Header_SIZE); ip->nextHeader = 17; *checksum = Checksum_udpIp6(ip->sourceAddr, (uint8_t*) uh, length); pushRouteDataHeaders(ctx, msg); struct IfaceContext* nodeIf = Allocator_calloc(alloc, sizeof(struct IfaceContext), 1); nodeIf->ctx = ctx; nodeIf->iface.send = responseWithIpCallback; struct IfaceContext* tunIf = Allocator_calloc(alloc, sizeof(struct IfaceContext), 1); tunIf->ctx = ctx; tunIf->iface.send = messageToTun; Iface_plumb(&nodeIf->iface, &ipTun->nodeInterface); Iface_plumb(&tunIf->iface, &ipTun->tunInterface); ctx->expectedResponse = getExpectedResponse(sa4, prefix4, alloc4, sa6, prefix6, alloc6, alloc); Iface_send(&nodeIf->iface, msg); Assert_true(ctx->called == 2); ctx->called = 0; if (sa4) { uint8_t* addrBytes = NULL; Assert_true(Sockaddr_getAddress(sa4, &addrBytes) == 4); uint32_t addr; Bits_memcpy(&addr, addrBytes, 4); addr = Endian_bigEndianToHost32(addr); // Send from the address specified Assert_true(trySend4(alloc, addr, &nodeIf->iface, ctx)); if (alloc4 < 32) { // Send from another (random) address in the prefix uint32_t flip = Random_uint32(ctx->rand) >> alloc4; if (prefix4 != 32) { Assert_true(trySend4(alloc, addr ^ flip, &nodeIf->iface, ctx)); } else { // If netSize is not specified, we do not allow multi-address Assert_true(!trySend4(alloc, addr ^ flip, &nodeIf->iface, ctx)); } } else {
int main() { AddressCalc_addressForPublicKey(nodeCjdnsIp6, fakePubKey); struct Allocator* alloc = MallocAllocator_new(1<<20); struct Log* logger = FileWriterLog_new(stdout, alloc); struct Random* rand = Random_new(alloc, logger, NULL); struct EventBase* eb = EventBase_new(alloc); struct IpTunnel* ipTun = IpTunnel_new(logger, eb, alloc, rand); struct Sockaddr_storage ip6ToGive; Sockaddr_parse("fd01:0101:0101:0101:0101:0101:0101:0101", &ip6ToGive); IpTunnel_allowConnection(fakePubKey, &ip6ToGive.addr, 0, NULL, 0, ipTun); struct Message* message; Message_STACK(message, 64, 512); message->alloc = alloc; const char* requestForAddresses = "d" "1:q" "21:IpTunnel_getAddresses" "4:txid" "4:abcd" "e"; CString_strcpy((char*)message->bytes, requestForAddresses); message->length = CString_strlen(requestForAddresses); Message_shift(message, Headers_UDPHeader_SIZE, NULL); struct Headers_UDPHeader* uh = (struct Headers_UDPHeader*) message->bytes; uh->srcPort_be = 0; uh->destPort_be = 0; uh->length_be = Endian_hostToBigEndian16(message->length - Headers_UDPHeader_SIZE); uint16_t* checksum = &uh->checksum_be; *checksum = 0; uint32_t length = message->length; Message_shift(message, Headers_IP6Header_SIZE, NULL); struct Headers_IP6Header* ip = (struct Headers_IP6Header*) message->bytes; ip->versionClassAndFlowLabel = 0; ip->flowLabelLow_be = 0; ip->payloadLength_be = Endian_hostToBigEndian16(length); ip->nextHeader = 17; ip->hopLimit = 255; Bits_memset(ip->sourceAddr, 0, 32); Headers_setIpVersion(ip); Message_shift(message, RouteHeader_SIZE + DataHeader_SIZE, NULL); struct RouteHeader* rh = (struct RouteHeader*) message->bytes; struct DataHeader* dh = (struct DataHeader*) &rh[1]; Bits_memset(rh, 0, RouteHeader_SIZE + DataHeader_SIZE); Bits_memcpy(rh->ip6, nodeCjdnsIp6, 16); Bits_memcpy(rh->publicKey, fakePubKey, 32); DataHeader_setContentType(dh, ContentType_IPTUN); *checksum = Checksum_udpIp6(ip->sourceAddr, (uint8_t*) uh, length); int origCap = message->capacity; int origLen = message->length; struct Iface nodeIface = { .send = responseWithIpCallback }; Iface_plumb(&nodeIface, &ipTun->nodeInterface); struct Iface tunIface = { .send = messageToTun }; Iface_plumb(&tunIface, &ipTun->tunInterface); Iface_send(&nodeIface, message); Assert_true(called == 2); called = 0; // This is a hack, reusing the message will cause breakage if IpTunnel is refactored. Message_reset(message); Message_shift(message, origCap, NULL); message->length = origLen; Bits_memcpy(ip->sourceAddr, fakeIp6ToGive, 16); // This can't be zero. Bits_memset(ip->destinationAddr, 1, 16); Iface_send(&nodeIface, message); Assert_true(called == 1); Allocator_free(alloc); return 0; }
static void encryptRndNonceTest() { uint8_t buff[44]; Bits_memset(buff, 0, 44); uint8_t nonce[24]; Bits_memset(nonce, 0, 24); uint8_t secret[32]; Bits_memset(secret, 0, 32); struct Message m = { .bytes=&buff[32], .length=HELLOWORLDLEN, .padding=32}; CString_strcpy((char*) m.bytes, HELLOWORLDLOWER); CryptoAuth_encryptRndNonce(nonce, &m, secret); uint8_t* expected = (uint8_t*) "1391ac5d03ba9f7099bffbb6e6c69d67ae5bd79391a5b94399b293dc"; uint8_t output[57]; Hex_encode(output, 57, m.bytes, m.length); printf("\n%s\n%s\n", (char*) expected, (char*) output); Assert_true(!Bits_memcmp(expected, output, 56)); Assert_true(!CryptoAuth_decryptRndNonce(nonce, &m, secret)); Assert_true(m.length == HELLOWORLDLEN && !Bits_memcmp(m.bytes, HELLOWORLDLOWER, m.length)); } static struct Random* evilRandom(struct Allocator* alloc, struct Log* logger) { struct RandomSeed* evilSeed = DeterminentRandomSeed_new(alloc, NULL); return Random_newWithSeed(alloc, logger, evilSeed, NULL); } struct Context { struct Allocator* alloc; struct CryptoAuth* ca; struct CryptoAuth_Session* sess; struct Log* log; struct EventBase* base; }; static struct Context* setUp(uint8_t* myPrivateKey, uint8_t* herPublicKey, uint8_t* authPassword, struct Allocator* alloc) { struct Context* ctx = Allocator_calloc(alloc, sizeof(struct Context), 1); struct Log* log = ctx->log = FileWriterLog_new(stdout, alloc); struct EventBase* base = ctx->base = EventBase_new(alloc); struct CryptoAuth* ca = ctx->ca = CryptoAuth_new(alloc, myPrivateKey, base, log, evilRandom(alloc, log)); struct CryptoAuth_Session* sess = ctx->sess = CryptoAuth_newSession(ca, alloc, herPublicKey, NULL, false, Gcc_FILE); if (authPassword) { CryptoAuth_setAuth(String_CONST(authPassword), NULL, sess); } return ctx; } static void testHello(uint8_t* password, uint8_t* expectedOutput) { Assert_true(CString_strlen((char*)expectedOutput) == 264); struct Allocator* alloc = MallocAllocator_new(1<<20); struct Context* ctx = setUp(NULL, HERPUBKEY, password, alloc); struct Message* msg = Message_new(0, CryptoHeader_SIZE + 12, alloc); Message_push(msg, HELLOWORLD, HELLOWORLDLEN, NULL); Assert_true(!CryptoAuth_encrypt(ctx->sess, msg)); char* actual = Hex_print(msg->bytes, msg->length, alloc); if (CString_strcmp(actual, expectedOutput)) { Assert_failure("Test failed.\n" "Expected %s\n" " Got %s\n", expectedOutput, actual); } Allocator_free(alloc); }