src/openvpn/forward.c
6fbf66fa
 /*
  *  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.
  *
49979459
  *  Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
6fbf66fa
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2
  *  as published by the Free Software Foundation.
  *
  *  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.
  *
caa54ac3
  *  You should have received a copy of the GNU General Public License along
  *  with this program; if not, write to the Free Software Foundation, Inc.,
  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
6fbf66fa
  */
 
c110b289
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #elif defined(_MSC_VER)
 #include "config-msvc.h"
 #endif
 
6fbf66fa
 #include "syshead.h"
 
 #include "forward.h"
 #include "init.h"
 #include "push.h"
 #include "gremlin.h"
 #include "mss.h"
 #include "event.h"
6add6b2f
 #include "ps.h"
03731db3
 #include "dhcp.h"
16322c78
 #include "common.h"
63dc03d0
 #include "ssl_verify.h"
6fbf66fa
 
 #include "memdbg.h"
 
 #include "forward-inline.h"
 #include "occ-inline.h"
 #include "ping-inline.h"
ffea644c
 #include "mstats.h"
6fbf66fa
 
16322c78
 counter_type link_read_bytes_global;  /* GLOBAL */
 counter_type link_write_bytes_global; /* GLOBAL */
 
6fbf66fa
 /* show event wait debugging info */
 
 #ifdef ENABLE_DEBUG
 
 const char *
81d882d5
 wait_status_string(struct context *c, struct gc_arena *gc)
6fbf66fa
 {
81d882d5
     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);
6fbf66fa
 }
 
 void
81d882d5
 show_wait_status(struct context *c)
6fbf66fa
 {
81d882d5
     struct gc_arena gc = gc_new();
     dmsg(D_EVENT_WAIT, "%s", wait_status_string(c, &gc));
     gc_free(&gc);
6fbf66fa
 }
 
81d882d5
 #endif /* ifdef ENABLE_DEBUG */
6fbf66fa
 
 /*
  * 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.
  *
  */
 void
81d882d5
 check_tls_dowork(struct context *c)
6fbf66fa
 {
81d882d5
     interval_t wakeup = BIG_TIMEOUT;
6fbf66fa
 
81d882d5
     if (interval_test(&c->c2.tmp_int))
6fbf66fa
     {
81d882d5
         const int tmp_status = tls_multi_process
                                    (c->c2.tls_multi, &c->c2.to_link, &c->c2.to_link_addr,
                                    get_link_socket_info(c), &wakeup);
         if (tmp_status == TLSMP_ACTIVE)
         {
             update_time();
             interval_action(&c->c2.tmp_int);
         }
         else if (tmp_status == TLSMP_KILL)
         {
             register_signal(c, SIGTERM, "auth-control-exit");
         }
 
         interval_future_trigger(&c->c2.tmp_int, wakeup);
6fbf66fa
     }
 
81d882d5
     interval_schedule_wakeup(&c->c2.tmp_int, &wakeup);
6fbf66fa
 
81d882d5
     if (wakeup)
     {
         context_reschedule_sec(c, wakeup);
     }
6fbf66fa
 }
 
 void
81d882d5
 check_tls_errors_co(struct context *c)
6fbf66fa
 {
81d882d5
     msg(D_STREAM_ERRORS, "Fatal TLS error (check_tls_errors_co), restarting");
     register_signal(c, c->c2.tls_exit_signal, "tls-error"); /* SOFT-SIGUSR1 -- TLS error */
6fbf66fa
 }
 
 void
81d882d5
 check_tls_errors_nco(struct context *c)
6fbf66fa
 {
81d882d5
     register_signal(c, c->c2.tls_exit_signal, "tls-error"); /* SOFT-SIGUSR1 -- TLS error */
6fbf66fa
 }
 
 #if P2MP
 
 /*
  * Handle incoming configuration
  * messages on the control channel.
  */
 void
81d882d5
 check_incoming_control_channel_dowork(struct context *c)
6fbf66fa
 {
81d882d5
     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))
         {
             /* force null termination of message */
             buf_null_terminate(&buf);
 
             /* enforce character class restrictions */
             string_mod(BSTR(&buf), CC_PRINT, CC_CRLF, 0);
 
             if (buf_string_match_head_str(&buf, "AUTH_FAILED"))
             {
                 receive_auth_failed(c, &buf);
             }
             else if (buf_string_match_head_str(&buf, "PUSH_"))
             {
                 incoming_push_message(c, &buf);
             }
             else if (buf_string_match_head_str(&buf, "RESTART"))
             {
                 server_pushed_signal(c, &buf, true, 7);
             }
             else if (buf_string_match_head_str(&buf, "HALT"))
             {
                 server_pushed_signal(c, &buf, false, 4);
             }
             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);
6fbf66fa
     }
 }
 
 /*
  * Periodically resend PUSH_REQUEST until PUSH message received
  */
 void
81d882d5
 check_push_request_dowork(struct context *c)
6fbf66fa
 {
81d882d5
     send_push_request(c);
72bf37c7
 
81d882d5
     /* if no response to first push_request, retry at PUSH_REQUEST_INTERVAL second intervals */
     event_timeout_modify_wakeup(&c->c2.push_request_interval, PUSH_REQUEST_INTERVAL);
6fbf66fa
 }
 
f25071b6
 #endif /* P2MP */
6fbf66fa
 
 /*
  * Things that need to happen immediately after connection initiation should go here.
  */
 void
81d882d5
 check_connection_established_dowork(struct context *c)
6fbf66fa
 {
81d882d5
     if (event_timeout_trigger(&c->c2.wait_for_connect, &c->c2.timeval, ETT_DEFAULT))
6fbf66fa
     {
81d882d5
         if (CONNECTION_ESTABLISHED(c))
         {
6fbf66fa
 #if P2MP
81d882d5
             /* if --pull was specified, send a push request to server */
             if (c->c2.tls_multi && c->options.pull)
             {
6fbf66fa
 #ifdef ENABLE_MANAGEMENT
81d882d5
                 if (management)
                 {
                     management_set_state(management,
                                          OPENVPN_STATE_GET_CONFIG,
                                          NULL,
                                          NULL,
                                          NULL,
                                          NULL,
                                          NULL);
                 }
6fbf66fa
 #endif
81d882d5
                 /* fire up push request right away (already 1s delayed) */
                 event_timeout_init(&c->c2.push_request_interval, 0, now);
                 reset_coarse_timers(c);
             }
             else
 #endif /* if P2MP */
             {
                 do_up(c, false, 0);
             }
 
             event_timeout_clear(&c->c2.wait_for_connect);
         }
6fbf66fa
     }
 }
 
 /*
  * Send a string to remote over the TLS control channel.
  * Used for push/pull messages, passing username/password,
  * etc.
  */
 bool
81d882d5
 send_control_channel_string(struct context *c, const char *str, int msglevel)
6fbf66fa
 {
81d882d5
     if (c->c2.tls_multi)
     {
         struct gc_arena gc = gc_new();
         bool stat;
 
         /* buffered cleartext write onto TLS control channel */
         stat = tls_send_payload(c->c2.tls_multi, (uint8_t *) str, strlen(str) + 1);
 
         /*
          * Reschedule tls_multi_process.
          * NOTE: in multi-client mode, usually the below two statements are
          * insufficient to reschedule the client instance object unless
          * multi_schedule_context_wakeup(m, mi) is also called.
          */
         interval_action(&c->c2.tmp_int);
         context_immediate_reschedule(c); /* ZERO-TIMEOUT */
 
         msg(msglevel, "SENT CONTROL [%s]: '%s' (status=%d)",
             tls_common_name(c->c2.tls_multi, false),
             sanitize_control_message(str, &gc),
             (int) stat);
 
         gc_free(&gc);
         return stat;
     }
     return true;
6fbf66fa
 }
 
 /*
  * Add routes.
  */
 
 static void
81d882d5
 check_add_routes_action(struct context *c, const bool errors)
