?? openvpn.c
字號:
/* * OpenVPN -- An application to securely tunnel IP networks * over a single UDP port, with support for SSL/TLS-based * session authentication and key exchange, * packet encryption, packet authentication, and * packet compression. * * Copyright (C) 2002-2003 James Yonan <jim@yonan.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program (see the file COPYING included with this * distribution); if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#ifdef WIN32#include "config-win32.h"#else#include "config.h"#endif#include "syshead.h"#include "common.h"#include "error.h"#include "options.h"#include "socket.h"#include "buffer.h"#include "crypto.h"#include "ssl.h"#include "misc.h"#include "lzo.h"#include "tun.h"#include "gremlin.h"#include "shaper.h"#include "thread.h"#include "interval.h"#include "fragment.h"#include "openvpn.h"#include "memdbg.h"/* * Should we become a daemon? * level == 0 after parameters have been parsed but before any initialization * level == 1 after initialization but before any SSL/TLS negotiation or * tunnel data is forwarded * first_time is true until first exit of openvpn() function * * Return true if we did it. */static boolpossibly_become_daemon (int level, const struct options* options, const bool first_time){ bool ret = false; if (first_time && options->daemon) { ASSERT (!options->inetd); if (level == DAEMONIZATION_LEVEL) { if (daemon (options->cd_dir != NULL, 0) < 0) msg (M_ERR, "daemon() failed"); ret = true; } } return ret;}/* Handle signals */static volatile int signal_received = 0;#ifdef HAVE_SIGNAL_H/* normal signal handler, when we are in event loop */static voidsignal_handler (int signum){ signal_received = signum; signal (signum, signal_handler);}/* temporary signal handler, before we are fully initialized */static voidsignal_handler_exit (int signum){ msg (M_FATAL | M_NOLOCK, "Signal %d received during initialization, exiting", signum);}#endif /* HAVE_SIGNAL_H *//* * For debugging, dump a packet in * nominally human-readable form. */#if defined(USE_CRYPTO) && defined(USE_SSL)#define TLS_MODE (tls_multi != NULL)#define PROTO_DUMP_FLAGS (check_debug_level (D_UDP_RW_VERBOSE) ? (PD_SHOW_DATA|PD_VERBOSE) : 0)#define PROTO_DUMP(buf) protocol_dump(buf, \ PROTO_DUMP_FLAGS | \ (tls_multi ? PD_TLS : 0) | \ (options->tls_auth_file ? ks->key_type.hmac_length : 0) \ )#else#define TLS_MODE (false)#define PROTO_DUMP(buf) format_hex (BPTR (buf), BLEN (buf), 80)#endif#ifdef USE_CRYPTO#define MD5SUM(buf, len) md5sum(buf, len)#else#define MD5SUM(buf, len) "[unavailable]"#endif#if defined(USE_PTHREAD) && defined(USE_CRYPTO)static void *test_crypto_thread (void *arg);#endif/* * Our global key schedules, packaged thusly * to facilitate --persist-key. */struct key_schedule{#ifdef USE_CRYPTO /* which cipher, HMAC digest, and key sizes are we using? */ struct key_type key_type; /* pre-shared static key, read from a file */ struct key_ctx_bi static_key;#ifdef USE_SSL /* our global SSL context */ SSL_CTX *ssl_ctx; /* optional authentication HMAC key for TLS control channel */ struct key_ctx_bi tls_auth_key;#endif /* USE_SSL */#else /* USE_CRYPTO */ int dummy;#endif /* USE_CRYPTO */};static voidkey_schedule_free(struct key_schedule* ks){#ifdef USE_CRYPTO free_key_ctx_bi (&ks->static_key);#ifdef USE_SSL if (ks->ssl_ctx) SSL_CTX_free (ks->ssl_ctx); free_key_ctx_bi (&ks->tls_auth_key);#endif /* USE_SSL */#endif /* USE_CRYPTO */ CLEAR (*ks);}/* * struct packet_id_persist should be empty if we are not * building with crypto. */#ifndef PACKET_ID_Hstruct packet_id_persist { int dummy; };static inline void packet_id_persist_init (struct packet_id_persist *p) {}#endif/* * Finalize MTU parameters based on command line or config file options. */static voidframe_finalize_options (struct frame *frame, const struct options *options){ frame_finalize (frame, options->udp_mtu_defined, options->udp_mtu, options->tun_mtu_defined, options->tun_mtu,#ifdef FRAGMENT_ENABLE options->mtu_min_defined, options->mtu_min, options->mtu_max_defined, options->mtu_max#else false, 0, false, 0#endif );}/* * Do the work. Initialize and enter main event loop. * Called after command line has been parsed. * * first_time is true during our first call -- we may * be called multiple times due to SIGHUP or SIGUSR1. */static intopenvpn (const struct options *options, struct udp_socket_addr *udp_socket_addr, struct tuntap *tuntap, struct key_schedule *ks, struct packet_id_persist *pid_persist, bool first_time){ /* * Initialize garbage collection level. * When we pop the level at the end * of the routine, everything we * allocated with gc_malloc at our level * or recursively lower levels will * automatically be freed. */ const int gc_level = gc_new_level (); /* used by select() */ int fm;#if PASSTOS_CAPABILITY /* used to get/set TOS. */ struct iphdr *iph; unsigned char ptos; bool ptos_defined = false;#endif /* declare various buffers */ struct buffer to_tun = clear_buf (); struct buffer to_udp = clear_buf (); struct buffer buf = clear_buf (); struct buffer ping_buf = clear_buf (); struct buffer nullbuf = clear_buf (); /* tells us to free to_udp buffer after it has been written to UDP port */ bool free_to_udp; /* used by select() */ fd_set reads, writes; struct udp_socket udp_socket; /* socket used for UDP connection to remote */ struct sockaddr_in to_udp_addr; /* IP address of remote */ int max_rw_size_udp = 0; /* max size of packet we can send to remote */ /* MTU frame parameters */ struct frame frame;#ifdef FRAGMENT_ENABLE /* Object to handle advanced MTU negotiation and datagram fragmentation */ struct fragment_master *fragment = NULL; struct frame frame_fragment; struct frame frame_fragment_omit;#endif /* Always set to current time. */ time_t current;#ifdef HAVE_GETTIMEOFDAY /* * Traffic shaper object. */ struct shaper shaper;#endif /* * Statistics */ counter_type tun_read_bytes = 0; counter_type tun_write_bytes = 0; counter_type udp_read_bytes = 0; counter_type udp_write_bytes = 0; /* * Timer objects for ping and inactivity * timeout features. */ struct event_timeout inactivity_interval; struct event_timeout ping_send_interval; struct event_timeout ping_rec_interval; /* * This random string identifies an OpenVPN ping packet. * It should be of sufficient length and randomness * so as not to collide with other tunnel data. */ static const uint8_t ping_string[] = { 0x2a, 0x18, 0x7b, 0xf3, 0x64, 0x1e, 0xb4, 0xcb, 0x07, 0xed, 0x2d, 0x0a, 0x98, 0x1f, 0xc7, 0x48 };#ifdef USE_CRYPTO /* * TLS-mode crypto objects. */#ifdef USE_SSL /* master OpenVPN SSL/TLS object */ struct tls_multi *tls_multi = NULL; /* an options string that must match on TLS client and server */ char *data_channel_options = NULL;#ifdef USE_PTHREAD /* object containing TLS thread state */ struct thread_parms thread_parms; /* object sent to us by TLS thread */ struct tt_ret tt_ret;#else /* used to optimize calls to tls_multi_process in single-threaded mode */ struct interval tmp_int;#endif#endif /* workspace buffers used by crypto routines */ struct buffer encrypt_buf = clear_buf (); struct buffer decrypt_buf = clear_buf (); /* passed to encrypt or decrypt, contains all crypto-related command line options related to data channel encryption/decryption */ struct crypto_options crypto_options; /* used to keep track of data channel packet sequence numbers */ struct packet_id packet_id; /* our residual iv from all encrypts */ uint8_t iv[EVP_MAX_IV_LENGTH];#endif /* * LZO compression library objects. */#ifdef USE_LZO struct buffer lzo_compress_buf = clear_buf (); struct buffer lzo_decompress_buf = clear_buf (); struct lzo_compress_workspace lzo_compwork;#endif /* * Buffers used to read from TUN device * and UDP port. */ struct buffer read_udp_buf = clear_buf (); struct buffer read_tun_buf = clear_buf (); /* * IPv4 TUN device? */ bool ipv4_tun = (!options->tun_ipv6 && is_dev_type (options->dev, options->dev_type, "tun")); const bool ipv6_udp_transport = false; /* we don't support IPv6 UDP sockets yet */ /* workspace for get_pid_file/write_pid */ struct pid_state pid_state; /* workspace for --user/--group */ struct user_state user_state; struct group_state group_state; /* temporary variable */ bool did_we_daemonize;#ifdef HAVE_SIGNAL_H /* * Special handling if signal arrives before * we are properly initialized. */ signal (SIGINT, signal_handler_exit); signal (SIGTERM, signal_handler_exit); signal (SIGHUP, SIG_IGN); signal (SIGUSR1, SIG_IGN); signal (SIGUSR2, SIG_IGN); signal (SIGPIPE, SIG_IGN);#endif /* HAVE_SIGNAL_H */ msg (M_INFO, "%s", title_string); CLEAR (udp_socket); CLEAR (frame);#ifdef FRAGMENT_ENABLE CLEAR (frame_fragment_omit);#endif /* should we disable paging? */ if (first_time && options->mlock) do_mlockall (true); /* * Initialize advanced MTU negotiation and datagram fragmentation */#ifdef FRAGMENT_ENABLE if (options->mtu_dynamic) fragment = fragment_init (&frame);#endif#ifdef USE_CRYPTO /* load a persisted packet-id for cross-session replay-protection */ if (options->packet_id_file) packet_id_persist_load (pid_persist, options->packet_id_file); if (!options->test_crypto)#endif /* open the UDP socket */ udp_socket_init (&udp_socket, options->local, options->remote, options->local_port, options->remote_port, options->bind_local, options->remote_float, options->inetd, udp_socket_addr, options->ipchange, options->resolve_retry_seconds, options->mtu_discover_type);#ifdef USE_CRYPTO /* Initialize crypto options */ CLEAR (crypto_options); CLEAR (packet_id); CLEAR (iv); /* Start with a random IV and carry forward the residuals */ if (options->iv) { randomize_iv (iv); crypto_options.iv = iv; } if (options->shared_secret_file) { /* * Static Key Mode (using a pre-shared key) */ /* Initialize packet ID tracking */ if (options->packet_id) { crypto_options.packet_id = &packet_id; crypto_options.pid_persist = pid_persist; crypto_options.packet_id_long_form = true; packet_id_persist_load_obj (pid_persist, crypto_options.packet_id); } if (!key_ctx_bi_defined (&ks->static_key)) { struct key key; /* Get cipher & hash algorithms */ init_key_type (&ks->key_type, options->ciphername, options->ciphername_defined, options->authname, options->authname_defined, options->keysize, options->test_crypto); /* Read cipher and hmac keys from shared secret file */ read_key_file (&key, options->shared_secret_file); /* Fix parity for DES keys and make sure not a weak key */ fixup_key (&key, &ks->key_type); if (!check_key (&key, &ks->key_type)) /* This should be a very improbable failure */ msg (M_FATAL, "Key in %s is bad. Try making a new key with --genkey.", options->shared_secret_file); /* Init cipher & hmac */ init_key_ctx (&ks->static_key.encrypt, &key, &ks->key_type, DO_ENCRYPT, "Static Encrypt"); init_key_ctx (&ks->static_key.decrypt, &key, &ks->key_type, DO_DECRYPT, "Static Decrypt"); /* Erase the key */ CLEAR (key); } else { msg (M_INFO, "Re-using pre-shared static key"); } /* Get key schedule */ crypto_options.key_ctx_bi = &ks->static_key; /* Compute MTU parameters */ crypto_adjust_frame_parameters(&frame, &ks->key_type, options->ciphername_defined, options->iv, options->packet_id, true); /* Sanity check on IV, sequence number, and cipher mode options */ check_replay_iv_consistency(&ks->key_type, options->packet_id, options->iv); /* * Test-crypto is a debugging tool * that basically does a loopback test * on the crypto subsystem. */ if (options->test_crypto) {#ifdef USE_PTHREAD if (first_time) { thread_init(); work_thread_create(test_crypto_thread, (void*) options); }#endif
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -