initial netlink jizz

This commit is contained in:
jeff 2020-08-21 16:03:07 +00:00 committed by Jeff Becker
parent b0bb0b7609
commit 8472aea93f
No known key found for this signature in database
GPG Key ID: F357B3B42F6F9B05
1 changed files with 181 additions and 3 deletions

View File

@ -1,5 +1,15 @@
#include "route.hpp"
#ifdef __linux__
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <linux/rtnetlink.h>
#endif
namespace llarp::net
{
#ifndef __linux__
@ -51,10 +61,154 @@ namespace llarp::net
}
#endif
#ifdef __linux__
struct NLSocket
{
NLSocket() : fd(socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE))
{
}
~NLSocket()
{
if (fd != -1)
close(fd);
}
const int fd;
};
/* Helper structure for ip address data and attributes */
typedef struct
{
char family;
char bitlen;
unsigned char data[sizeof(struct in6_addr)];
} _inet_addr;
/* */
#define NLMSG_TAIL(nmsg) ((struct rtattr*)(((void*)(nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
/* Add new data to rtattr */
int
rtattr_add(struct nlmsghdr* n, int maxlen, int type, const void* data, int alen)
{
int len = RTA_LENGTH(alen);
struct rtattr* rta;
if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen)
{
fprintf(stderr, "rtattr_add error: message exceeded bound of %d\n", maxlen);
return -1;
}
rta = NLMSG_TAIL(n);
rta->rta_type = type;
rta->rta_len = len;
if (alen)
{
memcpy(RTA_DATA(rta), data, alen);
}
n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
return 0;
}
int
do_route(int sock, int cmd, int flags, _inet_addr* dst, _inet_addr* gw, int def_gw, int if_idx)
{
struct
{
struct nlmsghdr n;
struct rtmsg r;
char buf[4096];
} nl_request;
/* Initialize request structure */
nl_request.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
nl_request.n.nlmsg_flags = NLM_F_REQUEST | flags;
nl_request.n.nlmsg_type = cmd;
nl_request.r.rtm_family = dst->family;
nl_request.r.rtm_table = RT_TABLE_MAIN;
nl_request.r.rtm_scope = RT_SCOPE_NOWHERE;
/* Set additional flags if NOT deleting route */
if (cmd != RTM_DELROUTE)
{
nl_request.r.rtm_protocol = RTPROT_BOOT;
nl_request.r.rtm_type = RTN_UNICAST;
}
nl_request.r.rtm_family = dst->family;
nl_request.r.rtm_dst_len = dst->bitlen;
/* Select scope, for simplicity we supports here only IPv6 and IPv4 */
if (nl_request.r.rtm_family == AF_INET6)
{
nl_request.r.rtm_scope = RT_SCOPE_UNIVERSE;
}
else
{
nl_request.r.rtm_scope = RT_SCOPE_LINK;
}
/* Set gateway */
if (gw->bitlen != 0)
{
rtattr_add(&nl_request.n, sizeof(nl_request), RTA_GATEWAY, &gw->data, gw->bitlen / 8);
nl_request.r.rtm_scope = 0;
nl_request.r.rtm_family = gw->family;
}
/* Don't set destination and interface in case of default gateways */
if (!def_gw)
{
/* Set destination network */
rtattr_add(
&nl_request.n, sizeof(nl_request), /*RTA_NEWDST*/ RTA_DST, &dst->data, dst->bitlen / 8);
/* Set interface */
rtattr_add(&nl_request.n, sizeof(nl_request), RTA_OIF, &if_idx, sizeof(int));
}
/* Send message to the netlink */
return send(sock, &nl_request, sizeof(nl_request), 0);
}
int
read_addr(char* addr, _inet_addr* res)
{
if (strchr(addr, ':'))
{
res->family = AF_INET6;
res->bitlen = 128;
}
else
{
res->family = AF_INET;
res->bitlen = 32;
}
return inet_pton(res->family, addr, res->data);
}
#endif
void
AddRoute(std::string ip, std::string gateway)
{
#ifdef __linux__
NLSocket sock;
int default_gw = 0;
int if_idx = 0;
_inet_addr to_addr = {0};
_inet_addr gw_addr = {0};
int nl_cmd = RTM_NEWROUTE;
int nl_flags = NLM_F_CREATE | NLM_F_EXCL;
read_addr(gateway.c_str(), &gw_addr);
read_addr(ip.c_str(), &to_addr);
do_route(sock.fd, nl_cmd, nl_flags, &to_addr, &gw_addr, default_gw, if_idx);
#else
std::stringstream ss;
#if _WIN32
@ -72,9 +226,18 @@ namespace llarp::net
DelRoute(std::string ip, std::string gateway)
{
#ifdef __linux__
NLSocket sock;
int default_gw = 0;
int if_idx = 0;
_inet_addr to_addr = {0};
_inet_addr gw_addr = {0};
int nl_cmd = RTM_DELROUTE;
int nl_flags = 0;
read_addr(gateway.c_str(), &gw_addr);
read_addr(ip.c_str(), &to_addr);
do_route(sock.fd, nl_cmd, nl_flags, &to_addr, &gw_addr, default_gw, if_idx);
#else
std::stringstream ss;
#if _WIN32
ss << "route DELETE " << ip << " MASK 255.255.255.255 " << gateway << " METRIC 2";
#elif __APPLE__
@ -90,7 +253,14 @@ namespace llarp::net
AddDefaultRouteViaInterface(std::string ifname)
{
#ifdef __linux__
// Execute("/sbin/ip route add default dev " + ifname);
NLSocket sock;
int default_gw = 1;
int if_idx = if_nametoindex(ifname.c_str());
_inet_addr to_addr = {0};
_inet_addr gw_addr = {0};
int nl_cmd = RTM_NEWROUTE;
int nl_flags = NLM_F_CREATE | NLM_F_EXCL;
do_route(sock.fd, nl_cmd, nl_flags, &to_addr, &gw_addr, default_gw, if_idx);
#elif _WIN32
ifname.back()++;
Execute("route ADD 0.0.0.0 MASK 128.0.0.0 " + ifname);
@ -106,7 +276,15 @@ namespace llarp::net
DelDefaultRouteViaInterface(std::string ifname)
{
#ifdef __linux__
// Execute("/sbin/ip route del default dev " + ifname);
NLSocket sock;
int default_gw = 1;
int if_idx = if_nametoindex(ifname.c_str());
_inet_addr to_addr = {0};
_inet_addr gw_addr = {0};
int nl_cmd = RTM_DELROUTE;
int nl_flags = 0;
do_route(sock.fd, nl_cmd, nl_flags, &to_addr, &gw_addr, default_gw, if_idx);
#elif _WIN32
ifname.back()++;
Execute("route DELETE 0.0.0.0 MASK 128.0.0.0 " + ifname);