summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/bsd/tun.c283
-rw-r--r--src/linux/tun.c2
-rw-r--r--src/tun.h2
-rw-r--r--src/uanytun.c20
4 files changed, 242 insertions, 65 deletions
diff --git a/src/bsd/tun.c b/src/bsd/tun.c
index b34c50d..20ccb68 100644
--- a/src/bsd/tun.c
+++ b/src/bsd/tun.c
@@ -40,6 +40,21 @@
#include "log.h"
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/if_tun.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#define DEVICE_FILE_MAX 255
+
void tun_init(tun_device_t** dev, const char* dev_name, const char* dev_type, const char* ifcfg_lp, const char* ifcfg_rnmp)
{
if(!dev)
@@ -50,17 +65,150 @@ void tun_init(tun_device_t** dev, const char* dev_name, const char* dev_type, co
return;
tun_conf(*dev, dev_name, dev_type, ifcfg_lp, ifcfg_rnmp, 1400);
+ (*dev)->actual_name_ = NULL;
+
+ char* device_file = NULL;
+ char* actual_name_start = NULL;
+ int dynamic = 1;
+ if(dev_name) {
+ asprintf(&device_file, "/dev/%s", dev_name);
+ dynamic = 0;
+ }
+ else if((*dev)->type_ == TYPE_TUN) {
+ asprintf(&device_file, "/dev/tun");
+ actual_name_start = "tun";
+ }
+ else if((*dev)->type_ == TYPE_TAP) {
+ asprintf(&device_file, "/dev/tap");
+ actual_name_start = "tap";
+ }
+ else {
+ log_printf(ERR, "unable to recognize type of device (tun or tap)");
+ tun_close(dev);
+ return;
+ }
+ if(!device_file) {
+ log_printf(ERR, "can't open device file: memory error");
+ tun_close(dev);
+ return;
+ }
+
+ u_int32_t dev_id=0;
+ if(dynamic) {
+ for(; dev_id <= DEVICE_FILE_MAX; ++dev_id) {
+ char* device_file_tmp = NULL;
+ asprintf(&device_file_tmp, "%s%d", device_file, dev_id);
+
+ if(!device_file_tmp) {
+ log_printf(ERR, "can't open device file: memory error");
+ free(device_file);
+ tun_close(dev);
+ return;
+ }
+
+ (*dev)->fd_ = open(device_file_tmp, O_RDWR);
+ free(device_file_tmp);
+ if((*dev)->fd_ >= 0)
+ break;
+ }
+ }
+ else
+ (*dev)->fd_ = open(device_file, O_RDWR);
+ free(device_file);
+
+ if((*dev)->fd_ < 0) {
+ if(dynamic)
+ log_printf(ERR, "can't open device file dynamically: no unused node left");
+ else
+ log_printf(ERR, "can't open device file (%s): %m", device_file);
+
+ tun_close(dev);
+ return;
+ }
+
+ if(dynamic)
+ asprintf(&((*dev)->actual_name_), "%s%d", actual_name_start, dev_id);
+ else
+ (*dev)->actual_name_ = strdup(dev_name);
+
+ if(!(*dev)->actual_name_) {
+ log_printf(ERR, "can't open device file: memory error");
+ tun_close(dev);
+ return;
+ }
+ tun_init_post(*dev);
if(ifcfg_lp && ifcfg_rnmp)
tun_do_ifconfig(*dev);
}
-void tun_init_post(tun_device_t* dev)
+
+#if defined(__GNUC__) && defined(__OpenBSD__)
+
+int tun_init_post(tun_device_t* dev)
{
-// nothing yet
+ if(!dev)
+ return;
+
+ dev->with_pi_ = 1;
+ if(dev->type_ == TYPE_TAP)
+ dev->with_pi_ = 0;
+
+ struct tuninfo ti;
+
+ if (ioctl(dev->fd_, TUNGIFINFO, &ti) < 0) {
+ log_printf(ERR, "can't enable multicast for interface");
+ return -1;
+ }
+
+ ti.flags |= IFF_MULTICAST;
+
+ if (ioctl(dev->fd_, TUNSIFINFO, &ti) < 0) {
+ log_printf(ERR, "can't enable multicast for interface");
+ return -1;
+ }
+ return 0;
}
+#elif defined(__GNUC__) && defined(__FreeBSD__)
+
+int tun_init_post(tun_device_t* dev)
+{
+ if(!dev)
+ return;
+
+ dev->with_pi_ = 1;
+ if(dev->type_ == TYPE_TAP)
+ dev->with_pi_ = 0;
+
+ int arg = 0;
+ ioctl(dev->fd_, TUNSLMODE, &arg);
+ arg = 1;
+ ioctl(dev->fd_, TUNSIFHEAD, &arg);
+}
+
+#elif defined(__GNUC__) && defined(__NetBSD__)
+
+int tun_init_post(tun_device_t* dev)
+{
+ if(!dev)
+ return;
+
+ dev->with_pi_ = 0;
+
+ int arg = IFF_POINTOPOINT|IFF_MULTICAST;
+ ioctl(dev->fd_, TUNSIFMODE, &arg);
+ arg = 0;
+ ioctl(dev->fd_, TUNSLMODE, &arg);
+}
+
+#else
+ #error This Device works just for OpenBSD, FreeBSD or NetBSD
+#endif
+
+
+
void tun_close(tun_device_t** dev)
{
if(!dev || !(*dev))
@@ -84,74 +232,89 @@ void tun_close(tun_device_t** dev)
int tun_read(tun_device_t* dev, u_int8_t* buf, u_int32_t len)
{
-/* if(!dev || dev->fd_ < 0) */
-/* return -1; */
+ if(!dev || dev->fd_ < 0)
+ return -1;
-/* if(dev->with_pi_) */
-/* { */
-/* struct iovec iov[2]; */
-/* struct tun_pi tpi; */
+ if(dev->with_pi_)
+ {
+ struct iovec iov[2];
+ u_int32_t type;
-/* iov[0].iov_base = &tpi; */
-/* iov[0].iov_len = sizeof(tpi); */
-/* iov[1].iov_base = buf; */
-/* iov[1].iov_len = len; */
-/* return(tun_fix_return(readv(dev->fd_, iov, 2), sizeof(tpi))); */
-/* } */
-/* else */
-/* return(read(dev->fd_, buf, len)); */
- return -1;
+ iov[0].iov_base = &type;
+ iov[0].iov_len = sizeof(type);
+ iov[1].iov_base = buf;
+ iov[1].iov_len = len;
+ return(tun_fix_return(readv(dev->fd_, iov, 2), sizeof(type)));
+ }
+ else
+ return(read(dev->fd_, buf, len));
}
int tun_write(tun_device_t* dev, u_int8_t* buf, u_int32_t len)
{
-/* if(!dev || dev->fd_ < 0) */
-/* return -1; */
-
-/* if(dev->with_pi_) */
-/* { */
-/* struct iovec iov[2]; */
-/* struct tun_pi tpi; */
-/* struct iphdr *hdr = (struct iphdr *)buf; */
+ if(!dev || dev->fd_ < 0)
+ return -1;
+
+ if(dev->with_pi_)
+ {
+ struct iovec iov[2];
+ u_int32_t type;
+ struct ip *hdr = (struct ip*)buf;
-/* tpi.flags = 0; */
-/* if(hdr->version == 4) */
-/* tpi.proto = htons(ETH_P_IP); */
-/* else */
-/* tpi.proto = htons(ETH_P_IPV6); */
+ type = 0;
+ if(hdr->ip_v == 4)
+ type = htonl(AF_INET);
+ else
+ type = htonl(AF_INET6);
-/* iov[0].iov_base = &tpi; */
-/* iov[0].iov_len = sizeof(tpi); */
-/* iov[1].iov_base = buf; */
-/* iov[1].iov_len = len; */
-/* return(tun_fix_return(writev(dev->fd_, iov, 2), sizeof(tpi))); */
-/* } */
-/* else */
-/* return(write(dev->fd_, buf, len)); */
- return -1;
+ iov[0].iov_base = &type;
+ iov[0].iov_len = sizeof(type);
+ iov[1].iov_base = buf;
+ iov[1].iov_len = len;
+ return(tun_fix_return(writev(dev->fd_, iov, 2), sizeof(type)));
+ }
+ else
+ return(write(dev->fd_, buf, len));
}
void tun_do_ifconfig(tun_device_t* dev)
{
-/* if(!dev || !dev->actual_name_ || !dev->local_ || !dev->remote_netmask_) */
-/* return; */
-
-/* char* command = NULL; */
-/* if(dev->type_ == TYPE_TUN) */
-/* asprintf(&command, "/sbin/ifconfig %s %s pointopoint %s mtu %d", dev->actual_name_, dev->local_, dev->remote_netmask_, dev->mtu_); */
-/* else */
-/* asprintf(&command, "/sbin/ifconfig %s %s netmask %s mtu %d", dev->actual_name_, dev->local_, dev->remote_netmask_, dev->mtu_); */
-
-/* if(!command) { */
-/* log_printf(ERR, "Execution of ifconfig failed"); */
-/* return; */
-/* } */
-
-/* int result = system(command); */
-/* if(result == -1) */
-/* log_printf(ERR, "Execution of ifconfig failed"); */
-/* else */
-/* log_printf(NOTICE, "ifconfig returned %d", WEXITSTATUS(result)); */
-
-/* free(command); */
+ if(!dev || !dev->actual_name_ || !dev->local_ || !dev->remote_netmask_)
+ return;
+
+
+ char* command = NULL;
+ char* netmask;
+ char* end;
+ if(dev->type_ == TYPE_TAP) {
+ netmask = "netmask ";
+#if defined(__GNUC__) && defined(__OpenBSD__)
+ end = " link0";
+#elif defined(__GNUC__) && defined(__FreeBSD__)
+ end = " up";
+#elif defined(__GNUC__) && defined(__NetBSD__)
+ end = "";
+#else
+ #error This Device works just for OpenBSD, FreeBSD or NetBSD
+#endif
+ }
+ else {
+ netmask = "";
+ end = " netmask 255.255.255.255 up";
+ }
+
+ asprintf(&command, "/sbin/ifconfig %s %s %s%s mtu %d%s", dev->actual_name_, dev->local_ , netmask,
+ dev->remote_netmask_, dev->mtu_, end);
+ if(!command) {
+ log_printf(ERR, "Execution of ifconfig failed");
+ return;
+ }
+
+ int result = system(command);
+ if(result == -1)
+ log_printf(ERR, "Execution of ifconfig failed");
+ else
+ log_printf(NOTICE, "ifconfig returned %d", WEXITSTATUS(result));
+
+ free(command);
}
diff --git a/src/linux/tun.c b/src/linux/tun.c
index b24f48b..da623ae 100644
--- a/src/linux/tun.c
+++ b/src/linux/tun.c
@@ -115,7 +115,7 @@ void tun_init(tun_device_t** dev, const char* dev_name, const char* dev_type, co
tun_do_ifconfig(*dev);
}
-void tun_init_post(tun_device_t* dev)
+int tun_init_post(tun_device_t* dev)
{
// nothing yet
}
diff --git a/src/tun.h b/src/tun.h
index f967054..5f30aab 100644
--- a/src/tun.h
+++ b/src/tun.h
@@ -52,7 +52,7 @@ struct tun_device_struct {
typedef struct tun_device_struct tun_device_t;
void tun_init(tun_device_t** dev, const char* dev_name, const char* dev_type, const char* ifcfg_lp, const char* ifcfg_rnmp);
-void tun_init_post(tun_device_t* dev);
+int tun_init_post(tun_device_t* dev);
void tun_do_ifconfig(tun_device_t* dev);
void tun_close(tun_device_t** dev);
diff --git a/src/uanytun.c b/src/uanytun.c
index 0d47e8f..fa2a207 100644
--- a/src/uanytun.c
+++ b/src/uanytun.c
@@ -62,7 +62,7 @@ int main_loop(tun_device_t* dev, udp_socket_t* sock, options_t* opt)
plain_packet_init(&plain_packet);
encrypted_packet_t encrypted_packet;
encrypted_packet_init(&encrypted_packet);
- u_int32_t len = 0;
+ int len = 0;
udp_endpoint_t remote;
seq_nr_t seq_nr = 0;
fd_set readfds;
@@ -99,6 +99,11 @@ int main_loop(tun_device_t* dev, udp_socket_t* sock, options_t* opt)
if(FD_ISSET(dev->fd_, &readfds)) {
len = tun_read(dev, plain_packet_get_payload(&plain_packet), plain_packet_get_payload_length(&plain_packet));
+ if(len == -1) {
+ log_printf(ERR, "error on reading from device: %m");
+ continue;
+ }
+
plain_packet_set_payload_length(&plain_packet, len);
if(dev->type_ = TYPE_TUN)
@@ -113,11 +118,18 @@ int main_loop(tun_device_t* dev, udp_socket_t* sock, options_t* opt)
// TODO: add auth-tag
- udp_write(sock, encrypted_packet_get_packet(&encrypted_packet), encrypted_packet_get_length(&encrypted_packet));
+ len = udp_write(sock, encrypted_packet_get_packet(&encrypted_packet), encrypted_packet_get_length(&encrypted_packet));
+ if(len == -1)
+ log_printf(ERR, "error on sending udp packet: %m");
}
if(FD_ISSET(sock->fd_, &readfds)) {
len = udp_read(sock, encrypted_packet_get_packet(&encrypted_packet), encrypted_packet_get_length(&encrypted_packet), &remote);
+ if(len == -1) {
+ log_printf(ERR, "error on receiving udp packet: %m");
+ continue;
+ }
+
encrypted_packet_set_length(&encrypted_packet, len);
// TODO: check auth-tag
@@ -136,7 +148,9 @@ int main_loop(tun_device_t* dev, udp_socket_t* sock, options_t* opt)
cipher_decrypt(c, &encrypted_packet, &plain_packet);
- tun_write(dev, plain_packet_get_payload(&plain_packet), plain_packet_get_payload_length(&plain_packet));
+ len = tun_write(dev, plain_packet_get_payload(&plain_packet), plain_packet_get_payload_length(&plain_packet));
+ if(len == -1)
+ log_printf(ERR, "error on writing to device: %m");
}
}