📄 forward.c
字号:
/* * 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 + -