Net::Route (windows compile)

Net::Route (windows compile only)
This commit is contained in:
aleks-f
2012-11-04 23:25:57 -06:00
parent eb8c662c4c
commit 325a98a91f
13 changed files with 1983 additions and 432 deletions

View File

@@ -131,7 +131,7 @@ public:
#endif
void setUp(bool up);
void setMtu(unsigned mtu);
void setMTU(unsigned mtu);
void setType(Type type);
void setIndex(unsigned index);
void setPhyParams();
@@ -227,7 +227,7 @@ void NetworkInterfaceImpl::setPhyParams()
setFlags(ifr.ifr_flags);
ds.impl()->ioctl(SIOCGIFMTU, &ifr);
setMtu(ifr.ifr_mtu);
setMTU(ifr.ifr_mtu);
#endif
}
@@ -466,7 +466,7 @@ inline void NetworkInterfaceImpl::setUp(bool up)
}
inline void NetworkInterfaceImpl::setMtu(unsigned mtu)
inline void NetworkInterfaceImpl::setMTU(unsigned mtu)
{
_mtu = mtu;
}
@@ -1011,7 +1011,7 @@ NetworkInterface::Map NetworkInterface::map(bool ipOnly, bool upOnly)
ifIt = result.insert(Map::value_type(ifIndex, ni)).first;
ifIt->second.impl().setFlags(pAddress->Flags, pAddress->IfType);
ifIt->second.impl().setMtu(pAddress->Mtu);
ifIt->second.impl().setMTU(pAddress->Mtu);
ifIt->second.impl().setUp(pAddress->OperStatus == IfOperStatusUp);
#if (_WIN32_WINNT >= 0x0600) // Vista and newer only
ifIt->second.impl().setRunning(pAddress->ReceiveLinkSpeed > 0 || pAddress->TransmitLinkSpeed > 0);

263
Net/src/Route.cpp Normal file
View File

