mirror of
https://github.com/yarrick/iodine.git
synced 2024-11-26 15:06:04 +03:00
Downstream fragmentation now working. Currently fragment size is hardcoded to 1200. More tweaking left, as well as fragsize auto detection. (#7)
This commit is contained in:
parent
78ae87ebc8
commit
23fad5b628
@ -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 = MIN(rlen, sizeof(rdata));
|
||||||
rv = readdata(packet, &data, rdata, rv);
|
rv = readdata(packet, &data, rdata, rv);
|
||||||
|
|
||||||
if(type == T_NULL && rv > 2 && buf) {
|
if(type == T_NULL && rv >= 2 && buf) {
|
||||||
rv = MIN(rv, buflen);
|
rv = MIN(rv, buflen);
|
||||||
memcpy(buf, rdata, rv);
|
memcpy(buf, rdata, rv);
|
||||||
}
|
}
|
||||||
|
92
src/iodine.c
92
src/iodine.c
@ -63,7 +63,8 @@ static int downstream_seqno;
|
|||||||
static int downstream_fragment;
|
static int downstream_fragment;
|
||||||
|
|
||||||
/* Current IP packet */
|
/* Current IP packet */
|
||||||
static struct packet packet;
|
static struct packet outpkt;
|
||||||
|
static struct packet inpkt;
|
||||||
|
|
||||||
/* My userid at the server */
|
/* My userid at the server */
|
||||||
static char userid;
|
static char userid;
|
||||||
@ -151,7 +152,7 @@ build_hostname(char *buf, size_t buflen,
|
|||||||
static int
|
static int
|
||||||
is_sending()
|
is_sending()
|
||||||
{
|
{
|
||||||
return (packet.len != 0);
|
return (outpkt.len != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -181,12 +182,12 @@ read_dns(int fd, char *buf, int buflen)
|
|||||||
|
|
||||||
if (is_sending() && chunkid == q.id) {
|
if (is_sending() && chunkid == q.id) {
|
||||||
/* Got ACK on sent packet */
|
/* Got ACK on sent packet */
|
||||||
packet.offset += packet.sentlen;
|
outpkt.offset += outpkt.sentlen;
|
||||||
if (packet.offset == packet.len) {
|
if (outpkt.offset == outpkt.len) {
|
||||||
/* Packet completed */
|
/* Packet completed */
|
||||||
packet.offset = 0;
|
outpkt.offset = 0;
|
||||||
packet.len = 0;
|
outpkt.len = 0;
|
||||||
packet.sentlen = 0;
|
outpkt.sentlen = 0;
|
||||||
} else {
|
} else {
|
||||||
/* More to send */
|
/* More to send */
|
||||||
send_chunk(fd);
|
send_chunk(fd);
|
||||||
@ -212,12 +213,12 @@ tunnel_tun(int tun_fd, int dns_fd)
|
|||||||
inlen = read;
|
inlen = read;
|
||||||
compress2((uint8_t*)out, &outlen, (uint8_t*)in, inlen, 9);
|
compress2((uint8_t*)out, &outlen, (uint8_t*)in, inlen, 9);
|
||||||
|
|
||||||
memcpy(packet.data, out, MIN(outlen, sizeof(packet.data)));
|
memcpy(outpkt.data, out, MIN(outlen, sizeof(outpkt.data)));
|
||||||
packet.sentlen = 0;
|
outpkt.sentlen = 0;
|
||||||
packet.offset = 0;
|
outpkt.offset = 0;
|
||||||
packet.len = outlen;
|
outpkt.len = outlen;
|
||||||
packet.seqno++;
|
outpkt.seqno++;
|
||||||
packet.fragment = 0;
|
outpkt.fragment = 0;
|
||||||
|
|
||||||
send_chunk(dns_fd);
|
send_chunk(dns_fd);
|
||||||
|
|
||||||
@ -227,24 +228,40 @@ tunnel_tun(int tun_fd, int dns_fd)
|
|||||||
static int
|
static int
|
||||||
tunnel_dns(int tun_fd, int dns_fd)
|
tunnel_dns(int tun_fd, int dns_fd)
|
||||||
{
|
{
|
||||||
unsigned long outlen;
|
unsigned long datalen;
|
||||||
unsigned long inlen;
|
char buf[64*1024];
|
||||||
char out[64*1024];
|
|
||||||
char in[64*1024];
|
|
||||||
size_t read;
|
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;
|
return -1;
|
||||||
|
|
||||||
outlen = sizeof(out);
|
if (downstream_seqno != inpkt.seqno) {
|
||||||
inlen = read;
|
/* New packet */
|
||||||
|
inpkt.seqno = downstream_seqno;
|
||||||
/* Skip 2 byte data header and uncompress */
|
inpkt.fragment = downstream_fragment;
|
||||||
if (uncompress((uint8_t*)out, &outlen, (uint8_t*) &in[2], inlen - 2) != Z_OK) {
|
inpkt.len = 0;
|
||||||
|
} else if (downstream_fragment <= inpkt.fragment) {
|
||||||
|
/* Duplicate fragment */
|
||||||
return -1;
|
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())
|
if (!is_sending())
|
||||||
send_ping(dns_fd);
|
send_ping(dns_fd);
|
||||||
|
|
||||||
@ -306,26 +323,26 @@ send_chunk(int fd)
|
|||||||
int code;
|
int code;
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
p = packet.data;
|
p = outpkt.data;
|
||||||
p += packet.offset;
|
p += outpkt.offset;
|
||||||
avail = packet.len - packet.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) */
|
/* Build upstream data header (see doc/proto_xxxxxxxx.txt) */
|
||||||
|
|
||||||
buf[0] = hex[userid & 15]; /* First byte is 4 bits userid */
|
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 */
|
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 */
|
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 */
|
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);
|
send_query(fd, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -352,13 +369,13 @@ send_ping(int fd)
|
|||||||
char data[4];
|
char data[4];
|
||||||
|
|
||||||
if (is_sending()) {
|
if (is_sending()) {
|
||||||
packet.sentlen = 0;
|
outpkt.sentlen = 0;
|
||||||
packet.offset = 0;
|
outpkt.offset = 0;
|
||||||
packet.len = 0;
|
outpkt.len = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
data[0] = userid;
|
data[0] = userid;
|
||||||
data[1] = 0;
|
data[1] = ((downstream_seqno & 7) << 4) | (downstream_fragment & 15);
|
||||||
data[2] = (rand_seed >> 8) & 0xff;
|
data[2] = (rand_seed >> 8) & 0xff;
|
||||||
data[3] = (rand_seed >> 0) & 0xff;
|
data[3] = (rand_seed >> 0) & 0xff;
|
||||||
|
|
||||||
@ -722,7 +739,8 @@ main(int argc, char **argv)
|
|||||||
device = NULL;
|
device = NULL;
|
||||||
chunkid = 0;
|
chunkid = 0;
|
||||||
|
|
||||||
packet.seqno = 0;
|
outpkt.seqno = 0;
|
||||||
|
inpkt.len = 0;
|
||||||
|
|
||||||
b32 = get_base32_encoder();
|
b32 = get_base32_encoder();
|
||||||
dataenc = get_base32_encoder();
|
dataenc = get_base32_encoder();
|
||||||
|
@ -118,7 +118,7 @@ tunnel_tun(int tun_fd, int dns_fd)
|
|||||||
users[userid].outpacket.len = outlen;
|
users[userid].outpacket.len = outlen;
|
||||||
users[userid].outpacket.offset = 0;
|
users[userid].outpacket.offset = 0;
|
||||||
users[userid].outpacket.sentlen = 0;
|
users[userid].outpacket.sentlen = 0;
|
||||||
users[userid].outpacket.seqno++;
|
users[userid].outpacket.seqno = (++users[userid].outpacket.seqno & 7);
|
||||||
users[userid].outpacket.fragment = 0;
|
users[userid].outpacket.fragment = 0;
|
||||||
return outlen;
|
return outlen;
|
||||||
} else {
|
} else {
|
||||||
@ -162,48 +162,93 @@ static void
|
|||||||
send_chunk(int dns_fd, int userid) {
|
send_chunk(int dns_fd, int userid) {
|
||||||
char pkt[4096];
|
char pkt[4096];
|
||||||
int datalen;
|
int datalen;
|
||||||
|
int last;
|
||||||
|
|
||||||
datalen = MIN(sizeof(pkt) - 2, users[userid].outpacket.len);
|
/* TODO change this 1200b value to dynamic */
|
||||||
memcpy(&pkt[2], users[userid].outpacket.data, datalen);
|
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) */
|
/* Build downstream data header (see doc/proto_xxxxxxxx.txt) */
|
||||||
|
|
||||||
/* First byte is 1 bit compression flag, 3 bits upstream seqno, 4 bits upstream fragment */
|
/* 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);
|
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 */
|
/* 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) {
|
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,
|
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);
|
write_dns(dns_fd, &users[userid].q, pkt, datalen + 2);
|
||||||
users[userid].outpacket.len = 0;
|
|
||||||
users[userid].q.id = 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
|
static void
|
||||||
update_downstream_seqno(int dns_fd, int userid, int down_seq, int down_frag)
|
update_downstream_seqno(int dns_fd, int userid, int down_seq, int down_frag)
|
||||||
{
|
{
|
||||||
/* update outgoing seqno/frag */
|
/* If we just read a new packet from tun we have not sent a fragment of, just send it */
|
||||||
if (down_seq != users[userid].out_acked_seqno) {
|
if (users[userid].outpacket.len > 0 && users[userid].outpacket.sentlen == 0) {
|
||||||
/* First ack on new outgoing packet */
|
send_chunk(dns_fd, userid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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_seqno = down_seq;
|
||||||
users[userid].out_acked_fragment = down_frag;
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Send reply if waiting */
|
/* Send reply if waiting */
|
||||||
if (users[userid].outpacket.len > 0) {
|
if (users[userid].outpacket.len > 0) {
|
||||||
send_chunk(dns_fd, userid);
|
send_chunk(dns_fd, userid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
|
handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
|
||||||
@ -345,6 +390,15 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
|
|||||||
return; /* illegal id */
|
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_seq = unpacked[1] >> 4;
|
||||||
dn_frag = unpacked[1] & 15;
|
dn_frag = unpacked[1] & 15;
|
||||||
memcpy(&(users[userid].q), q, sizeof(struct query));
|
memcpy(&(users[userid].q), q, sizeof(struct query));
|
||||||
@ -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 dn_frag = b32_8to5(in[3]) >> 1;
|
||||||
int lastfrag = 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 */
|
/* Update query and time info for user */
|
||||||
users[userid].last_pkt = time(NULL);
|
users[userid].last_pkt = time(NULL);
|
||||||
memcpy(&(users[userid].q), q, sizeof(struct query));
|
memcpy(&(users[userid].q), q, sizeof(struct query));
|
||||||
|
Loading…
Reference in New Issue
Block a user