initial route poking

pull/1319/head
jeff 4 years ago committed by Jeff Becker
parent 2e7f9d1b87
commit b0bb0b7609
No known key found for this signature in database
GPG Key ID: F357B3B42F6F9B05

@ -59,6 +59,7 @@ add_library(lokinet-platform
net/ip_range.cpp
net/net.cpp
net/net_int.cpp
net/route.cpp
net/sock_addr.cpp
$<TARGET_OBJECTS:tuntap>
)

@ -22,6 +22,12 @@ namespace llarp
return true;
}
std::string
GetIfName() const override
{
return "";
}
path::PathSet_ptr
GetSelf() override
{

@ -549,6 +549,12 @@ namespace llarp
return true;
}
std::string
TunEndpoint::GetIfName() const
{
return m_IfName;
}
bool
TunEndpoint::Start()
{
@ -661,6 +667,7 @@ namespace llarp
ifaddr = vpn.info.ifaddr;
netmask = vpn.info.netmask;
}
m_IfName = ifname;
if (ip.FromString(ifaddr))
{
m_OurIP = net::ExpandV4(ip);

@ -36,6 +36,9 @@ namespace llarp
void
SendPacketToRemote(const llarp_buffer_t&) override{};
std::string
GetIfName() const override;
void
Tick(llarp_time_t now) override;
@ -270,6 +273,7 @@ namespace llarp
llarp_vpn_io* io;
};
std::promise<lazy_vpn> m_LazyVPNPromise;
std::string m_IfName;
/// send packets on endpoint to user using send function
/// send function returns true to indicate stop iteration and do codel

@ -118,9 +118,11 @@ namespace llarp
std::string
toString() const;
/// get ip address component
std::string
getIpAddr() const;
toHost() const
{
return m_ipAddress;
}
// TODO: other utility functions left over from Addr which may be useful
// IsBogon() const;

