[svn-upgrade] Integrating new upstream version, iodine (0.4.2)
[debian/iodine.git] / src / iodine.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 <netdb.h>
24 #include <netinet/in.h>
25 #include <sys/types.h>
26 #include <sys/param.h>
27 #include <sys/time.h>
28 #include <sys/socket.h>
29 #include <fcntl.h>
30 #include <err.h>
31 #include <grp.h>
32 #include <pwd.h>
33 #include <arpa/inet.h>
34 #include <zlib.h>
35 #include <arpa/nameser.h>
36 #ifdef DARWIN
37 #include <arpa/nameser8_compat.h>
38 #endif
39
40 #include "common.h"
41 #include "encoding.h"
42 #include "base32.h"
43 #include "dns.h"
44 #include "login.h"
45 #include "tun.h"
46 #include "version.h"
47
48 static void send_ping(int fd);
49 static void send_chunk(int fd);
50 static int build_hostname(char *buf, size_t buflen, 
51         const char *data, const size_t datalen, 
52         const char *topdomain, struct encoder *encoder);
53
54 static int running = 1;
55 static char password[33];
56
57 static struct sockaddr_in nameserv;
58 static char *topdomain;
59
60 static uint16_t rand_seed;
61
62 /* Current IP packet */
63 static struct packet packet;
64
65 /* My userid at the server */
66 static char userid;
67
68 /* DNS id for next packet */
69 static uint16_t chunkid;
70
71 /* Base32 encoder used for non-data packets */
72 static struct encoder *b32;
73
74 /* The encoder used for data packets
75  * Defaults to Base32, can be changed after handshake */
76 static struct encoder *dataenc;
77
78 /* result of case preservation check done after login */
79 static int case_preserved;
80
81 #if !defined(BSD) && !defined(__GLIBC__)
82 static char *__progname;
83 #endif
84
85 static void
86 sighandler(int sig) 
87 {
88         running = 0;
89 }
90
91 static void
92 send_query(int fd, char *hostname)
93 {
94         char packet[4096];
95         struct query q;
96         size_t len;
97
98         q.id = ++chunkid;
99         q.type = T_NULL;
100
101         len = dns_encode(packet, sizeof(packet), &q, QR_QUERY, hostname, strlen(hostname));
102
103         sendto(fd, packet, len, 0, (struct sockaddr*)&nameserv, sizeof(nameserv));
104 }
105
106 static void
107 send_packet(int fd, char cmd, const char *data, const size_t datalen)
108 {
109         char buf[4096];
110
111         buf[0] = cmd;
112         
113         build_hostname(buf + 1, sizeof(buf) - 1, data, datalen, topdomain, b32);
114         send_query(fd, buf);
115 }
116
117 static int
118 build_hostname(char *buf, size_t buflen, 
119                 const char *data, const size_t datalen, 
120                 const char *topdomain, struct encoder *encoder)
121 {
122         int encsize;
123         size_t space;
124         char *b;
125
126
127         space = MIN(0xFF, buflen) - strlen(topdomain) - 2;
128         if (!encoder->places_dots())
129                 space -= (space / 62); /* space for dots */
130
131         memset(buf, 0, buflen);
132         
133         encsize = encoder->encode(buf, &space, data, datalen);
134
135         if (!encoder->places_dots())
136                 inline_dotify(buf, buflen);
137
138         b = buf;
139         b += strlen(buf);
140
141         if (*b != '.') 
142                 *b++ = '.';
143
144         strncpy(b, topdomain, strlen(topdomain)+1);
145
146         return space;
147 }
148
149 int
150 is_sending()
151 {
152         return (packet.len != 0);
153 }
154
155 int
156 read_dns(int fd, char *buf, int buflen)
157 {
158         struct sockaddr_in from;
159         char data[64*1024];
160         socklen_t addrlen;
161         struct query q;
162         int rv;
163         int r;
164
165         addrlen = sizeof(struct sockaddr);
166         if ((r = recvfrom(fd, data, sizeof(data), 0, 
167                           (struct sockaddr*)&from, &addrlen)) == -1) {
168                 warn("recvfrom");
169                 return 0;
170         }
171
172         rv = dns_decode(buf, buflen, &q, QR_ANSWER, data, r);
173
174         if (is_sending() && chunkid == q.id) {
175                 /* Got ACK on sent packet */
176                 packet.offset += packet.sentlen;
177                 if (packet.offset == packet.len) {
178                         /* Packet completed */
179                         packet.offset = 0;
180                         packet.len = 0;
181                         packet.sentlen = 0;
182                 } else {
183                         /* More to send */
184                         send_chunk(fd);
185                 }
186         }
187         return rv;
188 }
189
190
191 static int
192 tunnel_tun(int tun_fd, int dns_fd)
193 {
194         unsigned long outlen;
195         unsigned long inlen;
196         char out[64*1024];
197         char in[64*1024];
198         size_t read;
199
200         if ((read = read_tun(tun_fd, in, sizeof(in))) <= 0)
201                 return -1;
202
203         outlen = sizeof(out);
204         inlen = read;
205         compress2((uint8_t*)out, &outlen, (uint8_t*)in, inlen, 9);
206
207         memcpy(packet.data, out, MIN(outlen, sizeof(packet.data)));
208         packet.sentlen = 0;
209         packet.offset = 0;
210         packet.len = outlen;
211
212         send_chunk(dns_fd);
213
214         return read;
215 }
216
217 static int
218 tunnel_dns(int tun_fd, int dns_fd)
219 {
220         unsigned long outlen;
221         unsigned long inlen;
222         char out[64*1024];
223         char in[64*1024];
224         size_t read;
225
226         if ((read = read_dns(dns_fd, in, sizeof(in))) <= 0) 
227                 return -1;
228                 
229         outlen = sizeof(out);
230         inlen = read;
231         if (uncompress((uint8_t*)out, &outlen, (uint8_t*)in, inlen) != Z_OK)
232                 return -1;
233
234         write_tun(tun_fd, out, outlen);
235         if (!is_sending()) 
236                 send_ping(dns_fd);
237         
238         return read;
239 }
240
241 static int
242 tunnel(int tun_fd, int dns_fd)
243 {
244         struct timeval tv;
245         fd_set fds;
246         int rv;
247         int i;
248
249         rv = 0;
250
251         while (running) {
252                 tv.tv_sec = 1;
253                 tv.tv_usec = 0;
254
255                 FD_ZERO(&fds);
256                 if (!is_sending()) 
257                         FD_SET(tun_fd, &fds);
258                 FD_SET(dns_fd, &fds);
259
260                 i = select(MAX(tun_fd, dns_fd) + 1, &fds, NULL, NULL, &tv);
261                 
262                 if (running == 0)
263                         break;
264
265                 if (i < 0) 
266                         err(1, "select");
267
268                 if (i == 0) /* timeout */
269                         send_ping(dns_fd);
270                 else {
271                         if (FD_ISSET(tun_fd, &fds)) {
272                                 if (tunnel_tun(tun_fd, dns_fd) <= 0)
273                                         continue;
274                         }
275                         if (FD_ISSET(dns_fd, &fds)) {
276                                 if (tunnel_dns(tun_fd, dns_fd) <= 0)
277                                         continue;
278                         } 
279                 }
280         }
281
282         return rv;
283 }
284
285 static void
286 send_chunk(int fd)
287 {
288         char hex[] = "0123456789ABCDEF";
289         char buf[4096];
290         int avail;
291         int code;
292         char *p;
293
294         p = packet.data;
295         p += packet.offset;
296         avail = packet.len - packet.offset;
297
298         packet.sentlen = build_hostname(buf + 1, sizeof(buf) - 1, p, avail, topdomain, dataenc);
299
300         if (packet.sentlen == avail)
301                 code = 1;
302         else
303                 code = 0;
304                 
305         code |= (userid << 1);
306         buf[0] = hex[code];
307
308         send_query(fd, buf);
309 }
310
311 void
312 send_login(int fd, char *login, int len)
313 {
314         char data[19];
315
316         memset(data, 0, sizeof(data));
317         data[0] = userid;
318         memcpy(&data[1], login, MIN(len, 16));
319
320         data[17] = (rand_seed >> 8) & 0xff;
321         data[18] = (rand_seed >> 0) & 0xff;
322         
323         rand_seed++;
324
325         send_packet(fd, 'L', data, sizeof(data));
326 }
327
328 static void
329 send_ping(int fd)
330 {
331         char data[3];
332         
333         if (is_sending()) {
334                 packet.sentlen = 0;
335                 packet.offset = 0;
336                 packet.len = 0;
337         }
338
339         data[0] = userid;
340         data[1] = (rand_seed >> 8) & 0xff;
341         data[2] = (rand_seed >> 0) & 0xff;
342         
343         rand_seed++;
344
345         send_packet(fd, 'P', data, sizeof(data));
346 }
347
348 void 
349 send_version(int fd, uint32_t version)
350 {
351         char data[6];
352
353         data[0] = (version >> 24) & 0xff;
354         data[1] = (version >> 16) & 0xff;
355         data[2] = (version >> 8) & 0xff;
356         data[3] = (version >> 0) & 0xff;
357
358         data[4] = (rand_seed >> 8) & 0xff;
359         data[5] = (rand_seed >> 0) & 0xff;
360         
361         rand_seed++;
362
363         send_packet(fd, 'V', data, sizeof(data));
364 }
365
366 void
367 send_case_check(int fd)
368 {
369         char buf[512] = "zZaAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyY123-4560789.";
370
371         strncat(buf, topdomain, 512 - strlen(buf));
372         send_query(fd, buf);
373 }
374
375 static int
376 handshake(int dns_fd)
377 {
378         struct timeval tv;
379         uint32_t payload;
380         char server[65];
381         char client[65];
382         char login[16];
383         char in[4096];
384         fd_set fds;
385         int read;
386         int mtu;
387         int seed;
388         int i;
389         int r;
390
391         for (i = 0; running && i < 5; i++) {
392                 tv.tv_sec = i + 1;
393                 tv.tv_usec = 0;
394
395                 send_version(dns_fd, VERSION);
396                 
397                 FD_ZERO(&fds);
398                 FD_SET(dns_fd, &fds);
399
400                 r = select(dns_fd + 1, &fds, NULL, NULL, &tv);
401
402                 if(r > 0) {
403                         read = read_dns(dns_fd, in, sizeof(in));
404                         
405                         if(read <= 0) {
406                                 if (read == 0) {
407                                         warn("handshake read");
408                                 }
409                                 /* if read < 0 then warning has been printed already */
410                                 continue;
411                         }
412
413                         if (read >= 9) {
414                                 payload =  (((in[4] & 0xff) << 24) |
415                                                 ((in[5] & 0xff) << 16) |
416                                                 ((in[6] & 0xff) << 8) |
417                                                 ((in[7] & 0xff)));
418
419                                 if (strncmp("VACK", in, 4) == 0) {
420                                         seed = payload;
421                                         userid = in[8];
422
423                                         printf("Version ok, both running 0x%08x. You are user #%d\n", VERSION, userid);
424                                         goto perform_login;
425                                 } else if (strncmp("VNAK", in, 4) == 0) {
426                                         errx(1, "you run 0x%08x, server runs 0x%08x. giving up\n", 
427                                                         VERSION, payload);
428                                         /* NOTREACHED */
429                                 } else if (strncmp("VFUL", in, 4) == 0) {
430                                         errx(1, "server full, all %d slots are taken. try again later\n", payload);
431                                         /* NOTREACHED */
432                                 }
433                         } else 
434                                 warnx("did not receive proper login challenge\n");
435                 }
436                 
437                 printf("Retrying version check...\n");
438         }
439         errx(1, "couldn't connect to server");
440         /* NOTREACHED */
441         
442 perform_login:
443         login_calculate(login, 16, password, seed);
444         
445         for (i=0; running && i<5 ;i++) {
446                 tv.tv_sec = i + 1;
447                 tv.tv_usec = 0;
448
449                 send_login(dns_fd, login, 16);
450                 
451                 FD_ZERO(&fds);
452                 FD_SET(dns_fd, &fds);
453
454                 r = select(dns_fd + 1, &fds, NULL, NULL, &tv);
455
456                 if(r > 0) {
457                         read = read_dns(dns_fd, in, sizeof(in));
458                         
459                         if(read <= 0) {
460                                 warn("read");
461                                 continue;
462                         }
463
464                         if (read > 0) {
465                                 if (strncmp("LNAK", in, 4) == 0) {
466                                         printf("Bad password\n");
467                                         return 1;
468                                 } else if (sscanf(in, "%64[^-]-%64[^-]-%d", 
469                                         server, client, &mtu) == 3) {
470                                         
471                                         server[64] = 0;
472                                         client[64] = 0;
473                                         if (tun_setip(client) == 0 && 
474                                                 tun_setmtu(mtu) == 0) {
475                                                 goto perform_case_check;
476                                         } else {
477                                                 warnx("Received handshake with bad data");
478                                         }
479                                 } else {
480                                         printf("Received bad handshake\n");
481                                 }
482                         }
483                 }
484
485                 printf("Retrying login...\n");
486         }
487         errx(1, "couldn't login to server");
488         /* NOTREACHED */
489
490 perform_case_check:
491         case_preserved = 0;
492         for (i=0; running && i<5 ;i++) {
493                 tv.tv_sec = i + 1;
494                 tv.tv_usec = 0;
495
496                 send_case_check(dns_fd);
497                 
498                 FD_ZERO(&fds);
499                 FD_SET(dns_fd, &fds);
500
501                 r = select(dns_fd + 1, &fds, NULL, NULL, &tv);
502
503                 if(r > 0) {
504                         read = read_dns(dns_fd, in, sizeof(in));
505                         
506                         if(read <= 0) {
507                                 warn("read");
508                                 continue;
509                         }
510
511                         if (read > 0) {
512                                 if (in[0] == 'z' || in[0] == 'Z') {
513                                         if (read < (26 * 2)) {
514                                                 printf("Received short case reply...\n");
515                                         } else {
516                                                 int k;
517
518                                                 case_preserved = 1;
519                                                 for (k = 0; k < 26 && case_preserved; k += 2) {
520                                                         if (in[k] == in[k+1]) {
521                                                                 /* test string: zZaAbBcCdD... */
522                                                                 case_preserved = 0;
523                                                         }
524                                                 }
525                                                 return 0;
526                                         }
527                                 } else {
528                                         printf("Received bad case check reply\n");
529                                 }
530                         }
531                 }
532
533                 printf("Retrying case check...\n");
534         }
535
536         printf("No reply on case check, continuing\n");
537         return 0;
538 }
539                 
540 static char *
541 get_resolvconf_addr()
542 {
543         static char addr[16];
544         char buf[80];
545         char *rv;
546         FILE *fp;
547         
548         rv = NULL;
549
550         if ((fp = fopen("/etc/resolv.conf", "r")) == NULL) 
551                 err(1, "/etc/resolve.conf");
552         
553         while (feof(fp) == 0) {
554                 fgets(buf, sizeof(buf), fp);
555
556                 if (sscanf(buf, "nameserver %15s", addr) == 1) {
557                         rv = addr;
558                         break;
559                 }
560         }
561         
562         fclose(fp);
563
564         return rv;
565 }
566
567 static void
568 set_nameserver(const char *cp) 
569 {
570         struct in_addr addr;
571
572         if (inet_aton(cp, &addr) != 1)
573                 errx(1, "error parsing nameserver address: '%s'", cp);
574
575         memset(&nameserv, 0, sizeof(nameserv));
576         nameserv.sin_family = AF_INET;
577         nameserv.sin_port = htons(53);
578         nameserv.sin_addr = addr;
579 }
580
581 static void
582 usage() {
583         extern char *__progname;
584
585         printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] "
586                         "[nameserver] topdomain\n", __progname);
587         exit(2);
588 }
589
590 static void
591 help() {
592         extern char *__progname;
593
594         printf("iodine IP over DNS tunneling client\n");
595         printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] "
596                         "[-P password] [nameserver] topdomain\n", __progname);
597         printf("  -v to print version info and exit\n");
598         printf("  -h to print this help and exit\n");
599         printf("  -f to keep running in foreground\n");
600         printf("  -u name to drop privileges and run as user 'name'\n");
601         printf("  -t dir to chroot to directory dir\n");
602         printf("  -d device to set tunnel device name\n");
603         printf("  -P password used for authentication (max 32 chars will be used)\n");
604         printf("nameserver is the IP number of the relaying nameserver, if absent /etc/resolv.conf is used\n");
605         printf("topdomain is the FQDN that is delegated to the tunnel endpoint.\n");
606
607         exit(0);
608 }
609
610 static void
611 version() {
612
613         printf("iodine IP over DNS tunneling client\n");
614         printf("version: 0.4.2 from 2008-08-06\n");
615
616         exit(0);
617 }
618
619 int
620 main(int argc, char **argv)
621 {
622         char *nameserv_addr;
623         struct passwd *pw;
624         char *username;
625         int foreground;
626         char *newroot;
627         char *device;
628         int choice;
629         int tun_fd;
630         int dns_fd;
631
632         memset(password, 0, 33);
633         username = NULL;
634         foreground = 0;
635         newroot = NULL;
636         device = NULL;
637         chunkid = 0;
638
639         b32 = get_base32_encoder();
640         dataenc = get_base32_encoder();
641         
642 #if !defined(BSD) && !defined(__GLIBC__)
643         __progname = strrchr(argv[0], '/');
644         if (__progname == NULL)
645                 __progname = argv[0];
646         else
647                 __progname++;
648 #endif
649
650         while ((choice = getopt(argc, argv, "vfhu:t:d:P:")) != -1) {
651                 switch(choice) {
652                 case 'v':
653                         version();
654                         break;
655                 case 'f':
656                         foreground = 1;
657                         break;
658                 case 'h':
659                         help();
660                         break;
661                 case 'u':
662                         username = optarg;
663                         break;
664                 case 't':
665                         newroot = optarg;
666                         break;
667                 case 'd':
668                         device = optarg;
669                         break;
670                 case 'P':
671                         strncpy(password, optarg, sizeof(password));
672                         password[sizeof(password)-1] = 0;
673                         
674                         /* XXX: find better way of cleaning up ps(1) */
675                         memset(optarg, 0, strlen(optarg)); 
676                         break;
677                 default:
678                         usage();
679                         /* NOTREACHED */
680                 }
681         }
682         
683         if (geteuid() != 0) {
684                 warnx("Run as root and you'll be happy.\n");
685                 usage();
686         }
687
688         argc -= optind;
689         argv += optind;
690
691         switch (argc) {
692         case 1:
693                 nameserv_addr = get_resolvconf_addr();
694                 topdomain = strdup(argv[0]);
695                 break;
696         case 2:
697                 nameserv_addr = argv[0];
698                 topdomain = strdup(argv[1]);
699                 break;
700         default:
701                 usage();
702                 /* NOTREACHED */
703         }
704
705         set_nameserver(nameserv_addr);
706
707         if(strlen(topdomain) <= 128) {
708                 if(check_topdomain(topdomain)) {
709                         warnx("Topdomain contains invalid characters.\n");
710                         usage();
711                 }
712         } else {
713                 warnx("Use a topdomain max 128 chars long.\n");
714                 usage();
715         }
716
717         if (username != NULL) {
718                 if ((pw = getpwnam(username)) == NULL) {
719                         warnx("User %s does not exist!\n", username);
720                         usage();
721                 }
722         }
723         
724         if (strlen(password) == 0) 
725                 read_password(password, sizeof(password));
726
727         if ((tun_fd = open_tun(device)) == -1)
728                 goto cleanup1;
729         if ((dns_fd = open_dns(0, INADDR_ANY)) == -1)
730                 goto cleanup2;
731
732         signal(SIGINT, sighandler);
733         signal(SIGTERM, sighandler);
734
735         if(handshake(dns_fd))
736                 goto cleanup2;
737         
738         printf("Sending queries for %s to %s\n", topdomain, nameserv_addr);
739
740         if (foreground == 0) 
741                 do_detach();
742
743         if (newroot != NULL)
744                 do_chroot(newroot);
745         
746         if (username != NULL) {
747                 gid_t gids[1];
748                 gids[0] = pw->pw_gid;
749                 if (setgroups(1, gids) < 0 || setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {
750                         warnx("Could not switch to user %s!\n", username);
751                         usage();
752                 }
753         }
754         
755         tunnel(tun_fd, dns_fd);
756
757 cleanup2:
758         close_dns(dns_fd);
759         close_tun(tun_fd);
760 cleanup1:
761
762         return 0;
763 }