Merge commit '86cc97e55fe346502462284d2e636a2b3708163e' as 'Sources/OpenVPN3'

This commit is contained in:
Sergey Abramchuk
2020-02-24 14:43:11 +03:00
655 changed files with 146468 additions and 0 deletions

View File

@@ -0,0 +1,218 @@
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2017 OpenVPN Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License Version 3
// 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
// Enumerate iOS network interfaces
#ifndef OPENVPN_NETCONF_ENUMIFACE_H
#define OPENVPN_NETCONF_ENUMIFACE_H
#include <sys/types.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#ifdef OPENVPN_PLATFORM_IPHONE
#include <openvpn/netconf/ios/net-route.h>
#else
#include <net/route.h>
#endif
#include <cstring>
#include <string>
#include <sstream>
#include <memory>
#include <openvpn/common/size.hpp>
#include <openvpn/common/exception.hpp>
#include <openvpn/addr/ip.hpp>
namespace openvpn {
class EnumIface
{
public:
OPENVPN_EXCEPTION(enum_iface_error);
EnumIface()
: ifinfo(alloc_if_addrs(), free_if_addrs)
{
}
std::string to_string() const
{
std::ostringstream os;
os << "INTERFACES:" << std::endl;
for (const ifaddrs* i = ifinfo.get(); i->ifa_next; i = i->ifa_next)
render(i, os);
return os.str();
}
bool iface_up(const char *iface) const
{
for (const ifaddrs* i = ifinfo.get(); i->ifa_next; i = i->ifa_next)
{
if (!std::strcmp(iface, i->ifa_name)
&& (i->ifa_flags & RTF_UP)
&& IP::Addr::sockaddr_defined(i->ifa_addr))
return true;
}
return false;
}
protected:
static void render(const ifaddrs* i, std::ostream& os)
{
try {
os << i->ifa_name;
os << ' ' << render_flags(i->ifa_flags);
if (i->ifa_addr)
{
const IP::Addr a = IP::Addr::from_sockaddr(i->ifa_addr);
if (a.defined())
os << ' ' << a;
}
if (i->ifa_netmask)
{
const IP::Addr nm = IP::Addr::from_sockaddr(i->ifa_netmask);
if (nm.defined())
{
try {
unsigned int pl = nm.prefix_len();
os << '/' << pl;
}
catch (const std::exception&)
{
}
}
}
if (i->ifa_dstaddr)
{
const IP::Addr dst = IP::Addr::from_sockaddr(i->ifa_dstaddr);
if (dst.defined())
os << " (" << dst << ')';
}
}
catch (const std::exception&)
{
os << " ERROR";
}
os << std::endl;
}
static std::string render_flags(const u_int flags)
{
struct flag_info {
u_int flag;
char c;
};
static const struct flag_info flag_info[] = {
# ifdef RTF_UP
{ RTF_UP, 'U' }, // Route usable
# endif
# ifdef RTF_GATEWAY
{ RTF_GATEWAY, 'G' }, // Destination requires forwarding by intermediary
# endif
# ifdef RTF_HOST
{ RTF_HOST, 'H' }, // Host entry (net otherwise)
# endif
# ifdef RTF_REJECT
{ RTF_REJECT, 'R' }, // Host or net unreachable
# endif
# ifdef RTF_DYNAMIC
{ RTF_DYNAMIC, 'D' }, // Created dynamically (by redirect)
# endif
# ifdef RTF_MODIFIED
{ RTF_MODIFIED, 'M' }, // Modified dynamically (by redirect)
# endif
# ifdef RTF_CLONING
{ RTF_CLONING, 'C' }, // Generate new routes on use
# endif
# ifdef RTF_XRESOLVE
{ RTF_XRESOLVE, 'X' }, // External daemon translates proto to link address
# endif
# ifdef RTF_LLINFO
{ RTF_LLINFO, 'L' }, // Valid protocol to link address translation
# endif
# ifdef RTF_STATIC
{ RTF_STATIC, 'S' }, // Manually added
# endif
# ifdef RTF_BLACKHOLE
{ RTF_BLACKHOLE, 'B' }, // Just discard packets (during updates)
# endif
# ifdef RTF_PROTO2
{ RTF_PROTO2, '2' }, // Protocol specific routing flag #2
# endif
# ifdef RTF_PROTO1
{ RTF_PROTO1, '1' }, // Protocol specific routing flag #1
# endif
# ifdef RTF_PRCLONING
{ RTF_PRCLONING, 'c' }, // Protocol-specified generate new routes on use
# endif
# ifdef RTF_WASCLONED
{ RTF_WASCLONED, 'W' }, // Route was generated as a result of cloning
# endif
# ifdef RTF_PROTO3
{ RTF_PROTO3, '3' }, // Protocol specific routing flag #3
# endif
# ifdef RTF_BROADCAST
{ RTF_BROADCAST, 'b' }, // The route represents a broadcast address
# endif
# ifdef RTF_MULTICAST
{ RTF_MULTICAST, 'm' }, // The route represents a multicast address
# endif
# ifdef RTF_IFSCOPE
{ RTF_IFSCOPE, 'I' }, // Route is associated with an interface scope
# endif
# ifdef RTF_IFREF
{ RTF_IFREF, 'i' }, // Route is holding a reference to the interface
# endif
# ifdef RTF_PROXY
{ RTF_PROXY, 'Y' }, // Proxying; cloned routes will not be scoped
# endif
# ifdef RTF_ROUTER
{ RTF_ROUTER, 'r' }, // Host is a default router
# endif
{ 0, '\0' },
};
std::string ret;
for (const struct flag_info *fi = flag_info; fi->flag; ++fi)
if (flags & fi->flag)
ret += fi->c;
return ret;
}
static ifaddrs* alloc_if_addrs()
{
ifaddrs* ifa = nullptr;
::getifaddrs(&ifa);
return ifa;
}
static void free_if_addrs(ifaddrs* p)
{
// delete method for pointer returned by getifaddrs
freeifaddrs(p);
}
std::unique_ptr<ifaddrs, decltype(&free_if_addrs)> ifinfo;
};
}
#endif

