/** * Open the tun device. * * @param interfaceName the interface name you *want* to use or NULL to let the kernel decide. * @param assignedInterfaceName the interface name you get. * @param log * @param eh * @return a file descriptor for the tunnel. */ void* TUNConfigurator_initTun(const char* interfaceName, char assignedInterfaceName[TUNConfigurator_IFNAMSIZ], struct Log* logger, struct Except* eh) { // Open the descriptor int tunFd = open("/dev/tun", 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); } } if (tunFd < 0 || ppa < 0 ) { enum Errno err = Errno_get(); close(tunFd); char* error = NULL; if (tunFd < 0) { error = "open(\"/dev/tun\")"; } else if (ppa < 0) { error = "fdevname/getting number from fdevname"; } Except_raise(eh, TUNConfigurator_initTun_INTERNAL, error, Errno_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 snprintf(assignedInterfaceName, TUNConfigurator_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) { enum Errno err = Errno_get(); close(tunFd); Except_raise(eh, TUNConfigurator_initTun_INTERNAL, "%s [%s]", error, Errno_strerror(err)); } intptr_t ret = (intptr_t) tunFd; return (void*) ret; }
/** @see BencSerializer.h */ static int32_t parseint64_t(const struct Reader* reader, int64_t* output) { uint8_t buffer[32]; for (int i = 0; i < 21; i++) { int32_t status = reader->read(buffer + i, 0, reader); if (i == 0 && buffer[i] == '-' && status == 0) { // It's just a negative number, no need to fail it. continue; } if (buffer[i] < '0' || buffer[i] > '9' || status != 0 /* end of input */) { buffer[i] = '\0'; Errno_clear(); int64_t out = strtol((char*)buffer, NULL, 10); // Failed parse causes 0 to be set. if (out == 0 && buffer[0] != '0' && (buffer[0] != '-' || buffer[1] != '0')) { printf("Failed to parse \"%s\": not a number\n",buffer); return UNPARSABLE; } if ((out == INT64_MAX || out == INT64_MIN) && Errno_get() == Errno_ERANGE) { printf("Failed to parse \"%s\": number too large/small\n",buffer); return UNPARSABLE; } *output = out; return 0; } reader->skip(1, reader); } // Larger than the max possible int64. buffer[22] = '\0'; printf("Failed to parse \"%s\": number too large\n",buffer); return UNPARSABLE; }
static uint8_t sendMessage(struct Message* message, struct Interface* iface) { struct UDPAddrInterface_pvt* context = Identity_cast((struct UDPAddrInterface_pvt*) iface->senderContext); struct Sockaddr_storage addrStore; Message_pop(message, &addrStore, context->pub.addr->addrLen); Assert_true(addrStore.addr.addrLen == context->pub.addr->addrLen); if (Socket_sendto(context->socket, message->bytes, message->length, 0, &addrStore.addr) < 0) { switch (Errno_get()) { case Errno_EMSGSIZE: return Error_OVERSIZE_MESSAGE; case Errno_ENOBUFS: case Errno_EAGAIN: return Error_LINK_LIMIT_EXCEEDED; default:; Log_info(context->logger, "Got error sending to socket [%s]", Errno_getString()); } } return 0; }
void TUNConfigurator_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_raise(eh, TUNConfigurator_ERROR_GETTING_ADMIN_SOCKET, "socket() failed [%s]", Errno_getString()); } 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) { enum Errno err = Errno_get(); close(s); Except_raise(eh, TUNConfigurator_setMTU_INTERNAL, "ioctl(SIOCSIFMTU) failed [%s]", Errno_strerror(err)); } }
/** @see BencSerializer.h */ static int32_t parseint64_t(const struct Reader* reader, int64_t* output) { #define OUT_OF_CONTENT_TO_READ -2 #define UNPARSABLE -3 char buffer[32]; int i; for (i = 0; ; i++) { if (reader->read(buffer + i, 1, reader) != 0) { return OUT_OF_CONTENT_TO_READ; } if (i == 0) { if (buffer[i] != 'i') { /* Not an int. */ return UNPARSABLE; } else { continue; } } if (buffer[i] == 'e') { break; } if (i == 1 && buffer[i] == '-') { /* It's just a negative number, no need to fail it. */ continue; } if (buffer[i] < '0' || buffer[i] > '9') { return UNPARSABLE; } if (i > 21) { /* Larger than the max possible int64. */ return UNPARSABLE; } } /* buffer + 1, skip the 'i' */ int64_t out = strtol(buffer + 1, NULL, 10); /* Failed parse causes 0 to be set. */ if (out == 0 && buffer[1] != '0' && (buffer[1] != '-' || buffer[2] != '0')) { return UNPARSABLE; } if ((out == LONG_MAX || out == LONG_MIN) && Errno_get() == Errno_ERANGE) { /* errno (holds nose) */ return UNPARSABLE; } *output = out; return 0; #undef OUT_OF_CONTENT_TO_READ #undef UNPARSABLE }
void TUNConfigurator_setIpAddress(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_raise(eh, TUNConfigurator_setIpAddress_INTERNAL, "bad IPv6 address [%s]", gai_strerror(err)); } Bits_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_raise(eh, TUNConfigurator_setIpAddress_INTERNAL, "socket() failed [%s]", Errno_getString()); } if (ioctl(s, SIOCAIFADDR_IN6, &in6_addreq) < 0) { enum Errno err = Errno_get(); close(s); Except_raise(eh, TUNConfigurator_setIpAddress_INTERNAL, "ioctl(SIOCAIFADDR) failed [%s]", Errno_strerror(err)); } Log_info(logger, "Configured IPv6 [%s/%i] for [%s]", myIp, prefixLen, interfaceName); close(s); }
/** * handle incoming tcp data from client connections in the admin process */ static void incomingFromClient(evutil_socket_t socket, short eventType, void* vconn) { struct Connection* conn = (struct Connection*) vconn; struct AngelContext* context = conn->context; uint8_t buf[PipeInterface_MAX_MESSAGE_SIZE + PipeInterface_PADDING]; uint32_t connNumber = conn - context->connections; struct Message message = { .bytes = buf + PipeInterface_PADDING, .length = PipeInterface_MAX_MESSAGE_SIZE, .padding = PipeInterface_PADDING }; ssize_t result = recv(socket, message.bytes, message.length, 0); if (result > 0) { message.length = result; sendToCore(&message, connNumber, context); } else if (result < 0 && Errno_get() == Errno_EAGAIN) { return; } else { // The return value will be 0 when the peer has performed an orderly shutdown. EVUTIL_CLOSESOCKET(conn->socket); event_free(conn->read); conn->read = NULL; // send close channel message.length = 0; sendToCore(&message, connNumber, context); // set conn->socket = -1 later when we recv close ACK } } static struct Connection* newConnection(struct AngelContext* context, evutil_socket_t fd) { struct Connection* conn = NULL; for (int i = 0; i < Angel_MAX_CONNECTIONS; i++) { if (context->connections[i].read == NULL && context->connections[i].socket == -1) { conn = &context->connections[i]; break; } } if (!conn) { return NULL; } conn->read = event_new(context->eventBase, fd, EV_READ | EV_PERSIST, incomingFromClient, conn); conn->socket = fd; conn->context = context; if (!conn->read) { return NULL; } event_add(conn->read, NULL); return conn; } static void acceptConn(evutil_socket_t socket, short eventType, void* vcontext) { struct AngelContext* context = (struct AngelContext*) vcontext; struct sockaddr_storage ss; ev_socklen_t slen = sizeof(ss); evutil_socket_t fd = accept(socket, (struct sockaddr*)&ss, &slen); if (fd < 0) { perror("acceptConn() fd < 0"); return; } else if (fd > (evutil_socket_t) FD_SETSIZE) { EVUTIL_CLOSESOCKET(fd); return; } evutil_make_socket_nonblocking(fd); struct Connection* conn = newConnection(context, fd); if (!conn) { EVUTIL_CLOSESOCKET(fd); } } void Angel_start(String* pass, evutil_socket_t tcpSocket, struct Interface* coreIface, struct event_base* eventBase, struct Log* logger, struct Allocator* alloc) { struct AngelContext contextStore; struct AngelContext* context = &contextStore; Bits_memset(context, 0, sizeof(struct AngelContext)); for (int i = 0; i < Angel_MAX_CONNECTIONS; i++) { context->connections[i].socket = -1; } context->eventBase = eventBase; context->logger = logger; context->coreIface = coreIface; context->coreIface->receiveMessage = receiveMessage; context->coreIface->receiverContext = context; context->socketEvent = event_new(context->eventBase, tcpSocket, EV_READ | EV_PERSIST, acceptConn, context); event_add(context->socketEvent, NULL); event_base_dispatch(context->eventBase); }