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

📄 forward.c

📁 OpenVPN is a robust and highly flexible tunneling application that uses all of the encryption, authe
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  OpenVPN -- An application to securely tunnel IP networks *             over a single TCP/UDP port, with support for SSL/TLS-based *             session authentication and key exchange, *             packet encryption, packet authentication, and *             packet compression. * *  Copyright (C) 2002-2004 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 "forward.h"#include "init.h"#include "push.h"#include "gremlin.h"#include "mss.h"#include "event.h"#include "memdbg.h"#include "forward-inline.h"#include "occ-inline.h"#include "ping-inline.h"/* show event wait debugging info */const char *wait_status_string (struct context *c, struct gc_arena *gc){  struct buffer out = alloc_buf_gc (64, gc);  buf_printf (&out, "I/O WAIT %s|%s|%s|%s %s",	      tun_stat (c->c1.tuntap, EVENT_READ, gc),	      tun_stat (c->c1.tuntap, EVENT_WRITE, gc),	      socket_stat (c->c2.link_socket, EVENT_READ, gc),	      socket_stat (c->c2.link_socket, EVENT_WRITE, gc),	      tv_string (&c->c2.timeval, gc));  return BSTR (&out);}voidshow_wait_status (struct context *c){  struct gc_arena gc = gc_new ();  msg (D_EVENT_WAIT, "%s", wait_status_string (c, &gc));  gc_free (&gc);}/* * In TLS mode, let TLS level respond to any control-channel * packets which were received, or prepare any packets for * transmission. * * tmp_int is purely an optimization that allows us to call * tls_multi_process less frequently when there's not much * traffic on the control-channel. * */#if defined(USE_CRYPTO) && defined(USE_SSL)voidcheck_tls_dowork (struct context *c){  interval_t wakeup = BIG_TIMEOUT;  if (interval_test (&c->c2.tmp_int))    {      if (tls_multi_process	  (c->c2.tls_multi, &c->c2.to_link, &c->c2.to_link_addr,	   get_link_socket_info (c), &wakeup))	{	  update_time ();	  interval_action (&c->c2.tmp_int);	}      interval_future_trigger (&c->c2.tmp_int, wakeup);    }  interval_schedule_wakeup (&c->c2.tmp_int, &wakeup);  if (wakeup)    context_reschedule_sec (c, wakeup);}#endif#if defined(USE_CRYPTO) && defined(USE_SSL)voidcheck_tls_errors_dowork (struct context *c){  /* TLS errors are fatal in TCP mode */  c->sig->signal_received = SIGUSR1;  msg (D_STREAM_ERRORS, "Fatal decryption error, restarting");  c->sig->signal_text = "tls-error";}#endif/* * Handle incoming configuration * messages on the control channel. */#if P2MPvoidcheck_incoming_control_channel_dowork (struct context *c){  const int len = tls_test_payload_len (c->c2.tls_multi);  if (len)    {      struct gc_arena gc = gc_new ();      struct buffer buf = alloc_buf_gc (len, &gc);      if (tls_rec_payload (c->c2.tls_multi, &buf))	{	  msg (D_PUSH, "PUSH: Received control message: '%s'", BSTR (&buf));	  if (buf_string_match_head_str (&buf, "PUSH_"))	    {	      unsigned int option_types_found = 0;	      const int status = process_incoming_push_msg (c,							    &buf,							    c->options.pull,							    pull_permission_mask (),							    &option_types_found);	      if (status == PUSH_MSG_ERROR)		msg (D_PUSH_ERRORS, "WARNING: Received bad push/pull message: %s", BSTR (&buf));	      else if (status == PUSH_MSG_REPLY)		{		  do_up (c, true, option_types_found); /* delay bringing tun/tap up until --push parms received from remote */		  event_timeout_clear (&c->c2.push_request_interval);		}	      else if (status == PUSH_MSG_REQUEST)		{		  //msg (D_PUSH, "PUSH: PUSH_MSG_REQUEST Replied");		}	      else if (status == PUSH_MSG_REQUEST_DEFERRED)		{		  //msg (D_PUSH, "PUSH: PUSH_MSG_REQUEST Deferred");		}	    }	  else	    {	      msg (D_PUSH_ERRORS, "WARNING: Received unknown control message: %s", BSTR (&buf));	    }	}      else	{	  msg (D_PUSH_ERRORS, "WARNING: Receive control message failed");	}      gc_free (&gc);    }}/* * Periodically resend PUSH_REQUEST until PUSH message received */voidcheck_push_request_dowork (struct context *c){  send_push_request (c);}#endif/* * Things that need to happen immediately after connection initiation should go here. */voidcheck_connection_established_dowork (struct context *c){  if (event_timeout_trigger (&c->c2.wait_for_connect, &c->c2.timeval, ETT_DEFAULT))    {      if (CONNECTION_ESTABLISHED (c))	{#if P2MP	  /* if --pull was specified, send a push request to server */	  if (c->c2.tls_multi && c->options.pull)	    {	      send_push_request (c);	      /* if no reply, try again in 5 sec */	      event_timeout_init (&c->c2.push_request_interval, 5, now);	      reset_coarse_timers (c);	    }	  else#endif	    {	      do_up (c, false, 0);	    }	  event_timeout_clear (&c->c2.wait_for_connect);	}    }}boolsend_control_channel_string (struct context *c, char *str){#if defined(USE_CRYPTO) && defined(USE_SSL)  if (c->c2.tls_multi) {    struct buffer buf;    bool stat;    buf_set_read (&buf, str, strlen (str) + 1);    stat = tls_send_payload (c->c2.tls_multi, &buf);    interval_action (&c->c2.tmp_int);    context_immediate_reschedule (c);    msg (D_PUSH, "SENT CONTROL [%s]: '%s' (status=%d)",	 tls_common_name (c->c2.tls_multi, false),	 str,	 (int) stat);    return stat;  }#endif  return true;}/* * Add routes. */voidcheck_add_routes_dowork (struct context *c){  if (c->c1.route_list)    {      do_route (&c->options, c->c1.route_list);      update_time ();    }  event_timeout_clear (&c->c2.route_wakeup);}/* * Should we exit due to inactivity timeout? */voidcheck_inactivity_timeout_dowork (struct context *c){  struct gc_arena gc = gc_new ();  msg (M_INFO, "Inactivity timeout (--inactive), exiting");  c->sig->signal_received = SIGTERM;  c->sig->signal_text = "inactive";  gc_free (&gc);}/* * Should we write timer-triggered status file. */voidcheck_status_file_dowork (struct context *c){  if (c->c1.status_output)    print_status (c, c->c1.status_output);}/* * Should we deliver a datagram fragment to remote? */voidcheck_fragment_dowork (struct context *c){  struct link_socket_info *lsi = get_link_socket_info (c);  /* OS MTU Hint? */  if (lsi->mtu_changed && c->c2.ipv4_tun)    {      frame_adjust_path_mtu (&c->c2.frame_fragment, c->c2.link_socket->mtu,			     c->options.proto);      lsi->mtu_changed = false;    }  if (fragment_outgoing_defined (c->c2.fragment))    {      if (!c->c2.to_link.len)	{	  /* encrypt a fragment for output to TCP/UDP port */	  ASSERT (fragment_ready_to_send (c->c2.fragment, &c->c2.buf, &c->c2.frame_fragment));	  encrypt_sign (c, false);	}      else	{	  /* output buffer is full */	  //tv_clear (&c->c2.timeval);	}    }  fragment_housekeeping (c->c2.fragment, &c->c2.frame_fragment, &c->c2.timeval);}/* * Compress, fragment, encrypt and HMAC-sign an outgoing packet. */voidencrypt_sign (struct context *c, bool comp_frag){  struct context_buffers *b = c->c2.buffers;  if (comp_frag)    {#ifdef USE_LZO      /* Compress the packet. */      if (c->options.comp_lzo)	lzo_compress (&c->c2.buf, b->lzo_compress_buf, &c->c2.lzo_compwork, &c->c2.frame);#endif      if (c->c2.fragment)	fragment_outgoing (c->c2.fragment, &c->c2.buf, &c->c2.frame_fragment);    }#ifdef USE_CRYPTO#ifdef USE_SSL  /*   * If TLS mode, get the key we will use to encrypt   * the packet.   */  if (c->c2.tls_multi)    {      //tls_mutex_lock (c->c2.tls_multi);      tls_pre_encrypt (c->c2.tls_multi, &c->c2.buf, &c->c2.crypto_options);    }#endif  /*   * Encrypt the packet and write an optional   * HMAC signature.   */  openvpn_encrypt (&c->c2.buf, b->encrypt_buf, &c->c2.crypto_options, &c->c2.frame);#endif  /*   * Get the address we will be sending the packet to.   */  link_socket_get_outgoing_addr (&c->c2.buf, get_link_socket_info (c),				 &c->c2.to_link_addr);#ifdef USE_CRYPTO#ifdef USE_SSL  /*   * In TLS mode, prepend the appropriate one-byte opcode   * to the packet which identifies it as a data channel   * packet and gives the low-permutation version of   * the key-id to the recipient so it knows which   * decrypt key to use.   */  if (c->c2.tls_multi)    {      tls_post_encrypt (c->c2.tls_multi, &c->c2.buf);      //tls_mutex_unlock (c->c2.tls_multi);    }#endif#endif  c->c2.to_link = c->c2.buf;}/* * Coarse timers work to 1 second resolution. */static voidprocess_coarse_timers (struct context *c){#ifdef USE_CRYPTO  /* flush current packet-id to file once per 60     seconds if --replay-persist was specified */  check_packet_id_persist_flush (c);#endif  /* should we update status file? */  check_status_file (c);  /* process connection establishment items */  check_connection_established (c);#if P2MP  /* see if we should send a push_request in response to --pull */  check_push_request (c);#endif  /* process --route options */  check_add_routes (c);  /* possibly exit due to --inactive */  check_inactivity_timeout (c);  if (c->sig->signal_received)    return;  /* restart if ping not received */  check_ping_restart (c);  if (c->sig->signal_received)    return;  /* Should we send an OCC_REQUEST message? */  check_send_occ_req (c);  /* Should we send an MTU load test? */  check_send_occ_load_test (c);  /* Should we ping the remote? */  check_ping_send (c);}static voidcheck_coarse_timers_dowork (struct context *c){  const struct timeval save = c->c2.timeval;  c->c2.timeval.tv_sec = BIG_TIMEOUT;  c->c2.timeval.tv_usec = 0;  process_coarse_timers (c);  c->c2.coarse_timer_wakeup = now + c->c2.timeval.tv_sec;   msg (D_INTERVAL, "TIMER: coarse timer wakeup %d seconds", (int) c->c2.timeval.tv_sec);  /* Is the coarse timeout NOT the earliest one? */  if (c->c2.timeval.tv_sec > save.tv_sec)    c->c2.timeval = save;}static inline voidcheck_coarse_timers (struct context *c){  const time_t local_now = now;  if (local_now >= c->c2.coarse_timer_wakeup)    check_coarse_timers_dowork (c);  else    context_reschedule_sec (c, c->c2.coarse_timer_wakeup - local_now);}static voidcheck_timeout_random_component_dowork (struct context *c){  const int update_interval = 10; /* seconds */  c->c2.update_timeout_random_component = now + update_interval;  c->c2.timeout_random_component.tv_usec = (time_t) get_random () & 0x000FFFFF;  c->c2.timeout_random_component.tv_sec = 0;  msg (D_INTERVAL, "RANDOM USEC=%d", (int) c->c2.timeout_random_component.tv_usec);}static inline voidcheck_timeout_random_component (struct context *c){  if (now >= c->c2.update_timeout_random_component)    check_timeout_random_component_dowork (c);  if (c->c2.timeval.tv_sec >= 1)    tv_add (&c->c2.timeval, &c->c2.timeout_random_component);}/* * Handle addition and removal of the 10-byte Socks5 header * in UDP packets. */static inline voidsocks_postprocess_incoming_link (struct context *c){  if (c->c2.link_socket->socks_proxy && c->c2.link_socket->info.proto == PROTO_UDPv4)    socks_process_incoming_udp (&c->c2.buf, &c->c2.from);}static inline voidsocks_preprocess_outgoing_link (struct context *c,				struct sockaddr_in **to_addr,				int *size_delta){  if (c->c2.link_socket->socks_proxy && c->c2.link_socket->info.proto == PROTO_UDPv4)    {      *size_delta += socks_process_outgoing_udp (&c->c2.to_link, &c->c2.to_link_addr);      *to_addr = &c->c2.link_socket->socks_relay;    }}/* undo effect of socks_preprocess_outgoing_link */static inline voidlink_socket_write_post_size_adjust (int *size,				    int size_delta,				    struct buffer *buf){  if (size_delta > 0 && *size > size_delta)    {      *size -= size_delta;      if (!buf_advance (buf, size_delta))	*size = 0;    }}voidread_incoming_link (struct context *c){  /*   * Set up for recvfrom call to read datagram   * sent to our TCP/UDP port.   */  int status;  ASSERT (!c->c2.to_tun.len);  c->c2.buf = c->c2.buffers->read_link_buf;  ASSERT (buf_init (&c->c2.buf, FRAME_HEADROOM (&c->c2.frame)));  status = link_socket_read (c->c2.link_socket, &c->c2.buf, MAX_RW_SIZE_LINK (&c->c2.frame), &c->c2.from);  if (socket_connection_reset (c->c2.link_socket, status))    {      /* received a disconnect from a connection-oriented protocol */      if (c->options.inetd)	{	  c->sig->signal_received = SIGTERM;	  msg (D_STREAM_ERRORS, "Connection reset, inetd/xinetd exit [%d]", status);	}      else	{	  c->sig->signal_received = SIGUSR1;	  msg (D_STREAM_ERRORS, "Connection reset, restarting [%d]", status);	}      c->sig->signal_text = "connection-reset";      return;    }  /* check recvfrom status */  check_status (status, "read", c->c2.link_socket, NULL);  /* Remove socks header if applicable */  socks_postprocess_incoming_link (c);}voidprocess_incoming_link (struct context *c){  struct gc_arena gc = gc_new ();  bool decrypt_status;  struct link_socket_info *lsi = get_link_socket_info (c);  if (c->c2.buf.len > 0)    {      c->c2.link_read_bytes += c->c2.buf.len;      c->c2.original_recv_size = c->c2.buf.len;    }  else    c->c2.original_recv_size = 0;  /* take action to corrupt packet if we are in gremlin test mode */  if (c->options.gremlin) {    if (!ask_gremlin())      c->c2.buf.len = 0;    corrupt_gremlin (&c->c2.buf);  }  /* log incoming packet */#ifdef LOG_RW  if (c->c2.log_rw)    fprintf (stderr, "R");#endif  msg (D_LINK_RW, "%s READ [%d] from %s: %s",       proto2ascii (lsi->proto, true),       BLEN (&c->c2.buf),       print_sockaddr (&c->c2.from, &gc),       PROTO_DUMP (&c->c2.buf, &gc));  /*   * Good, non-zero length packet received.   * Commence multi-stage processing of packet,   * such as authenticate, decrypt, decompress.   * If any stage fails, it sets buf.len to 0 or -1,   * telling downstream stages to ignore the packet.   */  if (c->c2.buf.len > 0)    {      if (!link_socket_verify_incoming_addr (&c->c2.buf, lsi, &c->c2.from))	link_socket_bad_incoming_addr (&c->c2.buf, lsi, &c->c2.from);#ifdef USE_CRYPTO#ifdef USE_SSL      if (c->c2.tls_multi)	{	  /*	   * If tls_pre_decrypt returns true, it means the incoming	   * packet was a good TLS control channel packet.  If so, TLS code	   * will deal with the packet and set buf.len to 0 so downstream	   * stages ignore it.	   *	   * If the packet is a data channel packet, tls_pre_decrypt	   * will load crypto_options with the correct encryption key	   * and return false.	   */	  //tls_mutex_lock (c->c2.tls_multi);	  if (tls_pre_decrypt (c->c2.tls_multi, &c->c2.from, &c->c2.buf, &c->c2.crypto_options))	    {	      interval_action (&c->c2.tmp_int);

⌨️ 快捷键说明

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