source: src/iodined.c @ 5641fa

Revision 5641fa, 9.3 KB checked in by Erik Ekman <yarrick@…>, 7 years ago (diff)

use srand()

  • Property mode set to 100644
Line 
1/*
2 * Copyright (c) 2006 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 <netinet/in.h>
22#include <signal.h>
23#include <unistd.h>
24#include <sys/types.h>
25#include <sys/socket.h>
26#include <sys/stat.h>
27#include <fcntl.h>
28#include <err.h>
29#include <time.h>
30#include <pwd.h>
31#include <arpa/inet.h>
32#include <netinet/in.h>
33#include <zlib.h>
34
35#include "tun.h"
36#include "structs.h"
37#include "dns.h"
38#include "login.h"
39#include "version.h"
40
41#ifndef MAX
42#define MAX(a,b) ((a)>(b)?(a):(b))
43#endif
44
45int running = 1;
46
47struct packet packetbuf;
48struct packet outpacket;
49int outid;
50
51struct query q;
52
53struct user u;
54char password[33];
55
56int my_mtu;
57in_addr_t my_ip;
58
59static void
60sigint(int sig) {
61        running = 0;
62}
63
64static int
65tunnel(int tun_fd, int dns_fd)
66{
67        struct in_addr clientip;
68        struct in_addr myip;
69        struct timeval tv;
70        char out[64*1024];
71        char in[64*1024];
72        char *tmp[2];
73        char logindata[16];
74        long outlen;
75        fd_set fds;
76        int read;
77        int code;
78        int version;
79        int seed;
80        int nseed;
81        int i;
82
83        while (running) {
84                if (q.id != 0) {
85                        tv.tv_sec = 0;
86                        tv.tv_usec = 5000;
87                } else {
88                        tv.tv_sec = 1;
89                        tv.tv_usec = 0;
90                }
91
92                FD_ZERO(&fds);
93                if(outpacket.len == 0)
94                        FD_SET(tun_fd, &fds);
95                FD_SET(dns_fd, &fds);
96
97                i = select(MAX(tun_fd, dns_fd) + 1, &fds, NULL, NULL, &tv);
98               
99                if(i < 0) {
100                        if (running)
101                                warn("select");
102                        return 1;
103                }
104       
105                if (i==0) {     
106                        if (q.id != 0) {
107                                dnsd_send(dns_fd, &q, outpacket.data, outpacket.len);
108                                outpacket.len = 0;
109                                q.id = 0;
110                        }
111                } else {
112                        if(FD_ISSET(tun_fd, &fds)) {
113                                read = read_tun(tun_fd, in, sizeof(in));
114                                if (read <= 0)
115                                        continue;
116                               
117                                outlen = sizeof(out);
118                                compress2(out, &outlen, in, read, 9);
119                                memcpy(outpacket.data, out, outlen);
120                                outpacket.len = outlen;
121                        }
122                        if(FD_ISSET(dns_fd, &fds)) {
123                                read = dnsd_read(dns_fd, &q, in, sizeof(in));
124                                if (read <= 0)
125                                        continue;
126
127                                if(in[0] == 'V' || in[0] == 'v') {
128                                        // Version greeting, compare and send ack/nak
129                                        if (read >= 5) { // Received V + 32bits version
130                                                memcpy(&version, in + 1, 4);
131                                                version = ntohl(version);
132                                                if (version == VERSION) {
133                                                        seed = rand();
134                                                        nseed = htonl(seed);
135                                                        strcpy(out, "VACK");
136                                                        memcpy(out+4, &nseed, 4);
137                                                        dnsd_send(dns_fd, &q, out, 8);
138
139                                                        memcpy(&(u.host), &(q.from), q.fromlen);
140                                                        u.addrlen = q.fromlen;
141                                                } else {
142                                                        version = htonl(VERSION);
143                                                        strcpy(out, "VNAK");
144                                                        memcpy(out+4, &version, 4);
145                                                        dnsd_send(dns_fd, &q, out, 8);
146                                                }
147                                        } else {
148                                                version = htonl(VERSION);
149                                                strcpy(out, "VNAK");
150                                                memcpy(out+4, &version, 4);
151                                                dnsd_send(dns_fd, &q, out, 8);
152                                        }
153                                } else if(in[0] == 'L' || in[0] == 'l') {
154                                        // Check sending ip number
155                                        if (q.fromlen != u.addrlen ||
156                                                memcmp(&(u.host), &(q.from), q.fromlen) != 0) {
157                                                dnsd_send(dns_fd, &q, "BADIP", 5);
158                                        } else {
159                                                // Login phase, handle auth
160                                                login_calculate(logindata, 16, password, seed);
161                                                if (read >= 17 && (memcmp(logindata, in+1, 16) == 0)) {
162                                                        // Login ok, send ip/mtu info
163                                                        myip.s_addr = my_ip;
164                                                        clientip.s_addr = my_ip + inet_addr("0.0.0.1");
165
166                                                        tmp[0] = strdup(inet_ntoa(myip));
167                                                        tmp[1] = strdup(inet_ntoa(clientip));
168                                                       
169                                                        read = snprintf(out, sizeof(out), "%s-%s-%d",
170                                                                        tmp[0], tmp[1], my_mtu);
171
172                                                        dnsd_send(dns_fd, &q, out, read);
173                                                        q.id = 0;
174
175                                                        free(tmp[1]);
176                                                        free(tmp[0]);
177                                                } else {
178                                                        dnsd_send(dns_fd, &q, "LNAK", 4);
179                                                }
180                                        }
181                                } else if((in[0] >= '0' && in[0] <= '9')
182                                                || (in[0] >= 'a' && in[0] <= 'f')
183                                                || (in[0] >= 'A' && in[0] <= 'F')) {
184                                        if ((in[0] >= '0' && in[0] <= '9'))
185                                                code = in[0] - '0';
186                                        if ((in[0] >= 'a' && in[0] <= 'f'))
187                                                code = in[0] - 'a' + 10;
188                                        if ((in[0] >= 'A' && in[0] <= 'F'))
189                                                code = in[0] - 'A' + 10;
190                                       
191                                        // Check sending ip number
192                                        if (q.fromlen != u.addrlen ||
193                                                memcmp(&(u.host), &(q.from), q.fromlen) != 0) {
194                                                dnsd_send(dns_fd, &q, "BADIP", 5);
195                                        } else {
196                                                memcpy(packetbuf.data + packetbuf.offset, in + 1, read - 1);
197                                                packetbuf.len += read - 1;
198                                                packetbuf.offset += read - 1;
199
200                                                if (code & 1) {
201                                                        outlen = sizeof(out);
202                                                        uncompress(out, &outlen, packetbuf.data, packetbuf.len);
203
204                                                        write_tun(tun_fd, out, outlen);
205
206                                                        packetbuf.len = packetbuf.offset = 0;
207                                                }
208                                        }
209                                }
210                                if (q.fromlen == u.addrlen &&
211                                        memcmp(&(u.host), &(q.from), q.fromlen) == 0 &&
212                                        outpacket.len > 0) {
213
214                                        dnsd_send(dns_fd, &q, outpacket.data, outpacket.len);
215                                        outpacket.len = 0;
216                                        q.id = 0;
217                                }
218                        }
219                }
220        }
221
222        return 0;
223}
224
225static void
226usage() {
227        extern char *__progname;
228
229        printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] [-m mtu] "
230                "[-l ip address to listen on] [-p port] [-P password]"
231                " tunnel_ip topdomain\n", __progname);
232        exit(2);
233}
234
235static void
236help() {
237        extern char *__progname;
238
239        printf("iodine IP over DNS tunneling server\n");
240        printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] [-m mtu] "
241                "[-l ip address to listen on] [-p port] [-P password]"
242                " tunnel_ip topdomain\n", __progname);
243        printf("  -v to print version info and exit\n");
244        printf("  -h to print this help and exit\n");
245        printf("  -f to keep running in foreground\n");
246        printf("  -u name to drop privileges and run as user 'name'\n");
247        printf("  -t dir to chroot to directory dir\n");
248        printf("  -d device to set tunnel device name\n");
249        printf("  -m mtu to set tunnel device mtu\n");
250        printf("  -l ip address to listen on for incoming dns traffic (default 0.0.0.0)\n");
251        printf("  -p port to listen on for incoming dns traffic (default 53)\n");
252        printf("  -P password used for authentication (max 32 chars will be used)\n");
253        printf("tunnel_ip is the IP number of the local tunnel interface.\n");
254        printf("topdomain is the FQDN that is delegated to this server.\n");
255        exit(0);
256}
257
258static void
259version() {
260        char *svnver = "$Rev$ from $Date$";
261        printf("iodine IP over DNS tunneling server\n");
262        printf("SVN version: %s\n", svnver);
263        exit(0);
264}
265
266int
267main(int argc, char **argv)
268{
269        int choice;
270        int tun_fd;
271        int dnsd_fd;
272        char *newroot;
273        char *username;
274        char *device;
275        int foreground;
276        int mtu;
277        struct passwd *pw;
278        in_addr_t listen_ip;
279        int port;
280
281        username = NULL;
282        newroot = NULL;
283        device = NULL;
284        foreground = 0;
285        mtu = 1024;
286        listen_ip = INADDR_ANY;
287        port = 53;
288
289        packetbuf.len = 0;
290        packetbuf.offset = 0;
291        outpacket.len = 0;
292        q.id = 0;
293        memset(password, 0, 33);
294        srand(time(NULL));
295       
296        while ((choice = getopt(argc, argv, "vfhu:t:d:m:l:p:P:")) != -1) {
297                switch(choice) {
298                case 'v':
299                        version();
300                        break;
301                case 'f':
302                        foreground = 1;
303                        break;
304                case 'h':
305                        help();
306                        break;
307                case 'u':
308                        username = optarg;
309                        break;
310                case 't':
311                        newroot = optarg;
312                        break;
313                case 'd':
314                        device = optarg;
315                        break;
316                case 'm':
317                        mtu = atoi(optarg);
318                        break;
319                case 'l':
320                        listen_ip = inet_addr(optarg);
321                        break;
322                case 'p':
323                        port = atoi(optarg);
324                        if (port) {
325                                printf("ALERT! Other dns servers expect you to run on port 53.\n");
326                                printf("You must manually forward port 53 to port %d for things to work.\n", port);
327                        }
328                        break;
329                case 'P':
330                        strncpy(password, optarg, 32);
331                        password[32] = 0;
332                        break;
333                default:
334                        usage();
335                        break;
336                }
337        }
338
339        argc -= optind;
340        argv += optind;
341       
342        if (geteuid() != 0) {
343                printf("Run as root and you'll be happy.\n");
344                usage();
345        }
346
347        if (argc != 2)
348                usage();
349
350        if (username) {
351                pw = getpwnam(username);
352                if (!pw) {
353                        printf("User %s does not exist!\n", username);
354                        usage();
355                }
356        }
357
358        if (mtu == 0) {
359                printf("Bad MTU given.\n");
360                usage();
361        }
362
363        if (listen_ip == INADDR_NONE) {
364                printf("Bad IP address to listen on.\n");
365                usage();
366        }
367
368        if (strlen(password) == 0) {
369                printf("Enter password on stdin:\n");
370                scanf("%32s", password);
371                password[32] = 0;
372        }
373
374        if ((tun_fd = open_tun(device)) == -1)
375                goto cleanup0;
376        if (tun_setip(argv[0]) != 0 || tun_setmtu(mtu) != 0)
377                goto cleanup1;
378        if ((dnsd_fd = open_dns(argv[1], port, listen_ip)) == -1)
379                goto cleanup2;
380
381        my_ip = inet_addr(argv[0]);
382        my_mtu = mtu;
383
384        printf("Listening to dns for domain %s\n", argv[1]);
385
386        if (newroot) {
387                if (chroot(newroot) != 0 || chdir("/") != 0)
388                        err(1, "%s", newroot);
389                seteuid(geteuid());
390                setuid(getuid());
391        }
392       
393        if (!foreground) {
394                printf("Detaching from terminal...\n");
395                daemon(0, 0);
396                umask(0);
397                alarm(0);
398        }
399
400        signal(SIGINT, sigint);
401        if (username) {
402                if (setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {
403                        printf("Could not switch to user %s!\n", username);
404                        usage();
405                }
406        }
407       
408        tunnel(tun_fd, dnsd_fd);
409
410cleanup2:
411        close_dns(dnsd_fd);
412cleanup1:
413        close_tun(tun_fd);     
414cleanup0:
415
416        return 0;
417}
Note: See TracBrowser for help on using the repository browser.