tuntap.c | tuntap.c | |||
---|---|---|---|---|
skipping to change at line 18 | skipping to change at line 18 | |||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | */ | |||
#include <sys/types.h> | #include <sys/types.h> | |||
#include <sys/ioctl.h> | ||||
#include <sys/socket.h> | ||||
#include <netinet/in.h> | #if defined Windows | |||
#include <arpa/inet.h> | # include <winsock2.h> | |||
#if defined Linux | # include <ws2tcpip.h> | |||
# include <netinet/ether.h> | ||||
#else | #else | |||
# include <net/if.h> | ||||
# include <netinet/in.h> | # include <netinet/in.h> | |||
# include <netinet/if_ether.h> | # include <arpa/inet.h> | |||
#endif | #endif | |||
#include <stdio.h> | #include <stdio.h> | |||
#include <stdint.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | |||
#include <string.h> | #include <string.h> | |||
#include <time.h> | #include <ctype.h> | |||
#include <unistd.h> | ||||
#include "tuntap.h" | #include "tuntap.h" | |||
struct device * | struct device * | |||
tuntap_init(void) { | tuntap_init(void) { | |||
struct device *dev = NULL; | struct device *dev = NULL; | |||
if ((dev = malloc(sizeof(*dev))) == NULL) | if ((dev = (struct device *)malloc(sizeof(*dev))) == NULL) | |||
return NULL; | return NULL; | |||
(void)memset(dev->if_name, '\0', sizeof dev->if_name); | (void)memset(dev->if_name, '\0', sizeof dev->if_name); | |||
(void)memset(dev->hwaddr, '\0', sizeof dev->hwaddr); | (void)memset(dev->hwaddr, '\0', sizeof dev->hwaddr); | |||
dev->tun_fd = -1; | dev->tun_fd = TUNFD_INVALID_VALUE; | |||
dev->ctrl_sock = -1; | dev->ctrl_sock = -1; | |||
dev->flags = 0; | dev->flags = 0; | |||
tuntap_log = tuntap_log_default; | ||||
return dev; | return dev; | |||
} | } | |||
void | void | |||
tuntap_destroy(struct device *dev) { | tuntap_destroy(struct device *dev) { | |||
tuntap_sys_destroy(dev); | tuntap_sys_destroy(dev); | |||
tuntap_release(dev); | tuntap_release(dev); | |||
} | } | |||
int | ||||
tuntap_start(struct device *dev, int mode, int tun) { | ||||
int sock; | ||||
int fd; | ||||
fd = sock = -1; | ||||
/* Don't re-initialise a previously started device */ | ||||
if (dev->tun_fd != -1) { | ||||
return -1; | ||||
} | ||||
/* OpenBSD needs the control socket to be ready now */ | ||||
sock = socket(AF_INET, SOCK_DGRAM, 0); | ||||
if (sock == -1) { | ||||
goto clean; | ||||
} | ||||
dev->ctrl_sock = sock; | ||||
if (mode & TUNTAP_TUNMODE_PERSIST && tun == TUNTAP_TUNID_ANY) { | ||||
goto clean; /* XXX: Explain why */ | ||||
} | ||||
fd = tuntap_sys_start(dev, mode, tun); | ||||
if (fd == -1) { | ||||
goto clean; | ||||
} | ||||
dev->tun_fd = fd; | ||||
return 0; | ||||
clean: | ||||
if (fd != -1) { | ||||
(void)close(fd); | ||||
} | ||||
if (sock != -1) { | ||||
(void)close(sock); | ||||
} | ||||
return -1; | ||||
} | ||||
void | ||||
tuntap_release(struct device *dev) { | ||||
(void)close(dev->tun_fd); | ||||
(void)close(dev->ctrl_sock); | ||||
free(dev); | ||||
} | ||||
char * | char * | |||
tuntap_get_ifname(struct device *dev) { | tuntap_get_ifname(struct device *dev) { | |||
return dev->if_name; | return dev->if_name; | |||
} | } | |||
char * | ||||
tuntap_get_hwaddr(struct device *dev) { | ||||
struct ether_addr eth_attr; | ||||
(void)memcpy(ð_attr, dev->hwaddr, sizeof dev->hwaddr); | ||||
return ether_ntoa(ð_attr); | ||||
} | ||||
int | int | |||
tuntap_set_hwaddr(struct device *dev, const char *hwaddr) { | tuntap_version(void) { | |||
struct ether_addr *eth_addr, eth_rand; | return TUNTAP_VERSION; | |||
if (strcmp(hwaddr, "random") == 0) { | ||||
unsigned int i; | ||||
i = 0; | ||||
srandom((unsigned int)time(NULL)); | ||||
for (; i < sizeof eth_rand.ether_addr_octet; ++i) | ||||
eth_rand.ether_addr_octet[i] = (unsigned char)random | ||||
(); | ||||
eth_rand.ether_addr_octet[0] &= 0xfc; | ||||
eth_addr = ð_rand; | ||||
} else { | ||||
eth_addr = ether_aton(hwaddr); | ||||
if (eth_addr == NULL) { | ||||
return -1; | ||||
} | ||||
} | ||||
(void)memcpy(dev->hwaddr, eth_addr, 6); | ||||
if (tuntap_sys_set_hwaddr(dev, eth_addr) == -1) | ||||
return -1; | ||||
return 0; | ||||
} | } | |||
int | int | |||
tuntap_up(struct device *dev) { | tuntap_set_ip(struct device *dev, const char *addr, int netmask) { | |||
struct ifreq ifr; | t_tun_in_addr baddr4; | |||
t_tun_in6_addr baddr6; | ||||
(void)memset(&ifr, '\0', sizeof ifr); | uint32_t mask; | |||
(void)memcpy(ifr.ifr_name, dev->if_name, sizeof dev->if_name); | int errval; | |||
ifr.ifr_flags = (short int)dev->flags; | ||||
ifr.ifr_flags |= IFF_UP; | ||||
if (ioctl(dev->ctrl_sock, SIOCSIFFLAGS, &ifr) == -1) { | ||||
return -1; | ||||
} | ||||
dev->flags = ifr.ifr_flags; | ||||
return 0; | ||||
} | ||||
int | ||||
tuntap_down(struct device *dev) { | ||||
struct ifreq ifr; | ||||
(void)memset(&ifr, '\0', sizeof ifr); | ||||
(void)memcpy(ifr.ifr_name, dev->if_name, sizeof dev->if_name); | ||||
ifr.ifr_flags = (short)dev->flags; | ||||
ifr.ifr_flags &= ~IFF_UP; | ||||
if (ioctl(dev->ctrl_sock, SIOCSIFFLAGS, &ifr) == -1) { | ||||
return -1; | ||||
} | ||||
dev->flags = ifr.ifr_flags; | ||||
return 0; | ||||
} | ||||
int | ||||
tuntap_get_mtu(struct device *dev) { | ||||
struct ifreq ifr; | ||||
/* Only accept started device */ | /* Only accept started device */ | |||
if (dev->tun_fd == -1) | if (dev->tun_fd == TUNFD_INVALID_VALUE) { | |||
tuntap_log(TUNTAP_LOG_NOTICE, "Device is not started"); | ||||
return 0; | return 0; | |||
(void)memset(&ifr, '\0', sizeof ifr); | ||||
(void)memcpy(ifr.ifr_name, dev->if_name, sizeof dev->if_name); | ||||
if (ioctl(dev->ctrl_sock, SIOCGIFMTU, &ifr) == -1) { | ||||
return -1; | ||||
} | ||||
return ifr.ifr_mtu; | ||||
} | ||||
int | ||||
tuntap_set_mtu(struct device *dev, int mtu) { | ||||
struct ifreq ifr; | ||||
/* Only accept started device */ | ||||
if (dev->tun_fd == -1) | ||||
return 0; | ||||
(void)memset(&ifr, '\0', sizeof ifr); | ||||
(void)memcpy(ifr.ifr_name, dev->if_name, sizeof dev->if_name); | ||||
ifr.ifr_mtu = mtu; | ||||
if (ioctl(dev->ctrl_sock, SIOCSIFMTU, &ifr) == -1) { | ||||
return -1; | ||||
} | ||||
return 0; | ||||
} | ||||
int | ||||
tuntap_set_ip(struct device *dev, const char *saddr, int bits) { | ||||
struct sockaddr_in sa; | ||||
unsigned int addr; | ||||
unsigned int mask; | ||||
if (saddr == NULL) { | ||||
(void)fprintf(stderr, "libtuntap: tuntap_set_ip" | ||||
" invalid address\n"); | ||||
return -1; | ||||
} | } | |||
if (bits < 0 || bits > 128) { | if (addr == NULL) { | |||
(void)fprintf(stderr, "libtuntap: tuntap_set_ip" | tuntap_log(TUNTAP_LOG_ERR, "Invalid parameter 'addr'"); | |||
" invalid netmask\n"); | ||||
return -1; | return -1; | |||
} | } | |||
/* Destination address */ | if (netmask < 0 || netmask > 128) { | |||
if (inet_pton(AF_INET, saddr, &(sa.sin_addr)) != 1) { | tuntap_log(TUNTAP_LOG_ERR, "Invalid parameter 'netmask'"); | |||
(void)fprintf(stderr, "libtuntap: tuntap_set_ip (IPv4)" | ||||
" bad address\n"); | ||||
return -1; | return -1; | |||
} | } | |||
addr = sa.sin_addr.s_addr; | ||||
/* Netmask */ | /* Netmask */ | |||
mask = ~0; | mask = ~0; | |||
mask = ~(mask >> bits); | mask = ~(mask >> netmask); | |||
mask = ntohl(mask); | mask = htonl(mask); | |||
return tuntap_sys_set_ip(dev, addr, mask); | /* | |||
} | * Destination address parsing: we try IPv4 first and fall back to | |||
* IPv6 if inet_pton return 0 | ||||
int | */ | |||
tuntap_read(struct device *dev, void *buf, size_t size) { | (void)memset(&baddr4, '\0', sizeof baddr4); | |||
int n; | (void)memset(&baddr6, '\0', sizeof baddr6); | |||
/* Only accept started device */ | errval = inet_pton(AF_INET, addr, &(baddr4)); | |||
if (dev->tun_fd == -1) | if (errval == 1) { | |||
return 0; | return tuntap_sys_set_ipv4(dev, &baddr4, mask); | |||
} else if (errval == 0) { | ||||
n = read(dev->tun_fd, buf, size); | if (inet_pton(AF_INET6, addr, &(baddr6)) == -1) { | |||
if (n == -1) { | tuntap_log(TUNTAP_LOG_ERR, "Invalid parameters"); | |||
(void)fprintf(stderr, | return -1; | |||
"libtuntap: enable to read from device\n"); | } | |||
return tuntap_sys_set_ipv6(dev, &baddr6, mask); | ||||
} else if (errval == -1) { | ||||
tuntap_log(TUNTAP_LOG_ERR, "Invalid parameters"); | ||||
return -1; | return -1; | |||
} | } | |||
return n; | ||||
} | ||||
int | ||||
tuntap_write(struct device *dev, void *buf, size_t size) { | ||||
int n; | ||||
/* Only accept started device */ | ||||
if (dev->tun_fd == -1) | ||||
return 0; | ||||
n = write(dev->tun_fd, buf, size); | /* NOTREACHED */ | |||
if (n == -1) { | return -1; | |||
(void)fprintf(stderr, | ||||
"libtuntap: enable to write to device\n"); | ||||
return -1; | ||||
} | ||||
return n; | ||||
} | } | |||
End of changes. 22 change blocks. | ||||
209 lines changed or deleted | 45 lines changed or added | |||
This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/ |