Пример #1
0
void
pf_init_context(struct context *c)
{
    struct gc_arena gc = gc_new();
#ifdef PLUGIN_PF
    if (plugin_defined(c->plugins, OPENVPN_PLUGIN_ENABLE_PF))
    {
        const char *pf_file = create_temp_file(c->options.tmp_dir, "pf", &gc);
        if (pf_file)
        {
            setenv_str(c->c2.es, "pf_file", pf_file);

            if (plugin_call(c->plugins, OPENVPN_PLUGIN_ENABLE_PF, NULL, NULL, c->c2.es) == OPENVPN_PLUGIN_FUNC_SUCCESS)
            {
                event_timeout_init(&c->c2.pf.reload, 1, now);
                c->c2.pf.filename = string_alloc(pf_file, &c->c2.gc);
                c->c2.pf.enabled = true;
#ifdef ENABLE_DEBUG
                if (check_debug_level(D_PF_DEBUG))
                {
                    pf_context_print(&c->c2.pf, "pf_init_context#1", D_PF_DEBUG);
                }
#endif
            }
            else
            {
                msg(M_WARN, "WARNING: OPENVPN_PLUGIN_ENABLE_PF disabled");
            }
        }
    }
#endif /* ifdef PLUGIN_PF */
#ifdef MANAGEMENT_PF
    if (!c->c2.pf.enabled && management_enable_pf(management))
    {
        c->c2.pf.enabled = true;
#ifdef ENABLE_DEBUG
        if (check_debug_level(D_PF_DEBUG))
        {
            pf_context_print(&c->c2.pf, "pf_init_context#2", D_PF_DEBUG);
        }
#endif
    }
#endif
    gc_free(&gc);
}
Пример #2
0
static void
plugin_show_args_env (int msglevel, const char *argv[], const char *envp[])
{
  if (check_debug_level (msglevel))
    {
      plugin_show_string_array (msglevel, "ARGV", argv);
      plugin_show_string_array (msglevel, "ENVP", envp);
    }
}
Пример #3
0
bool
pf_addr_test_dowork(const struct context *src, const struct mroute_addr *dest, const char *prefix)
{
    struct pf_set *pfs = src->c2.pf.pfs;
    if (pfs && !pfs->kill)
    {
        const in_addr_t addr = in_addr_t_from_mroute_addr(dest);
        const struct pf_subnet *se = pfs->sns.list;
        while (se)
        {
            if ((addr & se->rule.netmask) == se->rule.network)
            {
#ifdef ENABLE_DEBUG
                if (check_debug_level(D_PF_DEBUG))
                {
                    pf_addr_test_print("PF_ADDR_MATCH", prefix, src, dest, !se->rule.exclude, &se->rule);
                }
#endif
                return !se->rule.exclude;
            }
            se = se->next;
        }
#ifdef ENABLE_DEBUG
        if (check_debug_level(D_PF_DEBUG))
        {
            pf_addr_test_print("PF_ADDR_DEFAULT", prefix, src, dest, pfs->sns.default_allow, NULL);
        }
#endif
        return pfs->sns.default_allow;
    }
    else
    {
#ifdef ENABLE_DEBUG
        if (check_debug_level(D_PF_DEBUG))
        {
            pf_addr_test_print("PF_ADDR_FAULT", prefix, src, dest, false, NULL);
        }
#endif
        return false;
    }
}
Пример #4
0
void
pf_check_reload(struct context *c)
{
    const int slow_wakeup = 15;
    const int fast_wakeup = 1;
    const int wakeup_transition = 60;
    bool reloaded = false;

    if (c->c2.pf.enabled
        && c->c2.pf.filename
        && event_timeout_trigger(&c->c2.pf.reload, &c->c2.timeval, ETT_DEFAULT))
    {
        platform_stat_t s;
        if (!platform_stat(c->c2.pf.filename, &s))
        {
            if (s.st_mtime > c->c2.pf.file_last_mod)
            {
                struct pf_set *pfs = pf_init_from_file(c->c2.pf.filename);
                if (pfs)
                {
                    if (c->c2.pf.pfs)
                    {
                        pf_destroy(c->c2.pf.pfs);
                    }
                    c->c2.pf.pfs = pfs;
                    reloaded = true;
                    if (pf_kill_test(pfs))
                    {
                        c->sig->signal_received = SIGTERM;
                        c->sig->signal_text = "pf-kill";
                    }
                }
                c->c2.pf.file_last_mod = s.st_mtime;
            }
        }
        {
            int wakeup = slow_wakeup;
            if (!c->c2.pf.pfs && c->c2.pf.n_check_reload < wakeup_transition)
            {
                wakeup = fast_wakeup;
            }
            event_timeout_init(&c->c2.pf.reload, wakeup, now);
            reset_coarse_timers(c);
            c->c2.pf.n_check_reload++;
        }
    }
#ifdef ENABLE_DEBUG
    if (reloaded && check_debug_level(D_PF_DEBUG))
    {
        pf_context_print(&c->c2.pf, "pf_check_reload", D_PF_DEBUG);
    }
#endif
}
Пример #5
0
bool
pf_cn_test (struct pf_set *pfs, const struct tls_multi *tm, const int type, const char *prefix)
{
  if (!pfs->kill)
    {
      const char *cn;
      uint32_t cn_hash;
      if (tls_common_name_hash (tm, &cn, &cn_hash))
	{
	  const struct pf_cn *rule = lookup_cn_rule (pfs->cns.hash_table, cn, cn_hash);
	  if (rule)
	    {
#ifdef ENABLE_DEBUG
	      if (check_debug_level (D_PF_DEBUG))
		pf_cn_test_print ("PF_CN_MATCH", type, prefix, cn, !rule->exclude, rule);
#endif
	      if (!rule->exclude)
		return true;
	      else
		return false;
	    }
	  else
	    {
#ifdef ENABLE_DEBUG
	      if (check_debug_level (D_PF_DEBUG))
		pf_cn_test_print ("PF_CN_DEFAULT", type, prefix, cn, pfs->cns.default_allow, NULL);
#endif
	      if (pfs->cns.default_allow)
		return true;
	      else
		return false;
	    }
	}
    }
#ifdef ENABLE_DEBUG
  if (check_debug_level (D_PF_DEBUG))
    pf_cn_test_print ("PF_CN_FAULT", type, prefix, tls_common_name (tm, false), false, NULL);
#endif
  return false;
}
Пример #6
0
void
pre_select (struct context *c)
{
  /* make sure current time (now) is updated on function entry */

  /*
   * 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;

#if defined(WIN32)
  if (check_debug_level (D_TAP_WIN_DEBUG))
    {
      c->c2.timeval.tv_sec = 1;
      if (tuntap_defined (c->c1.tuntap))
	tun_show_debug (c->c1.tuntap);
    }
#endif

  /* check coarse timers? */
  check_coarse_timers (c);
  if (c->sig->signal_received)
    return;

  /* Does TLS need service? */
  check_tls (c);

  /* In certain cases, TLS errors will require a restart */
  check_tls_errors (c);
  if (c->sig->signal_received)
    return;

  /* check for incoming configuration info on the control channel */
  check_incoming_control_channel (c);

#ifdef ENABLE_OCC
  /* Should we send an OCC message? */
  check_send_occ_msg (c);
#endif

#ifdef ENABLE_FRAGMENT
  /* Should we deliver a datagram fragment to remote? */
  check_fragment (c);
#endif

  /* Update random component of timeout */
  check_timeout_random_component (c);
}
/*
 * Find the earliest event to be scheduled
 */