6fbf66fa
 {
81d882d5
     do_route(&c->options, c->c1.route_list, c->c1.route_ipv6_list,
              c->c1.tuntap, c->plugins, c->c2.es);
     update_time();
     event_timeout_clear(&c->c2.route_wakeup);
     event_timeout_clear(&c->c2.route_wakeup_expire);
     initialization_sequence_completed(c, errors ? ISC_ERRORS : 0); /* client/p2p --route-delay was defined */
6fbf66fa
 }
 
 void
81d882d5
 check_add_routes_dowork(struct context *c)
6fbf66fa
 {
81d882d5
     if (test_routes(c->c1.route_list, c->c1.tuntap))
6fbf66fa
     {
81d882d5
         check_add_routes_action(c, false);
6fbf66fa
     }
81d882d5
     else if (event_timeout_trigger(&c->c2.route_wakeup_expire, &c->c2.timeval, ETT_DEFAULT))
6fbf66fa
     {
81d882d5
         check_add_routes_action(c, true);
6fbf66fa
     }
81d882d5
     else
6fbf66fa
     {
81d882d5
         msg(D_ROUTE, "Route: Waiting for TUN/TAP interface to come up...");
         if (c->c1.tuntap)
         {
             if (!tun_standby(c->c1.tuntap))
             {
                 register_signal(c, SIGHUP, "ip-fail");
                 c->persist.restart_sleep_seconds = 10;
445b192a
 #ifdef _WIN32
81d882d5
                 show_routes(M_INFO|M_NOPREFIX);
                 show_adapters(M_INFO|M_NOPREFIX);
a9c802b2
 #endif
81d882d5
             }
         }
         update_time();
         if (c->c2.route_wakeup.n != 1)
         {
             event_timeout_init(&c->c2.route_wakeup, 1, now);
         }
         event_timeout_reset(&c->c2.ping_rec_interval);
6fbf66fa
     }
 }
 
 /*
  * Should we exit due to inactivity timeout?
  */
 void
81d882d5
 check_inactivity_timeout_dowork(struct context *c)
6fbf66fa
 {
81d882d5
     msg(M_INFO, "Inactivity timeout (--inactive), exiting");
     register_signal(c, SIGTERM, "inactive");
6fbf66fa
 }
 
f2134b7b
 int
81d882d5
 get_server_poll_remaining_time(struct event_timeout *server_poll_timeout)
f2134b7b
 {
     update_time();
     int remaining = event_timeout_remaining(server_poll_timeout);
81d882d5
     return max_int(0, remaining);
f2134b7b
 }
6fbf66fa
 #if P2MP
 
e1e977f3
 void
81d882d5
 check_server_poll_timeout_dowork(struct context *c)
e1e977f3
 {
81d882d5
     event_timeout_reset(&c->c2.server_poll_interval);
     ASSERT(c->c2.tls_multi);
     if (!tls_initial_packet_received(c->c2.tls_multi))
e1e977f3
     {
81d882d5
         msg(M_INFO, "Server poll timeout, restarting");
         register_signal(c, SIGUSR1, "server_poll");
         c->persist.restart_sleep_seconds = -1;
e1e977f3
     }
 }
 
6fbf66fa
 /*
f25071b6
  * Schedule a signal n_seconds from now.
6fbf66fa
  */
 void
81d882d5
 schedule_exit(struct context *c, const int n_seconds, const int signal)
6fbf66fa
 {
81d882d5
     tls_set_single_session(c->c2.tls_multi);
     update_time();
     reset_coarse_timers(c);
     event_timeout_init(&c->c2.scheduled_exit, n_seconds, now);
     c->c2.scheduled_exit_signal = signal;
     msg(D_SCHED_EXIT, "Delayed exit in %d seconds", n_seconds);
6fbf66fa
 }
 
 /*
  * Scheduled exit?
  */
 void
81d882d5
 check_scheduled_exit_dowork(struct context *c)
6fbf66fa
 {
81d882d5
     register_signal(c, c->c2.scheduled_exit_signal, "delayed-exit");
6fbf66fa
 }
 
81d882d5
 #endif /* if P2MP */
6fbf66fa
 
 /*
  * Should we write timer-triggered status file.
  */
 void
81d882d5
 check_status_file_dowork(struct context *c)
6fbf66fa
 {
81d882d5
     if (c->c1.status_output)
     {
         print_status(c, c->c1.status_output);
     }
6fbf66fa
 }
 
 #ifdef ENABLE_FRAGMENT
 /*
  * Should we deliver a datagram fragment to remote?
  */
 void
81d882d5
 check_fragment_dowork(struct context *c)
6fbf66fa
 {
81d882d5
     struct link_socket_info *lsi = get_link_socket_info(c);
6fbf66fa
 
81d882d5
     /* OS MTU Hint? */
     if (lsi->mtu_changed)
6fbf66fa
     {
81d882d5
         frame_adjust_path_mtu(&c->c2.frame_fragment, c->c2.link_socket->mtu,
                               c->options.ce.proto);
         lsi->mtu_changed = false;
6fbf66fa
     }
 
81d882d5
     if (fragment_outgoing_defined(c->c2.fragment))
6fbf66fa
     {
81d882d5
         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);
         }
6fbf66fa
     }
 
81d882d5
     fragment_housekeeping(c->c2.fragment, &c->c2.frame_fragment, &c->c2.timeval);
6fbf66fa
 }
81d882d5
 #endif /* ifdef ENABLE_FRAGMENT */
6fbf66fa
 
 /*
  * Buffer reallocation, for use with null encryption.
  */
 static inline void
81d882d5
 buffer_turnover(const uint8_t *orig_buf, struct buffer *dest_stub, struct buffer *src_stub, struct buffer *storage)
6fbf66fa
 {
81d882d5
     if (orig_buf == src_stub->data && src_stub->data != storage->data)
6fbf66fa
     {
81d882d5
         buf_assign(storage, src_stub);
         *dest_stub = *storage;
6fbf66fa
     }
81d882d5
     else
6fbf66fa
     {
81d882d5
         *dest_stub = *src_stub;
6fbf66fa
     }
 }
 
 /*
  * Compress, fragment, encrypt and HMAC-sign an outgoing packet.
  * Input: c->c2.buf
  * Output: c->c2.to_link
  */
 void
81d882d5
 encrypt_sign(struct context *c, bool comp_frag)
6fbf66fa
 {
81d882d5
     struct context_buffers *b = c->c2.buffers;
     const uint8_t *orig_buf = c->c2.buf.data;
     struct crypto_options *co = NULL;
6fbf66fa
 
 #if P2MP_SERVER
81d882d5
     /*
      * Drop non-TLS outgoing packet if client-connect script/plugin
      * has not yet succeeded.
      */
     if (c->c2.context_auth != CAS_SUCCEEDED)
     {
         c->c2.buf.len = 0;
     }
6fbf66fa
 #endif
 
81d882d5
     if (comp_frag)
6fbf66fa
     {
38d96bd7
 #ifdef USE_COMP
81d882d5
         /* Compress the packet. */
         if (c->c2.comp_context)
         {
             (*c->c2.comp_context->alg.compress)(&c->c2.buf, b->compress_buf, c->c2.comp_context, &c->c2.frame);
         }
6fbf66fa
 #endif
 #ifdef ENABLE_FRAGMENT
81d882d5
         if (c->c2.fragment)
         {
             fragment_outgoing(c->c2.fragment, &c->c2.buf, &c->c2.frame_fragment);
         }
6fbf66fa
 #endif
     }
 
81d882d5
     /* initialize work buffer with FRAME_HEADROOM bytes of prepend capacity */
     ASSERT(buf_init(&b->encrypt_buf, FRAME_HEADROOM(&c->c2.frame)));
66407e11
 
81d882d5
     if (c->c2.tls_multi)
6fbf66fa
     {
81d882d5
         /* Get the key we will use to encrypt the packet. */
         tls_pre_encrypt(c->c2.tls_multi, &c->c2.buf, &co);
         /* If using P_DATA_V2, prepend the 1-byte opcode and 3-byte peer-id to the
          * packet before openvpn_encrypt(), so we can authenticate the opcode too.
          */
3b9cce65
         if (c->c2.buf.len > 0 && c->c2.tls_multi->use_peer_id)
81d882d5
         {
             tls_prepend_opcode_v2(c->c2.tls_multi, &b->encrypt_buf);
         }
2d9c6d20
     }
81d882d5
     else
2d9c6d20
     {
81d882d5
         co = &c->c2.crypto_options;
6fbf66fa
     }
 
81d882d5
     /* Encrypt and authenticate the packet */
     openvpn_encrypt(&c->c2.buf, b->encrypt_buf, co);
66407e11
 
81d882d5
     /* Do packet administration */
     if (c->c2.tls_multi)
66407e11
     {
3b9cce65
         if (c->c2.buf.len > 0 && !c->c2.tls_multi->use_peer_id)
81d882d5
         {
             tls_prepend_opcode_v1(c->c2.tls_multi, &c->c2.buf);
         }
         tls_post_encrypt(c->c2.tls_multi, &c->c2.buf);
66407e11
     }
 
81d882d5
     /*
      * 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);
6fbf66fa
 
81d882d5
     /* if null encryption, copy result to read_tun_buf */
     buffer_turnover(orig_buf, &c->c2.to_link, &c->c2.buf, &b->read_tun_buf);
6fbf66fa
 }
 
 /*
  * Coarse timers work to 1 second resolution.
  */
 static void
