Remove trailing whitespace from debian/*.
[debian/iodine.git] / src / iodine.c
1 /*
2  * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
3  * 2006-2009 Bjorn Andersson <flex@kryo.se>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 #include <stdio.h>
19 #include <stdint.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <signal.h>
23 #include <unistd.h>
24 #include <sys/types.h>
25 #include <sys/param.h>
26 #include <sys/time.h>
27 #include <fcntl.h>
28 #include <time.h>
29
30 #ifdef WINDOWS32
31 #include "windows.h"
32 #include <winsock2.h>
33 #else
34 #include <grp.h>
35 #include <pwd.h>
36 #include <netdb.h>
37 #endif
38
39 #include "common.h"
40 #include "tun.h"
41 #include "client.h"
42 #include "util.h"
43
44 #ifdef WINDOWS32
45 WORD req_version = MAKEWORD(2, 2);
46 WSADATA wsa_data;
47 #endif
48
49 #if !defined(BSD) && !defined(__GLIBC__)
50 static char *__progname;
51 #endif
52
53 #define PASSWORD_ENV_VAR "IODINE_PASS"
54
55 static void
56 sighandler(int sig)
57 {
58         client_stop();
59 }
60
61 #if defined(__GNUC__) || defined(__clang__)
62 /* mark as no return to help some compilers to avoid warnings
63  * about use of uninitialized variables */
64 static void usage() __attribute__((noreturn));
65 #endif
66
67 static void
68 usage() {
69         extern char *__progname;
70
71         fprintf(stderr, "Usage: %s [-v] [-h] [-f] [-r] [-u user] [-t chrootdir] [-d device] "
72                         "[-P password] [-m maxfragsize] [-M maxlen] [-T type] [-O enc] [-L 0|1] [-I sec] "
73                         "[-z context] [-F pidfile] [nameserver] topdomain\n", __progname);
74         exit(2);
75 }
76
77 static void
78 help() {
79         extern char *__progname;
80
81         fprintf(stderr, "iodine IP over DNS tunneling client\n");
82         fprintf(stderr, "Usage: %s [-v] [-h] [-f] [-r] [-u user] [-t chrootdir] [-d device] "
83                         "[-P password] [-m maxfragsize] [-M maxlen] [-T type] [-O enc] [-L 0|1] [-I sec] "
84                         "[-z context] [-F pidfile] [nameserver] topdomain\n", __progname);
85         fprintf(stderr, "Options to try if connection doesn't work:\n");
86         fprintf(stderr, "  -T force dns type: NULL, PRIVATE, TXT, SRV, MX, CNAME, A (default: autodetect)\n");
87         fprintf(stderr, "  -O force downstream encoding for -T other than NULL: Base32, Base64, Base64u,\n");
88         fprintf(stderr, "     Base128, or (only for TXT:) Raw  (default: autodetect)\n");
89         fprintf(stderr, "  -I max interval between requests (default 4 sec) to prevent DNS timeouts\n");
90         fprintf(stderr, "  -L 1: use lazy mode for low-latency (default). 0: don't (implies -I1)\n");
91         fprintf(stderr, "  -m max size of downstream fragments (default: autodetect)\n");
92         fprintf(stderr, "  -M max size of upstream hostnames (~100-255, default: 255)\n");
93         fprintf(stderr, "  -r to skip raw UDP mode attempt\n");
94         fprintf(stderr, "  -P password used for authentication (max 32 chars will be used)\n");
95         fprintf(stderr, "Other options:\n");
96         fprintf(stderr, "  -v to print version info and exit\n");
97         fprintf(stderr, "  -h to print this help and exit\n");
98         fprintf(stderr, "  -f to keep running in foreground\n");
99         fprintf(stderr, "  -u name to drop privileges and run as user 'name'\n");
100         fprintf(stderr, "  -t dir to chroot to directory dir\n");
101         fprintf(stderr, "  -d device to set tunnel device name\n");
102         fprintf(stderr, "  -z context, to apply specified SELinux context after initialization\n");
103         fprintf(stderr, "  -F pidfile to write pid to a file\n");
104         fprintf(stderr, "nameserver is the IP number/hostname of the relaying nameserver. if absent, /etc/resolv.conf is used\n");
105         fprintf(stderr, "topdomain is the FQDN that is delegated to the tunnel endpoint.\n");
106
107         exit(0);
108 }
109
110 static void
111 version() {
112
113         fprintf(stderr, "iodine IP over DNS tunneling client\n");
114         fprintf(stderr, "version: 0.7.0 from 2014-06-16\n");
115
116         exit(0);
117 }
118
119 int
120 main(int argc, char **argv)
121 {
122         char *nameserv_host;
123         char *topdomain;
124         char *errormsg;
125 #ifndef WINDOWS32
126         struct passwd *pw;
127 #endif
128         char *username;
129         char password[33];
130         int foreground;
131         char *newroot;
132         char *context;
133         char *device;
134         char *pidfile;
135         int choice;
136         int tun_fd;
137         int dns_fd;
138         int max_downstream_frag_size;
139         int autodetect_frag_size;
140         int retval;
141         int raw_mode;
142         int lazymode;
143         int selecttimeout;
144         int hostname_maxlen;
145 #ifdef OPENBSD
146         int rtable = 0;
147 #endif
148         struct sockaddr_storage nameservaddr;
149         int nameservaddr_len;
150         int nameserv_family;
151
152         nameserv_host = NULL;
153         topdomain = NULL;
154         errormsg = NULL;
155 #ifndef WINDOWS32
156         pw = NULL;
157 #endif
158         username = NULL;
159         memset(password, 0, 33);
160         srand(time(NULL));
161         foreground = 0;
162         newroot = NULL;
163         context = NULL;
164         device = NULL;
165         pidfile = NULL;
166
167         autodetect_frag_size = 1;
168         max_downstream_frag_size = 3072;
169         retval = 0;
170         raw_mode = 1;
171         lazymode = 1;
172         selecttimeout = 4;
173         hostname_maxlen = 0xFF;
174         nameserv_family = AF_UNSPEC;
175
176 #ifdef WINDOWS32
177         WSAStartup(req_version, &wsa_data);
178 #endif
179
180         srand((unsigned) time(NULL));
181         client_init();
182
183 #if !defined(BSD) && !defined(__GLIBC__)
184         __progname = strrchr(argv[0], '/');
185         if (__progname == NULL)
186                 __progname = argv[0];
187         else
188                 __progname++;
189 #endif
190
191         while ((choice = getopt(argc, argv, "46vfhru:t:d:R:P:m:M:F:T:O:L:I:")) != -1) {
192                 switch(choice) {
193                 case '4':
194                         nameserv_family = AF_INET;
195                         break;
196                 case '6':
197                         nameserv_family = AF_INET6;
198                         break;
199                 case 'v':
200                         version();
201                         /* NOTREACHED */
202                         break;
203                 case 'f':
204                         foreground = 1;
205                         break;
206                 case 'h':
207                         help();
208                         /* NOTREACHED */
209                         break;
210                 case 'r':
211                         raw_mode = 0;
212                         break;
213                 case 'u':
214                         username = optarg;
215                         break;
216                 case 't':
217                         newroot = optarg;
218                         break;
219                 case 'd':
220                         device = optarg;
221                         break;
222 #ifdef OPENBSD
223                 case 'R':
224                         rtable = atoi(optarg);
225                         break;
226 #endif
227                 case 'P':
228                         strncpy(password, optarg, sizeof(password));
229                         password[sizeof(password)-1] = 0;
230
231                         /* XXX: find better way of cleaning up ps(1) */
232                         memset(optarg, 0, strlen(optarg));
233                         break;
234                 case 'm':
235                         autodetect_frag_size = 0;
236                         max_downstream_frag_size = atoi(optarg);
237                         break;
238                 case 'M':
239                         hostname_maxlen = atoi(optarg);
240                         if (hostname_maxlen > 255)
241                                 hostname_maxlen = 255;
242                         if (hostname_maxlen < 10)
243                                 hostname_maxlen = 10;
244                         break;
245                 case 'z':
246                         context = optarg;
247                         break;
248                 case 'F':
249                         pidfile = optarg;
250                         break;
251                 case 'T':
252                         if (client_set_qtype(optarg))
253                                 errx(5, "Invalid query type '%s'", optarg);
254                         break;
255                 case 'O':       /* not -D, is Debug in server */
256                         client_set_downenc(optarg);
257                         break;
258                 case 'L':
259                         lazymode = atoi(optarg);
260                         if (lazymode > 1)
261                                 lazymode = 1;
262                         if (lazymode < 0)
263                                 lazymode = 0;
264                         if (!lazymode)
265                                 selecttimeout = 1;
266                         break;
267                 case 'I':
268                         selecttimeout = atoi(optarg);
269                         if (selecttimeout < 1)
270                                 selecttimeout = 1;
271                         break;
272                 default:
273                         usage();
274                         /* NOTREACHED */
275                 }
276         }
277
278         check_superuser(usage);
279
280         argc -= optind;
281         argv += optind;
282
283         switch (argc) {
284         case 1:
285                 nameserv_host = get_resolvconf_addr();
286                 topdomain = strdup(argv[0]);
287                 break;
288         case 2:
289                 nameserv_host = argv[0];
290                 topdomain = strdup(argv[1]);
291                 break;
292         default:
293                 usage();
294                 /* NOTREACHED */
295         }
296
297         if (max_downstream_frag_size < 1 || max_downstream_frag_size > 0xffff) {
298                 warnx("Use a max frag size between 1 and 65535 bytes.\n");
299                 usage();
300                 /* NOTREACHED */
301         }
302
303         if (nameserv_host) {
304                 nameservaddr_len = get_addr(nameserv_host, DNS_PORT, nameserv_family, 0, &nameservaddr);
305                 if (nameservaddr_len < 0) {
306                         errx(1, "Cannot lookup nameserver '%s': %s ",
307                                 nameserv_host, gai_strerror(nameservaddr_len));
308                 }
309                 client_set_nameserver(&nameservaddr, nameservaddr_len);
310         } else {
311                 warnx("No nameserver found - not connected to any network?\n");
312                 usage();
313                 /* NOTREACHED */
314         }
315
316         if(check_topdomain(topdomain, &errormsg)) {
317                 warnx("Invalid topdomain: %s", errormsg);
318                 usage();
319                 /* NOTREACHED */
320         }
321
322         client_set_selecttimeout(selecttimeout);
323         client_set_lazymode(lazymode);
324         client_set_topdomain(topdomain);
325         client_set_hostname_maxlen(hostname_maxlen);
326
327         if (username != NULL) {
328 #ifndef WINDOWS32
329                 if ((pw = getpwnam(username)) == NULL) {
330                         warnx("User %s does not exist!\n", username);
331                         usage();
332                         /* NOTREACHED */
333                 }
334 #endif
335         }
336
337         if (strlen(password) == 0) {
338                 if (NULL != getenv(PASSWORD_ENV_VAR))
339                         snprintf(password, sizeof(password), "%s", getenv(PASSWORD_ENV_VAR));
340                 else
341                         read_password(password, sizeof(password));
342         }
343
344         client_set_password(password);
345
346         if ((tun_fd = open_tun(device)) == -1) {
347                 retval = 1;
348                 goto cleanup1;
349         }
350         if ((dns_fd = open_dns_from_host(NULL, 0, nameservaddr.ss_family, AI_PASSIVE)) < 0) {
351                 retval = 1;
352                 goto cleanup2;
353         }
354 #ifdef OPENBSD
355         if (rtable > 0)
356                 socket_setrtable(dns_fd, rtable);
357 #endif
358
359         signal(SIGINT, sighandler);
360         signal(SIGTERM, sighandler);
361
362         fprintf(stderr, "Sending DNS queries for %s to %s\n",
363                 topdomain, format_addr(&nameservaddr, nameservaddr_len));
364
365         if (client_handshake(dns_fd, raw_mode, autodetect_frag_size, max_downstream_frag_size)) {
366                 retval = 1;
367                 goto cleanup2;
368         }
369
370         if (client_get_conn() == CONN_RAW_UDP) {
371                 fprintf(stderr, "Sending raw traffic directly to %s\n", client_get_raw_addr());
372         }
373
374         fprintf(stderr, "Connection setup complete, transmitting data.\n");
375
376         if (foreground == 0)
377                 do_detach();
378
379         if (pidfile != NULL)
380                 do_pidfile(pidfile);
381
382         if (newroot != NULL)
383                 do_chroot(newroot);
384
385         if (username != NULL) {
386 #ifndef WINDOWS32
387                 gid_t gids[1];
388                 gids[0] = pw->pw_gid;
389                 if (setgroups(1, gids) < 0 || setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {
390                         warnx("Could not switch to user %s!\n", username);
391                         usage();
392                         /* NOTREACHED */
393                 }
394 #endif
395         }
396
397         if (context != NULL)
398                 do_setcon(context);
399
400         client_tunnel(tun_fd, dns_fd);
401
402 cleanup2:
403         close_dns(dns_fd);
404         close_tun(tun_fd);
405 cleanup1:
406
407         return retval;
408 }
409