View File

@@ -0,0 +1,74 @@
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2017 OpenVPN Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License Version 3
// 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
// Get the local MAC addr of the interface that owns the default route
#ifndef OPENVPN_NETCONF_HWADDR_H
#define OPENVPN_NETCONF_HWADDR_H
#include <string>
#include <openvpn/common/platform.hpp>
#include <openvpn/addr/macaddr.hpp>
#if defined(OPENVPN_PLATFORM_WIN) && !defined(OPENVPN_PLATFORM_UWP)
#include <openvpn/tun/win/tunutil.hpp>
#elif defined(OPENVPN_PLATFORM_MAC)
#include <openvpn/tun/mac/gwv4.hpp>
#elif defined(TARGET_OS_IPHONE)
#include <UIKit/UIKit.h>
#endif
namespace openvpn {
inline std::string get_hwaddr()
{
#if defined(OPENVPN_PLATFORM_WIN) && !defined(OPENVPN_PLATFORM_UWP)
const TunWin::Util::DefaultGateway dg;
if (dg.defined())
{
const TunWin::Util::IPAdaptersInfo ai_list;
const IP_ADAPTER_INFO* ai = ai_list.adapter(dg.interface_index());
if (ai)
{
const MACAddr mac(ai->Address);
return mac.to_string();
}
}
#elif defined(OPENVPN_PLATFORM_MAC)
const MacGatewayInfoV4 gw;
if (gw.hwaddr_defined())
{
const MACAddr& mac = gw.hwaddr();
return mac.to_string();
}
#elif defined(TARGET_OS_IPHONE)
// as reported at https://developer.apple.com/library/content/releasenotes/General/WhatsNewIniOS/Articles/iOS7.html#//apple_ref/doc/uid/TP40013162-SW34
// we can't get the MAC address from iOS for privacy reasons, but we can
// use the UUID as unique identifier. It is unique among the App domain,
// meaning that a different app will get a different UUID from this call
const NSString *uuid = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
return std::string([uuid UTF8String]);
#endif
return std::string();
}
}
#endif

View File

