0
0
mirror of https://github.com/OpenVPN/openvpn3.git synced 2024-09-19 19:52:15 +02:00

Added IP address classes for IPv4/v6.

Implemented get_default_gateway() for Mac OS X.
This commit is contained in:
James Yonan 2012-01-11 06:15:32 +00:00
parent e5c2791c65
commit bd4673c60f
19 changed files with 789 additions and 75 deletions

View File

@ -1,27 +1,190 @@
#ifndef OPENVPN_ADDR_IP_H
#define OPENVPN_ADDR_IP_H
#include <string>
#include <boost/asio.hpp>
#include <openvpn/common/exception.hpp>
#include <openvpn/common/ostream.hpp>
#include <openvpn/addr/ipv4.hpp>
#include <openvpn/addr/ipv6.hpp>
namespace openvpn {
namespace IP {
OPENVPN_EXCEPTION(ip_address_error);
OPENVPN_SIMPLE_EXCEPTION(ip_addr_unspecified);
OPENVPN_SIMPLE_EXCEPTION(ip_addr_version_inconsistency);
OPENVPN_SIMPLE_EXCEPTION(ip_render_exception);
OPENVPN_EXCEPTION(ip_parse_exception);
std::string validate_ip_address(const char *title, const std::string ip_addr)
{
boost::system::error_code ec;
const boost::asio::ip::address addr = boost::asio::ip::address::from_string(ip_addr, ec);
if (!ec)
class Addr
{
public:
enum Version { UNSPEC, V4, V6 };
Addr()
{
std::string ret = addr.to_string(ec);
if (!ec)
return ret;
ver = UNSPEC;
}
OPENVPN_THROW(ip_address_error, "error validating " << title << " IP address '" << ip_addr << "' : " << ec.message());
}
static std::string validate(const std::string& ipstr, const char *title = NULL)
{
Addr a = from_string(ipstr, title);
return a.to_string();
}
static Addr from_string(const std::string& ipstr, const char *title = NULL)
{
boost::system::error_code ec;
boost::asio::ip::address a = boost::asio::ip::address::from_string(ipstr, ec);
if (ec)
{
if (!title)
title = "";
OPENVPN_THROW(ip_parse_exception, "error parsing " << title << " IP address '" << ipstr << "' : " << ec.message());
}
return from_asio(a);
}
std::string to_string() const
{
if (ver != UNSPEC)
{
const boost::asio::ip::address a = to_asio();
boost::system::error_code ec;
std::string ret = a.to_string(ec);
if (ec)
throw ip_render_exception();
return ret;
}
else
return "UNSPEC";
}
static Addr from_asio(const boost::asio::ip::address& addr)
{
if (addr.is_v4())
{
Addr a;
a.ver = V4;
a.u.v4 = IPv4::Addr::from_asio(addr.to_v4());
return a;
}
else if (addr.is_v6())
{
Addr a;
a.ver = V6;
a.u.v6 = IPv6::Addr::from_asio(addr.to_v6());
return a;
}
else
throw ip_addr_unspecified();
}
boost::asio::ip::address to_asio() const
{
switch (ver)
{
case V4:
return boost::asio::ip::address_v4(u.v4.to_asio());
case V6:
return boost::asio::ip::address_v6(u.v6.to_asio());
default:
throw ip_addr_unspecified();
}
}
Addr operator&(const Addr& other) const {
if (ver != other.ver)
throw ip_addr_version_inconsistency();
switch (ver)
{
case V4:
{
Addr ret;
ret.ver = V4;
ret.u.v4 = u.v4 & other.u.v4;
return ret;
}
case V6:
{
Addr ret;
ret.ver = V6;
ret.u.v6 = u.v6 & other.u.v6;
return ret;
}
default:
throw ip_addr_unspecified();
}
}
Addr operator|(const Addr& other) const {
if (ver != other.ver)
throw ip_addr_version_inconsistency();
switch (ver)
{
case V4:
{
Addr ret;
ret.ver = V4;
ret.u.v4 = u.v4 | other.u.v4;
return ret;
}
case V6:
{
Addr ret;
ret.ver = V6;
ret.u.v6 = u.v6 | other.u.v6;
return ret;
}
default:
throw ip_addr_unspecified();
}
}
void reset_ipv4_from_uint32(const IPv4::Addr::base_type addr)
{
ver = V4;
u.v4 = IPv4::Addr::from_uint32(addr);
}
bool unspecified() const
{
switch (ver)
{
case V4:
return u.v4.unspecified();
case V6:
return u.v6.unspecified();
default:
return true;
}
}
private:
union {
IPv4::Addr v4;
IPv6::Addr v6;
} u;
Version ver;
};
OPENVPN_OSTREAM(Addr, to_string)
struct AddrMaskPair
{
Addr addr;
Addr netmask;
std::string to_string() const
{
return addr.to_string() + "/" + netmask.to_string();
}
};
OPENVPN_OSTREAM(AddrMaskPair, to_string)
}
} // namespace openvpn
#endif // OPENVPN_ADDR_IP_H