@@ -0,0 +1,263 @@
//
// Route.cpp
//
// $Id: //poco/1.4/Foundation/src/Route.cpp#2 $
//
// Library: Net
// Package: NetCore
// Module: Route
//
// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#include "Poco/Net/Route.h"
#ifdef POCO_NET_HAS_ROUTE
#include "Poco/Net/IPAddress.h"
#include "Poco/Net/NetException.h"
#include <iphlpapi.h>
#if defined(POCO_OS_FAMILY_WINDOWS)
#include "Route_WIN32.cpp"
#elif defined(POCO_OS_FAMILY_BSD)
#include "Route_BSD.cpp"
#elif defined(POCO_OS_FAMILY_UNIX) && (POCO_OS == POCO_OS_LINUX)
#include "Route_Linux.cpp"
#endif
namespace Poco {
namespace Net {
Route::Route(const IPAddress& dst, const IPAddress& netmask, const IPAddress& nextHop, unsigned ifIndex, RouteType type) :
_dst(dst),
_netmask(netmask),
_nextHop(nextHop),
_ifIndex(ifIndex),
_type(type),
// attributes that might not be available on all platforms are set to sentinel values.
_metric(~0),
_hops(~0),
_mtu(0),
_use(~1),
_proto(ROUTE_PROTO_NONE),
_created(0)
{
if (_dst.family() != _nextHop.family())
throw InvalidArgumentException("Destination and nextHop have different families");
}
Route::Route(const IPAddress& dst, const IPAddress& netmask, unsigned ifIndex, RouteType type) :
_dst(dst),
_netmask(netmask),
_nextHop(IPAddress(dst.family())),
_ifIndex(ifIndex),
_type(type),
// attributes that might not be available on all platforms are set to sentinel values.
_metric(~0),
_hops(~0),
_mtu(0),
_use(~1),
_proto(ROUTE_PROTO_NONE),
_created(0)
{
if (_dst.family() != _nextHop.family())
throw InvalidArgumentException("Destination and nextHop have different families");
}
Route::Route(const IPAddress& dst, unsigned prefix, const IPAddress& nextHop, unsigned ifIndex, RouteType type) :
_dst(dst),
_netmask(IPAddress(prefix, dst.family())),
_nextHop(nextHop),
_ifIndex(ifIndex),
_type(type),
// attributes that might not be available on all platforms are set to sentinel values.
_metric(~0),
_hops(~0),
_mtu(0),
_use(~1),
_proto(ROUTE_PROTO_NONE),
_created(0)
{
if (_dst.family() != _nextHop.family())
throw InvalidArgumentException("Destination and nextHop have different families");
}
Route::Route(const IPAddress& dst, unsigned prefix, unsigned ifIndex, RouteType type) :
_dst(dst),
_netmask(IPAddress(prefix, dst.family())),
_nextHop(IPAddress(dst.family())),
_ifIndex(ifIndex),
_type(type),
// attributes that might not be available on all platforms are set to sentinel values.
_metric(~0),
_hops(~0),
_mtu(0),
_use(~1),
_proto(ROUTE_PROTO_NONE),
_created(0)
{
if (_dst.family() != _nextHop.family())
throw InvalidArgumentException("Destination and nextHop have different families");
}
Route::~Route()
{
}
std::time_t Route::getAge() const
{
std::time_t now = std::time(NULL);
return ((_created != 0) ? (now - _created.epochTime()) : 0);
}
void Route::setAge(std::time_t created)
{
std::time_t now;
time(&now);
if (_created > now)
throw std::invalid_argument("Creation time can't be in future");
_created = Timestamp::fromEpochTime(created);
}
void Route::setProto(RouteProto proto)
{
#if defined(_WIN32)
if (proto > ROUTE_PROTO_BGP) proto = ROUTE_PROTO_OTHER;
#endif
_proto = proto;
}
Route::RouteList Route::defaults(IPAddress::Family family)
{
Route::RouteList defaults, routes = Route::list(family);
for (Route::RouteList::const_iterator it = routes.begin();
it != routes.end(); it++) {
if (it->getPrefix() != 0) continue;
// look for insertion point
Route::RouteList::iterator it2 = defaults.begin();
Route::RouteList::const_iterator end = defaults.end();
while (it2 != end && it2->getMetric() <= it->getMetric())
it2++;
defaults.insert(it2, *it);
}
return defaults;
}
Route::RouteList Route::match(IPAddress target)
{
Route::RouteList targets, routes = Route::list(target.family());
for (Route::RouteList::const_iterator it = routes.begin();
it != routes.end(); it++) {
if ((target & it->getNetmask()) != it->getDest()) continue;
// look for insertion point
Route::RouteList::iterator it2 = targets.begin();
while (it2 != targets.end()
&& (it2->getPrefix() > it->getPrefix()
|| (it2->getPrefix() == it->getPrefix() && it2->getMetric() <= it->getMetric())))
it2++;
targets.insert(it2, *it);
}
return targets;
}
const IPAddress Route::getDefaultAddress(IPAddress::Family family)
{
Route::RouteList routes = Route::defaults(family);
if (! routes.empty()) {
Route::RouteList::const_iterator it = routes.begin();
IPAddress addr = it->getNetworkInterface().firstAddress(family);
return addr;
}
return IPAddress::wildcard(family);
}
std::string Route::protocolName(Route::RouteProto proto)
{
switch (proto) {
default:
return "unknown";
case ROUTE_PROTO_OTHER:
return "other";
case ROUTE_PROTO_LOCAL:
return "local";
case ROUTE_PROTO_NET_MGMT:
return "netmgmt";
case ROUTE_PROTO_ICMP:
return "icmp";
case ROUTE_PROTO_EGP:
return "egp";
case ROUTE_PROTO_GGP:
return "ggp";
case ROUTE_PROTO_HELLO:
return "hello";
case ROUTE_PROTO_RIP:
return "rip";
case ROUTE_PROTO_ISIS:
return "isis";
case ROUTE_PROTO_ESIS:
return "esis";
case ROUTE_PROTO_CISCO:
return "cisco";
case ROUTE_PROTO_BBN:
return "bbn";
case ROUTE_PROTO_OSPF:
return "ospf";
case ROUTE_PROTO_BGP:
return "bgp";
}
}
}} // namespace Poco::Net
#endif // POCO_NET_HAS_ROUTE