@@ -0,0 +1,248 @@
/*
* Copyright (c) 2000-2013 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. The rights granted to you under the License
* may not be used to create, or enable the creation or redistribution of,
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
*
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
/*
* Copyright (c) 1980, 1986, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)route.h 8.3 (Berkeley) 4/19/94
* $FreeBSD: src/sys/net/route.h,v 1.36.2.1 2000/08/16 06:14:23 jayanth Exp $
*/
#ifndef _NET_ROUTE_H_
#define _NET_ROUTE_H_
#include <sys/appleapiopts.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/socket.h>
/*
* These numbers are used by reliable protocols for determining
* retransmission behavior and are included in the routing structure.
*/
struct rt_metrics {
u_int32_t rmx_locks; /* Kernel leaves these values alone */
u_int32_t rmx_mtu; /* MTU for this path */
u_int32_t rmx_hopcount; /* max hops expected */
int32_t rmx_expire; /* lifetime for route, e.g. redirect */
u_int32_t rmx_recvpipe; /* inbound delay-bandwidth product */
u_int32_t rmx_sendpipe; /* outbound delay-bandwidth product */
u_int32_t rmx_ssthresh; /* outbound gateway buffer limit */
u_int32_t rmx_rtt; /* estimated round trip time */
u_int32_t rmx_rttvar; /* estimated rtt variance */
u_int32_t rmx_pksent; /* packets sent using this route */
u_int32_t rmx_filler[4]; /* will be used for T/TCP later */
};
/*
* rmx_rtt and rmx_rttvar are stored as microseconds;
*/
#define RTM_RTTUNIT 1000000 /* units for rtt, rttvar, as units per sec */
#define RTF_UP 0x1 /* route usable */
#define RTF_GATEWAY 0x2 /* destination is a gateway */
#define RTF_HOST 0x4 /* host entry (net otherwise) */
#define RTF_REJECT 0x8 /* host or net unreachable */
#define RTF_DYNAMIC 0x10 /* created dynamically (by redirect) */
#define RTF_MODIFIED 0x20 /* modified dynamically (by redirect) */
#define RTF_DONE 0x40 /* message confirmed */
#define RTF_DELCLONE 0x80 /* delete cloned route */
#define RTF_CLONING 0x100 /* generate new routes on use */
#define RTF_XRESOLVE 0x200 /* external daemon resolves name */
#define RTF_LLINFO 0x400 /* generated by link layer (e.g. ARP) */
#define RTF_STATIC 0x800 /* manually added */
#define RTF_BLACKHOLE 0x1000 /* just discard pkts (during updates) */
#define RTF_NOIFREF 0x2000 /* not eligible for RTF_IFREF */
#define RTF_PROTO2 0x4000 /* protocol specific routing flag */
#define RTF_PROTO1 0x8000 /* protocol specific routing flag */
#define RTF_PRCLONING 0x10000 /* protocol requires cloning */
#define RTF_WASCLONED 0x20000 /* route generated through cloning */
#define RTF_PROTO3 0x40000 /* protocol specific routing flag */
/* 0x80000 unused */
#define RTF_PINNED 0x100000 /* future use */
#define RTF_LOCAL 0x200000 /* route represents a local address */
#define RTF_BROADCAST 0x400000 /* route represents a bcast address */
#define RTF_MULTICAST 0x800000 /* route represents a mcast address */
#define RTF_IFSCOPE 0x1000000 /* has valid interface scope */
#define RTF_CONDEMNED 0x2000000 /* defunct; no longer modifiable */
#define RTF_IFREF 0x4000000 /* route holds a ref to interface */
#define RTF_PROXY 0x8000000 /* proxying, no interface scope */
#define RTF_ROUTER 0x10000000 /* host is a router */
/* 0x20000000 and up unassigned */
#define RTF_BITS \
"\020\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE" \
"\10DELCLONE\11CLONING\12XRESOLVE\13LLINFO\14STATIC\15BLACKHOLE" \
"\16NOIFREF\17PROTO2\20PROTO1\21PRCLONING\22WASCLONED\23PROTO3" \
"\25PINNED\26LOCAL\27BROADCAST\30MULTICAST\31IFSCOPE\32CONDEMNED" \
"\33IFREF\34PROXY\35ROUTER"
/*
* Routing statistics.
*/
struct rtstat {
short rts_badredirect; /* bogus redirect calls */
short rts_dynamic; /* routes created by redirects */
short rts_newgateway; /* routes modified by redirects */
short rts_unreach; /* lookups which failed */
short rts_wildcard; /* lookups satisfied by a wildcard */
};
/*
* Structures for routing messages.
*/
struct rt_msghdr {
u_short rtm_msglen; /* to skip over non-understood messages */
u_char rtm_version; /* future binary compatibility */
u_char rtm_type; /* message type */
u_short rtm_index; /* index for associated ifp */
int rtm_flags; /* flags, incl. kern & message, e.g. DONE */
int rtm_addrs; /* bitmask identifying sockaddrs in msg */
pid_t rtm_pid; /* identify sender */
int rtm_seq; /* for sender to identify action */
int rtm_errno; /* why failed */
int rtm_use; /* from rtentry */
u_int32_t rtm_inits; /* which metrics we are initializing */
struct rt_metrics rtm_rmx; /* metrics themselves */
};
struct rt_msghdr2 {
u_short rtm_msglen; /* to skip over non-understood messages */
u_char rtm_version; /* future binary compatibility */
u_char rtm_type; /* message type */
u_short rtm_index; /* index for associated ifp */
int rtm_flags; /* flags, incl. kern & message, e.g. DONE */
int rtm_addrs; /* bitmask identifying sockaddrs in msg */
int32_t rtm_refcnt; /* reference count */
int rtm_parentflags; /* flags of the parent route */
int rtm_reserved; /* reserved field set to 0 */
int rtm_use; /* from rtentry */
u_int32_t rtm_inits; /* which metrics we are initializing */
struct rt_metrics rtm_rmx; /* metrics themselves */
};
#define RTM_VERSION 5 /* Up the ante and ignore older versions */
/*
* Message types.
*/
#define RTM_ADD 0x1 /* Add Route */
#define RTM_DELETE 0x2 /* Delete Route */
#define RTM_CHANGE 0x3 /* Change Metrics or flags */
#define RTM_GET 0x4 /* Report Metrics */
#define RTM_LOSING 0x5 /* Kernel Suspects Partitioning */
#define RTM_REDIRECT 0x6 /* Told to use different route */
#define RTM_MISS 0x7 /* Lookup failed on this address */
#define RTM_LOCK 0x8 /* fix specified metrics */
#define RTM_OLDADD 0x9 /* caused by SIOCADDRT */
#define RTM_OLDDEL 0xa /* caused by SIOCDELRT */
#define RTM_RESOLVE 0xb /* req to resolve dst to LL addr */
#define RTM_NEWADDR 0xc /* address being added to iface */
#define RTM_DELADDR 0xd /* address being removed from iface */
#define RTM_IFINFO 0xe /* iface going up/down etc. */
#define RTM_NEWMADDR 0xf /* mcast group membership being added to if */
#define RTM_DELMADDR 0x10 /* mcast group membership being deleted */
#define RTM_IFINFO2 0x12 /* */
#define RTM_NEWMADDR2 0x13 /* */
#define RTM_GET2 0x14 /* */
/*
* Bitmask values for rtm_inits and rmx_locks.
*/
#define RTV_MTU 0x1 /* init or lock _mtu */
#define RTV_HOPCOUNT 0x2 /* init or lock _hopcount */
#define RTV_EXPIRE 0x4 /* init or lock _expire */
#define RTV_RPIPE 0x8 /* init or lock _recvpipe */
#define RTV_SPIPE 0x10 /* init or lock _sendpipe */
#define RTV_SSTHRESH 0x20 /* init or lock _ssthresh */
#define RTV_RTT 0x40 /* init or lock _rtt */
#define RTV_RTTVAR 0x80 /* init or lock _rttvar */
/*
* Bitmask values for rtm_addrs.
*/
#define RTA_DST 0x1 /* destination sockaddr present */
#define RTA_GATEWAY 0x2 /* gateway sockaddr present */
#define RTA_NETMASK 0x4 /* netmask sockaddr present */
#define RTA_GENMASK 0x8 /* cloning mask sockaddr present */
#define RTA_IFP 0x10 /* interface name sockaddr present */
#define RTA_IFA 0x20 /* interface addr sockaddr present */
#define RTA_AUTHOR 0x40 /* sockaddr for author of redirect */
#define RTA_BRD 0x80 /* for NEWADDR, broadcast or p-p dest addr */
/*
* Index offsets for sockaddr array for alternate internal encoding.
*/
#define RTAX_DST 0 /* destination sockaddr present */
#define RTAX_GATEWAY 1 /* gateway sockaddr present */
#define RTAX_NETMASK 2 /* netmask sockaddr present */
#define RTAX_GENMASK 3 /* cloning mask sockaddr present */
#define RTAX_IFP 4 /* interface name sockaddr present */
#define RTAX_IFA 5 /* interface addr sockaddr present */
#define RTAX_AUTHOR 6 /* sockaddr for author of redirect */
#define RTAX_BRD 7 /* for NEWADDR, broadcast or p-p dest addr */
#define RTAX_MAX 8 /* size of array to allocate */
struct rt_addrinfo {
int rti_addrs;
struct sockaddr *rti_info[RTAX_MAX];
};
#endif /* _NET_ROUTE_H_ */

