summaryrefslogtreecommitdiffstats
path: root/clatd.c
diff options
context:
space:
mode:
Diffstat (limited to 'clatd.c')
-rw-r--r--clatd.c132
1 files changed, 46 insertions, 86 deletions
diff --git a/clatd.c b/clatd.c
index 3f0af0b..faeb679 100644
--- a/clatd.c
+++ b/clatd.c
@@ -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 */);
}
}