/* * tun-bsd.c * * Copyright (c) 2001 Dug Song * * $Id: tun-bsd.c 573 2005-02-10 23:50:04Z dugsong $ */ #include "config.h" #include #include #include #include #include #include #include #include #include "dnet.h" struct tun { int fd; intf_t *intf; struct intf_entry save; }; #define MAX_DEVS 16 /* XXX - max number of tunnel devices */ tun_t * tun_open(struct addr *src, struct addr *dst, int mtu) { struct intf_entry ifent; tun_t *tun; char dev[128]; int i; if (src->addr_type != ADDR_TYPE_IP || dst->addr_type != ADDR_TYPE_IP || src->addr_bits != IP_ADDR_BITS || dst->addr_bits != IP_ADDR_BITS) { errno = EINVAL; return (NULL); } if ((tun = calloc(1, sizeof(*tun))) == NULL) return (NULL); if ((tun->intf = intf_open()) == NULL) return (tun_close(tun)); memset(&ifent, 0, sizeof(ifent)); ifent.intf_len = sizeof(ifent); for (i = 0; i < MAX_DEVS; i++) { snprintf(dev, sizeof(dev), "/dev/tun%d", i); strlcpy(ifent.intf_name, dev + 5, sizeof(ifent.intf_name)); tun->save = ifent; if ((tun->fd = open(dev, O_RDWR, 0)) != -1 && intf_get(tun->intf, &tun->save) == 0) { route_t *r; struct route_entry entry; ifent.intf_flags = INTF_FLAG_UP|INTF_FLAG_POINTOPOINT; ifent.intf_addr = *src; ifent.intf_dst_addr = *dst; ifent.intf_mtu = mtu; if (intf_set(tun->intf, &ifent) < 0) tun = tun_close(tun); /* XXX - try to ensure our route got set */ if ((r = route_open()) != NULL) { entry.route_dst = *dst; entry.route_gw = *src; route_add(r, &entry); route_close(r); } break; } } if (i == MAX_DEVS) tun = tun_close(tun); return (tun); } const char * tun_name(tun_t *tun) { return (tun->save.intf_name); } int tun_fileno(tun_t *tun) { return (tun->fd); } ssize_t tun_send(tun_t *tun, const void *buf, size_t size) { #ifdef __OpenBSD__ struct iovec iov[2]; uint32_t af = htonl(AF_INET); iov[0].iov_base = ⁡ iov[0].iov_len = sizeof(af); iov[1].iov_base = (void *)buf; iov[1].iov_len = size; return (writev(tun->fd, iov, 2)); #else return (write(tun->fd, buf, size)); #endif } ssize_t tun_recv(tun_t *tun, void *buf, size_t size) { #ifdef __OpenBSD__ struct iovec iov[2]; uint32_t af; iov[0].iov_base = ⁡ iov[0].iov_len = sizeof(af); iov[1].iov_base = (void *)buf; iov[1].iov_len = size; return (readv(tun->fd, iov, 2) - sizeof(af)); #else return (read(tun->fd, buf, size)); #endif } tun_t * tun_close(tun_t *tun) { if (tun->fd > 0) close(tun->fd); if (tun->intf != NULL) { /* Restore interface configuration on close. */ intf_set(tun->intf, &tun->save); intf_close(tun->intf); } free(tun); return (NULL); }