static void dns(Dict* dns, struct Context* ctx, struct Except* eh) { List* servers = Dict_getList(dns, String_CONST("servers")); int count = List_size(servers); for (int i = 0; i < count; i++) { String* server = List_getString(servers, i); if (!server) { Except_throw(eh, "dns.servers[%d] is not a string", i); } Dict* d = Dict_new(ctx->alloc); Dict_putString(d, String_CONST("addr"), server, ctx->alloc); rpcCall(String_CONST("RainflyClient_addServer"), d, ctx, ctx->alloc); } List* keys = Dict_getList(dns, String_CONST("keys")); count = List_size(keys); for (int i = 0; i < count; i++) { String* key = List_getString(keys, i); if (!key) { Except_throw(eh, "dns.keys[%d] is not a string", i); } Dict* d = Dict_new(ctx->alloc); Dict_putString(d, String_CONST("ident"), key, ctx->alloc); rpcCall(String_CONST("RainflyClient_addKey"), d, ctx, ctx->alloc); } int64_t* minSigs = Dict_getInt(dns, String_CONST("minSignatures")); if (minSigs) { Dict* d = Dict_new(ctx->alloc); Dict_putInt(d, String_CONST("count"), *minSigs, ctx->alloc); rpcCall(String_CONST("RainflyClient_minSignatures"), d, ctx, ctx->alloc); } }
struct Interface* TUNInterface_new(const char* interfaceName, char assignedInterfaceName[TUNInterface_IFNAMSIZ], struct EventBase* base, struct Log* logger, struct Except* eh, struct Allocator* alloc) { uint32_t maxNameSize = (IFNAMSIZ < TUNInterface_IFNAMSIZ) ? IFNAMSIZ : TUNInterface_IFNAMSIZ; Log_info(logger, "Initializing tun device [%s]", ((interfaceName) ? interfaceName : "auto")); struct ifreq ifRequest = { .ifr_flags = IFF_TUN }; if (interfaceName) { if (strlen(interfaceName) > maxNameSize) { Except_throw(eh, "tunnel name too big, limit is [%d] characters", maxNameSize); } strncpy(ifRequest.ifr_name, interfaceName, maxNameSize); } int fileno = open(DEVICE_PATH, O_RDWR); if (fileno < 0) { Except_throw(eh, "open(\"%s\") [%s]", DEVICE_PATH, strerror(errno)); } if (ioctl(fileno, TUNSETIFF, &ifRequest) < 0) { int err = errno; close(fileno); Except_throw(eh, "ioctl(TUNSETIFF) [%s]", strerror(err)); } strncpy(assignedInterfaceName, ifRequest.ifr_name, maxNameSize); struct Pipe* p = Pipe_forFiles(fileno, fileno, base, eh, alloc); return &p->iface; }
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); }
void NetPlatform_setMTU(const char* interfaceName, uint32_t mtu, struct Log* logger, struct Except* eh) { int s = socket(AF_INET6, SOCK_DGRAM, 0); if (s < 0) { Except_throw(eh, "socket() [%s]", strerror(errno)); } struct ifreq ifRequest; strncpy(ifRequest.ifr_name, interfaceName, IFNAMSIZ); ifRequest.ifr_mtu = mtu; Log_info(logger, "Setting MTU for device [%s] to [%u] bytes.", interfaceName, mtu); if (ioctl(s, SIOCSIFMTU, &ifRequest) < 0) { int err = errno; close(s); Except_throw(eh, "ioctl(SIOCSIFMTU) failed [%s]", strerror(err)); } }
static void checkInterfaceUp(int socket, struct ifreq* ifRequest, struct Log* logger, struct Except* eh) { if (ioctl(socket, SIOCGIFFLAGS, ifRequest) < 0) { int err = errno; close(socket); Except_throw(eh, "ioctl(SIOCGIFFLAGS) [%s]", strerror(err)); } if (ifRequest->ifr_flags & IFF_UP & IFF_RUNNING) { // already up. return; } Log_info(logger, "Bringing up interface [%s]", ifRequest->ifr_name); ifRequest->ifr_flags |= IFF_UP | IFF_RUNNING; if (ioctl(socket, SIOCSIFFLAGS, ifRequest) < 0) { int err = errno; close(socket); Except_throw(eh, "ioctl(SIOCSIFFLAGS) [%s]", strerror(err)); } }
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); } }
static void addIp4Address(const char* interfaceName, const uint8_t address[4], int prefixLen, struct Log* logger, struct Except* eh) { struct ifaliasreq ifaliasreq; struct sockaddr_in* in; memset(&ifaliasreq, 0, sizeof(ifaliasreq)); snprintf(ifaliasreq.ifra_name,IFNAMSIZ, "%s",interfaceName); char myIp[40]; snprintf(myIp, 40, "%u.%u.%u.%u", address[0], address[1], address[2], address[3]); in_addr_t nmask = ( ~((1 << (32 - prefixLen)) - 1) ); char myMask[40]; snprintf(myMask,40,"%u",nmask); in = (struct sockaddr_in *) &ifaliasreq.ifra_addr; in->sin_family = AF_INET; in->sin_len = sizeof(ifaliasreq.ifra_addr); int err = inet_aton(myIp, &in->sin_addr); if (err == 0){ Except_throw(eh, "inet_aton(myIp) failed"); } in = (struct sockaddr_in *) &ifaliasreq.ifra_mask; in->sin_family = AF_INET; in->sin_len = sizeof(ifaliasreq.ifra_mask); err = inet_aton(myMask, &in->sin_addr); if (err == 0){ Except_throw(eh, "inet_aton(myMask) failed"); } in = (struct sockaddr_in *) &ifaliasreq.ifra_broadaddr; in->sin_family = AF_INET; in->sin_len = sizeof(ifaliasreq.ifra_broadaddr); in->sin_addr.s_addr = ((struct sockaddr_in *) &ifaliasreq.ifra_addr)->sin_addr.s_addr | ~ ((struct sockaddr_in *) &ifaliasreq.ifra_mask)->sin_addr.s_addr; int s = socket(PF_INET, SOCK_STREAM, 0); if (ioctl(s, SIOCAIFADDR, &ifaliasreq) == -1){ int err = errno; close(s); Except_throw(eh, "ioctl(SIOCAIFADDR) [%s]",strerror(err)); } Log_info(logger, "Configured IPv4 [%s/%s] for [%s]", myIp, myMask, interfaceName); close(s); }
struct Interface* TUNInterface_new(const char* interfaceName, char assignedInterfaceName[TUNInterface_IFNAMSIZ], int isTapMode, struct EventBase* base, struct Log* logger, struct Except* eh, struct Allocator* alloc) { if (isTapMode) { Except_throw(eh, "tap mode not supported on this platform"); } // to store the tunnel device index int ppa = 0; // Open the descriptor int tunFd = open("/dev/tun0", O_RDWR); if (tunFd == -1) { tunFd = open("/dev/tun1", O_RDWR); ppa = 1; } if (tunFd == -1) { tunFd = open("/dev/tun2", O_RDWR); ppa = 2; } if (tunFd == -1) { tunFd = open("/dev/tun3", O_RDWR); ppa = 3; } if (tunFd < 0 ) { int err = errno; close(tunFd); char* error = NULL; if (tunFd < 0) { error = "open(\"/dev/tunX\")"; } Except_throw(eh, "%s [%s]", error, strerror(err)); } // Since devices are numbered rather than named, it's not possible to have tun0 and cjdns0 // so we'll skip the pretty names and call everything tunX if (assignedInterfaceName) { snprintf(assignedInterfaceName, TUNInterface_IFNAMSIZ, "tun%d", ppa); } char* error = NULL; if (error) { int err = errno; close(tunFd); Except_throw(eh, "%s [%s]", error, strerror(err)); } struct Pipe* p = Pipe_forFiles(tunFd, tunFd, base, eh, alloc); return BSDMessageTypeWrapper_new(&p->iface, logger); }
void NetPlatform_addAddress(const char* interfaceName, const uint8_t* address, int prefixLen, int addrFam, struct Log* logger, struct Allocator* tempAlloc, struct Except* eh) { struct ifreq ifRequest; int s = socketForIfName(interfaceName, addrFam, eh, &ifRequest); int ifIndex = ifRequest.ifr_ifindex; // checkInterfaceUp() clobbers the ifindex. checkInterfaceUp(s, &ifRequest, logger, eh); if (addrFam == Sockaddr_AF_INET6) { struct in6_ifreq ifr6 = { .ifr6_ifindex = ifIndex, .ifr6_prefixlen = prefixLen }; memcpy(&ifr6.ifr6_addr, address, 16); if (ioctl(s, SIOCSIFADDR, &ifr6) < 0) { int err = errno; close(s); Except_throw(eh, "ioctl(SIOCSIFADDR) [%s]", strerror(err)); } } else if (addrFam == Sockaddr_AF_INET) {
static void sendMessageInternal(struct Message* message, struct sockaddr_ll* addr, struct ETHInterface_pvt* context, struct Except* exHandler) { /* Cut down on the noise uint8_t buff[sizeof(*addr) * 2 + 1] = {0}; Hex_encode(buff, sizeof(buff), (uint8_t*)addr, sizeof(*addr)); Log_debug(context->logger, "Sending ethernet frame to [%s]", buff); */ if (sendto(context->socket, message->bytes, message->length, 0, (struct sockaddr*) addr, sizeof(struct sockaddr_ll)) < 0) { switch (errno) { default:; Log_info(context->logger, "[%s] Got error sending to socket [%s]", context->ifName->bytes, strerror(errno)); Except_throw(exHandler, "Interface %s removed: [%s]", context->ifName->bytes, strerror(errno)); case EMSGSIZE: case ENOBUFS: case EAGAIN:; // todo: care } } return; }
void Seccomp_dropPermissions(struct Allocator* tempAlloc, struct Log* logger, struct Except* eh) { struct sock_fprog* filter = mkFilter(tempAlloc, eh); installFilter(filter, logger, eh); if (!Seccomp_isWorking()) { Except_throw(eh, "Seccomp filter not installed properly, Seccomp_isWorking() -> false"); } }
static void addIp4Address(const char* interfaceName, const uint8_t address[4], int prefixLen, struct Log* logger, struct Except* eh) { Except_throw(eh, "unimplemented"); }
void NetPlatform_addRoute(const char* interfaceName, const uint8_t* address, int prefixLen, int addrFam, struct Log* logger, struct Except* eh) { Except_throw(eh, "NetPlatform_addRoute is not implemented in this platform."); }
static void addIp4Address(const char* interfaceName, const uint8_t address[4], int prefixLen, struct Log* logger, struct Except* eh) { // TODO(cjd): implement this and then remove the exception from TUNInterface_ipv4_root_test.c Except_throw(eh, "unimplemented"); }
void NetPlatform_setRoutes(const char* ifName, struct Sockaddr** prefixSet, int prefixCount, struct Log* logger, struct Allocator* tempAlloc, struct Except* eh) { Except_throw(eh, "NetPlatform_setRoutes is not implemented in this platform."); }
static void checkRunningInstance(struct Allocator* allocator, struct EventBase* base, String* addr, String* password, struct Log* logger, struct Except* eh) { struct Allocator* alloc = Allocator_child(allocator); struct Sockaddr_storage pingAddrStorage; if (Sockaddr_parse(addr->bytes, &pingAddrStorage)) { Except_throw(eh, "Unable to parse [%s] as an ip address port, eg: 127.0.0.1:11234", addr->bytes); } struct AdminClient* adminClient = AdminClient_new(&pingAddrStorage.addr, password, base, logger, alloc); // 100 milliseconds is plenty to wait for a process to respond on the same machine. adminClient->millisecondsToWait = 100; Dict* pingArgs = Dict_new(alloc); struct AdminClient_Promise* pingPromise = AdminClient_rpcCall(String_new("ping", alloc), pingArgs, adminClient, alloc); struct CheckRunningInstanceContext* ctx = Allocator_malloc(alloc, sizeof(struct CheckRunningInstanceContext)); ctx->base = base; ctx->alloc = alloc; ctx->res = NULL; pingPromise->callback = checkRunningInstanceCallback; pingPromise->userData = ctx; EventBase_beginLoop(base); Assert_true(ctx->res); if (ctx->res->err != AdminClient_Error_TIMEOUT) { Except_throw(eh, "Startup failed: cjdroute is already running. [%d]", ctx->res->err); } Allocator_free(alloc); }
/** * Get a socket and ifRequest for a given interface by name. * * @param interfaceName the name of the interface, eg: tun0 * @param af either AF_INET or AF_INET6 * @param eg an exception handler in case something goes wrong. * this will send a -1 for all errors. * @param ifRequestOut an ifreq which will be populated with the interface index of the interface. * @return a socket for interacting with this interface. */ static int socketForIfName(const char* interfaceName, int af, struct Except* eh, struct ifreq* ifRequestOut) { int s; if ((s = socket(af, SOCK_DGRAM, 0)) < 0) { Except_throw(eh, "socket() [%s]", strerror(errno)); } memset(ifRequestOut, 0, sizeof(struct ifreq)); strncpy(ifRequestOut->ifr_name, interfaceName, IFNAMSIZ); if (ioctl(s, SIOCGIFINDEX, ifRequestOut) < 0) { int err = errno; close(s); Except_throw(eh, "ioctl(SIOCGIFINDEX) [%s]", strerror(err)); } return s; }
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 void addIp6Address(const char* interfaceName, const uint8_t address[16], int prefixLen, struct Log* logger, struct Except* eh) { /* stringify our IP address */ char myIp[40]; AddrTools_printIp((uint8_t*)myIp, address); /* set up the interface ip assignment request */ struct in6_aliasreq in6_addreq; memset(&in6_addreq, 0, sizeof(in6_addreq)); in6_addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; in6_addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; /* parse the IPv6 address and add it to the request */ struct addrinfo hints, *result; bzero(&hints, sizeof(struct addrinfo)); hints.ai_family = AF_INET6; int err = getaddrinfo((const char *)myIp, NULL, &hints, &result); if (err) { // Should never happen since the address is specified as binary. Except_throw(eh, "bad IPv6 address [%s]", gai_strerror(err)); } memcpy(&in6_addreq.ifra_addr, result->ai_addr, result->ai_addrlen); /* turn the prefixlen into a mask, and add it to the request */ struct sockaddr_in6* mask = &in6_addreq.ifra_prefixmask; u_char *cp; int len = prefixLen; mask->sin6_len = sizeof(*mask); if ((prefixLen == 0) || (prefixLen == 128)) { memset(&mask->sin6_addr, 0xff, sizeof(struct in6_addr)); } else { memset((void *)&mask->sin6_addr, 0x00, sizeof(mask->sin6_addr)); for (cp = (u_char *)&mask->sin6_addr; len > 7; len -= 8) { *cp++ = 0xff; } *cp = 0xff << (8 - len); } strncpy(in6_addreq.ifra_name, interfaceName, sizeof(in6_addreq.ifra_name)); /* do the actual assignment ioctl */ int s = socket(AF_INET6, SOCK_DGRAM, 0); if (s < 0) { Except_throw(eh, "socket() [%s]", strerror(errno)); } if (ioctl(s, SIOCAIFADDR_IN6, &in6_addreq) < 0) { int err = errno; close(s); Except_throw(eh, "ioctl(SIOCAIFADDR) [%s]", strerror(err)); } Log_info(logger, "Configured IPv6 [%s/%i] for [%s]", myIp, prefixLen, interfaceName); close(s); }
struct Iface* TUNInterface_new(const char* interfaceName, char assignedInterfaceName[TUNInterface_IFNAMSIZ], int isTapMode, struct EventBase* base, struct Log* logger, struct Except* eh, struct Allocator* alloc) { if (isTapMode) { Except_throw(eh, "tap mode not supported on this platform"); } int maxNameSize = (IFNAMSIZ < TUNInterface_IFNAMSIZ) ? IFNAMSIZ : TUNInterface_IFNAMSIZ; int tunUnit = 0; /* allocate dynamically by default */ if (interfaceName) { int parsedUnit = 0; if (sscanf(interfaceName, "utun%i", &parsedUnit) != 1 || parsedUnit < 0) { Except_throw(eh, "Invalid utun device %s", interfaceName); } tunUnit = parsedUnit + 1; /* device number used is unit - 1*/ } Log_info(logger, "Initializing utun interface: %s\n", (interfaceName ? interfaceName : "auto")); int tunFd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL); if (tunFd < 0) { Except_throw(eh, "socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL) [%s]", strerror(errno)); } /* get the utun control id */ struct ctl_info info; memset(&info, 0, sizeof(info)); strncpy(info.ctl_name, APPLE_UTUN_CONTROL, strlen(APPLE_UTUN_CONTROL)); if (ioctl(tunFd, CTLIOCGINFO, &info) < 0) { int err = errno; close(tunFd); Except_throw(eh, "getting utun device id [%s]", strerror(err)); } /* connect the utun device */ struct sockaddr_ctl addr; addr.sc_id = info.ctl_id; addr.sc_len = sizeof(addr); addr.sc_family = AF_SYSTEM; addr.ss_sysaddr = AF_SYS_CONTROL; addr.sc_unit = tunUnit; if (connect(tunFd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { int err = errno; close(tunFd); Except_throw(eh, "connecting to utun device [%s]", strerror(err)); } char assignedIfName[TUNInterface_IFNAMSIZ]; if (!assignedInterfaceName) { assignedInterfaceName = assignedIfName; } /* retrieve the assigned utun interface name */ if (getsockopt(tunFd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, assignedInterfaceName, (uint32_t*) &maxNameSize) >= 0) { Log_info(logger, "Initialized utun interface [%s]\n", assignedInterfaceName); } else { int err = errno; close(tunFd); Except_throw(eh, "getting utun interface name [%s]", strerror(err)); } struct Pipe* p = Pipe_forFiles(tunFd, tunFd, base, eh, alloc); struct BSDMessageTypeWrapper* bmtw = BSDMessageTypeWrapper_new(alloc, logger); Iface_plumb(&p->iface, &bmtw->wireSide); return &bmtw->inside; }
struct Interface* TUNInterface_new(const char* interfaceName, char assignedInterfaceName[TUNInterface_IFNAMSIZ], int isTapMode, struct EventBase* base, struct Log* logger, struct Except* eh, struct Allocator* alloc) { // tap mode is not supported at all by the sunos tun driver. if (isTapMode) { Except_throw(eh, "tap mode not supported on this platform"); } // Extract the number eg: 0 from tun0 int ppa = 0; if (interfaceName) { for (uint32_t i = 0; i < strlen(interfaceName); i++) { if (isdigit(interfaceName[i])) { ppa = atoi(interfaceName); } } } // Open the descriptor int tunFd = open("/dev/tun", O_RDWR); // Either the name is specified and we use TUNSETPPA, // or it's not specified and we just want a TUNNEWPPA if (ppa) { ppa = ioctl(tunFd, TUNSETPPA, ppa); } else { ppa = ioctl(tunFd, TUNNEWPPA, -1); } int ipFd = open("/dev/ip6", O_RDWR, 0); int tunFd2 = open("/dev/tun", O_RDWR, 0); if (tunFd < 0 || ipFd < 0 || ppa < 0 || tunFd2 < 0) { int err = errno; close(tunFd); close(ipFd); close(tunFd2); char* error = NULL; if (tunFd < 0) { error = "open(\"/dev/tun\")"; } else if (ipFd < 0) { error = "open(\"/dev/ip6\")"; } else if (ppa < 0) { error = "ioctl(TUNNEWPPA)"; } else if (tunFd2 < 0) { error = "open(\"/dev/tun\") (opening for plumbing interface)"; } Except_throw(eh, "%s [%s]", error, strerror(err)); } struct lifreq ifr = { .lifr_ppa = ppa, .lifr_flags = IFF_IPV6 }; // Since devices are numbered rather than named, it's not possible to have tun0 and cjdns0 // so we'll skip the pretty names and call everything tunX int maxNameSize = (LIFNAMSIZ < TUNInterface_IFNAMSIZ) ? LIFNAMSIZ : TUNInterface_IFNAMSIZ; if (assignedInterfaceName) { snprintf(assignedInterfaceName, maxNameSize, "tun%d", ppa); } snprintf(ifr.lifr_name, maxNameSize, "tun%d", ppa); char* error = NULL; if (ioctl(tunFd, I_SRDOPT, RMSGD) < 0) { error = "putting tun into message-discard mode"; } else if (ioctl(tunFd2, I_PUSH, "ip") < 0) { // add the ip module error = "ioctl(I_PUSH)"; } else if (ioctl(tunFd2, SIOCSLIFNAME, &ifr) < 0) { // set the name of the interface and specify it as ipv6 error = "ioctl(SIOCSLIFNAME)"; } else if (ioctl(ipFd, I_LINK, tunFd2) < 0) { // link the device to the ipv6 router error = "ioctl(I_LINK)"; } if (error) { int err = errno; close(ipFd); close(tunFd2); close(tunFd); Except_throw(eh, "%s [%s]", error, strerror(err)); } close(ipFd); struct Pipe* p = Pipe_forFiles(tunFd, tunFd, base, eh, alloc); struct TUNInterface_Illumos_pvt* ctx = Allocator_clone(alloc, (&(struct TUNInterface_Illumos_pvt) { .pipe = p }));
int main(int argc, char** argv) { Assert_ifParanoid(argc > 0); struct Allocator* allocator = MallocAllocator_new(1<<23); if (argc != 6 || (argc == 2 && (!(CString_strcmp(argv[1], "--help") == 0) || (CString_strcmp(argv[1], "-h") == 0)))) { return usage(allocator, argv[0]); } struct Except* eh = NULL; struct EventBase* eventBase = EventBase_new(allocator); struct Log* logger = FileWriterLog_new(stdout, allocator); String* privateKey = String_new(argv[3], allocator); String* adminBind = String_new(argv[4], allocator); String* adminPass = String_new(argv[5], allocator); String* logTo = String_new("stdout", allocator); // --------------------- Welcome to cjdns ---------------------- // char* sysInfo = SysInfo_describe(SysInfo_detect(), allocator); Log_info(logger, "Cjdns %s %s", ArchInfo_getArchStr(), sysInfo); // --------------------- Setup Pipes to Angel --------------------- // struct Allocator* corePipeAlloc = Allocator_child(allocator); String* corePipeDir = String_new(argv[1], allocator); String* corePipeName = String_new(argv[2], allocator); if (!Defined(win32) && access(corePipeDir->bytes, W_OK)) { Except_throw(eh, "Don't have write permission to [%s].", corePipeDir->bytes); } Assert_ifParanoid(EventBase_eventCount(eventBase) == 0); struct Pipe* corePipe = Pipe_named(corePipeDir->bytes, corePipeName->bytes, eventBase, eh, corePipeAlloc); Assert_ifParanoid(EventBase_eventCount(eventBase) == 2); corePipe->logger = logger; // --------------------- Pre-Configure Core ------------------------- // Dict* preConf = Dict_new(allocator); Dict* adminPreConf = Dict_new(allocator); Dict* logPreConf = Dict_new(allocator); Dict_putDict(preConf, String_CONST("admin"), adminPreConf, allocator); Dict_putDict(preConf, String_CONST("logging"), logPreConf, 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); Dict_putString(logPreConf, String_CONST("logTo"), logTo, allocator); struct Message* toCoreMsg = Message_new(0, 1024, allocator); BencMessageWriter_write(preConf, toCoreMsg, eh); Iface_CALL(corePipe->iface.send, toCoreMsg, &corePipe->iface); Log_debug(logger, "Sent [%d] bytes to core.", toCoreMsg->length); // --------------------- Get Response from Core --------------------- // struct Message* fromCoreMsg = InterfaceWaiter_waitForData(&corePipe->iface, eventBase, allocator, eh); Dict* responseFromCore = BencMessageReader_read(fromCoreMsg, allocator, eh); // --------------------- Close the Core Pipe --------------------- // Allocator_free(corePipeAlloc); corePipe = NULL; // --------------------- Get Admin Addr/Port/Passwd --------------------- // Dict* responseFromCoreAdmin = Dict_getDict(responseFromCore, String_CONST("admin")); adminBind = Dict_getString(responseFromCoreAdmin, String_CONST("bind")); if (!adminBind) { Except_throw(eh, "Didn't get ADMIN_BIND back from cjdroute."); } struct Sockaddr_storage adminAddr; if (Sockaddr_parse(adminBind->bytes, &adminAddr)) { Except_throw(eh, "Unable to parse [%s] as an IP address:port.", adminBind->bytes); } Assert_ifParanoid(EventBase_eventCount(eventBase) == 0); Log_info(logger, "Admin API ready at [%s].", adminBind->bytes); return 0; }
static Iface_DEFUN sendMessage(struct Message* msg, struct Iface* iface) { struct ETHInterface_pvt* ctx = Identity_containerOf(iface, struct ETHInterface_pvt, pub.generic.iface); struct Sockaddr* sa = (struct Sockaddr*) msg->bytes; Assert_true(msg->length >= Sockaddr_OVERHEAD); Assert_true(sa->addrLen <= ETHInterface_Sockaddr_SIZE); struct ETHInterface_Sockaddr sockaddr = { .generic = { .addrLen = 0 } }; Message_pop(msg, &sockaddr, sa->addrLen, NULL); struct sockaddr_ll addr; Bits_memcpy(&addr, &ctx->addrBase, sizeof(struct sockaddr_ll)); if (sockaddr.generic.flags & Sockaddr_flags_BCAST) { Bits_memset(addr.sll_addr, 0xff, 6); } else { Bits_memcpy(addr.sll_addr, sockaddr.mac, 6); } struct ETHInterface_Header hdr = { .version = ETHInterface_CURRENT_VERSION, .zero = 0, .length_be = Endian_hostToBigEndian16(msg->length + ETHInterface_Header_SIZE), .fc00_be = Endian_hostToBigEndian16(0xfc00) }; Message_push(msg, &hdr, ETHInterface_Header_SIZE, NULL); struct Except* eh = NULL; sendMessageInternal(msg, &addr, ctx, eh); return NULL; } static void handleEvent2(struct ETHInterface_pvt* context, struct Allocator* messageAlloc) { struct Message* msg = Message_new(MAX_PACKET_SIZE, PADDING, messageAlloc); struct sockaddr_ll addr; uint32_t addrLen = sizeof(struct sockaddr_ll); // Knock it out of alignment by 2 bytes so that it will be // aligned when the idAndPadding is shifted off. Message_shift(msg, 2, NULL); int rc = recvfrom(context->socket, msg->bytes, msg->length, 0, (struct sockaddr*) &addr, &addrLen); if (rc < ETHInterface_Header_SIZE) { Log_debug(context->logger, "Failed to receive eth frame"); return; } Assert_true(msg->length >= rc); msg->length = rc; //Assert_true(addrLen == SOCKADDR_LL_LEN); struct ETHInterface_Header hdr; Message_pop(msg, &hdr, ETHInterface_Header_SIZE, NULL); // here we could put a switch statement to handle different versions differently. if (hdr.version != ETHInterface_CURRENT_VERSION) { Log_debug(context->logger, "DROP unknown version"); return; } uint16_t reportedLength = Endian_bigEndianToHost16(hdr.length_be); reportedLength -= ETHInterface_Header_SIZE; if (msg->length != reportedLength) { if (msg->length < reportedLength) { Log_debug(context->logger, "DROP size field is larger than frame"); return; } msg->length = reportedLength; } if (hdr.fc00_be != Endian_hostToBigEndian16(0xfc00)) { Log_debug(context->logger, "DROP bad magic"); return; } struct ETHInterface_Sockaddr sockaddr = { .zero = 0 }; Bits_memcpy(sockaddr.mac, addr.sll_addr, 6); sockaddr.generic.addrLen = ETHInterface_Sockaddr_SIZE; if (addr.sll_pkttype == PACKET_BROADCAST) { sockaddr.generic.flags |= Sockaddr_flags_BCAST; } Message_push(msg, &sockaddr, ETHInterface_Sockaddr_SIZE, NULL); Assert_true(!((uintptr_t)msg->bytes % 4) && "Alignment fault"); Iface_send(&context->pub.generic.iface, msg); } static void handleEvent(void* vcontext) { struct ETHInterface_pvt* context = Identity_check((struct ETHInterface_pvt*) vcontext); struct Allocator* messageAlloc = Allocator_child(context->pub.generic.alloc); handleEvent2(context, messageAlloc); Allocator_free(messageAlloc); } List* ETHInterface_listDevices(struct Allocator* alloc, struct Except* eh) { List* out = List_new(alloc); #ifndef android struct ifaddrs* ifaddr = NULL; if (getifaddrs(&ifaddr) || ifaddr == NULL) { Except_throw(eh, "getifaddrs() -> errno:%d [%s]", errno, strerror(errno)); } for (struct ifaddrs* ifa = ifaddr; ifa; ifa = ifa->ifa_next) { if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_PACKET) { List_addString(out, String_new(ifa->ifa_name, alloc), alloc); } } freeifaddrs(ifaddr); #endif return out; } static int closeSocket(struct Allocator_OnFreeJob* j) { struct ETHInterface_pvt* ctx = Identity_check((struct ETHInterface_pvt*) j->userData); close(ctx->socket); return 0; } struct ETHInterface* ETHInterface_new(struct EventBase* eventBase, const char* bindDevice, struct Allocator* alloc, struct Except* exHandler, struct Log* logger) { struct ETHInterface_pvt* ctx = Allocator_calloc(alloc, sizeof(struct ETHInterface_pvt), 1); Identity_set(ctx); ctx->pub.generic.iface.send = sendMessage; ctx->pub.generic.alloc = alloc; ctx->logger = logger; struct ifreq ifr = { .ifr_ifindex = 0 }; ctx->socket = socket(AF_PACKET, SOCK_DGRAM, Ethernet_TYPE_CJDNS); if (ctx->socket == -1) { Except_throw(exHandler, "call to socket() failed. [%s]", strerror(errno)); } Allocator_onFree(alloc, closeSocket, ctx); CString_strncpy(ifr.ifr_name, bindDevice, IFNAMSIZ - 1); ctx->ifName = String_new(bindDevice, alloc); if (ioctl(ctx->socket, SIOCGIFINDEX, &ifr) == -1) { Except_throw(exHandler, "failed to find interface index [%s]", strerror(errno)); } ctx->ifindex = ifr.ifr_ifindex; if (ioctl(ctx->socket, SIOCGIFFLAGS, &ifr) < 0) { Except_throw(exHandler, "ioctl(SIOCGIFFLAGS) [%s]", strerror(errno)); } if (!((ifr.ifr_flags & IFF_UP) && (ifr.ifr_flags & IFF_RUNNING))) { Log_info(logger, "Bringing up interface [%s]", ifr.ifr_name); ifr.ifr_flags |= IFF_UP | IFF_RUNNING; if (ioctl(ctx->socket, SIOCSIFFLAGS, &ifr) < 0) { Except_throw(exHandler, "ioctl(SIOCSIFFLAGS) [%s]", strerror(errno)); } } ctx->addrBase = (struct sockaddr_ll) { .sll_family = AF_PACKET, .sll_protocol = Ethernet_TYPE_CJDNS, .sll_ifindex = ctx->ifindex, .sll_hatype = ARPHRD_ETHER, .sll_pkttype = PACKET_OTHERHOST, .sll_halen = ETH_ALEN }; if (bind(ctx->socket, (struct sockaddr*) &ctx->addrBase, sizeof(struct sockaddr_ll))) { Except_throw(exHandler, "call to bind() failed [%s]", strerror(errno)); } Socket_makeNonBlocking(ctx->socket); Event_socketRead(handleEvent, ctx, ctx->socket, eventBase, alloc, exHandler); return &ctx->pub; }
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; }
struct Iface* TUNInterface_new(const char* interfaceName, char assignedInterfaceName[TUNInterface_IFNAMSIZ], int isTapMode, struct EventBase* base, struct Log* logger, struct Except* eh, struct Allocator* alloc) { char deviceFile[TUNInterface_IFNAMSIZ]; if (isTapMode) { Except_throw(eh, "tap mode not supported on this platform"); } // We are on FreeBSD so we just need to read /dev/tunxx to create the tun interface if (interfaceName) { snprintf(deviceFile,TUNInterface_IFNAMSIZ,"/dev/%s",interfaceName); } else { snprintf(deviceFile,TUNInterface_IFNAMSIZ,"%s","/dev/tun"); } // Open the descriptor int tunFd = open(deviceFile, O_RDWR); //Get the resulting device name const char* assignedDevname; assignedDevname = fdevname(tunFd); // Extract the number eg: 0 from tun0 int ppa = 0; for (uint32_t i = 0; i < strlen(assignedDevname); i++) { if (isdigit(assignedDevname[i])) { ppa = atoi(assignedDevname+i); break; } } if (tunFd < 0 || ppa < 0 ) { int err = errno; close(tunFd); char* error = NULL; if (tunFd < 0) { error = "open(\"/dev/tun\")"; } else if (ppa < 0) { error = "fdevname/getting number from fdevname"; } Except_throw(eh, "%s [%s]", error, strerror(err)); } // Since devices are numbered rather than named, it's not possible to have tun0 and cjdns0 // so we'll skip the pretty names and call everything tunX if (assignedInterfaceName) { snprintf(assignedInterfaceName, TUNInterface_IFNAMSIZ, "tun%d", ppa); } char* error = NULL; // We want to send IPv6 through our tun device, so we need to be able to specify "ethertype" int tunhead = 1; if (ioctl(tunFd,TUNSIFHEAD,&tunhead) == -1) { error = "TUNSIFHEAD"; } if (error) { int err = errno; close(tunFd); Except_throw(eh, "%s [%s]", error, strerror(err)); } struct Pipe* p = Pipe_forFiles(tunFd, tunFd, base, eh, alloc); struct BSDMessageTypeWrapper* bmtw = BSDMessageTypeWrapper_new(alloc, logger); Iface_plumb(&p->iface, &bmtw->wireSide); return &bmtw->inside; }