8f75b8de61849325d4b893cc217b2b2b5613cdde
[debian/uanytun.git] / src / options.c
1 /*
2  *  uAnytun
3  *
4  *  uAnytun is a tiny implementation of SATP. Unlike Anytun which is a full
5  *  featured implementation uAnytun has no support for multiple connections
6  *  or synchronisation. It is a small single threaded implementation intended
7  *  to act as a client on small platforms.
8  *  The secure anycast tunneling protocol (satp) defines a protocol used
9  *  for communication between any combination of unicast and anycast
10  *  tunnel endpoints.  It has less protocol overhead than IPSec in Tunnel
11  *  mode and allows tunneling of every ETHER TYPE protocol (e.g.
12  *  ethernet, ip, arp ...). satp directly includes cryptography and
13  *  message authentication based on the methods used by SRTP.  It is
14  *  intended to deliver a generic, scaleable and secure solution for
15  *  tunneling and relaying of packets of any protocol.
16  *
17  *
18  *  Copyright (C) 2007-2014 Christian Pointner <equinox@anytun.org>
19  *
20  *  This file is part of uAnytun.
21  *
22  *  uAnytun is free software: you can redistribute it and/or modify
23  *  it under the terms of the GNU General Public License as published by
24  *  the Free Software Foundation, either version 3 of the License, or
25  *  any later version.
26  *
27  *  uAnytun is distributed in the hope that it will be useful,
28  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
29  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
30  *  GNU General Public License for more details.
31  *
32  *  You should have received a copy of the GNU General Public License
33  *  along with uAnytun. If not, see <http://www.gnu.org/licenses/>.
34  *
35  *  In addition, as a special exception, the copyright holders give
36  *  permission to link the code of portions of this program with the
37  *  OpenSSL library under certain conditions as described in each
38  *  individual source file, and distribute linked combinations
39  *  including the two.
40  *  You must obey the GNU General Public License in all respects
41  *  for all of the code used other than OpenSSL.  If you modify
42  *  file(s) with this exception, you may extend this exception to your
43  *  version of the file(s), but you are not obligated to do so.  If you
44  *  do not wish to do so, delete this exception statement from your
45  *  version.  If you delete this exception statement from all source
46  *  files in the program, then also delete it here.
47  */
48
49 #include "datatypes.h"
50 #include "version.h"
51
52 #include "options.h"
53
54 #include <stdlib.h>
55 #include <stdio.h>
56 #include <string.h>
57 #include <ctype.h>
58
59 #include "log.h"
60
61 #ifndef NO_CRYPT
62 #include "auth_algo.h"
63 #endif
64
65 #define PARSE_BOOL_PARAM(SHORT, LONG, VALUE)             \
66     else if(!strcmp(str,SHORT) || !strcmp(str,LONG))     \
67       VALUE = 1;
68
69 #define PARSE_INVERSE_BOOL_PARAM(SHORT, LONG, VALUE)     \
70     else if(!strcmp(str,SHORT) || !strcmp(str,LONG))     \
71       VALUE = 0;
72
73 #define PARSE_INT_PARAM(SHORT, LONG, VALUE)              \
74     else if(!strcmp(str,SHORT) || !strcmp(str,LONG))     \
75     {                                                    \
76       if(argc < 1)                                       \
77         return i;                                        \
78       VALUE = atoi(argv[i+1]);                           \
79       argc--;                                            \
80       i++;                                               \
81     }
82
83 #define PARSE_STRING_PARAM(SHORT, LONG, VALUE)           \
84     else if(!strcmp(str,SHORT) || !strcmp(str,LONG))     \
85     {                                                    \
86       if(argc < 1 || argv[i+1][0] == '-')                \
87         return i;                                        \
88       if(VALUE) free(VALUE);                             \
89       VALUE = strdup(argv[i+1]);                         \
90       if(!VALUE)                                         \
91         return -2;                                       \
92       argc--;                                            \
93       i++;                                               \
94     }
95
96 #define PARSE_STRING_PARAM_SEC(SHORT, LONG, VALUE)       \
97     else if(!strcmp(str,SHORT) || !strcmp(str,LONG))     \
98     {                                                    \
99       if(argc < 1 || argv[i+1][0] == '-')                \
100         return i;                                        \
101       if(VALUE) free(VALUE);                             \
102       VALUE = strdup(argv[i+1]);                         \
103       if(!VALUE)                                         \
104         return -2;                                       \
105       size_t j;                                          \
106       for(j=0; j < strlen(argv[i+1]); ++j)               \
107         argv[i+1][j] = '#';                              \
108       argc--;                                            \
109       i++;                                               \
110     }
111
112 #define PARSE_IFCONFIG_PARAM(SHORT, LONG, VALUE)         \
113     else if(!strcmp(str,SHORT) || !strcmp(str,LONG))     \
114     {                                                    \
115       if(argc < 1 || argv[i+1][0] == '-')                \
116         return i;                                        \
117       int ret;                                           \
118       ret = options_parse_ifconfig(argv[i+1], &VALUE);   \
119       if(ret > 0)                                        \
120         return i+1;                                      \
121       if(ret < 0)                                        \
122         return ret;                                      \
123       argc--;                                            \
124       i++;                                               \
125     }
126
127 #define PARSE_HEXSTRING_PARAM_SEC(SHORT, LONG, VALUE)    \
128     else if(!strcmp(str,SHORT) || !strcmp(str,LONG))     \
129     {                                                    \
130       if(argc < 1 || argv[i+1][0] == '-')                \
131         return i;                                        \
132       int ret;                                           \
133       ret = options_parse_hex_string(argv[i+1], &VALUE); \
134       if(ret > 0)                                        \
135         return i+1;                                      \
136       else if(ret < 0)                                   \
137         return ret;                                      \
138       size_t j;                                          \
139       for(j=0; j < strlen(argv[i+1]); ++j)               \
140         argv[i+1][j] = '#';                              \
141       argc--;                                            \
142       i++;                                               \
143     }
144
145 #define PARSE_STRING_LIST(SHORT, LONG, LIST)             \
146     else if(!strcmp(str,SHORT) || !strcmp(str,LONG))     \
147     {                                                    \
148       if(argc < 1 || argv[i+1][0] == '-')                \
149         return i;                                        \
150       int ret = string_list_add(&LIST, argv[i+1]);       \
151       if(ret == -2)                                      \
152         return ret;                                      \
153       else if(ret)                                       \
154         return i+1;                                      \
155       argc--;                                            \
156       i++;                                               \
157     }
158
159 int options_parse_hex_string(const char* hex, buffer_t* buffer)
160 {
161   if(!hex || !buffer)
162     return -1;
163
164   u_int32_t hex_len = strlen(hex);
165   if(hex_len%2)
166     return 1;
167
168   if(buffer->buf_)
169     free(buffer->buf_);
170
171   buffer->length_ = hex_len/2;
172   buffer->buf_ = malloc(buffer->length_);
173   if(!buffer->buf_) {
174     buffer->length_ = 0;
175     return -2;
176   }
177
178   const char* ptr = hex;
179   int i;
180   for(i=0;i<buffer->length_;++i) {
181     u_int32_t tmp;
182     sscanf(ptr, "%2X", &tmp);
183     buffer->buf_[i] = (u_int8_t)tmp;
184     ptr += 2;
185   }
186
187   return 0;
188 }
189
190 int options_parse_ifconfig(const char* arg, ifconfig_param_t* ifcfg)
191 {
192   char* str = strdup(arg);
193   if(!str)
194     return -2;
195
196   char* ptr = str;
197   for(;*ptr;++ptr) {
198     if(*ptr == '/') {
199       *ptr = 0;
200       ptr++;
201       if(!(*ptr)) {
202         free(str);
203         return 1;
204       }
205
206       ifcfg->prefix_length_ = atoi(ptr);
207       ifcfg->net_addr_ = strdup(str);
208       free(str);
209
210       if(!ifcfg->net_addr_)
211         return -2;
212
213       return 0;
214     }
215     if(!isdigit(*ptr) && *ptr != '.') {
216       free(str);
217       return 1;
218     }
219   }
220
221   free(str);
222   return 1;
223 }
224
225 int options_parse(options_t* opt, int argc, char* argv[])
226 {
227   if(!opt)
228     return -1;
229
230   options_default(opt);
231
232   if(opt->progname_)
233     free(opt->progname_);
234   opt->progname_ = strdup(argv[0]);
235   if(!opt->progname_)
236     return -2;
237
238   argc--;
239
240 #ifndef NO_CRYPT
241   char* role = NULL;
242 #endif
243   int i, ipv4_only = 0, ipv6_only = 0;
244   for(i=1; argc > 0; ++i)
245   {
246     char* str = argv[i];
247     argc--;
248
249     if(!strcmp(str,"-h") || !strcmp(str,"--help"))
250       return -1;
251     else if(!strcmp(str,"-v") || !strcmp(str,"--version"))
252       return -5;
253     PARSE_INVERSE_BOOL_PARAM("-D","--nodaemonize", opt->daemonize_)
254     PARSE_STRING_PARAM("-u","--username", opt->username_)
255     PARSE_STRING_PARAM("-g","--groupname", opt->groupname_)
256     PARSE_STRING_PARAM("-C","--chroot", opt->chroot_dir_)
257     PARSE_STRING_PARAM("-P","--write-pid", opt->pid_file_)
258     PARSE_STRING_PARAM("-i","--interface", opt->local_addr_)
259     PARSE_STRING_PARAM("-p","--port", opt->local_port_)
260     PARSE_INT_PARAM("-s","--sender-id", opt->sender_id_)
261     PARSE_STRING_LIST("-L","--log", opt->log_targets_)
262     PARSE_BOOL_PARAM("-U", "--debug", opt->debug_)
263     PARSE_STRING_PARAM("-r","--remote-host", opt->remote_addr_)
264     PARSE_STRING_PARAM("-o","--remote-port", opt->remote_port_)
265     PARSE_BOOL_PARAM("-4","--ipv4-only", ipv4_only)
266     PARSE_BOOL_PARAM("-6","--ipv6-only", ipv6_only)
267     PARSE_STRING_PARAM("-d","--dev", opt->dev_name_)
268     PARSE_STRING_PARAM("-t","--type", opt->dev_type_)
269     PARSE_IFCONFIG_PARAM("-n","--ifconfig", opt->ifconfig_param_)
270     PARSE_STRING_PARAM("-x","--post-up-script", opt->post_up_script_)
271     PARSE_INT_PARAM("-m","--mux", opt->mux_)
272     PARSE_INT_PARAM("-w","--window-size", opt->seq_window_size_)
273 #ifndef NO_CRYPT
274     PARSE_STRING_PARAM("-k","--kd-prf", opt->kd_prf_)
275 #ifndef NO_PASSPHRASE
276     PARSE_STRING_PARAM_SEC("-E","--passphrase", opt->passphrase_)
277 #endif
278     PARSE_STRING_PARAM("-e","--role", role)
279     PARSE_HEXSTRING_PARAM_SEC("-K","--key", opt->key_)
280     PARSE_HEXSTRING_PARAM_SEC("-A","--salt", opt->salt_)
281     PARSE_STRING_PARAM("-c","--cipher", opt->cipher_)
282     PARSE_STRING_PARAM("-a","--auth-algo", opt->auth_algo_)
283     PARSE_INT_PARAM("-b","--auth-tag-length", opt->auth_tag_length_)
284 #endif
285     else
286       return i;
287   }
288   if(ipv4_only && ipv6_only)
289     return -3;
290   if(ipv4_only)
291     opt->resolv_addr_type_ = IPV4_ONLY;
292   if(ipv6_only)
293     opt->resolv_addr_type_ = IPV6_ONLY;
294
295   if(opt->debug_) {
296     string_list_add(&opt->log_targets_, "stdout:5");
297     opt->daemonize_ = 0;
298   }
299
300   if(!opt->log_targets_.first_)
301     string_list_add(&opt->log_targets_, "syslog:3,uanytun,daemon");
302
303 #ifndef NO_CRYPT
304   if(role) {
305     if(!strcmp(role, "alice") || !strcmp(role, "server") || !strcmp(role, "left"))
306       opt->role_ = ROLE_LEFT;
307     else if(!strcmp(role, "bob") || !strcmp(role, "client") || !strcmp(role, "right"))
308       opt->role_ = ROLE_RIGHT;
309     else {
310       free(role);
311       return -4;
312     }
313     free(role);
314   }
315 #endif
316   return 0;
317 }
318
319 void options_parse_post(options_t* opt)
320 {
321   if(!opt)
322     return;
323
324 #ifndef NO_CRYPT
325   if(!strcmp(opt->cipher_, "null") && !strcmp(opt->auth_algo_, "null") &&
326      strcmp(opt->kd_prf_, "null")) {
327     if(opt->kd_prf_)
328       free(opt->kd_prf_);
329     opt->kd_prf_ = strdup("null");
330   }
331   if((strcmp(opt->cipher_, "null") || strcmp(opt->auth_algo_, "null")) &&
332      !strcmp(opt->kd_prf_, "null")) {
333     log_printf(WARNING, "using NULL key derivation with encryption and or authentication enabled!");
334   }
335
336   u_int32_t tag_len_max = auth_algo_get_max_length(opt->auth_algo_);
337   if(!tag_len_max) opt->auth_tag_length_ = 0;
338   else if(tag_len_max < opt->auth_tag_length_) {
339     log_printf(WARNING, "%s auth algo can't generate tags of length %d, using maximum tag length(%d)", opt->auth_algo_, opt->auth_tag_length_, tag_len_max);
340     opt->auth_tag_length_ = tag_len_max;
341   }
342 #endif
343
344   if(!(opt->dev_name_) && !(opt->dev_type_))
345     opt->dev_type_ = strdup("tun");
346 }
347
348 void options_default(options_t* opt)
349 {
350   if(!opt)
351     return;
352
353   opt->progname_ = strdup("uanytun");
354   opt->daemonize_ = 1;
355   opt->username_ = NULL;
356   opt->groupname_ = NULL;
357   opt->chroot_dir_ = NULL;
358   opt->pid_file_ = NULL;
359   string_list_init(&opt->log_targets_);
360   opt->debug_ = 0;
361   opt->local_addr_ = NULL;
362   opt->local_port_ = strdup("4444");
363   opt->sender_id_ = 0;
364   opt->remote_addr_ = NULL;
365   opt->remote_port_ = strdup("4444");
366   opt->resolv_addr_type_ = ANY;
367   opt->dev_name_ = NULL;
368   opt->dev_type_ = NULL;
369   opt->ifconfig_param_.net_addr_ = NULL;
370   opt->ifconfig_param_.prefix_length_ = 0;
371   opt->post_up_script_ = NULL;
372   opt->mux_ = 0;
373   opt->seq_window_size_ = 0;
374 #ifndef NO_CRYPT
375   opt->kd_prf_ = strdup("aes-ctr");
376   opt->passphrase_ = NULL;
377   opt->role_ = ROLE_LEFT;
378   opt->cipher_ = strdup("aes-ctr");
379   opt->auth_algo_ = strdup("sha1");
380   opt->auth_tag_length_ = 10;
381 #else
382   opt->cipher_ = strdup("null");
383   opt->auth_tag_length_ = 0;
384 #endif
385   opt->key_.buf_ = NULL;
386   opt->key_.length_ = 0;
387   opt->salt_.buf_ = NULL;
388   opt->salt_.length_ = 0;
389 }
390
391 void options_clear(options_t* opt)
392 {
393   if(!opt)
394     return;
395
396   if(opt->progname_)
397     free(opt->progname_);
398   if(opt->username_)
399     free(opt->username_);
400   if(opt->groupname_)
401     free(opt->groupname_);
402   if(opt->chroot_dir_)
403     free(opt->chroot_dir_);
404   if(opt->pid_file_)
405     free(opt->pid_file_);
406   string_list_clear(&opt->log_targets_);
407   if(opt->local_addr_)
408     free(opt->local_addr_);
409   if(opt->local_port_)
410     free(opt->local_port_);
411   if(opt->remote_addr_)
412     free(opt->remote_addr_);
413   if(opt->remote_port_)
414     free(opt->remote_port_);
415   if(opt->dev_name_)
416     free(opt->dev_name_);
417   if(opt->dev_type_)
418     free(opt->dev_type_);
419   if(opt->ifconfig_param_.net_addr_)
420     free(opt->ifconfig_param_.net_addr_);
421   if(opt->post_up_script_)
422     free(opt->post_up_script_);
423   if(opt->cipher_)
424     free(opt->cipher_);
425 #ifndef NO_CRYPT
426   if(opt->auth_algo_)
427     free(opt->auth_algo_);
428   if(opt->kd_prf_)
429     free(opt->kd_prf_);
430   if(opt->passphrase_)
431     free(opt->passphrase_);
432 #endif
433   if(opt->key_.buf_)
434     free(opt->key_.buf_);
435   if(opt->salt_.buf_)
436     free(opt->salt_.buf_);
437 }
438
439 void options_print_usage()
440 {
441   printf("USAGE:\n");
442   printf("uanytun [-h|--help]                         prints this...\n");
443   printf("        [-v|--version]                      print version info and exit\n");
444   printf("        [-D|--nodaemonize]                  don't run in background\n");
445   printf("        [-u|--username] <username>          change to this user\n");
446   printf("        [-g|--groupname] <groupname>        change to this group\n");
447   printf("        [-C|--chroot] <path>                chroot to this directory\n");
448   printf("        [-P|--write-pid] <path>             write pid to this file\n");
449   printf("        [-i|--interface] <ip-address>       local ip address to bind to\n");
450   printf("        [-p|--port] <port>                  local port to bind to\n");
451   printf("        [-s|--sender-id ] <sender id>       the sender id to use\n");
452   printf("        [-L|--log] <target>:<level>[,<param1>[,<param2>..]]\n");
453   printf("                                            add a log target, can be invoked several times\n");
454   printf("        [-U|--debug]                        don't daemonize and log to stdout with maximum log level\n");
455
456   printf("        [-r|--remote-host] <hostname|ip>    remote host\n");
457   printf("        [-o|--remote-port] <port>           remote port\n");
458   printf("        [-4|--ipv4-only]                    always resolv IPv4 addresses\n");
459   printf("        [-6|--ipv6-only]                    always resolv IPv6 addresses\n");
460   printf("        [-d|--dev] <name>                   device name\n");
461   printf("        [-t|--type] <tun|tap>               device type\n");
462
463   printf("        [-n|--ifconfig] <local>/<prefix>    the local address for the tun/tap device and the used prefix length\n");
464   printf("        [-x|--post-up-script] <script>      script gets called after interface is created\n");
465   printf("        [-m|--mux] <mux-id>                 the multiplex id to use\n");
466   printf("        [-w|--window-size] <window size>    seqence number window size\n");
467 #ifndef NO_CRYPT
468   printf("        [-k|--kd-prf] <kd-prf type>         key derivation pseudo random function\n");
469 #ifndef NO_PASSPHRASE
470   printf("        [-E|--passphrase] <pass phrase>     a passprhase to generate master key and salt from\n");
471 #endif
472   printf("        [-K|--key] <master key>             master key to use for encryption\n");
473   printf("        [-A|--salt] <master salt>           master salt to use for encryption\n");
474   printf("        [-e|--role] <role>                  left (alice) or right (bob)\n");
475   printf("        [-c|--cipher] <cipher type>         payload encryption algorithm\n");
476   printf("        [-a|--auth-algo] <algo type>        message authentication algorithm\n");
477   printf("        [-b|--auth-tag-length] <length>     length of the auth tag\n");
478 #endif
479 }
480
481 void options_print_version()
482 {
483   printf("%s\n", VERSION_STRING);
484 #if defined(__clang__)
485   printf("built using CLANG %s with %s crypto library.\n", __clang_version__, CRYPTO_LIB_NAME);
486 #elif defined(__GNUC__)
487   printf("built using GCC %d.%d.%d with %s crypto library\n", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__, CRYPTO_LIB_NAME);
488 #else
489   printf("built using an unknown compiler with %s crypto library\n", CRYPTO_LIB_NAME, CRYPTO_LIB_NAME);
490 #endif
491 }
492
493 void options_print(options_t* opt)
494 {
495   if(!opt)
496     return;
497
498   printf("progname: '%s'\n", opt->progname_);
499   printf("daemonize: %d\n", opt->daemonize_);
500   printf("username: '%s'\n", opt->username_);
501   printf("groupname: '%s'\n", opt->groupname_);
502   printf("chroot_dir: '%s'\n", opt->chroot_dir_);
503   printf("pid_file: '%s'\n", opt->pid_file_);
504   printf("log_targets: \n");
505   string_list_print(&opt->log_targets_, "  '", "'\n");
506   printf("debug: %s\n", !opt->debug_ ? "false" : "true");
507   printf("local_addr: '%s'\n", opt->local_addr_);
508   printf("local_port: '%s'\n", opt->local_port_);
509   printf("sender_id: %d\n", opt->sender_id_);
510   printf("remote_addr: '%s'\n", opt->remote_addr_);
511   printf("remote_port: '%s'\n", opt->remote_port_);
512   printf("resolv_addr_type: ");
513   switch(opt->resolv_addr_type_) {
514   case ANY: printf("any\n"); break;
515   case IPV4_ONLY: printf("ipv4-only\n"); break;
516   case IPV6_ONLY: printf("ipv6-only\n"); break;
517   default: printf("??\n"); break;
518   }
519   printf("dev_name: '%s'\n", opt->dev_name_);
520   printf("dev_type: '%s'\n", opt->dev_type_);
521   printf("ifconfig_net_addr: '%s'\n", opt->ifconfig_param_.net_addr_);
522   printf("ifconfig_prefix_length: %d\n", opt->ifconfig_param_.prefix_length_);
523   printf("post_up_script: '%s'\n", opt->post_up_script_);
524   printf("mux: %d\n", opt->mux_);
525   printf("seq_window_size: %d\n", opt->seq_window_size_);
526   printf("cipher: '%s'\n", opt->cipher_);
527 #ifndef NO_CRYPT
528   printf("auth_algo: '%s'\n", opt->auth_algo_);
529   printf("auth_tag_length: %d\n", opt->auth_tag_length_);
530   printf("kd_prf: '%s'\n", opt->kd_prf_);
531   printf("passphrase: '%s'\n", opt->passphrase_);
532   printf("role: ");
533   switch(opt->role_) {
534   case ROLE_LEFT: printf("left\n"); break;
535   case ROLE_RIGHT: printf("right\n"); break;
536   default: printf("??\n"); break;
537   }
538 #endif
539
540   u_int32_t i;
541   printf("key_[%d]: '", opt->key_.length_);
542   for(i=0; i<opt->key_.length_; ++i) printf("%02X", opt->key_.buf_[i]);
543   printf("'\n");
544
545   printf("salt_[%d]: '", opt->salt_.length_);
546   for(i=0; i<opt->salt_.length_; ++i) printf("%02X", opt->salt_.buf_[i]);
547   printf("'\n");
548 }