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:
parent
7bf1cc419e
commit
cce93139d0
93
ndhc/ifset.c
93
ndhc/ifset.c
@ -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))
|
||||||
|
@ -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);
|
||||||
|
11
ndhc/nl.c
11
ndhc/nl.c
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user