1
0
mirror of https://github.com/mfontanini/libtins synced 2026-01-23 02:35:57 +01:00

Move routing related functions into their own header file

This commit is contained in:
Matias Fontanini
2017-04-30 12:32:16 -07:00
parent 2453e57436
commit f764f68e9c
6 changed files with 581 additions and 472 deletions

View File

@@ -32,8 +32,6 @@
#include "macros.h"
#include <string>
#include <set>
#include <vector>
#include <stdint.h>
#include "ip_address.h"
#include "ipv6_address.h"
@@ -41,6 +39,7 @@
#include "detail/type_traits.h"
#include "utils/checksum_utils.h"
#include "utils/frequency_utils.h"
#include "utils/routing_utils.h"
// Fix for Windows interface define on combaseapi.h
#undef interface
@@ -63,66 +62,6 @@ class HWAddress;
*/
namespace Utils {
/**
* Struct that represents an entry the routing table
*/
struct RouteEntry {
/**
* This interface's name.
*/
std::string interface;
/**
* This route entry's destination.
*/
IPv4Address destination;
/**
* This route entry's gateway.
*/
IPv4Address gateway;
/**
* This route entry's subnet mask.
*/
IPv4Address mask;
/**
* This route entry's metric.
*/
int metric;
};
/**
* Struct that represents an entry the IPv6 routing table
*/
struct Route6Entry {
/**
* This interface's name.
*/
std::string interface;
/**
* This route entry's destination.
*/
IPv6Address destination;
/**
* This route entry's subnet mask.
*/
IPv6Address mask;
/**
* This route entry's next hop.
*/
IPv6Address gateway;
/**
* This route entry's metric.
*/
int metric;
};
/**
* \brief Resolves a domain name and returns its corresponding ip address.
*
@@ -173,14 +112,6 @@ TINS_API HWAddress<6> resolve_hwaddr(const NetworkInterface& iface,
*/
TINS_API HWAddress<6> resolve_hwaddr(IPv4Address ip, PacketSender& sender);
/** \brief List all network interfaces.
*
* Returns a set of strings, each of them representing the name
* of a network interface. These names can be used as the input
* interface for Utils::interface_ip, Utils::interface_hwaddr, etc.
*/
TINS_API std::set<std::string> network_interfaces();
/**
* \brief Finds the gateway's IP address for the given IP
* address.
@@ -194,29 +125,6 @@ TINS_API std::set<std::string> network_interfaces();
*/
TINS_API bool gateway_from_ip(IPv4Address ip, IPv4Address& gw_addr);
/**
* \brief Retrieves entries in the routing table.
*
* \brief output ForwardIterator in which entries will be stored.
*/
template<typename ForwardIterator>
void route_entries(ForwardIterator output);
/**
* \brief Retrieves entries in the routing table.
*
* \return a vector which contains all of the route entries.
*/
TINS_API std::vector<RouteEntry> route_entries();
/**
* \brief Retrieves entries in the routing table.
*
* \return a vector which contains all of the route entries.
*/
TINS_API std::vector<Route6Entry> route6_entries();
/**
* \brief Converts a PDUType to a string.
* \param pduType The PDUType to be converted.
@@ -259,13 +167,4 @@ dereference_until_pdu(T& value) {
} // Utils
} // Tins
template<typename ForwardIterator>
void Tins::Utils::route_entries(ForwardIterator output) {
std::vector<RouteEntry> entries = route_entries();
for (size_t i = 0; i < entries.size(); ++i) {
*output = entries[i];
++output;
}
}
#endif // TINS_UTILS_H

View File

@@ -0,0 +1,148 @@
/*
* Copyright (c) 2017, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
* OWNER 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.
*
*/
#ifndef TINS_ROUTING_UTILS_H
#define TINS_ROUTING_UTILS_H
#include <vector>
#include <set>
#include "../macros.h"
#include "../ip_address.h"
#include "../ipv6_address.h"
// Fix for Windows interface define on combaseapi.h
#undef interface
namespace Tins {
namespace Utils {
/**
* Struct that represents an entry the routing table
*/
struct RouteEntry {
/**
* This interface's name.
*/
std::string interface;
/**
* This route entry's destination.
*/
IPv4Address destination;
/**
* This route entry's gateway.
*/
IPv4Address gateway;
/**
* This route entry's subnet mask.
*/
IPv4Address mask;
/**
* This route entry's metric.
*/
int metric;
};
/**
* Struct that represents an entry the IPv6 routing table
*/
struct Route6Entry {
/**
* This interface's name.
*/
std::string interface;
/**
* This route entry's destination.
*/
IPv6Address destination;
/**
* This route entry's subnet mask.
*/
IPv6Address mask;
/**
* This route entry's next hop.
*/
IPv6Address gateway;
/**
* This route entry's metric.
*/
int metric;
};
/**
* \brief Retrieves entries in the routing table.
*
* \brief output ForwardIterator in which entries will be stored.
*/
template<typename ForwardIterator>
void route_entries(ForwardIterator output);
/**
* \brief Retrieves entries in the routing table.
*
* \return a vector which contains all of the route entries.
*/
TINS_API std::vector<RouteEntry> route_entries();
/**
* \brief Retrieves entries in the routing table.
*
* \return a vector which contains all of the route entries.
*/
TINS_API std::vector<Route6Entry> route6_entries();
/**
* \brief List all network interfaces.
*
* Returns a set of strings, each of them representing the name
* of a network interface. These names can be used as the input
* interface for Utils::interface_ip, Utils::interface_hwaddr, etc.
*/
TINS_API std::set<std::string> network_interfaces();
} // Utils
} // Tins
template<typename ForwardIterator>
void Tins::Utils::route_entries(ForwardIterator output) {
std::vector<RouteEntry> entries = route_entries();
for (size_t i = 0; i < entries.size(); ++i) {
*output = entries[i];
++output;
}
}
#endif // TINS_ROUTING_UTILS_H

View File

@@ -74,6 +74,7 @@ set(SOURCES
dot11/dot11_control.cpp
utils/checksum_utils.cpp
utils/frequency_utils.cpp
utils/routing_utils.cpp
)
SET(PCAP_DEPENDENT_SOURCES

View File

@@ -31,7 +31,6 @@
#include <vector>
#include <cstring>
#include "macros.h"
#include "utils.h"
#ifndef _WIN32
#include <netinet/in.h>
#if defined(BSD) || defined(__FreeBSD_kernel__)
@@ -52,6 +51,7 @@
#include "network_interface.h"
#include "endianness.h"
#include "exceptions.h"
#include "utils/routing_utils.h"
using std::string;
using std::wstring;

View File

@@ -28,10 +28,7 @@
*/
#include <stdexcept>
#include <sstream>
#include <memory>
#include <cstring>
#include <fstream>
#include "macros.h"
#ifndef _WIN32
#if defined(BSD) || defined(__FreeBSD_kernel__)
@@ -59,22 +56,19 @@
#undef interface
#endif
#include "utils.h"
#include "pdu.h"
#include "arp.h"
#include "ethernetII.h"
#include "endianness.h"
#include "network_interface.h"
#include "packet_sender.h"
#include "cxxstd.h"
#include "hw_address.h"
#include "memory_helpers.h"
#include "internals.h"
#include "detail/smart_ptr.h"
#include "detail/smart_ptr.h"
using std::string;
using std::istream;
using std::set;
using std::ifstream;
using std::vector;
using std::back_inserter;
using std::runtime_error;
@@ -84,72 +78,6 @@ using Tins::Memory::OutputMemoryStream;
/** \cond */
bool from_hex(const string& str, uint32_t& result) {
size_t i = 0;
result = 0;
while (i < str.size()) {
uint8_t tmp;
if (str[i] >= 'A' && str[i] <= 'F') {
tmp = (str[i] - 'A' + 10);
}
else if (str[i] >= '0' && str[i] <= '9') {
tmp = (str[i] - '0');
}
else {
return false;
}
result = (result << 4) | tmp;
i++;
}
return true;
}
bool from_hex(const string& str, string& result) {
result.clear();
for (size_t i = 0; i < str.size(); i+= 2) {
uint8_t value = 0;
for (size_t j = i; j < i + 2 && j < str.size(); ++j) {
if (str[j] >= 'A' && str[j] <= 'F') {
value = (value << 4) | (str[j] - 'A' + 10);
}
else if (str[j] >= 'a' && str[j] <= 'f') {
value = (value << 4) | (str[j] - 'a' + 10);
}
else if (str[j] >= '0' && str[j] <= '9') {
value = (value << 4) | (str[j] - '0');
}
else {
return false;
}
}
result.push_back(value);
}
return true;
}
void skip_line(istream& input) {
int c = 0;
while (c != '\n' && input) {
c = input.get();
}
}
struct InterfaceCollector {
set<string> ifaces;
#ifdef _WIN32
bool operator() (PIP_ADAPTER_ADDRESSES addr) {
ifaces.insert(addr->AdapterName);
return false;
}
#else
bool operator() (struct ifaddrs* addr) {
ifaces.insert(addr->ifa_name);
return false;
}
#endif
};
addrinfo* resolve_domain(const string& to_resolve, int family) {
addrinfo* result, hints = addrinfo();
hints.ai_socktype = SOCK_STREAM;
@@ -163,47 +91,6 @@ addrinfo* resolve_domain(const string& to_resolve, int family) {
}
}
#if defined(BSD) || defined(__FreeBSD_kernel__)
vector<char> query_route_table(int family) {
int mib[6];
vector<char> buf;
size_t len;
mib[0] = CTL_NET;
mib[1] = AF_ROUTE;
mib[2] = 0;
mib[3] = family;
mib[4] = NET_RT_DUMP;
mib[5] = 0;
if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
throw runtime_error("sysctl failed");
}
buf.resize(len);
if (sysctl(mib, 6, &buf[0], &len, NULL, 0) < 0) {
throw runtime_error("sysctl failed");
}
return buf;
}
void parse_header(struct rt_msghdr* rtm, vector<sockaddr*>& addrs) {
char* ptr = (char *)(rtm + 1);
// Iterate from RTA_DST (0) to RTA_NETMASK (2)
for (int i = 0; i < 3; ++i) {
sockaddr* sa = 0;
if ((rtm->rtm_addrs & (1 << i)) != 0) {
sa = (struct sockaddr *)ptr;
ptr += sa->sa_len;
if (sa->sa_family == 0) {
sa = 0;
}
}
addrs[i] = sa;
}
}
#endif
namespace Tins {
/** \endcond */
@@ -256,230 +143,6 @@ HWAddress<6> resolve_hwaddr(IPv4Address ip, PacketSender& sender) {
return resolve_hwaddr(sender.default_interface(), ip, sender);
}
#if defined(BSD) || defined(__FreeBSD_kernel__)
vector<RouteEntry> route_entries() {
vector<RouteEntry> output;
vector<char> buffer = query_route_table(AF_INET);
char* next = &buffer[0], *end = &buffer[buffer.size()];
rt_msghdr* rtm;
vector<sockaddr*> sa(32);
char iface_name[IF_NAMESIZE];
while (next < end) {
rtm = (rt_msghdr*)next;
// Filter:
// * RTF_STATIC (only manually added routes)
if ((rtm->rtm_flags & (RTF_STATIC)) != 0) {
parse_header(rtm, sa);
if (sa[RTAX_DST] && sa[RTAX_GATEWAY] && if_indextoname(rtm->rtm_index, iface_name)) {
RouteEntry entry;
entry.destination = IPv4Address(((struct sockaddr_in *)sa[RTAX_DST])->sin_addr.s_addr);
entry.gateway = IPv4Address(((struct sockaddr_in *)sa[RTAX_GATEWAY])->sin_addr.s_addr);
if (sa[RTAX_NETMASK]) {
entry.mask = IPv4Address(((struct sockaddr_in *)sa[RTAX_NETMASK])->sin_addr.s_addr);
}
entry.interface = iface_name;
entry.metric = 0;
output.push_back(entry);
}
}
next += rtm->rtm_msglen;
}
return output;
}
vector<Route6Entry> route6_entries() {
vector<Route6Entry> output;
vector<char> buffer = query_route_table(AF_INET6);
char* next = &buffer[0], *end = &buffer[buffer.size()];
rt_msghdr* rtm;
vector<sockaddr*> sa(9);
char iface_name[IF_NAMESIZE];
while (next < end) {
rtm = (rt_msghdr*)next;
// Filter protocol-cloned entries
bool process_entry = true;
// These were removed in recent versions of FreeBSD
#if defined(RTF_WASCLONED) && defined(RTF_PRCLONING)
process_entry = (rtm->rtm_flags & RTF_WASCLONED) == 0 ||
(rtm->rtm_flags & RTF_PRCLONING) == 0;
#endif
if (process_entry) {
parse_header(rtm, sa);
if (sa[RTAX_DST] && sa[RTAX_GATEWAY] && if_indextoname(rtm->rtm_index, iface_name)) {
Route6Entry entry;
entry.destination = IPv6Address(((struct sockaddr_in6 *)sa[RTAX_DST])->sin6_addr.s6_addr);
entry.gateway = IPv6Address(((struct sockaddr_in6 *)sa[RTAX_GATEWAY])->sin6_addr.s6_addr);
int prefix_length = 0;
if (sa[RTAX_NETMASK]) {
struct sockaddr_in6 *sin = (struct sockaddr_in6 *)sa[RTAX_NETMASK];
for (size_t i = 0; i < 16; ++i) {
uint8_t this_byte = sin->sin6_addr.s6_addr[i];
// Stop when we find a zero byte
if (this_byte == 0) {
break;
}
switch (this_byte) {
case 0xff:
prefix_length += 8;
break;
case 0xfe:
prefix_length += 7;
break;
case 0xfc:
prefix_length += 6;
break;
case 0xf8:
prefix_length += 5;
break;
case 0xf0:
prefix_length += 4;
break;
case 0xe0:
prefix_length += 3;
break;
case 0xc0:
prefix_length += 2;
break;
case 0x80:
prefix_length += 1;
break;
default:
break;
}
}
}
entry.mask = IPv6Address::from_prefix_length(prefix_length);
entry.interface = iface_name;
entry.metric = 0;
output.push_back(entry);
}
}
next += rtm->rtm_msglen;
}
return output;
}
#elif defined(_WIN32)
vector<RouteEntry> route_entries() {
vector<RouteEntry> output;
MIB_IPFORWARDTABLE* table;
ULONG size = 0;
GetIpForwardTable(0, &size, 0);
vector<uint8_t> buffer(size);
table = (MIB_IPFORWARDTABLE*)&buffer[0];
GetIpForwardTable(table, &size, 0);
for (DWORD i = 0; i < table->dwNumEntries; i++) {
MIB_IPFORWARDROW* row = &table->table[i];
if (row->dwForwardType == MIB_IPROUTE_TYPE_INDIRECT ||
row->dwForwardType == MIB_IPROUTE_TYPE_DIRECT) {
RouteEntry entry;
entry.interface = NetworkInterface::from_index(row->dwForwardIfIndex).name();
entry.destination = IPv4Address(row->dwForwardDest);
entry.mask = IPv4Address(row->dwForwardMask);
entry.gateway = IPv4Address(row->dwForwardNextHop);
entry.metric = row->dwForwardMetric1;
output.push_back(entry);
}
}
return output;
}
vector<Route6Entry> route6_entries() {
vector<Route6Entry> output;
MIB_IPFORWARD_TABLE2* table;
GetIpForwardTable2(AF_INET6, &table);
for (ULONG i = 0; i < table->NumEntries; i++) {
MIB_IPFORWARD_ROW2* row = &table->Table[i];
if (true) {
try {
Route6Entry entry;
entry.interface = NetworkInterface::from_index(row->InterfaceIndex).name();
entry.destination = IPv6Address(row->DestinationPrefix.Prefix.Ipv6.sin6_addr.s6_addr);
entry.mask = IPv6Address::from_prefix_length(row->DestinationPrefix.PrefixLength);
entry.gateway = IPv6Address(row->NextHop.Ipv6.sin6_addr.s6_addr);
entry.metric = row->Metric;
output.push_back(entry);
}
catch (invalid_interface&) {
}
}
}
FreeMibTable(table);
return output;
}
#else // GNU/LINUX
vector<RouteEntry> route_entries() {
using namespace Tins::Internals;
vector<RouteEntry> output;
ifstream input("/proc/net/route");
string destination, mask, metric, gw;
uint32_t dummy;
skip_line(input);
RouteEntry entry;
while (input >> entry.interface >> destination >> gw) {
for (unsigned i(0); i < 4; ++i) {
input >> metric;
}
input >> mask;
from_hex(destination, dummy);
entry.destination = IPv4Address(dummy);
from_hex(mask, dummy);
entry.mask = IPv4Address(dummy);
from_hex(gw, dummy);
entry.gateway = IPv4Address(dummy);
from_hex(metric, dummy);
entry.metric = dummy;
skip_line(input);
output.push_back(entry);
}
return output;
}
vector<Route6Entry> route6_entries() {
using namespace Tins::Internals;
vector<Route6Entry> output;
ifstream input("/proc/net/ipv6_route");
string destination, mask_length, metric, next_hop, dummy, flags;
Route6Entry entry;
while (input >> destination >> mask_length) {
string temporary;
uint32_t temporary_int;
for (unsigned i(0); i < 2; ++i) {
input >> dummy;
}
input >> next_hop;
input >> metric;
for (unsigned i(0); i < 2; ++i) {
input >> dummy;
}
input >> flags >> entry.interface;
from_hex(destination, temporary);
entry.destination = IPv6Address((const uint8_t*)&temporary[0]);
from_hex(mask_length, temporary_int);
entry.mask = IPv6Address::from_prefix_length(temporary_int);
from_hex(next_hop, temporary);
entry.gateway = IPv6Address((const uint8_t*)&temporary[0]);
from_hex(metric, temporary_int);
entry.metric = temporary_int;
// Process flags
from_hex(flags, temporary_int);
// Skip:
// * 0x01000000 -> cache entries
if ((temporary_int & 0x01000000) == 0) {
output.push_back(entry);
}
}
return output;
}
#endif
bool gateway_from_ip(IPv4Address ip, IPv4Address& gw_addr) {
typedef vector<RouteEntry> entries_type;
entries_type entries;
@@ -493,37 +156,6 @@ bool gateway_from_ip(IPv4Address ip, IPv4Address& gw_addr) {
}
return false;
}
#ifdef _WIN32
set<string> network_interfaces() {
set<string> output;
ULONG size;
::GetAdaptersAddresses(AF_INET, 0, 0, 0, &size);
std::vector<uint8_t> buffer(size);
if (::GetAdaptersAddresses(AF_INET, 0, 0, (IP_ADAPTER_ADDRESSES *)&buffer[0], &size) == ERROR_SUCCESS) {
PIP_ADAPTER_ADDRESSES iface = (IP_ADAPTER_ADDRESSES *)&buffer[0];
while (iface) {
output.insert(iface->AdapterName);
iface = iface->Next;
}
}
return output;
}
#else
set<string> network_interfaces() {
set<string> output;
struct ifaddrs* ifaddrs = 0;
struct ifaddrs* if_it = 0;
getifaddrs(&ifaddrs);
for (if_it = ifaddrs; if_it; if_it = if_it->ifa_next) {
output.insert(if_it->ifa_name);
}
if (ifaddrs) {
freeifaddrs(ifaddrs);
}
return output;
}
#endif // _WIN32
string to_string(PDU::PDUType pduType) {
#define ENUM_TEXT(p) case(PDU::p): return #p;

429
src/utils/routing_utils.cpp Normal file
View File

@@ -0,0 +1,429 @@
/*
* Copyright (c) 2017, Matias Fontanini
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
* OWNER 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.
*
*/
#include "utils/routing_utils.h"
#ifndef _WIN32
#if defined(BSD) || defined(__FreeBSD_kernel__)
#include <sys/socket.h>
#include <sys/file.h>
#include <sys/sysctl.h>
#include <net/route.h>
#include <net/if_dl.h>
#include <net/if.h>
#include <netinet/in.h>
#else
#include <netpacket/packet.h>
#endif
#include <ifaddrs.h>
#include <netdb.h>
#include <net/if.h>
#ifdef __ANDROID_API__
#include <linux/in.h>
#include <linux/in6.h>
#endif
#else
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#undef interface
#endif
#include <set>
#include <fstream>
#include "network_interface.h"
using std::vector;
using std::string;
using std::set;
using std::ifstream;
using std::istream;
namespace Tins {
namespace Utils {
struct InterfaceCollector {
set<string> ifaces;
#ifdef _WIN32
bool operator() (PIP_ADAPTER_ADDRESSES addr) {
ifaces.insert(addr->AdapterName);
return false;
}
#else
bool operator() (struct ifaddrs* addr) {
ifaces.insert(addr->ifa_name);
return false;
}
#endif
};
bool from_hex(const string& str, uint32_t& result) {
size_t i = 0;
result = 0;
while (i < str.size()) {
uint8_t tmp;
if (str[i] >= 'A' && str[i] <= 'F') {
tmp = (str[i] - 'A' + 10);
}
else if (str[i] >= '0' && str[i] <= '9') {
tmp = (str[i] - '0');
}
else {
return false;
}
result = (result << 4) | tmp;
i++;
}
return true;
}
bool from_hex(const string& str, string& result) {
result.clear();
for (size_t i = 0; i < str.size(); i+= 2) {
uint8_t value = 0;
for (size_t j = i; j < i + 2 && j < str.size(); ++j) {
if (str[j] >= 'A' && str[j] <= 'F') {
value = (value << 4) | (str[j] - 'A' + 10);
}
else if (str[j] >= 'a' && str[j] <= 'f') {
value = (value << 4) | (str[j] - 'a' + 10);
}
else if (str[j] >= '0' && str[j] <= '9') {
value = (value << 4) | (str[j] - '0');
}
else {
return false;
}
}
result.push_back(value);
}
return true;
}
void skip_line(istream& input) {
int c = 0;
while (c != '\n' && input) {
c = input.get();
}
}
#if defined(BSD) || defined(__FreeBSD_kernel__)
vector<char> query_route_table(int family) {
int mib[6];
vector<char> buf;
size_t len;
mib[0] = CTL_NET;
mib[1] = AF_ROUTE;
mib[2] = 0;
mib[3] = family;
mib[4] = NET_RT_DUMP;
mib[5] = 0;
if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
throw runtime_error("sysctl failed");
}
buf.resize(len);
if (sysctl(mib, 6, &buf[0], &len, NULL, 0) < 0) {
throw runtime_error("sysctl failed");
}
return buf;
}
void parse_header(struct rt_msghdr* rtm, vector<sockaddr*>& addrs) {
char* ptr = (char *)(rtm + 1);
// Iterate from RTA_DST (0) to RTA_NETMASK (2)
for (int i = 0; i < 3; ++i) {
sockaddr* sa = 0;
if ((rtm->rtm_addrs & (1 << i)) != 0) {
sa = (struct sockaddr *)ptr;
ptr += sa->sa_len;
if (sa->sa_family == 0) {
sa = 0;
}
}
addrs[i] = sa;
}
}
vector<RouteEntry> route_entries() {
vector<RouteEntry> output;
vector<char> buffer = query_route_table(AF_INET);
char* next = &buffer[0], *end = &buffer[buffer.size()];
rt_msghdr* rtm;
vector<sockaddr*> sa(32);
char iface_name[IF_NAMESIZE];
while (next < end) {
rtm = (rt_msghdr*)next;
// Filter:
// * RTF_STATIC (only manually added routes)
if ((rtm->rtm_flags & (RTF_STATIC)) != 0) {
parse_header(rtm, sa);
if (sa[RTAX_DST] && sa[RTAX_GATEWAY] && if_indextoname(rtm->rtm_index, iface_name)) {
RouteEntry entry;
entry.destination = IPv4Address(((struct sockaddr_in *)sa[RTAX_DST])->sin_addr.s_addr);
entry.gateway = IPv4Address(((struct sockaddr_in *)sa[RTAX_GATEWAY])->sin_addr.s_addr);
if (sa[RTAX_NETMASK]) {
entry.mask = IPv4Address(((struct sockaddr_in *)sa[RTAX_NETMASK])->sin_addr.s_addr);
}
entry.interface = iface_name;
entry.metric = 0;
output.push_back(entry);
}
}
next += rtm->rtm_msglen;
}
return output;
}
vector<Route6Entry> route6_entries() {
vector<Route6Entry> output;
vector<char> buffer = query_route_table(AF_INET6);
char* next = &buffer[0], *end = &buffer[buffer.size()];
rt_msghdr* rtm;
vector<sockaddr*> sa(9);
char iface_name[IF_NAMESIZE];
while (next < end) {
rtm = (rt_msghdr*)next;
// Filter protocol-cloned entries
bool process_entry = true;
// These were removed in recent versions of FreeBSD
#if defined(RTF_WASCLONED) && defined(RTF_PRCLONING)
process_entry = (rtm->rtm_flags & RTF_WASCLONED) == 0 ||
(rtm->rtm_flags & RTF_PRCLONING) == 0;
#endif
if (process_entry) {
parse_header(rtm, sa);
if (sa[RTAX_DST] && sa[RTAX_GATEWAY] && if_indextoname(rtm->rtm_index, iface_name)) {
Route6Entry entry;
entry.destination = IPv6Address(((struct sockaddr_in6 *)sa[RTAX_DST])->sin6_addr.s6_addr);
entry.gateway = IPv6Address(((struct sockaddr_in6 *)sa[RTAX_GATEWAY])->sin6_addr.s6_addr);
int prefix_length = 0;
if (sa[RTAX_NETMASK]) {
struct sockaddr_in6 *sin = (struct sockaddr_in6 *)sa[RTAX_NETMASK];
for (size_t i = 0; i < 16; ++i) {
uint8_t this_byte = sin->sin6_addr.s6_addr[i];
// Stop when we find a zero byte
if (this_byte == 0) {
break;
}
switch (this_byte) {
case 0xff:
prefix_length += 8;
break;
case 0xfe:
prefix_length += 7;
break;
case 0xfc:
prefix_length += 6;
break;
case 0xf8:
prefix_length += 5;
break;
case 0xf0:
prefix_length += 4;
break;
case 0xe0:
prefix_length += 3;
break;
case 0xc0:
prefix_length += 2;
break;
case 0x80:
prefix_length += 1;
break;
default:
break;
}
}
}
entry.mask = IPv6Address::from_prefix_length(prefix_length);
entry.interface = iface_name;
entry.metric = 0;
output.push_back(entry);
}
}
next += rtm->rtm_msglen;
}
return output;
}
#elif defined(_WIN32)
vector<RouteEntry> route_entries() {
vector<RouteEntry> output;
MIB_IPFORWARDTABLE* table;
ULONG size = 0;
GetIpForwardTable(0, &size, 0);
vector<uint8_t> buffer(size);
table = (MIB_IPFORWARDTABLE*)&buffer[0];
GetIpForwardTable(table, &size, 0);
for (DWORD i = 0; i < table->dwNumEntries; i++) {
MIB_IPFORWARDROW* row = &table->table[i];
if (row->dwForwardType == MIB_IPROUTE_TYPE_INDIRECT ||
row->dwForwardType == MIB_IPROUTE_TYPE_DIRECT) {
RouteEntry entry;
entry.interface = NetworkInterface::from_index(row->dwForwardIfIndex).name();
entry.destination = IPv4Address(row->dwForwardDest);
entry.mask = IPv4Address(row->dwForwardMask);
entry.gateway = IPv4Address(row->dwForwardNextHop);
entry.metric = row->dwForwardMetric1;
output.push_back(entry);
}
}
return output;
}
vector<Route6Entry> route6_entries() {
vector<Route6Entry> output;
MIB_IPFORWARD_TABLE2* table;
GetIpForwardTable2(AF_INET6, &table);
for (ULONG i = 0; i < table->NumEntries; i++) {
MIB_IPFORWARD_ROW2* row = &table->Table[i];
if (true) {
try {
Route6Entry entry;
entry.interface = NetworkInterface::from_index(row->InterfaceIndex).name();
entry.destination = IPv6Address(row->DestinationPrefix.Prefix.Ipv6.sin6_addr.s6_addr);
entry.mask = IPv6Address::from_prefix_length(row->DestinationPrefix.PrefixLength);
entry.gateway = IPv6Address(row->NextHop.Ipv6.sin6_addr.s6_addr);
entry.metric = row->Metric;
output.push_back(entry);
}
catch (invalid_interface&) {
}
}
}
FreeMibTable(table);
return output;
}
#else // GNU/LINUX
vector<RouteEntry> route_entries() {
using namespace Tins::Internals;
vector<RouteEntry> output;
ifstream input("/proc/net/route");
string destination, mask, metric, gw;
uint32_t dummy;
skip_line(input);
RouteEntry entry;
while (input >> entry.interface >> destination >> gw) {
for (unsigned i(0); i < 4; ++i) {
input >> metric;
}
input >> mask;
from_hex(destination, dummy);
entry.destination = IPv4Address(dummy);
from_hex(mask, dummy);
entry.mask = IPv4Address(dummy);
from_hex(gw, dummy);
entry.gateway = IPv4Address(dummy);
from_hex(metric, dummy);
entry.metric = dummy;
skip_line(input);
output.push_back(entry);
}
return output;
}
vector<Route6Entry> route6_entries() {
using namespace Tins::Internals;
vector<Route6Entry> output;
ifstream input("/proc/net/ipv6_route");
string destination, mask_length, metric, next_hop, dummy, flags;
Route6Entry entry;
while (input >> destination >> mask_length) {
string temporary;
uint32_t temporary_int;
for (unsigned i(0); i < 2; ++i) {
input >> dummy;
}
input >> next_hop;
input >> metric;
for (unsigned i(0); i < 2; ++i) {
input >> dummy;
}
input >> flags >> entry.interface;
from_hex(destination, temporary);
entry.destination = IPv6Address((const uint8_t*)&temporary[0]);
from_hex(mask_length, temporary_int);
entry.mask = IPv6Address::from_prefix_length(temporary_int);
from_hex(next_hop, temporary);
entry.gateway = IPv6Address((const uint8_t*)&temporary[0]);
from_hex(metric, temporary_int);
entry.metric = temporary_int;
// Process flags
from_hex(flags, temporary_int);
// Skip:
// * 0x01000000 -> cache entries
if ((temporary_int & 0x01000000) == 0) {
output.push_back(entry);
}
}
return output;
}
#endif
#ifdef _WIN32
set<string> network_interfaces() {
set<string> output;
ULONG size;
::GetAdaptersAddresses(AF_INET, 0, 0, 0, &size);
vector<uint8_t> buffer(size);
if (::GetAdaptersAddresses(AF_INET, 0, 0, (IP_ADAPTER_ADDRESSES *)&buffer[0], &size) == ERROR_SUCCESS) {
PIP_ADAPTER_ADDRESSES iface = (IP_ADAPTER_ADDRESSES *)&buffer[0];
while (iface) {
output.insert(iface->AdapterName);
iface = iface->Next;
}
}
return output;
}
#else
set<string> network_interfaces() {
set<string> output;
struct ifaddrs* ifaddrs = 0;
struct ifaddrs* if_it = 0;
getifaddrs(&ifaddrs);
for (if_it = ifaddrs; if_it; if_it = if_it->ifa_next) {
output.insert(if_it->ifa_name);
}
if (ifaddrs) {
freeifaddrs(ifaddrs);
}
return output;
}
#endif // _WIN32
} // Utils
} // Tins