Imported Upstream version 0.3.2
[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 methodes 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-2008 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
36 #include "datatypes.h"
37
38 #include "options.h"
39
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <ctype.h>
44
45 #include "log.h"
46
47 #ifndef NO_CRYPT
48 #include "auth_algo.h"
49 #endif
50
51 #define PARSE_BOOL_PARAM(SHORT, LONG, VALUE)             \
52     else if(!strcmp(str,SHORT) || !strcmp(str,LONG))     \
53       VALUE = 1;
54
55 #define PARSE_INVERSE_BOOL_PARAM(SHORT, LONG, VALUE)     \
56     else if(!strcmp(str,SHORT) || !strcmp(str,LONG))     \
57       VALUE = 0;
58
59 #define PARSE_INT_PARAM(SHORT, LONG, VALUE)              \
60     else if(!strcmp(str,SHORT) || !strcmp(str,LONG))     \
61     {                                                    \
62       if(argc < 1)                                       \
63         return i;                                        \
64       VALUE = atoi(argv[i+1]);                           \
65       argc--;                                            \
66       i++;                                               \
67     }
68
69 #define PARSE_STRING_PARAM(SHORT, LONG, VALUE)           \
70     else if(!strcmp(str,SHORT) || !strcmp(str,LONG))     \
71     {                                                    \
72       if(argc < 1 || argv[i+1][0] == '-')                \
73         return i;                                        \
74       if(VALUE) free(VALUE);                             \
75       VALUE = strdup(argv[i+1]);                         \
76       if(!VALUE)                                         \
77         return -2;                                       \
78       argc--;                                            \
79       i++;                                               \
80     }
81
82 #define PARSE_STRING_PARAM_SEC(SHORT, LONG, VALUE)       \
83     else if(!strcmp(str,SHORT) || !strcmp(str,LONG))     \
84     {                                                    \
85       if(argc < 1 || argv[i+1][0] == '-')                \
86         return i;                                        \
87       if(VALUE) free(VALUE);                             \
88       VALUE = strdup(argv[i+1]);                         \
89       if(!VALUE)                                         \
90         return -2;                                       \
91       size_t j;                                          \
92       for(j=0; j < strlen(argv[i+1]); ++j)               \
93         argv[i+1][j] = '#';                              \
94       argc--;                                            \
95       i++;                                               \
96     }
97
98 #define PARSE_IFCONFIG_PARAM(SHORT, LONG, VALUE)         \
99     else if(!strcmp(str,SHORT) || !strcmp(str,LONG))     \
100     {                                                    \
101       if(argc < 1 || argv[i+1][0] == '-')                \
102         return i;                                        \
103       int ret;                                           \
104       ret = options_parse_ifconfig(argv[i+1], &VALUE);   \
105       if(ret > 0)                                        \
106         return i+1;                                      \
107       if(ret < 0)                                        \
108         return ret;                                      \
109       argc--;                                            \
110       i++;                                               \
111     }
112
113 #define PARSE_HEXSTRING_PARAM_SEC(SHORT, LONG, VALUE)    \
114     else if(!strcmp(str,SHORT) || !strcmp(str,LONG))     \
115     {                                                    \
116       if(argc < 1 || argv[i+1][0] == '-')                \
117         return i;                                        \
118       int ret;                                           \
119       ret = options_parse_hex_string(argv[i+1], &VALUE); \
120       if(ret > 0)                                        \
121         return i+1;                                      \
122       else if(ret < 0)                                   \
123         return ret;                                      \
124       size_t j;                                          \
125       for(j=0; j < strlen(argv[i+1]); ++j)               \
126         argv[i+1][j] = '#';                              \
127       argc--;                                            \
128       i++;                                               \
129     }
130
131 #define PARSE_STRING_LIST(SHORT, LONG, LIST)             \
132     else if(!strcmp(str,SHORT) || !strcmp(str,LONG))     \
133     {                                                    \
134       if(argc < 1 || argv[i+1][0] == '-')                \
135         return i;                                        \
136       int ret = string_list_add(&LIST, argv[i+1]);       \
137       if(ret == -2)                                      \
138         return ret;                                      \
139       else if(ret)                                       \
140         return i+1;                                      \
141       argc--;                                            \
142       i++;                                               \
143     }
144
145 int options_parse_hex_string(const char* hex, buffer_t* buffer)
146 {
147   if(!hex || !buffer)
148     return -1;
149
150   u_int32_t hex_len = strlen(hex);
151   if(hex_len%2)
152     return 1;
153
154   if(buffer->buf_) 
155     free(buffer->buf_);
156   
157   buffer->length_ = hex_len/2;
158   buffer->buf_ = malloc(buffer->length_);
159   if(!buffer->buf_) {
160     buffer->length_ = 0;
161     return -2;
162   }
163
164   const char* ptr = hex;
165   int i;
166   for(i=0;i<buffer->length_;++i) {
167     u_int32_t tmp;
168     sscanf(ptr, "%2X", &tmp);
169     buffer->buf_[i] = (u_int8_t)tmp;
170     ptr += 2;
171   }
172
173   return 0;
174 }
175
176 int options_parse_ifconfig(const char* arg, ifconfig_param_t* ifcfg)
177 {
178   char* str = strdup(arg);
179   if(!str)
180     return -2;
181
182   char* ptr = str;
183   for(;*ptr;++ptr) {
184     if(*ptr == '/') {
185       *ptr = 0;
186       ptr++;
187       if(!(*ptr)) {
188         free(str);
189         return 1;
190       }
191       
192       ifcfg->prefix_length_ = atoi(ptr);
193       ifcfg->net_addr_ = strdup(str);
194       free(str);
195
196       if(!ifcfg->net_addr_)
197         return -2;
198
199       return 0;
200     }
201     if(!isdigit(*ptr) && *ptr != '.') {
202       free(str);
203       return 1;
204     }
205   }
206
207   free(str);
208   return 1;
209 }
210
211
212 int options_parse(options_t* opt, int argc, char* argv[])
213 {
214   if(!opt)
215     return -1;
216
217   options_default(opt);
218
219   if(opt->progname_)
220     free(opt->progname_);
221   opt->progname_ = strdup(argv[0]);
222   if(!opt->progname_)
223     return -2;
224
225   argc--;
226
227   char* role = NULL;
228   int i, ipv4_only = 0, ipv6_only = 0;
229   for(i=1; argc > 0; ++i)
230   {
231     char* str = argv[i];
232     argc--;
233
234     if(!strcmp(str,"-h") || !strcmp(str,"--help"))
235       return -1;
236     PARSE_INVERSE_BOOL_PARAM("-D","--nodaemonize", opt->daemonize_)
237     PARSE_STRING_PARAM("-u","--username", opt->username_)
238     PARSE_STRING_PARAM("-g","--groupname", opt->groupname_)
239     PARSE_STRING_PARAM("-C","--chroot", opt->chroot_dir_)
240     PARSE_STRING_PARAM("-P","--write-pid", opt->pid_file_)
241     PARSE_STRING_PARAM("-i","--interface", opt->local_addr_)
242     PARSE_STRING_PARAM("-p","--port", opt->local_port_)
243     PARSE_INT_PARAM("-s","--sender-id", opt->sender_id_)
244     PARSE_STRING_LIST("-L","--log", opt->log_targets_)
245     PARSE_STRING_PARAM("-r","--remote-host", opt->remote_addr_)
246     PARSE_STRING_PARAM("-o","--remote-port", opt->remote_port_)
247     PARSE_BOOL_PARAM("-4","--ipv4-only", ipv4_only)
248     PARSE_BOOL_PARAM("-6","--ipv6-only", ipv6_only)
249     PARSE_STRING_PARAM("-d","--dev", opt->dev_name_)
250     PARSE_STRING_PARAM("-t","--type", opt->dev_type_)
251     PARSE_IFCONFIG_PARAM("-n","--ifconfig", opt->ifconfig_param_)
252     PARSE_STRING_PARAM("-x","--post-up-script", opt->post_up_script_)
253     PARSE_INT_PARAM("-m","--mux", opt->mux_)
254     PARSE_INT_PARAM("-w","--window-size", opt->seq_window_size_)
255 #ifndef NO_CRYPT
256     PARSE_STRING_PARAM("-k","--kd-prf", opt->kd_prf_)
257 #ifndef NO_PASSPHRASE
258     PARSE_STRING_PARAM_SEC("-E","--passphrase", opt->passphrase_)
259 #endif
260     PARSE_STRING_PARAM("-e","--role", role)
261     PARSE_HEXSTRING_PARAM_SEC("-K","--key", opt->key_)
262     PARSE_HEXSTRING_PARAM_SEC("-A","--salt", opt->salt_)
263     PARSE_STRING_PARAM("-c","--cipher", opt->cipher_)
264     PARSE_STRING_PARAM("-a","--auth-algo", opt->auth_algo_)
265     PARSE_INT_PARAM("-b","--auth-tag-length", opt->auth_tag_length_)
266 #endif
267     else 
268       return i;
269   }
270   if(ipv4_only && ipv6_only)
271     return -3;
272   if(ipv4_only)
273     opt->resolv_addr_type_ = IPV4_ONLY;
274   if(ipv6_only)
275     opt->resolv_addr_type_ = IPV6_ONLY;
276
277 #ifndef NO_CRYPT
278   if(role) {
279     if(!strcmp(role, "alice") || !strcmp(role, "server") || !strcmp(role, "left"))
280       opt->role_ = ROLE_LEFT;
281     else if(!strcmp(role, "bob") || !strcmp(role, "client") || !strcmp(role, "right"))
282       opt->role_ = ROLE_RIGHT;
283     else {
284       free(role);
285       return -4;
286     }
287     free(role);
288   }
289 #endif
290   return 0;
291 }
292
293 void options_parse_post(options_t* opt)
294 {
295   if(!opt)
296     return;
297
298 #ifdef NO_V4MAPPED
299   if(opt->resolv_addr_type_ == ANY) {
300     opt->resolv_addr_type_ = IPV4_ONLY;
301     log_printf(WARNING, "No support for V4-mapped Adresses on this platform, defaulting to only use IPv4 addresses");
302   }
303 #endif
304
305 #ifndef NO_CRYPT
306   if(!strcmp(opt->cipher_, "null") && !strcmp(opt->auth_algo_, "null") && 
307      strcmp(opt->kd_prf_, "null")) {
308     if(opt->kd_prf_)
309       free(opt->kd_prf_);
310     opt->kd_prf_ = strdup("null");
311   }
312   if((strcmp(opt->cipher_, "null") || strcmp(opt->auth_algo_, "null")) && 
313      !strcmp(opt->kd_prf_, "null")) {
314     log_printf(WARNING, "using NULL key derivation with encryption and or authentication enabled!");
315   }
316
317   u_int32_t tag_len_max = auth_algo_get_max_length(opt->auth_algo_);
318   if(!tag_len_max) opt->auth_tag_length_ = 0;
319   else if(tag_len_max < opt->auth_tag_length_) {
320     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);
321     opt->auth_tag_length_ = tag_len_max;
322   }
323 #endif
324
325   if(!(opt->dev_name_) && !(opt->dev_type_))
326     opt->dev_type_ = strdup("tun");
327 }
328
329 void options_default(options_t* opt)
330 {
331   if(!opt)
332     return;
333
334   opt->progname_ = strdup("uanytun");
335   opt->daemonize_ = 1;
336   opt->username_ = NULL;
337   opt->groupname_ = NULL;
338   opt->chroot_dir_ = NULL;
339   opt->pid_file_ = NULL;
340   string_list_init(&opt->log_targets_);
341   opt->local_addr_ = NULL;
342   opt->local_port_ = strdup("4444");
343   opt->sender_id_ = 0;
344   opt->remote_addr_ = NULL;
345   opt->remote_port_ = strdup("4444");
346   opt->resolv_addr_type_ = ANY;
347   opt->dev_name_ = NULL;
348   opt->dev_type_ = NULL;
349   opt->ifconfig_param_.net_addr_ = NULL;
350   opt->ifconfig_param_.prefix_length_ = 0;
351   opt->post_up_script_ = NULL;
352   opt->mux_ = 0;
353   opt->seq_window_size_ = 0;
354 #ifndef NO_CRYPT
355   opt->kd_prf_ = strdup("aes-ctr");
356   opt->passphrase_ = NULL;
357   opt->role_ = ROLE_LEFT;
358   opt->cipher_ = strdup("aes-ctr");
359   opt->auth_algo_ = strdup("sha1");
360   opt->auth_tag_length_ = 10;
361 #else
362   opt->cipher_ = strdup("null");
363   opt->auth_tag_length_ = 0;
364 #endif
365   opt->key_.buf_ = NULL;
366   opt->key_.length_ = 0;
367   opt->salt_.buf_ = NULL;
368   opt->salt_.length_ = 0;
369 }
370
371 void options_clear(options_t* opt)
372 {
373   if(!opt)
374     return;
375
376   if(opt->progname_)
377     free(opt->progname_);
378   if(opt->username_)
379     free(opt->username_);
380   if(opt->groupname_)
381     free(opt->groupname_);
382   if(opt->chroot_dir_)
383     free(opt->chroot_dir_);
384   if(opt->pid_file_)
385     free(opt->pid_file_);
386   string_list_clear(&opt->log_targets_);
387   if(opt->local_addr_)
388     free(opt->local_addr_);
389   if(opt->local_port_)
390     free(opt->local_port_);
391   if(opt->remote_addr_)
392     free(opt->remote_addr_);
393   if(opt->remote_port_)
394     free(opt->remote_port_);
395   if(opt->dev_name_)
396     free(opt->dev_name_);
397   if(opt->dev_type_)
398     free(opt->dev_type_);
399   if(opt->ifconfig_param_.net_addr_)
400     free(opt->ifconfig_param_.net_addr_);
401   if(opt->post_up_script_)
402     free(opt->post_up_script_);
403   if(opt->cipher_)
404     free(opt->cipher_);
405 #ifndef NO_CRYPT
406   if(opt->auth_algo_)
407     free(opt->auth_algo_);
408   if(opt->kd_prf_)
409     free(opt->kd_prf_);
410   if(opt->passphrase_)
411     free(opt->passphrase_);
412 #endif
413   if(opt->key_.buf_)
414     free(opt->key_.buf_);
415   if(opt->salt_.buf_)
416     free(opt->salt_.buf_);
417 }
418
419 void options_print_usage()
420 {
421   printf("USAGE:\n");
422   printf("uanytun [-h|--help]                         prints this...\n");
423   printf("        [-D|--nodaemonize]                  don't run in background\n");
424   printf("        [-u|--username] <username>          change to this user\n");
425   printf("        [-g|--groupname] <groupname>        change to this group\n");
426   printf("        [-C|--chroot] <path>                chroot to this directory\n");
427   printf("        [-P|--write-pid] <path>             write pid to this file\n");
428   printf("        [-i|--interface] <ip-address>       local ip address to bind to\n");
429   printf("        [-p|--port] <port>                  local port to bind to\n");
430   printf("        [-s|--sender-id ] <sender id>       the sender id to use\n");
431   printf("        [-L|--log] <target>:<level>[,<param1>[,<param2>..]]\n");
432   printf("                                            add a log target, can be invoked several times\n");
433
434   printf("        [-r|--remote-host] <hostname|ip>    remote host\n");
435   printf("        [-o|--remote-port] <port>           remote port\n");
436   printf("        [-4|--ipv4-only]                    always resolv IPv4 addresses\n");
437   printf("        [-6|--ipv6-only]                    always resolv IPv6 addresses\n");
438   printf("        [-d|--dev] <name>                   device name\n");
439   printf("        [-t|--type] <tun|tap>               device type\n");
440
441   printf("        [-n|--ifconfig] <local>/<prefix>    the local address for the tun/tap device and the used prefix length\n");
442   printf("        [-x|--post-up-script] <script>      script gets called after interface is created\n");
443   printf("        [-m|--mux] <mux-id>                 the multiplex id to use\n");
444   printf("        [-w|--window-size] <window size>    seqence number window size\n");
445 #ifndef NO_CRYPT
446   printf("        [-k|--kd-prf] <kd-prf type>         key derivation pseudo random function\n");
447 #ifndef NO_PASSPHRASE
448   printf("        [-E|--passphrase] <pass phrase>     a passprhase to generate master key and salt from\n");
449 #endif
450   printf("        [-K|--key] <master key>             master key to use for encryption\n");
451   printf("        [-A|--salt] <master salt>           master salt to use for encryption\n");
452   printf("        [-e|--role] <role>                  left (alice) or right (bob)\n");
453   printf("        [-c|--cipher] <cipher type>         payload encryption algorithm\n");
454   printf("        [-a|--auth-algo] <algo type>        message authentication algorithm\n");
455   printf("        [-b|--auth-tag-length] <length>     length of the auth tag\n");
456 #endif
457 }
458
459 void options_print(options_t* opt)
460 {
461   if(!opt)
462     return;
463
464   printf("progname: '%s'\n", opt->progname_);
465   printf("daemonize: %d\n", opt->daemonize_);
466   printf("username: '%s'\n", opt->username_);
467   printf("groupname: '%s'\n", opt->groupname_);
468   printf("chroot_dir: '%s'\n", opt->chroot_dir_);
469   printf("pid_file: '%s'\n", opt->pid_file_);
470   printf("log_targets: \n");
471   string_list_print(&opt->log_targets_, "  '", "'\n");
472   printf("local_addr: '%s'\n", opt->local_addr_);
473   printf("local_port: '%s'\n", opt->local_port_);
474   printf("sender_id: %d\n", opt->sender_id_);
475   printf("remote_addr: '%s'\n", opt->remote_addr_);
476   printf("remote_port: '%s'\n", opt->remote_port_);
477   printf("resolv_addr_type: ");
478   switch(opt->resolv_addr_type_) {
479   case ANY: printf("any\n"); break;
480   case IPV4_ONLY: printf("ipv4-only\n"); break;
481   case IPV6_ONLY: printf("ipv6-only\n"); break;
482   default: printf("??\n"); break;
483   }
484   printf("dev_name: '%s'\n", opt->dev_name_);
485   printf("dev_type: '%s'\n", opt->dev_type_);
486   printf("ifconfig_net_addr: '%s'\n", opt->ifconfig_param_.net_addr_);
487   printf("ifconfig_prefix_length: %d\n", opt->ifconfig_param_.prefix_length_);
488   printf("post_up_script: '%s'\n", opt->post_up_script_);
489   printf("mux: %d\n", opt->mux_);
490   printf("seq_window_size: %d\n", opt->seq_window_size_);
491   printf("cipher: '%s'\n", opt->cipher_);
492 #ifndef NO_CRYPT
493   printf("auth_algo: '%s'\n", opt->auth_algo_);
494   printf("auth_tag_length: %d\n", opt->auth_tag_length_);
495   printf("kd_prf: '%s'\n", opt->kd_prf_);
496   printf("passphrase: '%s'\n", opt->passphrase_);
497   printf("role: ");
498   switch(opt->role_) {
499   case ROLE_LEFT: printf("left\n"); break;
500   case ROLE_RIGHT: printf("right\n"); break;
501   default: printf("??\n"); break;
502   }
503 #endif
504
505   u_int32_t i;
506   printf("key_[%d]: '", opt->key_.length_);
507   for(i=0; i<opt->key_.length_; ++i) printf("%02X", opt->key_.buf_[i]);
508   printf("'\n");
509
510   printf("salt_[%d]: '", opt->salt_.length_);
511   for(i=0; i<opt->salt_.length_; ++i) printf("%02X", opt->salt_.buf_[i]);
512   printf("'\n");
513 }