tagging vde-2 version 2.3.2
[vde.git] / 2.3.2 / src / vde_over_ns / vde_over_ns.c
blob209b2a09f27fbff58914ec80eb748228c4a033d5
1 /* ----------------------------------------------------------------------------
3 VDE_OVER_NS
4 (C) 2007 Daniele Lacamera
6 Derived from:
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 -------------------------------------------------------------------------- */
26 #include <stdio.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <fcntl.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
34 #include <errno.h>
35 #include <time.h>
36 #include <stdlib.h>
37 #include <pwd.h>
38 #include <sysexits.h>
39 #include <syslog.h>
41 #include <config.h>
42 #include <vde.h>
43 #include <vdecommon.h>
45 #include "fun.h"
46 #include "pstack.h"
47 #include "dns.h"
49 #define DNSTIMEOUT 3
50 #define DRQLEN 10
52 #define BUFLEN 2000
54 static int nsid;
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);
65 static void
66 usage(const char *prog, int code)
68 fprintf (stderr, "usage: %s [-c DNSSERVER] [-s VDESOCK] [-i IP] [-D] <domainname>\n"
69 "Options:\n"
70 "\t-i IP (bind to port 53 on this IP only)\n"
71 "\n"
72 "\t-D (call daemon(3) to detach from terminal)\n"
73 "\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"
76 "\n"
77 "\t-s VDESOCKET: Attach to socket VDESOCKET \n"
78 "\t\t(if not specified, use stdin/stdout) \n"
79 "\n"
80 "example:\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);
83 exit(code);
86 int main (int argc, char *argv[]) {
87 signed char ch;
88 const char *dir = NULL;
89 in_addr_t bindto = INADDR_ANY;
90 uid_t uid = 0;
91 int daemonize = 0;
92 int logmask = LOG_UPTO(LOG_INFO);
93 char *clientmode_serveraddress=NULL;
94 struct nstxmsg *msg;
96 nsid = time(NULL);
98 while ((ch = getopt(argc, argv, "Dh:i:s:c:")) != -1) {
99 switch(ch) {
100 case 'i':
101 bindto = inet_addr(optarg);
102 if (bindto == INADDR_NONE) {
103 fprintf(stderr, "`%s' is not an IP-address\n",
104 optarg);
105 exit(EX_USAGE);
107 break;
108 case 'D':
109 daemonize = 1;
110 break;
111 case 'g':
112 logmask = LOG_UPTO(LOG_DEBUG);
113 break;
114 case 's':
115 vdesock = strdup(optarg);
116 break;
117 case 'h':
118 usage(argv[0], 0); /* no return */
119 case 'c':
120 clientmode_serveraddress = strdup(optarg);
121 break;
122 default:
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);
135 exit(EX_NOPERM);
137 if (daemonize && daemon(0, 0)) {
138 syslog(LOG_ERR, "Can't become a daemon: %m");
139 exit(EX_OSERR);
142 if (clientmode_serveraddress!=NULL){
143 fprintf(stderr,"Client Mode\n");
145 qsettimeout(10);
146 open_ns(clientmode_serveraddress);
147 init_vdesock(vdesock);
149 for (;;) {
150 msg = nstx_select(1);
151 if (msg) {
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);
158 timeoutqueue(NULL);
159 while (queuelen() < DRQLEN)
160 nstxc_send_packet (NULL, 0);
163 return 0;
165 } else {
166 fprintf(stderr,"Server Mode\n");
167 open_ns_bind(bindto);
168 init_vdesock(vdesock);
170 if (dir) {
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);
173 if (chroot(dir)) {
174 syslog(LOG_ERR, "Can't chroot to %s: %m", dir);
175 exit(EXIT_FAILURE); /* Too many possible causes */
177 } else
178 openlog(argv[0], LOG_PERROR|LOG_PID|LOG_CONS, LOG_DAEMON);
180 setlogmask(logmask);
182 while (1)
183 nstx_getpacket();
185 exit(0);
189 struct nstx_senditem * nstx_get_senditem(void) {
190 struct nstx_senditem *ptr = nstx_sendlist;
192 if (!nstx_sendlist)
193 return NULL;
195 ptr = nstx_sendlist;
196 nstx_sendlist = nstx_sendlist->next;
198 return ptr;
201 static void do_timeout (struct nstxqueue *q)
203 struct dnspkt *pkt;
204 int len;
205 char *buf;
207 pkt = dns_alloc();
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);
213 free(buf);
216 void nstx_getpacket (void) {
217 int len, link;
218 const char *name, *buf, *data;
219 struct nstxmsg *msg;
220 struct nstxqueue *qitem;
221 struct dnspkt *pkt;
223 msg = nstx_select(1);
225 if (msg) {
226 if (msg->src == FROMNS) {
227 pkt = dns_extractpkt((unsigned char*)msg->data, msg->len);
228 if (pkt)
230 name = dns_getquerydata(pkt);
231 if (name)
233 syslog(LOG_DEBUG, "getpacket: asked for name `%s'",
234 name);
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);
242 dns_free(pkt);
244 } else if (msg->src == FROMTUN)
245 queue_senditem(msg->data, msg->len);
248 while (queuelen()) {
249 if (!nstx_sendlist)
250 break;
251 qitem = dequeueitem(-1);
252 pkt = dns_alloc();
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));
272 } else {
273 while (ptr->next)
274 ptr = ptr->next;
275 ptr->next = malloc(sizeof(struct nstx_senditem));
276 ptr = ptr->next;
279 memset(ptr, 0, sizeof(struct nstx_senditem));
281 return ptr;
284 static void
285 queue_senditem(const char *buf, int len) {
286 static int id = 0;
287 struct nstx_senditem *item;
289 item = alloc_senditem();
290 item->data = malloc(len);
291 memcpy(item->data, buf, len);
292 item->len = len;
293 item->id = ++id;
296 static char *
297 dequeue_senditem (int *len) {
298 static char *buf;
299 struct nstx_senditem *item = nstx_sendlist;
300 struct nstxhdr *nh;
301 int remain, dlen;
303 remain = item->len - item->offset;
304 dlen = *len - sizeof(struct nstxhdr);
305 if (dlen > remain)
306 dlen = remain;
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++;
314 nh->id = item->id;
315 item->offset += dlen;
316 if (item->offset == item->len) {
317 nh->flags = NSTX_LF;
318 nstx_sendlist = item->next;
319 free(item->data);
320 free(item);
323 return buf;
326 static void nstxc_handle_reply (char * reply, int len) {
327 struct dnspkt *pkt;
328 const char *data;
329 int datalen;
331 pkt = dns_extractpkt ((unsigned char*)reply, len);
332 if (!pkt)
333 return;
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);
339 dns_free(pkt);
342 static int nstxc_send_packet (char *data, int datalen) {
343 static int id = -1;
345 char *p;
346 struct nstxhdr nh;
347 struct dnspkt *pkt;
348 int l;
350 if (id < 0)
351 id = time(NULL);
353 nh.magic = NSTX_MAGIC;
354 nh.seq = 0;
355 nh.id = id++;
356 nh.flags = 0;
358 do {
359 pkt = dns_alloc();
360 dns_settype(pkt, DNS_QUERY);
361 dns_setid(pkt, nsid);
363 l = dns_getfreespace(pkt, DNS_QUERY);
364 if (l <= 0) {
365 printf("Fatal: no free space in dns-packet?!\n");
366 exit(1);
368 p = malloc(l);
369 l -= sizeof(nh);
370 if (l > datalen) {
371 l = datalen;
372 nh.flags = NSTX_LF;
374 memcpy (p, (char*)&nh, sizeof(nh));
375 if (data)
376 memcpy (p + sizeof(nh), data, l);
377 data += l;
378 datalen -= l;
380 dns_addquery(pkt, dns_data2fqdn(nstx_encode((unsigned char*)p, sizeof(nh)+l)));
381 free(p);
382 p = (char*)dns_constructpacket(pkt, &l);
383 sendns(p, l, NULL);
384 free(p);
386 queueid(nsid);
387 nsid++;
388 nh.seq++;
389 } while (datalen);
391 return 0;