From 7068bcc08d3c08ccf14fe6ce8e952e60ab69dd52 Mon Sep 17 00:00:00 2001 From: frekky Date: Sat, 9 Jan 2016 19:29:17 +0800 Subject: [PATCH] Added command line option presets (--preset or -Y) Fixed some refactoring issues and passing this.* as arguments --- src/client.c | 282 +++++++++++++++++++++++++-------------------------- src/client.h | 10 +- src/iodine.c | 161 ++++++++++++++++++++++------- 3 files changed, 268 insertions(+), 185 deletions(-) diff --git a/src/client.c b/src/client.c index 8d33409..e9c661c 100644 --- a/src/client.c +++ b/src/client.c @@ -162,7 +162,7 @@ immediate_mode_defaults() #endif static int -update_server_timeout(int dns_fd, int handshake) +update_server_timeout(int handshake) /* Calculate server timeout based on average RTT, send ping "handshake" to set * if handshake sent, return query ID */ { @@ -201,7 +201,7 @@ update_server_timeout(int dns_fd, int handshake) if (handshake) { /* Send ping handshake to set server timeout */ - return send_ping(dns_fd, 1, -1, 1); + return send_ping(1, -1, 1); } return -1; } @@ -309,7 +309,7 @@ got_response(int id, int immediate, int fail) this.num_immediate++; if (this.autodetect_server_timeout) - update_server_timeout(-1, 0); + update_server_timeout(0); } /* Remove query info from buffer to mark it as answered */ @@ -326,7 +326,7 @@ got_response(int id, int immediate, int fail) } static int -send_query(int fd, uint8_t *hostname) +send_query(uint8_t *hostname) /* Returns DNS ID of sent query */ { uint8_t packet[4096]; @@ -351,7 +351,7 @@ send_query(int fd, uint8_t *hostname) DEBUG(4, " Sendquery: id %5d name[0] '%c'", q.id, hostname[0]); - sendto(fd, packet, len, 0, (struct sockaddr*) &this.nameserv_addrs[this.current_nameserver], + sendto(this.dns_fd, packet, len, 0, (struct sockaddr*) &this.nameserv_addrs[this.current_nameserver], sizeof(struct sockaddr_storage)); client_rotate_nameserver(); @@ -391,14 +391,14 @@ send_query(int fd, uint8_t *hostname) this.lazymode = 0; this.server_timeout_ms = 0; } - update_server_timeout(fd, 1); + update_server_timeout(1); } } return q.id; } static void -send_raw(int fd, uint8_t *buf, size_t buflen, int user, int cmd) +send_raw(uint8_t *buf, size_t buflen, int cmd) { char packet[4096]; int len; @@ -411,20 +411,20 @@ send_raw(int fd, uint8_t *buf, size_t buflen, int user, int cmd) } len += RAW_HDR_LEN; - packet[RAW_HDR_CMD] = (cmd & 0xF0) | (user & 0x0F); + packet[RAW_HDR_CMD] = (cmd & 0xF0) | (this.userid & 0x0F); - sendto(fd, packet, len, 0, (struct sockaddr*)&this.raw_serv, sizeof(this.raw_serv)); + sendto(this.dns_fd, packet, len, 0, (struct sockaddr*)&this.raw_serv, sizeof(this.raw_serv)); } static void -send_raw_data(int dns_fd, uint8_t *data, size_t datalen) +send_raw_data(uint8_t *data, size_t datalen) { - send_raw(dns_fd, data, datalen, this.userid, RAW_HDR_CMD_DATA); + send_raw(data, datalen, RAW_HDR_CMD_DATA); } static int -send_packet(int fd, char cmd, const uint8_t *data, const size_t datalen) +send_packet(char cmd, const uint8_t *data, const size_t datalen) /* Base32 encodes data and sends as single DNS query * Returns ID of sent query */ { @@ -434,11 +434,11 @@ send_packet(int fd, char cmd, const uint8_t *data, const size_t datalen) build_hostname(buf, sizeof(buf), data, datalen, this.topdomain, b32, this.hostname_maxlen, 1); - return send_query(fd, buf); + return send_query(buf); } int -send_ping(int fd, int ping_response, int ack, int set_timeout) +send_ping(int ping_response, int ack, int set_timeout) { this.num_pings++; if (this.conn == CONN_DNS_NULL) { @@ -469,19 +469,19 @@ send_ping(int fd, int ping_response, int ack, int set_timeout) ping_response, ack, set_timeout ? "SET " : "", this.server_timeout_ms, this.downstream_timeout_ms, data[8]); - id = send_packet(fd, 'p', data, sizeof(data)); + id = send_packet('p', data, sizeof(data)); /* Log query ID as being sent now */ query_sent_now(id); return id; } else { - send_raw(fd, NULL, 0, this.userid, RAW_HDR_CMD_PING); + send_raw(NULL, 0, RAW_HDR_CMD_PING); return -1; } } static void -send_next_frag(int fd) +send_next_frag() /* Sends next available fragment of data from the outgoing window buffer */ { static uint8_t buf[MAX_FRAGSIZE], hdr[5]; @@ -497,7 +497,7 @@ send_next_frag(int fd) if (this.outbuf->numitems > 0) { /* There is stuff to send but we're out of sync, so send a ping * to get things back in order and keep the packets flowing */ - send_ping(fd, 1, this.next_downstream_ack, 1); + send_ping(1, this.next_downstream_ack, 1); this.next_downstream_ack = -1; window_tick(this.outbuf); } @@ -532,7 +532,7 @@ send_next_frag(int fd) DEBUG(3, " SEND DATA: seq %d, ack %d, len %lu, s%d e%d c%d flags %1X", f->seqID, f->ack_other, f->len, f->start, f->end, f->compressed, hdr[2] >> 4); - id = send_query(fd, buf); + id = send_query(buf); /* Log query ID as being sent now */ query_sent_now(id); @@ -684,7 +684,7 @@ dns_namedec(uint8_t *outdata, size_t outdatalen, uint8_t *buf, size_t buflen) } static int -read_dns_withq(int dns_fd, int tun_fd, uint8_t *buf, size_t buflen, struct query *q) +read_dns_withq(uint8_t *buf, size_t buflen, struct query *q) /* Returns -1 on receive error or decode error, including DNS error replies. Returns 0 on replies that could be correct but are useless, and are not DNS error replies. @@ -697,7 +697,7 @@ read_dns_withq(int dns_fd, int tun_fd, uint8_t *buf, size_t buflen, struct query int r; addrlen = sizeof(from); - if ((r = recvfrom(dns_fd, data, sizeof(data), 0, + if ((r = recvfrom(this.dns_fd, data, sizeof(data), 0, (struct sockaddr*)&from, &addrlen)) < 0) { warn("recvfrom"); return -1; @@ -787,7 +787,7 @@ read_dns_withq(int dns_fd, int tun_fd, uint8_t *buf, size_t buflen, struct query r -= RAW_HDR_LEN; datalen = sizeof(buf); if (uncompress(buf, &datalen, data + RAW_HDR_LEN, r) == Z_OK) { - write_tun(tun_fd, buf, datalen); + write_tun(this.tun_fd, buf, datalen); } /* all done */ @@ -796,7 +796,7 @@ read_dns_withq(int dns_fd, int tun_fd, uint8_t *buf, size_t buflen, struct query } int -handshake_waitdns(int dns_fd, char *buf, size_t buflen, char cmd, int timeout) +handshake_waitdns(char *buf, size_t buflen, char cmd, int timeout) /* Wait for DNS reply fitting to our latest query and returns it. Returns length of reply = #bytes used in buf. Returns 0 if fitting reply happens to be useless. @@ -821,8 +821,8 @@ handshake_waitdns(int dns_fd, char *buf, size_t buflen, char cmd, int timeout) tv.tv_sec = timeout; tv.tv_usec = 0; FD_ZERO(&fds); - FD_SET(dns_fd, &fds); - r = select(dns_fd + 1, &fds, NULL, NULL, &tv); + FD_SET(this.dns_fd, &fds); + r = select(this.dns_fd + 1, &fds, NULL, NULL, &tv); if (r < 0) return -1; /* select error */ @@ -831,7 +831,7 @@ handshake_waitdns(int dns_fd, char *buf, size_t buflen, char cmd, int timeout) q.id = -1; q.name[0] = '\0'; - rv = read_dns_withq(dns_fd, 0, (uint8_t *)buf, buflen, &q); + rv = read_dns_withq((uint8_t *)buf, buflen, &q); qcmd = toupper(q.name[0]); if (q.id != this.chunkid || qcmd != cmd) { @@ -920,7 +920,7 @@ parse_data(uint8_t *data, size_t len, fragment *f, int *immediate) } static int -tunnel_tun(int tun_fd, int dns_fd) +tunnel_tun() { size_t datalen; uint8_t out[64*1024]; @@ -928,7 +928,7 @@ tunnel_tun(int tun_fd, int dns_fd) uint8_t *data; ssize_t read; - if ((read = read_tun(tun_fd, in, sizeof(in))) <= 0) + if ((read = read_tun(this.tun_fd, in, sizeof(in))) <= 0) return -1; DEBUG(2, " IN: %lu bytes on tunnel, to be compressed: %d", read, this.compression_up); @@ -953,14 +953,14 @@ tunnel_tun(int tun_fd, int dns_fd) window_add_outgoing_data(this.outbuf, data, datalen, this.compression_up); /* Don't send anything here to respect min. send interval */ } else { - send_raw_data(dns_fd, data, datalen); + send_raw_data(data, datalen); } return read; } static int -tunnel_dns(int tun_fd, int dns_fd) +tunnel_dns() { struct query q; size_t datalen, buflen; @@ -971,7 +971,7 @@ tunnel_dns(int tun_fd, int dns_fd) memset(&q, 0, sizeof(q)); memset(buf, 0, sizeof(buf)); memset(cbuf, 0, sizeof(cbuf)); - read = read_dns_withq(dns_fd, tun_fd, cbuf, sizeof(cbuf), &q); + read = read_dns_withq(cbuf, sizeof(cbuf), &q); if (this.conn != CONN_DNS_NULL) return 1; /* everything already done */ @@ -1016,7 +1016,7 @@ tunnel_dns(int tun_fd, int dns_fd) /* Reset query counts this.stats */ this.send_query_sendcnt = 0; this.send_query_recvcnt = 0; - update_server_timeout(dns_fd, 1); + update_server_timeout(1); } else if (this.send_query_recvcnt < 500 && this.num_servfail >= 40 && this.autodetect_server_timeout && this.max_timeout_ms < 500) { @@ -1024,7 +1024,7 @@ tunnel_dns(int tun_fd, int dns_fd) /* last-ditch attempt to fix SERVFAILs - disable lazy mode */ immediate_mode_defaults(); fprintf(stderr, "Attempting to disable lazy mode due to excessive SERVFAILs\n"); - handshake_switch_options(dns_fd, 0, this.compression_down, this.downenc); + handshake_switch_options(0, this.compression_down, this.downenc); } } } @@ -1111,7 +1111,7 @@ tunnel_dns(int tun_fd, int dns_fd) } if (datalen) - write_tun(tun_fd, data, datalen); + write_tun(this.tun_fd, data, datalen); } /* Move window along after doing all data processing */ @@ -1121,7 +1121,7 @@ tunnel_dns(int tun_fd, int dns_fd) } int -client_tunnel(int tun_fd, int dns_fd) +client_tunnel() { struct timeval tv, nextresend, tmp, now, now2; fd_set fds; @@ -1180,10 +1180,10 @@ client_tunnel(int tun_fd, int dns_fd) if (sending > 0) { /* More to send - next fragment */ - send_next_frag(dns_fd); + send_next_frag(); } else { /* Send ping if we didn't send anything yet */ - send_ping(dns_fd, 0, this.next_downstream_ack, (this.num_pings > 20 && this.num_pings % 50 == 0)); + send_ping(0, this.next_downstream_ack, (this.num_pings > 20 && this.num_pings % 50 == 0)); this.next_downstream_ack = -1; } @@ -1255,9 +1255,9 @@ client_tunnel(int tun_fd, int dns_fd) if (this.conn != CONN_DNS_NULL || window_buffer_available(this.outbuf) > 16) { /* Fill up outgoing buffer with available data if it has enough space * The windowing protocol manages data retransmits, timeouts etc. */ - FD_SET(tun_fd, &fds); + FD_SET(this.tun_fd, &fds); } - FD_SET(dns_fd, &fds); + FD_SET(this.dns_fd, &fds); DEBUG(4, "Waiting %ld ms before sending more... (min_send %d)", timeval_to_ms(&tv), use_min_send); @@ -1265,7 +1265,7 @@ client_tunnel(int tun_fd, int dns_fd) gettimeofday(&now, NULL); } - i = select(MAX(tun_fd, dns_fd) + 1, &fds, NULL, NULL, &tv); + i = select(MAX(this.tun_fd, this.dns_fd) + 1, &fds, NULL, NULL, &tv); if (use_min_send && i > 0) { /* enforce min_send_interval if we get interrupted by new tun data */ @@ -1291,8 +1291,8 @@ client_tunnel(int tun_fd, int dns_fd) if (i == 0) { /* timed out - no new packets recv'd */ } else { - if (FD_ISSET(tun_fd, &fds)) { - if (tunnel_tun(tun_fd, dns_fd) <= 0) + if (FD_ISSET(this.tun_fd, &fds)) { + if (tunnel_tun() <= 0) continue; /* Returns -1 on error OR when quickly dropping data in case of DNS congestion; @@ -1300,8 +1300,8 @@ client_tunnel(int tun_fd, int dns_fd) If chunk sent, sets this.send_ping_soon=0. */ } - if (FD_ISSET(dns_fd, &fds)) { - tunnel_dns(tun_fd, dns_fd); + if (FD_ISSET(this.dns_fd, &fds)) { + tunnel_dns(); } } } @@ -1310,7 +1310,7 @@ client_tunnel(int tun_fd, int dns_fd) } static void -send_login(int fd, char *login, int len) +send_login(char *login, int len) { uint8_t data[19]; @@ -1323,11 +1323,11 @@ send_login(int fd, char *login, int len) this.rand_seed++; - send_packet(fd, 'l', data, sizeof(data)); + send_packet('l', data, sizeof(data)); } static void -send_fragsize_probe(int fd, uint16_t fragsize) +send_fragsize_probe(uint16_t fragsize) { uint8_t probedata[256]; uint8_t buf[MAX_FRAGSIZE]; @@ -1350,11 +1350,11 @@ send_fragsize_probe(int fd, uint16_t fragsize) build_hostname(buf, sizeof(buf), probedata, sizeof(probedata), this.topdomain, this.dataenc, this.hostname_maxlen, 6); - send_query(fd, buf); + send_query(buf); } static void -send_set_downstream_fragsize(int fd, uint16_t fragsize) +send_set_downstream_fragsize(uint16_t fragsize) { uint8_t data[5]; @@ -1365,11 +1365,11 @@ send_set_downstream_fragsize(int fd, uint16_t fragsize) this.rand_seed++; - send_packet(fd, 'n', data, sizeof(data)); + send_packet('n', data, sizeof(data)); } static void -send_version(int fd, uint32_t version) +send_version(uint32_t version) { uint8_t data[6]; @@ -1381,11 +1381,11 @@ send_version(int fd, uint32_t version) this.rand_seed++; - send_packet(fd, 'v', data, sizeof(data)); + send_packet('v', data, sizeof(data)); } static void -send_ip_request(int fd, int userid) +send_ip_request() { uint8_t buf[512] = "i____."; buf[1] = b32_5to8(this.userid); @@ -1396,20 +1396,20 @@ send_ip_request(int fd, int userid) this.rand_seed++; strncat((char *)buf, this.topdomain, 512 - strlen((char *)buf)); - send_query(fd, buf); + send_query(buf); } static void -send_raw_udp_login(int dns_fd, int userid, int seed) +send_raw_udp_login(int seed) { char buf[16]; login_calculate(buf, 16, this.password, seed + 1); - send_raw(dns_fd, (uint8_t *) buf, sizeof(buf), this.userid, RAW_HDR_CMD_LOGIN); + send_raw((uint8_t *) buf, sizeof(buf), RAW_HDR_CMD_LOGIN); } static void -send_upenctest(int fd, char *s) +send_upenctest(char *s) /* NOTE: String may be at most 63-4=59 chars to fit in 1 dns chunk. */ { char buf[512] = "z___"; @@ -1422,16 +1422,16 @@ send_upenctest(int fd, char *s) strncat(buf, s, 512 - strlen(buf)); strncat(buf, ".", 512 - strlen(buf)); strncat(buf, this.topdomain, 512 - strlen(buf)); - send_query(fd, (uint8_t *)buf); + send_query((uint8_t *)buf); } static void -send_downenctest(int fd, char downenc, int variant, char *s, int slen) +send_downenctest(char downenc, int variant, char *s, int slen) /* Note: content/handling of s is not defined yet. */ { char buf[512] = "y_____."; - buf[1] = tolower(this.downenc); + buf[1] = tolower(downenc); buf[2] = b32_5to8(variant); buf[3] = b32_5to8((this.rand_seed >> 10) & 0x1f); @@ -1440,11 +1440,11 @@ send_downenctest(int fd, char downenc, int variant, char *s, int slen) this.rand_seed++; strncat(buf, this.topdomain, 512 - strlen(buf)); - send_query(fd, (uint8_t *)buf); + send_query((uint8_t *)buf); } static void -send_codec_switch(int fd, int userid, int bits) +send_codec_switch(int bits) { char buf[512] = "s_____."; buf[1] = b32_5to8(this.userid); @@ -1456,11 +1456,11 @@ send_codec_switch(int fd, int userid, int bits) this.rand_seed++; strncat(buf, this.topdomain, 512 - strlen(buf)); - send_query(fd, (uint8_t *)buf); + send_query((uint8_t *)buf); } static void -send_server_options(int fd, int userid, int lazy, int compression, char denc, char *options) +send_server_options(int lazy, int compression, char denc, char *options) /* Options must be length >=4 */ { char buf[512] = "oU3___CMC."; @@ -1478,11 +1478,11 @@ send_server_options(int fd, int userid, int lazy, int compression, char denc, ch this.rand_seed++; strncat(buf, this.topdomain, 512 - strlen(buf)); - send_query(fd, (uint8_t *)buf); + send_query((uint8_t *)buf); } static int -handshake_version(int dns_fd, int *seed) +handshake_version(int *seed) { char hex[] = "0123456789abcdef"; char hex2[] = "0123456789ABCDEF"; @@ -1493,9 +1493,9 @@ handshake_version(int dns_fd, int *seed) for (i = 0; this.running && i < 5; i++) { - send_version(dns_fd, PROTOCOL_VERSION); + send_version(PROTOCOL_VERSION); - read = handshake_waitdns(dns_fd, in, sizeof(in), 'V', i+1); + read = handshake_waitdns(in, sizeof(in), 'V', i+1); if (read >= 9) { payload = (((in[4] & 0xff) << 24) | @@ -1530,7 +1530,7 @@ handshake_version(int dns_fd, int *seed) } static int -handshake_login(int dns_fd, int seed) +handshake_login(int seed) { char in[4096]; char login[16]; @@ -1544,9 +1544,9 @@ handshake_login(int dns_fd, int seed) for (i=0; this.running && i<5 ;i++) { - send_login(dns_fd, login, 16); + send_login(login, 16); - read = handshake_waitdns(dns_fd, in, sizeof(in), 'L', i+1); + read = handshake_waitdns(in, sizeof(in), 'L', i+1); if (read > 0) { int netmask; @@ -1578,7 +1578,7 @@ handshake_login(int dns_fd, int seed) } static int -handshake_raw_udp(int dns_fd, int seed) +handshake_raw_udp(int seed) { struct timeval tv; char in[4096]; @@ -1594,9 +1594,9 @@ handshake_raw_udp(int dns_fd, int seed) fprintf(stderr, "Testing raw UDP data to the server (skip with -r)"); for (i=0; this.running && i<3 ;i++) { - send_ip_request(dns_fd, this.userid); + send_ip_request(); - len = handshake_waitdns(dns_fd, in, sizeof(in), 'I', i+1); + len = handshake_waitdns(in, sizeof(in), 'I', i+1); if (len == 5 && in[0] == 'I') { /* Received IPv4 address */ @@ -1640,16 +1640,16 @@ handshake_raw_udp(int dns_fd, int seed) tv.tv_sec = i + 1; tv.tv_usec = 0; - send_raw_udp_login(dns_fd, this.userid, seed); + send_raw_udp_login(seed); FD_ZERO(&fds); - FD_SET(dns_fd, &fds); + FD_SET(this.dns_fd, &fds); - r = select(dns_fd + 1, &fds, NULL, NULL, &tv); + r = select(this.dns_fd + 1, &fds, NULL, NULL, &tv); if(r > 0) { /* recv() needed for windows, dont change to read() */ - len = recv(dns_fd, in, sizeof(in), 0); + len = recv(this.dns_fd, in, sizeof(in), 0); if (len >= (16 + RAW_HDR_LEN)) { char hash[16]; login_calculate(hash, 16, this.password, seed - 1); @@ -1671,7 +1671,7 @@ handshake_raw_udp(int dns_fd, int seed) } static int -handshake_upenctest(int dns_fd, char *s) +handshake_upenctest(char *s) /* NOTE: *s may be max 59 chars; must start with "aA" for case-swap check Returns: -1: case swap, no need for any further test: error printed; or Ctrl-C @@ -1689,9 +1689,9 @@ handshake_upenctest(int dns_fd, char *s) slen = strlen(s); for (i=0; this.running && i<3 ;i++) { - send_upenctest(dns_fd, s); + send_upenctest(s); - read = handshake_waitdns(dns_fd, in, sizeof(in), 'Z', i+1); + read = handshake_waitdns(in, sizeof(in), 'Z', i+1); if (read == -2) return 0; /* hard error */ @@ -1741,7 +1741,7 @@ handshake_upenctest(int dns_fd, char *s) } static int -handshake_upenc_autodetect(int dns_fd) +handshake_upenc_autodetect() /* Returns: 0: keep Base32 1: Base64 is okay @@ -1771,7 +1771,7 @@ handshake_upenc_autodetect(int dns_fd) /* Try Base128, starting very gently to not draw attention */ while (1) { - res = handshake_upenctest(dns_fd, pat128a); + res = handshake_upenctest(pat128a); if (res < 0) { /* DNS swaps case, msg already printed; or Ctrl-C */ return 0; @@ -1780,7 +1780,7 @@ handshake_upenc_autodetect(int dns_fd) break; } - res = handshake_upenctest(dns_fd, pat128b); + res = handshake_upenctest(pat128b); if (res < 0) return 0; else if (res == 0) @@ -1788,19 +1788,19 @@ handshake_upenc_autodetect(int dns_fd) /* if this works, we can test the real stuff */ - res = handshake_upenctest(dns_fd, pat128c); + res = handshake_upenctest(pat128c); if (res < 0) return 0; else if (res == 0) break; - res = handshake_upenctest(dns_fd, pat128d); + res = handshake_upenctest(pat128d); if (res < 0) return 0; else if (res == 0) break; - res = handshake_upenctest(dns_fd, pat128e); + res = handshake_upenctest(pat128e); if (res < 0) return 0; else if (res == 0) @@ -1811,7 +1811,7 @@ handshake_upenc_autodetect(int dns_fd) } /* Try Base64 (with plus sign) */ - res = handshake_upenctest(dns_fd, pat64); + res = handshake_upenctest(pat64); if (res < 0) { /* DNS swaps case, msg already printed; or Ctrl-C */ return 0; @@ -1821,7 +1821,7 @@ handshake_upenc_autodetect(int dns_fd) } /* Try Base64u (with _u_nderscore) */ - res = handshake_upenctest(dns_fd, pat64u); + res = handshake_upenctest(pat64u); if (res < 0) { /* DNS swaps case, msg already printed; or Ctrl-C */ return 0; @@ -1836,7 +1836,7 @@ handshake_upenc_autodetect(int dns_fd) } static int -handshake_downenctest(int dns_fd, char trycodec) +handshake_downenctest(char trycodec) /* Returns: 0: not identical or error or timeout 1: identical string returned @@ -1850,9 +1850,9 @@ handshake_downenctest(int dns_fd, char trycodec) for (i=0; this.running && i<3 ;i++) { - send_downenctest(dns_fd, trycodec, 1, NULL, 0); + send_downenctest(trycodec, 1, NULL, 0); - read = handshake_waitdns(dns_fd, in, sizeof(in), 'Y', i+1); + read = handshake_waitdns(in, sizeof(in), 'Y', i+1); if (read == -2) return 0; /* hard error */ @@ -1880,7 +1880,7 @@ handshake_downenctest(int dns_fd, char trycodec) } static char -handshake_downenc_autodetect(int dns_fd) +handshake_downenc_autodetect() /* Returns codec char (or ' ' if no advanced codec works) */ { int base64ok = 0; @@ -1896,20 +1896,20 @@ handshake_downenc_autodetect(int dns_fd) fprintf(stderr, "Autodetecting downstream codec (use -O to override)\n"); /* Try Base64 */ - if (handshake_downenctest(dns_fd, 'S')) + if (handshake_downenctest('S')) base64ok = 1; - else if (this.running && handshake_downenctest(dns_fd, 'U')) + else if (this.running && handshake_downenctest('U')) base64uok = 1; /* Try Base128 only if 64 gives us some perspective */ if (this.running && (base64ok || base64uok)) { - if (handshake_downenctest(dns_fd, 'V')) + if (handshake_downenctest('V')) base128ok = 1; } /* If 128 works, then TXT may give us Raw as well */ if (this.running && (base128ok && this.do_qtype == T_TXT)) { - if (handshake_downenctest(dns_fd, 'R')) + if (handshake_downenctest('R')) return 'R'; } @@ -1928,7 +1928,7 @@ handshake_downenc_autodetect(int dns_fd) } static int -handshake_qtypetest(int dns_fd, int timeout) +handshake_qtypetest(int timeout) /* Returns: 0: doesn't work with this timeout 1: works properly @@ -1950,9 +1950,9 @@ handshake_qtypetest(int dns_fd, int timeout) byte values can be returned, which is needed for NULL/PRIVATE to work. */ - send_downenctest(dns_fd, trycodec, 1, NULL, 0); + send_downenctest(trycodec, 1, NULL, 0); - read = handshake_waitdns(dns_fd, in, sizeof(in), 'Y', timeout); + read = handshake_waitdns(in, sizeof(in), 'Y', timeout); if (read != slen) return 0; /* incorrect */ @@ -1984,7 +1984,7 @@ handshake_qtype_numcvt(int num) } static int -handshake_qtype_autodetect(int dns_fd) +handshake_qtype_autodetect() /* Returns: 0: okay, this.do_qtype set 1: problem, program exit @@ -2016,7 +2016,7 @@ handshake_qtype_autodetect(int dns_fd) fprintf(stderr, "."); fflush(stderr); - if (handshake_qtypetest(dns_fd, timeout)) { + if (handshake_qtypetest(timeout)) { /* okay */ highestworking = qtypenum; DEBUG(1, " Type %s timeout %d works", client_get_qtype(), timeout); @@ -2053,7 +2053,7 @@ handshake_qtype_autodetect(int dns_fd) } static int -handshake_edns0_check(int dns_fd) +handshake_edns0_check() /* Returns: 0: EDNS0 not supported; or Ctrl-C 1: EDNS0 works @@ -2073,9 +2073,9 @@ handshake_edns0_check(int dns_fd) for (i=0; this.running && i<3 ;i++) { - send_downenctest(dns_fd, trycodec, 1, NULL, 0); + send_downenctest(trycodec, 1, NULL, 0); - read = handshake_waitdns(dns_fd, in, sizeof(in), 'Y', i+1); + read = handshake_waitdns(in, sizeof(in), 'Y', i+1); if (read == -2) return 0; /* hard error */ @@ -2103,7 +2103,7 @@ handshake_edns0_check(int dns_fd) } static void -handshake_switch_codec(int dns_fd, int bits) +handshake_switch_codec(int bits) { char in[4096]; int i; @@ -2124,9 +2124,9 @@ handshake_switch_codec(int dns_fd, int bits) for (i=0; this.running && i<5 ;i++) { - send_codec_switch(dns_fd, this.userid, bits); + send_codec_switch(bits); - read = handshake_waitdns(dns_fd, in, sizeof(in), 'S', i+1); + read = handshake_waitdns(in, sizeof(in), 'S', i+1); if (read > 0) { if (strncmp("BADLEN", in, 6) == 0) { @@ -2160,7 +2160,7 @@ codec_revert: } void -handshake_switch_options(int dns_fd, int lazy, int compression, char denc) +handshake_switch_options(int lazy, int compression, char denc) { char in[4096]; int read; @@ -2185,9 +2185,9 @@ handshake_switch_options(int dns_fd, int lazy, int compression, char denc) lazy_status, dname, comp_status); for (int i = 0; this.running && i < 5; i++) { - send_server_options(dns_fd, this.userid, lazy, compression, denc, opts); + send_server_options(lazy, compression, denc, opts); - read = handshake_waitdns(dns_fd, in, sizeof(in) - 1, 'O', i + 1); + read = handshake_waitdns(in, sizeof(in) - 1, 'O', i + 1); if (read > 0) { if (strncmp("BADLEN", in, 6) == 0) { @@ -2295,7 +2295,7 @@ fragsize_check(char *in, int read, int proposed_fragsize, int *max_fragsize) static int -handshake_autoprobe_fragsize(int dns_fd) +handshake_autoprobe_fragsize() { char in[MAX_FRAGSIZE]; int i; @@ -2310,9 +2310,9 @@ handshake_autoprobe_fragsize(int dns_fd) /* stop the slow probing early when we have enough bytes anyway */ for (i=0; this.running && i<3 ;i++) { - send_fragsize_probe(dns_fd, proposed_fragsize); + send_fragsize_probe(proposed_fragsize); - read = handshake_waitdns(dns_fd, in, sizeof(in), 'R', 1); + read = handshake_waitdns(in, sizeof(in), 'R', 1); if (read > 0) { /* We got a reply */ @@ -2367,7 +2367,7 @@ handshake_autoprobe_fragsize(int dns_fd) } static void -handshake_set_fragsize(int dns_fd, int fragsize) +handshake_set_fragsize(int fragsize) { char in[4096]; int i; @@ -2376,9 +2376,9 @@ handshake_set_fragsize(int dns_fd, int fragsize) fprintf(stderr, "Setting downstream fragment size to max %d...\n", fragsize); for (i=0; this.running && i<5 ;i++) { - send_set_downstream_fragsize(dns_fd, fragsize); + send_set_downstream_fragsize(fragsize); - read = handshake_waitdns(dns_fd, in, sizeof(in), 'N', i+1); + read = handshake_waitdns(in, sizeof(in), 'N', i+1); if (read > 0) { @@ -2404,7 +2404,7 @@ handshake_set_fragsize(int dns_fd, int fragsize) } static void -handshake_set_timeout(int dns_fd) +handshake_set_timeout() { char in[4096]; int read, id; @@ -2419,9 +2419,9 @@ handshake_set_timeout(int dns_fd) for (int i = 0; this.running && i < 5; i++) { id = this.autodetect_server_timeout ? - update_server_timeout(dns_fd, 1) : send_ping(dns_fd, 1, -1, 1); + update_server_timeout(1) : send_ping(1, -1, 1); - read = handshake_waitdns(dns_fd, in, sizeof(in), 'P', i + 1); + read = handshake_waitdns(in, sizeof(in), 'P', i + 1); got_response(id, 1, 0); fprintf(stderr, "."); @@ -2447,7 +2447,7 @@ handshake_set_timeout(int dns_fd) } int -client_handshake(int dns_fd, int raw_mode, int autodetect_frag_size, int fragsize) +client_handshake() { int seed; int upcodec; @@ -2457,7 +2457,7 @@ client_handshake(int dns_fd, int raw_mode, int autodetect_frag_size, int fragsiz /* qtype message printed in handshake function */ if (this.do_qtype == T_UNSET) { - r = handshake_qtype_autodetect(dns_fd); + r = handshake_qtype_autodetect(); if (r) { return r; } @@ -2465,28 +2465,28 @@ client_handshake(int dns_fd, int raw_mode, int autodetect_frag_size, int fragsiz fprintf(stderr, "Using DNS type %s queries\n", client_get_qtype()); - r = handshake_version(dns_fd, &seed); + r = handshake_version(&seed); if (r) { return r; } - r = handshake_login(dns_fd, seed); + r = handshake_login(seed); if (r) { return r; } - if (raw_mode && handshake_raw_udp(dns_fd, seed)) { + if (this.raw_mode && handshake_raw_udp(seed)) { this.conn = CONN_RAW_UDP; this.max_timeout_ms = 10000; this.compression_down = 1; this.compression_up = 1; } else { - if (raw_mode == 0) { + if (this.raw_mode == 0) { fprintf(stderr, "Skipping raw mode\n"); } dnsc_use_edns0 = 1; - if (handshake_edns0_check(dns_fd) && this.running) { + if (handshake_edns0_check() && this.running) { fprintf(stderr, "Using EDNS0 extension\n"); } else if (!this.running) { return -1; @@ -2495,45 +2495,45 @@ client_handshake(int dns_fd, int raw_mode, int autodetect_frag_size, int fragsiz dnsc_use_edns0 = 0; } - upcodec = handshake_upenc_autodetect(dns_fd); + upcodec = handshake_upenc_autodetect(); if (!this.running) return -1; if (upcodec == 1) { /* Base64 */ - handshake_switch_codec(dns_fd, 6); + handshake_switch_codec(6); } else if (upcodec == 2) { /* Base64u */ - handshake_switch_codec(dns_fd, 26); + handshake_switch_codec(26); } else if (upcodec == 3) { /* Base128 */ - handshake_switch_codec(dns_fd, 7); + handshake_switch_codec(7); } if (!this.running) return -1; if (this.downenc == ' ') { - this.downenc = handshake_downenc_autodetect(dns_fd); + this.downenc = handshake_downenc_autodetect(); } if (!this.running) return -1; /* Set options for compression, this.lazymode and downstream codec */ - handshake_switch_options(dns_fd, this.lazymode, this.compression_down, this.downenc); + handshake_switch_options(this.lazymode, this.compression_down, this.downenc); if (!this.running) return -1; - if (autodetect_frag_size) { - fragsize = handshake_autoprobe_fragsize(dns_fd); - if (fragsize > MAX_FRAGSIZE) { + if (this.autodetect_frag_size) { + this.max_downstream_frag_size = handshake_autoprobe_fragsize(); + if (this.max_downstream_frag_size > MAX_FRAGSIZE) { /* This is very unlikely except perhaps over LAN */ fprintf(stderr, "Can transfer fragsize of %d, however iodine has been compiled with MAX_FRAGSIZE = %d." - " To fully utilize this connection, please recompile iodine/iodined.\n", fragsize, MAX_FRAGSIZE); - fragsize = MAX_FRAGSIZE; + " To fully utilize this connection, please recompile iodine/iodined.\n", this.max_downstream_frag_size, MAX_FRAGSIZE); + this.max_downstream_frag_size = MAX_FRAGSIZE; } - if (!fragsize) { + if (!this.max_downstream_frag_size) { return 1; } } - handshake_set_fragsize(dns_fd, fragsize); + handshake_set_fragsize(this.max_downstream_frag_size); if (!this.running) return -1; @@ -2551,7 +2551,7 @@ client_handshake(int dns_fd, int raw_mode, int autodetect_frag_size, int fragsiz this.pending_queries[i].id = -1; /* set server window/timeout parameters and calculate RTT */ - handshake_set_timeout(dns_fd); + handshake_set_timeout(); } return 0; diff --git a/src/client.h b/src/client.h index f76911a..1456073 100644 --- a/src/client.h +++ b/src/client.h @@ -153,12 +153,12 @@ char *format_qtype(); char parse_encoding(char *encoding); void client_set_hostname_maxlen(size_t i); -int client_handshake(int dns_fd, int raw_mode, int autodetect_frag_size, int fragsize); -int client_tunnel(int tun_fd, int dns_fd); +int client_handshake(); +int client_tunnel(); int parse_data(uint8_t *data, size_t len, fragment *f, int *immediate); -int handshake_waitdns(int dns_fd, char *buf, size_t buflen, char cmd, int timeout); -void handshake_switch_options(int dns_fd, int lazy, int compression, char denc); -int send_ping(int fd, int ping_response, int ack, int timeout); +int handshake_waitdns(char *buf, size_t buflen, char cmd, int timeout); +void handshake_switch_options(int lazy, int compression, char denc); +int send_ping(int ping_response, int ack, int timeout); #endif diff --git a/src/iodine.c b/src/iodine.c index f963531..e27f23a 100644 --- a/src/iodine.c +++ b/src/iodine.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -57,11 +58,20 @@ static char *__progname; struct client_instance this; +/* BEGIN PRESET DEFINITIONS */ + +/* static startup values - should not be changed in presets */ +#define PRESET_STATIC_VALUES \ + .conn = CONN_DNS_NULL, \ + .send_ping_soon = 1, \ + .downenc = ' ', \ + .do_qtype = T_UNSET, \ + .maxfragsize_up = 100, \ + .next_downstream_ack = -1, \ + .num_immediate = 1, \ + .rtt_total_ms = 200 + static struct client_instance preset_default = { - .foreground = 0, -#ifdef OPENBSD - .rtable = 0, -#endif .debug = 0, .stats = 0, .raw_mode = 1, @@ -79,18 +89,56 @@ static struct client_instance preset_default = { .windowsize_up = 8, .windowsize_down = 8, .hostname_maxlen = 0xFF, - - /* static startup values - should not be changed in presets */ - .conn = CONN_DNS_NULL, - .send_ping_soon = 1, - .downenc = ' ', - .do_qtype = T_UNSET, - .maxfragsize_up = 100, - .next_downstream_ack = -1, - .num_immediate = 1, - .rtt_total_ms = 200 + PRESET_STATIC_VALUES }; +static struct client_instance preset_original = { + .raw_mode = 1, + .lazymode = 1, + .max_timeout_ms = 4000, + .send_interval_ms = 0, + .server_timeout_ms = 3000, + .autodetect_server_timeout = 1, + .windowsize_down = 1, + .windowsize_up = 1, + .hostname_maxlen = 0xFF, + .downstream_timeout_ms = 4000, + .dataenc = &base32_encoder, + .autodetect_frag_size = 1, + .max_downstream_frag_size = MAX_FRAGSIZE, + .compression_down = 1, + .compression_up = 0, + PRESET_STATIC_VALUES +}; + +struct option_presets { + size_t preset_data_len; /* sizeof(struct client/server_instance) */ + size_t num_presets; + struct option_preset { + void *preset_data; /* Pointer to client/server "instance" struct */ + char short_name; + char *long_name; + } presets[]; +}; + +#define NUM_CLIENT_PRESETS 2 + +static struct { + struct client_instance *preset_data; + char short_name; +} client_presets[NUM_CLIENT_PRESETS] = { + { + .preset_data = &preset_default, + .short_name = 'D' + }, + { + .preset_data = &preset_original, + .short_name = 'O' + } +}; + +/* END PRESET DEFINITIONS */ + static void sighandler(int sig) { @@ -151,14 +199,16 @@ help() fprintf(stderr, " -v, --version print version info and exit\n"); fprintf(stderr, " -h, --help print this help and exit\n"); fprintf(stderr, " -V, --stats print connection statistics at given intervals (default: 5 sec)\n"); - fprintf(stderr, " -X skip tun device and forward data to/from stdin/out, telling the iodined to\n"); + /*fprintf(stderr, " -X skip tun device and forward data to/from stdin/out, telling iodined to\n"); fprintf(stderr, " connect to the specified port listening on the server host.\n"); - fprintf(stderr, " Can be used with SSH ProxyCommand option. (-X 22)\n"); + fprintf(stderr, " Can be used with SSH ProxyCommand option. (-X 22)\n");*/ fprintf(stderr, " -f keep running in foreground\n"); fprintf(stderr, " -D enable debug mode (add more D's to increase debug level)\n"); fprintf(stderr, " -d set tunnel device name\n"); fprintf(stderr, " -u drop privileges and run as specified user\n"); fprintf(stderr, " -F write PID to specified file\n"); + fprintf(stderr, " -Y, --preset use a set of predefined options (can be overridden manually)\n"); + fprintf(stderr, " Available presets: 'O' for iodine 0.7 behaviour, 'F' for fast/low latency settings\n"); fprintf(stderr, " --chroot chroot to given directory\n"); fprintf(stderr, " --context apply specified SELinux context after initialization\n"); fprintf(stderr, " --rdomain use specified routing domain (OpenBSD only)\n\n"); @@ -204,11 +254,6 @@ main(int argc, char **argv) WSAStartup(req_version, &wsa_data); #endif - srand((unsigned) time(NULL)); - this.rand_seed = (uint16_t) rand(); - this.chunkid = (uint16_t) rand(); - this.running = 1; - #if !defined(BSD) && !defined(__GLIBC__) __progname = strrchr(argv[0], '/'); if (__progname == NULL) @@ -227,13 +272,52 @@ main(int argc, char **argv) {"rdomain", required_argument, 0, 'R'}, {"chrootdir", required_argument, 0, 't'}, {"proxycommand", no_argument, 0, 'X'}, + {"preset", required_argument, 0, 'Y'}, {NULL, 0, 0, 0} }; - static char *iodine_args_short = "46vfDhrXs:V:c:C:i:j:u:t:d:R:P:w:W:m:M:F:T:O:L:I:"; + /* Pre-parse command line to get preset + * This is so that all options override preset values regardless of order in command line */ + int optind_orig = optind, preset_id = -1; + static char *iodine_args_short = "46vfDhrX:Y:s:V:c:C:i:j:u:t:d:R:P:w:W:m:M:F:T:O:L:I:"; + + while ((choice = getopt_long(argc, argv, iodine_args_short, iodine_args, NULL))) { + if (preset_id < 0) { + if (choice == -1) { + /* reached end of command line and no preset specified - use default */ + preset_id = 0; + } else if (choice == 'Y') { + /* find index of preset */ + if (optarg) { + for (int i = 0; i < NUM_CLIENT_PRESETS; i++) { + if (toupper(optarg[0] == client_presets[i].short_name)) { + preset_id = i; + break; + } + } + } + } else { + /* skip all other options until we find preset */ + continue; + } + + if (preset_id < 0) { + /* invalid preset or none specified */ + fprintf(stderr, "Invalid preset or none specified with -Y or --preset! Run 'iodine -h' to see available presets.\n"); + usage(); + /* not reached */ + } + + memcpy(&this, client_presets[preset_id].preset_data, sizeof(struct client_instance)); + + /* Reset optind to reparse command line */ + optind = optind_orig; + continue; + } else if (choice == -1) { + break; + } - while ((choice = getopt_long(argc, argv, iodine_args_short, iodine_args, NULL)) != -1) { switch (choice) { case '4': nameserv_family = AF_INET; @@ -318,6 +402,9 @@ main(int argc, char **argv) break; case 'I': this.max_timeout_ms = strtod(optarg, NULL) * 1000; + if (this.autodetect_server_timeout) { + this.server_timeout_ms = this.max_timeout_ms / 2; + } break; case 'i': this.server_timeout_ms = strtod(optarg, NULL) * 1000; @@ -346,6 +433,9 @@ main(int argc, char **argv) case 'C': this.compression_up = atoi(optarg) & 1; break; + case 'Y': + /* Already processed preset: ignore */ + continue; case 'X': // TODO implement option for remote host/port to pipe stdin/out default: @@ -354,6 +444,11 @@ main(int argc, char **argv) } } + srand((unsigned) time(NULL)); + this.rand_seed = (uint16_t) rand(); + this.chunkid = (uint16_t) rand(); + this.running = 1; + check_superuser(usage); argc -= optind; @@ -404,9 +499,6 @@ main(int argc, char **argv) usage(); } - // TODO remove client_set_... functions -// client_set_nameservers(nameserv_addrs, nameserv_addrs_len); - if (this.max_downstream_frag_size < 10 || this.max_downstream_frag_size > MAX_FRAGSIZE) { warnx("Use a max frag size between 10 and %d bytes.", MAX_FRAGSIZE); usage(); @@ -431,7 +523,8 @@ main(int argc, char **argv) usage(); } - if (this.server_timeout_ms < 100 || this.server_timeout_ms >= this.max_timeout_ms) { + if ((this.server_timeout_ms < 100 || this.server_timeout_ms >= this.max_timeout_ms) + && !this.autodetect_server_timeout) { warnx("Server timeout (-i) must be greater than 0.1 sec and less than target interval!"); usage(); } @@ -445,14 +538,6 @@ main(int argc, char **argv) fprintf(stderr, "Warning: Target interval of >1 second in immediate mode will cause high latency.\n"); } -// client_set_compression(up_compression, down_compression); -// 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); -// client_set_hostname_maxlen(hostname_maxlen); -// client_set_windowsize(up_windowsize, down_windowsize); - if (username != NULL) { #ifndef WINDOWS32 if ((pw = getpwnam(username)) == NULL) { @@ -494,8 +579,7 @@ main(int argc, char **argv) (a != this.nameserv_addrs_len - 1) ? ", " : ""); fprintf(stderr, "\n"); - // TODO not pass args to client stuff - use "this" as shared instance - if (client_handshake(this.dns_fd, this.raw_mode, this.autodetect_frag_size, this.max_downstream_frag_size)) { + if (client_handshake()) { retval = 1; goto cleanup2; } @@ -530,8 +614,7 @@ main(int argc, char **argv) if (context != NULL) do_setcon(context); - // todo don't pass args again. - client_tunnel(this.tun_fd, this.dns_fd); + client_tunnel(); cleanup2: close_dns(this.dns_fd);