97
openvpn/addr/ipv4.hpp Normal file
View File

@ -0,0 +1,97 @@
#ifndef OPENVPN_ADDR_IPV4_H
#define OPENVPN_ADDR_IPV4_H
#include <boost/cstdint.hpp> // for boost::uint32_t
#include <boost/asio.hpp>
#include <openvpn/common/exception.hpp>
#include <openvpn/common/ostream.hpp>
namespace openvpn {
namespace IP {
class Addr;
}
namespace IPv4 {
OPENVPN_SIMPLE_EXCEPTION(ipv4_render_exception);
OPENVPN_EXCEPTION(ipv4_parse_exception);
class Addr // NOTE: must be union-legal, so default constructor does not initialize
{
friend class IP::Addr;
public:
typedef boost::uint32_t base_type;
static Addr from_uint32(const base_type addr)
{
Addr ret;
ret.u.addr = addr;
return ret;
}
static Addr from_string(const std::string& ipstr, const char *title = NULL)
{
boost::system::error_code ec;
boost::asio::ip::address_v4 a = boost::asio::ip::address_v4::from_string(ipstr, ec);
if (ec)
{
if (!title)
title = "";
OPENVPN_THROW(ipv4_parse_exception, "error parsing " << title << " IPv4 address '" << ipstr << "' : " << ec.message());
}
return from_asio(a);
}
std::string to_string() const
{
const boost::asio::ip::address_v4 a = to_asio();
boost::system::error_code ec;
std::string ret = a.to_string(ec);
if (ec)
throw ipv4_render_exception();
return ret;
}
static Addr from_asio(const boost::asio::ip::address_v4& asio_addr)
{
Addr ret;
ret.u.addr = asio_addr.to_ulong();
return ret;
}
boost::asio::ip::address_v4 to_asio() const
{
return boost::asio::ip::address_v4(u.addr);
}
Addr operator&(const Addr& other) const {
Addr ret;
ret.u.addr = u.addr & other.u.addr;
return ret;
}
Addr operator|(const Addr& other) const {
Addr ret;
ret.u.addr = u.addr | other.u.addr;
return ret;
}
bool unspecified() const
{
return u.addr == 0;
}
private:
union {
boost::uint32_t addr;
unsigned char bytes[4];
} u;
};
OPENVPN_OSTREAM(Addr, to_string)
}
} // namespace openvpn
#endif // OPENVPN_ADDR_IPV4_H

101
openvpn/addr/ipv6.hpp Normal file
View File

@ -0,0 +1,101 @@
#ifndef OPENVPN_ADDR_IPV6_H
#define OPENVPN_ADDR_IPV6_H
#include <cstring> // for std::memcpy
#include <boost/cstdint.hpp> // for boost::uint32_t
#include <boost/asio.hpp>
#include <openvpn/common/exception.hpp>
#include <openvpn/common/ostream.hpp>
namespace openvpn {
namespace IP {
class Addr;
}
namespace IPv6 {
OPENVPN_SIMPLE_EXCEPTION(ipv6_render_exception);
OPENVPN_EXCEPTION(ipv6_parse_exception);
class Addr // NOTE: must be union-legal, so default constructor does not initialize
{
friend class IP::Addr;
public:
static Addr from_string(const std::string& ipstr, const char *title = NULL)
{
boost::system::error_code ec;
boost::asio::ip::address_v6 a = boost::asio::ip::address_v6::from_string(ipstr, ec);
if (ec)
{
if (!title)
title = "";
OPENVPN_THROW(ipv6_parse_exception, "error parsing " << title << " IPv6 address '" << ipstr << "' : " << ec.message());
}
return from_asio(a);
}
std::string to_string() const
{
const boost::asio::ip::address_v6 a = to_asio();
boost::system::error_code ec;
std::string ret = a.to_string(ec);
if (ec)
throw ipv6_render_exception();
return ret;
}
static Addr from_asio(const boost::asio::ip::address_v6& asio_addr)
{
Addr ret;
boost::asio::ip::address_v6::bytes_type bytes = asio_addr.to_bytes();
ret.scope_id_ = asio_addr.scope_id();
std::memcpy(ret.u.bytes, bytes.data(), 16);
return ret;
}
boost::asio::ip::address_v6 to_asio() const
{
boost::asio::ip::address_v6::bytes_type bytes;
std::memcpy(bytes.data(), u.bytes, 16);
return boost::asio::ip::address_v6(bytes, scope_id_);
}
Addr operator&(const Addr& other) const {
Addr ret;
ret.scope_id_ = scope_id_;
ret.u.u64[0] = u.u64[0] & other.u.u64[0];
ret.u.u64[1] = u.u64[1] & other.u.u64[1];
return ret;
}
Addr operator|(const Addr& other) const {
Addr ret;
ret.scope_id_ = scope_id_;
ret.u.u64[0] = u.u64[0] | other.u.u64[0];
ret.u.u64[1] = u.u64[1] | other.u.u64[1];
return ret;
}
bool unspecified() const
{
return u.u64[0] == 0 && u.u64[1] == 0;
}
private:
union {
boost::uint64_t u64[2];
boost::uint32_t u32[4];
unsigned char bytes[16];
} u;
unsigned int scope_id_;
};
OPENVPN_OSTREAM(Addr, to_string)
}
} // namespace openvpn
#endif // OPENVPN_ADDR_IPV6_H

