From: Joseph C. Lehner Date: Sat, 25 Feb 2017 09:01:04 +0000 (+0100) Subject: Use libnl to add/remove IPs on Linux X-Git-Tag: v0.9.11~6 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=86e490f249f842f05063c87c8a53707423eb851e;p=oweals%2Fnmrpflash.git Use libnl to add/remove IPs on Linux --- diff --git a/Makefile b/Makefile index 9ac4356..79b1fbe 100644 --- a/Makefile +++ b/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 diff --git a/ethsock.c b/ethsock.c index 18774e0..e1d8a45 100644 --- a/ethsock.c +++ b/ethsock.c @@ -38,6 +38,7 @@ #if defined(NMRPFLASH_LINUX) #define NMRPFLASH_AF_PACKET AF_PACKET #include +#include #else #define NMRPFLASH_AF_PACKET AF_LINK #include @@ -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; }