Delete old IP addresses associated with the interface when setting the

DHCP-assigned IP, broadcast, and subnet.

The nl_foreach_nlmsg() gains a seq parameter that when set to non-0 will
cause nl_foreach_nlmsg() to ignore any nlmsg that has a seq number
that does not match the caller-supplied seq argument.
This commit is contained in:
Nicholas J. Kain 2014-03-15 04:43:29 -04:00
parent 7bf1cc419e
commit cce93139d0
4 changed files with 51 additions and 58 deletions

View File

@ -55,7 +55,7 @@
#include "strl.h" #include "strl.h"
#include "nl.h" #include "nl.h"
static uint32_t ifset_nl_seq; static uint32_t ifset_nl_seq = 1;
static int set_if_flag(short flag) static int set_if_flag(short flag)
{ {
@ -126,9 +126,8 @@ static int rtattr_assign(struct rtattr *attr, int type, void *data)
} }
static ssize_t rtnl_addr_broadcast_send(int fd, int type, int ifa_flags, static ssize_t rtnl_addr_broadcast_send(int fd, int type, int ifa_flags,
int ifa_scope, struct in_addr *ipaddr, int ifa_scope, uint32_t *ipaddr,
struct in_addr *bcast, uint32_t *bcast, uint8_t prefixlen)
uint8_t prefixlen)
{ {
uint8_t request[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + uint8_t request[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
NLMSG_ALIGN(sizeof(struct ifaddrmsg)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg)) +
@ -161,7 +160,7 @@ static ssize_t rtnl_addr_broadcast_send(int fd, int type, int ifa_flags,
if (ipaddr) { if (ipaddr) {
if (nl_add_rtattr(header, sizeof request, IFA_LOCAL, if (nl_add_rtattr(header, sizeof request, IFA_LOCAL,
&ipaddr, sizeof ipaddr) < 0) { ipaddr, sizeof *ipaddr) < 0) {
log_line("%s: (%s) couldn't add IFA_LOCAL to nlmsg", log_line("%s: (%s) couldn't add IFA_LOCAL to nlmsg",
client_config.interface, __func__); client_config.interface, __func__);
return -1; return -1;
@ -169,7 +168,7 @@ static ssize_t rtnl_addr_broadcast_send(int fd, int type, int ifa_flags,
} }
if (bcast) { if (bcast) {
if (nl_add_rtattr(header, sizeof request, IFA_BROADCAST, if (nl_add_rtattr(header, sizeof request, IFA_BROADCAST,
&bcast, sizeof bcast) < 0) { bcast, sizeof *bcast) < 0) {
log_line("%s: (%s) couldn't add IFA_BROADCAST to nlmsg", log_line("%s: (%s) couldn't add IFA_BROADCAST to nlmsg",
client_config.interface, __func__); client_config.interface, __func__);
return -1; return -1;
@ -224,47 +223,31 @@ static void ipbcpfx_clear_others_do(const struct nlmsghdr *nlh, void *data)
struct ipbcpfx *ipx = data; struct ipbcpfx *ipx = data;
int r; int r;
nl_rtattr_parse(nlh, sizeof *ifm, rtattr_assign, tb);
switch(nlh->nlmsg_type) { switch(nlh->nlmsg_type) {
case RTM_NEWADDR: case RTM_NEWADDR:
if (ifm->ifa_index != (unsigned)client_config.ifindex) { if (ifm->ifa_index != (unsigned)client_config.ifindex) {
printf("not correct ifindex\n"); printf("not correct ifindex\n");
return; return;
} }
if (ifm->ifa_family != AF_INET) { if (ifm->ifa_family != AF_INET)
printf("not AF_INET\n");
return; return;
} if (!(ifm->ifa_flags & IFA_F_PERMANENT))
if (!(ifm->ifa_flags & IFA_F_PERMANENT)) {
printf("not F_PERMANENT\n");
goto erase; goto erase;
} if (ifm->ifa_scope != RT_SCOPE_UNIVERSE)
if (!(ifm->ifa_scope & RT_SCOPE_UNIVERSE)) {
printf("not SCOPE_UNIVERSE\n");
goto erase; goto erase;
} if (ifm->ifa_prefixlen != ipx->prefixlen)
if (ifm->ifa_prefixlen != ipx->prefixlen) {
printf("different prefixlen (%u)\n", ifm->ifa_prefixlen);
goto erase; goto erase;
} if (!tb[IFA_ADDRESS])
nl_rtattr_parse(nlh, sizeof *ifm, rtattr_assign, tb);
if (!tb[IFA_ADDRESS]) {
printf("no IFA_ADDRESS\n");
goto erase; goto erase;
}
if (memcmp(rtattr_get_data(tb[IFA_ADDRESS]), &ipx->ipaddr, if (memcmp(rtattr_get_data(tb[IFA_ADDRESS]), &ipx->ipaddr,
sizeof ipx->ipaddr)) { sizeof ipx->ipaddr))
printf("different IFA_ADDRESS\n");
goto erase; goto erase;
} if (!tb[IFA_BROADCAST])
if (!tb[IFA_BROADCAST]) {
printf("no IFA_BROADCAST\n");
goto erase; goto erase;
} if (memcmp(rtattr_get_data(tb[IFA_BROADCAST]), &ipx->bcast,
if (memcmp(rtattr_get_data(tb[IFA_BROADCAST]), &ipx->ipaddr, sizeof ipx->bcast))
sizeof ipx->ipaddr)) {
printf("different IFA_BROADCAST\n");
goto erase; goto erase;
}
break; break;
default: default:
return; return;
@ -276,8 +259,8 @@ static void ipbcpfx_clear_others_do(const struct nlmsghdr *nlh, void *data)
erase: erase:
r = rtnl_addr_broadcast_send(ipx->fd, RTM_DELADDR, ifm->ifa_flags, r = rtnl_addr_broadcast_send(ipx->fd, RTM_DELADDR, ifm->ifa_flags,
ifm->ifa_scope, ifm->ifa_scope,
rtattr_get_data(tb[IFA_ADDRESS]), tb[IFA_ADDRESS] ? rtattr_get_data(tb[IFA_ADDRESS]) : NULL,
rtattr_get_data(tb[IFA_BROADCAST]), tb[IFA_BROADCAST] ? rtattr_get_data(tb[IFA_BROADCAST]) : NULL,
ifm->ifa_prefixlen); ifm->ifa_prefixlen);
if (r < 0) { if (r < 0) {
log_warning("%s: (%s) Failed to delete IP and broadcast addresses.", log_warning("%s: (%s) Failed to delete IP and broadcast addresses.",
@ -293,19 +276,20 @@ static int ipbcpfx_clear_others(int fd, uint32_t ipaddr, uint32_t bcast,
struct ipbcpfx ipx = { .fd = fd, .ipaddr = ipaddr, .bcast = bcast, struct ipbcpfx ipx = { .fd = fd, .ipaddr = ipaddr, .bcast = bcast,
.prefixlen = prefixlen, .already_ok = false }; .prefixlen = prefixlen, .already_ok = false };
ssize_t ret; ssize_t ret;
ret = nl_sendgetaddr(fd, ifset_nl_seq++, client_config.ifindex); uint32_t seq = ifset_nl_seq++;
ret = nl_sendgetaddr(fd, seq, client_config.ifindex);
if (ret < 0) if (ret < 0)
return ret; return -1;
do { do {
ret = nl_recv_buf(fd, nlbuf, sizeof nlbuf); ret = nl_recv_buf(fd, nlbuf, sizeof nlbuf);
if (ret == -1) if (ret == -1)
break; return -2;
if (nl_foreach_nlmsg(nlbuf, ret, 0, if (nl_foreach_nlmsg(nlbuf, ret, seq, 0,
ipbcpfx_clear_others_do, &ipx) == -1) ipbcpfx_clear_others_do, &ipx) == -1)
break; return -3;
} while (ret > 0); } while (ret > 0);
return ret; return ipx.already_ok ? 1 : 0;
} }
// str_bcast is optional. // str_bcast is optional.
@ -359,23 +343,30 @@ void perform_ip_subnet_bcast(const char *str_ipaddr,
} }
r = ipbcpfx_clear_others(fd, ipaddr.s_addr, bcast.s_addr, prefixlen); r = ipbcpfx_clear_others(fd, ipaddr.s_addr, bcast.s_addr, prefixlen);
if (r < 0) { if (r < 0 && r > -3) {
if (r == -1)
log_line("sending getaddrinfo packet failed");
else if (r == -2)
log_line("receiving getaddrinfo reply failed");
close(fd); close(fd);
return; return;
} }
r = rtnl_addr_broadcast_send(fd, RTM_NEWADDR, IFA_F_PERMANENT, if (r < 1) {
RT_SCOPE_UNIVERSE, &ipaddr, &bcast, r = rtnl_addr_broadcast_send(fd, RTM_NEWADDR, IFA_F_PERMANENT,
prefixlen); RT_SCOPE_UNIVERSE, &ipaddr.s_addr, &bcast.s_addr,
prefixlen);
close(fd); // XXX: Move this when we also set the link flags. close(fd); // XXX: Move this when we also set the link flags.
if (r < 0) if (r < 0)
return; return;
log_line("Interface IP set to: '%s'", str_ipaddr); log_line("Interface IP set to: '%s'", str_ipaddr);
log_line("Interface subnet set to: '%s'", str_subnet); log_line("Interface subnet set to: '%s'", str_subnet);
if (str_bcast) if (str_bcast)
log_line("Broadcast address set to: '%s'", str_bcast); log_line("Broadcast address set to: '%s'", str_bcast);
} else
log_line("Interface IP, subnet, and broadcast were already OK.");
// XXX: Would be nice to do this via netlink, too. // XXX: Would be nice to do this via netlink, too.
if (set_if_flag(IFF_UP | IFF_RUNNING)) if (set_if_flag(IFF_UP | IFF_RUNNING))

View File

@ -131,7 +131,7 @@ void handle_nl_message(struct client_state_t *cs)
ret = nl_recv_buf(cs->nlFd, nlbuf, sizeof nlbuf); ret = nl_recv_buf(cs->nlFd, nlbuf, sizeof nlbuf);
if (ret == -1) if (ret == -1)
break; break;
if (nl_foreach_nlmsg(nlbuf, ret, cs->nlPortId, nl_process_msgs, cs) if (nl_foreach_nlmsg(nlbuf, ret, 0, cs->nlPortId, nl_process_msgs, cs)
== -1) == -1)
break; break;
} while (ret > 0); } while (ret > 0);

View File

@ -129,17 +129,19 @@ ssize_t nl_recv_buf(int fd, char *buf, size_t blen)
return ret; return ret;
} }
int nl_foreach_nlmsg(char *buf, size_t blen, uint32_t portid, int nl_foreach_nlmsg(char *buf, size_t blen, uint32_t seq, uint32_t portid,
nlmsg_foreach_fn pfn, void *fnarg) nlmsg_foreach_fn pfn, void *fnarg)
{ {
const struct nlmsghdr *nlh = (const struct nlmsghdr *)buf; const struct nlmsghdr *nlh = (const struct nlmsghdr *)buf;
assert(pfn); assert(pfn);
while (NLMSG_OK(nlh, blen)) { for (;NLMSG_OK(nlh, blen); nlh = NLMSG_NEXT(nlh, blen)) {
// PortID should be zero for messages from the kernel. // PortID should be zero for messages from the kernel.
if (nlh->nlmsg_pid && nlh->nlmsg_pid != portid) if (nlh->nlmsg_pid && portid && nlh->nlmsg_pid != portid)
continue;
log_line("%s: seq=%u nlh->nlmsg_seq=%u", __func__, seq, nlh->nlmsg_seq);
if (seq && nlh->nlmsg_seq != seq)
continue; continue;
// XXX don't bother with sequence # tracking (0 = kernel, ours = ??)
if (nlh->nlmsg_type >= NLMSG_MIN_TYPE) { if (nlh->nlmsg_type >= NLMSG_MIN_TYPE) {
pfn(nlh, fnarg); pfn(nlh, fnarg);
@ -158,7 +160,6 @@ int nl_foreach_nlmsg(char *buf, size_t blen, uint32_t portid,
break; break;
} }
} }
nlh = NLMSG_NEXT(nlh, blen);
} }
return 0; return 0;
} }

View File

@ -89,7 +89,8 @@ extern void nl_rtattr_parse(const struct nlmsghdr *nlh, size_t offset,
extern ssize_t nl_recv_buf(int fd, char *buf, size_t blen); extern ssize_t nl_recv_buf(int fd, char *buf, size_t blen);
typedef void (*nlmsg_foreach_fn)(const struct nlmsghdr *, void *); typedef void (*nlmsg_foreach_fn)(const struct nlmsghdr *, void *);
extern int nl_foreach_nlmsg(char *buf, size_t blen, uint32_t portid, extern int nl_foreach_nlmsg(char *buf, size_t blen, uint32_t seq,
uint32_t portid,
nlmsg_foreach_fn pfn, void *fnarg); nlmsg_foreach_fn pfn, void *fnarg);
extern int nl_sendgetlink(int fd, int seq); extern int nl_sendgetlink(int fd, int seq);
extern int nl_sendgetaddr(int fd, int seq, int ifindex); extern int nl_sendgetaddr(int fd, int seq, int ifindex);