struct schedule_entry *
schedule_find_least (struct schedule_entry *e)
{
  if (e)
    {
      while (e->lt)
	{
#ifdef SCHEDULE_TEST
	  ++z.lsteps;
#endif
	  e = e->lt;
	}
    }
  
#ifdef ENABLE_DEBUG
  if (check_debug_level (D_SCHEDULER))
    schedule_entry_debug_info ("schedule_find_least", e);
#endif

  return e;
}
Пример #8
0
void
env_set_print (int msglevel, const struct env_set *es)
{
  if (check_debug_level (msglevel))
    {
      const struct env_item *e;
      int i;

      if (es)
	{
	  e = es->list;
	  i = 0;

	  while (e)
	    {
	      if (env_safe_to_print (e->string))
		msg (msglevel, "ENV [%d] '%s'", i, e->string);
	      ++i;
	      e = e->next;
	    }
	}
    }
}
Пример #9
0
void x_msg_va (const unsigned int flags, const char *format, va_list arglist)
{
  struct gc_arena gc;
#if SYSLOG_CAPABILITY
  int level;
#endif
  char *m1;
  char *m2;
  char *tmp;
  int e;
  const char *prefix;
  const char *prefix_sep;

  void usage_small (void);

#ifndef HAVE_VARARG_MACROS
  /* the macro has checked this otherwise */
  if (!MSG_TEST (flags))
    return;
#endif

  e = openvpn_errno ();

  /*
   * Apply muting filter.
   */
#ifndef HAVE_VARARG_MACROS
  /* the macro has checked this otherwise */
  if (!dont_mute (flags))
    return;
#endif

  gc_init (&gc);

  m1 = (char *) gc_malloc (ERR_BUF_SIZE, false, &gc);
  m2 = (char *) gc_malloc (ERR_BUF_SIZE, false, &gc);

  vsnprintf (m1, ERR_BUF_SIZE, format, arglist);
  m1[ERR_BUF_SIZE - 1] = 0; /* windows vsnprintf needs this */

  if ((flags & M_ERRNO) && e)
    {
      openvpn_snprintf (m2, ERR_BUF_SIZE, "%s: %s (errno=%d)",
			m1, strerror_ts (e, &gc), e);
      SWAP;
    }

#ifdef ENABLE_CRYPTO
#ifdef ENABLE_CRYPTO_OPENSSL
  if (flags & M_SSL)
    {
      int nerrs = 0;
      int err;
      while ((err = ERR_get_error ()))
	{
	  openvpn_snprintf (m2, ERR_BUF_SIZE, "%s: %s",
			    m1, ERR_error_string (err, NULL));
	  SWAP;
	  ++nerrs;
	}
      if (!nerrs)
	{
	  openvpn_snprintf (m2, ERR_BUF_SIZE, "%s (OpenSSL)", m1);
	  SWAP;
	}
    }
#endif
#endif

  if (flags & M_OPTERR)
    {
      openvpn_snprintf (m2, ERR_BUF_SIZE, "Options error: %s", m1);
      SWAP;
    }

#if SYSLOG_CAPABILITY
  if (flags & (M_FATAL|M_NONFATAL|M_USAGE_SMALL))
    level = LOG_ERR;
  else if (flags & M_WARN)
    level = LOG_WARNING;
  else
    level = LOG_NOTICE;
#endif

  /* set up client prefix */
  if (flags & M_NOIPREFIX)
    prefix = NULL;
  else
    prefix = msg_get_prefix ();
  prefix_sep = " ";
  if (!prefix)
    prefix_sep = prefix = "";

  /* virtual output capability used to copy output to management subsystem */
  if (!forked)
    {
      const struct virtual_output *vo = msg_get_virtual_output ();
      if (vo)
	{
	  openvpn_snprintf (m2, ERR_BUF_SIZE, "%s%s%s",
			    prefix,
			    prefix_sep,
			    m1);
	  virtual_output_print (vo, flags, m2);
	}
    }

  if (!(flags & M_MSG_VIRT_OUT))
    {
      if (use_syslog && !std_redir && !forked)
	{
#if SYSLOG_CAPABILITY
	  syslog (level, "%s%s%s",
		  prefix,
		  prefix_sep,
		  m1);
#endif
	}
      else
	{
	  FILE *fp = msg_fp(flags);
	  const bool show_usec = check_debug_level (DEBUG_LEVEL_USEC_TIME);

	  if ((flags & M_NOPREFIX) || suppress_timestamps)
	    {
	      fprintf (fp, "%s%s%s%s",
		       prefix,
		       prefix_sep,
		       m1,
		       (flags&M_NOLF) ? "" : "\n");
	    }
	  else
	    {
	      fprintf (fp, "%s %s%s%s%s",
		       time_string (0, 0, show_usec, &gc),
		       prefix,
		       prefix_sep,
		       m1,
		       (flags&M_NOLF) ? "" : "\n");
	    }
	  fflush(fp);
	  ++x_msg_line_num;
	}
    }

  if (flags & M_FATAL)
    msg (M_INFO, "Exiting due to fatal error");

  if (flags & M_FATAL)
    openvpn_exit (OPENVPN_EXIT_STATUS_ERROR); /* exit point */

  if (flags & M_USAGE_SMALL)
    usage_small ();

  gc_free (&gc);
}
Пример #10
0
struct multi_instance *
multi_get_create_instance_udp (struct multi_context *m)
{
  struct gc_arena gc = gc_new ();
  struct mroute_addr real;
  struct multi_instance *mi = NULL;
  struct hash *hash = m->hash;

  if (mroute_extract_openvpn_sockaddr (&real, &m->top.c2.from.dest, true))
    {
      struct hash_element *he;
      const uint32_t hv = hash_value (hash, &real);
      struct hash_bucket *bucket = hash_bucket (hash, hv);
  
      he = hash_lookup_fast (hash, bucket, &real, hv);

      if (he)
	{
	  mi = (struct multi_instance *) he->value;
	}
      else
	{
	  if (!m->top.c2.tls_auth_standalone
	      || tls_pre_decrypt_lite (m->top.c2.tls_auth_standalone, &m->top.c2.from, &m->top.c2.buf))
	    {
	      if (frequency_limit_event_allowed (m->new_connection_limiter))
		{
		  mi = multi_create_instance (m, &real);
		  if (mi)
		    {
		      hash_add_fast (hash, bucket, &mi->real, hv, mi);
		      mi->did_real_hash = true;
		    }
		}
	      else
		{
		  msg (D_MULTI_ERRORS,
		       "MULTI: Connection from %s would exceed new connection frequency limit as controlled by --connect-freq",
		       mroute_addr_print (&real, &gc));
		}
	    }
	}

#ifdef ENABLE_DEBUG
      if (check_debug_level (D_MULTI_DEBUG))
	{
	  const char *status;

	  if (he && mi)
	    status = "[succeeded]";
	  else if (!he && mi)
	    status = "[created]";
	  else
	    status = "[failed]";
	
	  dmsg (D_MULTI_DEBUG, "GET INST BY REAL: %s %s",
	       mroute_addr_print (&real, &gc),
	       status);
	}
#endif
    }

  gc_free (&gc);
  ASSERT (!(mi && mi->halt));
  return mi;
}
Пример #11
0
void
io_wait_dowork (struct context *c, const unsigned int flags)
{
  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 */
#ifdef ENABLE_MANAGEMENT
  static int management_shift = 6; /* depends on MANAGEMENT_READ and MANAGEMENT_WRITE */
#endif

  /*
   * 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.
	   */
#ifdef ENABLE_FEATURE_SHAPER
	  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);
	    }