81d882d5
 process_coarse_timers(struct context *c)
6fbf66fa
 {
81d882d5
     /* flush current packet-id to file once per 60
      * seconds if --replay-persist was specified */
     check_packet_id_persist_flush(c);
6fbf66fa
 
81d882d5
     /* should we update status file? */
     check_status_file(c);
6fbf66fa
 
81d882d5
     /* process connection establishment items */
     check_connection_established(c);
6fbf66fa
 
 #if P2MP
81d882d5
     /* see if we should send a push_request in response to --pull */
     check_push_request(c);
6fbf66fa
 #endif
 
90efcacb
 #ifdef PLUGIN_PF
81d882d5
     pf_check_reload(c);
47ae8457
 #endif
 
81d882d5
     /* process --route options */
     check_add_routes(c);
6fbf66fa
 
81d882d5
     /* possibly exit due to --inactive */
     check_inactivity_timeout(c);
     if (c->sig->signal_received)
     {
         return;
     }
6fbf66fa
 
81d882d5
     /* restart if ping not received */
     check_ping_restart(c);
     if (c->sig->signal_received)
     {
         return;
     }
6fbf66fa
 
 #if P2MP
81d882d5
     if (c->c2.tls_multi)
f2134b7b
     {
81d882d5
         check_server_poll_timeout(c);
         if (c->sig->signal_received)
         {
             return;
         }
 
         check_scheduled_exit(c);
         if (c->sig->signal_received)
         {
             return;
         }
f2134b7b
     }
6fbf66fa
 #endif
 
 #ifdef ENABLE_OCC
81d882d5
     /* Should we send an OCC_REQUEST message? */
     check_send_occ_req(c);
6fbf66fa
 
81d882d5
     /* Should we send an MTU load test? */
     check_send_occ_load_test(c);
6fbf66fa
 
81d882d5
     /* Should we send an OCC_EXIT message to remote? */
     if (c->c2.explicit_exit_notification_time_wait)
     {
         process_explicit_exit_notification_timer_wakeup(c);
     }
6fbf66fa
 #endif
 
81d882d5
     /* Should we ping the remote? */
     check_ping_send(c);
6fbf66fa
 }
 
 static void
81d882d5
 check_coarse_timers_dowork(struct context *c)
6fbf66fa
 {
81d882d5
     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;
6fbf66fa
 
31b5c0e9
     dmsg(D_INTERVAL, "TIMER: coarse timer wakeup %lld seconds", (long long)c->c2.timeval.tv_sec);
6fbf66fa
 
81d882d5
     /* Is the coarse timeout NOT the earliest one? */
     if (c->c2.timeval.tv_sec > save.tv_sec)
     {
         c->c2.timeval = save;
     }
6fbf66fa
 }
 
 static inline void
81d882d5
 check_coarse_timers(struct context *c)
6fbf66fa
 {
81d882d5
     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);
     }
6fbf66fa
 }
 
 static void
81d882d5
 check_timeout_random_component_dowork(struct context *c)
6fbf66fa
 {
81d882d5
     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() & 0x0003FFFF;
     c->c2.timeout_random_component.tv_sec = 0;
6fbf66fa
 
10f12d2a
     dmsg(D_INTERVAL, "RANDOM USEC=%ld", (long) c->c2.timeout_random_component.tv_usec);
6fbf66fa
 }
 
 static inline void
81d882d5
 check_timeout_random_component(struct context *c)
6fbf66fa
 {
81d882d5
     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);
     }
6fbf66fa
 }
 
 /*
  * Handle addition and removal of the 10-byte Socks5 header
  * in UDP packets.
  */
 
 static inline void
81d882d5
 socks_postprocess_incoming_link(struct context *c)
6fbf66fa
 {
81d882d5
     if (c->c2.link_socket->socks_proxy && c->c2.link_socket->info.proto == PROTO_UDP)
     {
         socks_process_incoming_udp(&c->c2.buf, &c->c2.from);
     }
6fbf66fa
 }
 
 static inline void
81d882d5
 socks_preprocess_outgoing_link(struct context *c,
                                struct link_socket_actual **to_addr,
                                int *size_delta)
6fbf66fa
 {
81d882d5
     if (c->c2.link_socket->socks_proxy && c->c2.link_socket->info.proto == PROTO_UDP)
6fbf66fa
     {
81d882d5
         *size_delta += socks_process_outgoing_udp(&c->c2.to_link, c->c2.to_link_addr);
         *to_addr = &c->c2.link_socket->socks_relay;
6fbf66fa
     }
 }
 
 /* undo effect of socks_preprocess_outgoing_link */
 static inline void
81d882d5
 link_socket_write_post_size_adjust(int *size,
                                    int size_delta,
                                    struct buffer *buf)
6fbf66fa
 {
81d882d5
     if (size_delta > 0 && *size > size_delta)
6fbf66fa
     {
81d882d5
         *size -= size_delta;
         if (!buf_advance(buf, size_delta))
         {
             *size = 0;
         }
6fbf66fa
     }
 }
 
 /*
  * Output: c->c2.buf
  */
 
 void
81d882d5
 read_incoming_link(struct context *c)
6fbf66fa
 {
81d882d5
     /*
      * Set up for recvfrom call to read datagram
      * sent to our TCP/UDP port.
      */
     int status;
6fbf66fa
 
81d882d5
     /*ASSERT (!c->c2.to_tun.len);*/
6fbf66fa
 
81d882d5
     perf_push(PERF_READ_IN_LINK);
6fbf66fa
 
81d882d5
     c->c2.buf = c->c2.buffers->read_link_buf;
     ASSERT(buf_init(&c->c2.buf, FRAME_HEADROOM_ADJ(&c->c2.frame, FRAME_HEADROOM_MARKER_READ_LINK)));
3c7f2f55
 
81d882d5
     status = link_socket_read(c->c2.link_socket,
                               &c->c2.buf,
                               &c->c2.from);
6fbf66fa
 
81d882d5
     if (socket_connection_reset(c->c2.link_socket, status))
6fbf66fa
     {
6add6b2f
 #if PORT_SHARE
81d882d5
         if (port_share && socket_foreign_protocol_detected(c->c2.link_socket))
         {
             const struct buffer *fbuf = socket_foreign_protocol_head(c->c2.link_socket);
             const int sd = socket_foreign_protocol_sd(c->c2.link_socket);
             port_share_redirect(port_share, fbuf, sd);
             register_signal(c, SIGTERM, "port-share-redirect");
         }
         else
6add6b2f
 #endif
81d882d5
         {
             /* received a disconnect from a connection-oriented protocol */
             if (c->options.inetd)
             {
                 register_signal(c, SIGTERM, "connection-reset-inetd");
                 msg(D_STREAM_ERRORS, "Connection reset, inetd/xinetd exit [%d]", status);
             }
             else
             {
3cf6c932
 #ifdef ENABLE_OCC
81d882d5
                 if (event_timeout_defined(&c->c2.explicit_exit_notification_interval))
                 {
                     msg(D_STREAM_ERRORS, "Connection reset during exit notification period, ignoring [%d]", status);
45b2af9c
                     management_sleep(1);
81d882d5
                 }
                 else
3cf6c932
 #endif
81d882d5
                 {
                     register_signal(c, SIGUSR1, "connection-reset"); /* SOFT-SIGUSR1 -- TCP connection reset */
                     msg(D_STREAM_ERRORS, "Connection reset, restarting [%d]", status);
                 }
             }
         }
         perf_pop();
         return;
6fbf66fa
     }
 
81d882d5
     /* check recvfrom status */
     check_status(status, "read", c->c2.link_socket, NULL);
6fbf66fa
 
81d882d5
     /* Remove socks header if applicable */
     socks_postprocess_incoming_link(c);
6fbf66fa
 
81d882d5
     perf_pop();
6fbf66fa
 }
 