@ -0,0 +1,229 @@
#include "route.hpp"
namespace llarp::net
{
#ifndef __linux__
void
Execute(std::string cmd)
{
std::cout << cmd << std::endl;
#ifdef _WIN32
system(cmd.c_str());
#else
std::vector<std::string> parts_str;
std::vector<const char*> parts_raw;
std::stringstream in(cmd);
for (std::string part; std::getline(in, part, ' ');)
{
if (part.empty())
continue;
parts_str.push_back(part);
}
for (const auto& part : parts_str)
{
parts_raw.push_back(part.c_str());
}
parts_raw.push_back(nullptr);
const auto pid = fork();
if (pid == -1)
{
throw std::runtime_error("failed to fork");
}
else if (pid == 0)
{
char* const* args = (char* const*)parts_raw.data();
const auto result = execv(parts_raw[0], args);
if (result)
{
std::cout << "failed: " << result << std::endl;
}
else
{
std::cout << "ok" << std::endl;
}
exit(result);
}
else
{
waitpid(pid, 0, 0);
}
#endif
}
#endif
void
AddRoute(std::string ip, std::string gateway)
{
#ifdef __linux__
#else
std::stringstream ss;
#if _WIN32
ss << "route ADD " << ip << " MASK 255.255.255.255 " << gateway << " METRIC 2";
#elif __APPLE__
ss << "route -n add -host " << ip << " " << gateway;
#else
#error unsupported platform
#endif
Execute(ss.str());
#endif
}
void
DelRoute(std::string ip, std::string gateway)
{
#ifdef __linux__
#else
std::stringstream ss;
#if _WIN32
ss << "route DELETE " << ip << " MASK 255.255.255.255 " << gateway << " METRIC 2";
#elif __APPLE__
ss << "route -n delete -host " << ip << " " << gateway;
#else
#error unsupported platform
#endif
Execute(ss.str());
#endif
}
void
AddDefaultRouteViaInterface(std::string ifname)
{
#ifdef __linux__
// Execute("/sbin/ip route add default dev " + ifname);
#elif _WIN32
ifname.back()++;
Execute("route ADD 0.0.0.0 MASK 128.0.0.0 " + ifname);
Execute("route ADD 128.0.0.0 MASK 128.0.0.0 " + ifname);
#elif __APPLE__
Execute("route -cloning add -net 0.0.0.0 -netmask 0.0.0.0 -interface " + ifname);
#else
#error unsupported platform
#endif
}
void
DelDefaultRouteViaInterface(std::string ifname)
{
#ifdef __linux__
// Execute("/sbin/ip route del default dev " + ifname);
#elif _WIN32
ifname.back()++;
Execute("route DELETE 0.0.0.0 MASK 128.0.0.0 " + ifname);
Execute("route DELETE 128.0.0.0 MASK 128.0.0.0 " + ifname);
#elif __APPLE__
Execute("route -cloning delete -net 0.0.0.0 -netmask 0.0.0.0 -interface " + ifname);
#else
#error unsupported platform
#endif
}
std::vector<std::string>
GetGatewaysNotOnInterface(std::string ifname)
{
std::vector<std::string> gateways;
#ifdef __linux__
/*
FILE* p = popen("ip route", "r");
if (p == nullptr)
return gateways;
char* line = nullptr;
size_t len = 0;
ssize_t read = 0;
while ((read = getline(&line, &len, p)) != -1)
{
std::string line_str(line, len);
std::vector<std::string> words;
std::istringstream instr(line_str);
for (std::string word; std::getline(instr, word, ' ');)
{
words.emplace_back(std::move(word));
}
if (words[0] == "default" and words[1] == "via" and words[3] == "dev" and words[4] != ifname)
{
gateways.emplace_back(std::move(words[2]));
}
}
pclose(p);
*/
return gateways;
#elif _WIN32
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
PMIB_IPFORWARDTABLE pIpForwardTable;
DWORD dwSize = 0;
DWORD dwRetVal = 0;
pIpForwardTable = (MIB_IPFORWARDTABLE*)MALLOC(sizeof(MIB_IPFORWARDTABLE));
if (pIpForwardTable == nullptr)
return gateways;
if (GetIpForwardTable(pIpForwardTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER)
{
FREE(pIpForwardTable);
pIpForwardTable = (MIB_IPFORWARDTABLE*)MALLOC(dwSize);
if (pIpForwardTable == nullptr)
{
return gateways;
}
}
if ((dwRetVal = GetIpForwardTable(pIpForwardTable, &dwSize, 0)) == NO_ERROR)
{
for (int i = 0; i < (int)pIpForwardTable->dwNumEntries; i++)
{
struct in_addr gateway, interface_addr;
gateway.S_un.S_addr = (u_long)pIpForwardTable->table[i].dwForwardDest;
interface_addr.S_un.S_addr = (u_long)pIpForwardTable->table[i].dwForwardNextHop;
std::array<char, 128> interface_str{};
StringCchCopy(interface_str.data(), interface_str.size(), inet_ntoa(interface_addr));
std::string interface_name{interface_str.data()};
if ((!gateway.S_un.S_addr) and interface_name != ifname)
{
gateways.push_back(std::move(interface_name));
}
}
}
FREE(pIpForwardTable);
#undef MALLOC
#undef FREE
return gateways;
#elif __APPLE__
const auto maybe = llarp::GetIFAddr(ifname);
if (not maybe.has_value())
return gateways;
const auto interface = maybe->toString();
// mac os is so godawful man
FILE* p = popen("netstat -rn -f inet", "r");
if (p == nullptr)
return gateways;
char* line = nullptr;
size_t len = 0;
ssize_t read = 0;
while ((read = getline(&line, &len, p)) != -1)
{
std::string line_str(line, len);
if (line_str.find("default") == 0)
{
line_str = line_str.substr(7);
while (line_str[0] == ' ')
{
line_str = line_str.substr(1);
}
const auto pos = line_str.find(" ");
if (pos != std::string::npos)
{
auto gateway = line_str.substr(0, pos);
if (gateway != interface)
gateways.emplace_back(std::move(gateway));
}
}
}
pclose(p);
return gateways;
#else
#error unsupported platform
#endif
}
} // namespace llarp::net

@ -0,0 +1,28 @@
#pragma once
#include <string>
#include <vector>
namespace llarp::net
{
/// get every ip address that is a gateway that isn't owned by interface with name ifname
std::vector<std::string>
GetGatewaysNotOnInterface(std::string ifname);
/// add route to ipaddr via gateway ip
void
AddRoute(std::string ipaddr, std::string gateway);
/// delete route to ipaddr via gateway ip
void
DelRoute(std::string ipaddr, std::string gateway);
/// add default route via interface with name ifname
void
AddDefaultRouteViaInterface(std::string ifname);
/// delete default route via interface with name ifname
void
DelDefaultRouteViaInterface(std::string ifname);
} // namespace llarp::net

@ -587,6 +587,11 @@ namespace llarp
_linkManager.AddLink(std::move(server), true);
}
if (conf.links.m_InboundLinks.empty() and m_isServiceNode)
{
throw std::runtime_error("service node enabled but have no inbound links");
}
// Network config
if (conf.network.m_enableProfiling.has_value() and not*conf.network.m_enableProfiling)
{

@ -4,6 +4,7 @@
#include <constants/version.hpp>
#include <nlohmann/json.hpp>
#include <net/ip_range.hpp>
#include <net/route.hpp>
#include <service/context.hpp>
#include <service/auth.hpp>
@ -111,6 +112,11 @@ namespace llarp::rpc
})
.add_request_command("exit", [&](lokimq::Message& msg) {
HandleJSONRequest(msg, [r = m_Router](nlohmann::json obj, ReplyFunction_t reply) {
if (r->IsServiceNode())
{
reply(CreateJSONError("not supported"));
return;
}
std::optional<service::Address> exit;
IPRange range;
bool map = true;
@ -164,11 +170,35 @@ namespace llarp::rpc
}
if (map and exit.has_value())
{
const auto gateways = net::GetGatewaysNotOnInterface(ep->GetIfName());
if (gateways.empty())
{
reply(CreateJSONError("no gateway found"));
return;
}
ep->MapExitRange(range, *exit);
if (token.has_value())
{
ep->SetAuthInfoForEndpoint(*exit, service::AuthInfo{*token});
}
ep->EnsurePathToService(
*exit,
[r, gateway = gateways[0], reply, ep](auto, service::OutboundContext* ctx) {
if (ctx == nullptr)
{
reply(CreateJSONError("could not find exit"));
return;
}
r->ForEachPeer(
[gateway](const auto* link, bool) {
net::AddRoute(link->GetRemoteEndpoint().toHost(), gateway);
},
false);
net::AddDefaultRouteViaInterface(ep->GetIfName());
reply(CreateJSONResponse("OK"));
},
5s);
return;
}
else if (map and not exit.has_value())
{
@ -177,6 +207,19 @@ namespace llarp::rpc
}
else if (not map)
{
const auto gateways = net::GetGatewaysNotOnInterface(ep->GetIfName());
if (gateways.empty())
{
reply(CreateJSONError("no gateway found"));
return;
}
net::DelDefaultRouteViaInterface(ep->GetIfName());
r->ForEachPeer(
[gateway = gateways[0]](const auto* link, bool) {
net::DelRoute(link->GetRemoteEndpoint().toHost(), gateway);
},
false);
ep->UnmapExitRange(range);
}
reply(CreateJSONResponse("OK"));

@ -108,6 +108,9 @@ namespace llarp
return false;
}
virtual std::string
GetIfName() const = 0;
/// inject vpn io
/// return false if not supported
virtual bool

@ -62,6 +62,12 @@ namespace llarp
return {0};
}
std::string
GetIfName() const override
{
return "";
}
using PacketHandler_t =
std::function<void(service::Address, std::vector<byte_t>, service::ProtocolType)>;

Loading…
Cancel
Save