237
Net/src/Route_BSD.cpp Normal file
View File

@@ -0,0 +1,237 @@
//
// Route_BSD.cpp
//
// $Id: //poco/1.4/Foundation/src/Route_BSD.cpp#2 $
//
// Library: Net
// Package: NetCore
// Module: Route
//
// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/route.h>
#include <sys/sysctl.h>
#include <netinet/in.h>
#include <string>
#define RTMSG_LEN (sizeof(struct rt_msghdr) + 512)
#define ROUNDUP(a) ((a) > 0 ? (((a) + sizeof(uint32_t) - 1) & ~(sizeof(uint32_t) - 1)) : sizeof(long))
#define NEXTADDR(w, u) \
if (rtm_addrs & (w)) {\
int l = ROUNDUP(u.sin_len); memmove(cp, &(u), l); cp += l;\
}
#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
#define SIN_OFFSET (offsetof(sockaddr_in,sin_addr))
#define SIN_LENGTH (sizeof(struct in_addr))
#define SIN6_OFFSET (offsetof(sockaddr_in6,sin6_addr))
#define SIN6_LENGTH (sizeof(struct in6_addr))
static int seq = rand();
static void get_rtaddrs(unsigned addrs, struct sockaddr *sa, struct sockaddr **rti_info)
{
for (unsigned i = 0; i < RTAX_MAX; i++) {
if (addrs & (1 << i)) {
rti_info[i] = sa;
sa = (struct sockaddr *)((char *)sa + ROUNDUP(sa->sa_len));
} else {
rti_info[i] = NULL;
}
}
}
static IPAddress unpack_sockaddr_inX(struct sockaddr *sa, bool ipv4)
{
const unsigned offset = (ipv4 ? SIN_OFFSET : SIN6_OFFSET);
unsigned char *addr = (unsigned char*)sa + offset;
// return wildcard
if (sa->sa_len == 0)
return IPAddress(ipv4 ? IPAddress::IPv4 : IPAddress::IPv6);
struct in6_addr buf;
memset(&buf, 0, sizeof(buf));
memcpy(&buf, addr, sa->sa_len - offset);
IPAddress ip(&buf, (ipv4 ? SIN_LENGTH : SIN6_LENGTH));
return ip;
}
class RouteHelper {
public:
static Route* createRoute(struct rt_msghdr2 *rtm, struct sockaddr **rti_info);
private:
RouteHelper();
~RouteHelper();
};
Route* RouteHelper::createRoute(struct rt_msghdr2 *rtm, struct sockaddr **rti_info)
{
IPAddress dest, netmask, nexthop;
int ifIndex = rtm->rtm_index;
bool adjacent = false;
sa_family_t family = AF_MAX;
char macaddr[16]; // should be plenty, right?
for (unsigned i = 0; i < RTAX_MAX; i++) {
sockaddr* sa = (struct sockaddr*)rti_info[i];
if (sa == NULL) continue;
switch (i) {
case RTAX_DST:
poco_assert(sa->sa_family == AF_INET || sa->sa_family == AF_INET6);
family = sa->sa_family;
if (family == AF_INET) {
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
dest = IPAddress(&sin->sin_addr, SIN_LENGTH);
} else {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
dest = IPAddress(&sin6->sin6_addr, SIN6_LENGTH, rtm->rtm_index);
}
break;
case RTAX_GATEWAY:
poco_assert((sa->sa_family == family || sa->sa_family == AF_LINK));
switch (sa->sa_family) {
case AF_INET:
{
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
nexthop = IPAddress(&sin->sin_addr, SIN_LENGTH);
break;
}
case AF_INET6:
{
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
nexthop = IPAddress(&sin6->sin6_addr, SIN6_LENGTH, rtm->rtm_index);
break;
}
case AF_LINK:
{
struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
adjacent = true;
ifIndex = sdl->sdl_index;
memcpy(macaddr, sdl->sdl_data, sdl->sdl_alen);
break;
}
default:
break;
}
break;
case RTAX_NETMASK:
netmask = unpack_sockaddr_inX(sa, (family == AF_INET));
break;
case RTAX_GENMASK:
// IPAddress genmask = unpack_sockaddr_inX(sa, (family == AF_INET));
break;
default:
// do something?
break;
}
}
if (rtm->rtm_flags & RTF_HOST) {
poco_assert(! (rtm->rtm_addrs & RTA_NETMASK));
if (family == AF_INET)
netmask = IPAddress(32, IPAddress::IPv4);
else
netmask = IPAddress(128, IPAddress::IPv6);
}
Route *route;
if (adjacent)
route = new Route(dest, netmask, ifIndex, Route::ROUTE_DIRECT);
else
route = new Route(dest, netmask, nexthop, ifIndex, Route::ROUTE_INDIRECT);
route->setMTU(rtm->rtm_rmx.rmx_mtu);
route->setHops(rtm->rtm_rmx.rmx_hopcount);
route->setUsage(rtm->rtm_use);
return route;
}
Route::RouteList Route::list(IPAddress::Family family)
{
Route::RouteList routes;
int mib[6];
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = mib[3] = 0;
mib[4] = NET_RT_DUMP2;
mib[5] = 0;
size_t needed = 0;
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
throw std::runtime_error("sysctl failed to return routing table size");;
char *buf = new char[needed];
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
throw std::runtime_error("sysctl faield to populate routing table");
struct rt_msghdr2 *rtm = NULL;
for (char *next = buf, *lim = &buf[needed]; next < lim; next += rtm->rtm_msglen) {
rtm = (struct rt_msghdr2 *)next;
struct sockaddr_in *sin = (struct sockaddr_in*)(rtm + 1);
if (sin->sin_family != ((family == IPAddress::IPv4) ? AF_INET : AF_INET6)) continue;
// skip cloned routes
if (rtm->rtm_parentflags & RTF_PRCLONING) continue;
struct sockaddr* rti_info[RTAX_MAX];
get_rtaddrs(rtm->rtm_addrs, (struct sockaddr *)sin, rti_info);
Route *route = RouteHelper::createRoute(rtm, rti_info);
// RTF_IFSCOPE?
routes.push_back(route);
}
delete[] buf;
return routes;
}