65eedc35
 bool
81d882d5
 process_incoming_link_part1(struct context *c, struct link_socket_info *lsi, bool floated)
6fbf66fa
 {
81d882d5
     struct gc_arena gc = gc_new();
     bool decrypt_status = false;
6fbf66fa
 
81d882d5
     if (c->c2.buf.len > 0)
6fbf66fa
     {
81d882d5
         c->c2.link_read_bytes += c->c2.buf.len;
         link_read_bytes_global += c->c2.buf.len;
ffea644c
 #ifdef ENABLE_MEMSTATS
81d882d5
         if (mmap_stats)
         {
             mmap_stats->link_read_bytes = link_read_bytes_global;
         }
ffea644c
 #endif
81d882d5
         c->c2.original_recv_size = c->c2.buf.len;
34a507c9
 #ifdef ENABLE_MANAGEMENT
81d882d5
         if (management)
         {
             management_bytes_in(management, c->c2.buf.len);
5f435d64
 #ifdef MANAGEMENT_DEF_AUTH
81d882d5
             management_bytes_server(management, &c->c2.link_read_bytes, &c->c2.link_write_bytes, &c->c2.mda_context);
5f435d64
 #endif
81d882d5
         }
34a507c9
 #endif
6fbf66fa
     }
81d882d5
     else
     {
         c->c2.original_recv_size = 0;
     }
 
6fbf66fa
 #ifdef ENABLE_DEBUG
81d882d5
     /* take action to corrupt packet if we are in gremlin test mode */
     if (c->options.gremlin)
     {
         if (!ask_gremlin(c->options.gremlin))
         {
             c->c2.buf.len = 0;
         }
         corrupt_gremlin(&c->c2.buf, c->options.gremlin);
     }
6fbf66fa
 #endif
 
81d882d5
     /* log incoming packet */
6fbf66fa
 #ifdef LOG_RW
81d882d5
     if (c->c2.log_rw && c->c2.buf.len > 0)
     {
         fprintf(stderr, "R");
     }
6fbf66fa
 #endif
81d882d5
     msg(D_LINK_RW, "%s READ [%d] from %s: %s",
         proto2ascii(lsi->proto, lsi->af, true),
         BLEN(&c->c2.buf),
         print_link_socket_actual(&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)
     {
         struct crypto_options *co = NULL;
         const uint8_t *ad_start = NULL;
         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);
         }
6fbf66fa
 
81d882d5
         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.
              */
9900e023
             uint8_t opcode = *BPTR(&c->c2.buf) >> P_OPCODE_SHIFT;
81d882d5
             if (tls_pre_decrypt(c->c2.tls_multi, &c->c2.from, &c->c2.buf, &co,
                                 floated, &ad_start))
             {
9900e023
                 /* Restore pre-NCP frame parameters */
                 if (is_hard_reset(opcode, c->options.key_method))
                 {
                     c->c2.frame = c->c2.frame_initial;
                 }
 
81d882d5
                 interval_action(&c->c2.tmp_int);
 
                 /* reset packet received timer if TLS packet */
                 if (c->options.ping_rec_timeout)
                 {
                     event_timeout_reset(&c->c2.ping_rec_interval);
                 }
             }
         }
         else
         {
             co = &c->c2.crypto_options;
         }
6fbf66fa
 #if P2MP_SERVER
81d882d5
         /*
          * Drop non-TLS packet if client-connect script/plugin has not
          * yet succeeded.
          */
         if (c->c2.context_auth != CAS_SUCCEEDED)
         {
             c->c2.buf.len = 0;
         }
6fbf66fa
 #endif
 
81d882d5
         /* authenticate and decrypt the incoming packet */
         decrypt_status = openvpn_decrypt(&c->c2.buf, c->c2.buffers->decrypt_buf,
                                          co, &c->c2.frame, ad_start);
6fbf66fa
 
81d882d5
         if (!decrypt_status && link_socket_connection_oriented(c->c2.link_socket))
         {
             /* decryption errors are fatal in TCP mode */
             register_signal(c, SIGUSR1, "decryption-error"); /* SOFT-SIGUSR1 -- decryption error in TCP mode */
             msg(D_STREAM_ERRORS, "Fatal decryption error (process_incoming_link), restarting");
         }
65eedc35
     }
81d882d5
     else
65eedc35
     {
81d882d5
         buf_reset(&c->c2.to_tun);
65eedc35
     }
81d882d5
     gc_free(&gc);
6fbf66fa
 
81d882d5
     return decrypt_status;
65eedc35
 }
 
 void
81d882d5
 process_incoming_link_part2(struct context *c, struct link_socket_info *lsi, const uint8_t *orig_buf)
65eedc35
 {
81d882d5
     if (c->c2.buf.len > 0)
65eedc35
     {
6fbf66fa
 #ifdef ENABLE_FRAGMENT
81d882d5
         if (c->c2.fragment)
         {
             fragment_incoming(c->c2.fragment, &c->c2.buf, &c->c2.frame_fragment);
         }
6fbf66fa
 #endif
 
38d96bd7
 #ifdef USE_COMP
81d882d5
         /* decompress the incoming packet */
         if (c->c2.comp_context)
         {
             (*c->c2.comp_context->alg.decompress)(&c->c2.buf, c->c2.buffers->decompress_buf, c->c2.comp_context, &c->c2.frame);
         }
6fbf66fa
 #endif
3c7f2f55
 
 #ifdef PACKET_TRUNCATION_CHECK
81d882d5
         /* if (c->c2.buf.len > 1) --c->c2.buf.len; */
         ipv4_packet_size_verify(BPTR(&c->c2.buf),
                                 BLEN(&c->c2.buf),
                                 TUNNEL_TYPE(c->c1.tuntap),
                                 "POST_DECRYPT",
                                 &c->c2.n_trunc_post_decrypt);
3c7f2f55
 #endif
 
81d882d5
         /*
          * Set our "official" outgoing address, since
          * if buf.len is non-zero, we know the packet
          * authenticated.  In TLS mode we do nothing
          * because TLS mode takes care of source address
          * authentication.
          *
          * Also, update the persisted version of our packet-id.
          */
         if (!TLS_MODE(c))
         {
             link_socket_set_outgoing_addr(&c->c2.buf, lsi, &c->c2.from, NULL, c->c2.es);
         }
 
         /* reset packet received timer */
         if (c->options.ping_rec_timeout && c->c2.buf.len > 0)
         {
             event_timeout_reset(&c->c2.ping_rec_interval);
         }
 
         /* increment authenticated receive byte count */
         if (c->c2.buf.len > 0)
         {
             c->c2.link_read_bytes_auth += c->c2.buf.len;
             c->c2.max_recv_size_local = max_int(c->c2.original_recv_size, c->c2.max_recv_size_local);
         }
 
         /* Did we just receive an openvpn ping packet? */
         if (is_ping_msg(&c->c2.buf))
         {
             dmsg(D_PING, "RECEIVED PING PACKET");
             c->c2.buf.len = 0; /* drop packet */
         }
6fbf66fa
 
 #ifdef ENABLE_OCC
81d882d5
         /* Did we just receive an OCC packet? */
         if (is_occ_msg(&c->c2.buf))
         {
             process_received_occ_msg(c);
         }
6fbf66fa
 #endif
 
81d882d5
         buffer_turnover(orig_buf, &c->c2.to_tun, &c->c2.buf, &c->c2.buffers->read_link_buf);
6fbf66fa
 
81d882d5
         /* to_tun defined + unopened tuntap can cause deadlock */
         if (!tuntap_defined(c->c1.tuntap))
         {
             c->c2.to_tun.len = 0;
         }
6fbf66fa
     }
81d882d5
     else
6fbf66fa
     {
81d882d5
         buf_reset(&c->c2.to_tun);
6fbf66fa
     }
65eedc35
 }
 
