diff --git a/src/client.c b/src/client.c index 46a87ca..fc84c6d 100644 --- a/src/client.c +++ b/src/client.c @@ -94,8 +94,9 @@ static time_t max_timeout_ms; static time_t send_interval_ms; static time_t min_send_interval_ms; -/* Server response timeout in ms */ +/* Server response timeout in ms and downstream window timeout */ static time_t server_timeout_ms; +static time_t downstream_timeout_ms; static int autodetect_server_timeout; /* Cumulative Round-Trip-Time in ms */ @@ -185,6 +186,7 @@ client_init() rtt_total_ms = 1000; send_interval_ms = 1000; min_send_interval_ms = 1; + downstream_timeout_ms = 5000; outbuf = NULL; inbuf = NULL; @@ -282,10 +284,11 @@ client_set_compression(int up, int down) } void -client_set_dnstimeout(double timeout, double servertimeout, int autodetect) +client_set_dnstimeout(double timeout, double servertimeout, double downfrag, int autodetect) { max_timeout_ms = timeout * 1000; server_timeout_ms = servertimeout * 1000; + downstream_timeout_ms = downfrag * 1000; autodetect_server_timeout = autodetect; } @@ -385,11 +388,13 @@ update_server_timeout(int dns_fd, int handshake) server_timeout_ms = max_timeout_ms - rtt_ms; if (server_timeout_ms <= 0) { server_timeout_ms = 0; - fprintf(stderr, "Setting server timeout to 0 ms: if this continues try disabling lazy mode.\n"); + fprintf(stderr, "Setting server timeout to 0 ms: if this continues try disabling lazy mode. (-L0)\n"); } } - /* TODO: update window timeout */ + /* update up/down window timeouts to something reasonable */ + downstream_timeout_ms = rtt_ms * 2; + outbuf->timeout = ms_to_timeval(downstream_timeout_ms); if (handshake) { /* Send ping handshake to set server timeout */ @@ -626,7 +631,7 @@ send_packet(int fd, char cmd, const uint8_t *data, const size_t datalen) } int -send_ping(int fd, int ping_response, int ack, int timeout) +send_ping(int fd, int ping_response, int ack, int set_timeout) { num_pings++; if (conn == CONN_DNS_NULL) { @@ -645,15 +650,17 @@ send_ping(int fd, int ping_response, int ack, int timeout) } *(uint16_t *) (data + 6) = htons(server_timeout_ms); + *(uint16_t *) (data + 8) = htons(downstream_timeout_ms); - /* update server lazy timeout, ack flag, respond with ping flag */ - data[8] = ((timeout & 1) << 3) | ((ack < 0 ? 0 : 1) << 2) | (ping_response & 1); - data[9] = (rand_seed >> 8) & 0xff; - data[10] = (rand_seed >> 0) & 0xff; + /* update server frag/lazy timeout, ack flag, respond with ping flag */ + data[10] = ((set_timeout & 1) << 4) | ((set_timeout & 1) << 3) | ((ack < 0 ? 0 : 1) << 2) | (ping_response & 1); + data[11] = (rand_seed >> 8) & 0xff; + data[12] = (rand_seed >> 0) & 0xff; rand_seed += 263; - DEBUG(3, " SEND PING: respond %d, ack %d, server timeout %ld, flags %02X", - ping_response, ack, server_timeout_ms, data[8]); + DEBUG(3, " SEND PING: respond %d, ack %d, %s(server %ld ms, downfrag %ld ms), flags %02X", + ping_response, ack, set_timeout ? "SET " : "", server_timeout_ms, + downstream_timeout_ms, data[8]); id = send_packet(fd, 'p', data, sizeof(data)); @@ -1014,7 +1021,7 @@ handshake_waitdns(int dns_fd, char *buf, size_t buflen, char cmd, int timeout) if (r == 0) return -3; /* select timeout */ - q.id = 0; + q.id = -1; q.name[0] = '\0'; rv = read_dns_withq(dns_fd, 0, (uint8_t *)buf, buflen, &q); @@ -1373,6 +1380,7 @@ client_tunnel(int tun_fd, int dns_fd) if (sending > 0 || (total > 0 && lazymode)) { tv = ms_to_timeval(min_send_interval_ms); + tv.tv_usec += 1; } else if (total > 0 && !lazymode) { /* use immediate mode send interval if nothing pending */ tv = ms_to_timeval(send_interval_ms); @@ -1392,12 +1400,12 @@ client_tunnel(int tun_fd, int dns_fd) num_recv - recv_since_report, (num_recv - recv_since_report) / stats); fprintf(stderr, " num IP rejected: %4lu, untracked: %4lu, lazy mode: %1d\n", num_badip, num_untracked, lazymode); - fprintf(stderr, " Min send: %4ld ms, Avg RTT: %4ld ms, immediate replies: %5lu\n", - min_send_interval_ms, rtt_total_ms / num_immediate, num_immediate); - fprintf(stderr, " query timeouts: %4lu, target: %4ld ms, server: %4ld ms\n", - num_timeouts, max_timeout_ms, server_timeout_ms); - fprintf(stderr, " Resent fragments up: %4u, downstream out of window: %4u\n", - outbuf->resends, inbuf->oos); + fprintf(stderr, " Min send: %5ld ms, Avg RTT: %5ld ms Timeout server: %4ld ms\n", + min_send_interval_ms, rtt_total_ms / num_immediate, server_timeout_ms); + fprintf(stderr, " Queries immediate: %5lu, timed out: %4lu target: %4ld ms\n", + num_immediate, num_timeouts, max_timeout_ms); + fprintf(stderr, " Frags resent: %4u, OOS: %4u down frag: %4ld ms\n", + outbuf->resends, inbuf->oos, downstream_timeout_ms); fprintf(stderr, " TX fragments: %8lu" ", RX: %8lu" ", pings: %8lu" "\n\n", num_frags_sent, num_frags_recv, num_pings); @@ -1568,8 +1576,8 @@ send_upenctest(int fd, char *s) buf[3] = b32_5to8((rand_seed ) & 0x1f); rand_seed++; - strncat(buf, s, 512); - strncat(buf, ".", 512); + strncat(buf, s, 512 - strlen(buf)); + strncat(buf, ".", 512 - strlen(buf)); strncat(buf, topdomain, 512 - strlen(buf)); send_query(fd, (uint8_t *)buf); } @@ -2573,6 +2581,7 @@ handshake_set_timeout(int dns_fd) read = handshake_waitdns(dns_fd, in, sizeof(in), 'P', i + 1); got_response(id, 1, 0); + fprintf(stderr, "."); if (read > 0) { if (strncmp("BADIP", in, 5) == 0) { fprintf(stderr, "Server rejected sender IP address.\n"); @@ -2583,7 +2592,6 @@ handshake_set_timeout(int dns_fd) break; } - fprintf(stderr, "."); } if (!running) return; diff --git a/src/client.h b/src/client.h index 198b150..92d4983 100644 --- a/src/client.h +++ b/src/client.h @@ -44,7 +44,7 @@ int client_set_qtype(char *qtype); char *client_get_qtype(); void client_set_downenc(char *encoding); void client_set_compression(int up, int down); -void client_set_dnstimeout(double, double, int); +void client_set_dnstimeout(double, double, double, int); void client_set_lazymode(int lazy_mode); void client_set_windowsize(size_t, size_t); void client_set_hostname_maxlen(size_t i); diff --git a/src/iodine.c b/src/iodine.c index 76090d2..a7b96b3 100644 --- a/src/iodine.c +++ b/src/iodine.c @@ -70,7 +70,7 @@ print_usage() extern char *__progname; fprintf(stderr, "Usage: %s [-v] [-h] [-V sec] [-f] [-r] [-u user] [-t chrootdir] [-d device] " - "[-w downfrags] [-W upfrags] [-i sec] [-I sec] [-c 0|1] [-C 0|1] [-s ms] " + "[-w downfrags] [-W upfrags] [-i sec -j sec] [-I sec] [-c 0|1] [-C 0|1] [-s ms] " "[-P password] [-m maxfragsize] [-M maxlen] [-T type] [-O enc] [-L 0|1] " "[-z context] [-F pidfile] topdomain [nameserver1 [nameserver2 [nameserverN ...]]]\n", __progname); } @@ -93,7 +93,7 @@ help() fprintf(stderr, " Base128, or (only for TXT:) Raw (default: autodetect)\n"); fprintf(stderr, " -I target interval between sending and receiving requests (default: 4 secs)\n"); fprintf(stderr, " or ping interval in immediate mode (default: 1 sec)\n"); - fprintf(stderr, " -s minimum interval between queries (default: 1ms)\n"); + fprintf(stderr, " -s minimum interval between queries (default: 0ms)\n"); fprintf(stderr, " -L 1: use lazy mode for low-latency (default). 0: don't (implies -I1)\n"); fprintf(stderr, " -m max size of downstream fragments (default: autodetect)\n"); fprintf(stderr, " -M max size of upstream hostnames (~100-255, default: 255)\n"); @@ -101,11 +101,12 @@ help() fprintf(stderr, " -P password used for authentication (max 32 chars will be used)\n\n"); fprintf(stderr, "Fine-tuning options:\n"); - fprintf(stderr, " -w downstream fragment window size (default: 8)\n"); - fprintf(stderr, " -W upstream fragment window size (default: 8)\n"); + fprintf(stderr, " -w downstream fragment window size (default: 8 frags)\n"); + fprintf(stderr, " -W upstream fragment window size (default: 8 frags)\n"); fprintf(stderr, " -i server-side request timeout in lazy mode (default: auto)\n"); + fprintf(stderr, " -j downstream fragment ACK timeout, implies -i4 (default: 2 sec)\n"); fprintf(stderr, " -c 1: use downstream compression (default), 0: disable\n"); - fprintf(stderr, " -C 1: use upstream compression, 0: disable (default)\n\n"); + fprintf(stderr, " -C 1: use upstream compression (default), 0: disable\n\n"); fprintf(stderr, "Other options:\n"); fprintf(stderr, " -v to print version info and exit\n"); @@ -162,6 +163,7 @@ main(int argc, char **argv) int lazymode; double target_interval_sec; double server_timeout_sec; + double downstream_timeout_sec; int min_interval_ms; int autodetect_server_timeout; int up_compression; @@ -183,6 +185,7 @@ main(int argc, char **argv) int nameservaddr_len; int nameserv_family; + /* Set default values */ nameserv_addrs_len = 0; nameservaddr_len = 0; nameserv_host = NULL; @@ -208,12 +211,13 @@ main(int argc, char **argv) raw_mode = 1; lazymode = 1; target_interval_sec = 5; /* DNS RFC says 5 seconds minimum */ - min_interval_ms = 1; + min_interval_ms = 0; server_timeout_sec = 4; /* Safe value for RTT <1s */ + downstream_timeout_sec = 2; autodetect_server_timeout = 1; hostname_maxlen = 0xFF; nameserv_family = AF_UNSPEC; - up_compression = 0; + up_compression = 1; down_compression = 1; up_windowsize = 8; @@ -234,7 +238,7 @@ main(int argc, char **argv) __progname++; #endif - while ((choice = getopt(argc, argv, "46vfDhrs:V:c:C:i:u:t:d:R:P:w:W:m:M:F:T:O:L:I:")) != -1) { + while ((choice = getopt(argc, argv, "46vfDhrs:V:c:C:i:j:u:t:d:R:P:w:W:m:M:F:T:O:L:I:")) != -1) { switch(choice) { case '4': nameserv_family = AF_INET; @@ -315,24 +319,25 @@ main(int argc, char **argv) lazymode = 1; if (lazymode < 0) lazymode = 0; - if (!lazymode && target_interval_sec > 1) - target_interval_sec = 1; break; case 'I': target_interval_sec = strtod(optarg, NULL); - if (target_interval_sec < 1) - target_interval_sec = 1; break; case 'i': server_timeout_sec = strtod(optarg, NULL); - if (server_timeout_sec < 0.4) - server_timeout_sec = 0.4; autodetect_server_timeout = 0; break; + case 'j': + downstream_timeout_sec = strtod(optarg, NULL); + if (autodetect_server_timeout) { + autodetect_server_timeout = 0; + server_timeout_sec = 4; + } + break; case 's': min_interval_ms = atoi(optarg); - if (min_interval_ms < 1) - min_interval_ms = 1; + if (min_interval_ms < 0) + min_interval_ms = 0; case 'w': down_windowsize = atoi(optarg); break; @@ -418,8 +423,28 @@ main(int argc, char **argv) usage(); } + if (target_interval_sec < 0.1) { + warnx("Target interval must be greater than 0.1 seconds!"); + usage(); + } + + if (server_timeout_sec < 0.1 || server_timeout_sec >= target_interval_sec) { + warnx("Server timeout must be greater than 0.1 sec and less than target interval!"); + usage(); + } + + if (downstream_timeout_sec < 0.1) { + warnx("Downstream fragment timeout must be more than 0.1 sec to prevent excessive retransmits."); + usage(); + } + + if (!lazymode && target_interval_sec > 1) { + warnx("Warning: Target interval of >1 second in immediate mode will cause high latency."); + usage(); + } + client_set_compression(up_compression, down_compression); - client_set_dnstimeout(target_interval_sec, server_timeout_sec, autodetect_server_timeout); + client_set_dnstimeout(target_interval_sec, server_timeout_sec, downstream_timeout_sec, autodetect_server_timeout); client_set_interval(target_interval_sec * 1000.0, min_interval_ms); client_set_lazymode(lazymode); client_set_topdomain(topdomain);