static void allowConnection(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc) { struct Context* context = (struct Context*) vcontext; String* publicKeyOfAuthorizedNode = Dict_getString(args, String_CONST("publicKeyOfAuthorizedNode")); String* ip6Address = Dict_getString(args, String_CONST("ip6Address")); int64_t* ip6Prefix = Dict_getInt(args, String_CONST("ip6Prefix")); String* ip4Address = Dict_getString(args, String_CONST("ip4Address")); int64_t* ip4Prefix = Dict_getInt(args, String_CONST("ip4Prefix")); uint8_t pubKey[32]; uint8_t ip6Addr[16]; struct Sockaddr_storage ip6ToGive; struct Sockaddr_storage ip4ToGive; char* error; int ret; if (!ip6Address && !ip4Address) { error = "Must specify ip6Address or ip4Address"; } else if ((ret = Key_parse(publicKeyOfAuthorizedNode, pubKey, ip6Addr)) != 0) { error = Key_parse_strerror(ret); } else if (ip6Prefix && !ip6Address) { error = "Must specify ip6Address with ip6Prefix"; } else if (ip6Prefix && (*ip6Prefix > 128 || *ip6Prefix < 0)) { error = "ip6Prefix out of range: must be 0 to 128"; } else if (ip4Prefix && (*ip4Prefix > 32 || *ip4Prefix < 0)) { error = "ip4Prefix out of range: must be 0 to 32"; } else if (ip4Prefix && !ip4Address) { error = "Must specify ip4Address with ip4Prefix"; } else if (ip6Address && (Sockaddr_parse(ip6Address->bytes, &ip6ToGive) || Sockaddr_getFamily(&ip6ToGive.addr) != Sockaddr_AF_INET6)) { error = "malformed ip6Address"; } else if (ip4Address && (Sockaddr_parse(ip4Address->bytes, &ip4ToGive) || Sockaddr_getFamily(&ip4ToGive.addr) != Sockaddr_AF_INET)) { error = "malformed ip4Address"; } else { int conn = IpTunnel_allowConnection(pubKey, (ip6Address) ? &ip6ToGive.addr : NULL, (ip6Prefix) ? (uint8_t) (*ip6Prefix) : 0, (ip4Address) ? &ip4ToGive.addr : NULL, (ip4Prefix) ? (uint8_t) (*ip4Prefix) : 0, context->ipTun); sendResponse(conn, txid, context->admin); return; } sendError(error, txid, context->admin); }
static void checkAddressAndPrefix(struct Sockaddr* sa, int* addrFam, char** printedAddr, void** addr, struct Allocator* alloc, struct Except* eh) { *printedAddr = Sockaddr_print(sa, alloc); *addrFam = Sockaddr_getFamily(sa); if (*addrFam != Sockaddr_AF_INET && *addrFam != Sockaddr_AF_INET6) { Except_throw(eh, "Unknown address type for address [%s]", *printedAddr); } int prefixMax = (*addrFam == Sockaddr_AF_INET6) ? 128 : 32; if (!(sa->flags & Sockaddr_flags_PREFIX)) { sa->prefix = prefixMax; } if (sa->prefix > prefixMax) { Except_throw(eh, "prefix [%u] must be less than %d", sa->prefix, prefixMax); } int len = Sockaddr_getAddress(sa, addr); if (len < 0 || len != prefixMax / 8) { Except_throw(eh, "Invalid sockaddr [%s]", *printedAddr); } }
void NetDev_addAddress(const char* ifName, struct Sockaddr* sa, int prefixLen, struct Log* logger, struct Except* eh) { int addrFam = Sockaddr_getFamily(sa); struct Allocator* alloc; BufferAllocator_STACK(alloc, 4096); char* printedAddr = Sockaddr_print(sa, alloc); if (addrFam != Sockaddr_AF_INET && addrFam != Sockaddr_AF_INET6) { Except_throw(eh, "Unknown address type for address [%s]", printedAddr); } int prefixMax = (addrFam == Sockaddr_AF_INET6) ? 128 : 32; if (prefixLen < 0 || prefixLen > prefixMax) { Except_throw(eh, "prefixLen [%d] must be greater than 0 and less than %d", prefixLen, prefixMax); } void* addr; int len = Sockaddr_getAddress(sa, &addr); if (len < 0 || len != prefixMax / 8) { Except_throw(eh, "Invalid sockaddr [%s]", printedAddr); } Log_info(logger, "Setting IP address [%s/%d] on interface [%s]", printedAddr, prefixLen, ifName); NetPlatform_addAddress(ifName, addr, prefixLen, addrFam, logger, eh); }
static void addRemoveSomething(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc, enum addRemoveSomething_What what) { struct RouteGen_admin_Ctx* ctx = Identity_check((struct RouteGen_admin_Ctx*) vcontext); String* route = Dict_getString(args, String_CONST("route")); char* error = NULL; struct Sockaddr_storage ss; if (route->len > 63) { error = "parse_failed"; } if (!error) { if (Sockaddr_parse(route->bytes, &ss)) { error = "parse_failed"; } else { int family = Sockaddr_getFamily(&ss.addr); if (family != Sockaddr_AF_INET && family != Sockaddr_AF_INET6) { error = "unexpected_af"; } } } int retVal = -1; Dict* out = Dict_new(requestAlloc); if (!error) { switch (what) { case addRemoveSomething_What_ADD_EXCEPTION: RouteGen_addException(ctx->rg, &ss.addr); break; case addRemoveSomething_What_ADD_PREFIX: RouteGen_addPrefix(ctx->rg, &ss.addr); break; case addRemoveSomething_What_ADD_LOCALPREFIX: RouteGen_addLocalPrefix(ctx->rg, &ss.addr); break; case addRemoveSomething_What_RM_EXCEPTION: retVal = RouteGen_removeException(ctx->rg, &ss.addr); break; case addRemoveSomething_What_RM_PREFIX: retVal = RouteGen_removePrefix(ctx->rg, &ss.addr); break; case addRemoveSomething_What_RM_LOCALPREFIX: retVal = RouteGen_removeLocalPrefix(ctx->rg, &ss.addr); break; default: Assert_failure("invalid op"); } if (!retVal) { error = "no_such_route"; } else { error = "none"; } } Dict_putString(out, String_new("error", requestAlloc), String_new(error, requestAlloc), requestAlloc); Admin_sendMessage(out, txid, ctx->admin); }
/** * Parse out an address. * * @param out a pointer to a byte array which will be set to the bytes of the ipv6 address. * @param hexAddr a string representation of the ipv6 address such as: * "fc4f:630d:e499:8f5b:c49f:6e6b:01ae:3120". * @return 0 if successful, -1 if the hexAddr is malformed. */ int AddrTools_parseIp(uint8_t out[16], const uint8_t hexAddr[40]) { struct Sockaddr_storage ss; if (Sockaddr_parse((const char*) hexAddr, &ss) || Sockaddr_getFamily(&ss.addr) != Sockaddr_AF_INET6) { return -1; } uint8_t* addr = NULL; Sockaddr_getAddress(&ss.addr, &addr); Bits_memcpy(out, addr, 16); 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 {
static void beginConnection(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc) { struct Context* ctx = vcontext; String* password = Dict_getString(args, String_CONST("password")); String* publicKey = Dict_getString(args, String_CONST("publicKey")); String* address = Dict_getString(args, String_CONST("address")); int64_t* interfaceNumber = Dict_getInt(args, String_CONST("interfaceNumber")); uint32_t ifNum = (interfaceNumber) ? ((uint32_t) *interfaceNumber) : 0; String* peerName = Dict_getString(args, String_CONST("peerName")); String* error = NULL; Log_debug(ctx->logger, "Peering with [%s]", publicKey->bytes); struct Sockaddr_storage ss; uint8_t pkBytes[32]; int ret; if (interfaceNumber && *interfaceNumber < 0) { error = String_CONST("negative interfaceNumber"); } else if ((ret = Key_parse(publicKey, pkBytes, NULL))) { error = String_CONST(Key_parse_strerror(ret)); } else if (Sockaddr_parse(address->bytes, &ss)) { error = String_CONST("unable to parse ip address and port."); } else if (Sockaddr_getFamily(&ss.addr) != Sockaddr_getFamily(ctx->udpIf->addr)) { error = String_CONST("different address type than this socket is bound to."); } else { struct Sockaddr* addr = &ss.addr; char* addrPtr = NULL; int addrLen = Sockaddr_getAddress(&ss.addr, &addrPtr); Assert_true(addrLen > 0); struct Allocator* tempAlloc = Allocator_child(ctx->alloc); if (Bits_isZero(addrPtr, addrLen)) { // unspec'd address, convert to loopback if (Sockaddr_getFamily(addr) == Sockaddr_AF_INET) { addr = Sockaddr_clone(Sockaddr_LOOPBACK, tempAlloc); } else if (Sockaddr_getFamily(addr) == Sockaddr_AF_INET6) { addr = Sockaddr_clone(Sockaddr_LOOPBACK6, tempAlloc); } else { Assert_failure("Sockaddr which is not AF_INET nor AF_INET6"); } Sockaddr_setPort(addr, Sockaddr_getPort(&ss.addr)); } int ret = InterfaceController_bootstrapPeer( ctx->ic, ifNum, pkBytes, addr, password, peerName, ctx->alloc); Allocator_free(tempAlloc); if (ret) { switch(ret) { case InterfaceController_bootstrapPeer_BAD_IFNUM: error = String_CONST("no such interface for interfaceNumber"); break; case InterfaceController_bootstrapPeer_BAD_KEY: error = String_CONST("invalid cjdns public key."); break; case InterfaceController_bootstrapPeer_OUT_OF_SPACE: error = String_CONST("no more space to register with the switch."); break; default: error = String_CONST("unknown error"); break; } } else { error = String_CONST("none"); } } Dict out = Dict_CONST(String_CONST("error"), String_OBJ(error), NULL); Admin_sendMessage(&out, txid, ctx->admin); }