[svn-upgrade] Integrating new upstream version, iodine (0.4.1)
[debian/iodine.git] / src / iodined.c
1 /*
2  * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include <stdio.h>
18 #include <stdint.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <signal.h>
22 #include <unistd.h>
23 #include <sys/types.h>
24 #include <sys/time.h>
25 #include <sys/socket.h>
26 #include <fcntl.h>
27 #include <err.h>
28 #include <time.h>
29 #include <pwd.h>
30 #include <arpa/inet.h>
31 #include <netinet/in.h>
32 #include <netinet/in_systm.h>
33 #include <netinet/ip.h>
34 #include <zlib.h>
35
36 #include "common.h"
37 #include "dns.h"
38 #include "encoding.h"
39 #include "base32.h"
40 #include "user.h"
41 #include "login.h"
42 #include "tun.h"
43 #include "version.h"
44
45 static int running = 1;
46 static char *topdomain;
47 static char password[33];
48 static struct encoder *b32;
49
50 static int my_mtu;
51 static in_addr_t my_ip;
52
53 static int read_dns(int, struct query *, char *, int);
54 static void write_dns(int, struct query *, char *, int);
55
56 static void
57 sigint(int sig) 
58 {
59         running = 0;
60 }
61
62 static int
63 tunnel_tun(int tun_fd, int dns_fd)
64 {
65         unsigned long outlen;
66         struct ip *header;
67         char out[64*1024];
68         char in[64*1024];
69         int userid;
70         int read;
71
72         if ((read = read_tun(tun_fd, in, sizeof(in))) <= 0)
73                 return 0;
74         
75         /* find target ip in packet, in is padded with 4 bytes TUN header */
76         header = (struct ip*) (in + 4);
77         userid = find_user_by_ip(header->ip_dst.s_addr);
78         if (userid < 0)
79                 return 0;
80
81         outlen = sizeof(out);
82         compress2((uint8_t*)out, &outlen, (uint8_t*)in, read, 9);
83
84         /* if another packet is queued, throw away this one. TODO build queue */
85         if (users[userid].outpacket.len == 0) {
86                 memcpy(users[userid].outpacket.data, out, outlen);
87                 users[userid].outpacket.len = outlen;
88                 return outlen;
89         } else {
90                 return 0;
91         }
92 }
93
94 typedef enum {
95         VERSION_ACK,
96         VERSION_NACK,
97         VERSION_FULL
98 } version_ack_t;
99
100 static void
101 send_version_response(int fd, version_ack_t ack, uint32_t payload, struct user *u)
102 {
103         char out[9];
104         
105         switch (ack) {
106         case VERSION_ACK:
107                 strncpy(out, "VACK", sizeof(out));
108                 break;
109         case VERSION_NACK:
110                 strncpy(out, "VNAK", sizeof(out));
111                 break;
112         case VERSION_FULL:
113                 strncpy(out, "VFUL", sizeof(out));
114                 break;
115         }
116         
117         out[4] = ((payload >> 24) & 0xff);
118         out[5] = ((payload >> 16) & 0xff);
119         out[6] = ((payload >> 8) & 0xff);
120         out[7] = ((payload) & 0xff);
121         out[8] = u->id;
122
123
124         write_dns(fd, &u->q, out, sizeof(out));
125 }
126
127 static int
128 tunnel_dns(int tun_fd, int dns_fd)
129 {
130         struct in_addr tempip;
131         struct user dummy;
132         struct ip *hdr;
133         unsigned long outlen;
134         char logindata[16];
135         char out[64*1024];
136         char in[64*1024];
137         char unpacked[64*1024];
138         char *tmp[2];
139         int userid;
140         int touser;
141         int version;
142         int read;
143         int code;
144
145         userid = -1;
146         if ((read = read_dns(dns_fd, &(dummy.q), in, sizeof(in))) <= 0)
147                 return 0;
148                                 
149         if(in[0] == 'V' || in[0] == 'v') {
150                 read = unpack_data(unpacked, sizeof(unpacked), &(in[1]), read - 1, b32);
151                 /* Version greeting, compare and send ack/nak */
152                 if (read > 4) { 
153                         /* Received V + 32bits version */
154                         version = (((unpacked[0] & 0xff) << 24) |
155                                            ((unpacked[1] & 0xff) << 16) |
156                                            ((unpacked[2] & 0xff) << 8) |
157                                            ((unpacked[3] & 0xff)));
158                 }
159
160                 if (version == VERSION) {
161                         userid = find_available_user();
162                         if (userid >= 0) {
163                                 users[userid].seed = rand();
164                                 memcpy(&(users[userid].host), &(dummy.q.from), dummy.q.fromlen);
165                                 memcpy(&(users[userid].q), &(dummy.q), sizeof(struct query));
166                                 users[userid].addrlen = dummy.q.fromlen;
167                                 users[userid].encoder = get_base32_encoder();
168                                 send_version_response(dns_fd, VERSION_ACK, users[userid].seed, &users[userid]);
169                                 users[userid].q.id = 0;
170                         } else {
171                                 /* No space for another user */
172                                 send_version_response(dns_fd, VERSION_FULL, USERS, &dummy);
173                         }
174                 } else {
175                         send_version_response(dns_fd, VERSION_NACK, VERSION, &dummy);
176                 }
177         } else if(in[0] == 'L' || in[0] == 'l') {
178                 read = unpack_data(unpacked, sizeof(unpacked), &(in[1]), read - 1, b32);
179                 /* Login phase, handle auth */
180                 userid = unpacked[0];
181                 if (userid < 0 || userid >= USERS) {
182                         write_dns(dns_fd, &(dummy.q), "BADIP", 5);
183                         return 0; /* illegal id */
184                 }
185                 users[userid].last_pkt = time(NULL);
186                 login_calculate(logindata, 16, password, users[userid].seed);
187
188                 if (dummy.q.fromlen != users[userid].addrlen ||
189                                 memcmp(&(users[userid].host), &(dummy.q.from), dummy.q.fromlen) != 0) {
190                         write_dns(dns_fd, &(dummy.q), "BADIP", 5);
191                 } else {
192                         if (read >= 18 && (memcmp(logindata, unpacked+1, 16) == 0)) {
193                                 /* Login ok, send ip/mtu info */
194
195                                 tempip.s_addr = my_ip;
196                                 tmp[0] = strdup(inet_ntoa(tempip));
197                                 tempip.s_addr = users[userid].tun_ip;
198                                 tmp[1] = strdup(inet_ntoa(tempip));
199
200                                 read = snprintf(out, sizeof(out), "%s-%s-%d", 
201                                                 tmp[0], tmp[1], my_mtu);
202
203                                 write_dns(dns_fd, &(dummy.q), out, read);
204                                 dummy.q.id = 0;
205
206                                 free(tmp[1]);
207                                 free(tmp[0]);
208                         } else {
209                                 write_dns(dns_fd, &(dummy.q), "LNAK", 4);
210                         }
211                 }
212         } else if(in[0] == 'P' || in[0] == 'p') {
213                 read = unpack_data(unpacked, sizeof(unpacked), &(in[1]), read - 1, b32);
214                 /* Ping packet, store userid */
215                 userid = unpacked[0];
216                 if (userid < 0 || userid >= USERS) {
217                         write_dns(dns_fd, &(dummy.q), "BADIP", 5);
218                         return 0; /* illegal id */
219                 }
220                 memcpy(&(users[userid].q), &(dummy.q), sizeof(struct query));
221                 users[userid].last_pkt = time(NULL);
222         } else if(in[0] == 'Z' || in[0] == 'z') {
223                 /* Case conservation check */
224
225                 /* Reply with received hostname as data */
226                 write_dns(dns_fd, &(dummy.q), in, read);
227                 return 0;
228         } else if((in[0] >= '0' && in[0] <= '9')
229                         || (in[0] >= 'a' && in[0] <= 'f')
230                         || (in[0] >= 'A' && in[0] <= 'F')) {
231                 if ((in[0] >= '0' && in[0] <= '9'))
232                         code = in[0] - '0';
233                 if ((in[0] >= 'a' && in[0] <= 'f'))
234                         code = in[0] - 'a' + 10;
235                 if ((in[0] >= 'A' && in[0] <= 'F'))
236                         code = in[0] - 'A' + 10;
237
238                 userid = code >> 1;
239                 if (userid < 0 || userid >= USERS) {
240                         write_dns(dns_fd, &(dummy.q), "BADIP", 5);
241                         return 0; /* illegal id */
242                 }
243
244                 /* Check sending ip number */
245                 if (dummy.q.fromlen != users[userid].addrlen ||
246                                 memcmp(&(users[userid].host), &(dummy.q.from), dummy.q.fromlen) != 0) {
247                         write_dns(dns_fd, &(dummy.q), "BADIP", 5);
248                 } else {
249                         /* decode with this users encoding */
250                         read = unpack_data(unpacked, sizeof(unpacked), &(in[1]), read - 1, 
251                                            users[userid].encoder);
252
253                         users[userid].last_pkt = time(NULL);
254                         memcpy(&(users[userid].q), &(dummy.q), sizeof(struct query));
255                         users[userid].addrlen = dummy.q.fromlen;
256                         memcpy(users[userid].inpacket.data + users[userid].inpacket.offset, unpacked, read);
257                         users[userid].inpacket.len += read;
258                         users[userid].inpacket.offset += read;
259
260                         if (code & 1) {
261                                 outlen = sizeof(out);
262                                 uncompress((uint8_t*)out, &outlen, 
263                                                    (uint8_t*)users[userid].inpacket.data, users[userid].inpacket.len);
264
265                                 hdr = (struct ip*) (out + 4);
266                                 touser = find_user_by_ip(hdr->ip_dst.s_addr);
267
268                                 if (touser == -1) {
269                                         /* send the uncompressed packet to tun device */
270                                         write_tun(tun_fd, out, outlen);
271                                 } else {
272                                         /* send the compressed packet to other client
273                                          * if another packet is queued, throw away this one. TODO build queue */
274                                         if (users[touser].outpacket.len == 0) {
275                                                 memcpy(users[touser].outpacket.data, users[userid].inpacket.data, users[userid].inpacket.len);
276                                                 users[touser].outpacket.len = users[userid].inpacket.len;
277                                         }
278                                 }
279                                 users[userid].inpacket.len = users[userid].inpacket.offset = 0;
280                         }
281                 }
282         }
283         /* userid must be set for a reply to be sent */
284         if (userid >= 0 && userid < USERS && dummy.q.fromlen == users[userid].addrlen &&
285                         memcmp(&(users[userid].host), &(dummy.q.from), dummy.q.fromlen) == 0 &&
286                         users[userid].outpacket.len > 0) {
287
288                 write_dns(dns_fd, &(dummy.q), users[userid].outpacket.data, users[userid].outpacket.len);
289                 users[userid].outpacket.len = 0;
290                 users[userid].q.id = 0;
291         }
292
293         return 0;
294 }
295
296 static int
297 tunnel(int tun_fd, int dns_fd)
298 {
299         struct timeval tv;
300         fd_set fds;
301         int i;
302         int j;
303
304         while (running) {
305                 if (users_waiting_on_reply()) {
306                         tv.tv_sec = 0;
307                         tv.tv_usec = 5000;
308                 } else {
309                         tv.tv_sec = 1;
310                         tv.tv_usec = 0;
311                 }
312
313                 FD_ZERO(&fds);
314                 /* TODO : use some kind of packet queue */
315                 if(!all_users_waiting_to_send()) {
316                         FD_SET(tun_fd, &fds);
317                 }
318                 FD_SET(dns_fd, &fds);
319
320                 i = select(MAX(tun_fd, dns_fd) + 1, &fds, NULL, NULL, &tv);
321                 
322                 if(i < 0) {
323                         if (running) 
324                                 warn("select");
325                         return 1;
326                 }
327         
328                 if (i==0) {     
329                         for (j = 0; j < USERS; j++) {
330                                 if (users[j].q.id != 0) {
331                                         write_dns(dns_fd, &(users[j].q), users[j].outpacket.data, users[j].outpacket.len);
332                                         users[j].outpacket.len = 0;
333                                         users[j].q.id = 0;
334                                 }
335                         }
336                 } else {
337                         if(FD_ISSET(tun_fd, &fds)) {
338                                 tunnel_tun(tun_fd, dns_fd);
339                                 continue;
340                         }
341                         if(FD_ISSET(dns_fd, &fds)) {
342                                 tunnel_dns(tun_fd, dns_fd);
343                                 continue;
344                         } 
345                 }
346         }
347
348         return 0;
349 }
350
351 static int
352 read_dns(int fd, struct query *q, char *buf, int buflen)
353 {
354         struct sockaddr_in from;
355         char packet[64*1024];
356         char *domain;
357         socklen_t addrlen;
358         int rv;
359         int r;
360
361         addrlen = sizeof(struct sockaddr);
362         r = recvfrom(fd, packet, sizeof(packet), 0, (struct sockaddr*)&from, &addrlen);
363
364         if (r > 0) {
365                 dns_decode(buf, buflen, q, QR_QUERY, packet, r);
366                 domain = strstr(q->name, topdomain);
367                 if (domain) {
368                         rv = (int) (domain - q->name); 
369                         memcpy(buf, q->name, MIN(rv, buflen));
370                         q->fromlen = addrlen;
371                         memcpy((struct sockaddr*)&q->from, (struct sockaddr*)&from, addrlen);
372                 } else {
373                         rv = 0;
374                 }
375         } else if (r < 0) { 
376                 /* Error */
377                 warn("read dns");
378                 rv = 0;
379         }
380
381         return rv;
382 }
383
384 static void
385 write_dns(int fd, struct query *q, char *data, int datalen)
386 {
387         char buf[64*1024];
388         int len;
389
390         len = dns_encode(buf, sizeof(buf), q, QR_ANSWER, data, datalen);
391         
392         sendto(fd, buf, len, 0, (struct sockaddr*)&q->from, q->fromlen);
393 }
394
395 static void
396 usage() {
397         extern char *__progname;
398
399         printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] [-m mtu] "
400                 "[-l ip address to listen on] [-p port] [-P password]"
401                 " tunnel_ip topdomain\n", __progname);
402         exit(2);
403 }
404
405 static void
406 help() {
407         extern char *__progname;
408
409         printf("iodine IP over DNS tunneling server\n");
410         printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] [-m mtu] "
411                 "[-l ip address to listen on] [-p port] [-P password]"
412                 " tunnel_ip topdomain\n", __progname);
413         printf("  -v to print version info and exit\n");
414         printf("  -h to print this help and exit\n");
415         printf("  -f to keep running in foreground\n");
416         printf("  -u name to drop privileges and run as user 'name'\n");
417         printf("  -t dir to chroot to directory dir\n");
418         printf("  -d device to set tunnel device name\n");
419         printf("  -m mtu to set tunnel device mtu\n");
420         printf("  -l ip address to listen on for incoming dns traffic (default 0.0.0.0)\n");
421         printf("  -p port to listen on for incoming dns traffic (default 53)\n");
422         printf("  -P password used for authentication (max 32 chars will be used)\n");
423         printf("tunnel_ip is the IP number of the local tunnel interface.\n");
424         printf("topdomain is the FQDN that is delegated to this server.\n");
425         exit(0);
426 }
427
428 static void
429 version() {
430         printf("iodine IP over DNS tunneling server\n");
431         printf("version: 0.4.1 from 2007-11-30\n");
432         exit(0);
433 }
434
435 int
436 main(int argc, char **argv)
437 {
438         in_addr_t listen_ip;
439         struct passwd *pw;
440         int foreground;
441         char *username;
442         char *newroot;
443         char *device;
444         int dnsd_fd;
445         int tun_fd;
446         int choice;
447         int port;
448         int mtu;
449
450         username = NULL;
451         newroot = NULL;
452         device = NULL;
453         foreground = 0;
454         mtu = 1024;
455         listen_ip = INADDR_ANY;
456         port = 53;
457
458         b32 = get_base32_encoder();
459
460         memset(password, 0, sizeof(password));
461         srand(time(NULL));
462         
463         while ((choice = getopt(argc, argv, "vfhu:t:d:m:l:p:P:")) != -1) {
464                 switch(choice) {
465                 case 'v':
466                         version();
467                         break;
468                 case 'f':
469                         foreground = 1;
470                         break;
471                 case 'h':
472                         help();
473                         break;
474                 case 'u':
475                         username = optarg;
476                         break;
477                 case 't':
478                         newroot = optarg;
479                         break;
480                 case 'd':
481                         device = optarg;
482                         break;
483                 case 'm':
484                         mtu = atoi(optarg);
485                         break;
486                 case 'l':
487                         listen_ip = inet_addr(optarg);
488                         break;
489                 case 'p':
490                         port = atoi(optarg);
491                         if (port) {
492                                 printf("ALERT! Other dns servers expect you to run on port 53.\n");
493                                 printf("You must manually forward port 53 to port %d for things to work.\n", port);
494                         }
495                         break;
496                 case 'P':
497                         strncpy(password, optarg, sizeof(password));
498                         password[sizeof(password)-1] = 0;
499                         
500                         /* XXX: find better way of cleaning up ps(1) */
501                         memset(optarg, 0, strlen(optarg)); 
502                         break;
503                 default:
504                         usage();
505                         break;
506                 }
507         }
508
509         argc -= optind;
510         argv += optind;
511
512         if (geteuid() != 0) {
513                 warnx("Run as root and you'll be happy.\n");
514                 usage();
515         }
516
517         if (argc != 2) 
518                 usage();
519
520         topdomain = strdup(argv[1]);
521         if (strlen(topdomain) > 128 || topdomain[0] == '.') {
522                 warnx("Use a topdomain max 128 chars long. Do not start it with a dot.\n");
523                 usage();
524         }
525
526         if (username != NULL) {
527                 if ((pw = getpwnam(username)) == NULL) {
528                         warnx("User %s does not exist!\n", username);
529                         usage();
530                 }
531         }
532
533         if (mtu == 0) {
534                 warnx("Bad MTU given.\n");
535                 usage();
536         }
537
538         if (listen_ip == INADDR_NONE) {
539                 warnx("Bad IP address to listen on.\n");
540                 usage();
541         }
542
543         if (strlen(password) == 0)
544                 read_password(password, sizeof(password));
545
546         if ((tun_fd = open_tun(device)) == -1)
547                 goto cleanup0;
548         if (tun_setip(argv[0]) != 0 || tun_setmtu(mtu) != 0)
549                 goto cleanup1;
550         if ((dnsd_fd = open_dns(port, listen_ip)) == -1) 
551                 goto cleanup2;
552
553         my_ip = inet_addr(argv[0]);
554         my_mtu = mtu;
555         init_users(my_ip);
556
557         printf("Listening to dns for domain %s\n", topdomain);
558
559         if (foreground == 0) 
560                 do_detach();
561         
562         if (newroot != NULL)
563                 do_chroot(newroot);
564
565         signal(SIGINT, sigint);
566         if (username != NULL) {
567                 if (setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {
568                         warnx("Could not switch to user %s!\n", username);
569                         usage();
570                 }
571         }
572         
573         tunnel(tun_fd, dnsd_fd);
574
575 cleanup2:
576         close_dns(dnsd_fd);
577 cleanup1:
578         close_tun(tun_fd);      
579 cleanup0:
580
581         return 0;
582 }