source: src/iodined.c @ 539ebb

Revision 539ebb, 15.2 KB checked in by Erik Ekman <yarrick@…>, 5 years ago (diff)

Changes to allow handling of queries of type A, NS etc

  • Property mode set to 100644
Line 
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/param.h>
25#include <sys/time.h>
26#include <sys/socket.h>
27#include <fcntl.h>
28#include <err.h>
29#include <grp.h>
30#include <time.h>
31#include <pwd.h>
32#include <arpa/inet.h>
33#include <netinet/in.h>
34#include <netinet/in_systm.h>
35#include <netinet/ip.h>
36#include <zlib.h>
37#include <arpa/nameser.h>
38#ifdef DARWIN
39#include <arpa/nameser8_compat.h>
40#endif
41
42#include "common.h"
43#include "dns.h"
44#include "encoding.h"
45#include "base32.h"
46#include "user.h"
47#include "login.h"
48#include "tun.h"
49#include "version.h"
50
51static int running = 1;
52static char *topdomain;
53static char password[33];
54static struct encoder *b32;
55
56static int check_ip;
57static int my_mtu;
58static in_addr_t my_ip;
59
60#if !defined(BSD) && !defined(__GLIBC__)
61static char *__progname;
62#endif
63
64static int read_dns(int, struct query *);
65static void write_dns(int, struct query *, char *, int);
66
67static void
68sigint(int sig)
69{
70        running = 0;
71}
72
73static int
74ip_cmp(int userid, struct query *q)
75{
76        struct sockaddr_in *tempin;
77
78        tempin = (struct sockaddr_in *) &(q->from);
79        return memcmp(&(users[userid].host), &(tempin->sin_addr), sizeof(struct in_addr));
80}
81
82static int
83tunnel_tun(int tun_fd, int dns_fd)
84{
85        unsigned long outlen;
86        struct ip *header;
87        char out[64*1024];
88        char in[64*1024];
89        int userid;
90        int read;
91
92        if ((read = read_tun(tun_fd, in, sizeof(in))) <= 0)
93                return 0;
94       
95        /* find target ip in packet, in is padded with 4 bytes TUN header */
96        header = (struct ip*) (in + 4);
97        userid = find_user_by_ip(header->ip_dst.s_addr);
98        if (userid < 0)
99                return 0;
100
101        outlen = sizeof(out);
102        compress2((uint8_t*)out, &outlen, (uint8_t*)in, read, 9);
103
104        /* if another packet is queued, throw away this one. TODO build queue */
105        if (users[userid].outpacket.len == 0) {
106                memcpy(users[userid].outpacket.data, out, outlen);
107                users[userid].outpacket.len = outlen;
108                return outlen;
109        } else {
110                return 0;
111        }
112}
113
114typedef enum {
115        VERSION_ACK,
116        VERSION_NACK,
117        VERSION_FULL
118} version_ack_t;
119
120static void
121send_version_response(int fd, version_ack_t ack, uint32_t payload, struct user *u)
122{
123        char out[9];
124       
125        switch (ack) {
126        case VERSION_ACK:
127                strncpy(out, "VACK", sizeof(out));
128                break;
129        case VERSION_NACK:
130                strncpy(out, "VNAK", sizeof(out));
131                break;
132        case VERSION_FULL:
133                strncpy(out, "VFUL", sizeof(out));
134                break;
135        }
136       
137        out[4] = ((payload >> 24) & 0xff);
138        out[5] = ((payload >> 16) & 0xff);
139        out[6] = ((payload >> 8) & 0xff);
140        out[7] = ((payload) & 0xff);
141        if (u) {
142                out[8] = u->id;
143        } else {
144                out[8] = 0;
145        }
146
147
148        write_dns(fd, &u->q, out, sizeof(out));
149}
150
151static void
152handle_null_request(int tun_fd, int dns_fd, struct query *q)
153{
154        struct in_addr tempip;
155        struct ip *hdr;
156        unsigned long outlen;
157        char in[64*1024];
158        char logindata[16];
159        char out[64*1024];
160        char unpacked[64*1024];
161        char *tmp[2];
162        char *domain;
163        int userid;
164        int touser;
165        int version;
166        int code;
167        int read;
168
169        userid = -1;
170        domain = strstr(q->name, topdomain);
171        if (!domain) {
172                /* Not for us, discard */
173                return;
174        }
175       
176        read = (int) (domain - q->name);
177        memcpy(in, q->name, MIN(read, sizeof(in)));
178
179        if(in[0] == 'V' || in[0] == 'v') {
180                read = unpack_data(unpacked, sizeof(unpacked), &(in[1]), read - 1, b32);
181                /* Version greeting, compare and send ack/nak */
182                if (read > 4) {
183                        /* Received V + 32bits version */
184                        version = (((unpacked[0] & 0xff) << 24) |
185                                           ((unpacked[1] & 0xff) << 16) |
186                                           ((unpacked[2] & 0xff) << 8) |
187                                           ((unpacked[3] & 0xff)));
188                }
189
190                if (version == VERSION) {
191                        userid = find_available_user();
192                        if (userid >= 0) {
193                                struct sockaddr_in *tempin;
194
195                                users[userid].seed = rand();
196                                /* Store remote IP number */
197                                tempin = (struct sockaddr_in *) &(q->from);
198                                memcpy(&(users[userid].host), &(tempin->sin_addr), sizeof(struct in_addr));
199                               
200                                memcpy(&(users[userid].q), q, sizeof(struct query));
201                                users[userid].encoder = get_base32_encoder();
202                                send_version_response(dns_fd, VERSION_ACK, users[userid].seed, &users[userid]);
203                                users[userid].q.id = 0;
204                        } else {
205                                /* No space for another user */
206                                send_version_response(dns_fd, VERSION_FULL, USERS, NULL);
207                        }
208                } else {
209                        send_version_response(dns_fd, VERSION_NACK, VERSION, NULL);
210                }
211        } else if(in[0] == 'L' || in[0] == 'l') {
212                read = unpack_data(unpacked, sizeof(unpacked), &(in[1]), read - 1, b32);
213                /* Login phase, handle auth */
214                userid = unpacked[0];
215                if (userid < 0 || userid >= USERS) {
216                        write_dns(dns_fd, q, "BADIP", 5);
217                        return; /* illegal id */
218                }
219                users[userid].last_pkt = time(NULL);
220                login_calculate(logindata, 16, password, users[userid].seed);
221
222                if (check_ip && ip_cmp(userid, q) != 0) {
223                        write_dns(dns_fd, q, "BADIP", 5);
224                } else {
225                        if (read >= 18 && (memcmp(logindata, unpacked+1, 16) == 0)) {
226                                /* Login ok, send ip/mtu info */
227
228                                tempip.s_addr = my_ip;
229                                tmp[0] = strdup(inet_ntoa(tempip));
230                                tempip.s_addr = users[userid].tun_ip;
231                                tmp[1] = strdup(inet_ntoa(tempip));
232
233                                read = snprintf(out, sizeof(out), "%s-%s-%d",
234                                                tmp[0], tmp[1], my_mtu);
235
236                                write_dns(dns_fd, q, out, read);
237                                q->id = 0;
238
239                                free(tmp[1]);
240                                free(tmp[0]);
241                        } else {
242                                write_dns(dns_fd, q, "LNAK", 4);
243                        }
244                }
245        } else if(in[0] == 'P' || in[0] == 'p') {
246                read = unpack_data(unpacked, sizeof(unpacked), &(in[1]), read - 1, b32);
247                /* Ping packet, store userid */
248                userid = unpacked[0];
249                if (userid < 0 || userid >= USERS || ip_cmp(userid, q) != 0) {
250                        write_dns(dns_fd, q, "BADIP", 5);
251                        return; /* illegal id */
252                }
253                memcpy(&(users[userid].q), q, sizeof(struct query));
254                users[userid].last_pkt = time(NULL);
255        } else if(in[0] == 'Z' || in[0] == 'z') {
256                /* Case conservation check */
257
258                /* Reply with received hostname as data */
259                write_dns(dns_fd, q, in, read);
260                return;
261        } else if((in[0] >= '0' && in[0] <= '9')
262                        || (in[0] >= 'a' && in[0] <= 'f')
263                        || (in[0] >= 'A' && in[0] <= 'F')) {
264                if ((in[0] >= '0' && in[0] <= '9'))
265                        code = in[0] - '0';
266                if ((in[0] >= 'a' && in[0] <= 'f'))
267                        code = in[0] - 'a' + 10;
268                if ((in[0] >= 'A' && in[0] <= 'F'))
269                        code = in[0] - 'A' + 10;
270
271                userid = code >> 1;
272                if (userid < 0 || userid >= USERS) {
273                        write_dns(dns_fd, q, "BADIP", 5);
274                        return; /* illegal id */
275                }
276
277                /* Check sending ip number */
278                if (check_ip && ip_cmp(userid, q) != 0) {
279                        write_dns(dns_fd, q, "BADIP", 5);
280                } else {
281                        /* decode with this users encoding */
282                        read = unpack_data(unpacked, sizeof(unpacked), &(in[1]), read - 1,
283                                           users[userid].encoder);
284
285                        users[userid].last_pkt = time(NULL);
286                        memcpy(&(users[userid].q), q, sizeof(struct query));
287                        memcpy(users[userid].inpacket.data + users[userid].inpacket.offset, unpacked, read);
288                        users[userid].inpacket.len += read;
289                        users[userid].inpacket.offset += read;
290
291                        if (code & 1) {
292                                outlen = sizeof(out);
293                                uncompress((uint8_t*)out, &outlen,
294                                                   (uint8_t*)users[userid].inpacket.data, users[userid].inpacket.len);
295
296                                hdr = (struct ip*) (out + 4);
297                                touser = find_user_by_ip(hdr->ip_dst.s_addr);
298
299                                if (touser == -1) {
300                                        /* send the uncompressed packet to tun device */
301                                        write_tun(tun_fd, out, outlen);
302                                } else {
303                                        /* send the compressed packet to other client
304                                         * if another packet is queued, throw away this one. TODO build queue */
305                                        if (users[touser].outpacket.len == 0) {
306                                                memcpy(users[touser].outpacket.data, users[userid].inpacket.data, users[userid].inpacket.len);
307                                                users[touser].outpacket.len = users[userid].inpacket.len;
308                                        }
309                                }
310                                users[userid].inpacket.len = users[userid].inpacket.offset = 0;
311                        }
312                }
313        }
314        /* userid must be set for a reply to be sent */
315        if (userid >= 0 && userid < USERS && ip_cmp(userid, q) == 0 && users[userid].outpacket.len > 0) {
316                write_dns(dns_fd, q, users[userid].outpacket.data, users[userid].outpacket.len);
317                users[userid].outpacket.len = 0;
318                users[userid].q.id = 0;
319        }
320}
321
322static int
323tunnel_dns(int tun_fd, int dns_fd)
324{
325        struct query q;
326        int read;
327
328        if ((read = read_dns(dns_fd, &q)) <= 0)
329                return 0;
330       
331        switch (q.type) {
332        case T_NULL:
333                handle_null_request(tun_fd, dns_fd, &q);
334                break;
335        default:
336                break;
337        }
338
339        return 0;
340}
341
342static int
343tunnel(int tun_fd, int dns_fd)
344{
345        struct timeval tv;
346        fd_set fds;
347        int i;
348        int j;
349
350        while (running) {
351                if (users_waiting_on_reply()) {
352                        tv.tv_sec = 0;
353                        tv.tv_usec = 5000;
354                } else {
355                        tv.tv_sec = 1;
356                        tv.tv_usec = 0;
357                }
358
359                FD_ZERO(&fds);
360                /* TODO : use some kind of packet queue */
361                if(!all_users_waiting_to_send()) {
362                        FD_SET(tun_fd, &fds);
363                }
364                FD_SET(dns_fd, &fds);
365
366                i = select(MAX(tun_fd, dns_fd) + 1, &fds, NULL, NULL, &tv);
367               
368                if(i < 0) {
369                        if (running)
370                                warn("select");
371                        return 1;
372                }
373       
374                if (i==0) {     
375                        for (j = 0; j < USERS; j++) {
376                                if (users[j].q.id != 0) {
377                                        write_dns(dns_fd, &(users[j].q), users[j].outpacket.data, users[j].outpacket.len);
378                                        users[j].outpacket.len = 0;
379                                        users[j].q.id = 0;
380                                }
381                        }
382                } else {
383                        if(FD_ISSET(tun_fd, &fds)) {
384                                tunnel_tun(tun_fd, dns_fd);
385                                continue;
386                        }
387                        if(FD_ISSET(dns_fd, &fds)) {
388                                tunnel_dns(tun_fd, dns_fd);
389                                continue;
390                        }
391                }
392        }
393
394        return 0;
395}
396
397static int
398read_dns(int fd, struct query *q)
399{
400        struct sockaddr_in from;
401        char packet[64*1024];
402        socklen_t addrlen;
403        int r;
404
405        addrlen = sizeof(struct sockaddr);
406        r = recvfrom(fd, packet, sizeof(packet), 0, (struct sockaddr*)&from, &addrlen);
407
408        if (r > 0) {
409                dns_decode(NULL, 0, q, QR_QUERY, packet, r);
410                memcpy((struct sockaddr*)&q->from, (struct sockaddr*)&from, addrlen);
411                q->fromlen = addrlen;
412
413                return strlen(q->name);
414        } else if (r < 0) {
415                /* Error */
416                warn("read dns");
417        }
418
419        return 0;
420}
421
422static void
423write_dns(int fd, struct query *q, char *data, int datalen)
424{
425        char buf[64*1024];
426        int len;
427
428        len = dns_encode(buf, sizeof(buf), q, QR_ANSWER, data, datalen);
429       
430        sendto(fd, buf, len, 0, (struct sockaddr*)&q->from, q->fromlen);
431}
432
433static void
434usage() {
435        extern char *__progname;
436
437        printf("Usage: %s [-v] [-h] [-c] [-s] [-f] [-u user] [-t chrootdir] [-d device] [-m mtu] "
438                "[-l ip address to listen on] [-p port] [-P password]"
439                " tunnel_ip topdomain\n", __progname);
440        exit(2);
441}
442
443static void
444help() {
445        extern char *__progname;
446
447        printf("iodine IP over DNS tunneling server\n");
448        printf("Usage: %s [-v] [-h] [-c] [-s] [-f] [-u user] [-t chrootdir] [-d device] [-m mtu] "
449                "[-l ip address to listen on] [-p port] [-P password]"
450                " tunnel_ip topdomain\n", __progname);
451        printf("  -v to print version info and exit\n");
452        printf("  -h to print this help and exit\n");
453        printf("  -c to disable check of client IP/port on each request\n");
454        printf("  -s to skip creating and configuring the tun device which then has to be created manually\n");
455        printf("  -f to keep running in foreground\n");
456        printf("  -u name to drop privileges and run as user 'name'\n");
457        printf("  -t dir to chroot to directory dir\n");
458        printf("  -d device to set tunnel device name\n");
459        printf("  -m mtu to set tunnel device mtu\n");
460        printf("  -l ip address to listen on for incoming dns traffic (default 0.0.0.0)\n");
461        printf("  -p port to listen on for incoming dns traffic (default 53)\n");
462        printf("  -P password used for authentication (max 32 chars will be used)\n");
463        printf("tunnel_ip is the IP number of the local tunnel interface.\n");
464        printf("topdomain is the FQDN that is delegated to this server.\n");
465        exit(0);
466}
467
468static void
469version() {
470        char *svnver;
471        svnver = "$Rev$ from $Date$";
472        printf("iodine IP over DNS tunneling server\n");
473        printf("SVN version: %s\n", svnver);
474        exit(0);
475}
476
477int
478main(int argc, char **argv)
479{
480        in_addr_t listen_ip;
481        struct passwd *pw;
482        int foreground;
483        char *username;
484        char *newroot;
485        char *device;
486        int dnsd_fd;
487        int tun_fd;
488        int choice;
489        int port;
490        int mtu;
491        int skipipconfig;
492
493        username = NULL;
494        newroot = NULL;
495        device = NULL;
496        foreground = 0;
497        mtu = 1024;
498        listen_ip = INADDR_ANY;
499        port = 53;
500        check_ip = 1;
501        skipipconfig = 0;
502
503        b32 = get_base32_encoder();
504
505#if !defined(BSD) && !defined(__GLIBC__)
506        __progname = strrchr(argv[0], '/');
507        if (__progname == NULL)
508                __progname = argv[0];
509        else
510                __progname++;
511#endif
512
513        memset(password, 0, sizeof(password));
514        srand(time(NULL));
515       
516        while ((choice = getopt(argc, argv, "vcsfhu:t:d:m:l:p:P:")) != -1) {
517                switch(choice) {
518                case 'v':
519                        version();
520                        break;
521                case 'c':
522                        check_ip = 0;
523                        break;
524                case 's':
525                        skipipconfig = 1;
526                        break;
527                case 'f':
528                        foreground = 1;
529                        break;
530                case 'h':
531                        help();
532                        break;
533                case 'u':
534                        username = optarg;
535                        break;
536                case 't':
537                        newroot = optarg;
538                        break;
539                case 'd':
540                        device = optarg;
541                        break;
542                case 'm':
543                        mtu = atoi(optarg);
544                        break;
545                case 'l':
546                        listen_ip = inet_addr(optarg);
547                        break;
548                case 'p':
549                        port = atoi(optarg);
550                        break;
551                case 'P':
552                        strncpy(password, optarg, sizeof(password));
553                        password[sizeof(password)-1] = 0;
554                       
555                        /* XXX: find better way of cleaning up ps(1) */
556                        memset(optarg, 0, strlen(optarg));
557                        break;
558                default:
559                        usage();
560                        break;
561                }
562        }
563
564        argc -= optind;
565        argv += optind;
566
567        if (geteuid() != 0) {
568                warnx("Run as root and you'll be happy.\n");
569                usage();
570        }
571
572        if (argc != 2)
573                usage();
574
575        topdomain = strdup(argv[1]);
576        if(strlen(topdomain) <= 128) {
577                if(check_topdomain(topdomain)) {
578                        warnx("Topdomain contains invalid characters.\n");
579                        usage();
580                }
581        } else {
582                warnx("Use a topdomain max 128 chars long.\n");
583                usage();
584        }
585
586        if (username != NULL) {
587                if ((pw = getpwnam(username)) == NULL) {
588                        warnx("User %s does not exist!\n", username);
589                        usage();
590                }
591        }
592
593        if (mtu <= 0) {
594                warnx("Bad MTU given.\n");
595                usage();
596        }
597       
598        if(port < 1 || port > 65535) {
599                warnx("Bad port number given.\n");
600                usage();
601        }
602       
603        if (port != 53) {
604                printf("ALERT! Other dns servers expect you to run on port 53.\n");
605                printf("You must manually forward port 53 to port %d for things to work.\n", port);
606        }
607
608        if (listen_ip == INADDR_NONE) {
609                warnx("Bad IP address to listen on.\n");
610                usage();
611        }
612
613        if (strlen(password) == 0)
614                read_password(password, sizeof(password));
615
616        if ((tun_fd = open_tun(device)) == -1)
617                goto cleanup0;
618        if (!skipipconfig)
619                if (tun_setip(argv[0]) != 0 || tun_setmtu(mtu) != 0)
620                        goto cleanup1;
621        if ((dnsd_fd = open_dns(port, listen_ip)) == -1)
622                goto cleanup2;
623
624        my_ip = inet_addr(argv[0]);
625        my_mtu = mtu;
626        init_users(my_ip);
627
628        printf("Listening to dns for domain %s\n", topdomain);
629
630        if (foreground == 0)
631                do_detach();
632       
633        if (newroot != NULL)
634                do_chroot(newroot);
635
636        signal(SIGINT, sigint);
637        if (username != NULL) {
638                gid_t gids[1];
639                gids[0] = pw->pw_gid;
640                if (setgroups(1, gids) < 0 || setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {
641                        warnx("Could not switch to user %s!\n", username);
642                        usage();
643                }
644        }
645       
646        tunnel(tun_fd, dnsd_fd);
647
648cleanup2:
649        close_dns(dnsd_fd);
650cleanup1:
651        close_tun(tun_fd);     
652cleanup0:
653
654        return 0;
655}
Note: See TracBrowser for help on using the repository browser.