#else /* ENABLE_FEATURE_SHAPER */
	  socket |= EVENT_WRITE;
#endif /* ENABLE_FEATURE_SHAPER */
	}
      else
	{
	  socket |= EVENT_WRITE;
	}
    }
  else if (!((flags & IOW_FRAG) && TO_LINK_FRAG (c)))
    {
      if (flags & IOW_READ_TUN)
	tuntap |= EVENT_READ;
    }

  /*
   * 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)
    {
      tuntap |= EVENT_WRITE;
    }
  else
    {
      if (flags & IOW_READ_LINK)
	socket |= EVENT_READ;
    }

  /*
   * outgoing bcast buffer waiting to be sent?
   */
  if (flags & IOW_MBUF)
    socket |= EVENT_WRITE;

  /*
   * Force wait on TUN input, even if also waiting on TCP/UDP output
   */
  if (flags & IOW_READ_TUN_FORCE)
    tuntap |= EVENT_READ;

  /*
   * 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);

#ifdef ENABLE_MANAGEMENT
  if (management)
    management_socket_set (management, c->c2.event_set, (void*)&management_shift, NULL);
#endif

  /*
   * 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
   */

  c->c2.event_set_status = ES_ERROR;

  if (!c->sig->signal_received)
    {
      if (!(flags & IOW_CHECK_RESIDUAL) || !socket_read_residual (c->c2.link_socket))
	{
	  int status;

#ifdef ENABLE_DEBUG
	  if (check_debug_level (D_EVENT_WAIT))
	    show_wait_status (c);
#endif

	  /*
	   * 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);
}
Пример #12
0
struct multi_instance *
multi_get_create_instance_udp (struct multi_context *m, bool *floated)
{
  struct gc_arena gc = gc_new ();
  struct mroute_addr real;
  struct multi_instance *mi = NULL;
  struct hash *hash = m->hash;

  if (mroute_extract_openvpn_sockaddr (&real, &m->top.c2.from.dest, true) &&
      m->top.c2.buf.len > 0)
    {
      struct hash_element *he;
      const uint32_t hv = hash_value (hash, &real);
      struct hash_bucket *bucket = hash_bucket (hash, hv);
      uint8_t* ptr = BPTR(&m->top.c2.buf);
      uint8_t op = ptr[0] >> P_OPCODE_SHIFT;

      /* make sure buffer has enough length to read opcode (1 byte) and peer-id (3 bytes) */
      if (op == P_DATA_V2 && m->top.c2.buf.len >= (1 + 3))
	{
	  uint32_t peer_id = ntohl(*(uint32_t*)ptr) & 0xFFFFFF;
	  if ((peer_id < m->max_clients) && (m->instances[peer_id]))
	    {
	      mi = m->instances[peer_id];

	      *floated = !link_socket_actual_match(&mi->context.c2.from, &m->top.c2.from);

	      if (*floated)
	      {
		/* reset prefix, since here we are not sure peer is the one it claims to be */
		ungenerate_prefix(mi);
		msg (D_MULTI_ERRORS, "Untrusted peer %" PRIu32 " wants to float to %s", peer_id,
			mroute_addr_print (&real, &gc));
	      }
	    }
	}
      else
	{
	  he = hash_lookup_fast (hash, bucket, &real, hv);
	  if (he)
	    {
	      mi = (struct multi_instance *) he->value;
	    }
	}
      if (!mi)
	{
	  if (!m->top.c2.tls_auth_standalone
	      || tls_pre_decrypt_lite (m->top.c2.tls_auth_standalone, &m->top.c2.from, &m->top.c2.buf))
	    {
	      if (frequency_limit_event_allowed (m->new_connection_limiter))
		{
		  mi = multi_create_instance (m, &real);
		  if (mi)
		    {
		      int i;

		      hash_add_fast (hash, bucket, &mi->real, hv, mi);
		      mi->did_real_hash = true;

		      for (i = 0; i < m->max_clients; ++i)
			{
			  if (!m->instances[i])
			    {
			      mi->context.c2.tls_multi->peer_id = i;
			      m->instances[i] = mi;
			      break;
			    }
			}

		      /* should not really end up here, since multi_create_instance returns null
		       * if amount of clients exceeds max_clients */
		      ASSERT(i < m->max_clients);
		    }
		}
	      else
		{
		  msg (D_MULTI_ERRORS,
		       "MULTI: Connection from %s would exceed new connection frequency limit as controlled by --connect-freq",
		       mroute_addr_print (&real, &gc));
		}
	    }
	}

#ifdef ENABLE_DEBUG
      if (check_debug_level (D_MULTI_DEBUG))
	{
	  const char *status = mi ? "[ok]" : "[failed]";

	  dmsg (D_MULTI_DEBUG, "GET INST BY REAL: %s %s",
	       mroute_addr_print (&real, &gc),
	       status);
	}
#endif
    }

  gc_free (&gc);
  ASSERT (!(mi && mi->halt));
  return mi;
}
Пример #13
0
void
client_nat_transform(const struct client_nat_option_list *list,
                     struct buffer *ipbuf,
                     const int direction)
{
    struct ip_tcp_udp_hdr *h = (struct ip_tcp_udp_hdr *) BPTR(ipbuf);
    int i;
    uint32_t addr, *addr_ptr;
    const uint32_t *from, *to;
    int accumulate = 0;
    unsigned int amask;
    unsigned int alog = 0;

    if (check_debug_level(D_CLIENT_NAT))
    {
        print_pkt(&h->ip, "BEFORE", direction, D_CLIENT_NAT);
    }

    for (i = 0; i < list->n; ++i)
    {
        const struct client_nat_entry *e = &list->entries[i]; /* current NAT rule */
        if (e->type ^ direction)
        {
            addr = *(addr_ptr = &h->ip.daddr);
            amask = 2;
        }
        else
        {
            addr = *(addr_ptr = &h->ip.saddr);
            amask = 1;
        }
        if (direction)
        {
            from = &e->foreign_network;
            to = &e->network;
        }
        else
        {
            from = &e->network;
            to = &e->foreign_network;
        }

        if (((addr & e->netmask) == *from) && !(amask & alog))
        {
            /* pre-adjust IP checksum */
            ADD_CHECKSUM_32(accumulate, addr);

            /* do NAT transform */
            addr = (addr & ~e->netmask) | *to;

            /* post-adjust IP checksum */
            SUB_CHECKSUM_32(accumulate, addr);

            /* write the modified address to packet */
            *addr_ptr = addr;

            /* mark as modified */
            alog |= amask;
        }
    }
    if (alog)
    {
        if (check_debug_level(D_CLIENT_NAT))
        {
            print_pkt(&h->ip, "AFTER", direction, D_CLIENT_NAT);
        }

        ADJUST_CHECKSUM(accumulate, h->ip.check);

        if (h->ip.protocol == OPENVPN_IPPROTO_TCP)
        {
            if (BLEN(ipbuf) >= sizeof(struct openvpn_iphdr) + sizeof(struct openvpn_tcphdr))
            {
                ADJUST_CHECKSUM(accumulate, h->u.tcp.check);
            }
        }
        else if (h->ip.protocol == OPENVPN_IPPROTO_UDP)
        {
            if (BLEN(ipbuf) >= sizeof(struct openvpn_iphdr) + sizeof(struct openvpn_udphdr))
            {
                ADJUST_CHECKSUM(accumulate, h->u.udp.check);
            }
        }
    }
}