72bcdfdc
 static void
81d882d5
 process_incoming_link(struct context *c)
65eedc35
 {
81d882d5
     perf_push(PERF_PROC_IN_LINK);
65eedc35
 
81d882d5
     struct link_socket_info *lsi = get_link_socket_info(c);
     const uint8_t *orig_buf = c->c2.buf.data;
65eedc35
 
81d882d5
     process_incoming_link_part1(c, lsi, false);
     process_incoming_link_part2(c, lsi, orig_buf);
65eedc35
 
81d882d5
     perf_pop();
6fbf66fa
 }
 
 /*
  * Output: c->c2.buf
  */
 
 void
81d882d5
 read_incoming_tun(struct context *c)
6fbf66fa
 {
81d882d5
     /*
      * Setup for read() call on TUN/TAP device.
      */
     /*ASSERT (!c->c2.to_link.len);*/
ba3ff466
 
81d882d5
     perf_push(PERF_READ_IN_TUN);
6fbf66fa
 
81d882d5
     c->c2.buf = c->c2.buffers->read_tun_buf;
6fbf66fa
 #ifdef TUN_PASS_BUFFER
81d882d5
     read_tun_buffered(c->c1.tuntap, &c->c2.buf, MAX_RW_SIZE_TUN(&c->c2.frame));
6fbf66fa
 #else
81d882d5
     ASSERT(buf_init(&c->c2.buf, FRAME_HEADROOM(&c->c2.frame)));
     ASSERT(buf_safe(&c->c2.buf, MAX_RW_SIZE_TUN(&c->c2.frame)));
     c->c2.buf.len = read_tun(c->c1.tuntap, BPTR(&c->c2.buf), MAX_RW_SIZE_TUN(&c->c2.frame));
6fbf66fa
 #endif
 
3c7f2f55
 #ifdef PACKET_TRUNCATION_CHECK
81d882d5
     ipv4_packet_size_verify(BPTR(&c->c2.buf),
                             BLEN(&c->c2.buf),
                             TUNNEL_TYPE(c->c1.tuntap),
                             "READ_TUN",
                             &c->c2.n_trunc_tun_read);
3c7f2f55
 #endif
 
81d882d5
     /* Was TUN/TAP interface stopped? */
     if (tuntap_stop(c->c2.buf.len))
6fbf66fa
     {
81d882d5
         register_signal(c, SIGTERM, "tun-stop");
         msg(M_INFO, "TUN/TAP interface has been stopped, exiting");
         perf_pop();
         return;
6fbf66fa
     }
 
81d882d5
     /* Was TUN/TAP I/O operation aborted? */
     if (tuntap_abort(c->c2.buf.len))
     {
         register_signal(c, SIGHUP, "tun-abort");
         c->persist.restart_sleep_seconds = 10;
         msg(M_INFO, "TUN/TAP I/O operation aborted, restarting");
         perf_pop();
         return;
     }
7aa17838
 
81d882d5
     /* Check the status return from read() */
     check_status(c->c2.buf.len, "read from TUN/TAP", NULL, c->c1.tuntap);
6fbf66fa
 
81d882d5
     perf_pop();
6fbf66fa
 }
 
e8c42658
 /**
  * Drops UDP packets which OS decided to route via tun.
  *
  * On Windows and OS X when netwotk adapter is disabled or
  * disconnected, platform starts to use tun as external interface.
  * When packet is sent to tun, it comes to openvpn, encapsulated
  * and sent to routing table, which sends it again to tun.
  */
 static void
81d882d5
 drop_if_recursive_routing(struct context *c, struct buffer *buf)
e8c42658
 {
81d882d5
     bool drop = false;
     struct openvpn_sockaddr tun_sa;
     int ip_hdr_offset = 0;
e8c42658
 
81d882d5
     if (c->c2.to_link_addr == NULL) /* no remote addr known */
e8c42658
     {
81d882d5
         return;
     }
e8c42658
 
81d882d5
     tun_sa = c->c2.to_link_addr->dest;
e8c42658
 
81d882d5
     int proto_ver = get_tun_ip_ver(TUNNEL_TYPE(c->c1.tuntap), &c->c2.buf, &ip_hdr_offset);
e8c42658
 
81d882d5
     if (proto_ver == 4)
     {
         const struct openvpn_iphdr *pip;
 
         /* make sure we got whole IP header */
         if (BLEN(buf) < ((int) sizeof(struct openvpn_iphdr) + ip_hdr_offset))
         {
             return;
         }
 
         /* skip ipv4 packets for ipv6 tun */
         if (tun_sa.addr.sa.sa_family != AF_INET)
         {
             return;
         }
 
         pip = (struct openvpn_iphdr *) (BPTR(buf) + ip_hdr_offset);
 
         /* drop packets with same dest addr as gateway */
         if (tun_sa.addr.in4.sin_addr.s_addr == pip->daddr)
         {
             drop = true;
         }
e8c42658
     }
81d882d5
     else if (proto_ver == 6)
e8c42658
     {
81d882d5
         const struct openvpn_ipv6hdr *pip6;
 
         /* make sure we got whole IPv6 header */
         if (BLEN(buf) < ((int) sizeof(struct openvpn_ipv6hdr) + ip_hdr_offset))
         {
             return;
         }
 
         /* skip ipv6 packets for ipv4 tun */
         if (tun_sa.addr.sa.sa_family != AF_INET6)
         {
             return;
         }
 
         /* drop packets with same dest addr as gateway */
         pip6 = (struct openvpn_ipv6hdr *) (BPTR(buf) + ip_hdr_offset);
         if (IN6_ARE_ADDR_EQUAL(&tun_sa.addr.in6.sin6_addr, &pip6->daddr))
         {
             drop = true;
         }
e8c42658
     }
 
81d882d5
     if (drop)
e8c42658
     {
81d882d5
         struct gc_arena gc = gc_new();
e8c42658
 
81d882d5
         c->c2.buf.len = 0;
e8c42658
 
81d882d5
         msg(D_LOW, "Recursive routing detected, drop tun packet to %s",
             print_link_socket_actual(c->c2.to_link_addr, &gc));
         gc_free(&gc);
e8c42658
     }
 }
 
6fbf66fa
 /*
  * Input:  c->c2.buf
  * Output: c->c2.to_link
  */
 
 void
81d882d5
 process_incoming_tun(struct context *c)
