diff options
author | Benjamin Cohen <bencoh@notk.org> | 2012-04-23 00:39:22 +0200 |
---|---|---|
committer | Benjamin Cohen <bencoh@notk.org> | 2012-04-23 00:39:22 +0200 |
commit | f24cfe6c89b9943e63927c769024d4e0e146e79e (patch) | |
tree | 9beda9f4d8e1ab498edf7bfbe15a193303f2f6a5 | |
parent | 7339ae0b22820cd29cb59d8cbcab4263a2a16cf0 (diff) |
peervpn v0.022 (2012-04-22)v0.022
from http://www.peervpn.net/files/peervpn-0-022.tar.gz
http://www.peervpn.net/
-rw-r--r-- | Makefile | 5 | ||||
-rw-r--r-- | config.ic | 8 | ||||
-rw-r--r-- | console.ic | 10 | ||||
-rw-r--r-- | globals.ic | 5 | ||||
-rw-r--r-- | helpers.ic | 4 | ||||
-rw-r--r-- | init.ic | 34 | ||||
-rw-r--r-- | io.c | 436 | ||||
-rw-r--r-- | libp2psec/peermgt.c | 2 | ||||
-rw-r--r-- | mainloop.ic | 6 | ||||
-rw-r--r-- | peervpn.c | 11 | ||||
-rw-r--r-- | peervpn.conf | 26 | ||||
-rw-r--r-- | platform/ifconfig.c | 175 | ||||
-rw-r--r-- | platform/io.c | 855 | ||||
-rw-r--r-- | platform/tapwin.h | 73 | ||||
-rw-r--r-- | pwd.ic | 26 |
15 files changed, 1203 insertions, 473 deletions
@@ -1,6 +1,5 @@ -CC=cc -CFLAGS=-Os -LDFLAGS=-lcrypto -ldl -lz +CFLAGS+=-O2 +LDFLAGS+=-lcrypto -ldl -lz all: peervpn peervpn: peervpn.o @@ -123,6 +123,14 @@ static int parseConfigLine(char *line, int len, struct s_initconfig *cs) { strncpy(cs->tapname,&line[vpos],CONFPARSER_NAMEBUF_SIZE); return 1; } + else if(parseConfigLineCheckCommand(line,len,"ifconfig4",&vpos)) { + strncpy(cs->ifconfig4,&line[vpos],CONFPARSER_NAMEBUF_SIZE); + return 1; + } + else if(parseConfigLineCheckCommand(line,len,"ifconfig6",&vpos)) { + strncpy(cs->ifconfig6,&line[vpos],CONFPARSER_NAMEBUF_SIZE); + return 1; + } else if(parseConfigLineCheckCommand(line,len,"upcmd",&vpos)) { strncpy(cs->upcmd,&line[vpos],CONFPARSER_NAMEBUF_SIZE); return 1; @@ -27,7 +27,7 @@ static void printActivePeerTable() { // parse command -static void parseCMD(char *cmd, int cmdlen) { +static void decodeConsole(char *cmd, int cmdlen) { char text[4096]; unsigned char new_peeraddr[peeraddr_SIZE]; if(cmd[0] == 'A' || cmd[0] == 'a') { @@ -59,11 +59,3 @@ static void parseCMD(char *cmd, int cmdlen) { printActivePeerTable(); } } - - -// decode console command -static void decodeConsole() { - char cmd[COMMAND_BUFSIZE] = {0,0}; - int len = read(STDIN_FILENO, cmd, COMMAND_BUFSIZE); - if(len > 0) parseCMD(cmd,len); -} @@ -19,12 +19,11 @@ // version information #define PEERVPN_VERSION_MAJOR 0 -#define PEERVPN_VERSION_MINOR 21 +#define PEERVPN_VERSION_MINOR 22 // compile time options & timing parameters #define INITPEER_STORAGE 1024 -#define COMMAND_BUFSIZE 1024 #define POLLWAIT 1000 @@ -42,6 +41,8 @@ struct s_initconfig { char groupstr[CONFPARSER_NAMEBUF_SIZE+1]; char chrootstr[CONFPARSER_NAMEBUF_SIZE+1]; char networkname[CONFPARSER_NAMEBUF_SIZE+1]; + char ifconfig4[CONFPARSER_NAMEBUF_SIZE+1]; + char ifconfig6[CONFPARSER_NAMEBUF_SIZE+1]; char upcmd[CONFPARSER_NAMEBUF_SIZE+1]; char initpeers[CONFPARSER_NAMEBUF_SIZE+1]; char engines[CONFPARSER_NAMEBUF_SIZE+1]; @@ -18,7 +18,7 @@ // converts a big endian byte array to a hexstring (size of *out must be 2*len+1) -static void byteArrayToString(char *out, u_int8_t *in, int len) { +static void byteArrayToString(char *out, unsigned char *in, int len) { int i; out[0] = '\0'; for(i=0; i<len; i++) sprintf(&out[i*2], "%02X", in[i]); @@ -59,7 +59,7 @@ static void connectInitpeers() { unsigned char new_peeraddr[peeraddr_SIZE]; i=0;j=0;k=0; for(;;) { - j = *(u_int8_t *)(&g_initpeers[i]); + j = g_initpeers[i]; if((j > 0) && (i+j+1 < INITPEER_STORAGE)) { if(k) { port = &g_initpeers[i+1]; @@ -61,6 +61,7 @@ int loadengine(const char *engine_name) { void init(struct s_initconfig *initconfig) { int c,i,j,k,l,m; char str[256]; + char tapname[256]; // initialize signal handler g_mainloop = 1; @@ -71,7 +72,7 @@ void init(struct s_initconfig *initconfig) { // load initpeers i=0;j=0;k=0;l=0;m=0; - *(u_int8_t *)(&g_initpeers[0]) = 0; + g_initpeers[0] = 0; for(;;) { c = initconfig->initpeers[i]; if(m) { @@ -80,11 +81,11 @@ void init(struct s_initconfig *initconfig) { m=k-j; if(m>0) { if(m > 254) m = 254; - *(u_int8_t *)(&g_initpeers[l]) = (m+1); + g_initpeers[l] = (m+1); memcpy(&g_initpeers[l+1],&initconfig->initpeers[j],m); g_initpeers[l+1+m] = '\0'; l = l+2+m; - *(u_int8_t *)(&g_initpeers[l]) = 0; + g_initpeers[l] = 0; } m=0; } @@ -104,8 +105,12 @@ void init(struct s_initconfig *initconfig) { // enable console if(initconfig->enableconsole) { - g_enableconsole = 1; - if((fcntl(STDIN_FILENO,F_SETFL,O_NONBLOCK)) < 0) throwError("could not initialize console!"); + if(ioOpenSTDIN(&iostate)) { + g_enableconsole = 1; + } + else { + throwError("could not initialize console!"); + } } else { g_enableconsole = 0; @@ -139,16 +144,29 @@ void init(struct s_initconfig *initconfig) { // open tap device if(initconfig->enableeth) { printf("opening TAP device...\n"); - if(!ioOpenTap(&iostate, initconfig->tapname)) { + if(!ioOpenTap(&iostate, tapname, initconfig->tapname)) { g_enableeth = 0; throwError("tap device could not be opened!"); } else { g_enableeth = 1; + printf(" device \"%s\": ok.\n", tapname); + if(strlen(initconfig->ifconfig4) > 0) { + // configure IPv4 address + if(!(ifconfig4(tapname, strlen(tapname), initconfig->ifconfig4, strlen(initconfig->ifconfig4)))) { + logWarning("could not automatically configure IPv4 address!"); + } + } + if(strlen(initconfig->ifconfig6) > 0) { + // configure IPv6 address + if(!(ifconfig6(tapname, strlen(tapname), initconfig->ifconfig6, strlen(initconfig->ifconfig6)))) { + logWarning("could not automatically configure IPv6 address!"); + } + } if(strlen(initconfig->upcmd) > 0) { // execute shell command - if((system(initconfig->upcmd)) < 0) { - throwError("upcmd failed!"); + if((ifconfigExec(initconfig->upcmd)) < 0) { + logWarning("upcmd failed!"); } } } @@ -1,436 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2012 by Tobias Volk * - * mail@tobiasvolk.de * - * * - * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, either version 3 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see <http://www.gnu.org/licenses/>. * - ***************************************************************************/ - - -#ifndef F_IO_C -#define F_IO_C - - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <fcntl.h> -#include <netdb.h> -#include <poll.h> -#include <sys/ioctl.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <net/if.h> -#include <linux/if_tun.h> - - -// IDs. -#define IO_FDID_CONSOLE 0 -#define IO_FDID_UDPV4SOCKET 1 -#define IO_FDID_UDPV6SOCKET 2 -#define IO_FDID_TAP 3 -#define IO_FDID_COUNT 4 - - -// The IO state structure. -struct s_io_state { - struct pollfd fd[IO_FDID_COUNT]; -}; - - -// The IPv4 addr/port structure. -struct s_io_v4addr { - unsigned char addr[4]; - unsigned char port[2]; -}; - - -// The IPv6 addr/port structure. -struct s_io_v6addr { - unsigned char addr[16]; - unsigned char port[2]; -}; - - -// Opens TAP device. Returns 1 if successful. -static int ioOpenTap(struct s_io_state *iostate, const char *tapname) { - struct ifreq ifr; - char *file = "/dev/net/tun"; - int tapfd = open(file,(O_RDWR | O_NONBLOCK)); - - if(tapfd < 0) { - return 0; - } - - memset(&ifr,0,sizeof(ifr)); - ifr.ifr_flags = (IFF_TAP | IFF_NO_PI); - strncpy(ifr.ifr_name, tapname, sizeof(ifr.ifr_name) - 1); - if(ioctl(tapfd,TUNSETIFF,(void *)&ifr) < 0) { - return 0; - } - - iostate->fd[IO_FDID_TAP].fd = tapfd; - iostate->fd[IO_FDID_TAP].events = POLLIN; - return 1; -} - - -// Writes to TAP device. Returns number of bytes written. -static int ioWriteTap(struct s_io_state *iostate, const unsigned char *buf, const int len) { - return write(iostate->fd[IO_FDID_TAP].fd, buf, len); -} - - -// Reads from TAP device. Returns number of bytes read. -static int ioReadTap(struct s_io_state *iostate, unsigned char *buf, const int len) { - return read(iostate->fd[IO_FDID_TAP].fd, buf, len); -} - - -// Opens a socket. Returns 1 if successful. -static int ioOpenSocket(int *handle, const char *bindaddress, const char *bindport, const int domain, const int type, const int protocol) { - int ret; - int fd; - int one = 1; - const char *zeroport = "0"; - const char *useport; - const char *useaddr; - struct addrinfo *d = NULL; - struct addrinfo *di; - struct addrinfo hints; - if((fd = socket(domain, type, 0)) < 0) return 0; - if((fcntl(fd,F_SETFL,O_NONBLOCK)) < 0) return 0; - setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(int)); - memset(&hints,0,sizeof(struct addrinfo)); - hints.ai_family = domain; - hints.ai_socktype = type; - hints.ai_flags = AI_PASSIVE; - if(bindaddress == NULL) { - useaddr = NULL; - } - else { - if(strlen(bindaddress) > 0) { - useaddr = bindaddress; - } - else { - useaddr = NULL; - } - } - if(bindport == NULL) { - useport = zeroport; - } - else { - useport = bindport; - } - if(getaddrinfo(useaddr, useport, &hints, &d) == 0) { - ret = -1; - di = d; - while(di != NULL) { - if(bind(fd, di->ai_addr, di->ai_addrlen) == 0) { - ret = fd; - break; - } - di = di->ai_next; - } - freeaddrinfo(d); - if(ret < 0) { - close(fd); - return 0; - } - *handle = ret; - return 1; - } - else { - return 0; - } -} - - -// Get IPv6 UDP address from name. Returns 1 if successful. -static int ioGetUDPv6Address(struct s_io_v6addr *addr, const char *hostname, const char *port) { - int ret; - struct sockaddr_in6 *saddr; - struct addrinfo *d = NULL; - struct addrinfo hints; - if(hostname != NULL && port != NULL) { - memset(&hints,0,sizeof(struct addrinfo)); - hints.ai_family = AF_INET6; - hints.ai_socktype = SOCK_DGRAM; - hints.ai_flags = 0; - if(getaddrinfo(hostname, port, &hints, &d) == 0) { - if(d != NULL) { - saddr = (struct sockaddr_in6 *)d->ai_addr; - memcpy(addr->addr, saddr->sin6_addr.s6_addr, 16); - memcpy(addr->port, &saddr->sin6_port, 2); - ret = 1; - } - else { - ret = 0; - } - freeaddrinfo(d); - } - else { - ret = 0; - } - return ret; - } - else { - return 0; - } -} - - -// Opens an IPv6 UDP socket. Returns 1 if successful. -static int ioOpenUDPv6Socket(struct s_io_state *iostate, const char *bindaddress, const char *bindport) { - int fd; - if(ioOpenSocket(&fd, bindaddress, bindport, AF_INET6, SOCK_DGRAM, 0)) { - iostate->fd[IO_FDID_UDPV6SOCKET].fd = fd; - iostate->fd[IO_FDID_UDPV6SOCKET].events = POLLIN; - return 1; - } - else { - return 0; - } -} - - -// Sends an IPv6 UDP packet. Returns length of sent message. -static int ioSendUDPv6Packet(struct s_io_state *iostate, const unsigned char *buf, const int len, struct s_io_v6addr *destination) { - struct sockaddr_in6 addr; - memset(&addr, 0, sizeof(struct sockaddr_in6)); - addr.sin6_family = AF_INET6; - memcpy(addr.sin6_addr.s6_addr, destination->addr, 16); - memcpy(&addr.sin6_port, destination->port, 2); - return sendto(iostate->fd[IO_FDID_UDPV6SOCKET].fd, buf, len, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in6)); -} - - -// Receives an IPv6 UDP packet. Returns length of received message. -static int ioRecvUDPv6Packet(struct s_io_state *iostate, unsigned char *buf, const int len, struct s_io_v6addr *source) { - struct sockaddr_in6 addr; - socklen_t addrlen = sizeof(struct sockaddr_in6); - int ret = recvfrom(iostate->fd[IO_FDID_UDPV6SOCKET].fd, buf, len, 0, (struct sockaddr *)&addr, &addrlen); - if(ret > 0) { - memcpy(source->addr, addr.sin6_addr.s6_addr, 16); - memcpy(source->port, &addr.sin6_port, 2); - } - return ret; -} - - -// Convert UDPv6 address to 24 bit address. -static void ioConvertAddressFromUDPv6(unsigned char *address, const struct s_io_v6addr *v6addr) { - memset(address, 0, 24); - address[0] = 1; - address[1] = 6; - address[2] = 1; - memcpy(&address[4], &v6addr->addr, 16); - memcpy(&address[20], v6addr->port, 2); -} - - -// Get IPv4 UDP address from name. Returns 1 if successful. -static int ioGetUDPv4Address(struct s_io_v4addr *addr, const char *hostname, const char *port) { - int ret; - struct sockaddr_in *saddr; - struct addrinfo *d = NULL; - struct addrinfo hints; - if(hostname != NULL && port != NULL) { - memset(&hints,0,sizeof(struct addrinfo)); - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_DGRAM; - hints.ai_flags = 0; - if(getaddrinfo(hostname, port, &hints, &d) == 0) { - if(d != NULL) { - saddr = (struct sockaddr_in *)d->ai_addr; - memcpy(addr->addr, &saddr->sin_addr.s_addr, 4); - memcpy(addr->port, &saddr->sin_port, 2); - ret = 1; - } - else { - ret = 0; - } - freeaddrinfo(d); - } - else { - ret = 0; - } - return ret; - } - else { - return 0; - } -} - - -// Opens an IPv4 UDP socket. Returns 1 if successful. -static int ioOpenUDPv4Socket(struct s_io_state *iostate, const char *bindaddress, const char *bindport) { - int fd; - if(ioOpenSocket(&fd, bindaddress, bindport, AF_INET, SOCK_DGRAM, 0)) { - iostate->fd[IO_FDID_UDPV4SOCKET].fd = fd; - iostate->fd[IO_FDID_UDPV4SOCKET].events = POLLIN; - return 1; - } - else { - return 0; - } -} - - -// Sends an IPv4 UDP packet. Returns length of sent message. -static int ioSendUDPv4Packet(struct s_io_state *iostate, const unsigned char *buf, const int len, const struct s_io_v4addr *destination) { - struct sockaddr_in addr; - memset(&addr, 0, sizeof(struct sockaddr_in)); - addr.sin_family = AF_INET; - memcpy(&addr.sin_addr.s_addr, destination->addr, 4); - memcpy(&addr.sin_port, destination->port, 2); - return sendto(iostate->fd[IO_FDID_UDPV4SOCKET].fd, buf, len, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)); -} - - -// Receives an IPv4 UDP packet. Returns length of received message. -static int ioRecvUDPv4Packet(struct s_io_state *iostate, unsigned char *buf, const int len, struct s_io_v4addr *source) { - struct sockaddr_in addr; - socklen_t addrlen = sizeof(struct sockaddr_in); - int ret = recvfrom(iostate->fd[IO_FDID_UDPV4SOCKET].fd, buf, len, 0, (struct sockaddr *)&addr, &addrlen); - if(ret > 0) { - memcpy(source->addr, &addr.sin_addr.s_addr, 4); - memcpy(source->port, &addr.sin_port, 2); - } - return ret; -} - - -// Convert UDPv4 address to 24 bit address. -static void ioConvertAddressFromUDPv4(unsigned char *address, const struct s_io_v4addr *v4addr) { - memset(address, 0, 24); - address[0] = 1; - address[1] = 4; - address[2] = 1; - memcpy(&address[4], v4addr->addr, 4); - memcpy(&address[8], v4addr->port, 2); -} - - -// Get 24 bit address (UDP over IPv4 or IPv6) from hostname/port. Returns 1 if successful. -static int ioGetUDPAddress(struct s_io_state *iostate, unsigned char *address, const char *hostname, const char *port) { - struct s_io_v4addr v4addr; - struct s_io_v6addr v6addr; - - if((!(iostate->fd[IO_FDID_UDPV6SOCKET].fd < 0)) && (ioGetUDPv6Address(&v6addr, hostname, port))) { - ioConvertAddressFromUDPv6(address, &v6addr); - return 1; - } - if((!(iostate->fd[IO_FDID_UDPV4SOCKET].fd < 0)) && (ioGetUDPv4Address(&v4addr, hostname, port))) { - ioConvertAddressFromUDPv4(address, &v4addr); - return 1; - } - - return 0; -} - - -// Send a packet and detect protocol using the 24 bit destination address. Returns length of sent message. -static int ioSendPacket(struct s_io_state *iostate, const unsigned char *buf, const int len, const unsigned char *destination) { - struct s_io_v4addr v4addr; - struct s_io_v6addr v6addr; - - // char text[64]; utilByteArrayToHexstring(text, 64, destination, 24); printf("(debug) sending packet to %s\n", text); - - switch(destination[0]) { - case 1: - // default protocol set - switch(destination[1]) { - case 6: - // IPv6 - switch(destination[2]) { - case 1: - // UDP over IPv6 - memcpy(v6addr.addr, &destination[4], 16); - memcpy(v6addr.port, &destination[20], 2); - return ioSendUDPv6Packet(iostate, buf, len, &v6addr); - break; - } - break; - case 4: - // IPv4 - switch(destination[2]) { - case 1: - // UDP over IPv4 - memcpy(v4addr.addr, &destination[4], 4); - memcpy(v4addr.port, &destination[8], 2); - return ioSendUDPv4Packet(iostate, buf, len, &v4addr); - break; - } - break; - } - break; - } - - return -1; -} - - -// Receive a packet and generate the 24 bit source address depending on the protocol. Returns length of received message. -static int ioRecvPacket(struct s_io_state *iostate, unsigned char *buf, const int len, unsigned char *source) { - int ret; - struct s_io_v4addr v4addr; - struct s_io_v6addr v6addr; - - if((!(iostate->fd[IO_FDID_UDPV6SOCKET].fd < 0)) && ((ret = (ioRecvUDPv6Packet(iostate, buf, len, &v6addr))) > 0)) { - // received UDP over IPv6 - ioConvertAddressFromUDPv6(source, &v6addr); - // char text[64]; utilByteArrayToHexstring(text, 64, source, 24); printf("(debug) received packet from %s\n", text); - return ret; - } - if((!(iostate->fd[IO_FDID_UDPV4SOCKET].fd < 0)) && ((ret = (ioRecvUDPv4Packet(iostate, buf, len, &v4addr))) > 0)) { - // received UDP over IPv4 - ioConvertAddressFromUDPv4(source, &v4addr); - // char text[64]; utilByteArrayToHexstring(text, 64, source, 24); printf("(debug) received packet from %s\n", text); - return ret; - } - - return -1; -} - - -// Wait for data. -static void ioWait(struct s_io_state *iostate, const int max_wait) { - poll(iostate->fd,IO_FDID_COUNT,max_wait); -} - - -// Initialize IO state. -static void ioCreate(struct s_io_state *iostate) { - int i; - for(i=0; i<IO_FDID_COUNT; i++) { - iostate->fd[i].fd = -1; - iostate->fd[i].events = 0; - } -} - - -// Close all opened FDs. -static void ioReset(struct s_io_state *iostate) { - int i; - for(i=0; i<IO_FDID_COUNT; i++) { - if(!(iostate->fd[i].fd < 0)) { - close(iostate->fd[i].fd); - } - } - ioCreate(iostate); -} - - -#endif // F_IO_C diff --git a/libp2psec/peermgt.c b/libp2psec/peermgt.c index d828d37..edfce2a 100644 --- a/libp2psec/peermgt.c +++ b/libp2psec/peermgt.c @@ -474,7 +474,7 @@ static int peermgtDecodePacketAuth(struct s_peermgt *mgt, const struct s_packet_ struct s_nodeid peer_nodeid; int peerid; int dupid; - int64_t remoteflags; + int64_t remoteflags = 0; if(authmgtDecodeMsg(authmgt, data->pl_buf, data->pl_length, source_addr)) { if(authmgtGetAuthedPeerNodeID(authmgt, &peer_nodeid)) { diff --git a/mainloop.ic b/mainloop.ic index 604ea32..a96d31e 100644 --- a/mainloop.ic +++ b/mainloop.ic @@ -22,6 +22,7 @@ static void mainLoop() { int tnow; unsigned char buf[4096]; unsigned char msgbuf[4096]; + unsigned char cmdbuf[1024]; unsigned char *msg; int lastinit = 0; int laststatus = 0; @@ -80,7 +81,10 @@ static void mainLoop() { // check console if(g_enableconsole > 0) { - decodeConsole(); + len = ioReadSTDIN(&iostate, cmdbuf, 1024); + if(len > 0) { + decodeConsole((char *)cmdbuf, len); + } } } } @@ -19,17 +19,12 @@ #include <signal.h> #include <stdio.h> -#include <string.h> -#include <time.h> -#include <stdlib.h> -#include <unistd.h> -#include <pwd.h> -#include <grp.h> #include <openssl/engine.h> #include "libp2psec/p2psec.c" -#include "io.c" +#include "platform/io.c" +#include "platform/ifconfig.c" #include "globals.ic" #include "helpers.ic" #include "console.ic" @@ -47,6 +42,8 @@ int main(int argc, char **argv) { // default configuration strcpy(config.tapname,""); + strcpy(config.ifconfig4,""); + strcpy(config.ifconfig6,""); strcpy(config.upcmd,""); strcpy(config.sourceip,""); strcpy(config.sourceport,""); diff --git a/peervpn.conf b/peervpn.conf index 16e827b..70dbf6c 100644 --- a/peervpn.conf +++ b/peervpn.conf @@ -25,7 +25,7 @@ ## Option: enableipv4 <yes|no> -## Description: Enables IPv4 support. +## Description: Enables IPv4 sockets. ## Defaults to "yes". ## Example: enableipv4 yes @@ -34,7 +34,7 @@ ## Option: enableipv6 <yes|no> -## Description: Enables IPv6 support. +## Description: Enables IPv6 sockets. ## Defaults to "yes". ## Example: enableipv6 yes @@ -81,14 +81,32 @@ +## Option: ifconfig4 <address>/<prefixlen> +## Description: Defines the IPv4 address and its prefix length that +## should be assigned to the TAP device. +## Example: ifconfig4 10.1.2.3/24 + +#ifconfig4 10.1.2.3/24 + + + +## Option: ifconfig6 <address>/<prefixlen> +## Description: Defines the IPv6 address and its prefix length that +## should be assigned to the TAP device. +## Example: ifconfig6 2001:DB8:1:2::3/64 + +#ifconfig6 2001:DB8:1:2::3/64 + + + ## Option: upcmd <command> ## Description: Defines a shell command that will be executed after ## the TAP device has been opened. This can be used to ## invoke a program/script or to control interface ## parameters (IP address, MTU, etc.). -## Example: upcmd ifconfig peervpn0 up 10.1.2.3 netmask 255.255.255.0 +## Example: upcmd echo virtual interface is up -#upcmd ifconfig peervpn0 up && echo virtual interface is up +#upcmd echo virtual interface is up diff --git a/platform/ifconfig.c b/platform/ifconfig.c new file mode 100644 index 0000000..b639aee --- /dev/null +++ b/platform/ifconfig.c @@ -0,0 +1,175 @@ +/*************************************************************************** + * Copyright (C) 2012 by Tobias Volk * + * mail@tobiasvolk.de * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + + +#ifndef F_IFCONFIG_C +#define F_IFCONFIG_C + + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + + +#ifdef WIN32 +#define IFCONFIG_WINDOWS +#endif + + +// Execute command. +static int ifconfigExec(const char *cmd) { + int ret = system(cmd); +#ifdef IFCONFIG_DEBUG + printf("executed=\"%s\", result=\"%d\"\n", cmd, ret); +#endif + return ret; +} + + +// Check & copy input. +static int ifconfigCheckCopyInput(char *out, const int out_len, const char *in, const int in_len) { + int i; + char c; + if(!(in_len < out_len)) return 0; + i = 0; + while(i < in_len) { + c = in[i]; + if(!(c >= 32 && c < 127)) return 0; + switch(c) { + case ';': + case '\'': + case '\"': + case '?': + case '!': + case '`': + return 0; + } + i++; + } + memcpy(out, in, in_len); + out[in_len] = '\0'; + return 1; +} + + +// Split input. +static int ifconfigSplit(char *a_out, const int a_len, char *b_out, const int b_len, const char *in, const int in_len, const char split_char) { + int i; + int s; + if((a_len + 1 + b_len) < in_len) return 0; + i = 0; + s = 0; + while(i < in_len) { + if(in[i] == split_char) { + s = i; + break; + } + i++; + } + if(!(s > 0)) return 0; + if(!ifconfigCheckCopyInput(a_out, a_len, &in[0], s)) return 0; + if(!ifconfigCheckCopyInput(b_out, b_len, &in[(s + 1)], (in_len - (s + 1)))) return 0; + return 1; +} + + +// Calculate netmask from prefixlen. +static void ifconfig4Netmask(char *out, const int prefixlen) { + int mask[4]; + int i, j, p; + for(j=0; j<4; j++) { + mask[j] = 0; + } + p = prefixlen; + j = 0; + while(p > 0 && j < 4) { + i = 0; + while(p > 0 && i < 8) { + mask[j] = (mask[j] | (1 << (8 - i - 1))); + p--; + i++; + } + j++; + } + snprintf(out, 16, "%d.%d.%d.%d", mask[0], mask[1], mask[2], mask[3]); +} + + +// Configure IPv4 address on specified interface. +static int ifconfig4(const char *ifname, const int ifname_len, const char *addr, const int addr_len) { + char cmd[1024]; memset(cmd, 0, 1024); + char ifname_s[256]; memset(ifname_s, 0, 256); + char ip_s[256]; memset(ip_s, 0, 256); + char netmask_s[16]; memset(netmask_s, 0, 16); + char prefixlen_s[4]; memset(prefixlen_s, 0, 4); + int ret; + + if(!ifconfigCheckCopyInput(ifname_s, 256, ifname, ifname_len)) return 0; + if(!ifconfigSplit(ip_s, 256, prefixlen_s, 4, addr, addr_len, '/')) return 0; + if(strlen(prefixlen_s) == 0) memcpy(prefixlen_s, "32", 2); + ret = 0; sscanf(prefixlen_s, "%d", &ret); ifconfig4Netmask(netmask_s, ret); + +#ifdef IFCONFIG_WINDOWS + sprintf(cmd, "netsh interface ip set address name=\"%s\" static \"%s\" \"%s\"", ifname_s, ip_s, netmask_s); ret = ifconfigExec(cmd); + return(ret == 0); +#else + sprintf(cmd, "ip link set dev \"%s\" up", ifname_s); ret = ifconfigExec(cmd); + if(ret == 0) { + sprintf(cmd, "ip -4 addr add dev \"%s\" \"%s/%s\" broadcast +", ifname_s, ip_s, prefixlen_s); ret = ifconfigExec(cmd); + return(ret == 0); + } + + sprintf(cmd, "ifconfig \"%s\" up", ifname_s); ret = ifconfigExec(cmd); + if(ret == 0) { + sprintf(cmd, "ifconfig \"%s\" \"%s\" netmask \"%s\"", ifname_s, ip_s, netmask_s); ret = ifconfigExec(cmd); + return(ret == 0); + } +#endif + + return 0; +} + + +// Configure IPv6 address on specified interface. +static int ifconfig6(const char *ifname, const int ifname_len, const char *addr, const int addr_len) { + char cmd[1024]; memset(cmd, 0, 1024); + char ifname_s[256]; memset(ifname_s, 0, 256); + char ip_s[256]; memset(ip_s, 0, 256); + char netmask_s[16]; memset(netmask_s, 0, 16); + char prefixlen_s[4]; memset(prefixlen_s, 0, 4); + int ret; + + if(!ifconfigCheckCopyInput(ifname_s, 256, ifname, ifname_len)) return 0; + if(!ifconfigSplit(ip_s, 256, prefixlen_s, 4, addr, addr_len, '/')) return 0; + if(strlen(prefixlen_s) == 0) memcpy(prefixlen_s, "128", 2); + ret = 0; sscanf(prefixlen_s, "%d", &ret); ifconfig4Netmask(netmask_s, ret); + +#ifdef IFCONFIG_WINDOWS +#else + sprintf(cmd, "ip link set dev \"%s\" up", ifname_s); ret = ifconfigExec(cmd); + if(ret == 0) { + sprintf(cmd, "ip -6 addr add dev \"%s\" \"%s/%s\"", ifname_s, ip_s, prefixlen_s); ret = ifconfigExec(cmd); + return(ret == 0); + } +#endif + + return 0; +} + + +#endif // F_IFCONFIG_C diff --git a/platform/io.c b/platform/io.c new file mode 100644 index 0000000..acdb450 --- /dev/null +++ b/platform/io.c @@ -0,0 +1,855 @@ +/*************************************************************************** + * Copyright (C) 2012 by Tobias Volk * + * mail@tobiasvolk.de * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + + +#ifndef F_IO_C +#define F_IO_C + + +#ifdef WIN32 +#define IO_WINDOWS +#endif + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#ifdef IO_WINDOWS +#include <winsock2.h> +#include <ws2tcpip.h> +#include <winioctl.h> +#include "tapwin.h" +#else +#include <poll.h> +#include <netdb.h> +#include <linux/if_tun.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <net/if.h> +#endif + + +// IDs. +#define IO_FDID_STDIN 0 +#define IO_FDID_UDPV4SOCKET 1 +#define IO_FDID_UDPV6SOCKET 2 +#define IO_FDID_TAP 3 +#define IO_FDID_COUNT 4 + + +// The IO state structure. +#ifdef IO_WINDOWS +struct s_io_state_fd { + int fd; +}; +#endif +struct s_io_state { +#ifdef IO_WINDOWS + OVERLAPPED overlapped_read[IO_FDID_COUNT]; + OVERLAPPED overlapped_write[IO_FDID_COUNT]; + HANDLE event_read[IO_FDID_COUNT]; + unsigned char readbuf[(4096 * IO_FDID_COUNT)]; + struct sockaddr readaddr[IO_FDID_COUNT]; + socklen_t readaddr_len[IO_FDID_COUNT]; + DWORD readbuf_len[IO_FDID_COUNT]; + int readbuf_used[IO_FDID_COUNT]; + struct s_io_state_fd fd[IO_FDID_COUNT]; + HANDLE handle[IO_FDID_COUNT]; +#else + struct pollfd fd[IO_FDID_COUNT]; +#endif +}; + + +// The IPv4 addr/port structure. +struct s_io_v4addr { + unsigned char addr[4]; + unsigned char port[2]; +}; + + +// The IPv6 addr/port structure. +struct s_io_v6addr { + unsigned char addr[16]; + unsigned char port[2]; +}; + + +// Opens STDIN. Returns 1 if successful. +static int ioOpenSTDIN(struct s_io_state *iostate) { +#ifdef IO_WINDOWS + return 0; // not implemented +#else + if(!((fcntl(STDIN_FILENO,F_SETFL,O_NONBLOCK)) < 0)) { + iostate->fd[IO_FDID_STDIN].fd = STDIN_FILENO; + iostate->fd[IO_FDID_STDIN].events = POLLIN; + return 1; + } + else { + return 0; + } +#endif +} + + +// Reads from STDIN. Returns number of bytes read. +static int ioReadSTDIN(struct s_io_state *iostate, unsigned char *buf, const int len) { +#ifdef IO_WINDOWS + return 0; // not implemented +#else + return read(iostate->fd[IO_FDID_STDIN].fd, buf, len); +#endif +} + + +// Helper functions for TAP devices on Windows. +#ifdef IO_WINDOWS +#define IO_TAPSEARCH_IF_GUID_FROM_NAME 0 +#define IO_TAPSEARCH_IF_NAME_FROM_GUID 1 +static char *ioOpenTapSearch(char *value, char *key, int type) +{ + int i = 0; + LONG status; + DWORD len; + HKEY net_conn_key; + BOOL found = FALSE; + char guid[256]; + char ifname[256]; + char conn_string[512]; + HKEY conn_key; + DWORD value_type; + if (!value || !key) { + return NULL; + } + status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &net_conn_key); + if (status != ERROR_SUCCESS) { + return NULL; + } + while (!found) { + len = sizeof(guid); + status = RegEnumKeyEx(net_conn_key, i++, guid, &len, + NULL, NULL, NULL, NULL); + if (status == ERROR_NO_MORE_ITEMS) { + break; + } else if (status != ERROR_SUCCESS) { + continue; + } + snprintf(conn_string, sizeof(conn_string), "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, guid); + status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, conn_string, 0, KEY_READ, &conn_key); + if (status != ERROR_SUCCESS) { + continue; + } + len = sizeof(ifname); + status = RegQueryValueEx(conn_key, "Name", NULL, &value_type, (BYTE *)ifname, &len); + if (status != ERROR_SUCCESS || value_type != REG_SZ) { + RegCloseKey(conn_key); + continue; + } + switch (type) { + case IO_TAPSEARCH_IF_GUID_FROM_NAME: + if (!strcmp(key, ifname)) { + strcpy(value, guid); + found = TRUE; + } + break; + case IO_TAPSEARCH_IF_NAME_FROM_GUID: + if (!strcmp(key, guid)) { + strcpy(value, ifname); + found = TRUE; + } + break; + default: + break; + } + RegCloseKey(conn_key); + } + RegCloseKey(net_conn_key); + if (found) { + return value; + } + return NULL; +} +static HANDLE ioOpenTapDev(char *guid, char *dev) { + HANDLE handle; + ULONG len, status; + char device_path[512]; + snprintf(device_path, sizeof(device_path), "%s%s%s", USERMODEDEVICEDIR, guid, TAPSUFFIX); + handle = CreateFile(device_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0); + if (handle == INVALID_HANDLE_VALUE) { + return INVALID_HANDLE_VALUE; + } + status = TRUE; + if (!DeviceIoControl(handle, TAP_IOCTL_SET_MEDIA_STATUS, + &status, sizeof(status), + &status, sizeof(status), &len, NULL)) { + } + return handle; +} +#endif + + +// Opens TAP device. Returns 1 and a tapname (max. 256 bytes) if successful. +static int ioOpenTap(struct s_io_state *iostate, char *tapname, const char *reqname) { +#ifdef IO_WINDOWS + HANDLE handle = INVALID_HANDLE_VALUE; + HKEY unit_key; + char guid[256]; + char comp_id[256]; + char enum_name[256]; + char unit_string[512]; + char tmpname[256]; + int tmpname_len; + BOOL found = FALSE; + HKEY adapter_key; + DWORD value_type; + LONG status; + DWORD len; + + tmpname_len = strlen(reqname); + if(tmpname_len >= 256) { + tmpname_len = 255; + } + if(tmpname_len > 0) { + memcpy(tmpname, reqname, tmpname_len); + } + else { + tmpname_len = 0; + } + tmpname[tmpname_len] = '\0'; + + if(tmpname != NULL) { + if (tmpname[0] != '\0') { + if (!ioOpenTapSearch(guid, tmpname, IO_TAPSEARCH_IF_GUID_FROM_NAME)) { + return 0; + } + handle = ioOpenTapDev(guid, tmpname); + if(handle != INVALID_HANDLE_VALUE) { + if(tapname != NULL) { + tapname[0] = '\0'; + tmpname_len = strlen(tmpname); + if(tmpname_len > 0 && tmpname_len < 256) { + memcpy(tapname, tmpname, tmpname_len); + tapname[tmpname_len] = '\0'; + } + } + iostate->handle[IO_FDID_TAP] = handle; + return 1; + } + else { + return 0; + } + } + } + + int i = 0; + status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, ADAPTER_KEY, 0, KEY_READ, &adapter_key); + if (status != ERROR_SUCCESS) { + return 0; + } + while (!found) { + len = sizeof(enum_name); + status = RegEnumKeyEx(adapter_key, i++, + enum_name, &len, + NULL, NULL, NULL, NULL); + if (status == ERROR_NO_MORE_ITEMS) { + break; + } else if (status != ERROR_SUCCESS) { + continue; + } + 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) { + continue; + } + len = sizeof(comp_id); + status = RegQueryValueEx(unit_key, "ComponentId", NULL, &value_type, (BYTE *)comp_id, &len); + if (status != ERROR_SUCCESS || value_type != REG_SZ) { + RegCloseKey(unit_key); + continue; + } + len = sizeof(guid); + status = RegQueryValueEx(unit_key, "NetCfgInstanceId", NULL, &value_type, (BYTE *)guid, &len); + if (status != ERROR_SUCCESS || value_type != REG_SZ) { + RegCloseKey(unit_key); + continue; + } + ioOpenTapSearch(tmpname, guid, IO_TAPSEARCH_IF_NAME_FROM_GUID); + handle = ioOpenTapDev(guid, tmpname); + if (handle != INVALID_HANDLE_VALUE) { + found = TRUE; + } + RegCloseKey(unit_key); + } + RegCloseKey(adapter_key); + if(handle != INVALID_HANDLE_VALUE) { + if(tapname != NULL) { + tapname[0] = '\0'; + tmpname_len = strlen(tmpname); + if(tmpname_len > 0 && tmpname_len < 256) { + memcpy(tapname, tmpname, tmpname_len); + tapname[tmpname_len] = '\0'; + } + } + iostate->handle[IO_FDID_TAP] = handle; + return 1; + } + else { + return 0; + } +#else + struct ifreq ifr; + char *file = "/dev/net/tun"; + int tapfd = open(file,(O_RDWR | O_NONBLOCK)); + int name_len; + + if(tapfd < 0) { + return 0; + } + + memset(&ifr,0,sizeof(struct ifreq)); + ifr.ifr_flags = (IFF_TAP | IFF_NO_PI); + strncpy(ifr.ifr_name, reqname, sizeof(ifr.ifr_name) - 1); + if(ioctl(tapfd,TUNSETIFF,(void *)&ifr) < 0) { + return 0; + } + + iostate->fd[IO_FDID_TAP].fd = tapfd; + iostate->fd[IO_FDID_TAP].events = POLLIN; + + if(tapname != NULL) { + name_len = strlen(ifr.ifr_name); + tapname[0] = '\0'; + if(name_len > 0 && name_len < 256) { + memcpy(tapname, ifr.ifr_name, name_len); + tapname[name_len] = '\0'; + } + } + + return 1; +#endif +} + + +// Writes to TAP device. Returns number of bytes written. +static int ioWriteTap(struct s_io_state *iostate, const unsigned char *buf, const int len) { +#ifdef IO_WINDOWS + DWORD ret; + ret = 0; + WriteFile(iostate->handle[IO_FDID_TAP], buf, len, NULL, &iostate->overlapped_write[IO_FDID_TAP]); + GetOverlappedResult(iostate->handle[IO_FDID_TAP], &iostate->overlapped_write[IO_FDID_TAP], &ret, TRUE); + if(ret > 0) { + return ret; + } + else { + return 0; + } +#else + return write(iostate->fd[IO_FDID_TAP].fd, buf, len); +#endif +} + + +// Reads from TAP device. Returns number of bytes read. +static int ioReadTap(struct s_io_state *iostate, unsigned char *buf, const int len) { +#ifdef IO_WINDOWS + int buflen = iostate->readbuf_len[IO_FDID_TAP]; + if(buflen > 0) { + iostate->readbuf_len[IO_FDID_TAP] = 0; + if(buflen > 0 && buflen < len) { + memcpy(buf, &iostate->readbuf[(4096 * IO_FDID_TAP)], buflen); + return buflen; + } + else { + return 0; + } + } + else { + return 0; + } +#else + return read(iostate->fd[IO_FDID_TAP].fd, buf, len); +#endif +} + + +// Opens a socket. Returns 1 if successful. +static int ioOpenSocket(int *handle, const char *bindaddress, const char *bindport, const int domain, const int type, const int protocol) { + int ret; + int fd; + const char *zeroport = "0"; + const char *useport; + const char *useaddr; + struct addrinfo *d = NULL; + struct addrinfo *di; + struct addrinfo hints; + memset(&hints,0,sizeof(struct addrinfo)); +#ifdef IO_WINDOWS + if((fd = WSASocket(domain, type, 0, 0, 0, WSA_FLAG_OVERLAPPED)) < 0) return 0; +#else + if((fd = socket(domain, type, 0)) < 0) return 0; + int one = 1; + if((fcntl(fd,F_SETFL,O_NONBLOCK)) < 0) return 0; + if(domain == AF_INET6) setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(int)); +#endif + hints.ai_family = domain; + hints.ai_socktype = type; + hints.ai_protocol = protocol; + hints.ai_flags = AI_PASSIVE; + if(bindaddress == NULL) { + useaddr = NULL; + } + else { + if(strlen(bindaddress) > 0) { + useaddr = bindaddress; + } + else { + useaddr = NULL; + } + } + if(bindport == NULL) { + useport = zeroport; + } + else { + useport = bindport; + } + if(getaddrinfo(useaddr, useport, &hints, &d) == 0) { + ret = -1; + di = d; + while(di != NULL) { + if(bind(fd, di->ai_addr, di->ai_addrlen) == 0) { + ret = fd; + break; + } + di = di->ai_next; + } + freeaddrinfo(d); + if(ret < 0) { + close(fd); + return 0; + } + *handle = ret; + return 1; + } + else { + return 0; + } +} + + +// Get IPv6 UDP address from name. Returns 1 if successful. +static int ioGetUDPv6Address(struct s_io_v6addr *addr, const char *hostname, const char *port) { +#ifdef IO_WINDOWS + return 0; // not implemented +#else + int ret; + struct sockaddr_in6 *saddr; + struct addrinfo *d = NULL; + struct addrinfo hints; + if(hostname != NULL && port != NULL) { + memset(&hints,0,sizeof(struct addrinfo)); + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = 0; + if(getaddrinfo(hostname, port, &hints, &d) == 0) { + if(d != NULL) { + saddr = (struct sockaddr_in6 *)d->ai_addr; + memcpy(addr->addr, saddr->sin6_addr.s6_addr, 16); + memcpy(addr->port, &saddr->sin6_port, 2); + ret = 1; + } + else { + ret = 0; + } + freeaddrinfo(d); + } + else { + ret = 0; + } + return ret; + } + else { + return 0; + } +#endif +} + + +// Opens an IPv6 UDP socket. Returns 1 if successful. +static int ioOpenUDPv6Socket(struct s_io_state *iostate, const char *bindaddress, const char *bindport) { +#ifdef IO_WINDOWS + return 0; // not implemented +#else + int fd; + if(ioOpenSocket(&fd, bindaddress, bindport, AF_INET6, SOCK_DGRAM, 0)) { + iostate->fd[IO_FDID_UDPV6SOCKET].fd = fd; + iostate->fd[IO_FDID_UDPV6SOCKET].events = POLLIN; + return 1; + } + else { + return 0; + } +#endif +} + + +// Sends an IPv6 UDP packet. Returns length of sent message. +static int ioSendUDPv6Packet(struct s_io_state *iostate, const unsigned char *buf, const int len, struct s_io_v6addr *destination) { +#ifdef IO_WINDOWS + return 0; // not implemented +#else + int ret; + struct sockaddr_in6 addr; + memset(&addr, 0, sizeof(struct sockaddr_in6)); + addr.sin6_family = AF_INET6; + memcpy(addr.sin6_addr.s6_addr, destination->addr, 16); + memcpy(&addr.sin6_port, destination->port, 2); + ret = sendto(iostate->fd[IO_FDID_UDPV6SOCKET].fd, buf, len, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in6)); + return ret; +#endif +} + + +// Receives an IPv6 UDP packet. Returns length of received message. +static int ioRecvUDPv6Packet(struct s_io_state *iostate, unsigned char *buf, const int len, struct s_io_v6addr *source) { +#ifdef IO_WINDOWS + return 0; // not implemented +#else + struct sockaddr_in6 addr; + socklen_t addrlen = sizeof(struct sockaddr_in6); + int ret = recvfrom(iostate->fd[IO_FDID_UDPV6SOCKET].fd, buf, len, 0, (struct sockaddr *)&addr, &addrlen); + if(ret > 0) { + memcpy(source->addr, addr.sin6_addr.s6_addr, 16); + memcpy(source->port, &addr.sin6_port, 2); + } + return ret; +#endif +} + + +// Convert UDPv6 address to 24 bit address. +static void ioConvertAddressFromUDPv6(unsigned char *address, const struct s_io_v6addr *v6addr) { + memset(address, 0, 24); + address[0] = 1; + address[1] = 6; + address[2] = 1; + memcpy(&address[4], &v6addr->addr, 16); + memcpy(&address[20], v6addr->port, 2); +} + + +// Get IPv4 UDP address from name. Returns 1 if successful. +static int ioGetUDPv4Address(struct s_io_v4addr *addr, const char *hostname, const char *port) { + int ret; + struct sockaddr_in *saddr; + struct addrinfo *d = NULL; + struct addrinfo hints; + if(hostname != NULL && port != NULL) { + memset(&hints,0,sizeof(struct addrinfo)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = 0; + if(getaddrinfo(hostname, port, &hints, &d) == 0) { + if(d != NULL) { + saddr = (struct sockaddr_in *)d->ai_addr; + memcpy(addr->addr, &saddr->sin_addr.s_addr, 4); + memcpy(addr->port, &saddr->sin_port, 2); + ret = 1; + } + else { + ret = 0; + } + freeaddrinfo(d); + } + else { + ret = 0; + } + return ret; + } + else { + return 0; + } +} + + +// Opens an IPv4 UDP socket. Returns 1 if successful. +static int ioOpenUDPv4Socket(struct s_io_state *iostate, const char *bindaddress, const char *bindport) { + int fd; + if(ioOpenSocket(&fd, bindaddress, bindport, AF_INET, SOCK_DGRAM, 0)) { + iostate->fd[IO_FDID_UDPV4SOCKET].fd = fd; +#ifdef IO_WINDOWS +#else + iostate->fd[IO_FDID_UDPV4SOCKET].events = POLLIN; +#endif + return 1; + } + else { + return 0; + } +} + + +// Sends an IPv4 UDP packet. Returns length of sent message. +static int ioSendUDPv4Packet(struct s_io_state *iostate, const unsigned char *buf, const int len, const struct s_io_v4addr *destination) { + struct sockaddr_in addr; + memset(&addr, 0, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; + memcpy(&addr.sin_addr.s_addr, destination->addr, 4); + memcpy(&addr.sin_port, destination->port, 2); +#ifdef IO_WINDOWS + DWORD ret = 0; + DWORD flags = 0; + WSABUF wsabuf; + wsabuf.buf = (char *)buf; + wsabuf.len = len; + WSASendTo(iostate->fd[IO_FDID_UDPV4SOCKET].fd, &wsabuf, 1, NULL, flags, (struct sockaddr *)&addr, sizeof(struct sockaddr_in), &iostate->overlapped_write[IO_FDID_UDPV4SOCKET], NULL); + WSAGetOverlappedResult(iostate->fd[IO_FDID_UDPV4SOCKET].fd, &iostate->overlapped_write[IO_FDID_UDPV4SOCKET], &ret, TRUE, &flags); +#else + int ret; + ret = sendto(iostate->fd[IO_FDID_UDPV4SOCKET].fd, buf, len, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)); +#endif + if(ret > 0) { + return ret; + } + else { + return 0; + } +} + + +// Receives an IPv4 UDP packet. Returns length of received message. +static int ioRecvUDPv4Packet(struct s_io_state *iostate, unsigned char *buf, const int len, struct s_io_v4addr *source) { +#ifdef IO_WINDOWS + struct sockaddr_in *readaddr = (struct sockaddr_in *)&iostate->readaddr[IO_FDID_UDPV4SOCKET]; + int buflen = iostate->readbuf_len[IO_FDID_UDPV4SOCKET]; + if(buflen > 0) { + iostate->readbuf_len[IO_FDID_UDPV4SOCKET] = 0; + if(buflen < len) { + memcpy(buf, &iostate->readbuf[(4096 * IO_FDID_UDPV4SOCKET)], buflen); + memcpy(source->addr, &readaddr->sin_addr.s_addr, 4); + memcpy(source->port, &readaddr->sin_port, 2); + return buflen; + } + else { + return 0; + } + } + else { + return 0; + } +#else + struct sockaddr_in addr; + socklen_t addrlen = sizeof(struct sockaddr_in); + int ret = recvfrom(iostate->fd[IO_FDID_UDPV4SOCKET].fd, buf, len, 0, (struct sockaddr *)&addr, &addrlen); + if(ret > 0) { + memcpy(source->addr, &addr.sin_addr.s_addr, 4); + memcpy(source->port, &addr.sin_port, 2); + } + return ret; +#endif +} + + +// Convert UDPv4 address to 24 bit address. +static void ioConvertAddressFromUDPv4(unsigned char *address, const struct s_io_v4addr *v4addr) { + memset(address, 0, 24); + address[0] = 1; + address[1] = 4; + address[2] = 1; + memcpy(&address[4], v4addr->addr, 4); + memcpy(&address[8], v4addr->port, 2); +} + + +// Get 24 bit address (UDP over IPv4 or IPv6) from hostname/port. Returns 1 if successful. +static int ioGetUDPAddress(struct s_io_state *iostate, unsigned char *address, const char *hostname, const char *port) { + struct s_io_v4addr v4addr; + struct s_io_v6addr v6addr; + + if((!(iostate->fd[IO_FDID_UDPV6SOCKET].fd < 0)) && (ioGetUDPv6Address(&v6addr, hostname, port))) { + ioConvertAddressFromUDPv6(address, &v6addr); + return 1; + } + if((!(iostate->fd[IO_FDID_UDPV4SOCKET].fd < 0)) && (ioGetUDPv4Address(&v4addr, hostname, port))) { + ioConvertAddressFromUDPv4(address, &v4addr); + return 1; + } + + return 0; +} + + +// Send a packet and detect protocol using the 24 bit destination address. Returns length of sent message. +static int ioSendPacket(struct s_io_state *iostate, const unsigned char *buf, const int len, const unsigned char *destination) { + struct s_io_v4addr v4addr; + struct s_io_v6addr v6addr; + + switch(destination[0]) { + case 1: + // default protocol set + switch(destination[1]) { + case 6: + // IPv6 + switch(destination[2]) { + case 1: + // UDP over IPv6 + memcpy(v6addr.addr, &destination[4], 16); + memcpy(v6addr.port, &destination[20], 2); + return ioSendUDPv6Packet(iostate, buf, len, &v6addr); + break; + } + break; + case 4: + // IPv4 + switch(destination[2]) { + case 1: + // UDP over IPv4 + memcpy(v4addr.addr, &destination[4], 4); + memcpy(v4addr.port, &destination[8], 2); + return ioSendUDPv4Packet(iostate, buf, len, &v4addr); + break; + } + break; + } + break; + } + + return -1; +} + + +// Receive a packet and generate the 24 bit source address depending on the protocol. Returns length of received message. +static int ioRecvPacket(struct s_io_state *iostate, unsigned char *buf, const int len, unsigned char *source) { + int ret; + struct s_io_v4addr v4addr; + struct s_io_v6addr v6addr; + + if((!(iostate->fd[IO_FDID_UDPV6SOCKET].fd < 0)) && ((ret = (ioRecvUDPv6Packet(iostate, buf, len, &v6addr))) > 0)) { + // received UDP over IPv6 + ioConvertAddressFromUDPv6(source, &v6addr); + return ret; + } + if((!(iostate->fd[IO_FDID_UDPV4SOCKET].fd < 0)) && ((ret = (ioRecvUDPv4Packet(iostate, buf, len, &v4addr))) > 0)) { + // received UDP over IPv4 + ioConvertAddressFromUDPv4(source, &v4addr); + return ret; + } + + return -1; +} + + +// Wait for data. +static void ioWait(struct s_io_state *iostate, const int max_wait) { +#ifdef IO_WINDOWS + // start reading UDPv4 socket + DWORD udpv4recvlen; + DWORD udpv4flags; + udpv4flags = 0; + WSABUF udpv4wsabuf; + udpv4wsabuf.buf = (char *)&iostate->readbuf[(4096 * IO_FDID_UDPV4SOCKET)]; + udpv4wsabuf.len = 4096; + iostate->readaddr_len[IO_FDID_UDPV4SOCKET] = sizeof(struct sockaddr_in); + if((!(iostate->readbuf_used[IO_FDID_UDPV4SOCKET])) && (!(iostate->readbuf_len[IO_FDID_UDPV4SOCKET] > 0)) && (!(iostate->fd[IO_FDID_UDPV4SOCKET].fd < 0))) { + iostate->readbuf_used[IO_FDID_UDPV4SOCKET] = 1; + WSARecvFrom(iostate->fd[IO_FDID_UDPV4SOCKET].fd, &udpv4wsabuf, 1, NULL, &udpv4flags, &iostate->readaddr[IO_FDID_UDPV4SOCKET], &iostate->readaddr_len[IO_FDID_UDPV4SOCKET], &iostate->overlapped_read[IO_FDID_UDPV4SOCKET], 0); + } + + // start reading TAP device + DWORD tapreadlen; + if((!(iostate->readbuf_used[IO_FDID_TAP])) && (!(iostate->readbuf_len[IO_FDID_TAP] > 0)) && (iostate->handle[IO_FDID_TAP] != INVALID_HANDLE_VALUE)) { + iostate->readbuf_used[IO_FDID_TAP] = 1; + ReadFile(iostate->handle[IO_FDID_TAP], &iostate->readbuf[(4096 * IO_FDID_TAP)], 4096, NULL, &iostate->overlapped_read[IO_FDID_TAP]); + } + + // check for events + WaitForMultipleObjects(IO_FDID_COUNT, iostate->event_read, FALSE, max_wait); + if((iostate->readbuf_used[IO_FDID_UDPV4SOCKET]) && (!(iostate->readbuf_len[IO_FDID_UDPV4SOCKET] > 0)) && (!(iostate->fd[IO_FDID_UDPV4SOCKET].fd < 0))) { + udpv4flags = 0; udpv4recvlen = 0; + if(WSAGetOverlappedResult(iostate->fd[IO_FDID_UDPV4SOCKET].fd, &iostate->overlapped_read[IO_FDID_UDPV4SOCKET], &udpv4recvlen, FALSE, &udpv4flags) == TRUE) { + iostate->readbuf_used[IO_FDID_UDPV4SOCKET] = 0; + if(udpv4recvlen > 0) { + iostate->readbuf_len[IO_FDID_UDPV4SOCKET] = udpv4recvlen; + } + } + else { + if(WSAGetLastError() != WSA_IO_INCOMPLETE) { + iostate->readbuf_used[IO_FDID_UDPV4SOCKET] = 0; + } + } + } + if((iostate->readbuf_used[IO_FDID_TAP]) && (!(iostate->readbuf_len[IO_FDID_TAP] > 0)) && (iostate->handle[IO_FDID_TAP] != INVALID_HANDLE_VALUE)) { + tapreadlen = 0; + if(GetOverlappedResult(iostate->handle[IO_FDID_TAP], &iostate->overlapped_read[IO_FDID_TAP], &tapreadlen, FALSE) != 0) { + iostate->readbuf_used[IO_FDID_TAP] = 0; + if(tapreadlen > 0) { + iostate->readbuf_len[IO_FDID_TAP] = tapreadlen; + } + } + else { + if(GetLastError() != ERROR_IO_INCOMPLETE) { + iostate->readbuf_used[IO_FDID_TAP] = 0; + } + } + } +#else + poll(iostate->fd,IO_FDID_COUNT,max_wait); +#endif +} + + +// Initialize IO state. +static void ioCreate(struct s_io_state *iostate) { +#ifdef IO_WINDOWS + WSADATA wsadata; + WSAStartup(MAKEWORD(2,2), &wsadata); +#endif + int i; + for(i=0; i<IO_FDID_COUNT; i++) { +#ifdef IO_WINDOWS + iostate->readbuf_len[i] = 0; + iostate->readbuf_used[i] = 0; + iostate->handle[i] = INVALID_HANDLE_VALUE; + memset(&iostate->overlapped_read[i], 0, sizeof(OVERLAPPED)); + memset(&iostate->overlapped_write[i], 0, sizeof(OVERLAPPED)); + iostate->overlapped_read[i].hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + iostate->overlapped_write[i].hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + iostate->event_read[i] = iostate->overlapped_read[i].hEvent; +#else + iostate->fd[i].events = 0; +#endif + iostate->fd[i].fd = -1; + } +} + + +// Close all opened FDs. +static void ioReset(struct s_io_state *iostate) { + int i; + for(i=0; i<IO_FDID_COUNT; i++) { + if(!(iostate->fd[i].fd < 0)) { + close(iostate->fd[i].fd); + } + } + ioCreate(iostate); +} + + +#endif // F_IO_C diff --git a/platform/tapwin.h b/platform/tapwin.h new file mode 100644 index 0000000..5dbd4b0 --- /dev/null +++ b/platform/tapwin.h @@ -0,0 +1,73 @@ +/* + * TAP-Win32/TAP-Win64 -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2010 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +//============= +// TAP IOCTLs +//============= + +#define TAP_CONTROL_CODE(request,method) \ + CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS) + +// Present in 8.1 + +#define TAP_IOCTL_GET_MAC TAP_CONTROL_CODE (1, METHOD_BUFFERED) +#define TAP_IOCTL_GET_VERSION TAP_CONTROL_CODE (2, METHOD_BUFFERED) +#define TAP_IOCTL_GET_MTU TAP_CONTROL_CODE (3, METHOD_BUFFERED) +#define TAP_IOCTL_GET_INFO TAP_CONTROL_CODE (4, METHOD_BUFFERED) +#define TAP_IOCTL_CONFIG_POINT_TO_POINT TAP_CONTROL_CODE (5, METHOD_BUFFERED) +#define TAP_IOCTL_SET_MEDIA_STATUS TAP_CONTROL_CODE (6, METHOD_BUFFERED) +#define TAP_IOCTL_CONFIG_DHCP_MASQ TAP_CONTROL_CODE (7, METHOD_BUFFERED) +#define TAP_IOCTL_GET_LOG_LINE TAP_CONTROL_CODE (8, METHOD_BUFFERED) +#define TAP_IOCTL_CONFIG_DHCP_SET_OPT TAP_CONTROL_CODE (9, METHOD_BUFFERED) + +// Added in 8.2 + +/* obsoletes TAP_IOCTL_CONFIG_POINT_TO_POINT */ +#define TAP_IOCTL_CONFIG_TUN TAP_CONTROL_CODE (10, METHOD_BUFFERED) + +//================= +// Registry keys +//================= + +#define ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}" + +#define NETWORK_CONNECTIONS_KEY "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}" + +//====================== +// Filesystem prefixes +//====================== + +#define USERMODEDEVICEDIR "\\\\.\\Global\\" +#define SYSDEVICEDIR "\\Device\\" +#define USERDEVICEDIR "\\DosDevices\\Global\\" +#define TAPSUFFIX ".tap" + +//========================================================= +// TAP_COMPONENT_ID -- This string defines the TAP driver +// type -- different component IDs can reside in the system +// simultaneously. +//========================================================= + +#define TAP_COMPONENT_ID TAP_ID @@ -17,6 +17,29 @@ ***************************************************************************/ +#ifdef WIN32 + static void dropPrivileges(char *username, char *groupname, char *chrootdir) { + int error = 0; + if(strlen(username) > 0) { + error = 1; + } + if(strlen(groupname) > 0) { + error = 1; + } + if(strlen(chrootdir) > 0) { + error = 1; + } + if(error) { + throwError("user/group changing not implemented in windows version!\n"); + } + } +#else + + +#include <pwd.h> +#include <grp.h> + + // drop privileges static void dropPrivileges(char *username, char *groupname, char *chrootdir) { struct passwd *pwd = NULL; @@ -46,3 +69,6 @@ static void dropPrivileges(char *username, char *groupname, char *chrootdir) { if(swgroup) if(setgid(grp->gr_gid) < 0) throwError("could not switch group!"); if(swuser) if(setuid(pwd->pw_uid) < 0) throwError("could not switch user!"); } + + +#endif
\ No newline at end of file |