diff options
Diffstat (limited to 'clatd.c')
-rw-r--r-- | clatd.c | 132 |
1 files changed, 46 insertions, 86 deletions
@@ -50,6 +50,8 @@ #include "mtu.h" #include "getaddr.h" #include "dump.h" +#include "tun.h" +#include "ring.h" #define DEVICEPREFIX "v4-" @@ -65,44 +67,6 @@ void stop_loop() { running = 0; } -/* function: tun_open - * tries to open the tunnel device - */ -int tun_open() { - int fd; - - fd = open("/dev/tun", O_RDWR); - if(fd < 0) { - fd = open("/dev/net/tun", O_RDWR); - } - - return fd; -} - -/* function: tun_alloc - * creates a tun interface and names it - * dev - the name for the new tun device - */ -int tun_alloc(char *dev, int fd) { - struct ifreq ifr; - int err; - - memset(&ifr, 0, sizeof(ifr)); - - ifr.ifr_flags = IFF_TUN; - if( *dev ) { - strncpy(ifr.ifr_name, dev, IFNAMSIZ); - ifr.ifr_name[IFNAMSIZ-1] = '\0'; - } - - if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ){ - close(fd); - return err; - } - strcpy(dev, ifr.ifr_name); - return 0; -} - /* function: configure_packet_socket * Binds the packet socket and attaches the receive filter to it. * sock - the socket to configure @@ -234,7 +198,7 @@ void drop_root() { * mark - the socket mark to use for the sending raw socket */ void open_sockets(struct tun_data *tunnel, uint32_t mark) { - int rawsock = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW); + int rawsock = socket(AF_INET6, SOCK_RAW | SOCK_NONBLOCK, IPPROTO_RAW); if (rawsock < 0) { logmsg(ANDROID_LOG_FATAL, "raw socket failed: %s", strerror(errno)); exit(1); @@ -250,13 +214,10 @@ void open_sockets(struct tun_data *tunnel, uint32_t mark) { tunnel->write_fd6 = rawsock; - int packetsock = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6)); - if (packetsock < 0) { - logmsg(ANDROID_LOG_FATAL, "packet socket failed: %s", strerror(errno)); + tunnel->read_fd6 = ring_create(tunnel); + if (tunnel->read_fd6 < 0) { exit(1); } - - tunnel->read_fd6 = packetsock; } /* function: update_clat_ipv6_address @@ -353,23 +314,31 @@ void configure_interface(const char *uplink_interface, const char *plat_prefix, exit(1); } + error = set_nonblocking(tunnel->fd4); + if (error < 0) { + logmsg(ANDROID_LOG_FATAL, "set_nonblocking failed: %s", strerror(errno)); + exit(1); + } + configure_tun_ip(tunnel); } /* function: read_packet - * reads a packet from the tunnel fd and passes it down the stack - * active_fd - tun file descriptor marked ready for reading - * tunnel - tun device data + * reads a packet from the tunnel fd and translates it + * read_fd - file descriptor to read original packet from + * write_fd - file descriptor to write translated packet to + * to_ipv6 - whether the packet is to be translated to ipv6 or ipv4 */ -void read_packet(int active_fd, const struct tun_data *tunnel) { +void read_packet(int read_fd, int write_fd, int to_ipv6) { ssize_t readlen; uint8_t buf[PACKETLEN], *packet; - int fd; - readlen = read(active_fd, buf, PACKETLEN); + readlen = read(read_fd, buf, PACKETLEN); if(readlen < 0) { - logmsg(ANDROID_LOG_WARN,"read_packet/read error: %s", strerror(errno)); + if (errno != EAGAIN) { + logmsg(ANDROID_LOG_WARN,"read_packet/read error: %s", strerror(errno)); + } return; } else if(readlen == 0) { logmsg(ANDROID_LOG_WARN,"read_packet/tun interface removed"); @@ -377,41 +346,32 @@ void read_packet(int active_fd, const struct tun_data *tunnel) { return; } - if (active_fd == tunnel->fd4) { - ssize_t header_size = sizeof(struct tun_pi); - - if (readlen < header_size) { - logmsg(ANDROID_LOG_WARN,"read_packet/short read: got %ld bytes", readlen); - return; - } - - struct tun_pi *tun_header = (struct tun_pi *) buf; - uint16_t proto = ntohs(tun_header->proto); - if (proto != ETH_P_IP) { - logmsg(ANDROID_LOG_WARN, "%s: unknown packet type = 0x%x", __func__, proto); - return; - } + struct tun_pi *tun_header = (struct tun_pi *) buf; + if (readlen < (ssize_t) sizeof(*tun_header)) { + logmsg(ANDROID_LOG_WARN,"read_packet/short read: got %ld bytes", readlen); + return; + } - if(tun_header->flags != 0) { - logmsg(ANDROID_LOG_WARN, "%s: unexpected flags = %d", __func__, tun_header->flags); - } + uint16_t proto = ntohs(tun_header->proto); + if (proto != ETH_P_IP) { + logmsg(ANDROID_LOG_WARN, "%s: unknown packet type = 0x%x", __func__, proto); + return; + } - fd = tunnel->write_fd6; - packet = buf + header_size; - readlen -= header_size; - } else { - fd = tunnel->fd4; - packet = buf; + if(tun_header->flags != 0) { + logmsg(ANDROID_LOG_WARN, "%s: unexpected flags = %d", __func__, tun_header->flags); } - translate_packet(fd, (fd == tunnel->write_fd6), packet, readlen); + packet = (uint8_t *) (tun_header + 1); + readlen -= sizeof(*tun_header); + translate_packet(write_fd, to_ipv6, packet, readlen); } /* function: event_loop * reads packets from the tun network interface and passes them down the stack * tunnel - tun device data */ -void event_loop(const struct tun_data *tunnel) { +void event_loop(struct tun_data *tunnel) { time_t last_interface_poll; struct pollfd wait_fd[] = { { tunnel->read_fd6, POLLIN, 0 }, @@ -427,16 +387,16 @@ void event_loop(const struct tun_data *tunnel) { logmsg(ANDROID_LOG_WARN,"event_loop/poll returned an error: %s",strerror(errno)); } } else { - size_t i; - for(i = 0; i < ARRAY_SIZE(wait_fd); i++) { - // Call read_packet if the socket has data to be read, but also if an - // error is waiting. If we don't call read() after getting POLLERR, a - // subsequent poll() will return immediately with POLLERR again, - // causing this code to spin in a loop. Calling read() will clear the - // socket error flag instead. - if(wait_fd[i].revents != 0) { - read_packet(wait_fd[i].fd,tunnel); - } + // Call read_packet if the socket has data to be read, but also if an + // error is waiting. If we don't call read() after getting POLLERR, a + // subsequent poll() will return immediately with POLLERR again, + // causing this code to spin in a loop. Calling read() will clear the + // socket error flag instead. + if (wait_fd[0].revents) { + ring_read(&tunnel->ring, tunnel->fd4, 0 /* to_ipv6 */); + } + if (wait_fd[1].revents) { + read_packet(tunnel->fd4, tunnel->write_fd6, 1 /* to_ipv6 */); } } |