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); }
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); } }
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; } }
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 }
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; }
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; }
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; } } } }
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); }
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; }
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); }
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; }
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); } } } }