* 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 <equinox@anytun.org>
+ *
+ * Copyright (C) 2007-2014 Christian Pointner <equinox@anytun.org>
*
* This file is part of uAnytun.
*
*
* You should have received a copy of the GNU General Public License
* along with uAnytun. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * 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"
#ifndef NO_CRYPT
#include "key_derivation.h"
#include "auth_algo.h"
-
-#ifndef USE_SSL_CRYPTO
-#include <gcrypt.h>
-#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)
{
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) {
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);
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));
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");
FD_ZERO(&readfds);
FD_SET(dev->fd_, &readfds);
- FD_SET(sock->fd_, &readfds);
- int nfds = dev->fd_ > sock->fd_ ? dev->fd_ : sock->fd_;
+ int nfds = udp_fill_fd_set(sock, &readfds);
+ nfds = dev->fd_ > nfds ? dev->fd_ : nfds;
int return_value = 0;
int sig_fd = signal_init();
if(sig_fd < 0)
- return_value -1;
+ return_value = -1;
FD_SET(sig_fd, &readfds);
nfds = (nfds < sig_fd) ? sig_fd : nfds;
continue;
if(FD_ISSET(sig_fd, &readyfds)) {
- if(signal_handle()) {
- return_value = 1;
+ return_value = signal_handle();
+ if(return_value == 1)
break;
+ else if(return_value == 2) {
+ 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_, &readyfds)) {
- return_value = process_tun_data(dev, sock, opt, &plain_packet, &encrypted_packet, &c, &aa, &kd, seq_nr);
- seq_nr++;
+ 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_, &readyfds)) {
- 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_;
}
}
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...");
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_);
log_printf(NOTICE, "executing post-up script '%s'", opt.post_up_script_);
char* const argv[] = { opt.post_up_script_, dev.actual_name_, NULL };
char* const evp[] = { NULL };
- int ret = uanytun_exec(opt.post_up_script_, argv, evp);
+ 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");
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;
options_clear(&opt);
log_close();
exit(-1);
- }
+ }
if(opt.daemonize_) {
pid_t oldpid = getpid();