Forward non-tunnel requests to another udp port (fixes #31)

This commit is contained in:
Erik Ekman 2008-08-07 21:18:15 +00:00 committed by Erik Ekman
parent ec2d6657a0
commit 02d40c1a7b
9 changed files with 244 additions and 17 deletions

View file

@ -16,6 +16,8 @@ CHANGES:
sends data and gets data back directly. sends data and gets data back directly.
- Applied patch to make iodine build on BeOS R5-BONE and Haiku, - Applied patch to make iodine build on BeOS R5-BONE and Haiku,
from Francois Revol. Still work to do to get tun device working. from Francois Revol. Still work to do to get tun device working.
- Added capability to forward DNS queries outside tunnel domain to
a nameserver on localhost. Use -b port to enable.
2008-08-06: 0.4.2 "Opened Zone" 2008-08-06: 0.4.2 "Opened Zone"
- Applied a few small patches from Maxim Bourmistrov and Gregor Herrmann - Applied a few small patches from Maxim Bourmistrov and Gregor Herrmann

8
README
View file

@ -28,9 +28,11 @@ HOW TO USE:
Server side: Server side:
To use this tunnel, you need control over a real domain (like mytunnel.com), To use this tunnel, you need control over a real domain (like mytunnel.com),
and a server with a public IP number that does not yet run a DNS server. and a server with a public IP number. If the server already runs a DNS
Then, delegate a subdomain (say, tunnel1.mytunnel.com) to the server. server, change the listening port and then use the -b option to let
If you use BIND for the domain, add these lines to the zone file: iodined forward the DNS requests. Then, delegate a subdomain
(say, tunnel1.mytunnel.com) to the server. If you use BIND for the domain,
add these lines to the zone file:
tunnel1host IN A 10.15.213.99 tunnel1host IN A 10.15.213.99
tunnel1 IN NS tunnel1host.mytunnel.com. tunnel1 IN NS tunnel1host.mytunnel.com.

View file

@ -157,10 +157,11 @@ To actually use it through a relaying nameserver, see below.
.TP .TP
.B Server side: .B Server side:
To use this tunnel, you need control over a real domain (like mytunnel.com), To use this tunnel, you need control over a real domain (like mytunnel.com),
and a server with a static public IP number that does not yet run a DNS and a server with a public IP number. If the server already runs a DNS
server. Then, delegate a subdomain (say, tunnel1.mytunnel.com) to the server. server, change the listening port and then use the \-b option to let
If you use BIND for the domain, add these lines to the zone file (replace iodined forward the DNS requests. Then, delegate a subdomain
10.15.213.99 with your server ip): (say, tunnel1.mytunnel.com) to the server. If you use BIND for the domain,
add these lines to the zone file (replace 10.15.213.99 with your server ip):
.nf .nf
tunnel1host IN A 10.15.213.99 tunnel1host IN A 10.15.213.99

View file

@ -2,7 +2,7 @@ CC = gcc
COMMONOBJS = tun.o dns.o read.o encoding.o login.o base32.o base64.o md5.o common.o COMMONOBJS = tun.o dns.o read.o encoding.o login.o base32.o base64.o md5.o common.o
CLIENTOBJS = iodine.o CLIENTOBJS = iodine.o
CLIENT = ../bin/iodine CLIENT = ../bin/iodine
SERVEROBJS = iodined.o user.o SERVEROBJS = iodined.o user.o fw_query.o
SERVER = ../bin/iodined SERVER = ../bin/iodined
OS = `uname | tr "a-z" "A-Z"` OS = `uname | tr "a-z" "A-Z"`

View file

@ -98,6 +98,18 @@ dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_
return len; return len;
} }
short
dns_get_id(char *packet, size_t packetlen)
{
HEADER *header;
header = (HEADER*)packet;
if (packetlen < sizeof(HEADER))
return 0;
return ntohs(header->id);
}
int int
dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, size_t packetlen) dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, size_t packetlen)
{ {

View file

@ -25,6 +25,7 @@ typedef enum {
} qr_t; } qr_t;
int dns_encode(char *, size_t, struct query *, qr_t, char *, size_t); int dns_encode(char *, size_t, struct query *, qr_t, char *, size_t);
short dns_get_id(char *packet, size_t packetlen);
int dns_decode(char *, size_t, struct query *, qr_t, char *, size_t); int dns_decode(char *, size_t, struct query *, qr_t, char *, size_t);
#endif /* _DNS_H_ */ #endif /* _DNS_H_ */

49
src/fw_query.c Normal file
View file

@ -0,0 +1,49 @@
/*
* Copyright (c) 2008 Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <string.h>
#include "fw_query.h"
static struct fw_query fwq[FW_QUERY_CACHE_SIZE];
static int fwq_ix;
void fw_query_init()
{
memset(fwq, 0, sizeof(struct fw_query) * FW_QUERY_CACHE_SIZE);
fwq_ix = 0;
}
void fw_query_put(struct fw_query *fw_query)
{
memcpy(&(fwq[fwq_ix]), fw_query, sizeof(struct fw_query));
++fwq_ix;
if (fwq_ix >= FW_QUERY_CACHE_SIZE)
fwq_ix = 0;
}
void fw_query_get(short query_id, struct fw_query **fw_query)
{
int i;
*fw_query = NULL;
for (i = 0; i < FW_QUERY_CACHE_SIZE; i++) {
if (fwq[i].id == query_id) {
*fw_query = &(fwq[i]);
return;
}
}
}

36
src/fw_query.h Normal file
View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2008 Erik Ekman <yarrick@kryo.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __FW_QUERY_H__
#define __FW_QUERY_H__
#include <netinet/in.h>
#include <netinet/in_systm.h>
#define FW_QUERY_CACHE_SIZE 16
struct fw_query {
struct sockaddr addr;
int addrlen;
short id;
};
void fw_query_init();
void fw_query_put(struct fw_query *fw_query);
void fw_query_get(short query_id, struct fw_query **fw_query);
#endif /*__FW_QUERY_H__*/

View file

@ -46,6 +46,7 @@
#include "user.h" #include "user.h"
#include "login.h" #include "login.h"
#include "tun.h" #include "tun.h"
#include "fw_query.h"
#include "version.h" #include "version.h"
static int running = 1; static int running = 1;
@ -57,6 +58,7 @@ static int check_ip;
static int my_mtu; static int my_mtu;
static in_addr_t my_ip; static in_addr_t my_ip;
static int bind_port;
static int debug; static int debug;
#if !defined(BSD) && !defined(__GLIBC__) #if !defined(BSD) && !defined(__GLIBC__)
@ -330,8 +332,82 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
} }
} }
static void
forward_query(int bind_fd, struct query *q)
{
char buf[64*1024];
int len;
struct fw_query fwq;
struct sockaddr_in *myaddr;
in_addr_t newaddr;
len = dns_encode(buf, sizeof(buf), q, QR_QUERY, q->name, strlen(q->name));
/* Store sockaddr for q->id */
memcpy(&(fwq.addr), &(q->from), q->fromlen);
fwq.addrlen = q->fromlen;
fwq.id = q->id;
fw_query_put(&fwq);
newaddr = inet_addr("127.0.0.1");
myaddr = (struct sockaddr_in *) &(q->from);
memcpy(&(myaddr->sin_addr), &newaddr, sizeof(in_addr_t));
myaddr->sin_port = htons(bind_port);
if (debug >= 1) {
printf("TX: send query %u to DNS (port %d)\n", (q->id & 0xffff), bind_port);
}
if (sendto(bind_fd, buf, len, 0, (struct sockaddr*)&q->from, q->fromlen) <= 0) {
warn("forward query error");
}
}
static int static int
tunnel_dns(int tun_fd, int dns_fd) tunnel_bind(int bind_fd, int dns_fd)
{
char packet[64*1024];
struct sockaddr_in from;
socklen_t fromlen;
struct fw_query *query;
short id;
int r;
fromlen = sizeof(struct sockaddr);
r = recvfrom(bind_fd, packet, sizeof(packet), 0, (struct sockaddr*)&from, &fromlen);
if (r <= 0)
return 0;
id = dns_get_id(packet, r);
if (debug >= 1) {
printf("RX: Got response on query %u from DNS\n", (id & 0xFFFF));
}
/* Get sockaddr from id */
fw_query_get(id, &query);
if (!query && debug >= 1) {
printf("Lost sender of id %u, dropping reply\n", (id & 0xFFFF));
return 0;
}
if (debug >= 1) {
struct sockaddr_in *in;
in = (struct sockaddr_in *) &(query->addr);
printf("TX: client %s id %u, %d bytes\n",
inet_ntoa(in->sin_addr), (id & 0xffff), r);
}
if (sendto(dns_fd, packet, r, 0, (const struct sockaddr *) &(query->addr), query->addrlen) <= 0) {
warn("forward reply error");
}
return 0;
}
static int
tunnel_dns(int tun_fd, int dns_fd, int bind_fd)
{ {
struct query q; struct query q;
int read; int read;
@ -368,29 +444,44 @@ tunnel_dns(int tun_fd, int dns_fd)
} }
} else { } else {
/* Forward query to other port ? */ /* Forward query to other port ? */
if (bind_fd) {
forward_query(bind_fd, &q);
}
} }
return 0; return 0;
} }
static int static int
tunnel(int tun_fd, int dns_fd) tunnel(int tun_fd, int dns_fd, int bind_fd)
{ {
struct timeval tv; struct timeval tv;
fd_set fds; fd_set fds;
int i; int i;
while (running) { while (running) {
int maxfd;
tv.tv_sec = 1; tv.tv_sec = 1;
tv.tv_usec = 0; tv.tv_usec = 0;
FD_ZERO(&fds); FD_ZERO(&fds);
FD_SET(dns_fd, &fds);
maxfd = dns_fd;
if (bind_fd) {
/* wait for replies from real DNS */
FD_SET(bind_fd, &fds);
maxfd = MAX(bind_fd, maxfd);
}
/* TODO : use some kind of packet queue */ /* TODO : use some kind of packet queue */
if(!all_users_waiting_to_send()) { if(!all_users_waiting_to_send()) {
FD_SET(tun_fd, &fds); FD_SET(tun_fd, &fds);
maxfd = MAX(tun_fd, maxfd);
} }
FD_SET(dns_fd, &fds);
i = select(MAX(tun_fd, dns_fd) + 1, &fds, NULL, NULL, &tv); i = select(maxfd + 1, &fds, NULL, NULL, &tv);
if(i < 0) { if(i < 0) {
if (running) if (running)
@ -403,9 +494,13 @@ tunnel(int tun_fd, int dns_fd)
continue; continue;
} }
if(FD_ISSET(dns_fd, &fds)) { if(FD_ISSET(dns_fd, &fds)) {
tunnel_dns(tun_fd, dns_fd); tunnel_dns(tun_fd, dns_fd, bind_fd);
continue; continue;
} }
if(FD_ISSET(bind_fd, &fds)) {
tunnel_bind(bind_fd, dns_fd);
continue;
}
} }
return 0; return 0;
@ -459,7 +554,7 @@ usage() {
extern char *__progname; extern char *__progname;
printf("Usage: %s [-v] [-h] [-c] [-s] [-f] [-D] [-u user] [-t chrootdir] [-d device] [-m mtu] " 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] [-P password]" "[-l ip address to listen on] [-p port] [-b port] [-P password]"
" tunnel_ip topdomain\n", __progname); " tunnel_ip topdomain\n", __progname);
exit(2); exit(2);
} }
@ -470,7 +565,7 @@ help() {
printf("iodine IP over DNS tunneling server\n"); 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] " 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] [-P password]" "[-l ip address to listen on] [-p port] [-b port] [-P password]"
" tunnel_ip topdomain\n", __progname); " tunnel_ip topdomain\n", __progname);
printf(" -v to print version info and exit\n"); printf(" -v to print version info and exit\n");
printf(" -h to print this help and exit\n"); printf(" -h to print this help and exit\n");
@ -484,6 +579,7 @@ help() {
printf(" -m mtu to set tunnel device mtu\n"); printf(" -m mtu to set tunnel device mtu\n");
printf(" -l ip address to listen on for incoming dns traffic (default 0.0.0.0)\n"); 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(" -p port to listen on for incoming dns traffic (default 53)\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(" -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"); printf("tunnel_ip is the IP number of the local tunnel interface.\n");
printf("topdomain is the FQDN that is delegated to this server.\n"); printf("topdomain is the FQDN that is delegated to this server.\n");
@ -510,6 +606,12 @@ main(int argc, char **argv)
char *device; char *device;
int dnsd_fd; int dnsd_fd;
int tun_fd; int tun_fd;
/* settings for forwarding normal DNS to
* local real DNS server */
int bind_fd;
int bind_enable;
int choice; int choice;
int port; int port;
int mtu; int mtu;
@ -519,6 +621,8 @@ main(int argc, char **argv)
newroot = NULL; newroot = NULL;
device = NULL; device = NULL;
foreground = 0; foreground = 0;
bind_enable = 0;
bind_fd = 0;
mtu = 1024; mtu = 1024;
listen_ip = INADDR_ANY; listen_ip = INADDR_ANY;
port = 53; port = 53;
@ -538,8 +642,9 @@ main(int argc, char **argv)
memset(password, 0, sizeof(password)); memset(password, 0, sizeof(password));
srand(time(NULL)); srand(time(NULL));
fw_query_init();
while ((choice = getopt(argc, argv, "vcsfhDu:t:d:m:l:p:P:")) != -1) { while ((choice = getopt(argc, argv, "vcsfhDu:t:d:m:l:p:b:P:")) != -1) {
switch(choice) { switch(choice) {
case 'v': case 'v':
version(); version();
@ -577,6 +682,10 @@ main(int argc, char **argv)
case 'p': case 'p':
port = atoi(optarg); port = atoi(optarg);
break; break;
case 'b':
bind_enable = 1;
bind_port = atoi(optarg);
break;
case 'P': case 'P':
strncpy(password, optarg, sizeof(password)); strncpy(password, optarg, sizeof(password));
password[sizeof(password)-1] = 0; password[sizeof(password)-1] = 0;
@ -629,6 +738,16 @@ main(int argc, char **argv)
usage(); usage();
} }
if(bind_enable) {
if (bind_port < 1 || bind_port > 65535 || bind_port == port) {
warnx("Bad DNS server port number given.\n");
usage();
/* NOTREACHED */
}
printf("Requests for domains outside of %s will be forwarded to port %d\n",
topdomain, bind_port);
}
if (port != 53) { if (port != 53) {
printf("ALERT! Other dns servers expect you to run on port 53.\n"); printf("ALERT! Other dns servers expect you to run on port 53.\n");
printf("You must manually forward port 53 to port %d for things to work.\n", port); printf("You must manually forward port 53 to port %d for things to work.\n", port);
@ -655,6 +774,9 @@ main(int argc, char **argv)
goto cleanup1; goto cleanup1;
if ((dnsd_fd = open_dns(port, listen_ip)) == -1) if ((dnsd_fd = open_dns(port, listen_ip)) == -1)
goto cleanup2; goto cleanup2;
if (bind_enable)
if ((bind_fd = open_dns(0, INADDR_ANY)) == -1)
goto cleanup3;
my_ip = inet_addr(argv[0]); my_ip = inet_addr(argv[0]);
my_mtu = mtu; my_mtu = mtu;
@ -678,8 +800,10 @@ main(int argc, char **argv)
} }
} }
tunnel(tun_fd, dnsd_fd); tunnel(tun_fd, dnsd_fd, bind_fd);
cleanup3:
close_dns(bind_fd);
cleanup2: cleanup2:
close_dns(dnsd_fd); close_dns(dnsd_fd);
cleanup1: cleanup1: