Forward non-tunnel requests to another udp port (fixes #31)
This commit is contained in:
parent
ec2d6657a0
commit
02d40c1a7b
|
@ -16,6 +16,8 @@ CHANGES:
|
|||
sends data and gets data back directly.
|
||||
- Applied patch to make iodine build on BeOS R5-BONE and Haiku,
|
||||
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"
|
||||
- Applied a few small patches from Maxim Bourmistrov and Gregor Herrmann
|
||||
|
|
8
README
8
README
|
@ -28,9 +28,11 @@ HOW TO USE:
|
|||
|
||||
Server side:
|
||||
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.
|
||||
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:
|
||||
and a server with a public IP number. If the server already runs a DNS
|
||||
server, change the listening port and then use the -b option to let
|
||||
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
|
||||
tunnel1 IN NS tunnel1host.mytunnel.com.
|
||||
|
|
|
@ -157,10 +157,11 @@ To actually use it through a relaying nameserver, see below.
|
|||
.TP
|
||||
.B Server side:
|
||||
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
|
||||
server. 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 (replace
|
||||
10.15.213.99 with your server ip):
|
||||
and a server with a public IP number. If the server already runs a DNS
|
||||
server, change the listening port and then use the \-b option to let
|
||||
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 (replace 10.15.213.99 with your server ip):
|
||||
|
||||
.nf
|
||||
tunnel1host IN A 10.15.213.99
|
||||
|
|
|
@ -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
|
||||
CLIENTOBJS = iodine.o
|
||||
CLIENT = ../bin/iodine
|
||||
SERVEROBJS = iodined.o user.o
|
||||
SERVEROBJS = iodined.o user.o fw_query.o
|
||||
SERVER = ../bin/iodined
|
||||
|
||||
OS = `uname | tr "a-z" "A-Z"`
|
||||
|
|
12
src/dns.c
12
src/dns.c
|
@ -98,6 +98,18 @@ dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_
|
|||
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
|
||||
dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, size_t packetlen)
|
||||
{
|
||||
|
|
|
@ -25,6 +25,7 @@ typedef enum {
|
|||
} qr_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);
|
||||
|
||||
#endif /* _DNS_H_ */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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__*/
|
||||
|
142
src/iodined.c
142
src/iodined.c
|
@ -46,6 +46,7 @@
|
|||
#include "user.h"
|
||||
#include "login.h"
|
||||
#include "tun.h"
|
||||
#include "fw_query.h"
|
||||
#include "version.h"
|
||||
|
||||
static int running = 1;
|
||||
|
@ -57,6 +58,7 @@ static int check_ip;
|
|||
static int my_mtu;
|
||||
static in_addr_t my_ip;
|
||||
|
||||
static int bind_port;
|
||||
static int debug;
|
||||
|
||||
#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
|
||||
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;
|
||||
int read;
|
||||
|
@ -368,29 +444,44 @@ tunnel_dns(int tun_fd, int dns_fd)
|
|||
}
|
||||
} else {
|
||||
/* Forward query to other port ? */
|
||||
if (bind_fd) {
|
||||
forward_query(bind_fd, &q);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
tunnel(int tun_fd, int dns_fd)
|
||||
tunnel(int tun_fd, int dns_fd, int bind_fd)
|
||||
{
|
||||
struct timeval tv;
|
||||
fd_set fds;
|
||||
int i;
|
||||
|
||||
while (running) {
|
||||
int maxfd;
|
||||
|
||||
tv.tv_sec = 1;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
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 */
|
||||
if(!all_users_waiting_to_send()) {
|
||||
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 (running)
|
||||
|
@ -403,9 +494,13 @@ tunnel(int tun_fd, int dns_fd)
|
|||
continue;
|
||||
}
|
||||
if(FD_ISSET(dns_fd, &fds)) {
|
||||
tunnel_dns(tun_fd, dns_fd);
|
||||
tunnel_dns(tun_fd, dns_fd, bind_fd);
|
||||
continue;
|
||||
}
|
||||
if(FD_ISSET(bind_fd, &fds)) {
|
||||
tunnel_bind(bind_fd, dns_fd);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -459,7 +554,7 @@ usage() {
|
|||
extern char *__progname;
|
||||
|
||||
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);
|
||||
exit(2);
|
||||
}
|
||||
|
@ -470,7 +565,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] [-P password]"
|
||||
"[-l ip address to listen on] [-p port] [-b port] [-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");
|
||||
|
@ -484,6 +579,7 @@ help() {
|
|||
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(" -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("tunnel_ip is the IP number of the local tunnel interface.\n");
|
||||
printf("topdomain is the FQDN that is delegated to this server.\n");
|
||||
|
@ -510,6 +606,12 @@ main(int argc, char **argv)
|
|||
char *device;
|
||||
int dnsd_fd;
|
||||
int tun_fd;
|
||||
|
||||
/* settings for forwarding normal DNS to
|
||||
* local real DNS server */
|
||||
int bind_fd;
|
||||
int bind_enable;
|
||||
|
||||
int choice;
|
||||
int port;
|
||||
int mtu;
|
||||
|
@ -519,6 +621,8 @@ main(int argc, char **argv)
|
|||
newroot = NULL;
|
||||
device = NULL;
|
||||
foreground = 0;
|
||||
bind_enable = 0;
|
||||
bind_fd = 0;
|
||||
mtu = 1024;
|
||||
listen_ip = INADDR_ANY;
|
||||
port = 53;
|
||||
|
@ -538,8 +642,9 @@ main(int argc, char **argv)
|
|||
|
||||
memset(password, 0, sizeof(password));
|
||||
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) {
|
||||
case 'v':
|
||||
version();
|
||||
|
@ -577,6 +682,10 @@ main(int argc, char **argv)
|
|||
case 'p':
|
||||
port = atoi(optarg);
|
||||
break;
|
||||
case 'b':
|
||||
bind_enable = 1;
|
||||
bind_port = atoi(optarg);
|
||||
break;
|
||||
case 'P':
|
||||
strncpy(password, optarg, sizeof(password));
|
||||
password[sizeof(password)-1] = 0;
|
||||
|
@ -629,6 +738,16 @@ main(int argc, char **argv)
|
|||
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) {
|
||||
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);
|
||||
|
@ -655,6 +774,9 @@ main(int argc, char **argv)
|
|||
goto cleanup1;
|
||||
if ((dnsd_fd = open_dns(port, listen_ip)) == -1)
|
||||
goto cleanup2;
|
||||
if (bind_enable)
|
||||
if ((bind_fd = open_dns(0, INADDR_ANY)) == -1)
|
||||
goto cleanup3;
|
||||
|
||||
my_ip = inet_addr(argv[0]);
|
||||
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:
|
||||
close_dns(dnsd_fd);
|
||||
cleanup1:
|
||||
|
|
Loading…
Reference in New Issue