Use libnl to add/remove IPs on Linux
This commit is contained in:
parent
590e7a079f
commit
86e490f249
2 changed files with 82 additions and 28 deletions
5
Makefile
5
Makefile
|
@ -5,6 +5,11 @@ LIBS = -lpcap
|
|||
CFLAGS += -Wall -g -DNMRPFLASH_VERSION=\"$(VERSION)\"
|
||||
LDFLAGS += $(LIBS)
|
||||
|
||||
ifeq ($(shell uname -s),Linux)
|
||||
CFLAGS += $(shell pkg-config libnl-route-3.0 --cflags)
|
||||
LIBS += $(shell pkg-config libnl-route-3.0 --libs)
|
||||
endif
|
||||
|
||||
nmrpflash_OBJ = nmrp.o tftp.o ethsock.o main.o util.o
|
||||
|
||||
.PHONY: clean install release release/osx release/linux release/win32
|
||||
|
|
105
ethsock.c
105
ethsock.c
|
@ -38,6 +38,7 @@
|
|||
#if defined(NMRPFLASH_LINUX)
|
||||
#define NMRPFLASH_AF_PACKET AF_PACKET
|
||||
#include <linux/if_packet.h>
|
||||
#include <netlink/route/addr.h>
|
||||
#else
|
||||
#define NMRPFLASH_AF_PACKET AF_LINK
|
||||
#include <net/if_types.h>
|
||||
|
@ -156,6 +157,62 @@ static bool bridge_stp(const char *intf, bool enabled)
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool xrtnl_addr_set(struct rtnl_addr *ra, uint32_t addr, int (*cb)(struct rtnl_addr*, struct nl_addr*))
|
||||
{
|
||||
struct nl_addr *na = nl_addr_build(AF_INET, &addr, 4);
|
||||
if (!na) {
|
||||
xperror("nl_addr_build");
|
||||
return false;
|
||||
}
|
||||
|
||||
cb(ra, na);
|
||||
nl_addr_put(na);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool intf_add_del_ip(const char *intf, uint32_t ipaddr, uint32_t ipmask, bool add)
|
||||
{
|
||||
struct rtnl_addr *ra = NULL;
|
||||
struct nl_addr *na = NULL;
|
||||
struct nl_sock *sk = NULL;
|
||||
int err = 1;
|
||||
|
||||
if (!(sk = nl_socket_alloc())) {
|
||||
xperror("nl_socket_alloc");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((err = nl_connect(sk, NETLINK_ROUTE)) < 0) {
|
||||
fprintf(stderr, "nl_connect: %s\n", nl_geterror(err));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(ra = rtnl_addr_alloc())) {
|
||||
xperror("rtnl_addr_alloc");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!xrtnl_addr_set(ra, (ipaddr & ipmask) | ~ipmask, &rtnl_addr_set_broadcast)
|
||||
|| !xrtnl_addr_set(ra, ipaddr, &rtnl_addr_set_local)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
rtnl_addr_set_ifindex(ra, if_nametoindex(intf));
|
||||
rtnl_addr_set_prefixlen(ra, bitcount(ipmask));
|
||||
|
||||
if ((err = add ? rtnl_addr_add(sk, ra, 0) : rtnl_addr_delete(sk, ra, 0)) < 0) {
|
||||
fprintf(stderr, "%s: %s\n", add ? "rtnl_addr_add" : "rtnl_addr_delete", nl_geterror(err));
|
||||
}
|
||||
|
||||
out:
|
||||
nl_addr_put(na);
|
||||
rtnl_addr_put(ra);
|
||||
nl_socket_free(sk);
|
||||
|
||||
return !err;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool intf_get_info(const char *intf, uint8_t *hwaddr, bool *bridge)
|
||||
|
@ -779,7 +836,7 @@ static inline void set_addr(void *p, uint32_t addr)
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifndef NMRPFLASH_WINDOWS
|
||||
#if !defined(NMRPFLASH_WINDOWS) && !defined(NMRPFLASH_LINUX)
|
||||
static bool intf_up(int fd, const char *intf, bool up)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
|
@ -809,47 +866,34 @@ static bool intf_up(int fd, const char *intf, bool up)
|
|||
}
|
||||
#endif
|
||||
|
||||
int ethsock_ip_add(struct ethsock *sock, uint32_t ipaddr, uint32_t ipmask, struct ethsock_ip_undo **undo)
|
||||
static int ethsock_ip_add_del(struct ethsock *sock, uint32_t ipaddr, uint32_t ipmask, struct ethsock_ip_undo **undo, bool add)
|
||||
{
|
||||
if (undo && !(*undo = malloc(sizeof(struct ethsock_ip_undo)))) {
|
||||
xperror("malloc");
|
||||
return -1;
|
||||
int ret, fd;
|
||||
|
||||
if (add && undo) {
|
||||
if (!(*undo = malloc(sizeof(struct ethsock_ip_undo)))) {
|
||||
xperror("malloc");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(*undo, 0, sizeof(**undo));
|
||||
}
|
||||
|
||||
int ret = -1;
|
||||
int fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
ret = -1;
|
||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fd < 0) {
|
||||
sock_perror("socket");
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifndef NMRPFLASH_WINDOWS
|
||||
// XXX: undo is non-zero only if we're adding an IP
|
||||
bool add = undo;
|
||||
#ifdef NMRPFLASH_LINUX
|
||||
struct ifreq ifr;
|
||||
strncpy(ifr.ifr_name, sock->intf, IFNAMSIZ);
|
||||
// FIXME: automatically determine the next free alias
|
||||
strcat(ifr.ifr_name, ":42");
|
||||
|
||||
if (add) {
|
||||
set_addr(&ifr.ifr_addr, ipaddr);
|
||||
if (ioctl(fd, SIOCSIFADDR, &ifr) != 0) {
|
||||
xperror("ioctl(SIOSIFADDR)");
|
||||
goto out;
|
||||
}
|
||||
|
||||
set_addr(&ifr.ifr_netmask, ipmask);
|
||||
if (ioctl(fd, SIOCSIFNETMASK, &ifr) != 0) {
|
||||
xperror("ioctl(SIOCSIFNETMASK)");
|
||||
goto out;
|
||||
}
|
||||
|
||||
(*undo)->ip[0] = ipaddr;
|
||||
(*undo)->ip[1] = ipmask;
|
||||
}
|
||||
|
||||
if (!intf_up(fd, ifr.ifr_name, add)) {
|
||||
if (!intf_add_del_ip(sock->intf, (*undo)->ip[0], (*undo)->ip[1], add)) {
|
||||
goto out;
|
||||
}
|
||||
#else // NMRPFLASH_OSX (or any other BSD)
|
||||
|
@ -917,6 +961,11 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int ethsock_ip_add(struct ethsock *sock, uint32_t ipaddr, uint32_t ipmask, struct ethsock_ip_undo **undo)
|
||||
{
|
||||
return ethsock_ip_add_del(sock, ipaddr, ipmask, undo, true);
|
||||
}
|
||||
|
||||
int ethsock_ip_del(struct ethsock *sock, struct ethsock_ip_undo **undo)
|
||||
{
|
||||
if (!*undo) {
|
||||
|
@ -927,7 +976,7 @@ int ethsock_ip_del(struct ethsock *sock, struct ethsock_ip_undo **undo)
|
|||
|
||||
#ifndef NMRPFLASH_WINDOWS
|
||||
if ((*undo)->ip[0] != INADDR_NONE) {
|
||||
ret = ethsock_ip_add(sock, (*undo)->ip[0], (*undo)->ip[1], NULL);
|
||||
ret = ethsock_ip_add_del(sock, (*undo)->ip[0], (*undo)->ip[1], undo, false);
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue