|
|
|
@ -11,6 +11,15 @@ extern "C" {
|
|
|
|
|
#include <time.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <cstring>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <asm/types.h>
|
|
|
|
|
#include <netinet/in.h>
|
|
|
|
|
#include <linux/netlink.h>
|
|
|
|
|
#include <linux/rtnetlink.h>
|
|
|
|
|
#include <malloc.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
|
|
std::string getWireguardVersion() {
|
|
|
|
|
return "Kernel";
|
|
|
|
@ -39,6 +48,26 @@ void WireguardDevices::deleteInterface(std::string wgName) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string HostAdresses(bool addPort, const sockaddr* addr) {
|
|
|
|
|
char host[4096 + 1], service[512 + 1];
|
|
|
|
|
static char buf[sizeof(host) + sizeof(service) + 4];
|
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
|
int ret;
|
|
|
|
|
socklen_t addr_len = 0;
|
|
|
|
|
if (addr->sa_family == AF_INET) addr_len = sizeof(struct sockaddr_in);
|
|
|
|
|
else if (addr->sa_family == AF_INET6) addr_len = sizeof(struct sockaddr_in6);
|
|
|
|
|
|
|
|
|
|
ret = getnameinfo(addr, addr_len, host, sizeof(host), service, sizeof(service), NI_DGRAM | NI_NUMERICSERV | NI_NUMERICHOST);
|
|
|
|
|
if (ret) {
|
|
|
|
|
strncpy(buf, gai_strerror(ret), sizeof(buf) - 1);
|
|
|
|
|
buf[sizeof(buf) - 1] = '\0';
|
|
|
|
|
} else {
|
|
|
|
|
if (addPort) snprintf(buf, sizeof(buf), (addr->sa_family == AF_INET6 && strchr(host, ':')) ? "[%s]:%s" : "%s:%s", host, service);
|
|
|
|
|
else snprintf(buf, sizeof(buf), "%s", host);
|
|
|
|
|
}
|
|
|
|
|
return std::string(buf);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void WireguardConfig::getWireguardConfig() {
|
|
|
|
|
if (this->name.length() == 0) throw std::string("Set wireguard name!");
|
|
|
|
|
else if (this->name.length() > IFNAMSIZ) throw std::string("Wireguard interface name is long, max name length is ").append(std::to_string(IFNAMSIZ));
|
|
|
|
@ -48,37 +77,7 @@ void WireguardConfig::getWireguardConfig() {
|
|
|
|
|
if (devConfig->flags & WGDEVICE_HAS_PRIVATE_KEY) privateKey = wgKeys::toString(devConfig->private_key);
|
|
|
|
|
if (devConfig->flags & WGDEVICE_HAS_PUBLIC_KEY) publicKey = wgKeys::toString(devConfig->public_key);
|
|
|
|
|
if (devConfig->flags & WGDEVICE_HAS_LISTEN_PORT) portListen = devConfig->listen_port;
|
|
|
|
|
|
|
|
|
|
auto HostAdresses = [](bool addPort, const sockaddr* addr) -> std::string {
|
|
|
|
|
char host[4096 + 1], service[512 + 1];
|
|
|
|
|
static char buf[sizeof(host) + sizeof(service) + 4];
|
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
|
int ret;
|
|
|
|
|
socklen_t addr_len = 0;
|
|
|
|
|
if (addr->sa_family == AF_INET) addr_len = sizeof(struct sockaddr_in);
|
|
|
|
|
else if (addr->sa_family == AF_INET6) addr_len = sizeof(struct sockaddr_in6);
|
|
|
|
|
|
|
|
|
|
ret = getnameinfo(addr, addr_len, host, sizeof(host), service, sizeof(service), NI_DGRAM | NI_NUMERICSERV | NI_NUMERICHOST);
|
|
|
|
|
if (ret) {
|
|
|
|
|
strncpy(buf, gai_strerror(ret), sizeof(buf) - 1);
|
|
|
|
|
buf[sizeof(buf) - 1] = '\0';
|
|
|
|
|
} else {
|
|
|
|
|
if (addPort) snprintf(buf, sizeof(buf), (addr->sa_family == AF_INET6 && strchr(host, ':')) ? "[%s]:%s" : "%s:%s", host, service);
|
|
|
|
|
else snprintf(buf, sizeof(buf), "%s", host);
|
|
|
|
|
}
|
|
|
|
|
return std::string(buf);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
ifaddrs* ptr_ifaddrs = nullptr;
|
|
|
|
|
if(getifaddrs(&ptr_ifaddrs) > 0) {
|
|
|
|
|
for (ifaddrs* ptr_entry = ptr_ifaddrs; ptr_entry != nullptr; ptr_entry = ptr_entry->ifa_next) {
|
|
|
|
|
if (ptr_entry->ifa_addr == nullptr) continue;
|
|
|
|
|
else if (strcmp(ptr_entry->ifa_name, this->name.c_str()) != 0) continue;
|
|
|
|
|
else if (ptr_entry->ifa_addr->sa_family == AF_INET) this->interfaceAddress.addIPMask(HostAdresses(false, ptr_entry->ifa_addr));
|
|
|
|
|
else if (ptr_entry->ifa_addr->sa_family == AF_INET6) this->interfaceAddress.addIPMask(HostAdresses(false, ptr_entry->ifa_addr));
|
|
|
|
|
}
|
|
|
|
|
freeifaddrs(ptr_ifaddrs);
|
|
|
|
|
}
|
|
|
|
|
this->interfaceAddress.GetInInterface(this->name);
|
|
|
|
|
|
|
|
|
|
for ((peer) = (devConfig)->first_peer; (peer); (peer) = (peer)->next_peer) {
|
|
|
|
|
auto PeerConfig = Peer();
|
|
|
|
@ -90,16 +89,13 @@ void WireguardConfig::getWireguardConfig() {
|
|
|
|
|
PeerConfig.rxBytes = peer->rx_bytes;
|
|
|
|
|
PeerConfig.txBytes = peer->tx_bytes;
|
|
|
|
|
|
|
|
|
|
if (peer->first_allowedip) {
|
|
|
|
|
wg_allowedip *allowedip;
|
|
|
|
|
for ((allowedip) = (peer)->first_allowedip; (allowedip); (allowedip) = (allowedip)->next_allowedip) {
|
|
|
|
|
static char buf[INET6_ADDRSTRLEN + 1];
|
|
|
|
|
memset(buf, 0, INET6_ADDRSTRLEN + 1);
|
|
|
|
|
if (allowedip->family == AF_INET) inet_ntop(AF_INET, &allowedip->ip4, buf, INET6_ADDRSTRLEN);
|
|
|
|
|
else if (allowedip->family == AF_INET6) inet_ntop(AF_INET6, &allowedip->ip6, buf, INET6_ADDRSTRLEN);
|
|
|
|
|
else continue;
|
|
|
|
|
PeerConfig.allowedIPs.push_back(std::string(buf).append("/").append(std::to_string(allowedip->cidr)));
|
|
|
|
|
}
|
|
|
|
|
wg_allowedip *allowedip;
|
|
|
|
|
for ((allowedip) = (peer)->first_allowedip; (allowedip); (allowedip) = (allowedip)->next_allowedip) {
|
|
|
|
|
static char buf[INET6_ADDRSTRLEN + 1];
|
|
|
|
|
memset(buf, 0, INET6_ADDRSTRLEN + 1);
|
|
|
|
|
if (allowedip->family == AF_INET) inet_ntop(AF_INET, &allowedip->ip4, buf, INET6_ADDRSTRLEN);
|
|
|
|
|
else if (allowedip->family == AF_INET6) inet_ntop(AF_INET6, &allowedip->ip6, buf, INET6_ADDRSTRLEN);
|
|
|
|
|
PeerConfig.allowedIPs.push_back(std::string(buf).append("/").append(std::to_string(allowedip->cidr)));
|
|
|
|
|
}
|
|
|
|
|
this->Peers[wgKeys::toString(peer->public_key)] = PeerConfig;
|
|
|
|
|
}
|
|
|
|
@ -229,22 +225,19 @@ void WireguardConfig::setWireguardConfig() {
|
|
|
|
|
free(Endpoint);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set allowed IPs
|
|
|
|
|
if (PeerConfig.second.allowedIPs.size() > 0) {
|
|
|
|
|
peer->flags = (wg_peer_flags)(peer->flags|WGPEER_REPLACE_ALLOWEDIPS);
|
|
|
|
|
for (const auto &Ip : PeerConfig.second.allowedIPs.getIpParsed()) {
|
|
|
|
|
auto newAllowedIP = new wg_allowedip({});
|
|
|
|
|
newAllowedIP->cidr = Ip.Mask;
|
|
|
|
|
if (Ip.Proto == 6 && inet_pton(AF_INET6, Ip.Address.c_str(), &newAllowedIP->ip6) == 1) newAllowedIP->family = AF_INET6;
|
|
|
|
|
else if (Ip.Proto == 4 && inet_pton(AF_INET, Ip.Address.c_str(), &newAllowedIP->ip4) == 1) newAllowedIP->family = AF_INET;
|
|
|
|
|
else {
|
|
|
|
|
delete newAllowedIP;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (peer->first_allowedip) newAllowedIP->next_allowedip = peer->first_allowedip;
|
|
|
|
|
peer->first_allowedip = newAllowedIP;
|
|
|
|
|
for (const auto Ip : PeerConfig.second.allowedIPs.getIpParsed()) {
|
|
|
|
|
if (peer->flags & WGPEER_REPLACE_ALLOWEDIPS) peer->flags = (wg_peer_flags)(peer->flags|WGPEER_REPLACE_ALLOWEDIPS);
|
|
|
|
|
auto newAllowedIP = new wg_allowedip({});
|
|
|
|
|
newAllowedIP->cidr = Ip.Mask;
|
|
|
|
|
if (Ip.Proto == 6 && inet_pton(AF_INET6, Ip.Address.c_str(), &newAllowedIP->ip6) == 1) newAllowedIP->family = AF_INET6;
|
|
|
|
|
else if (Ip.Proto == 4 && inet_pton(AF_INET, Ip.Address.c_str(), &newAllowedIP->ip4) == 1) newAllowedIP->family = AF_INET;
|
|
|
|
|
else {
|
|
|
|
|
delete newAllowedIP;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (peer->first_allowedip) newAllowedIP->next_allowedip = peer->first_allowedip;
|
|
|
|
|
peer->first_allowedip = newAllowedIP;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -269,6 +262,232 @@ void WireguardConfig::setWireguardConfig() {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IpManeger::GetInInterface(std::string interfaceName) {
|
|
|
|
|
ifaddrs* ptr_ifaddrs = nullptr;
|
|
|
|
|
if(getifaddrs(&ptr_ifaddrs) >= 0) {
|
|
|
|
|
for (ifaddrs* ptr_entry = ptr_ifaddrs; ptr_entry != nullptr; ptr_entry = ptr_entry->ifa_next) {
|
|
|
|
|
if (ptr_entry->ifa_addr == nullptr) continue;
|
|
|
|
|
else if (strcmp(ptr_entry->ifa_name, interfaceName.c_str()) != 0) continue;
|
|
|
|
|
else if (ptr_entry->ifa_addr->sa_family == AF_INET) this->addIPMask(HostAdresses(false, ptr_entry->ifa_addr));
|
|
|
|
|
else if (ptr_entry->ifa_addr->sa_family == AF_INET6) this->addIPMask(HostAdresses(false, ptr_entry->ifa_addr));
|
|
|
|
|
}
|
|
|
|
|
freeifaddrs(ptr_ifaddrs);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct rtnl_handle {
|
|
|
|
|
int fd;
|
|
|
|
|
struct sockaddr_nl local;
|
|
|
|
|
struct sockaddr_nl peer;
|
|
|
|
|
__u32 seq;
|
|
|
|
|
__u32 dump;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
__u8 family;
|
|
|
|
|
__u8 bytelen;
|
|
|
|
|
__s16 bitlen;
|
|
|
|
|
__u32 flags;
|
|
|
|
|
__u32 data[8];
|
|
|
|
|
} inet_prefix;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// This function is to open the netlink socket as the name suggests.
|
|
|
|
|
int netlink_open(struct rtnl_handle* rth) {
|
|
|
|
|
int addr_len;
|
|
|
|
|
memset(rth, 0, sizeof(rth));
|
|
|
|
|
|
|
|
|
|
// Creating the netlink socket of family NETLINK_ROUTE
|
|
|
|
|
|
|
|
|
|
rth->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
|
|
|
|
if (rth->fd < 0)
|
|
|
|
|
{
|
|
|
|
|
perror("cannot open netlink socket");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
memset(&rth->local, 0, sizeof(rth->local));
|
|
|
|
|
rth->local.nl_family = AF_NETLINK;
|
|
|
|
|
rth->local.nl_groups = 0;
|
|
|
|
|
|
|
|
|
|
// Binding the netlink socket
|
|
|
|
|
if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0)
|
|
|
|
|
{
|
|
|
|
|
perror("cannot bind netlink socket");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
addr_len = sizeof(rth->local);
|
|
|
|
|
if (getsockname(rth->fd, (struct sockaddr*)&rth->local, (socklen_t*) &addr_len) < 0)
|
|
|
|
|
{
|
|
|
|
|
perror("cannot getsockname");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if (addr_len != sizeof(rth->local))
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr, "wrong address lenght %d\n", addr_len);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if (rth->local.nl_family != AF_NETLINK)
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr, "wrong address family %d\n", rth->local.nl_family);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
rth->seq = time(NULL);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This function does the actual reading and writing to the netlink socket
|
|
|
|
|
int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer, unsigned groups, struct nlmsghdr *answer) {
|
|
|
|
|
int status;
|
|
|
|
|
struct nlmsghdr *h;
|
|
|
|
|
struct sockaddr_nl nladdr;
|
|
|
|
|
// Forming the iovector with the netlink packet.
|
|
|
|
|
struct iovec iov = { (void*)n, n->nlmsg_len };
|
|
|
|
|
char buf[8192];
|
|
|
|
|
// Forming the message to be sent.
|
|
|
|
|
struct msghdr msg = { (void*)&nladdr, sizeof(nladdr), &iov, 1, NULL, 0, 0 };
|
|
|
|
|
// Filling up the details of the netlink socket to be contacted in the
|
|
|
|
|
// kernel.
|
|
|
|
|
memset(&nladdr, 0, sizeof(nladdr));
|
|
|
|
|
nladdr.nl_family = AF_NETLINK;
|
|
|
|
|
nladdr.nl_pid = peer;
|
|
|
|
|
nladdr.nl_groups = groups;
|
|
|
|
|
n->nlmsg_seq = ++rtnl->seq;
|
|
|
|
|
if (answer == NULL)
|
|
|
|
|
n->nlmsg_flags |= NLM_F_ACK;
|
|
|
|
|
// Actual sending of the message, status contains success/failure
|
|
|
|
|
status = sendmsg(rtnl->fd, &msg, 0);
|
|
|
|
|
if (status < 0)
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This is the utility function for adding the parameters to the packet.
|
|
|
|
|
int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen) {
|
|
|
|
|
int len = RTA_LENGTH(alen);
|
|
|
|
|
struct rtattr *rta;
|
|
|
|
|
|
|
|
|
|
if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen)
|
|
|
|
|
return -1;
|
|
|
|
|
rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len));
|
|
|
|
|
rta->rta_type = type;
|
|
|
|
|
rta->rta_len = len;
|
|
|
|
|
memcpy(RTA_DATA(rta), data, alen);
|
|
|
|
|
n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int get_addr_1(inet_prefix *addr, const char *name, int family) {
|
|
|
|
|
memset(addr, 0, sizeof(*addr));
|
|
|
|
|
|
|
|
|
|
if (strcmp(name, "default") == 0 ||
|
|
|
|
|
strcmp(name, "all") == 0 ||
|
|
|
|
|
strcmp(name, "any") == 0) {
|
|
|
|
|
if (family == AF_DECnet)
|
|
|
|
|
return -1;
|
|
|
|
|
addr->family = family;
|
|
|
|
|
addr->bytelen = (family == AF_INET6 ? 16 : 4);
|
|
|
|
|
addr->bitlen = -1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (strchr(name, ':')) {
|
|
|
|
|
addr->family = AF_INET6;
|
|
|
|
|
if (family != AF_UNSPEC && family != AF_INET6)
|
|
|
|
|
return -1;
|
|
|
|
|
if (inet_pton(AF_INET6, name, addr->data) <= 0)
|
|
|
|
|
return -1;
|
|
|
|
|
addr->bytelen = 16;
|
|
|
|
|
addr->bitlen = -1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
addr->family = AF_INET;
|
|
|
|
|
if (family != AF_UNSPEC && family != AF_INET)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
struct in_addr inAddr;
|
|
|
|
|
inet_pton(AF_INET, name, (void*)&inAddr);
|
|
|
|
|
memcpy(&addr->data,&inAddr.s_addr, sizeof(inAddr.s_addr));
|
|
|
|
|
|
|
|
|
|
// if (get_addr_ipv4((__u8 *)addr->data, name) <= 0)
|
|
|
|
|
// return -1;
|
|
|
|
|
|
|
|
|
|
addr->bytelen = 4;
|
|
|
|
|
addr->bitlen = -1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int get_prefix(inet_prefix *dst, char *arg, int family) {
|
|
|
|
|
int err;
|
|
|
|
|
unsigned plen;
|
|
|
|
|
|
|
|
|
|
memset(dst, 0, sizeof(*dst));
|
|
|
|
|
|
|
|
|
|
if (strcmp(arg, "default") == 0 ||
|
|
|
|
|
strcmp(arg, "any") == 0 ||
|
|
|
|
|
strcmp(arg, "all") == 0) {
|
|
|
|
|
if (family == AF_DECnet)
|
|
|
|
|
return -1;
|
|
|
|
|
dst->family = family;
|
|
|
|
|
dst->bytelen = 0;
|
|
|
|
|
dst->bitlen = 0;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = get_addr_1(dst, arg, family);
|
|
|
|
|
if (err == 0) {
|
|
|
|
|
switch(dst->family) {
|
|
|
|
|
case AF_INET6:
|
|
|
|
|
dst->bitlen = 128;
|
|
|
|
|
break;
|
|
|
|
|
case AF_DECnet:
|
|
|
|
|
dst->bitlen = 16;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
case AF_INET:
|
|
|
|
|
dst->bitlen = 32;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IpManeger::SetInInterface(std::string interfaceName) {
|
|
|
|
|
if (this->size() == 0) return;
|
|
|
|
|
if (!(WireguardDevices().exist(interfaceName))) throw std::string("Wireguard interface not exists!");
|
|
|
|
|
int status; unsigned int ifa_index; wg_device *devConfig;;
|
|
|
|
|
if ((status = wg_get_device(&devConfig, interfaceName.c_str())) < 0) throw std::string("It was not possible to get the Wireguard interface settings, code: ").append(std::to_string(status));
|
|
|
|
|
ifa_index = devConfig->ifindex;
|
|
|
|
|
free(devConfig);
|
|
|
|
|
|
|
|
|
|
struct rtnl_handle * rth;
|
|
|
|
|
rth = (rtnl_handle*)malloc(sizeof(rtnl_handle));
|
|
|
|
|
netlink_open(rth);
|
|
|
|
|
for (const auto ip : this->getIpParsed()) {
|
|
|
|
|
inet_prefix lcl;
|
|
|
|
|
// structure of the netlink packet.
|
|
|
|
|
struct {
|
|
|
|
|
struct nlmsghdr n;
|
|
|
|
|
struct ifaddrmsg ifa;
|
|
|
|
|
char buf[1024];
|
|
|
|
|
} req;
|
|
|
|
|
|
|
|
|
|
memset(&req, 0, sizeof(req));
|
|
|
|
|
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
|
|
|
|
|
req.n.nlmsg_type = RTM_NEWADDR;
|
|
|
|
|
req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL | NLM_F_REQUEST;
|
|
|
|
|
|
|
|
|
|
req.ifa.ifa_family = ip.Proto == 4 ? AF_INET : AF_INET6;
|
|
|
|
|
req.ifa.ifa_prefixlen = ip.Mask;
|
|
|
|
|
req.ifa.ifa_index = ifa_index ; // get the loopback index
|
|
|
|
|
req.ifa.ifa_scope = 0 ;
|
|
|
|
|
|
|
|
|
|
get_prefix(&lcl, ip.Address.c_str(), req.ifa.ifa_family);
|
|
|
|
|
if (req.ifa.ifa_family == AF_UNSPEC) req.ifa.ifa_family = lcl.family;
|
|
|
|
|
|
|
|
|
|
struct in_addr inAddr;
|
|
|
|
|
inet_pton(req.ifa.ifa_family, ip.Address.c_str(), (void*)&inAddr);
|
|
|
|
|
addattr_l(&req.n, sizeof(req), IFA_LOCAL, &inAddr, sizeof(inAddr));
|
|
|
|
|
if (rtnl_talk(rth, &req.n, 0, 0, NULL) < 0); //throw std::string("Cannot set interface ip!");
|
|
|
|
|
}
|
|
|
|
|
}
|