X-Git-Url: https://git.syn-net.org/?p=debian%2Fuanytun.git;a=blobdiff_plain;f=src%2Fuanytun.c;h=da90eda8fb12abe1556812c31b980bf3163cc697;hp=c9c6c443349a5de381fad75eff00dbbba8219981;hb=cd587a97e53c5eddf158462a6ff2271351e813e5;hpb=b81b2c1954fe3e3317e6fa260c5ffdc9eeee966c diff --git a/src/uanytun.c b/src/uanytun.c index c9c6c44..da90eda 100644 --- a/src/uanytun.c +++ b/src/uanytun.c @@ -10,18 +10,19 @@ * tunnel endpoints. It has less protocol overhead than IPSec in Tunnel * mode and allows tunneling of every ETHER TYPE protocol (e.g. * ethernet, ip, arp ...). satp directly includes cryptography and - * message authentication based on the methodes used by SRTP. It is + * message authentication based on the methods used by SRTP. It is * intended to deliver a generic, scaleable and secure solution for * tunneling and relaying of packets of any protocol. - * * - * Copyright (C) 2007-2008 Christian Pointner + * + * Copyright (C) 2007-2014 Christian Pointner * * This file is part of uAnytun. * * uAnytun is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3 as - * published by the Free Software Foundation. + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. * * uAnytun is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -30,6 +31,19 @@ * * You should have received a copy of the GNU General Public License * along with uAnytun. If not, see . + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you + * do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source + * files in the program, then also delete it here. */ #include "datatypes.h" @@ -38,6 +52,10 @@ #include #include #include +#include +#include +#include +#include #include "log.h" #include "sig_handler.h" @@ -55,49 +73,14 @@ #ifndef NO_CRYPT #include "key_derivation.h" #include "auth_algo.h" - -#ifndef USE_SSL_CRYPTO -#include -#endif +#else +typedef u_int8_t auth_algo_t; #endif - +#include "init_crypt.h" #include "daemon.h" #include "sysexec.h" -#ifndef NO_CRYPT -#ifndef USE_SSL_CRYPTO - -#define MIN_GCRYPT_VERSION "1.2.0" - -int init_libgcrypt() -{ - if(!gcry_check_version(MIN_GCRYPT_VERSION)) { - log_printf(NOTICE, "invalid Version of libgcrypt, should be >= %s", MIN_GCRYPT_VERSION); - return -1; - } - - gcry_error_t err = gcry_control(GCRYCTL_DISABLE_SECMEM, 0); - if(err) { - log_printf(ERROR, "failed to disable secure memory: %s", gcry_strerror(err)); - return -1; - } - - err = gcry_control(GCRYCTL_INITIALIZATION_FINISHED); - if(err) { - log_printf(ERROR, "failed to finish libgcrypt initialization: %s", gcry_strerror(err)); - return -1; - } - - log_printf(NOTICE, "libgcrypt init finished"); - return 0; -} -#endif -#endif - -#ifdef NO_CRYPT -typedef u_int8_t auth_algo_t; -#endif int init_main_loop(options_t* opt, cipher_t* c, auth_algo_t* aa, key_derivation_t* kd, seq_win_t* seq_win) { @@ -106,7 +89,7 @@ int init_main_loop(options_t* opt, cipher_t* c, auth_algo_t* aa, key_derivation_ log_printf(ERROR, "could not initialize cipher of type %s", opt->cipher_); return ret; } - + #ifndef NO_CRYPT ret = auth_algo_init(aa, opt->auth_algo_); if(ret) { @@ -137,8 +120,8 @@ int init_main_loop(options_t* opt, cipher_t* c, auth_algo_t* aa, key_derivation_ return 0; } -int process_tun_data(tun_device_t* dev, udp_socket_t* sock, options_t* opt, plain_packet_t* plain_packet, encrypted_packet_t* encrypted_packet, - cipher_t* c, auth_algo_t* aa, key_derivation_t* kd, seq_nr_t seq_nr) +int process_tun_data(tun_device_t* dev, udp_t* sock, options_t* opt, plain_packet_t* plain_packet, encrypted_packet_t* encrypted_packet, + cipher_t* c, auth_algo_t* aa, key_derivation_t* kd, seq_nr_t* seq_nr) { plain_packet_set_payload_length(plain_packet, -1); encrypted_packet_set_length(encrypted_packet, -1); @@ -148,25 +131,25 @@ int process_tun_data(tun_device_t* dev, udp_socket_t* sock, options_t* opt, plai log_printf(ERROR, "error on reading from device: %s", strerror(errno)); return 0; } - + plain_packet_set_payload_length(plain_packet, len); - + if(dev->type_ == TYPE_TUN) plain_packet_set_type(plain_packet, PAYLOAD_TYPE_TUN); else if(dev->type_ == TYPE_TAP) - plain_packet_set_type(plain_packet, PAYLOAD_TYPE_TAP); + plain_packet_set_type(plain_packet, PAYLOAD_TYPE_TAP); else plain_packet_set_type(plain_packet, PAYLOAD_TYPE_UNKNOWN); - if(!sock->remote_end_set_) + if(!udp_has_remote(sock)) return 0; - - cipher_encrypt(c, kd, kd_outbound, plain_packet, encrypted_packet, seq_nr, opt->sender_id_, opt->mux_); - + + cipher_encrypt(c, kd, kd_outbound, plain_packet, encrypted_packet, *seq_nr, opt->sender_id_, opt->mux_); + (*seq_nr)++; #ifndef NO_CRYPT auth_algo_generate(aa, kd, kd_outbound, encrypted_packet); #endif - + len = udp_write(sock, encrypted_packet_get_packet(encrypted_packet), encrypted_packet_get_length(encrypted_packet)); if(len == -1) log_printf(ERROR, "error on sending udp packet: %s", strerror(errno)); @@ -174,73 +157,66 @@ int process_tun_data(tun_device_t* dev, udp_socket_t* sock, options_t* opt, plai return 0; } -int process_sock_data(tun_device_t* dev, udp_socket_t* sock, options_t* opt, plain_packet_t* plain_packet, encrypted_packet_t* encrypted_packet, +int process_sock_data(tun_device_t* dev, int fd, udp_t* sock, options_t* opt, plain_packet_t* plain_packet, encrypted_packet_t* encrypted_packet, cipher_t* c, auth_algo_t* aa, key_derivation_t* kd, seq_win_t* seq_win) { plain_packet_set_payload_length(plain_packet, -1); encrypted_packet_set_length(encrypted_packet, -1); udp_endpoint_t remote; - memset(&remote, 0, sizeof(udp_endpoint_t)); - int len = udp_read(sock, encrypted_packet_get_packet(encrypted_packet), encrypted_packet_get_length(encrypted_packet), &remote); + memset(&(remote.addr_), 0, sizeof(remote.addr_)); + remote.len_ = sizeof(remote.addr_); + int len = udp_read(sock, fd, encrypted_packet_get_packet(encrypted_packet), encrypted_packet_get_length(encrypted_packet), &remote); if(len == -1) { log_printf(ERROR, "error on receiving udp packet: %s", strerror(errno)); return 0; - } - else if(len < encrypted_packet_get_minimum_length(encrypted_packet)) { - log_printf(WARNING, "received packet is to short"); + } else if(len < encrypted_packet_get_minimum_length(encrypted_packet)) { + log_printf(WARNING, "received packet is too short"); return 0; } encrypted_packet_set_length(encrypted_packet, len); + if(encrypted_packet_get_mux(encrypted_packet) != opt->mux_) { + log_printf(WARNING, "wrong mux value, discarding packet"); + return 0; + } + #ifndef NO_CRYPT if(!auth_algo_check_tag(aa, kd, kd_inbound, encrypted_packet)) { log_printf(WARNING, "wrong authentication tag, discarding packet"); return 0; } #endif - - if(encrypted_packet_get_mux(encrypted_packet) != opt->mux_) { - log_printf(WARNING, "wrong mux value, discarding packet"); - return 0; - } - + int result = seq_win_check_and_add(seq_win, encrypted_packet_get_sender_id(encrypted_packet), encrypted_packet_get_seq_nr(encrypted_packet)); if(result > 0) { log_printf(WARNING, "detected replay attack, discarding packet"); return 0; - } - else if(result < 0) { + } else if(result < 0) { log_printf(ERROR, "memory error at sequence window"); return -2; } - - if(memcmp(&remote, &(sock->remote_end_), sizeof(remote))) { - memcpy(&(sock->remote_end_), &remote, sizeof(remote)); - sock->remote_end_set_ = 1; - char* addrstring = udp_endpoint_to_string(remote); - log_printf(NOTICE, "autodetected remote host changed %s", addrstring); - free(addrstring); - } + + udp_update_remote(sock, fd, &remote); if(encrypted_packet_get_payload_length(encrypted_packet) <= plain_packet_get_header_length()) { log_printf(WARNING, "ignoring packet with zero length payload"); return 0; } - int ret = cipher_decrypt(c, kd, kd_inbound, encrypted_packet, plain_packet); - if(ret) + int ret = cipher_decrypt(c, kd, kd_inbound, encrypted_packet, plain_packet); + if(ret) return ret; - + len = tun_write(dev, plain_packet_get_payload(plain_packet), plain_packet_get_payload_length(plain_packet)); if(len == -1) log_printf(ERROR, "error on writing to device: %s", strerror(errno)); - + return 0; } -int main_loop(tun_device_t* dev, udp_socket_t* sock, options_t* opt) +int main_loop(tun_device_t* dev, udp_t* sock, options_t* opt) { log_printf(INFO, "entering main loop"); @@ -249,7 +225,7 @@ int main_loop(tun_device_t* dev, udp_socket_t* sock, options_t* opt) encrypted_packet_t encrypted_packet; encrypted_packet_init(&encrypted_packet, opt->auth_tag_length_); seq_nr_t seq_nr = 0; - fd_set readfds; + fd_set readfds, readyfds; cipher_t c; auth_algo_t aa; @@ -260,39 +236,57 @@ int main_loop(tun_device_t* dev, udp_socket_t* sock, options_t* opt) if(ret) return ret; - signal_init(); + FD_ZERO(&readfds); + FD_SET(dev->fd_, &readfds); + int nfds = udp_fill_fd_set(sock, &readfds); + nfds = dev->fd_ > nfds ? dev->fd_ : nfds; + int return_value = 0; - while(!return_value) { - FD_ZERO(&readfds); - FD_SET(dev->fd_, &readfds); - FD_SET(sock->fd_, &readfds); - int nfds = dev->fd_ > sock->fd_ ? dev->fd_+1 : sock->fd_+1; + int sig_fd = signal_init(); + if(sig_fd < 0) + return_value = -1; - int ret = select(nfds, &readfds, NULL, NULL, NULL); + FD_SET(sig_fd, &readfds); + nfds = (nfds < sig_fd) ? sig_fd : nfds; + + while(!return_value) { + memcpy(&readyfds, &readfds, sizeof(readyfds)); + int ret = select(nfds + 1, &readyfds, NULL, NULL, NULL); if(ret == -1 && errno != EINTR) { log_printf(ERROR, "select returned with error: %s", strerror(errno)); return_value = -1; break; } - if(!ret) + if(!ret || ret == -1) continue; - if(signal_exit) { - return_value = 1; - break; + if(FD_ISSET(sig_fd, &readyfds)) { + return_value = signal_handle(); + if(return_value == SIGINT || return_value == SIGQUIT || return_value == SIGTERM) break; + else if(return_value == SIGHUP) { + seq_win_clear(&seq_win); + seq_nr = 0; + log_printf(NOTICE, "sequence window cleared"); + return_value = 0; + } + else + return_value = 0; } - if(FD_ISSET(dev->fd_, &readfds)) { - return_value = process_tun_data(dev, sock, opt, &plain_packet, &encrypted_packet, &c, &aa, &kd, seq_nr); - seq_nr++; + if(FD_ISSET(dev->fd_, &readyfds)) { + return_value = process_tun_data(dev, sock, opt, &plain_packet, &encrypted_packet, &c, &aa, &kd, &seq_nr); if(return_value) break; } - if(FD_ISSET(sock->fd_, &readfds)) { - return_value = process_sock_data(dev, sock, opt, &plain_packet, &encrypted_packet, &c, &aa, &kd, &seq_win); - if(return_value) - break; + udp_socket_t* s = sock->socks_; + while(s) { + if(FD_ISSET(s->fd_, &readyfds)) { + return_value = process_sock_data(dev, s->fd_, sock, opt, &plain_packet, &encrypted_packet, &c, &aa, &kd, &seq_win); + if(return_value) + break; + } + s = s->next_; } } @@ -302,6 +296,7 @@ int main_loop(tun_device_t* dev, udp_socket_t* sock, options_t* opt) key_derivation_close(&kd); #endif seq_win_clear(&seq_win); + signal_stop(); return return_value; } @@ -325,35 +320,36 @@ int main(int argc, char* argv[]) if(ret == -4) { fprintf(stderr, "syntax error: unknown role name\n\n"); } + if(ret == -5) { + options_print_version(); + } - if(ret != -2) + if(ret != -2 && ret != -5) options_print_usage(); + if(ret == -1 || ret == -5) + ret = 0; + options_clear(&opt); log_close(); exit(ret); } string_list_element_t* tmp = opt.log_targets_.first_; - if(!tmp) { - log_add_target("syslog:3,uanytun,daemon"); - } - else { - while(tmp) { - ret = log_add_target(tmp->string_); - if(ret) { - switch(ret) { - case -2: fprintf(stderr, "memory error on log_add_target, exitting\n"); break; - case -3: fprintf(stderr, "unknown log target: '%s', exitting\n", tmp->string_); break; - case -4: fprintf(stderr, "this log target is only allowed once: '%s', exitting\n", tmp->string_); break; - default: fprintf(stderr, "syntax error near: '%s', exitting\n", tmp->string_); break; - } - - options_clear(&opt); - log_close(); - exit(ret); + while(tmp) { + ret = log_add_target(tmp->string_); + if(ret) { + switch(ret) { + case -2: fprintf(stderr, "memory error on log_add_target, exitting\n"); break; + case -3: fprintf(stderr, "unknown log target: '%s', exitting\n", tmp->string_); break; + case -4: fprintf(stderr, "this log target is only allowed once: '%s', exitting\n", tmp->string_); break; + default: fprintf(stderr, "syntax error near: '%s', exitting\n", tmp->string_); break; } - tmp = tmp->next_; + + options_clear(&opt); + log_close(); + exit(ret); } + tmp = tmp->next_; } log_printf(NOTICE, "just started..."); @@ -367,17 +363,13 @@ int main(int argc, char* argv[]) exit(-1); } -#ifndef NO_CRYPT -#ifndef USE_SSL_CRYPTO - ret = init_libgcrypt(); + ret = init_crypt(); if(ret) { - log_printf(ERROR, "error on libgcrpyt initialization, exitting"); + log_printf(ERROR, "error on crpyto initialization, exitting"); options_clear(&opt); log_close(); exit(ret); } -#endif -#endif tun_device_t dev; ret = tun_init(&dev, opt.dev_name_, opt.dev_type_, opt.ifconfig_param_.net_addr_, opt.ifconfig_param_.prefix_length_); @@ -391,11 +383,13 @@ int main(int argc, char* argv[]) if(opt.post_up_script_) { log_printf(NOTICE, "executing post-up script '%s'", opt.post_up_script_); - int ret = exec_script(opt.post_up_script_, dev.actual_name_); + char* const argv[] = { opt.post_up_script_, dev.actual_name_, NULL }; + char* const evp[] = { NULL }; + uanytun_exec(opt.post_up_script_, argv, evp); } - udp_socket_t sock; + udp_t sock; ret = udp_init(&sock, opt.local_addr_, opt.local_port_, opt.resolv_addr_type_); if(ret) { log_printf(ERROR, "error on udp_init, exitting"); @@ -404,22 +398,9 @@ int main(int argc, char* argv[]) log_close(); exit(ret); } - char* local_string = udp_get_local_end_string(&sock); - if(local_string) { - log_printf(NOTICE, "listening on: %s", local_string); - free(local_string); - } - - if(opt.remote_addr_) { - if(!udp_set_remote(&sock, opt.remote_addr_, opt.remote_port_, opt.resolv_addr_type_)) { - char* remote_string = udp_get_remote_end_string(&sock); - if(remote_string) { - log_printf(NOTICE, "set remote end to: %s", remote_string); - free(remote_string); - } - } - } + if(opt.remote_addr_) + udp_resolv_remote(&sock, opt.remote_addr_, opt.remote_port_, opt.resolv_addr_type_); FILE* pid_file = NULL; @@ -445,7 +426,7 @@ int main(int argc, char* argv[]) options_clear(&opt); log_close(); exit(-1); - } + } if(opt.daemonize_) { pid_t oldpid = getpid(); @@ -469,8 +450,11 @@ int main(int argc, char* argv[]) log_printf(NOTICE, "normal shutdown"); else if(ret < 0) log_printf(NOTICE, "shutdown after error"); - else + else { log_printf(NOTICE, "shutdown after signal"); + log_close(); + kill(getpid(), ret); + } log_close();