Added command line option presets (--preset or -Y)

Fixed some refactoring issues and passing this.* as arguments
This commit is contained in:
frekky 2016-01-09 19:29:17 +08:00
parent f4d1d1634c
commit 7068bcc08d
3 changed files with 268 additions and 185 deletions

View File

@ -162,7 +162,7 @@ immediate_mode_defaults()
#endif #endif
static int 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 /* Calculate server timeout based on average RTT, send ping "handshake" to set
* if handshake sent, return query ID */ * if handshake sent, return query ID */
{ {
@ -201,7 +201,7 @@ update_server_timeout(int dns_fd, int handshake)
if (handshake) { if (handshake) {
/* Send ping handshake to set server timeout */ /* Send ping handshake to set server timeout */
return send_ping(dns_fd, 1, -1, 1); return send_ping(1, -1, 1);
} }
return -1; return -1;
} }
@ -309,7 +309,7 @@ got_response(int id, int immediate, int fail)
this.num_immediate++; this.num_immediate++;
if (this.autodetect_server_timeout) if (this.autodetect_server_timeout)
update_server_timeout(-1, 0); update_server_timeout(0);
} }
/* Remove query info from buffer to mark it as answered */ /* Remove query info from buffer to mark it as answered */
@ -326,7 +326,7 @@ got_response(int id, int immediate, int fail)
} }
static int static int
send_query(int fd, uint8_t *hostname) send_query(uint8_t *hostname)
/* Returns DNS ID of sent query */ /* Returns DNS ID of sent query */
{ {
uint8_t packet[4096]; 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]); 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)); sizeof(struct sockaddr_storage));
client_rotate_nameserver(); client_rotate_nameserver();
@ -391,14 +391,14 @@ send_query(int fd, uint8_t *hostname)
this.lazymode = 0; this.lazymode = 0;
this.server_timeout_ms = 0; this.server_timeout_ms = 0;
} }
update_server_timeout(fd, 1); update_server_timeout(1);
} }
} }
return q.id; return q.id;
} }
static void 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]; char packet[4096];
int len; int len;
@ -411,20 +411,20 @@ send_raw(int fd, uint8_t *buf, size_t buflen, int user, int cmd)
} }
len += RAW_HDR_LEN; 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 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 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 /* Base32 encodes data and sends as single DNS query
* Returns ID of sent 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); build_hostname(buf, sizeof(buf), data, datalen, this.topdomain, b32, this.hostname_maxlen, 1);
return send_query(fd, buf); return send_query(buf);
} }
int 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++; this.num_pings++;
if (this.conn == CONN_DNS_NULL) { 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, ping_response, ack, set_timeout ? "SET " : "", this.server_timeout_ms,
this.downstream_timeout_ms, data[8]); 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 */ /* Log query ID as being sent now */
query_sent_now(id); query_sent_now(id);
return id; return id;
} else { } else {
send_raw(fd, NULL, 0, this.userid, RAW_HDR_CMD_PING); send_raw(NULL, 0, RAW_HDR_CMD_PING);
return -1; return -1;
} }
} }
static void static void
send_next_frag(int fd) send_next_frag()
/* Sends next available fragment of data from the outgoing window buffer */ /* Sends next available fragment of data from the outgoing window buffer */
{ {
static uint8_t buf[MAX_FRAGSIZE], hdr[5]; static uint8_t buf[MAX_FRAGSIZE], hdr[5];
@ -497,7 +497,7 @@ send_next_frag(int fd)
if (this.outbuf->numitems > 0) { if (this.outbuf->numitems > 0) {
/* There is stuff to send but we're out of sync, so send a ping /* 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 */ * 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; this.next_downstream_ack = -1;
window_tick(this.outbuf); 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", 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); 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 */ /* Log query ID as being sent now */
query_sent_now(id); query_sent_now(id);
@ -684,7 +684,7 @@ dns_namedec(uint8_t *outdata, size_t outdatalen, uint8_t *buf, size_t buflen)
} }
static int 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 -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 Returns 0 on replies that could be correct but are useless, and are not
DNS error replies. 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; int r;
addrlen = sizeof(from); 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) { (struct sockaddr*)&from, &addrlen)) < 0) {
warn("recvfrom"); warn("recvfrom");
return -1; 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; r -= RAW_HDR_LEN;
datalen = sizeof(buf); datalen = sizeof(buf);
if (uncompress(buf, &datalen, data + RAW_HDR_LEN, r) == Z_OK) { 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 */ /* all done */
@ -796,7 +796,7 @@ read_dns_withq(int dns_fd, int tun_fd, uint8_t *buf, size_t buflen, struct query
} }
int 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. /* Wait for DNS reply fitting to our latest query and returns it.
Returns length of reply = #bytes used in buf. Returns length of reply = #bytes used in buf.
Returns 0 if fitting reply happens to be useless. 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_sec = timeout;
tv.tv_usec = 0; tv.tv_usec = 0;
FD_ZERO(&fds); 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) if (r < 0)
return -1; /* select error */ 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.id = -1;
q.name[0] = '\0'; 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]); qcmd = toupper(q.name[0]);
if (q.id != this.chunkid || qcmd != cmd) { 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 static int
tunnel_tun(int tun_fd, int dns_fd) tunnel_tun()
{ {
size_t datalen; size_t datalen;
uint8_t out[64*1024]; uint8_t out[64*1024];
@ -928,7 +928,7 @@ tunnel_tun(int tun_fd, int dns_fd)
uint8_t *data; uint8_t *data;
ssize_t read; 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; return -1;
DEBUG(2, " IN: %lu bytes on tunnel, to be compressed: %d", read, this.compression_up); 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); window_add_outgoing_data(this.outbuf, data, datalen, this.compression_up);
/* Don't send anything here to respect min. send interval */ /* Don't send anything here to respect min. send interval */
} else { } else {
send_raw_data(dns_fd, data, datalen); send_raw_data(data, datalen);
} }
return read; return read;
} }
static int static int
tunnel_dns(int tun_fd, int dns_fd) tunnel_dns()
{ {
struct query q; struct query q;
size_t datalen, buflen; size_t datalen, buflen;
@ -971,7 +971,7 @@ tunnel_dns(int tun_fd, int dns_fd)
memset(&q, 0, sizeof(q)); memset(&q, 0, sizeof(q));
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));
memset(cbuf, 0, sizeof(cbuf)); 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) if (this.conn != CONN_DNS_NULL)
return 1; /* everything already done */ return 1; /* everything already done */
@ -1016,7 +1016,7 @@ tunnel_dns(int tun_fd, int dns_fd)
/* Reset query counts this.stats */ /* Reset query counts this.stats */
this.send_query_sendcnt = 0; this.send_query_sendcnt = 0;
this.send_query_recvcnt = 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 && } else if (this.send_query_recvcnt < 500 && this.num_servfail >= 40 &&
this.autodetect_server_timeout && this.max_timeout_ms < 500) { 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 */ /* last-ditch attempt to fix SERVFAILs - disable lazy mode */
immediate_mode_defaults(); immediate_mode_defaults();
fprintf(stderr, "Attempting to disable lazy mode due to excessive SERVFAILs\n"); 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) if (datalen)
write_tun(tun_fd, data, datalen); write_tun(this.tun_fd, data, datalen);
} }
/* Move window along after doing all data processing */ /* Move window along after doing all data processing */
@ -1121,7 +1121,7 @@ tunnel_dns(int tun_fd, int dns_fd)
} }
int int
client_tunnel(int tun_fd, int dns_fd) client_tunnel()
{ {
struct timeval tv, nextresend, tmp, now, now2; struct timeval tv, nextresend, tmp, now, now2;
fd_set fds; fd_set fds;
@ -1180,10 +1180,10 @@ client_tunnel(int tun_fd, int dns_fd)
if (sending > 0) { if (sending > 0) {
/* More to send - next fragment */ /* More to send - next fragment */
send_next_frag(dns_fd); send_next_frag();
} else { } else {
/* Send ping if we didn't send anything yet */ /* 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; 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) { if (this.conn != CONN_DNS_NULL || window_buffer_available(this.outbuf) > 16) {
/* Fill up outgoing buffer with available data if it has enough space /* Fill up outgoing buffer with available data if it has enough space
* The windowing protocol manages data retransmits, timeouts etc. */ * 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); 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); 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) { if (use_min_send && i > 0) {
/* enforce min_send_interval if we get interrupted by new tun data */ /* 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) { if (i == 0) {
/* timed out - no new packets recv'd */ /* timed out - no new packets recv'd */
} else { } else {
if (FD_ISSET(tun_fd, &fds)) { if (FD_ISSET(this.tun_fd, &fds)) {
if (tunnel_tun(tun_fd, dns_fd) <= 0) if (tunnel_tun() <= 0)
continue; continue;
/* Returns -1 on error OR when quickly /* Returns -1 on error OR when quickly
dropping data in case of DNS congestion; 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 chunk sent, sets this.send_ping_soon=0. */
} }
if (FD_ISSET(dns_fd, &fds)) { if (FD_ISSET(this.dns_fd, &fds)) {
tunnel_dns(tun_fd, dns_fd); tunnel_dns();
} }
} }
} }
@ -1310,7 +1310,7 @@ client_tunnel(int tun_fd, int dns_fd)
} }
static void static void
send_login(int fd, char *login, int len) send_login(char *login, int len)
{ {
uint8_t data[19]; uint8_t data[19];
@ -1323,11 +1323,11 @@ send_login(int fd, char *login, int len)
this.rand_seed++; this.rand_seed++;
send_packet(fd, 'l', data, sizeof(data)); send_packet('l', data, sizeof(data));
} }
static void static void
send_fragsize_probe(int fd, uint16_t fragsize) send_fragsize_probe(uint16_t fragsize)
{ {
uint8_t probedata[256]; uint8_t probedata[256];
uint8_t buf[MAX_FRAGSIZE]; 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, build_hostname(buf, sizeof(buf), probedata, sizeof(probedata), this.topdomain,
this.dataenc, this.hostname_maxlen, 6); this.dataenc, this.hostname_maxlen, 6);
send_query(fd, buf); send_query(buf);
} }
static void static void
send_set_downstream_fragsize(int fd, uint16_t fragsize) send_set_downstream_fragsize(uint16_t fragsize)
{ {
uint8_t data[5]; uint8_t data[5];
@ -1365,11 +1365,11 @@ send_set_downstream_fragsize(int fd, uint16_t fragsize)
this.rand_seed++; this.rand_seed++;
send_packet(fd, 'n', data, sizeof(data)); send_packet('n', data, sizeof(data));
} }
static void static void
send_version(int fd, uint32_t version) send_version(uint32_t version)
{ {
uint8_t data[6]; uint8_t data[6];
@ -1381,11 +1381,11 @@ send_version(int fd, uint32_t version)
this.rand_seed++; this.rand_seed++;
send_packet(fd, 'v', data, sizeof(data)); send_packet('v', data, sizeof(data));
} }
static void static void
send_ip_request(int fd, int userid) send_ip_request()
{ {
uint8_t buf[512] = "i____."; uint8_t buf[512] = "i____.";
buf[1] = b32_5to8(this.userid); buf[1] = b32_5to8(this.userid);
@ -1396,20 +1396,20 @@ send_ip_request(int fd, int userid)
this.rand_seed++; this.rand_seed++;
strncat((char *)buf, this.topdomain, 512 - strlen((char *)buf)); strncat((char *)buf, this.topdomain, 512 - strlen((char *)buf));
send_query(fd, buf); send_query(buf);
} }
static void static void
send_raw_udp_login(int dns_fd, int userid, int seed) send_raw_udp_login(int seed)
{ {
char buf[16]; char buf[16];
login_calculate(buf, 16, this.password, seed + 1); 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 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. */ /* NOTE: String may be at most 63-4=59 chars to fit in 1 dns chunk. */
{ {
char buf[512] = "z___"; char buf[512] = "z___";
@ -1422,16 +1422,16 @@ send_upenctest(int fd, char *s)
strncat(buf, s, 512 - strlen(buf)); strncat(buf, s, 512 - strlen(buf));
strncat(buf, ".", 512 - strlen(buf)); strncat(buf, ".", 512 - strlen(buf));
strncat(buf, this.topdomain, 512 - strlen(buf)); strncat(buf, this.topdomain, 512 - strlen(buf));
send_query(fd, (uint8_t *)buf); send_query((uint8_t *)buf);
} }
static void 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. */ /* Note: content/handling of s is not defined yet. */
{ {
char buf[512] = "y_____."; char buf[512] = "y_____.";
buf[1] = tolower(this.downenc); buf[1] = tolower(downenc);
buf[2] = b32_5to8(variant); buf[2] = b32_5to8(variant);
buf[3] = b32_5to8((this.rand_seed >> 10) & 0x1f); 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++; this.rand_seed++;
strncat(buf, this.topdomain, 512 - strlen(buf)); strncat(buf, this.topdomain, 512 - strlen(buf));
send_query(fd, (uint8_t *)buf); send_query((uint8_t *)buf);
} }
static void static void
send_codec_switch(int fd, int userid, int bits) send_codec_switch(int bits)
{ {
char buf[512] = "s_____."; char buf[512] = "s_____.";
buf[1] = b32_5to8(this.userid); buf[1] = b32_5to8(this.userid);
@ -1456,11 +1456,11 @@ send_codec_switch(int fd, int userid, int bits)
this.rand_seed++; this.rand_seed++;
strncat(buf, this.topdomain, 512 - strlen(buf)); strncat(buf, this.topdomain, 512 - strlen(buf));
send_query(fd, (uint8_t *)buf); send_query((uint8_t *)buf);
} }
static void 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 */ /* Options must be length >=4 */
{ {
char buf[512] = "oU3___CMC."; 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++; this.rand_seed++;
strncat(buf, this.topdomain, 512 - strlen(buf)); strncat(buf, this.topdomain, 512 - strlen(buf));
send_query(fd, (uint8_t *)buf); send_query((uint8_t *)buf);
} }
static int static int
handshake_version(int dns_fd, int *seed) handshake_version(int *seed)
{ {
char hex[] = "0123456789abcdef"; char hex[] = "0123456789abcdef";
char hex2[] = "0123456789ABCDEF"; char hex2[] = "0123456789ABCDEF";
@ -1493,9 +1493,9 @@ handshake_version(int dns_fd, int *seed)
for (i = 0; this.running && i < 5; i++) { 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) { if (read >= 9) {
payload = (((in[4] & 0xff) << 24) | payload = (((in[4] & 0xff) << 24) |
@ -1530,7 +1530,7 @@ handshake_version(int dns_fd, int *seed)
} }
static int static int
handshake_login(int dns_fd, int seed) handshake_login(int seed)
{ {
char in[4096]; char in[4096];
char login[16]; char login[16];
@ -1544,9 +1544,9 @@ handshake_login(int dns_fd, int seed)
for (i=0; this.running && i<5 ;i++) { 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) { if (read > 0) {
int netmask; int netmask;
@ -1578,7 +1578,7 @@ handshake_login(int dns_fd, int seed)
} }
static int static int
handshake_raw_udp(int dns_fd, int seed) handshake_raw_udp(int seed)
{ {
struct timeval tv; struct timeval tv;
char in[4096]; 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)"); fprintf(stderr, "Testing raw UDP data to the server (skip with -r)");
for (i=0; this.running && i<3 ;i++) { 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') { if (len == 5 && in[0] == 'I') {
/* Received IPv4 address */ /* Received IPv4 address */
@ -1640,16 +1640,16 @@ handshake_raw_udp(int dns_fd, int seed)
tv.tv_sec = i + 1; tv.tv_sec = i + 1;
tv.tv_usec = 0; tv.tv_usec = 0;
send_raw_udp_login(dns_fd, this.userid, seed); send_raw_udp_login(seed);
FD_ZERO(&fds); 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) { if(r > 0) {
/* recv() needed for windows, dont change to read() */ /* 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)) { if (len >= (16 + RAW_HDR_LEN)) {
char hash[16]; char hash[16];
login_calculate(hash, 16, this.password, seed - 1); login_calculate(hash, 16, this.password, seed - 1);
@ -1671,7 +1671,7 @@ handshake_raw_udp(int dns_fd, int seed)
} }
static int 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 /* NOTE: *s may be max 59 chars; must start with "aA" for case-swap check
Returns: Returns:
-1: case swap, no need for any further test: error printed; or Ctrl-C -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); slen = strlen(s);
for (i=0; this.running && i<3 ;i++) { 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) if (read == -2)
return 0; /* hard error */ return 0; /* hard error */
@ -1741,7 +1741,7 @@ handshake_upenctest(int dns_fd, char *s)
} }
static int static int
handshake_upenc_autodetect(int dns_fd) handshake_upenc_autodetect()
/* Returns: /* Returns:
0: keep Base32 0: keep Base32
1: Base64 is okay 1: Base64 is okay
@ -1771,7 +1771,7 @@ handshake_upenc_autodetect(int dns_fd)
/* Try Base128, starting very gently to not draw attention */ /* Try Base128, starting very gently to not draw attention */
while (1) { while (1) {
res = handshake_upenctest(dns_fd, pat128a); res = handshake_upenctest(pat128a);
if (res < 0) { if (res < 0) {
/* DNS swaps case, msg already printed; or Ctrl-C */ /* DNS swaps case, msg already printed; or Ctrl-C */
return 0; return 0;
@ -1780,7 +1780,7 @@ handshake_upenc_autodetect(int dns_fd)
break; break;
} }
res = handshake_upenctest(dns_fd, pat128b); res = handshake_upenctest(pat128b);
if (res < 0) if (res < 0)
return 0; return 0;
else if (res == 0) else if (res == 0)
@ -1788,19 +1788,19 @@ handshake_upenc_autodetect(int dns_fd)
/* if this works, we can test the real stuff */ /* if this works, we can test the real stuff */
res = handshake_upenctest(dns_fd, pat128c); res = handshake_upenctest(pat128c);
if (res < 0) if (res < 0)
return 0; return 0;
else if (res == 0) else if (res == 0)
break; break;
res = handshake_upenctest(dns_fd, pat128d); res = handshake_upenctest(pat128d);
if (res < 0) if (res < 0)
return 0; return 0;
else if (res == 0) else if (res == 0)
break; break;
res = handshake_upenctest(dns_fd, pat128e); res = handshake_upenctest(pat128e);
if (res < 0) if (res < 0)
return 0; return 0;
else if (res == 0) else if (res == 0)
@ -1811,7 +1811,7 @@ handshake_upenc_autodetect(int dns_fd)
} }
/* Try Base64 (with plus sign) */ /* Try Base64 (with plus sign) */
res = handshake_upenctest(dns_fd, pat64); res = handshake_upenctest(pat64);
if (res < 0) { if (res < 0) {
/* DNS swaps case, msg already printed; or Ctrl-C */ /* DNS swaps case, msg already printed; or Ctrl-C */
return 0; return 0;
@ -1821,7 +1821,7 @@ handshake_upenc_autodetect(int dns_fd)
} }
/* Try Base64u (with _u_nderscore) */ /* Try Base64u (with _u_nderscore) */
res = handshake_upenctest(dns_fd, pat64u); res = handshake_upenctest(pat64u);
if (res < 0) { if (res < 0) {
/* DNS swaps case, msg already printed; or Ctrl-C */ /* DNS swaps case, msg already printed; or Ctrl-C */
return 0; return 0;
@ -1836,7 +1836,7 @@ handshake_upenc_autodetect(int dns_fd)
} }
static int static int
handshake_downenctest(int dns_fd, char trycodec) handshake_downenctest(char trycodec)
/* Returns: /* Returns:
0: not identical or error or timeout 0: not identical or error or timeout
1: identical string returned 1: identical string returned
@ -1850,9 +1850,9 @@ handshake_downenctest(int dns_fd, char trycodec)
for (i=0; this.running && i<3 ;i++) { 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) if (read == -2)
return 0; /* hard error */ return 0; /* hard error */
@ -1880,7 +1880,7 @@ handshake_downenctest(int dns_fd, char trycodec)
} }
static char static char
handshake_downenc_autodetect(int dns_fd) handshake_downenc_autodetect()
/* Returns codec char (or ' ' if no advanced codec works) */ /* Returns codec char (or ' ' if no advanced codec works) */
{ {
int base64ok = 0; int base64ok = 0;
@ -1896,20 +1896,20 @@ handshake_downenc_autodetect(int dns_fd)
fprintf(stderr, "Autodetecting downstream codec (use -O to override)\n"); fprintf(stderr, "Autodetecting downstream codec (use -O to override)\n");
/* Try Base64 */ /* Try Base64 */
if (handshake_downenctest(dns_fd, 'S')) if (handshake_downenctest('S'))
base64ok = 1; base64ok = 1;
else if (this.running && handshake_downenctest(dns_fd, 'U')) else if (this.running && handshake_downenctest('U'))
base64uok = 1; base64uok = 1;
/* Try Base128 only if 64 gives us some perspective */ /* Try Base128 only if 64 gives us some perspective */
if (this.running && (base64ok || base64uok)) { if (this.running && (base64ok || base64uok)) {
if (handshake_downenctest(dns_fd, 'V')) if (handshake_downenctest('V'))
base128ok = 1; base128ok = 1;
} }
/* If 128 works, then TXT may give us Raw as well */ /* If 128 works, then TXT may give us Raw as well */
if (this.running && (base128ok && this.do_qtype == T_TXT)) { if (this.running && (base128ok && this.do_qtype == T_TXT)) {
if (handshake_downenctest(dns_fd, 'R')) if (handshake_downenctest('R'))
return 'R'; return 'R';
} }
@ -1928,7 +1928,7 @@ handshake_downenc_autodetect(int dns_fd)
} }
static int static int
handshake_qtypetest(int dns_fd, int timeout) handshake_qtypetest(int timeout)
/* Returns: /* Returns:
0: doesn't work with this timeout 0: doesn't work with this timeout
1: works properly 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 byte values can be returned, which is needed for NULL/PRIVATE
to work. */ 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) if (read != slen)
return 0; /* incorrect */ return 0; /* incorrect */
@ -1984,7 +1984,7 @@ handshake_qtype_numcvt(int num)
} }
static int static int
handshake_qtype_autodetect(int dns_fd) handshake_qtype_autodetect()
/* Returns: /* Returns:
0: okay, this.do_qtype set 0: okay, this.do_qtype set
1: problem, program exit 1: problem, program exit
@ -2016,7 +2016,7 @@ handshake_qtype_autodetect(int dns_fd)
fprintf(stderr, "."); fprintf(stderr, ".");
fflush(stderr); fflush(stderr);
if (handshake_qtypetest(dns_fd, timeout)) { if (handshake_qtypetest(timeout)) {
/* okay */ /* okay */
highestworking = qtypenum; highestworking = qtypenum;
DEBUG(1, " Type %s timeout %d works", client_get_qtype(), timeout); DEBUG(1, " Type %s timeout %d works", client_get_qtype(), timeout);
@ -2053,7 +2053,7 @@ handshake_qtype_autodetect(int dns_fd)
} }
static int static int
handshake_edns0_check(int dns_fd) handshake_edns0_check()
/* Returns: /* Returns:
0: EDNS0 not supported; or Ctrl-C 0: EDNS0 not supported; or Ctrl-C
1: EDNS0 works 1: EDNS0 works
@ -2073,9 +2073,9 @@ handshake_edns0_check(int dns_fd)
for (i=0; this.running && i<3 ;i++) { 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) if (read == -2)
return 0; /* hard error */ return 0; /* hard error */
@ -2103,7 +2103,7 @@ handshake_edns0_check(int dns_fd)
} }
static void static void
handshake_switch_codec(int dns_fd, int bits) handshake_switch_codec(int bits)
{ {
char in[4096]; char in[4096];
int i; int i;
@ -2124,9 +2124,9 @@ handshake_switch_codec(int dns_fd, int bits)
for (i=0; this.running && i<5 ;i++) { 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 (read > 0) {
if (strncmp("BADLEN", in, 6) == 0) { if (strncmp("BADLEN", in, 6) == 0) {
@ -2160,7 +2160,7 @@ codec_revert:
} }
void 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]; char in[4096];
int read; int read;
@ -2185,9 +2185,9 @@ handshake_switch_options(int dns_fd, int lazy, int compression, char denc)
lazy_status, dname, comp_status); lazy_status, dname, comp_status);
for (int i = 0; this.running && i < 5; i++) { 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 (read > 0) {
if (strncmp("BADLEN", in, 6) == 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 static int
handshake_autoprobe_fragsize(int dns_fd) handshake_autoprobe_fragsize()
{ {
char in[MAX_FRAGSIZE]; char in[MAX_FRAGSIZE];
int i; int i;
@ -2310,9 +2310,9 @@ handshake_autoprobe_fragsize(int dns_fd)
/* stop the slow probing early when we have enough bytes anyway */ /* stop the slow probing early when we have enough bytes anyway */
for (i=0; this.running && i<3 ;i++) { 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) { if (read > 0) {
/* We got a reply */ /* We got a reply */
@ -2367,7 +2367,7 @@ handshake_autoprobe_fragsize(int dns_fd)
} }
static void static void
handshake_set_fragsize(int dns_fd, int fragsize) handshake_set_fragsize(int fragsize)
{ {
char in[4096]; char in[4096];
int i; 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); fprintf(stderr, "Setting downstream fragment size to max %d...\n", fragsize);
for (i=0; this.running && i<5 ;i++) { 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) { if (read > 0) {
@ -2404,7 +2404,7 @@ handshake_set_fragsize(int dns_fd, int fragsize)
} }
static void static void
handshake_set_timeout(int dns_fd) handshake_set_timeout()
{ {
char in[4096]; char in[4096];
int read, id; int read, id;
@ -2419,9 +2419,9 @@ handshake_set_timeout(int dns_fd)
for (int i = 0; this.running && i < 5; i++) { for (int i = 0; this.running && i < 5; i++) {
id = this.autodetect_server_timeout ? 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); got_response(id, 1, 0);
fprintf(stderr, "."); fprintf(stderr, ".");
@ -2447,7 +2447,7 @@ handshake_set_timeout(int dns_fd)
} }
int int
client_handshake(int dns_fd, int raw_mode, int autodetect_frag_size, int fragsize) client_handshake()
{ {
int seed; int seed;
int upcodec; 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 */ /* qtype message printed in handshake function */
if (this.do_qtype == T_UNSET) { if (this.do_qtype == T_UNSET) {
r = handshake_qtype_autodetect(dns_fd); r = handshake_qtype_autodetect();
if (r) { if (r) {
return 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()); fprintf(stderr, "Using DNS type %s queries\n", client_get_qtype());
r = handshake_version(dns_fd, &seed); r = handshake_version(&seed);
if (r) { if (r) {
return r; return r;
} }
r = handshake_login(dns_fd, seed); r = handshake_login(seed);
if (r) { if (r) {
return 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.conn = CONN_RAW_UDP;
this.max_timeout_ms = 10000; this.max_timeout_ms = 10000;
this.compression_down = 1; this.compression_down = 1;
this.compression_up = 1; this.compression_up = 1;
} else { } else {
if (raw_mode == 0) { if (this.raw_mode == 0) {
fprintf(stderr, "Skipping raw mode\n"); fprintf(stderr, "Skipping raw mode\n");
} }
dnsc_use_edns0 = 1; dnsc_use_edns0 = 1;
if (handshake_edns0_check(dns_fd) && this.running) { if (handshake_edns0_check() && this.running) {
fprintf(stderr, "Using EDNS0 extension\n"); fprintf(stderr, "Using EDNS0 extension\n");
} else if (!this.running) { } else if (!this.running) {
return -1; return -1;
@ -2495,45 +2495,45 @@ client_handshake(int dns_fd, int raw_mode, int autodetect_frag_size, int fragsiz
dnsc_use_edns0 = 0; dnsc_use_edns0 = 0;
} }
upcodec = handshake_upenc_autodetect(dns_fd); upcodec = handshake_upenc_autodetect();
if (!this.running) if (!this.running)
return -1; return -1;
if (upcodec == 1) { /* Base64 */ if (upcodec == 1) { /* Base64 */
handshake_switch_codec(dns_fd, 6); handshake_switch_codec(6);
} else if (upcodec == 2) { /* Base64u */ } else if (upcodec == 2) { /* Base64u */
handshake_switch_codec(dns_fd, 26); handshake_switch_codec(26);
} else if (upcodec == 3) { /* Base128 */ } else if (upcodec == 3) { /* Base128 */
handshake_switch_codec(dns_fd, 7); handshake_switch_codec(7);
} }
if (!this.running) if (!this.running)
return -1; return -1;
if (this.downenc == ' ') { if (this.downenc == ' ') {
this.downenc = handshake_downenc_autodetect(dns_fd); this.downenc = handshake_downenc_autodetect();
} }
if (!this.running) if (!this.running)
return -1; return -1;
/* Set options for compression, this.lazymode and downstream codec */ /* 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) if (!this.running)
return -1; return -1;
if (autodetect_frag_size) { if (this.autodetect_frag_size) {
fragsize = handshake_autoprobe_fragsize(dns_fd); this.max_downstream_frag_size = handshake_autoprobe_fragsize();
if (fragsize > MAX_FRAGSIZE) { if (this.max_downstream_frag_size > MAX_FRAGSIZE) {
/* This is very unlikely except perhaps over LAN */ /* This is very unlikely except perhaps over LAN */
fprintf(stderr, "Can transfer fragsize of %d, however iodine has been compiled with MAX_FRAGSIZE = %d." 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); " To fully utilize this connection, please recompile iodine/iodined.\n", this.max_downstream_frag_size, MAX_FRAGSIZE);
fragsize = MAX_FRAGSIZE; this.max_downstream_frag_size = MAX_FRAGSIZE;
} }
if (!fragsize) { if (!this.max_downstream_frag_size) {
return 1; return 1;
} }
} }
handshake_set_fragsize(dns_fd, fragsize); handshake_set_fragsize(this.max_downstream_frag_size);
if (!this.running) if (!this.running)
return -1; 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; this.pending_queries[i].id = -1;
/* set server window/timeout parameters and calculate RTT */ /* set server window/timeout parameters and calculate RTT */
handshake_set_timeout(dns_fd); handshake_set_timeout();
} }
return 0; return 0;

View File

@ -153,12 +153,12 @@ char *format_qtype();
char parse_encoding(char *encoding); char parse_encoding(char *encoding);
void client_set_hostname_maxlen(size_t i); 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_handshake();
int client_tunnel(int tun_fd, int dns_fd); int client_tunnel();
int parse_data(uint8_t *data, size_t len, fragment *f, int *immediate); 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); int handshake_waitdns(char *buf, size_t buflen, char cmd, int timeout);
void handshake_switch_options(int dns_fd, int lazy, int compression, char denc); void handshake_switch_options(int lazy, int compression, char denc);
int send_ping(int fd, int ping_response, int ack, int timeout); int send_ping(int ping_response, int ack, int timeout);
#endif #endif

View File

@ -24,6 +24,7 @@
#include <getopt.h> #include <getopt.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/param.h> #include <sys/param.h>
#include <ctype.h>
#include <fcntl.h> #include <fcntl.h>
#include <time.h> #include <time.h>
@ -57,11 +58,20 @@ static char *__progname;
struct client_instance this; 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 = { static struct client_instance preset_default = {
.foreground = 0,
#ifdef OPENBSD
.rtable = 0,
#endif
.debug = 0, .debug = 0,
.stats = 0, .stats = 0,
.raw_mode = 1, .raw_mode = 1,
@ -79,18 +89,56 @@ static struct client_instance preset_default = {
.windowsize_up = 8, .windowsize_up = 8,
.windowsize_down = 8, .windowsize_down = 8,
.hostname_maxlen = 0xFF, .hostname_maxlen = 0xFF,
PRESET_STATIC_VALUES
/* 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
}; };
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 static void
sighandler(int sig) sighandler(int sig)
{ {
@ -151,14 +199,16 @@ help()
fprintf(stderr, " -v, --version print version info and exit\n"); fprintf(stderr, " -v, --version print version info and exit\n");
fprintf(stderr, " -h, --help print this help 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, " -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, " 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, " -f keep running in foreground\n");
fprintf(stderr, " -D enable debug mode (add more D's to increase debug level)\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, " -d set tunnel device name\n");
fprintf(stderr, " -u drop privileges and run as specified user\n"); fprintf(stderr, " -u drop privileges and run as specified user\n");
fprintf(stderr, " -F write PID to specified file\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, " --chroot chroot to given directory\n");
fprintf(stderr, " --context apply specified SELinux context after initialization\n"); fprintf(stderr, " --context apply specified SELinux context after initialization\n");
fprintf(stderr, " --rdomain use specified routing domain (OpenBSD only)\n\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); WSAStartup(req_version, &wsa_data);
#endif #endif
srand((unsigned) time(NULL));
this.rand_seed = (uint16_t) rand();
this.chunkid = (uint16_t) rand();
this.running = 1;
#if !defined(BSD) && !defined(__GLIBC__) #if !defined(BSD) && !defined(__GLIBC__)
__progname = strrchr(argv[0], '/'); __progname = strrchr(argv[0], '/');
if (__progname == NULL) if (__progname == NULL)
@ -227,13 +272,52 @@ main(int argc, char **argv)
{"rdomain", required_argument, 0, 'R'}, {"rdomain", required_argument, 0, 'R'},
{"chrootdir", required_argument, 0, 't'}, {"chrootdir", required_argument, 0, 't'},
{"proxycommand", no_argument, 0, 'X'}, {"proxycommand", no_argument, 0, 'X'},
{"preset", required_argument, 0, 'Y'},
{NULL, 0, 0, 0} {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) { switch (choice) {
case '4': case '4':
nameserv_family = AF_INET; nameserv_family = AF_INET;
@ -318,6 +402,9 @@ main(int argc, char **argv)
break; break;
case 'I': case 'I':
this.max_timeout_ms = strtod(optarg, NULL) * 1000; this.max_timeout_ms = strtod(optarg, NULL) * 1000;
if (this.autodetect_server_timeout) {
this.server_timeout_ms = this.max_timeout_ms / 2;
}
break; break;
case 'i': case 'i':
this.server_timeout_ms = strtod(optarg, NULL) * 1000; this.server_timeout_ms = strtod(optarg, NULL) * 1000;
@ -346,6 +433,9 @@ main(int argc, char **argv)
case 'C': case 'C':
this.compression_up = atoi(optarg) & 1; this.compression_up = atoi(optarg) & 1;
break; break;
case 'Y':
/* Already processed preset: ignore */
continue;
case 'X': case 'X':
// TODO implement option for remote host/port to pipe stdin/out // TODO implement option for remote host/port to pipe stdin/out
default: 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); check_superuser(usage);
argc -= optind; argc -= optind;
@ -404,9 +499,6 @@ main(int argc, char **argv)
usage(); 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) { 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); warnx("Use a max frag size between 10 and %d bytes.", MAX_FRAGSIZE);
usage(); usage();
@ -431,7 +523,8 @@ main(int argc, char **argv)
usage(); 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!"); warnx("Server timeout (-i) must be greater than 0.1 sec and less than target interval!");
usage(); 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"); 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) { if (username != NULL) {
#ifndef WINDOWS32 #ifndef WINDOWS32
if ((pw = getpwnam(username)) == NULL) { if ((pw = getpwnam(username)) == NULL) {
@ -494,8 +579,7 @@ main(int argc, char **argv)
(a != this.nameserv_addrs_len - 1) ? ", " : ""); (a != this.nameserv_addrs_len - 1) ? ", " : "");
fprintf(stderr, "\n"); fprintf(stderr, "\n");
// TODO not pass args to client stuff - use "this" as shared instance if (client_handshake()) {
if (client_handshake(this.dns_fd, this.raw_mode, this.autodetect_frag_size, this.max_downstream_frag_size)) {
retval = 1; retval = 1;
goto cleanup2; goto cleanup2;
} }
@ -530,8 +614,7 @@ main(int argc, char **argv)
if (context != NULL) if (context != NULL)
do_setcon(context); do_setcon(context);
// todo don't pass args again. client_tunnel();
client_tunnel(this.tun_fd, this.dns_fd);
cleanup2: cleanup2:
close_dns(this.dns_fd); close_dns(this.dns_fd);