332
Net/src/Route_Linux.cpp Normal file
View File

@@ -0,0 +1,332 @@
//
// Route_Linux.cpp
//
// $Id: //poco/1.4/Foundation/src/Route_Linux.cpp#2 $
//
// Library: Net
// Package: NetCore
// Module: Route
//
// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#include <time.h>
#include <string.h>
#include <arpa/inet.h>
#include <net/route.h>
#include <linux/if.h>
#include <libmnl/libmnl.h>
#include <linux/rtnetlink.h>
class RouteHelper
{
public:
static void createRouteIPv4(Route::RouteList *routes, struct rt_container *rt_stuff);
static void createRouteIPv6(Route::RouteList *routes, struct rt_container *rt_stuff);
private:
RouteHelper();
~RouteHelper();
};
typedef union
{
struct in_addr u_in;
struct in6_addr u_in6;
} in_addrX;
#define in4 u_in
#define in6 u_in6
struct rt_container
{
const struct nlattr *tb[RTA_MAX+1];
in_addrX gw;
in_addrX dest;
in_addrX src;
in_addrX prefsrc;
uint32_t oif, flow, priority;
unsigned char family;
unsigned char prefix;
unsigned char table;
unsigned char protocol;
unsigned char scope;
unsigned char type;
uint32_t metrics[RTA_MAX+1];
};
static inline bool in6zero(struct in6_addr in6)
{
return ((in6.s6_addr32[0] | in6.s6_addr32[1] | in6.s6_addr32[2] | in6.s6_addr32[3]) == 0);
}
static Route::RouteProto xlateProto(unsigned prot)
{
switch (prot) {
default:
// fallthru
case RTPROT_UNSPEC:
return Route::ROUTE_PROTO_OTHER;
case RTPROT_REDIRECT:
return Route::ROUTE_PROTO_ICMP;
case RTPROT_KERNEL:
case RTPROT_BOOT:
case RTPROT_STATIC:
return Route::ROUTE_PROTO_LOCAL;
// others?
}
}
void RouteHelper::createRouteIPv4(Route::RouteList *routes, struct rt_container *rt_stuff)
{
if (rt_stuff->table == RT_TABLE_MAIN && rt_stuff->type <= RTN_MULTICAST) {
Route *route;
if (rt_stuff->gw.in4.s_addr != 0)
route = new Route(IPAddress(&rt_stuff->dest.in4, sizeof(rt_stuff->dest.in4)), IPAddress(rt_stuff->prefix, IPAddress::IPv4), IPAddress(&rt_stuff->gw.in4, sizeof(rt_stuff->gw.in4)), rt_stuff->oif, Route::ROUTE_INDIRECT);
else
route = new Route(IPAddress(&rt_stuff->dest.in4, sizeof(rt_stuff->dest.in4)), IPAddress(rt_stuff->prefix, IPAddress::IPv4), rt_stuff->oif, Route::ROUTE_DIRECT);
route->setProto(xlateProto(rt_stuff->protocol));
route->setMetric(rt_stuff->metrics[0]);
// route->setPriority(rt_stuff->priority);
// no hops, usage, mtu, or age...
routes->push_back(route);
}
}
void RouteHelper::createRouteIPv6(Route::RouteList *routes, struct rt_container *rt_stuff)
{
if (rt_stuff->table == RT_TABLE_MAIN && rt_stuff->type <= RTN_MULTICAST) {
Route *route;
if (!in6zero(rt_stuff->gw.in6))
route = new Route(IPAddress(&rt_stuff->dest.in6, sizeof(rt_stuff->dest.in6)), IPAddress(rt_stuff->prefix, IPAddress::IPv6), IPAddress(&rt_stuff->gw.in6, sizeof(rt_stuff->gw.in6), rt_stuff->oif), rt_stuff->oif, Route::ROUTE_INDIRECT);
else
route = new Route(IPAddress(&rt_stuff->dest.in6, sizeof(rt_stuff->dest.in6)), IPAddress(rt_stuff->prefix, IPAddress::IPv6), rt_stuff->oif, Route::ROUTE_DIRECT);
route->setProto(xlateProto(rt_stuff->protocol));
route->setMetric(rt_stuff->metrics[0]);
// route->setPriority(rt_stuff->priority);
// no hops, usage, mtu, or age...
routes->push_back(route);
}
}
static int data_attr_cb2(const struct nlattr *attr, void *)
{
// skip unsupported attribute in user-space
if (mnl_attr_type_valid(attr, RTAX_MAX) < 0)
return MNL_CB_OK;
if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
return MNL_CB_ERROR;
return MNL_CB_OK;
}
static void parse_attrs_ipv4(struct rt_container *rt_stuff)
{
if (rt_stuff->tb[RTA_TABLE])
rt_stuff->table = mnl_attr_get_u32(rt_stuff->tb[RTA_TABLE]);
if (rt_stuff->tb[RTA_DST])
rt_stuff->dest.in4 = *(struct in_addr *)mnl_attr_get_payload(rt_stuff->tb[RTA_DST]);
if (rt_stuff->tb[RTA_SRC])
rt_stuff->src.in4 = *(struct in_addr *)mnl_attr_get_payload(rt_stuff->tb[RTA_SRC]);
if (rt_stuff->tb[RTA_OIF])
rt_stuff->oif = mnl_attr_get_u32(rt_stuff->tb[RTA_OIF]);
if (rt_stuff->tb[RTA_FLOW])
rt_stuff->flow = mnl_attr_get_u32(rt_stuff->tb[RTA_FLOW]);
if (rt_stuff->tb[RTA_PRIORITY])
rt_stuff->priority = mnl_attr_get_u32(rt_stuff->tb[RTA_PRIORITY]);
if (rt_stuff->tb[RTA_PREFSRC])
rt_stuff->prefsrc.in4 = *(struct in_addr *)mnl_attr_get_payload(rt_stuff->tb[RTA_PREFSRC]);
if (rt_stuff->tb[RTA_GATEWAY])
rt_stuff->gw.in4 = *(struct in_addr *)mnl_attr_get_payload(rt_stuff->tb[RTA_GATEWAY]);
if (rt_stuff->tb[RTA_METRICS]) {
struct nlattr *tbx[RTAX_MAX+1] = {};
mnl_attr_parse_nested(rt_stuff->tb[RTA_METRICS], data_attr_cb2, tbx);
for (unsigned i = 0; i < RTAX_MAX; ++i)
if (tbx[i])
rt_stuff->metrics[i] = mnl_attr_get_u32(tbx[i]);
}
}
static void parse_attrs_ipv6(struct rt_container *rt_stuff)
{
if (rt_stuff->tb[RTA_TABLE])
rt_stuff->table = mnl_attr_get_u32(rt_stuff->tb[RTA_TABLE]);
if (rt_stuff->tb[RTA_DST])
memcpy(&rt_stuff->dest.in6, (struct in6_addr *)mnl_attr_get_payload(rt_stuff->tb[RTA_DST]), sizeof(struct in6_addr));
if (rt_stuff->tb[RTA_SRC])
memcpy(&rt_stuff->src.in6, (struct in_addr *)mnl_attr_get_payload(rt_stuff->tb[RTA_SRC]), sizeof(struct in6_addr));
if (rt_stuff->tb[RTA_OIF])
rt_stuff->oif = mnl_attr_get_u32(rt_stuff->tb[RTA_OIF]);
if (rt_stuff->tb[RTA_FLOW])
rt_stuff->flow = mnl_attr_get_u32(rt_stuff->tb[RTA_FLOW]);
if (rt_stuff->tb[RTA_PRIORITY])
rt_stuff->priority = mnl_attr_get_u32(rt_stuff->tb[RTA_PRIORITY]);
if (rt_stuff->tb[RTA_PREFSRC])
memcpy(&rt_stuff->prefsrc.in6, (struct in_addr *)mnl_attr_get_payload(rt_stuff->tb[RTA_PREFSRC]), sizeof(struct in6_addr));
if (rt_stuff->tb[RTA_GATEWAY])
memcpy(&rt_stuff->gw.in6, (struct in_addr *)mnl_attr_get_payload(rt_stuff->tb[RTA_GATEWAY]), sizeof(struct in6_addr));
if (rt_stuff->tb[RTA_METRICS]) {
struct nlattr *tbx[RTAX_MAX+1] = {};
mnl_attr_parse_nested(rt_stuff->tb[RTA_METRICS], data_attr_cb2, tbx);
for (unsigned i = 0; i < RTAX_MAX; ++i)
if (tbx[i])
rt_stuff->metrics[i] = mnl_attr_get_u32(tbx[i]);
}
}
static int data_attr_cb(const struct nlattr *attr, void *data)
{
struct rt_container *rt_stuff = (struct rt_container*)data;
int type = mnl_attr_get_type(attr);
if (mnl_attr_type_valid(attr, RTA_MAX) < 0)
return MNL_CB_OK;
switch (type) {
case RTA_DST:
case RTA_SRC:
case RTA_PREFSRC:
case RTA_GATEWAY:
if (rt_stuff->family == AF_INET) {
if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
return MNL_CB_ERROR;
} else {
if (mnl_attr_validate2(attr, MNL_TYPE_BINARY, sizeof(struct in6_addr)) < 0)
return MNL_CB_ERROR;
}
break;
case RTA_TABLE:
case RTA_OIF:
case RTA_FLOW:
case RTA_PRIORITY:
if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
return MNL_CB_ERROR;
break;
case RTA_METRICS:
if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
return MNL_CB_ERROR;
break;
}
rt_stuff->tb[type] = attr;
return MNL_CB_OK;
}
static int data_cb(const struct nlmsghdr *nlh, void *data)
{
const struct rtmsg *rm = (const struct rtmsg *)mnl_nlmsg_get_payload(nlh);
Route::RouteList *routes = (Route::RouteList *)data;
struct rt_container rt_stuff;
memset(&rt_stuff, 0, sizeof(rt_stuff));
rt_stuff.family = rm->rtm_family;
rt_stuff.prefix = rm->rtm_dst_len;
rt_stuff.protocol = rm->rtm_protocol;
rt_stuff.scope = rm->rtm_scope;
rt_stuff.type = rm->rtm_type;
mnl_attr_parse(nlh, sizeof(*rm), data_attr_cb, &rt_stuff);
switch (rm->rtm_family) {
case AF_INET:
parse_attrs_ipv4(&rt_stuff);
RouteHelper::createRouteIPv4(routes, &rt_stuff);
break;
case AF_INET6:
parse_attrs_ipv6(&rt_stuff);
RouteHelper::createRouteIPv6(routes, &rt_stuff);
break;
}
return MNL_CB_OK;
}
Route::RouteList Route::list(IPAddress::Family family)
{
struct mnl_socket *nl;
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nlmsghdr *nlh;
struct rtmsg *rtm;
int ret;
unsigned seq, portid;
nlh = mnl_nlmsg_put_header(buf);
nlh->nlmsg_type = RTM_GETROUTE;
nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
nlh->nlmsg_seq = seq = time(NULL);
rtm = (struct rtmsg *)mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtmsg));
rtm->rtm_family = ((family == IPAddress::IPv4) ? AF_INET : AF_INET6);
Route::RouteList routes;
do {
nl = mnl_socket_open(NETLINK_ROUTE);
if (nl == NULL)
break;
if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0)
break;
portid = mnl_socket_get_portid(nl);
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0)
break;
while (1) {
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
if (ret <= 0)
break;
ret = mnl_cb_run(buf, ret, seq, portid, data_cb, &routes);
if (ret == MNL_CB_ERROR)
throw std::runtime_error("Couldn't parse routing table");
else if (ret == MNL_CB_STOP)
break;
}
if (ret == -1)
throw std::runtime_error("Couldn't talk to kernel");
} while (false);
if (nl)
mnl_socket_close(nl);
return routes;
}