50
openvpn/addr/macaddr.hpp Normal file
View File

@ -0,0 +1,50 @@
#ifndef OPENVPN_ADDR_MACADDR_H
#define OPENVPN_ADDR_MACADDR_H
#include <ostream>
#include <cstring>
#include <string>
#include <openvpn/common/exception.hpp>
#include <openvpn/common/ostream.hpp>
#include <openvpn/common/hexstr.hpp>
namespace openvpn {
class MACAddr {
public:
MACAddr()
{
std::memset(addr_, 0, sizeof(addr_));
}
void reset(const unsigned char *addr)
{
std::memcpy(addr_, addr, sizeof(addr_));
}
std::string to_string() const
{
std::string ret;
ret.reserve(sizeof(addr_)*3);
size_t size = sizeof(addr_);
const unsigned char *data = addr_;
while (size--)
{
const unsigned char c = *data++;
ret += render_hex_char(c >> 4);
ret += render_hex_char(c & 0x0F);
if (size)
ret += ':';
}
return ret;
}
private:
unsigned char addr_[6];
};
OPENVPN_OSTREAM(MACAddr, to_string)
} // namespace openvpn
#endif // OPENVPN_ADDR_MACADDR_H

View File

@ -0,0 +1,17 @@
#ifndef OPENVPN_COMMON_OSTREAM_H
#define OPENVPN_COMMON_OSTREAM_H
#include <ostream>
#include <string>
#define OPENVPN_OSTREAM(TYPE, TO_STRING) \
template <typename Elem, typename Traits> \
std::basic_ostream<Elem, Traits>& operator<<( \
std::basic_ostream<Elem, Traits>& os, const TYPE& addr) \
{ \
std::string s = addr.TO_STRING(); \
os << s; \
return os; \
}
#endif // OPENVPN_COMMON_OSTREAM_H

View File

@ -0,0 +1,7 @@
#ifndef OPENVPN_COMMON_SOCKTYPES_H
#define OPENVPN_COMMON_SOCKTYPES_H
// defines stuff like htonl, htons, etc.
#include <boost/asio/detail/socket_types.hpp>
#endif // OPENVPN_COMMON_SOCKTYPES_H

View File

@ -3,12 +3,22 @@
#include <cstring>
#include <openvpn/common/types.hpp>
namespace openvpn {
namespace string {
inline int strcasecmp(const char *s1, const char *s2)
{
return ::strcasecmp(s1, s2);
}
/* Like strncpy but makes sure dest is always null terminated */
inline void strncpynt (char *dest, const char *src, size_t maxlen)
{
strncpy (dest, src, maxlen);
if (maxlen > 0)
dest[maxlen - 1] = 0;
}
} // namespace string
} // namespace openvpn

View File

@ -4,13 +4,14 @@
#include <string>
#include <sstream>
#include <boost/cstdint.hpp>
#include <boost/cstdint.hpp> // for boost::uint32_t
#include <boost/asio.hpp>
#include <openvpn/common/types.hpp>
#include <openvpn/common/exception.hpp>
#include <openvpn/log/log.hpp>
#include <openvpn/common/circ_list.hpp>
#include <openvpn/common/socktypes.hpp>
#include <openvpn/log/log.hpp>
#include <openvpn/time/time.hpp>
#include <openvpn/buffer/buffer.hpp>

View File