View File

@@ -0,0 +1,211 @@
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2017 OpenVPN Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License Version 3
// 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
// Find default gateways on Linux using ip route command
#ifndef OPENVPN_NETCONF_LINUX_GW_H
#define OPENVPN_NETCONF_LINUX_GW_H
#include <string>
#include <limits>
#include <openvpn/common/exception.hpp>
#include <openvpn/common/number.hpp>
#include <openvpn/common/split.hpp>
#include <openvpn/common/splitlines.hpp>
#include <openvpn/common/process.hpp>
#include <openvpn/addr/route.hpp>
namespace openvpn {
class LinuxGW
{
public:
OPENVPN_EXCEPTION(linux_gw_error);
LinuxGW(const std::string& ip_route_show_txt, const bool ignore_errors)
{
int best_metric = std::numeric_limits<int>::max();
SplitLines sl(ip_route_show_txt);
while (sl())
{
const std::string& line = sl.line_ref();
try {
// parse an output line generated by "ip [-6] route show"
const std::vector<std::string> v = Split::by_space<std::vector<std::string>, NullLex, SpaceMatch, Split::NullLimit>(line);
// blank line?
if (v.empty())
continue;
// only interested in default routes
if (v[0] != "default")
continue;
// parse out route information
enum RouteInfo {
INITIAL,
VIA,
DEV,
METRIC,
};
std::string d;
IP::Addr a;
int m = std::numeric_limits<int>::max();
RouteInfo ri = INITIAL;
for (const auto &term : v)
{
switch (ri)
{
case INITIAL:
if (term == "via")
ri = VIA;
else if (term == "dev")
ri = DEV;
else if (term == "metric")
ri = METRIC;
else
ri = INITIAL;
break;
case VIA:
a = IP::Addr(term, "via");
ri = INITIAL;
break;
case DEV:
d = validate_dev(term);
ri = INITIAL;
break;
case METRIC:
m = parse_number_throw<int>(term, "bad metric");
ri = INITIAL;
break;
}
}
// best metric?
if (m < best_metric || best_metric == std::numeric_limits<int>::max())
{
best_metric = m;
dev_ = d;
addr_ = a;
}
}
catch (const std::exception& e)
{
if (!ignore_errors)
OPENVPN_THROW(linux_gw_error, "error parsing line: " << line << " : " << e.what());
}
}
}
static std::string ip_route_show(const bool ipv6)
{
RedirectPipe::InOut pipe;
Argv argv;
argv.emplace_back("/sbin/ip");
if (ipv6)
argv.emplace_back("-6");
argv.emplace_back("route");
argv.emplace_back("show");
const int status = system_cmd(argv[0], argv, nullptr, pipe, 0);
if (status != 0)
OPENVPN_THROW(linux_gw_error, "command returned error status " << status << " : " << argv.to_string());
return pipe.out;
}
const std::string& dev() const
{
return dev_;
}
const IP::Addr& addr() const
{
return addr_;
}
bool defined() const
{
return !dev_.empty() && addr_.defined();
}
std::string to_string() const
{
return dev_ + '/' + addr_.to_string();
}
private:
std::string validate_dev(const std::string& dev)
{
if (dev.empty())
OPENVPN_THROW_EXCEPTION("dev is empty");
return dev;
}
std::string dev_;
IP::Addr addr_;
};
struct LinuxGW46
{
LinuxGW46(const bool ignore_errors)
: v4(LinuxGW::ip_route_show(false), ignore_errors),
v6(LinuxGW::ip_route_show(true), ignore_errors)
{
}
std::string to_string() const
{
std::string ret = "[";
if (v4.defined())
{
ret += "4:";
ret += v4.to_string();
}
if (v6.defined())
{
if (v4.defined())
ret += ' ';
ret += "6:";
ret += v6.to_string();
}
ret += "]";
return ret;
}
std::string dev() const
{
if (v4.defined())
return v4.dev();
else if (v6.defined())
return v6.dev();
else
throw LinuxGW::linux_gw_error("cannot determine gateway interface");
}
LinuxGW v4;
LinuxGW v6;
};
}
#endif

