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:
@@ -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
|
||||
|
||||
148
include/tins/utils/routing_utils.h
Normal file
148
include/tins/utils/routing_utils.h
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
370
src/utils.cpp
370
src/utils.cpp
@@ -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
429
src/utils/routing_utils.cpp
Normal 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
|
||||
Reference in New Issue
Block a user