6fbf66fa
 {
81d882d5
     struct gc_arena gc = gc_new();
6fbf66fa
 
81d882d5
     perf_push(PERF_PROC_IN_TUN);
6fbf66fa
 
81d882d5
     if (c->c2.buf.len > 0)
     {
         c->c2.tun_read_bytes += c->c2.buf.len;
     }
6fbf66fa
 
 #ifdef LOG_RW
81d882d5
     if (c->c2.log_rw && c->c2.buf.len > 0)
     {
         fprintf(stderr, "r");
     }
6fbf66fa
 #endif
 
81d882d5
     /* Show packet content */
     dmsg(D_TUN_RW, "TUN READ [%d]", BLEN(&c->c2.buf));
6fbf66fa
 
81d882d5
     if (c->c2.buf.len > 0)
6fbf66fa
     {
81d882d5
         if ((c->options.mode == MODE_POINT_TO_POINT) && (!c->options.allow_recursive_routing))
         {
             drop_if_recursive_routing(c, &c->c2.buf);
         }
         /*
          * The --passtos and --mssfix options require
          * us to examine the IP header (IPv4 or IPv6).
          */
         process_ip_header(c, PIPV4_PASSTOS|PIP_MSSFIX|PIPV4_CLIENT_NAT, &c->c2.buf);
3c7f2f55
 
 #ifdef PACKET_TRUNCATION_CHECK
81d882d5
         /* if (c->c2.buf.len > 1) --c->c2.buf.len; */
         ipv4_packet_size_verify(BPTR(&c->c2.buf),
                                 BLEN(&c->c2.buf),
                                 TUNNEL_TYPE(c->c1.tuntap),
                                 "PRE_ENCRYPT",
                                 &c->c2.n_trunc_pre_encrypt);
3c7f2f55
 #endif
 
81d882d5
         encrypt_sign(c, true);
6fbf66fa
     }
81d882d5
     else
6fbf66fa
     {
81d882d5
         buf_reset(&c->c2.to_link);
6fbf66fa
     }
81d882d5
     perf_pop();
     gc_free(&gc);
6fbf66fa
 }
 
 void
81d882d5
 process_ip_header(struct context *c, unsigned int flags, struct buffer *buf)
6fbf66fa
 {
81d882d5
     if (!c->options.ce.mssfix)
     {
         flags &= ~PIP_MSSFIX;
     }
6fbf66fa
 #if PASSTOS_CAPABILITY
81d882d5
     if (!c->options.passtos)
     {
         flags &= ~PIPV4_PASSTOS;
     }
6fbf66fa
 #endif
81d882d5
     if (!c->options.client_nat)
     {
         flags &= ~PIPV4_CLIENT_NAT;
     }
     if (!c->options.route_gateway_via_dhcp)
     {
         flags &= ~PIPV4_EXTRACT_DHCP_ROUTER;
     }
6fbf66fa
 
81d882d5
     if (buf->len > 0)
6fbf66fa
     {
81d882d5
         /*
          * The --passtos and --mssfix options require
          * us to examine the IPv4 header.
          */
8db23a57
 
81d882d5
         if (flags & (PIP_MSSFIX
6fbf66fa
 #if PASSTOS_CAPABILITY
81d882d5
                      | PIPV4_PASSTOS
6fbf66fa
 #endif
81d882d5
                      | PIPV4_CLIENT_NAT
                      ))
         {
             struct buffer ipbuf = *buf;
             if (is_ipv4(TUNNEL_TYPE(c->c1.tuntap), &ipbuf))
             {
6fbf66fa
 #if PASSTOS_CAPABILITY
81d882d5
                 /* extract TOS from IP header */
                 if (flags & PIPV4_PASSTOS)
                 {
                     link_socket_extract_tos(c->c2.link_socket, &ipbuf);
                 }
6fbf66fa
 #endif
81d882d5
 
                 /* possibly alter the TCP MSS */
                 if (flags & PIP_MSSFIX)
                 {
                     mss_fixup_ipv4(&ipbuf, MTU_TO_MSS(TUN_MTU_SIZE_DYNAMIC(&c->c2.frame)));
                 }
 
                 /* possibly do NAT on packet */
                 if ((flags & PIPV4_CLIENT_NAT) && c->options.client_nat)
                 {
                     const int direction = (flags & PIPV4_OUTGOING) ? CN_INCOMING : CN_OUTGOING;
                     client_nat_transform(c->options.client_nat, &ipbuf, direction);
                 }
                 /* possibly extract a DHCP router message */
                 if (flags & PIPV4_EXTRACT_DHCP_ROUTER)
                 {
                     const in_addr_t dhcp_router = dhcp_extract_router_msg(&ipbuf);
                     if (dhcp_router)
                     {
                         route_list_add_vpn_gateway(c->c1.route_list, c->c2.es, dhcp_router);
                     }
                 }
             }
             else if (is_ipv6(TUNNEL_TYPE(c->c1.tuntap), &ipbuf))
             {
                 /* possibly alter the TCP MSS */
                 if (flags & PIP_MSSFIX)
                 {
                     mss_fixup_ipv6(&ipbuf, MTU_TO_MSS(TUN_MTU_SIZE_DYNAMIC(&c->c2.frame)));
                 }
             }
         }
6fbf66fa
     }
 }
 
 /*
  * Input: c->c2.to_link
  */
 
 void
81d882d5
 process_outgoing_link(struct context *c)
6fbf66fa
 {
81d882d5
     struct gc_arena gc = gc_new();
     int error_code = 0;
6fbf66fa
 
81d882d5
     perf_push(PERF_PROC_OUT_LINK);
6fbf66fa
 
81d882d5
     if (c->c2.to_link.len > 0 && c->c2.to_link.len <= EXPANDED_SIZE(&c->c2.frame))
6fbf66fa
     {
81d882d5
         /*
          * Setup for call to send/sendto which will send
          * packet to remote over the TCP/UDP port.
          */
         int size = 0;
         ASSERT(link_socket_actual_defined(c->c2.to_link_addr));
6fbf66fa
 
 #ifdef ENABLE_DEBUG
81d882d5
         /* In gremlin-test mode, we may choose to drop this packet */
         if (!c->options.gremlin || ask_gremlin(c->options.gremlin))
6fbf66fa
 #endif
81d882d5
         {
             /*
              * Let the traffic shaper know how many bytes
              * we wrote.
              */
3d163bc5
 #ifdef ENABLE_FEATURE_SHAPER
81d882d5
             if (c->options.shaper)
             {
                 shaper_wrote_bytes(&c->c2.shaper, BLEN(&c->c2.to_link)
                                    + datagram_overhead(c->options.ce.proto));
             }
6fbf66fa
 #endif
81d882d5
             /*
              * Let the pinger know that we sent a packet.
              */
             if (c->options.ping_send_timeout)
             {
                 event_timeout_reset(&c->c2.ping_send_interval);
             }
6fbf66fa
 
 #if PASSTOS_CAPABILITY
81d882d5
             /* Set TOS */
             link_socket_set_tos(c->c2.link_socket);
6fbf66fa
 #endif
 
81d882d5
             /* Log packet send */
6fbf66fa
 #ifdef LOG_RW
81d882d5
             if (c->c2.log_rw)
             {
                 fprintf(stderr, "W");
             }
6fbf66fa
 #endif
81d882d5
             msg(D_LINK_RW, "%s WRITE [%d] to %s: %s",
                 proto2ascii(c->c2.link_socket->info.proto, c->c2.link_socket->info.af, true),
                 BLEN(&c->c2.to_link),
                 print_link_socket_actual(c->c2.to_link_addr, &gc),
                 PROTO_DUMP(&c->c2.to_link, &gc));
 
             /* Packet send complexified by possible Socks5 usage */
             {
                 struct link_socket_actual *to_addr = c->c2.to_link_addr;
                 int size_delta = 0;
 
                 /* If Socks5 over UDP, prepend header */
                 socks_preprocess_outgoing_link(c, &to_addr, &size_delta);
 
                 /* Send packet */
                 size = link_socket_write(c->c2.link_socket,
                                          &c->c2.to_link,
                                          to_addr);
 
                 /* Undo effect of prepend */
                 link_socket_write_post_size_adjust(&size, size_delta, &c->c2.to_link);
             }
 
             if (size > 0)
             {
                 c->c2.max_send_size_local = max_int(size, c->c2.max_send_size_local);
                 c->c2.link_write_bytes += size;
                 link_write_bytes_global += size;
ffea644c
 #ifdef ENABLE_MEMSTATS
81d882d5
                 if (mmap_stats)
                 {
                     mmap_stats->link_write_bytes = link_write_bytes_global;
                 }
ffea644c
 #endif
34a507c9
 #ifdef ENABLE_MANAGEMENT
81d882d5
                 if (management)
                 {
                     management_bytes_out(management, size);
5f435d64
 #ifdef MANAGEMENT_DEF_AUTH
81d882d5
                     management_bytes_server(management, &c->c2.link_read_bytes, &c->c2.link_write_bytes, &c->c2.mda_context);
5f435d64
 #endif
81d882d5
                 }
34a507c9
 #endif
81d882d5
             }
         }
 
         /* Check return status */
         error_code = openvpn_errno();
         check_status(size, "write", c->c2.link_socket, NULL);
 
         if (size > 0)
         {
             /* Did we write a different size packet than we intended? */
             if (size != BLEN(&c->c2.to_link))
             {
                 msg(D_LINK_ERRORS,
                     "TCP/UDP packet was truncated/expanded on write to %s (tried=%d,actual=%d)",
                     print_link_socket_actual(c->c2.to_link_addr, &gc),
                     BLEN(&c->c2.to_link),
                     size);
             }
         }
 
         /* if not a ping/control message, indicate activity regarding --inactive parameter */
         if (c->c2.buf.len > 0)
         {
             register_activity(c, size);
         }
99daa6b1
 
81d882d5
         /* for unreachable network and "connecting" state switch to the next host */
         if (size < 0 && ENETUNREACH == error_code && c->c2.tls_multi
             && !tls_initial_packet_received(c->c2.tls_multi) && c->options.mode == MODE_POINT_TO_POINT)
         {
             msg(M_INFO, "Network unreachable, restarting");
             register_signal(c, SIGUSR1, "network-unreachable");
         }
6fbf66fa
     }
81d882d5
     else
6fbf66fa
     {
81d882d5
         if (c->c2.to_link.len > 0)
         {
             msg(D_LINK_ERRORS, "TCP/UDP packet too large on write to %s (tried=%d,max=%d)",
                 print_link_socket_actual(c->c2.to_link_addr, &gc),
                 c->c2.to_link.len,
                 EXPANDED_SIZE(&c->c2.frame));
         }
6fbf66fa
     }
 
81d882d5
     buf_reset(&c->c2.to_link);
6fbf66fa
 
81d882d5
     perf_pop();
     gc_free(&gc);
6fbf66fa
 }
 
 /*
  * Input: c->c2.to_tun
  */
 
 void
