Skip to content

Commit

Permalink
Merge OpenVPN 3 Core Library v3.9 to master
Browse files Browse the repository at this point in the history
Signed-off-by: David Sommerseth <[email protected]>
  • Loading branch information
dsommers committed Jun 5, 2024
2 parents 3ceb4ff + 733d00b commit f2e67aa
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 60 deletions.
2 changes: 1 addition & 1 deletion openvpn/common/version.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,5 @@
#pragma once

#ifndef OPENVPN_VERSION
#define OPENVPN_VERSION "3.9_git:master"
#define OPENVPN_VERSION "3.9_qa"
#endif
6 changes: 6 additions & 0 deletions openvpn/log/sessionstats.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,12 @@ class SessionStats : public RC<thread_safe_refcount>
if (dco_)
{
const DCOTransportSource::Data data = dco_->dco_transport_stats_delta();

if (data.transport_bytes_in > 0)
{
update_last_packet_received(Time::now());
}

stats_[BYTES_IN] += data.transport_bytes_in;
stats_[BYTES_OUT] += data.transport_bytes_out;
stats_[TUN_BYTES_IN] += data.tun_bytes_in;
Expand Down
58 changes: 29 additions & 29 deletions openvpn/tun/win/client/tunsetup.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -607,8 +607,9 @@ class Setup : public SetupBase
const bool block_local_traffic = (pull.reroute_gw.flags & RedirectGatewayFlags::RG_BLOCK_LOCAL) != 0;
if (use_wfp && block_local_traffic && !openvpn_app_path.empty())
{
create.add(new WFP::ActionBlock(openvpn_app_path, tap.index, false, wfp));
destroy.add(new WFP::ActionUnblock(openvpn_app_path, tap.index, false, wfp));
WFP::Block block_type = (allow_local_dns_resolvers ? WFP::Block::AllButLocalDns : WFP::Block::All);
create.add(new WFP::ActionBlock(openvpn_app_path, tap.index, block_type, wfp));
destroy.add(new WFP::ActionUnblock(openvpn_app_path, tap.index, block_type, wfp));
}

// The process id for NRPT rules
Expand All @@ -634,12 +635,6 @@ class Setup : public SetupBase
{
domains.push_back("." + dom.domain);
}
if (domains.empty() && allow_local_dns_resolvers)
{
// This empty domain tells the NRPT code that
// no '.' rule should be created
domains.push_back("");
}

const bool dnssec = server.dnssec == DnsServer::Security::Yes;

Expand All @@ -651,16 +646,23 @@ class Setup : public SetupBase
delimiter = ",";
}

create.add(new NRPT::ActionCreate(pid, domains, addresses, dnssec));
// To keep local resolvers working, only split rules must be created
if (!allow_local_dns_resolvers || !domains.empty())
{
create.add(new NRPT::ActionCreate(pid, domains, addresses, dnssec));
destroy.add(new NRPT::ActionDelete(pid));
}

create.add(new DNS::ActionCreate(tap.name, search_domains));
destroy.add(new NRPT::ActionDelete(pid));
destroy.add(new DNS::ActionDelete(tap.name, search_domains));

// block local DNS lookup unless all traffic is blocked already
if (use_wfp && pull.block_outside_dns && !block_local_traffic && !openvpn_app_path.empty())
// Use WFP for DNS leak protection unless local traffic is blocked already.
// Block DNS on all interfaces except the TAP adapter.
if (use_wfp && pull.block_outside_dns && !block_local_traffic
&& !allow_local_dns_resolvers && !openvpn_app_path.empty())
{
create.add(new WFP::ActionBlock(openvpn_app_path, tap.index, true, wfp));
destroy.add(new WFP::ActionUnblock(openvpn_app_path, tap.index, true, wfp));
create.add(new WFP::ActionBlock(openvpn_app_path, tap.index, WFP::Block::Dns, wfp));
destroy.add(new WFP::ActionUnblock(openvpn_app_path, tap.index, WFP::Block::Dns, wfp));
}
}
else
Expand Down Expand Up @@ -732,7 +734,7 @@ class Setup : public SetupBase
if (use_nrpt && (dns.ipv4() || dns.ipv6()))
{
// domain suffix list
std::vector<std::string> dsfx;
std::vector<std::string> split_domains;

// Only add DNS routing suffixes if not rerouting gateway.
// Otherwise, route all DNS requests with wildcard (".").
Expand All @@ -746,23 +748,22 @@ class Setup : public SetupBase
// each DNS suffix must begin with '.'
if (dom[0] != '.')
dom = "." + dom;
dsfx.push_back(std::move(dom));
split_domains.push_back(std::move(dom));
}
}
}

// This empty domain tells the NRPT code that
// no '.' rule should be created
if (dsfx.empty() && allow_local_dns_resolvers)
dsfx.emplace_back("");

// DNS server list
std::vector<std::string> dserv;
for (const auto &ds : pull.dns_servers)
dserv.push_back(ds.address);