View File

@@ -0,0 +1,159 @@
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2017 OpenVPN Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License Version 3
// 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
// Find default gateways on Linux using ip route command
#pragma once
#include <string>
#include <openvpn/common/exception.hpp>
#include <openvpn/addr/ip.hpp>
#include <openvpn/addr/ipv4.hpp>
#include <openvpn/addr/ipv6.hpp>
#include <openvpn/tun/linux/client/sitnl.hpp>
namespace openvpn {
class LinuxGWNetlink
{
public:
OPENVPN_EXCEPTION(linux_gw_netlink_error);
/**
* Provides gateway which is used to reach given address
*
* @param addr address which we want to reach
* @param iface_to_ignore this allows to exclude certain interface
* from discovered gateways. Used when we want to exclude VPN interface
* when there is active VPN connection with redirected default gateway
*
* @param ipv6 true if address is IPv6
*/
LinuxGWNetlink(const std::string& addr, const std::string& iface_to_ignore, bool ipv6)
{
try
{
if (ipv6)
{
IPv6::Addr addr6;
if (TunNetlink::SITNL::net_route_best_gw(IP::Route6::from_string(addr),
addr6, dev_, iface_to_ignore) < 0)
{
OPENVPN_THROW(linux_gw_netlink_error,
"error retrieving default IPv6 GW");
}
addr_ = IP::Addr::from_ipv6(addr6);
}
else
{
IPv4::Addr addr4;
if (TunNetlink::SITNL::net_route_best_gw(IP::Route4::from_string(addr),
addr4, dev_, iface_to_ignore) < 0)
{
OPENVPN_THROW(linux_gw_netlink_error,
"error retrieving default IPv4 GW");
}
addr_ = IP::Addr::from_ipv4(addr4);
}
} catch (...)
{
/* nothing to do. just leave default GW unassigned */
}
}
const std::string& dev() const
{
return dev_;
}
const IP::Addr& addr() const
{
return addr_;
}
bool defined() const
{
return !dev_.empty() && addr_.defined();
}
std::string to_string() const
{
return dev_ + '/' + addr_.to_string();
}
private:
IP::Addr addr_;
std::string dev_;
};
/**
* Provides IPv4/6 gateway which is used to reach given address
*
* @param iface_to_ignore this allows to exclude certain interface
* from discovered gateways. Used when we want to exclude VPN interface
* when there is active VPN connection with redirected default gateway
* @param addr address which we want to reach
*/
struct LinuxGW46Netlink
{
LinuxGW46Netlink(const std::string& iface_to_ignore, const std::string& addr = "")
: v4(addr.empty() ? IPv4::Addr::from_zero().to_string() : addr, iface_to_ignore, false),
v6(addr.empty() ? IPv6::Addr::from_zero().to_string() : addr, iface_to_ignore, true)
{
}
std::string to_string() const
{
std::string ret = "[";
if (v4.defined())
{
ret += "4:";
ret += v4.to_string();
}
if (v6.defined())
{
if (v4.defined())
ret += ' ';
ret += "6:";
ret += v6.to_string();
}
ret += "]";
return ret;
}
std::string dev() const
{
if (v4.defined())
return v4.dev();
else if (v6.defined())
return v6.dev();
else
throw LinuxGWNetlink::linux_gw_netlink_error("cannot determine gateway interface");
}
LinuxGWNetlink v4;
LinuxGWNetlink v6;
};
}

