diff --git a/src/dns.c b/src/dns.c index d8d51fa..df06fd1 100644 --- a/src/dns.c +++ b/src/dns.c @@ -269,7 +269,7 @@ dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, siz rv = MIN(rlen, sizeof(rdata)); rv = readdata(packet, &data, rdata, rv); - if(type == T_NULL && rv > 2 && buf) { + if(type == T_NULL && rv >= 2 && buf) { rv = MIN(rv, buflen); memcpy(buf, rdata, rv); } diff --git a/src/iodine.c b/src/iodine.c index de37320..b6ed9a6 100644 --- a/src/iodine.c +++ b/src/iodine.c @@ -63,7 +63,8 @@ static int downstream_seqno; static int downstream_fragment; /* Current IP packet */ -static struct packet packet; +static struct packet outpkt; +static struct packet inpkt; /* My userid at the server */ static char userid; @@ -151,7 +152,7 @@ build_hostname(char *buf, size_t buflen, static int is_sending() { - return (packet.len != 0); + return (outpkt.len != 0); } static int @@ -181,12 +182,12 @@ read_dns(int fd, char *buf, int buflen) if (is_sending() && chunkid == q.id) { /* Got ACK on sent packet */ - packet.offset += packet.sentlen; - if (packet.offset == packet.len) { + outpkt.offset += outpkt.sentlen; + if (outpkt.offset == outpkt.len) { /* Packet completed */ - packet.offset = 0; - packet.len = 0; - packet.sentlen = 0; + outpkt.offset = 0; + outpkt.len = 0; + outpkt.sentlen = 0; } else { /* More to send */ send_chunk(fd); @@ -212,12 +213,12 @@ tunnel_tun(int tun_fd, int dns_fd) inlen = read; compress2((uint8_t*)out, &outlen, (uint8_t*)in, inlen, 9); - memcpy(packet.data, out, MIN(outlen, sizeof(packet.data))); - packet.sentlen = 0; - packet.offset = 0; - packet.len = outlen; - packet.seqno++; - packet.fragment = 0; + memcpy(outpkt.data, out, MIN(outlen, sizeof(outpkt.data))); + outpkt.sentlen = 0; + outpkt.offset = 0; + outpkt.len = outlen; + outpkt.seqno++; + outpkt.fragment = 0; send_chunk(dns_fd); @@ -227,24 +228,40 @@ tunnel_tun(int tun_fd, int dns_fd) static int tunnel_dns(int tun_fd, int dns_fd) { - unsigned long outlen; - unsigned long inlen; - char out[64*1024]; - char in[64*1024]; + unsigned long datalen; + char buf[64*1024]; size_t read; - if ((read = read_dns(dns_fd, in, sizeof(in))) <= 2) + if ((read = read_dns(dns_fd, buf, sizeof(buf))) <= 2) return -1; - - outlen = sizeof(out); - inlen = read; - /* Skip 2 byte data header and uncompress */ - if (uncompress((uint8_t*)out, &outlen, (uint8_t*) &in[2], inlen - 2) != Z_OK) { + if (downstream_seqno != inpkt.seqno) { + /* New packet */ + inpkt.seqno = downstream_seqno; + inpkt.fragment = downstream_fragment; + inpkt.len = 0; + } else if (downstream_fragment <= inpkt.fragment) { + /* Duplicate fragment */ return -1; } + inpkt.fragment = downstream_fragment; - write_tun(tun_fd, out, outlen); + datalen = MIN(read - 2, sizeof(inpkt.data) - inpkt.len); + + /* Skip 2 byte data header and append to packet */ + memcpy(&inpkt.data[inpkt.len], &buf[2], datalen); + inpkt.len += datalen; + + if (buf[1] & 1) { /* If last fragment flag is set */ + /* Uncompress packet and send to tun */ + datalen = sizeof(buf); + if (uncompress((uint8_t*)buf, &datalen, (uint8_t*) inpkt.data, inpkt.len) == Z_OK) { + write_tun(tun_fd, buf, datalen); + } + inpkt.len = 0; + } + + /* If we have nothing to send, send a ping to get more data */ if (!is_sending()) send_ping(dns_fd); @@ -306,26 +323,26 @@ send_chunk(int fd) int code; char *p; - p = packet.data; - p += packet.offset; - avail = packet.len - packet.offset; + p = outpkt.data; + p += outpkt.offset; + avail = outpkt.len - outpkt.offset; - packet.sentlen = build_hostname(buf + 4, sizeof(buf) - 4, p, avail, topdomain, dataenc); + outpkt.sentlen = build_hostname(buf + 4, sizeof(buf) - 4, p, avail, topdomain, dataenc); /* Build upstream data header (see doc/proto_xxxxxxxx.txt) */ buf[0] = hex[userid & 15]; /* First byte is 4 bits userid */ - code = ((packet.seqno & 7) << 2) | ((packet.fragment & 15) >> 2); + code = ((outpkt.seqno & 7) << 2) | ((outpkt.fragment & 15) >> 2); buf[1] = b32_5to8(code); /* Second byte is 3 bits seqno, 2 upper bits fragment count */ - code = ((packet.fragment & 3) << 3) | (downstream_seqno & 7); + code = ((outpkt.fragment & 3) << 3) | (downstream_seqno & 7); buf[2] = b32_5to8(code); /* Third byte is 2 bits lower fragment count, 3 bits downstream packet seqno */ - code = ((downstream_fragment & 15) << 1) | (packet.sentlen == avail); + code = ((downstream_fragment & 15) << 1) | (outpkt.sentlen == avail); buf[3] = b32_5to8(code); /* Fourth byte is 4 bits downstream fragment count, 1 bit compression flag */ - packet.fragment++; + outpkt.fragment++; send_query(fd, buf); } @@ -352,13 +369,13 @@ send_ping(int fd) char data[4]; if (is_sending()) { - packet.sentlen = 0; - packet.offset = 0; - packet.len = 0; + outpkt.sentlen = 0; + outpkt.offset = 0; + outpkt.len = 0; } data[0] = userid; - data[1] = 0; + data[1] = ((downstream_seqno & 7) << 4) | (downstream_fragment & 15); data[2] = (rand_seed >> 8) & 0xff; data[3] = (rand_seed >> 0) & 0xff; @@ -722,7 +739,8 @@ main(int argc, char **argv) device = NULL; chunkid = 0; - packet.seqno = 0; + outpkt.seqno = 0; + inpkt.len = 0; b32 = get_base32_encoder(); dataenc = get_base32_encoder(); diff --git a/src/iodined.c b/src/iodined.c index 2dfc4bc..10c1a33 100644 --- a/src/iodined.c +++ b/src/iodined.c @@ -118,7 +118,7 @@ tunnel_tun(int tun_fd, int dns_fd) users[userid].outpacket.len = outlen; users[userid].outpacket.offset = 0; users[userid].outpacket.sentlen = 0; - users[userid].outpacket.seqno++; + users[userid].outpacket.seqno = (++users[userid].outpacket.seqno & 7); users[userid].outpacket.fragment = 0; return outlen; } else { @@ -162,46 +162,91 @@ static void send_chunk(int dns_fd, int userid) { char pkt[4096]; int datalen; + int last; - datalen = MIN(sizeof(pkt) - 2, users[userid].outpacket.len); - memcpy(&pkt[2], users[userid].outpacket.data, datalen); + /* TODO change this 1200b value to dynamic */ + datalen = MIN(1200, users[userid].outpacket.len - users[userid].outpacket.offset); + + if (datalen && users[userid].outpacket.sentlen > 0 && + ( + users[userid].outpacket.seqno != users[userid].out_acked_seqno || + users[userid].outpacket.fragment != users[userid].out_acked_fragment + ) + ) { + + /* Still waiting on latest ack, send nothing */ + datalen = 0; + last = 0; + /* TODO : count down and discard packet if no acks arrive within X queries */ + } else { + memcpy(&pkt[2], &users[userid].outpacket.data[users[userid].outpacket.offset], datalen); + users[userid].outpacket.sentlen = datalen; + last = (users[userid].outpacket.len == users[userid].outpacket.offset + users[userid].outpacket.sentlen); + + /* Increase fragment# when sending data with offset */ + if (users[userid].outpacket.offset && datalen) + users[userid].outpacket.fragment++; + } /* Build downstream data header (see doc/proto_xxxxxxxx.txt) */ /* First byte is 1 bit compression flag, 3 bits upstream seqno, 4 bits upstream fragment */ pkt[0] = (1<<7) | ((users[userid].inpacket.seqno & 7) << 4) | (users[userid].inpacket.fragment & 15); /* Second byte is 3 bits downstream seqno, 4 bits downstream fragment, 1 bit last flag */ - pkt[1] = ((users[userid].outpacket.seqno & 7) << 5) | ((users[userid].outpacket.fragment & 15) << 1) | 1; - + pkt[1] = ((users[userid].outpacket.seqno & 7) << 5) | + ((users[userid].outpacket.fragment & 15) << 1) | (last & 1); if (debug >= 1) { - printf("OUT pkt seq# %d, frag %d (last=%d), fragsize %d, total %d, to user %d\n", + printf("OUT pkt seq# %d, frag %d (last=%d), offset %d, fragsize %d, total %d, to user %d\n", users[userid].outpacket.seqno & 7, users[userid].outpacket.fragment & 15, - 1, users[userid].outpacket.len, datalen, userid); + last, users[userid].outpacket.offset, datalen, users[userid].outpacket.len, userid); } write_dns(dns_fd, &users[userid].q, pkt, datalen + 2); - users[userid].outpacket.len = 0; users[userid].q.id = 0; + + if (users[userid].outpacket.len > 0 && + users[userid].outpacket.len == users[userid].outpacket.sentlen) { + + /* Whole packet was sent in one chunk, dont wait for ack */ + users[userid].outpacket.len = 0; + users[userid].outpacket.offset = 0; + users[userid].outpacket.sentlen = 0; + } } static void update_downstream_seqno(int dns_fd, int userid, int down_seq, int down_frag) { - /* update outgoing seqno/frag */ - if (down_seq != users[userid].out_acked_seqno) { - /* First ack on new outgoing packet */ - users[userid].out_acked_seqno = down_seq; - users[userid].out_acked_fragment = down_frag; - } else { - if (down_frag > users[userid].out_acked_fragment) { - /* Ack on later fragment */ - users[userid].out_acked_fragment = down_frag; - } + /* If we just read a new packet from tun we have not sent a fragment of, just send it */ + if (users[userid].outpacket.len > 0 && users[userid].outpacket.sentlen == 0) { + send_chunk(dns_fd, userid); + return; } - /* Send reply if waiting */ - if (users[userid].outpacket.len > 0) { - send_chunk(dns_fd, userid); + /* otherwise, check if we received ack on a fragment and can send next */ + if (users[userid].outpacket.len > 0 && + users[userid].outpacket.seqno == down_seq && users[userid].outpacket.fragment == down_frag) { + + if (down_seq != users[userid].out_acked_seqno || down_frag != users[userid].out_acked_fragment) { + /* Received ACK on downstream fragment */ + users[userid].outpacket.offset += users[userid].outpacket.sentlen; + users[userid].outpacket.sentlen = 0; + + /* Is packet done? */ + if (users[userid].outpacket.offset == users[userid].outpacket.len) { + users[userid].outpacket.len = 0; + users[userid].outpacket.offset = 0; + users[userid].outpacket.sentlen = 0; + } + + users[userid].out_acked_seqno = down_seq; + users[userid].out_acked_fragment = down_frag; + + /* Send reply if waiting */ + if (users[userid].outpacket.len > 0) { + send_chunk(dns_fd, userid); + } + } } } @@ -344,6 +389,15 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len) write_dns(dns_fd, q, "BADIP", 5); return; /* illegal id */ } + + if (debug >= 1) { + printf("PING pkt from user %d\n", userid); + } + + if (users[userid].q.id != 0) { + /* Send reply on earlier query before overwriting */ + send_chunk(dns_fd, userid); + } dn_seq = unpacked[1] >> 4; dn_frag = unpacked[1] & 15; @@ -379,6 +433,11 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len) int dn_frag = b32_8to5(in[3]) >> 1; int lastfrag = b32_8to5(in[3]) & 1; + if (users[userid].q.id != 0) { + /* Send reply on earlier query before overwriting */ + send_chunk(dns_fd, userid); + } + /* Update query and time info for user */ users[userid].last_pkt = time(NULL); memcpy(&(users[userid].q), q, sizeof(struct query)); @@ -387,7 +446,7 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len) up_frag <= users[userid].inpacket.fragment) { /* Got repeated old packet, skip it */ if (debug >= 1) { - printf("IN pkt seq# %d, frag %d, dropped duplicate\n", + printf("IN pkt seq# %d, frag %d, dropped duplicate\n", up_seq, up_frag); } /* Update seqno and maybe send immediate response packet */ @@ -412,7 +471,7 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len) users[userid].inpacket.offset += read; if (debug >= 1) { - printf("IN pkt seq# %d, frag %d (last=%d), fragsize %d, total %d, from user %d\n", + printf("IN pkt seq# %d, frag %d (last=%d), fragsize %d, total %d, from user %d\n", up_seq, up_frag, lastfrag, read, users[userid].inpacket.len, userid); }