create.add(new NRPT::ActionCreate(pid, dsfx, dserv, false));
destroy.add(new NRPT::ActionDelete(pid));
// To keep local resolvers working, only split rules must be created
if (!allow_local_dns_resolvers || !split_domains.empty())
{
create.add(new NRPT::ActionCreate(pid, split_domains, dserv, false));
destroy.add(new NRPT::ActionDelete(pid));
}
}

// Set a default TAP-adapter domain suffix using
Expand All @@ -776,13 +777,12 @@ class Setup : public SetupBase


// Use WFP for DNS leak protection unless local traffic is blocked already.
// If we added DNS servers, block DNS on all interfaces except
// the TAP adapter and loopback.
if (use_wfp && !block_local_traffic
&& !split_dns && !openvpn_app_path.empty() && (dns.ipv4() || dns.ipv6()))
// Block DNS on all interfaces except the TAP adapter.
if (use_wfp && !split_dns && !block_local_traffic && !allow_local_dns_resolvers
&& !openvpn_app_path.empty() && (dns.ipv4() || dns.ipv6()))
{
create.add(new WFP::ActionBlock(openvpn_app_path, tap.index, true, wfp));
destroy.add(new WFP::ActionUnblock(openvpn_app_path, tap.index, true, wfp));
create.add(new WFP::ActionBlock(openvpn_app_path, tap.index, WFP::Block::Dns, wfp));
destroy.add(new WFP::ActionUnblock(openvpn_app_path, tap.index, WFP::Block::Dns, wfp));
}

