1 /* ----------------------------------------------------------------------------
4 (C) 2007 Daniele Lacamera
7 NSTX -- tunneling network-packets over DNS
9 (C) 2000 by Florian Heinz and Julien Oster
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License version 2, as
13 published by the Free Software Foundation.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 -------------------------------------------------------------------------- */
29 #include <sys/types.h>
30 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
43 #include <vdecommon.h>
56 static void nstx_getpacket (void);
57 static struct nstx_senditem
* alloc_senditem(void);
58 static void queue_senditem(const char *buf
, int len
);
59 static char *dequeue_senditem (int *len
);
60 struct nstx_senditem
* nstx_sendlist
= NULL
;
61 static char *vdesock
= NULL
;
62 static void nstxc_handle_reply(char *, int);
63 static int nstxc_send_packet(char *, int);
66 usage(const char *prog
, int code
)
68 fprintf (stderr
, "usage: %s [-c DNSSERVER] [-s VDESOCK] [-i IP] [-D] <domainname>\n"
70 "\t-i IP (bind to port 53 on this IP only)\n"
72 "\t-D (call daemon(3) to detach from terminal)\n"
74 "\t-c DNSSERVER: Client mode. Tries to 'connect' to DNSSERVER.\n"
75 "\t\t(if this is not specified, server mode will be enabled by default.) \n"
77 "\t-s VDESOCKET: Attach to socket VDESOCKET \n"
78 "\t\t(if not specified, use stdin/stdout) \n"
81 "\t%s -s /tmp/vde.ctl -c 1.2.3.4 tun.vdevirtualnetwork.foo [Client mode]\n"
82 "\t%s -s /var/vde-master-switch.ctl tun.vdevirtualnetwork.foo [Server mode]\n", prog
, prog
, prog
);
86 int main (int argc
, char *argv
[]) {
88 const char *dir
= NULL
;
89 in_addr_t bindto
= INADDR_ANY
;
92 int logmask
= LOG_UPTO(LOG_INFO
);
93 char *clientmode_serveraddress
=NULL
;
98 while ((ch
= getopt(argc
, argv
, "Dh:i:s:c:")) != -1) {
101 bindto
= inet_addr(optarg
);
102 if (bindto
== INADDR_NONE
) {
103 fprintf(stderr
, "`%s' is not an IP-address\n",
112 logmask
= LOG_UPTO(LOG_DEBUG
);
115 vdesock
= strdup(optarg
);
118 usage(argv
[0], 0); /* no return */
120 clientmode_serveraddress
= strdup(optarg
);
123 usage(argv
[0], EX_USAGE
); /* no return */
127 if (argc
- optind
< 1)
128 usage(argv
[0], EX_USAGE
);
130 dns_setsuffix(argv
[optind
]);
133 if (uid
&& setuid(uid
)) {
134 syslog(LOG_ERR
, "Can't setuid to %ld: %m", (long)uid
);
137 if (daemonize
&& daemon(0, 0)) {
138 syslog(LOG_ERR
, "Can't become a daemon: %m");
142 if (clientmode_serveraddress
!=NULL
){
143 fprintf(stderr
,"Client Mode\n");
146 open_ns(clientmode_serveraddress
);
147 init_vdesock(vdesock
);
150 msg
= nstx_select(1);
152 if (msg
->src
== FROMNS
) {
153 nstxc_handle_reply (msg
->data
, msg
->len
);
154 } else if (msg
->src
== FROMTUN
) {
155 nstxc_send_packet (msg
->data
, msg
->len
);
159 while (queuelen() < DRQLEN
)
160 nstxc_send_packet (NULL
, 0);
166 fprintf(stderr
,"Server Mode\n");
167 open_ns_bind(bindto
);
168 init_vdesock(vdesock
);
171 /* Open the log-socket now (with LOG_NDELAY) before chroot-ing */
172 openlog(argv
[0], LOG_PERROR
|LOG_PID
|LOG_CONS
|LOG_NDELAY
, LOG_DAEMON
);
174 syslog(LOG_ERR
, "Can't chroot to %s: %m", dir
);
175 exit(EXIT_FAILURE
); /* Too many possible causes */
178 openlog(argv
[0], LOG_PERROR
|LOG_PID
|LOG_CONS
, LOG_DAEMON
);
189 struct nstx_senditem
* nstx_get_senditem(void) {
190 struct nstx_senditem
*ptr
= nstx_sendlist
;
196 nstx_sendlist
= nstx_sendlist
->next
;
201 static void do_timeout (struct nstxqueue
*q
)
208 dns_setid(pkt
, q
->id
);
209 dns_settype(pkt
, DNS_RESPONSE
);
210 dns_addanswer(pkt
, "\xb4\x00\x00\x00", 4, dns_addquery(pkt
, q
->name
));
211 buf
= (char*)dns_constructpacket (pkt
, &len
);
212 sendns(buf
, len
, &q
->peer
);
216 void nstx_getpacket (void) {
218 const char *name
, *buf
, *data
;
220 struct nstxqueue
*qitem
;
223 msg
= nstx_select(1);
226 if (msg
->src
== FROMNS
) {
227 pkt
= dns_extractpkt((unsigned char*)msg
->data
, msg
->len
);
230 name
= dns_getquerydata(pkt
);
233 syslog(LOG_DEBUG
, "getpacket: asked for name `%s'",
235 queueitem(pkt
->id
, name
, &msg
->peer
);
236 if ((data
= dns_fqdn2data(name
)) &&
237 (buf
= nstx_decode((unsigned char*)data
, &len
)))
239 nstx_handlepacket(buf
, len
, &send_vde
);
244 } else if (msg
->src
== FROMTUN
)
245 queue_senditem(msg
->data
, msg
->len
);
251 qitem
= dequeueitem(-1);
253 dns_setid(pkt
, qitem
->id
);
254 dns_settype(pkt
, DNS_RESPONSE
);
255 link
= dns_addquery(pkt
, qitem
->name
);
256 len
= dns_getfreespace(pkt
, DNS_RESPONSE
);
257 buf
= dequeue_senditem(&len
);
258 dns_addanswer(pkt
, buf
, len
, link
);
259 buf
= (char*)dns_constructpacket(pkt
, &len
);
260 sendns(buf
, len
, &qitem
->peer
);
262 timeoutqueue(do_timeout
);
267 static struct nstx_senditem
* alloc_senditem(void) {
268 struct nstx_senditem
*ptr
= nstx_sendlist
;
270 if (!nstx_sendlist
) {
271 ptr
= nstx_sendlist
= malloc(sizeof(struct nstx_senditem
));
275 ptr
->next
= malloc(sizeof(struct nstx_senditem
));
279 memset(ptr
, 0, sizeof(struct nstx_senditem
));
285 queue_senditem(const char *buf
, int len
) {
287 struct nstx_senditem
*item
;
289 item
= alloc_senditem();
290 item
->data
= malloc(len
);
291 memcpy(item
->data
, buf
, len
);
297 dequeue_senditem (int *len
) {
299 struct nstx_senditem
*item
= nstx_sendlist
;
303 remain
= item
->len
- item
->offset
;
304 dlen
= *len
- sizeof(struct nstxhdr
);
307 *len
= dlen
+ sizeof(struct nstxhdr
);
308 buf
= realloc(buf
, *len
);
309 nh
= (struct nstxhdr
*)buf
;
310 memset(nh
, 0, sizeof(struct nstxhdr
));
311 memcpy(buf
+sizeof(struct nstxhdr
), item
->data
+ item
->offset
, dlen
);
312 nh
->magic
= NSTX_MAGIC
;
313 nh
->seq
= item
->seq
++;
315 item
->offset
+= dlen
;
316 if (item
->offset
== item
->len
) {
318 nstx_sendlist
= item
->next
;
326 static void nstxc_handle_reply (char * reply
, int len
) {
331 pkt
= dns_extractpkt ((unsigned char*)reply
, len
);
334 while ((data
= dns_getanswerdata(pkt
, &datalen
))) {
335 data
= (char*)txt2data((unsigned char*)data
, &datalen
);
336 nstx_handlepacket (data
, datalen
, &send_vde
);
338 dequeueitem(pkt
->id
);
342 static int nstxc_send_packet (char *data
, int datalen
) {
353 nh
.magic
= NSTX_MAGIC
;
360 dns_settype(pkt
, DNS_QUERY
);
361 dns_setid(pkt
, nsid
);
363 l
= dns_getfreespace(pkt
, DNS_QUERY
);
365 printf("Fatal: no free space in dns-packet?!\n");
374 memcpy (p
, (char*)&nh
, sizeof(nh
));
376 memcpy (p
+ sizeof(nh
), data
, l
);
380 dns_addquery(pkt
, dns_data2fqdn(nstx_encode((unsigned char*)p
, sizeof(nh
)+l
)));
382 p
= (char*)dns_constructpacket(pkt
, &l
);