View File

@@ -0,0 +1,160 @@
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2017 OpenVPN Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License Version 3
// 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
// Add routes on Linux using AF_NETLINK socket
#ifndef OPENVPN_NETCONF_LINUX_ROUTE_H
#define OPENVPN_NETCONF_LINUX_ROUTE_H
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <net/if.h>
#include <errno.h>
#include <string>
#include <openvpn/common/exception.hpp>
#include <openvpn/common/scoped_fd.hpp>
#include <openvpn/common/strerror.hpp>
#include <openvpn/addr/route.hpp>
namespace openvpn {
class LinuxRoute
{
public:
OPENVPN_EXCEPTION(linux_route_error);
LinuxRoute()
{
fd.reset(::socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE));
if (!fd.defined())
throw linux_route_error("creating AF_NETLINK socket");
struct sockaddr_nl local;
::memset(&local, 0, sizeof(local));
local.nl_family = AF_NETLINK;
local.nl_pad = 0;
local.nl_pid = 0; // only use getpid() if unique instantiation per process
local.nl_groups = 0;
if (::bind(fd(), (struct sockaddr*)&local, sizeof(local)) < 0)
throw linux_route_error("binding to AF_NETLINK socket");
}
void add_delete(const bool add,
const IP::Route& route,
const int if_index,
const int table=RT_TABLE_MAIN)
{
typedef struct {
struct nlmsghdr nlmsg_info;
struct rtmsg rtmsg_info;
char buffer[64]; // must be large enough to contain request
} netlink_req_t;
struct rtattr *rtattr_ptr;
int rtmsg_len;
struct sockaddr_nl peer;
struct msghdr msg_info;
struct iovec iov_info;
netlink_req_t netlink_req;
::memset(&peer, 0, sizeof(peer));
peer.nl_family = AF_NETLINK;
peer.nl_pad = 0;
peer.nl_pid = 0;
peer.nl_groups = 0;
::memset(&msg_info, 0, sizeof(msg_info));
msg_info.msg_name = (void *) &peer;
msg_info.msg_namelen = sizeof(peer);
::memset(&netlink_req, 0, sizeof(netlink_req));
rtmsg_len = sizeof(struct rtmsg);
// add destination addr
rtattr_ptr = (struct rtattr *) netlink_req.buffer;
rtattr_ptr->rta_type = RTA_DST;
rtattr_ptr->rta_len = sizeof(struct rtattr) + route.addr.size_bytes();
route.addr.to_byte_string_variable(((unsigned char *)rtattr_ptr) + sizeof(struct rtattr));
rtmsg_len += rtattr_ptr->rta_len;
// add if_index
rtattr_ptr = (struct rtattr *) (((unsigned char *)rtattr_ptr) + rtattr_ptr->rta_len);
rtattr_ptr->rta_type = RTA_OIF;
rtattr_ptr->rta_len = sizeof(struct rtattr) + 4;
::memcpy(((unsigned char *)rtattr_ptr) + sizeof(struct rtattr), &if_index, 4);
rtmsg_len += rtattr_ptr->rta_len;
netlink_req.nlmsg_info.nlmsg_len = NLMSG_LENGTH(rtmsg_len);
if (add)
{
netlink_req.nlmsg_info.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
netlink_req.nlmsg_info.nlmsg_type = RTM_NEWROUTE;
}
else // delete
{
netlink_req.nlmsg_info.nlmsg_flags = NLM_F_REQUEST;
netlink_req.nlmsg_info.nlmsg_type = RTM_DELROUTE;
}
netlink_req.rtmsg_info.rtm_family = route.addr.family();
netlink_req.rtmsg_info.rtm_table = table;
netlink_req.rtmsg_info.rtm_dst_len = route.prefix_len; // add prefix
netlink_req.rtmsg_info.rtm_protocol = RTPROT_STATIC;
netlink_req.rtmsg_info.rtm_scope = RT_SCOPE_UNIVERSE;
netlink_req.rtmsg_info.rtm_type = RTN_UNICAST;
iov_info.iov_base = (void *) &netlink_req.nlmsg_info;
iov_info.iov_len = netlink_req.nlmsg_info.nlmsg_len;
msg_info.msg_iov = &iov_info;
msg_info.msg_iovlen = 1;
const ssize_t status = ::sendmsg(fd(), &msg_info, 0);
if (status < 0)
{
const int eno = errno;
OPENVPN_THROW(linux_route_error, "add_delete: sendmsg failed: " << strerror_str(eno));
}
}
static int if_index(const std::string& iface)
{
const unsigned int ret = ::if_nametoindex(iface.c_str());
if (!ret)
OPENVPN_THROW(linux_route_error, "if_index: no such interface: " << iface);
return ret;
}
private:
ScopedFD fd;
};
}
#endif