static void initTunfd(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc) { struct Context* ctx = Identity_check((struct Context*) vcontext); struct Jmp jmp; Jmp_try(jmp) { int64_t* tunfd = Dict_getInt(args, String_CONST("tunfd")); int64_t* tuntype = Dict_getInt(args, String_CONST("type")); if (!tunfd || *tunfd < 0) { String* error = String_printf(requestAlloc, "Invalid tunfd"); sendResponse(error, ctx->admin, txid, requestAlloc); return; } int fileno = *tunfd; int type = (*tuntype) ? *tuntype : FileNo_Type_NORMAL; struct Pipe* p = Pipe_forFiles(fileno, fileno, ctx->base, &jmp.handler, ctx->alloc); p->logger = ctx->logger; if (type == FileNo_Type_ANDROID) { struct AndroidWrapper* aw = AndroidWrapper_new(ctx->alloc, ctx->logger); Iface_plumb(&aw->externalIf, &p->iface); Iface_plumb(&aw->internalIf, &ctx->nc->tunAdapt->tunIf); } else { Iface_plumb(&p->iface, &ctx->nc->tunAdapt->tunIf); } sendResponse(String_CONST("none"), ctx->admin, txid, requestAlloc); } Jmp_catch { String* error = String_printf(requestAlloc, "Failed to configure tunnel [%s]", jmp.message); sendResponse(error, ctx->admin, txid, requestAlloc); return; } }
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; }
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_raise(eh, TUNConfigurator_initTun_INTERNAL, 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, TUNConfigurator_IFNAMSIZ, "tun%d", ppa); } char* error = NULL; if (error) { int err = errno; close(tunFd); Except_raise(eh, TUNConfigurator_initTun_INTERNAL, "%s [%s]", error, strerror(err)); } struct Pipe* p = Pipe_forFiles(tunFd, tunFd, base, eh, alloc); return BSDMessageTypeWrapper_new(&p->iface, logger); }
static void sendConfToCore(struct Interface* toCoreInterface, struct Allocator* tempAlloc, Dict* config, struct Except* eh, struct Log* logger) { #define CONFIG_BUFF_SIZE 1024 uint8_t buff[CONFIG_BUFF_SIZE + 32] = {0}; uint8_t* start = buff + 32; struct Writer* writer = ArrayWriter_new(start, CONFIG_BUFF_SIZE - 33, tempAlloc); if (StandardBencSerializer_get()->serializeDictionary(writer, config)) { Except_raise(eh, -1, "Failed to serialize pre-configuration for core."); } struct Message* m = &(struct Message) { .bytes = start, .length = writer->bytesWritten, .padding = 32 }; m = Message_clone(m, tempAlloc); Log_keys(logger, "Sent [%d] bytes to core [%s].", m->length, m->bytes); toCoreInterface->sendMessage(m, toCoreInterface); } static void setUser(char* user, struct Log* logger, struct Except* eh) { struct Jmp jmp; Jmp_try(jmp) { Security_setUser(user, logger, &jmp.handler); } Jmp_catch { if (jmp.code == Security_setUser_PERMISSION) { return; } Except_raise(eh, jmp.code, "%s", jmp.message); } } static struct Pipe* getClientPipe(int argc, char** argv, struct EventBase* base, struct Except* eh, struct Allocator* alloc) { int inFromClientNo; int outToClientNo; if (argc < 4 || (inFromClientNo = atoi(argv[2])) == 0) { inFromClientNo = STDIN_FILENO; } if (argc < 4 || (outToClientNo = atoi(argv[3])) == 0) { outToClientNo = STDOUT_FILENO; } // named pipe. if (argc > 2 && inFromClientNo == STDIN_FILENO) { return Pipe_named(argv[2], base, eh, alloc); } return Pipe_forFiles(inFromClientNo, outToClientNo, base, eh, alloc); }
struct Interface* TUNInterface_new(const char* interfaceName, char assignedInterfaceName[TUNInterface_IFNAMSIZ], struct EventBase* base, struct Log* logger, struct Except* eh, struct Allocator* alloc) { // 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_raise(eh, TUNInterface_new_INTERNAL, 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; 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_raise(eh, TUNInterface_new_INTERNAL, "%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 }));
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; }
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; }