81d882d5
 process_outgoing_tun(struct context *c)
6fbf66fa
 {
81d882d5
     struct gc_arena gc = gc_new();
6fbf66fa
 
81d882d5
     /*
      * Set up for write() call to TUN/TAP
      * device.
      */
     if (c->c2.to_tun.len <= 0)
     {
         return;
     }
ba3ff466
 
81d882d5
     perf_push(PERF_PROC_OUT_TUN);
6fbf66fa
 
81d882d5
     /*
      * The --mssfix option requires
      * us to examine the IP header (IPv4 or IPv6).
      */
     process_ip_header(c, PIP_MSSFIX|PIPV4_EXTRACT_DHCP_ROUTER|PIPV4_CLIENT_NAT|PIPV4_OUTGOING, &c->c2.to_tun);
6fbf66fa
 
81d882d5
     if (c->c2.to_tun.len <= MAX_RW_SIZE_TUN(&c->c2.frame))
6fbf66fa
     {
81d882d5
         /*
          * Write to TUN/TAP device.
          */
         int size;
6fbf66fa
 
 #ifdef LOG_RW
81d882d5
         if (c->c2.log_rw)
         {
             fprintf(stderr, "w");
         }
6fbf66fa
 #endif
81d882d5
         dmsg(D_TUN_RW, "TUN WRITE [%d]", BLEN(&c->c2.to_tun));
6fbf66fa
 
3c7f2f55
 #ifdef PACKET_TRUNCATION_CHECK
81d882d5
         ipv4_packet_size_verify(BPTR(&c->c2.to_tun),
                                 BLEN(&c->c2.to_tun),
                                 TUNNEL_TYPE(c->c1.tuntap),
                                 "WRITE_TUN",
                                 &c->c2.n_trunc_tun_write);
3c7f2f55
 #endif
 
6fbf66fa
 #ifdef TUN_PASS_BUFFER
81d882d5
         size = write_tun_buffered(c->c1.tuntap, &c->c2.to_tun);
6fbf66fa
 #else
81d882d5
         size = write_tun(c->c1.tuntap, BPTR(&c->c2.to_tun), BLEN(&c->c2.to_tun));
6fbf66fa
 #endif
 
81d882d5
         if (size > 0)
         {
             c->c2.tun_write_bytes += size;
         }
         check_status(size, "write to TUN/TAP", NULL, c->c1.tuntap);
 
         /* check written packet size */
         if (size > 0)
         {
             /* Did we write a different size packet than we intended? */
             if (size != BLEN(&c->c2.to_tun))
             {
                 msg(D_LINK_ERRORS,
                     "TUN/TAP packet was destructively fragmented on write to %s (tried=%d,actual=%d)",
                     c->c1.tuntap->actual_name,
                     BLEN(&c->c2.to_tun),
                     size);
             }
 
             /* indicate activity regarding --inactive parameter */
             register_activity(c, size);
         }
6fbf66fa
     }
81d882d5
     else
6fbf66fa
     {
81d882d5
         /*
          * This should never happen, probably indicates some kind
          * of MTU mismatch.
          */
         msg(D_LINK_ERRORS, "tun packet too large on write (tried=%d,max=%d)",
             c->c2.to_tun.len,
             MAX_RW_SIZE_TUN(&c->c2.frame));
6fbf66fa
     }
 
81d882d5
     buf_reset(&c->c2.to_tun);
6fbf66fa
 
81d882d5
     perf_pop();
     gc_free(&gc);
6fbf66fa
 }
 
 void
81d882d5
 pre_select(struct context *c)
6fbf66fa
 {
81d882d5
     /* make sure current time (now) is updated on function entry */
6fbf66fa
 
81d882d5
     /*
      * Start with an effectively infinite timeout, then let it
      * reduce to a timeout that reflects the component which
      * needs the earliest service.
      */
     c->c2.timeval.tv_sec = BIG_TIMEOUT;
     c->c2.timeval.tv_usec = 0;
6fbf66fa
 
445b192a
 #if defined(_WIN32)
81d882d5
     if (check_debug_level(D_TAP_WIN_DEBUG))
6fbf66fa
     {
81d882d5
         c->c2.timeval.tv_sec = 1;
         if (tuntap_defined(c->c1.tuntap))
         {
             tun_show_debug(c->c1.tuntap);
         }
6fbf66fa
     }
 #endif
 
81d882d5
     /* check coarse timers? */
     check_coarse_timers(c);
     if (c->sig->signal_received)
     {
         return;
     }
6fbf66fa
 
81d882d5
     /* Does TLS need service? */
     check_tls(c);
6fbf66fa
 
81d882d5
     /* In certain cases, TLS errors will require a restart */
     check_tls_errors(c);
     if (c->sig->signal_received)
     {
         return;
     }
6fbf66fa
 
81d882d5
     /* check for incoming configuration info on the control channel */
     check_incoming_control_channel(c);
6fbf66fa
 
 #ifdef ENABLE_OCC
81d882d5
     /* Should we send an OCC message? */
     check_send_occ_msg(c);
6fbf66fa
 #endif
 
 #ifdef ENABLE_FRAGMENT
81d882d5
     /* Should we deliver a datagram fragment to remote? */
     check_fragment(c);
6fbf66fa
 #endif
 
81d882d5
     /* Update random component of timeout */
     check_timeout_random_component(c);
6fbf66fa
 }
 
 /*
  * Wait for I/O events.  Used for both TCP & UDP sockets
  * in point-to-point mode and for UDP sockets in
  * point-to-multipoint mode.
  */
 
 void
81d882d5
 io_wait_dowork(struct context *c, const unsigned int flags)