@ -37,7 +37,7 @@ namespace openvpn {
OPENVPN_EXCEPTION(route_error);
RouteListLinux(const OptionList& opt, const boost::asio::ip::address& server_addr_arg)
RouteListLinux(const OptionList& opt, const IP::Addr& server_addr_arg)
: stopped(false), rg_flags(0), did_redirect_gw(false), server_addr(server_addr_arg)
{
local_gateway = get_default_gateway();
@ -46,7 +46,7 @@ namespace openvpn {
{
const Option& o = opt.get("route-gateway");
o.exact_args(2);
route_gateway = validate_ip_address("route-gateway", o[1]);
route_gateway = IP::Addr::validate(o[1], "route-gateway");
}
// do redirect-gateway
@ -154,7 +154,7 @@ namespace openvpn {
bool stopped;
unsigned int rg_flags;
bool did_redirect_gw;
boost::asio::ip::address server_addr;
IP::Addr server_addr;
std::string route_gateway;
std::string local_gateway;
};

View File

@ -0,0 +1,246 @@
#ifndef OPENVPN_NETCONF_MAC_GWV4_H
#define OPENVPN_NETCONF_MAC_GWV4_H
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/route.h>
#include <net/if_dl.h>
#include <cstring>
#include <string>
#include <sstream>
#include <algorithm> // for std::max
#include <boost/cstdint.hpp> // for boost::uint32_t
#include <openvpn/common/exception.hpp>
#include <openvpn/common/hexstr.hpp>
#include <openvpn/common/scoped_fd.hpp>
#include <openvpn/common/scoped_ptr.hpp>
#include <openvpn/common/socktypes.hpp>
#include <openvpn/common/string.hpp>
#include <openvpn/addr/ip.hpp>
#include <openvpn/addr/macaddr.hpp>
#include <openvpn/log/log.hpp>
namespace openvpn {
class MacGatewayInfoV4
{
struct rtmsg {
struct rt_msghdr m_rtm;
char m_space[512];
};
# define OPENVPN_ROUNDUP(a) \
((a) > 0 ? (1 + (((a) - 1) | (sizeof(boost::uint32_t) - 1))) : sizeof(boost::uint32_t))
# define OPENVPN_NEXTADDR(w, u) \
if (rtm_addrs & (w)) { \
l = OPENVPN_ROUNDUP(u.sa_len); \
std::memmove(cp, &(u), l); \
cp += l; \
}
# define OPENVPN_ADVANCE(x, n) \
(x += OPENVPN_ROUNDUP((n)->sa_len))
public:
OPENVPN_EXCEPTION(route_gateway_error);
enum {
ADDR_DEFINED = (1<<0), /* set if gateway.addr defined */
NETMASK_DEFINED = (1<<1), /* set if gateway.netmask defined */
HWADDR_DEFINED = (1<<2), /* set if hwaddr is defined */
IFACE_DEFINED = (1<<3), /* set if iface is defined */
};
MacGatewayInfoV4()
: flags_(0)
{
struct rtmsg m_rtmsg;
ScopedFD sockfd;
int seq, l, pid, rtm_addrs, i;
struct sockaddr so_dst, so_mask;
char *cp = m_rtmsg.m_space;
struct sockaddr *gate = NULL, *ifp = NULL, *sa;
struct rt_msghdr *rtm_aux;
/* setup data to send to routing socket */
pid = ::getpid();
seq = 0;
rtm_addrs = RTA_DST | RTA_NETMASK | RTA_IFP;
std::memset(&m_rtmsg, 0, sizeof(m_rtmsg));
std::memset(&so_dst, 0, sizeof(so_dst));
std::memset(&so_mask, 0, sizeof(so_mask));
std::memset(&m_rtmsg.m_rtm, 0, sizeof(struct rt_msghdr));
m_rtmsg.m_rtm.rtm_type = RTM_GET;
m_rtmsg.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY;
m_rtmsg.m_rtm.rtm_version = RTM_VERSION;
m_rtmsg.m_rtm.rtm_seq = ++seq;
m_rtmsg.m_rtm.rtm_addrs = rtm_addrs;
so_dst.sa_family = AF_INET;
so_dst.sa_len = sizeof(struct sockaddr_in);
so_mask.sa_family = AF_INET;
so_mask.sa_len = sizeof(struct sockaddr_in);
OPENVPN_NEXTADDR(RTA_DST, so_dst);
OPENVPN_NEXTADDR(RTA_NETMASK, so_mask);
m_rtmsg.m_rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
/* transact with routing socket */
sockfd.reset(socket(PF_ROUTE, SOCK_RAW, 0));
if (!sockfd.defined())
throw route_gateway_error("GDG: socket #1 failed");
if (::write(sockfd(), (char *)&m_rtmsg, l) < 0)
throw route_gateway_error("GDG: problem writing to routing socket");
do {
l = ::read(sockfd(), (char *)&m_rtmsg, sizeof(m_rtmsg));
} while (l > 0 && (m_rtmsg.m_rtm.rtm_seq != seq || m_rtmsg.m_rtm.rtm_pid != pid));
sockfd.close();
/* extract return data from routing socket */
rtm_aux = &m_rtmsg.m_rtm;
cp = ((char *)(rtm_aux + 1));
if (rtm_aux->rtm_addrs)
{
for (i = 1; i; i <<= 1)
{
if (i & rtm_aux->rtm_addrs)
{
sa = (struct sockaddr *)cp;
if (i == RTA_GATEWAY )
gate = sa;
else if (i == RTA_IFP)
ifp = sa;
OPENVPN_ADVANCE(cp, sa);
}
}
}
else
return;
/* get gateway addr and interface name */
if (gate != NULL )
{
/* get default gateway addr */
gateway_.addr.reset_ipv4_from_uint32(ntohl(((struct sockaddr_in *)gate)->sin_addr.s_addr));
if (!gateway_.addr.unspecified())
flags_ |= ADDR_DEFINED;
if (ifp)
{
/* get interface name */
const struct sockaddr_dl *adl = (struct sockaddr_dl *) ifp;
const size_t len = adl->sdl_nlen;
if (len && len < sizeof(iface_))
{
std::memcpy (iface_, adl->sdl_data, len);
iface_[len] = '\0';
flags_ |= IFACE_DEFINED;
}
}
}
/* get netmask of interface that owns default gateway */
if (flags_ & IFACE_DEFINED) {
struct ifreq ifr;
sockfd.reset(socket(AF_INET, SOCK_DGRAM, 0));
if (!sockfd.defined())
throw route_gateway_error("GDG: socket #2 failed");
std::memset(&ifr, 0, sizeof(ifr));
ifr.ifr_addr.sa_family = AF_INET;
string::strncpynt(ifr.ifr_name, iface_, IFNAMSIZ);
if (::ioctl(sockfd(), SIOCGIFNETMASK, (char *)&ifr) < 0)
throw route_gateway_error("GDG: ioctl #1 failed");
sockfd.close();
gateway_.netmask.reset_ipv4_from_uint32(ntohl(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr));
flags_ |= NETMASK_DEFINED;
}
/* try to read MAC addr associated with interface that owns default gateway */
if (flags_ & IFACE_DEFINED)
{
struct ifconf ifc;
struct ifreq *ifr;
const int bufsize = 4096;
ScopedPtr<char> buffer(new char[bufsize]);
std::memset(buffer.get(), 0, bufsize);
sockfd.reset(socket(AF_INET, SOCK_DGRAM, 0));
if (!sockfd.defined())
throw route_gateway_error("GDG: socket #3 failed");
ifc.ifc_len = bufsize;
ifc.ifc_buf = buffer.get();
if (::ioctl(sockfd(), SIOCGIFCONF, (char *)&ifc) < 0)
throw route_gateway_error("GDG: ioctl #2 failed");
sockfd.close();
for (cp = buffer.get(); cp <= buffer.get() + ifc.ifc_len - sizeof(struct ifreq); )
{
ifr = (struct ifreq *)cp;
const size_t len = sizeof(ifr->ifr_name) + std::max(sizeof(ifr->ifr_addr), size_t(ifr->ifr_addr.sa_len));
if (!ifr->ifr_addr.sa_family)
break;
if (!::strncmp(ifr->ifr_name, iface_, IFNAMSIZ))
{
if (ifr->ifr_addr.sa_family == AF_LINK)
{
struct sockaddr_dl *sdl = (struct sockaddr_dl *)&ifr->ifr_addr;
hwaddr_.reset((const unsigned char *)LLADDR(sdl));
flags_ |= HWADDR_DEFINED;
}
}
cp += len;
}
}
}
# undef OPENVPN_ROUNDUP
# undef OPENVPN_NEXTADDR
# undef OPENVPN_ADVANCE
std::string info() const
{
std::ostringstream os;
os << "GATEWAY";
if (flags_ & ADDR_DEFINED)
{
os << " ADDR=" << gateway_.addr;
if (flags_ & NETMASK_DEFINED)
{
os << '/' << gateway_.netmask;
}
}
if (flags_ & IFACE_DEFINED)
os << " IFACE=" << iface_;
if (flags_ & HWADDR_DEFINED)
os << " HWADDR=" << hwaddr_;
return os.str();
}
unsigned int flags() const { return flags_; }
const IP::Addr& gateway_addr() const { return gateway_.addr; }
const IP::Addr& gateway_netmask() const { return gateway_.netmask; }
std::string iface() const { return iface_; }
const MACAddr& hwaddr() const { return hwaddr_; }
private:
unsigned int flags_;
IP::AddrMaskPair gateway_;
char iface_[16];
MACAddr hwaddr_;
};
} // namespace openvpn
#endif // OPENVPN_NETCONF_MAC_GWV4_H

View File

@ -1,11 +1,10 @@
#ifndef OPENVPN_NETCONF_MAC_ROUTE_H
#define OPENVPN_NETCONF_MAC_ROUTE_H
#include <cstring>
#include <string>
#include <sstream>
#include <boost/lexical_cast.hpp>
#include <openvpn/common/rc.hpp>
#include <openvpn/common/exception.hpp>
#include <openvpn/common/options.hpp>
@ -15,6 +14,7 @@
#include <openvpn/common/hexstr.hpp>
#include <openvpn/addr/ip.hpp>
#include <openvpn/log/log.hpp>
#include <openvpn/netconf/mac/gwv4.hpp>
namespace openvpn {
@ -37,7 +37,7 @@ namespace openvpn {
OPENVPN_EXCEPTION(route_error);
RouteListMac(const OptionList& opt, const boost::asio::ip::address& server_addr_arg)
RouteListMac(const OptionList& opt, const IP::Addr& server_addr_arg)
: stopped(false), rg_flags(0), did_redirect_gw(false), server_addr(server_addr_arg)
{
local_gateway = get_default_gateway();
@ -46,7 +46,7 @@ namespace openvpn {
{
const Option& o = opt.get("route-gateway");
o.exact_args(2);
route_gateway = validate_ip_address("route-gateway", o[1]);
route_gateway = IP::Addr::from_string(o[1], "route-gateway");
}
// do redirect-gateway
@ -69,9 +69,7 @@ namespace openvpn {
}
if (rg_flags & RG_ENABLE)
{
add_del_route(true, server_addr.to_string(), "255.255.255.255", local_gateway);
add_del_route(true, "0.0.0.0", "128.0.0.0", route_gateway);
add_del_route(true, "128.0.0.0", "128.0.0.0", route_gateway);
add_del_reroute_gw_v4(true);
did_redirect_gw = true;
}
}
@ -83,9 +81,7 @@ namespace openvpn {
{
if (did_redirect_gw)
{
add_del_route(false, server_addr.to_string(), "255.255.255.255", local_gateway);
add_del_route(false, "0.0.0.0", "128.0.0.0", route_gateway);
add_del_route(false, "128.0.0.0", "128.0.0.0", route_gateway);
add_del_reroute_gw_v4(false);
did_redirect_gw = false;
}
stopped = true;
@ -97,35 +93,47 @@ namespace openvpn {
stop();
}
static std::string get_default_gateway()
static const IP::Addr& get_default_gateway()
{
return "10.10.0.1"; // fixme
MacGatewayInfoV4 gw; // fixme: handle IPv6
return gw.gateway_addr();
}
private:
int add_del_route(const bool add,
const std::string& net,
const std::string& mask,
const std::string& gw)
void add_del_reroute_gw_v4(const bool add)
{
std::ostringstream cmd;
cmd << "/sbin/route";
if (add)
cmd << " add";
else
cmd << " delete";
cmd << " -net " << net << ' ' << gw << ' ' << mask;
const std::string cmd_str = cmd.str();
OPENVPN_LOG(cmd_str);
return ::system(cmd_str.c_str());
const IP::Addr a_255_255_255_255 = IP::Addr::from_string("255.255.255.255");
const IP::Addr a_0_0_0_0 = IP::Addr::from_string("0.0.0.0");
const IP::Addr a_128_0_0_0 = IP::Addr::from_string("128.0.0.0");
add_del_route(add, server_addr, a_255_255_255_255, local_gateway);
add_del_route(add, a_0_0_0_0, a_128_0_0_0, route_gateway);
add_del_route(add, a_128_0_0_0, a_128_0_0_0, route_gateway);
}
int add_del_route(const bool add,
const IP::Addr& net,
const IP::Addr& mask,
const IP::Addr& gw)
{
std::ostringstream cmd;
cmd << "/sbin/route";
if (add)
cmd << " add";
else
cmd << " delete";
cmd << " -net " << net << ' ' << gw << ' ' << mask;
const std::string cmd_str = cmd.str();
OPENVPN_LOG(cmd_str);
return ::system(cmd_str.c_str());
}
bool stopped;
unsigned int rg_flags;
bool did_redirect_gw;
boost::asio::ip::address server_addr;
std::string route_gateway;
std::string local_gateway;
IP::Addr server_addr;
IP::Addr route_gateway;
IP::Addr local_gateway;
};
} // namespace openvpn

View File

@ -5,6 +5,7 @@
#include <algorithm>
#include <limits>
#include <openvpn/common/socktypes.hpp>
#include <openvpn/buffer/buffer.hpp>
#include <openvpn/crypto/packet_id.hpp>
#include <openvpn/reliable/relcommon.hpp>

View File

@ -13,6 +13,7 @@
#include <openvpn/common/hexstr.hpp>
#include <openvpn/common/options.hpp>
#include <openvpn/common/mode.hpp>
#include <openvpn/common/socktypes.hpp>
#include <openvpn/log/log.hpp>
#include <openvpn/buffer/buffer.hpp>
#include <openvpn/time/time.hpp>

View File

@ -7,6 +7,7 @@
#include <openvpn/common/exception.hpp>
#include <openvpn/common/rc.hpp>
#include <openvpn/addr/ip.hpp>
namespace openvpn {
@ -19,7 +20,7 @@ namespace openvpn {
virtual bool transport_send_const(const Buffer& buf) = 0;
virtual bool transport_send(BufferAllocated& buf) = 0;
virtual std::string server_endpoint_render() const = 0;
virtual boost::asio::ip::address server_endpoint_addr() const = 0;
virtual IP::Addr server_endpoint_addr() const = 0;
};
struct TransportClientParent

View File

@ -77,9 +77,9 @@ namespace openvpn {
return os.str();
}
virtual boost::asio::ip::address server_endpoint_addr() const
virtual IP::Addr server_endpoint_addr() const
{
return server_endpoint.address();
return IP::Addr::from_asio(server_endpoint.address());
}
virtual void stop() { stop_(); }

View File

@ -15,7 +15,7 @@ namespace openvpn {
std::string name;
bool ipv6;
bool tap;
Layer layer;
int txqueuelen;
unsigned int mtu;
@ -32,7 +32,7 @@ namespace openvpn {
TunClientParent& parent);
private:
ClientConfig()
: ipv6(false), tap(false), txqueuelen(200), mtu(1500), n_parallel(8) {}
: ipv6(false), txqueuelen(200), mtu(1500), n_parallel(8) {}
};
class Client : public TunClient
@ -56,7 +56,7 @@ namespace openvpn {
config->stats,
config->name,
config->ipv6,
config->tap,
config->layer,
config->txqueuelen
));
impl->start(config->n_parallel);

View File

@ -24,6 +24,7 @@
#include <openvpn/log/protostats.hpp>
#include <openvpn/tun/tunspec.hpp>
#include <openvpn/tun/tunlog.hpp>
#include <openvpn/tun/layer.hpp>
namespace openvpn {
namespace TunLinux {
@ -36,6 +37,7 @@ namespace openvpn {
// exceptions
OPENVPN_EXCEPTION(tun_open_error);
OPENVPN_EXCEPTION(tun_layer_error);
OPENVPN_EXCEPTION(tun_ioctl_error);
OPENVPN_EXCEPTION(tun_fcntl_error);
OPENVPN_EXCEPTION(tun_name_error);
@ -53,7 +55,7 @@ namespace openvpn {
const ProtoStats::Ptr& stats_arg,
const std::string name,
const bool ipv6,
const bool tap,
const Layer& layer,
const int txqueuelen)
: halt(false),
@ -71,10 +73,12 @@ namespace openvpn {
ifr.ifr_flags = IFF_ONE_QUEUE;
if (!ipv6)
ifr.ifr_flags |= IFF_NO_PI;
if (tap)
if (layer() == Layer::OSI_LAYER_3)
ifr.ifr_flags |= IFF_TUN;
else if (layer() == Layer::OSI_LAYER_2)
ifr.ifr_flags |= IFF_TAP;
else
ifr.ifr_flags |= IFF_TUN;
throw tun_layer_error("unknown OSI layer");
if (!name.empty())
{
if (name.length() < IFNAMSIZ)
@ -172,8 +176,8 @@ namespace openvpn {
{
const Option& o = opt.get("ifconfig");
o.exact_args(3);
std::string ip = validate_ip_address("ifconfig-ip", o[1]);
std::string mask = validate_ip_address("ifconfig-net", o[2]);
std::string ip = IP::Addr::validate(o[1], "ifconfig-ip");
std::string mask = IP::Addr::validate(o[2], "ifconfig-net");
std::ostringstream cmd;
cmd << "/sbin/ifconfig " << name() << ' ' << ip << " netmask " << mask << " mtu " << mtu;
const std::string cmd_str = cmd.str();

View File

@ -13,7 +13,7 @@ namespace openvpn {
public:
typedef boost::intrusive_ptr<ClientConfig> Ptr;
bool tap;
Layer layer;
unsigned int mtu;
int n_parallel;
@ -29,7 +29,7 @@ namespace openvpn {
TunClientParent& parent);
private:
ClientConfig()
: tap(false), mtu(1500), n_parallel(8) {}
: mtu(1500), n_parallel(8) {}
};
class Client : public TunClient
@ -51,7 +51,7 @@ namespace openvpn {
this,
config->frame,
config->stats,
config->tap
config->layer
));
impl->start(config->n_parallel);

View File

@ -21,6 +21,7 @@
#include <openvpn/log/protostats.hpp>
#include <openvpn/tun/tunspec.hpp>
#include <openvpn/tun/tunlog.hpp>
#include <openvpn/tun/layer.hpp>
namespace openvpn {
namespace TunMac {
@ -33,6 +34,7 @@ namespace openvpn {
// exceptions
OPENVPN_EXCEPTION(tun_open_error);
OPENVPN_EXCEPTION(tun_layer_error);
OPENVPN_EXCEPTION(tun_fcntl_error);
template <typename ReadHandler>
@ -45,7 +47,7 @@ namespace openvpn {
ReadHandler read_handler_arg,
const Frame::Ptr& frame_arg,
const ProtoStats::Ptr& stats_arg,
const bool tap)
const Layer& layer)
: halt(false),
read_handler(read_handler_arg),
@ -55,10 +57,12 @@ namespace openvpn {
for (int i = 0; i < 256; ++i)
{
std::ostringstream node;
if (tap)
if (layer() == Layer::OSI_LAYER_3)
node << "tun";
else if (layer() == Layer::OSI_LAYER_2)
node << "tap";
else
node << "tun";
throw tun_layer_error("unknown OSI layer");
node << i;
const std::string node_str = node.str();
const std::string node_fn = "/dev/" + node_str;
@ -77,7 +81,7 @@ namespace openvpn {
}
}
OPENVPN_THROW(tun_open_error, "error opening Mac " << (tap ? "tap" : "tun") << " device");
OPENVPN_THROW(tun_open_error, "error opening Mac " << layer.dev_type() << " device");
}
bool write(const Buffer& buf)
@ -128,6 +132,8 @@ namespace openvpn {
int ifconfig(const OptionList& opt, const unsigned int mtu) // fixme -- support IPv6
{
int status = 0;
// first verify topology
{
const Option& o = opt.get("topology");
@ -140,24 +146,26 @@ namespace openvpn {
{
const Option& o = opt.get("ifconfig");
o.exact_args(3);
std::string ip = validate_ip_address("ifconfig-ip", o[1]);
std::string mask = validate_ip_address("ifconfig-net", o[2]);
const IP::Addr ip = IP::Addr::from_string(o[1], "ifconfig-ip");
const IP::Addr mask = IP::Addr::from_string(o[2], "ifconfig-net");
{
std::ostringstream cmd;
cmd << "/sbin/ifconfig " << name() << ' ' << ip << ' ' << ip << " netmask " << mask << " mtu " << mtu << " up";
const std::string cmd_str = cmd.str();
OPENVPN_LOG_TUN(cmd_str);
const int status = ::system(cmd_str.c_str());
}
{
std::ostringstream cmd;
cmd << "/sbin/route add -net 5.5.8.0 " << ip << ' ' << mask; // fixme
const std::string cmd_str = cmd.str();
OPENVPN_LOG_TUN(cmd_str);
const int status = ::system(cmd_str.c_str());
status = ::system(cmd_str.c_str());
}
if (!status)
{
std::ostringstream cmd;
const IP::Addr net = ip & mask;
cmd << "/sbin/route add -net " << net << ' ' << ip << ' ' << mask;
const std::string cmd_str = cmd.str();
OPENVPN_LOG_TUN(cmd_str);
status = ::system(cmd_str.c_str());
}
}
return 0; // fixme -- maybe return system() status
return status;
}
~Tun() { stop(); }
@ -193,7 +201,6 @@ namespace openvpn {
}
else
{
::sleep(1);
OPENVPN_LOG_TUN_ERROR("TUN Read Error: " << error);
stats->error(ProtoStats::TUN_ERROR);
}