// flush DNS cache
Expand Down
5 changes: 0 additions & 5 deletions openvpn/tun/win/nrpt.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -424,11 +424,6 @@ class Nrpt
*/
void execute(std::ostream &log) override
{
// Don't add anything if there is only one empty domain. This
// is the way to tell us that no '.' rules should be added
if (domains_.size() == 1 && domains_[0] == "")
return;

// Convert domains into a wide MULTI_SZ string
std::wstring domains;
if (domains_.empty())
Expand Down
80 changes: 55 additions & 25 deletions openvpn/tun/win/wfp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,16 @@ class WFP : public RC<thread_unsafe_refcount>

OPENVPN_EXCEPTION(wfp_error);

/**
* @brief Enum for type of local traffic to block
*/
enum class Block
{
All,
AllButLocalDns,
Dns,
};

class ActionBase;

/**
Expand All @@ -169,12 +179,12 @@ class WFP : public RC<thread_unsafe_refcount>

void block(const std::wstring &openvpn_app_path,
const NET_IFINDEX itf_index,
const bool dns_only,
const Block block_type,
std::ostream &log)
{
unblock(log);
wfp.reset(new WFP());
wfp->block(openvpn_app_path, itf_index, dns_only, log);
wfp->block(openvpn_app_path, itf_index, block_type, log);
}

void unblock(std::ostream &log)
Expand Down Expand Up @@ -209,7 +219,7 @@ class WFP : public RC<thread_unsafe_refcount>
{
log << to_string() << std::endl;
if (block_)
ctx_->block(openvpn_app_path_, itf_index_, dns_only_, log);
ctx_->block(openvpn_app_path_, itf_index_, block_type_, log);
else
ctx_->unblock(log);
}
Expand All @@ -225,12 +235,12 @@ class WFP : public RC<thread_unsafe_refcount>
ActionBase(const bool block,
const std::wstring &openvpn_app_path,
const NET_IFINDEX itf_index,
const bool dns_only,
const Block block_type,
const Context::Ptr &ctx)
: block_(block),
openvpn_app_path_(openvpn_app_path),
itf_index_(itf_index),
dns_only_(dns_only),
block_type_(block_type),
ctx_(ctx)
{
}
Expand All @@ -239,17 +249,17 @@ class WFP : public RC<thread_unsafe_refcount>
const bool block_;
const std::wstring openvpn_app_path_;
const NET_IFINDEX itf_index_;
const bool dns_only_;
const Block block_type_;
Context::Ptr ctx_;
};

struct ActionBlock : public ActionBase
{
ActionBlock(const std::wstring &openvpn_app_path,
const NET_IFINDEX itf_index,
const bool dns_only,
const Block block_type,
const Context::Ptr &wfp)
: ActionBase(true, openvpn_app_path, itf_index, dns_only, wfp)
: ActionBase(true, openvpn_app_path, itf_index, block_type, wfp)
{
}
};
Expand All @@ -258,9 +268,9 @@ class WFP : public RC<thread_unsafe_refcount>
{
ActionUnblock(const std::wstring &openvpn_app_path,
const NET_IFINDEX itf_index,
const bool dns_only,
const Block block_type,
const Context::Ptr &wfp)
: ActionBase(false, openvpn_app_path, itf_index, dns_only, wfp)
: ActionBase(false, openvpn_app_path, itf_index, block_type, wfp)
{
}
};
Expand All @@ -280,12 +290,12 @@ class WFP : public RC<thread_unsafe_refcount>
*
* @param openvpn_app_path path to the openvpn executable
* @param itf_index interface index of the VPN interface
* @param dns_only whether only port 53 should be blocked
* @param block_type which type of traffic should be blocked
* @param log the log ostream to use for diagnostics
*/
void block(const std::wstring &openvpn_app_path,
NET_IFINDEX itf_index,
bool dns_only,
Block block_type,
std::ostream &log)
{
// WFP filter/conditions
Expand All @@ -294,6 +304,7 @@ class WFP : public RC<thread_unsafe_refcount>
FWPM_FILTER_CONDITION0 match_openvpn = {0};
FWPM_FILTER_CONDITION0 match_port_53 = {0};
FWPM_FILTER_CONDITION0 match_interface = {0};
FWPM_FILTER_CONDITION0 match_loopback = {0};
FWPM_FILTER_CONDITION0 match_not_loopback = {0};
UINT64 filterid = 0;

Expand Down Expand Up @@ -334,6 +345,11 @@ class WFP : public RC<thread_unsafe_refcount>
match_interface.conditionValue.type = FWP_UINT64;
match_interface.conditionValue.uint64 = &itf_luid.Value;

match_loopback.fieldKey = FWPM_CONDITION_FLAGS;
match_loopback.matchType = FWP_MATCH_FLAGS_ALL_SET;
match_loopback.conditionValue.type = FWP_UINT32;
match_loopback.conditionValue.uint32 = FWP_CONDITION_FLAG_IS_LOOPBACK;

match_not_loopback.fieldKey = FWPM_CONDITION_FLAGS;
match_not_loopback.matchType = FWP_MATCH_FLAGS_NONE_SET;
match_not_loopback.conditionValue.type = FWP_UINT32;
Expand All @@ -351,11 +367,6 @@ class WFP : public RC<thread_unsafe_refcount>
filter.action.type = FWP_ACTION_PERMIT;
filter.numFilterConditions = 1;
condition[0] = match_openvpn;
if (dns_only)
{
filter.numFilterConditions = 2;
condition[1] = match_port_53;
}
add_filter(&filter, NULL, &filterid);
log << "permit IPv4 requests from OpenVPN app" << std::endl;

Expand All @@ -366,17 +377,22 @@ class WFP : public RC<thread_unsafe_refcount>
log << "permit IPv6 requests from OpenVPN app" << std::endl;


// Filter #3 -- block IPv4 requests (except to loopback) from other apps
// Filter #3 -- block IPv4 (DNS) requests, except to loopback, from other apps
filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4;
filter.action.type = FWP_ACTION_BLOCK;
filter.weight.type = FWP_EMPTY;
filter.numFilterConditions = 1;
condition[0] = dns_only ? match_port_53 : match_not_loopback;
condition[0] = match_not_loopback;
if (block_type == Block::Dns)
{
filter.numFilterConditions = 2;
condition[1] = match_port_53;
}
add_filter(&filter, NULL, &filterid);
log << "block IPv4 requests from other apps" << std::endl;


// Filter #4 -- block IPv6 requests (except to loopback) from other apps
// Filter #4 -- block IPv6 (DNS) requests, except to loopback, from other apps
filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6;
add_filter(&filter, NULL, &filterid);
log << "block IPv6 requests from other apps" << std::endl;
Expand All @@ -387,11 +403,6 @@ class WFP : public RC<thread_unsafe_refcount>
filter.action.type = FWP_ACTION_PERMIT;
filter.numFilterConditions = 1;
condition[0] = match_interface;
if (dns_only)
{
filter.numFilterConditions = 2;
condition[1] = match_port_53;
}
add_filter(&filter, NULL, &filterid);
log << "allow IPv4 traffic from TAP" << std::endl;

Expand All @@ -400,6 +411,25 @@ class WFP : public RC<thread_unsafe_refcount>
filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6;
add_filter(&filter, NULL, &filterid);
log << "allow IPv6 traffic from TAP" << std::endl;

if (block_type != Block::AllButLocalDns)
{
// Filter #7 -- block IPv4 DNS requests to loopback from other apps
filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4;
filter.action.type = FWP_ACTION_BLOCK;
filter.weight.type = FWP_EMPTY;
filter.numFilterConditions = 2;
condition[0] = match_loopback;
condition[1] = match_port_53;
add_filter(&filter, NULL, &filterid);
log << "block IPv4 DNS requests to loopback from other apps" << std::endl;


// Filter #8 -- block IPv6 DNS requests to loopback from other apps
filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6;
add_filter(&filter, NULL, &filterid);
log << "block IPv6 DNS requests to loopback from other apps" << std::endl;
}
}

/**
Expand Down

0 comments on commit f2e67aa

Please sign in to comment.