diff --git a/CHANGELOG b/CHANGELOG index 320e083..d9c27ca 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -13,7 +13,8 @@ CHANGES: a nameserver on localhost. Use -b port to enable. - iodine client now shuts down if it detects a server restart. - iodined now replies to NS request on its own domain, fixes issue #33. - The destination IP address is sent as reply. + The destination IP address is sent as reply. Use -n to specify + a specific IP address to return (if behind NAT etc). - Upstream data is now Base64 encoded if relay server preserves case and supports the plus (+) character in domain names, fixes #16. diff --git a/man/iodine.8 b/man/iodine.8 index 92d8040..08bbd57 100644 --- a/man/iodine.8 +++ b/man/iodine.8 @@ -27,17 +27,23 @@ iodine, iodined \- tunnel IPv4 over DNS .B iodined [-c] [-s] [-f] [-D] [-u .I user -.B ] [-P -.I password .B ] [-t .I chrootdir +.B ] [-d +.I device .B ] [-m .I mtu .B ] [-l .I listen_ip -.B ] [-d -.I device -.B ] +.B ] [-p +.I port +.B ] [-n +.I external ip +.B ] [-b +.I dnsport +.B ] [-P +.I password +.B ] .I tunnel_ip .I topdomain .SH DESCRIPTION @@ -68,14 +74,14 @@ Drop privileges and run as user 'user' after setting up tunnel. .B -t chrootdir Chroot to 'chrootdir' after setting up tunnel. .TP +.B -d device +Use the TUN device 'device' instead of the normal one, which is dnsX on Linux +and otherwise tunX. +.TP .B -P password Use 'password' to authenticate. If not used, .B stdin will be used as input. Only the first 32 characters will be used. -.TP -.B -d device -Use the TUN device 'device' instead of the normal one, which is dnsX on Linux -and otherwise tunX. .SS Server Options: .TP .B -c @@ -100,6 +106,14 @@ connections. Make the server listen on 'port' instead of 53 for traffic. .B Note: You must make sure the dns requests are forwarded to this port yourself. +.TP +.B -n external ip +The IP address to return in NS responses. Default is to return the address used +as destination in the query. +.TP +.B -b dnsport +If this port is specified, all incoming requests not inside the tunnel domain +will be forwarded to this port on localhost, to be handled by a real dns. .SS Client Arguments: .TP .B nameserver diff --git a/src/iodined.c b/src/iodined.c index ef5470e..3ddb752 100644 --- a/src/iodined.c +++ b/src/iodined.c @@ -60,6 +60,8 @@ static int check_ip; static int my_mtu; static in_addr_t my_ip; +static in_addr_t ns_ip; + static int bind_port; static int debug; @@ -353,6 +355,10 @@ handle_ns_request(int dns_fd, struct query *q) char buf[64*1024]; int len; + if (ns_ip != INADDR_ANY) { + memcpy(&q->destination.s_addr, &ns_ip, sizeof(in_addr_t)); + } + len = dns_encode_ns_response(buf, sizeof(buf), q, topdomain); if (debug >= 1) { @@ -636,7 +642,7 @@ usage() { printf("Usage: %s [-v] [-h] [-c] [-s] [-f] [-D] [-u user] " "[-t chrootdir] [-d device] [-m mtu] " - "[-l ip address to listen on] [-p port] [-b port] [-P password]" + "[-l ip address to listen on] [-p port] [-n external ip] [-b dnsport] [-P password]" " tunnel_ip topdomain\n", __progname); exit(2); } @@ -648,7 +654,7 @@ help() { printf("iodine IP over DNS tunneling server\n"); printf("Usage: %s [-v] [-h] [-c] [-s] [-f] [-D] [-u user] " "[-t chrootdir] [-d device] [-m mtu] " - "[-l ip address to listen on] [-p port] [-b port] [-P password]" + "[-l ip address to listen on] [-p port] [-n external ip] [-b dnsport] [-P password]" " tunnel_ip topdomain\n", __progname); printf(" -v to print version info and exit\n"); printf(" -h to print this help and exit\n"); @@ -664,6 +670,7 @@ help() { printf(" -l ip address to listen on for incoming dns traffic " "(default 0.0.0.0)\n"); printf(" -p port to listen on for incoming dns traffic (default 53)\n"); + printf(" -n ip to respond with to NS queries\n"); printf(" -b port to forward normal DNS queries to (on localhost)\n"); printf(" -P password used for authentication (max 32 chars will be used)\n"); printf("tunnel_ip is the IP number of the local tunnel interface.\n"); @@ -711,6 +718,7 @@ main(int argc, char **argv) mtu = 1024; listen_ip = INADDR_ANY; port = 53; + ns_ip = INADDR_ANY; check_ip = 1; skipipconfig = 0; debug = 0; @@ -729,7 +737,7 @@ main(int argc, char **argv) srand(time(NULL)); fw_query_init(); - while ((choice = getopt(argc, argv, "vcsfhDu:t:d:m:l:p:b:P:")) != -1) { + while ((choice = getopt(argc, argv, "vcsfhDu:t:d:m:l:p:n:b:P:")) != -1) { switch(choice) { case 'v': version(); @@ -767,6 +775,9 @@ main(int argc, char **argv) case 'p': port = atoi(optarg); break; + case 'n': + ns_ip = inet_addr(optarg); + break; case 'b': bind_enable = 1; bind_port = atoi(optarg); @@ -794,6 +805,13 @@ main(int argc, char **argv) if (argc != 2) usage(); + + my_ip = inet_addr(argv[0]); + + if (my_ip == INADDR_NONE) { + warnx("Bad IP address to use inside tunnel.\n"); + usage(); + } topdomain = strdup(argv[1]); if(strlen(topdomain) <= 128) { @@ -848,7 +866,12 @@ main(int argc, char **argv) warnx("Bad IP address to listen on.\n"); usage(); } - + + if (ns_ip == INADDR_NONE) { + warnx("Bad IP address to return as nameserver.\n"); + usage(); + } + if (strlen(password) == 0) read_password(password, sizeof(password)); @@ -863,7 +886,6 @@ main(int argc, char **argv) if ((bind_fd = open_dns(0, INADDR_ANY)) == -1) goto cleanup3; - my_ip = inet_addr(argv[0]); my_mtu = mtu; init_users(my_ip);