76
Net/src/Route_WIN32.cpp Normal file
View File

@@ -0,0 +1,76 @@
//
// Route_WIN32.cpp
//
// $Id: //poco/1.4/Foundation/src/Route_WIN32.cpp#2 $
//
// Library: Net
// Package: NetCore
// Module: Route
//
// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
namespace Poco {
namespace Net {
Route::RouteList Route::list(IPAddress::Family family)
{
std::time_t now;
PMIB_IPFORWARD_TABLE2 pIpForwardTable2 = NULL;
if (GetIpForwardTable2(((family == IPAddress::IPv4) ? AF_INET : AF_INET6), &pIpForwardTable2) != NO_ERROR)
throw std::runtime_error("Couldn't fetch routing table");
::time(&now);
RouteList list;
for (unsigned i = 0; i < pIpForwardTable2->NumEntries; ++i)
{
PMIB_IPFORWARD_ROW2 pIp2 = &pIpForwardTable2->Table[i];
IPAddress::Family family2 = (pIp2->DestinationPrefix.Prefix.si_family == AF_INET ? IPAddress::IPv4 : IPAddress::IPv6);
IPAddress dest(*(struct sockaddr *)&pIp2->DestinationPrefix.Prefix);
IPAddress netmask(pIp2->DestinationPrefix.PrefixLength, family2);
IPAddress nexthop(*(struct sockaddr *)&pIp2->NextHop);
Route route(dest, netmask, nexthop, pIp2->InterfaceIndex, nexthop.isWildcard() ? ROUTE_INDIRECT : ROUTE_INDIRECT);
route.setMetric(pIp2->Metric);
route.setAge(now - pIp2->Age);
route.setProto((RouteProto) pIp2->Protocol);
list.push_back(route);
}
FreeMibTable(pIpForwardTable2);
return list;
}
}} // namespace Poco::Net