⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 openvpn.c

📁 一个开源的VPN原码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  OpenVPN -- An application to securely tunnel IP networks *             over a single UDP port, with support for TLS-based *             session authentication and key exchange, *             packet encryption, packet authentication, and *             packet compression. * *  Copyright (C) 2002 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 */#include "config.h"#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 "openvpn.h"#include "memdbg.h"/* Handle signals */static volatile int signal_received = 0;/* 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);}/* * 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(buf) protocol_dump(buf, \				      PD_SHOW_DATA | \				      (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)#endifstatic void print_frame_parms(int level, const struct frame *frame, const char* prefix){  msg (level, "%s: mtu=%d extra_frame=%d extra_buffer=%d extra_tun=%d",       prefix,       frame->mtu,       frame->extra_frame,       frame->extra_buffer,       frame->extra_tun);}/* * Finish initialization of the frame MTU parameters * based on command line options and buffering requirements. */static voidframe_finalize(struct frame *frame, const struct options *options){  if (options->tun_mtu_defined)    {      frame->mtu = options->tun_mtu;    }  else    {      ASSERT (options->udp_mtu_defined);      frame->mtu = options->udp_mtu - frame->extra_frame;    }  if (frame->mtu < MIN_TUN_MTU)    {      msg (M_WARN, "TUN MTU value must be at least %d", MIN_TUN_MTU);      print_frame_parms (M_FATAL, frame, "MTU is too small");    }  frame->extra_buffer += frame->extra_frame + frame->extra_tun;}#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 */#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);}/* * 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,	 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;  /* declare various buffers */  struct buffer to_tun = clear_buf ();  struct buffer to_udp = clear_buf ();  struct buffer 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;  /* Always set to current time. */  time_t current;  /*   * Traffic shaper object.   */  struct shaper shaper;  /*   * 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  /* local socket descriptor used to communicate with TLS thread */  int tls_thread_socket = 0;  /* 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 ();  /*   * 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);  msg (M_INFO, "%s", TITLE);  CLEAR (udp_socket);  CLEAR (frame);  if (first_time)    {      /* initialize threading if pthread configure option enabled */      thread_init();            /* save process ID in a file */      write_pid (options->writepid);      if (options->mlock) /* should we disable paging? */	do_mlockall (true);      /* chroot if requested */      do_chroot (options->chroot_dir);    }#ifdef USE_CRYPTO  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);#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.packet_id_long_form = true;	}      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)	    work_thread_create(test_crypto_thread, (struct options*) options);#endif	  frame_finalize (&frame, options);	  test_crypto (&crypto_options, &frame);	  key_schedule_free (ks);	  signal_received = 0;#ifdef USE_PTHREAD	  if (first_time)	    work_thread_join ();#endif	  goto done;	}    }#ifdef USE_SSL  else if (options->tls_server || options->tls_client)    {      /*       * TLS-based dynamic key exchange mode       */      struct tls_options to;      bool packet_id_long_form;      ASSERT (!options->test_crypto);      /* Make sure we are either a TLS client or server but not both */      ASSERT (options->tls_server == !options->tls_client);      /* Let user specify a script to verify the incoming certificate */      tls_set_verify_command (options->tls_verify);      if (!ks->ssl_ctx)	{	  /*	   * Initialize the OpenSSL library's global	   * SSL context.	   */	  ks->ssl_ctx = init_ssl (options->tls_server,				  options->ca_file,				  options->dh_file,				  options->cert_file,				  options->priv_key_file,				  options->cipher_list);	  /* Get cipher & hash algorithms */	  init_key_type (&ks->key_type, options->ciphername,			 options->ciphername_defined, options->authname,			 options->authname_defined, options->keysize,			 true);	  /* TLS handshake authentication (--tls-auth) */	  if (options->tls_auth_file)	    get_tls_handshake_key (&ks->key_type, &ks->tls_auth_key, options->tls_auth_file);	}      else	{	  msg (M_INFO, "Re-using SSL/TLS context");	}      /* Sanity check on IV, sequence number, and cipher mode options */      check_replay_iv_consistency(&ks->key_type, options->packet_id, options->iv);      /* In short form, unique datagram identifier is 32 bits, in long form 64 bits */      packet_id_long_form = cfb_ofb_mode (&ks->key_type);      /* Compute MTU parameters */      crypto_adjust_frame_parameters(&frame,				     &ks->key_type,				     options->ciphername_defined,				     options->iv,				     options->packet_id,				     packet_id_long_form);      tls_adjust_frame_parameters(&frame);      /* Set all command-line TLS-related options */      CLEAR (to);      to.ssl_ctx = ks->ssl_ctx;      to.key_type = ks->key_type;      to.server = options->tls_server;      to.options = data_channel_options = options_string (options);      to.packet_id = options->packet_id;      to.packet_id_long_form = packet_id_long_form;      to.transition_window = options->transition_window;      to.handshake_window = options->handshake_window;      to.packet_timeout = options->tls_timeout;      to.renegotiate_bytes = options->renegotiate_bytes;      to.renegotiate_packets = options->renegotiate_packets;      to.renegotiate_seconds = options->renegotiate_seconds;      to.single_session = options->single_session;      to.disable_occ = options->disable_occ;      /* TLS handshake authentication (--tls-auth) */      if (options->tls_auth_file)	{	  to.tls_auth_key = ks->tls_auth_key;	  to.tls_auth.packet_id_long_form = true;	  crypto_adjust_frame_parameters(&to.frame,					 &ks->key_type,					 false,					 false,					 true,					 true);	}      /*       * Initialize OpenVPN's master TLS-mode object.       */      tls_multi = tls_multi_init (&to, &udp_socket);    }#endif  else    {      /*       * No encryption or authentication.       */      ASSERT (!options->test_crypto);      free_key_ctx_bi (&ks->static_key);      crypto_options.key_ctx_bi = &ks->static_key;      msg (M_WARN,	   "******* WARNING *******: all encryption and authentication features disabled -- all data will be tunnelled as cleartext");    }#else /* USE_CRYPTO */  msg (M_WARN,       "******* WARNING *******: OpenVPN built without OpenSSL -- encryption and authentication features disabled -- all data will be tunnelled as cleartext");#endif /* USE_CRYPTO */#ifdef USE_LZO  /*   * Initialize LZO compression library.   */  if (options->comp_lzo)    {      lzo_compress_init (&lzo_compwork, options->comp_lzo_adaptive);      lzo_adjust_frame_parameters (&frame);    }#endif#if 0  /*

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -