diff --git a/src/common.h b/src/common.h index dd7db6e..cc977d2 100644 --- a/src/common.h +++ b/src/common.h @@ -23,6 +23,7 @@ #define RAW_HDR_CMD 3 #define RAW_HDR_CMD_LOGIN 0x10 #define RAW_HDR_CMD_DATA 0x20 +#define RAW_HDR_CMD_PING 0x30 #define RAW_HDR_CMD_MASK 0xF0 #define RAW_HDR_USR_MASK 0x0F diff --git a/src/iodine.c b/src/iodine.c index 0ca60f3..81a757c 100644 --- a/src/iodine.c +++ b/src/iodine.c @@ -58,6 +58,8 @@ WORD req_version = MAKEWORD(2, 2); WSADATA wsa_data; #endif +#define PING_TIMEOUT(t) ((t) >= (conn == CONN_DNS_NULL ? 1 : 20)) + static void send_ping(int fd); static void send_chunk(int fd); static void send_raw_data(int fd); @@ -132,7 +134,9 @@ send_raw(int fd, char *buf, int buflen, int user, int cmd) len = MIN(sizeof(packet) - RAW_HDR_LEN, buflen); memcpy(packet, raw_header, RAW_HDR_LEN); - memcpy(&packet[RAW_HDR_LEN], buf, len); + if (len) { + memcpy(&packet[RAW_HDR_LEN], buf, len); + } len += RAW_HDR_LEN; packet[RAW_HDR_CMD] = cmd | (user & 0x0F); @@ -345,8 +349,10 @@ tunnel(int tun_fd, int dns_fd) fd_set fds; int rv; int i; + int seconds; rv = 0; + seconds = 0; while (running) { tv.tv_sec = 1; @@ -367,10 +373,11 @@ tunnel(int tun_fd, int dns_fd) if (i < 0) err(1, "select"); - if (i == 0 && conn == CONN_DNS_NULL) /* timeout */ - send_ping(dns_fd); - else { + if (i == 0) { /* timeout */ + seconds++; + } else { if (FD_ISSET(tun_fd, &fds)) { + seconds = 0; if (tunnel_tun(tun_fd, dns_fd) <= 0) continue; } @@ -379,6 +386,11 @@ tunnel(int tun_fd, int dns_fd) continue; } } + + if (PING_TIMEOUT(seconds)) { + send_ping(dns_fd); + seconds = 0; + } } return rv; @@ -445,25 +457,29 @@ send_login(int fd, char *login, int len) static void send_ping(int fd) { - char data[4]; - - if (is_sending()) { - outpkt.sentlen = 0; - outpkt.offset = 0; - outpkt.len = 0; + if (conn == CONN_DNS_NULL) { + char data[4]; + + if (is_sending()) { + outpkt.sentlen = 0; + outpkt.offset = 0; + outpkt.len = 0; + } + + data[0] = userid; + data[1] = ((downstream_seqno & 7) << 4) | (downstream_fragment & 15); + data[2] = (rand_seed >> 8) & 0xff; + data[3] = (rand_seed >> 0) & 0xff; + + down_ack_seqno = downstream_seqno; + down_ack_fragment = downstream_fragment; + + rand_seed++; + + send_packet(fd, 'P', data, sizeof(data)); + } else { + send_raw(fd, NULL, 0, userid, RAW_HDR_CMD_PING); } - - data[0] = userid; - data[1] = ((downstream_seqno & 7) << 4) | (downstream_fragment & 15); - data[2] = (rand_seed >> 8) & 0xff; - data[3] = (rand_seed >> 0) & 0xff; - - down_ack_seqno = downstream_seqno; - down_ack_fragment = downstream_fragment; - - rand_seed++; - - send_packet(fd, 'P', data, sizeof(data)); } static void diff --git a/src/iodined.c b/src/iodined.c index 3b7d33d..f29b0d9 100644 --- a/src/iodined.c +++ b/src/iodined.c @@ -145,7 +145,9 @@ send_raw(int fd, char *buf, int buflen, int user, int cmd, struct query *q) len = MIN(sizeof(packet) - RAW_HDR_LEN, buflen); memcpy(packet, raw_header, RAW_HDR_LEN); - memcpy(&packet[RAW_HDR_LEN], buf, len); + if (len) { + memcpy(&packet[RAW_HDR_LEN], buf, len); + } len += RAW_HDR_LEN; packet[RAW_HDR_CMD] = cmd | (user & 0x0F); @@ -929,6 +931,21 @@ handle_raw_data(char *packet, int len, struct query *q, int dns_fd, int tun_fd, handle_full_packet(tun_fd, userid); } +static void +handle_raw_ping(struct query *q, int dns_fd, int userid) +{ + if (check_user_and_ip(userid, q) != 0) { + return; + } + + /* Update query and time info for user */ + users[userid].last_pkt = time(NULL); + memcpy(&(users[userid].q), q, sizeof(struct query)); + + /* Send ping reply */ + send_raw(dns_fd, NULL, 0, userid, RAW_HDR_CMD_PING, q); +} + static int raw_decode(char *packet, int len, struct query *q, int dns_fd, int tun_fd) { @@ -949,6 +966,10 @@ raw_decode(char *packet, int len, struct query *q, int dns_fd, int tun_fd) /* Data packet */ handle_raw_data(&packet[RAW_HDR_LEN], len - RAW_HDR_LEN, q, dns_fd, tun_fd, raw_user); break; + case RAW_HDR_CMD_PING: + /* Keepalive packet */ + handle_raw_ping(q, dns_fd, raw_user); + break; default: warnx("Unhandled raw command %02X from user %d", RAW_HDR_GET_CMD(packet), raw_user); break;