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.
18 * Copyright (C) 2007-2014 Christian Pointner <equinox@anytun.org>
20 * This file is part of uAnytun.
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
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.
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/>.
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
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.
49 #include "datatypes.h"
55 #include <sys/select.h>
56 #include <sys/types.h>
61 #include "sig_handler.h"
67 #include "plain_packet.h"
68 #include "encrypted_packet.h"
70 #include "seq_window.h"
74 #include "key_derivation.h"
75 #include "auth_algo.h"
77 typedef u_int8_t auth_algo_t;
79 #include "init_crypt.h"
85 int init_main_loop(options_t* opt, cipher_t* c, auth_algo_t* aa, key_derivation_t* kd, seq_win_t* seq_win)
87 int ret = cipher_init(c, opt->cipher_);
89 log_printf(ERROR, "could not initialize cipher of type %s", opt->cipher_);
94 ret = auth_algo_init(aa, opt->auth_algo_);
96 log_printf(ERROR, "could not initialize auth algo of type %s", opt->auth_algo_);
101 ret = key_derivation_init(kd, opt->kd_prf_, opt->role_, opt->passphrase_, opt->key_.buf_, opt->key_.length_, opt->salt_.buf_, opt->salt_.length_);
103 log_printf(ERROR, "could not initialize key derivation of type %s", opt->kd_prf_);
110 ret = seq_win_init(seq_win, opt->seq_window_size_);
112 printf("could not initialize sequence window");
116 key_derivation_close(kd);
123 int process_tun_data(tun_device_t* dev, udp_t* sock, options_t* opt, plain_packet_t* plain_packet, encrypted_packet_t* encrypted_packet,
124 cipher_t* c, auth_algo_t* aa, key_derivation_t* kd, seq_nr_t* seq_nr)
126 plain_packet_set_payload_length(plain_packet, -1);
127 encrypted_packet_set_length(encrypted_packet, -1);
129 int len = tun_read(dev, plain_packet_get_payload(plain_packet), plain_packet_get_payload_length(plain_packet));
131 log_printf(ERROR, "error on reading from device: %s", strerror(errno));
135 plain_packet_set_payload_length(plain_packet, len);
137 if(dev->type_ == TYPE_TUN)
138 plain_packet_set_type(plain_packet, PAYLOAD_TYPE_TUN);
139 else if(dev->type_ == TYPE_TAP)
140 plain_packet_set_type(plain_packet, PAYLOAD_TYPE_TAP);
142 plain_packet_set_type(plain_packet, PAYLOAD_TYPE_UNKNOWN);
144 if(!udp_has_remote(sock))
147 cipher_encrypt(c, kd, kd_outbound, plain_packet, encrypted_packet, *seq_nr, opt->sender_id_, opt->mux_);
150 auth_algo_generate(aa, kd, kd_outbound, encrypted_packet);
153 len = udp_write(sock, encrypted_packet_get_packet(encrypted_packet), encrypted_packet_get_length(encrypted_packet));
155 log_printf(ERROR, "error on sending udp packet: %s", strerror(errno));
160 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,
161 cipher_t* c, auth_algo_t* aa, key_derivation_t* kd, seq_win_t* seq_win)
163 plain_packet_set_payload_length(plain_packet, -1);
164 encrypted_packet_set_length(encrypted_packet, -1);
166 udp_endpoint_t remote;
167 memset(&(remote.addr_), 0, sizeof(remote.addr_));
168 remote.len_ = sizeof(remote.addr_);
169 int len = udp_read(sock, fd, encrypted_packet_get_packet(encrypted_packet), encrypted_packet_get_length(encrypted_packet), &remote);
171 log_printf(ERROR, "error on receiving udp packet: %s", strerror(errno));
173 } else if(len < encrypted_packet_get_minimum_length(encrypted_packet)) {
174 log_printf(WARNING, "received packet is too short");
177 encrypted_packet_set_length(encrypted_packet, len);
179 if(encrypted_packet_get_mux(encrypted_packet) != opt->mux_) {
180 log_printf(WARNING, "wrong mux value, discarding packet");
185 if(!auth_algo_check_tag(aa, kd, kd_inbound, encrypted_packet)) {
186 log_printf(WARNING, "wrong authentication tag, discarding packet");
191 int result = seq_win_check_and_add(seq_win, encrypted_packet_get_sender_id(encrypted_packet), encrypted_packet_get_seq_nr(encrypted_packet));
193 log_printf(WARNING, "detected replay attack, discarding packet");
195 } else if(result < 0) {
196 log_printf(ERROR, "memory error at sequence window");
200 udp_update_remote(sock, fd, &remote);
202 if(encrypted_packet_get_payload_length(encrypted_packet) <= plain_packet_get_header_length()) {
203 log_printf(WARNING, "ignoring packet with zero length payload");
207 int ret = cipher_decrypt(c, kd, kd_inbound, encrypted_packet, plain_packet);
211 len = tun_write(dev, plain_packet_get_payload(plain_packet), plain_packet_get_payload_length(plain_packet));
213 log_printf(ERROR, "error on writing to device: %s", strerror(errno));
219 int main_loop(tun_device_t* dev, udp_t* sock, options_t* opt)
221 log_printf(INFO, "entering main loop");
223 plain_packet_t plain_packet;
224 plain_packet_init(&plain_packet);
225 encrypted_packet_t encrypted_packet;
226 encrypted_packet_init(&encrypted_packet, opt->auth_tag_length_);
228 fd_set readfds, readyfds;
235 int ret = init_main_loop(opt, &c, &aa, &kd, &seq_win);
240 FD_SET(dev->fd_, &readfds);
241 int nfds = udp_fill_fd_set(sock, &readfds);
242 nfds = dev->fd_ > nfds ? dev->fd_ : nfds;
244 int return_value = 0;
245 int sig_fd = signal_init();
249 FD_SET(sig_fd, &readfds);
250 nfds = (nfds < sig_fd) ? sig_fd : nfds;
252 while(!return_value) {
253 memcpy(&readyfds, &readfds, sizeof(readyfds));
254 int ret = select(nfds + 1, &readyfds, NULL, NULL, NULL);
255 if(ret == -1 && errno != EINTR) {
256 log_printf(ERROR, "select returned with error: %s", strerror(errno));
260 if(!ret || ret == -1)
263 if(FD_ISSET(sig_fd, &readyfds)) {
264 return_value = signal_handle();
265 if(return_value == SIGINT || return_value == SIGQUIT || return_value == SIGTERM) break;
266 else if(return_value == SIGHUP) {
267 seq_win_clear(&seq_win);
269 log_printf(NOTICE, "sequence window cleared");
276 if(FD_ISSET(dev->fd_, &readyfds)) {
277 return_value = process_tun_data(dev, sock, opt, &plain_packet, &encrypted_packet, &c, &aa, &kd, &seq_nr);
282 udp_socket_t* s = sock->socks_;
284 if(FD_ISSET(s->fd_, &readyfds)) {
285 return_value = process_sock_data(dev, s->fd_, sock, opt, &plain_packet, &encrypted_packet, &c, &aa, &kd, &seq_win);
295 auth_algo_close(&aa);
296 key_derivation_close(&kd);
298 seq_win_clear(&seq_win);
304 int main(int argc, char* argv[])
309 int ret = options_parse(&opt, argc, argv);
312 fprintf(stderr, "syntax error near: %s\n\n", argv[ret]);
315 fprintf(stderr, "memory error on options_parse, exitting\n");
318 fprintf(stderr, "syntax error: -4 and -6 are mutual exclusive\n\n");
321 fprintf(stderr, "syntax error: unknown role name\n\n");
324 options_print_version();
327 if(ret != -2 && ret != -5)
328 options_print_usage();
330 if(ret == -1 || ret == -5)
337 string_list_element_t* tmp = opt.log_targets_.first_;
339 ret = log_add_target(tmp->string_);
342 case -2: fprintf(stderr, "memory error on log_add_target, exitting\n"); break;
343 case -3: fprintf(stderr, "unknown log target: '%s', exitting\n", tmp->string_); break;
344 case -4: fprintf(stderr, "this log target is only allowed once: '%s', exitting\n", tmp->string_); break;
345 default: fprintf(stderr, "syntax error near: '%s', exitting\n", tmp->string_); break;
355 log_printf(NOTICE, "just started...");
356 options_parse_post(&opt);
360 if(priv_init(&priv, opt.username_, opt.groupname_)) {
368 log_printf(ERROR, "error on crpyto initialization, exitting");
375 ret = tun_init(&dev, opt.dev_name_, opt.dev_type_, opt.ifconfig_param_.net_addr_, opt.ifconfig_param_.prefix_length_);
377 log_printf(ERROR, "error on tun_init, exitting");
382 log_printf(NOTICE, "dev of type '%s' opened, actual name is '%s'", tun_get_type_string(&dev), dev.actual_name_);
384 if(opt.post_up_script_) {
385 log_printf(NOTICE, "executing post-up script '%s'", opt.post_up_script_);
386 char* const argv[] = { opt.post_up_script_, dev.actual_name_, NULL };
387 char* const evp[] = { NULL };
388 uanytun_exec(opt.post_up_script_, argv, evp);
393 ret = udp_init(&sock, opt.local_addr_, opt.local_port_, opt.resolv_addr_type_);
395 log_printf(ERROR, "error on udp_init, exitting");
403 udp_resolv_remote(&sock, opt.remote_addr_, opt.remote_port_, opt.resolv_addr_type_);
406 FILE* pid_file = NULL;
408 pid_file = fopen(opt.pid_file_, "w");
410 log_printf(WARNING, "unable to open pid file: %s", strerror(errno));
415 if(do_chroot(opt.chroot_dir_)) {
423 if(priv_drop(&priv)) {
432 pid_t oldpid = getpid();
434 log_printf(INFO, "running in background now (old pid: %d)", oldpid);
438 pid_t pid = getpid();
439 fprintf(pid_file, "%d", pid);
443 ret = main_loop(&dev, &sock, &opt);
450 log_printf(NOTICE, "normal shutdown");
452 log_printf(NOTICE, "shutdown after error");
454 log_printf(NOTICE, "shutdown after signal");