6fbf66fa
 {
81d882d5
     unsigned int socket = 0;
     unsigned int tuntap = 0;
     struct event_set_return esr[4];
 
     /* These shifts all depend on EVENT_READ and EVENT_WRITE */
     static int socket_shift = 0;   /* depends on SOCKET_READ and SOCKET_WRITE */
     static int tun_shift = 2;      /* depends on TUN_READ and TUN_WRITE */
     static int err_shift = 4;      /* depends on ES_ERROR */
6fbf66fa
 #ifdef ENABLE_MANAGEMENT
81d882d5
     static int management_shift = 6; /* depends on MANAGEMENT_READ and MANAGEMENT_WRITE */
6fbf66fa
 #endif
0d1a75bf
 #ifdef ENABLE_ASYNC_PUSH
81d882d5
     static int file_shift = 8;     /* listening inotify events */
0d1a75bf
 #endif
6fbf66fa
 
81d882d5
     /*
      * Decide what kind of events we want to wait for.
      */
     event_reset(c->c2.event_set);
 
     /*
      * On win32 we use the keyboard or an event object as a source
      * of asynchronous signals.
      */
     if (flags & IOW_WAIT_SIGNAL)
     {
         wait_signal(c->c2.event_set, (void *)&err_shift);
     }
 
     /*
      * If outgoing data (for TCP/UDP port) pending, wait for ready-to-send
      * status from TCP/UDP port. Otherwise, wait for incoming data on
      * TUN/TAP device.
      */
     if (flags & IOW_TO_LINK)
     {
         if (flags & IOW_SHAPER)
         {
             /*
              * If sending this packet would put us over our traffic shaping
              * quota, don't send -- instead compute the delay we must wait
              * until it will be OK to send the packet.
              */
3d163bc5
 #ifdef ENABLE_FEATURE_SHAPER
81d882d5
             int delay = 0;
 
             /* set traffic shaping delay in microseconds */
             if (c->options.shaper)
             {
                 delay = max_int(delay, shaper_delay(&c->c2.shaper));
             }
 
             if (delay < 1000)
             {
                 socket |= EVENT_WRITE;
             }
             else
             {
                 shaper_soonest_event(&c->c2.timeval, delay);
             }
3d163bc5
 #else /* ENABLE_FEATURE_SHAPER */
81d882d5
             socket |= EVENT_WRITE;
3d163bc5
 #endif /* ENABLE_FEATURE_SHAPER */
81d882d5
         }
         else
         {
             socket |= EVENT_WRITE;
         }
6fbf66fa
     }
81d882d5
     else if (!((flags & IOW_FRAG) && TO_LINK_FRAG(c)))
6fbf66fa
     {
81d882d5
         if (flags & IOW_READ_TUN)
         {
             tuntap |= EVENT_READ;
         }
6fbf66fa
     }
 
81d882d5
     /*
      * If outgoing data (for TUN/TAP device) pending, wait for ready-to-send status
      * from device.  Otherwise, wait for incoming data on TCP/UDP port.
      */
     if (flags & IOW_TO_TUN)
6fbf66fa
     {
81d882d5
         tuntap |= EVENT_WRITE;
6fbf66fa
     }
81d882d5
     else
6fbf66fa
     {
81d882d5
         if (flags & IOW_READ_LINK)
         {
             socket |= EVENT_READ;
         }
6fbf66fa
     }
 
81d882d5
     /*
      * outgoing bcast buffer waiting to be sent?
      */
     if (flags & IOW_MBUF)
     {
         socket |= EVENT_WRITE;
     }
6fbf66fa
 
81d882d5
     /*
      * Force wait on TUN input, even if also waiting on TCP/UDP output
      */
     if (flags & IOW_READ_TUN_FORCE)
     {
         tuntap |= EVENT_READ;
     }
6fbf66fa
 
81d882d5
     /*
      * Configure event wait based on socket, tuntap flags.
      */
     socket_set(c->c2.link_socket, c->c2.event_set, socket, (void *)&socket_shift, NULL);
     tun_set(c->c1.tuntap, c->c2.event_set, tuntap, (void *)&tun_shift, NULL);
6fbf66fa
 
 #ifdef ENABLE_MANAGEMENT
81d882d5
     if (management)
     {
         management_socket_set(management, c->c2.event_set, (void *)&management_shift, NULL);
     }
6fbf66fa
 #endif
 
0d1a75bf
 #ifdef ENABLE_ASYNC_PUSH
81d882d5
     /* arm inotify watcher */
     if (c->options.mode == MODE_SERVER)
     {
         event_ctl(c->c2.event_set, c->c2.inotify_fd, EVENT_READ, (void *)&file_shift);
     }
0d1a75bf
 #endif
 
81d882d5
     /*
      * Possible scenarios:
      *  (1) tcp/udp port has data available to read
      *  (2) tcp/udp port is ready to accept more data to write
      *  (3) tun dev has data available to read
      *  (4) tun dev is ready to accept more data to write
      *  (5) we received a signal (handler sets signal_received)
      *  (6) timeout (tv) expired
      */
6fbf66fa
 
81d882d5
     c->c2.event_set_status = ES_ERROR;
6fbf66fa
 
81d882d5
     if (!c->sig->signal_received)
6fbf66fa
     {
81d882d5
         if (!(flags & IOW_CHECK_RESIDUAL) || !socket_read_residual(c->c2.link_socket))
         {
             int status;
6fbf66fa
 
 #ifdef ENABLE_DEBUG
81d882d5
             if (check_debug_level(D_EVENT_WAIT))
             {
                 show_wait_status(c);
             }
6fbf66fa
 #endif
 
81d882d5
             /*
              * Wait for something to happen.
              */
             status = event_wait(c->c2.event_set, &c->c2.timeval, esr, SIZE(esr));
 
             check_status(status, "event_wait", NULL, NULL);
 
             if (status > 0)
             {
                 int i;
                 c->c2.event_set_status = 0;
                 for (i = 0; i < status; ++i)
                 {
                     const struct event_set_return *e = &esr[i];
                     c->c2.event_set_status |= ((e->rwflags & 3) << *((int *)e->arg));
                 }
             }
             else if (status == 0)
             {
                 c->c2.event_set_status = ES_TIMEOUT;
             }
         }
         else
         {
             c->c2.event_set_status = SOCKET_READ;
         }
     }
 
     /* 'now' should always be a reasonably up-to-date timestamp */
     update_time();
 
     /* set signal_received if a signal was received */
     if (c->c2.event_set_status & ES_ERROR)
     {
         get_signal(&c->sig->signal_received);
     }
 
     dmsg(D_EVENT_WAIT, "I/O WAIT status=0x%04x", c->c2.event_set_status);
6fbf66fa
 }
 
 void
81d882d5
 process_io(struct context *c)
6fbf66fa
 {
81d882d5
     const unsigned int status = c->c2.event_set_status;
6fbf66fa
 
 #ifdef ENABLE_MANAGEMENT
81d882d5
     if (status & (MANAGEMENT_READ|MANAGEMENT_WRITE))
6fbf66fa
     {
81d882d5
         ASSERT(management);
         management_io(management);
6fbf66fa
     }
 #endif
 
81d882d5
     /* TCP/UDP port ready to accept write */
     if (status & SOCKET_WRITE)
6fbf66fa
     {
81d882d5
         process_outgoing_link(c);
6fbf66fa
     }
81d882d5
     /* TUN device ready to accept write */
     else if (status & TUN_WRITE)
6fbf66fa
     {
81d882d5
         process_outgoing_tun(c);
6fbf66fa
     }
81d882d5
     /* Incoming data on TCP/UDP port */
     else if (status & SOCKET_READ)
6fbf66fa
     {
81d882d5
         read_incoming_link(c);
         if (!IS_SIG(c))
         {
             process_incoming_link(c);
         }
6fbf66fa
     }
81d882d5
     /* Incoming data on TUN device */
     else if (status & TUN_READ)
6fbf66fa
     {
81d882d5
         read_incoming_tun(c);
         if (!IS_SIG(c))
         {
             process_incoming_tun(c);
         }
6fbf66fa
     }
 }