Netlink deletion notification does not guarentee actual address deletion:
it might still exist on some other interface. Make sure we do not unbind unless the address is really gone.
This commit is contained in:
parent
c1e6ef0c6b
commit
3a9671366f
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: grabmyaddr.c,v 1.26 2010/10/22 06:26:26 tteras Exp $ */
|
||||
/* $NetBSD: grabmyaddr.c,v 1.27 2010/12/03 09:46:24 tteras Exp $ */
|
||||
/*
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
* Copyright (C) 2008 Timo Teras <timo.teras@iki.fi>.
|
||||
|
@ -319,6 +319,11 @@ myaddr_close()
|
|||
|
||||
#if defined(USE_NETLINK)
|
||||
|
||||
static int netlink_fd = -1;
|
||||
|
||||
#define NLMSG_TAIL(nmsg) \
|
||||
((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
|
||||
|
||||
static void
|
||||
parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
|
||||
{
|
||||
|
@ -330,6 +335,24 @@ parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
|
|||
}
|
||||
}
|
||||
|
||||
static int
|
||||
netlink_add_rtattr_l(struct nlmsghdr *n, int maxlen, int type,
|
||||
const void *data, int alen)
|
||||
{
|
||||
int len = RTA_LENGTH(alen);
|
||||
struct rtattr *rta;
|
||||
|
||||
if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen)
|
||||
return FALSE;
|
||||
|
||||
rta = NLMSG_TAIL(n);
|
||||
rta->rta_type = type;
|
||||
rta->rta_len = len;
|
||||
memcpy(RTA_DATA(rta), data, alen);
|
||||
n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
netlink_enumerate(fd, family, type)
|
||||
int fd;
|
||||
|
@ -409,6 +432,42 @@ netlink_process_addr(struct nlmsghdr *h)
|
|||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
netlink_route_is_local(int family, const unsigned char *addr, size_t addr_len)
|
||||
{
|
||||
struct {
|
||||
struct nlmsghdr n;
|
||||
struct rtmsg r;
|
||||
char buf[1024];
|
||||
} req;
|
||||
struct rtmsg *r = NLMSG_DATA(&req.n);
|
||||
struct rtattr *rta[RTA_MAX+1];
|
||||
struct sockaddr_nl nladdr;
|
||||
ssize_t rlen;
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
|
||||
req.n.nlmsg_flags = NLM_F_REQUEST;
|
||||
req.n.nlmsg_type = RTM_GETROUTE;
|
||||
req.r.rtm_family = family;
|
||||
netlink_add_rtattr_l(&req.n, sizeof(req), RTA_DST,
|
||||
addr, addr_len);
|
||||
req.r.rtm_dst_len = addr_len * 8;
|
||||
|
||||
memset(&nladdr, 0, sizeof(nladdr));
|
||||
nladdr.nl_family = AF_NETLINK;
|
||||
|
||||
if (sendto(netlink_fd, &req, sizeof(req), 0,
|
||||
(struct sockaddr *) &nladdr, sizeof(nladdr)) < 0)
|
||||
return 0;
|
||||
rlen = recv(netlink_fd, &req, sizeof(req), 0);
|
||||
if (rlen < 0)
|
||||
return 0;
|
||||
|
||||
return req.n.nlmsg_type == RTM_NEWROUTE &&
|
||||
req.r.rtm_type == RTN_LOCAL;
|
||||
}
|
||||
|
||||
static int
|
||||
netlink_process_route(struct nlmsghdr *h)
|
||||
{
|
||||
|
@ -455,6 +514,18 @@ netlink_process_route(struct nlmsghdr *h)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* If local route was deleted, check if there is still local
|
||||
* route for the same IP on another interface */
|
||||
if (h->nlmsg_type == RTM_DELROUTE &&
|
||||
netlink_route_is_local(rtm->rtm_family,
|
||||
RTA_DATA(rta[RTA_DST]),
|
||||
RTA_PAYLOAD(rta[RTA_DST]))) {
|
||||
plog(LLV_DEBUG, LOCATION, NULL,
|
||||
"Netlink: not deleting %s yet, it exists still\n",
|
||||
saddrwop2str((struct sockaddr *) &addr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
netlink_add_del_address(h->nlmsg_type == RTM_NEWROUTE,
|
||||
(struct sockaddr *) &addr);
|
||||
return 0;
|
||||
|
@ -518,9 +589,8 @@ kernel_receive(ctx, fd)
|
|||
}
|
||||
|
||||
static int
|
||||
kernel_open_socket()
|
||||
netlink_open_socket()
|
||||
{
|
||||
struct sockaddr_nl nl;
|
||||
int fd;
|
||||
|
||||
fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||
|
@ -535,6 +605,25 @@ kernel_open_socket()
|
|||
plog(LLV_WARNING, LOCATION, NULL,
|
||||
"failed to put socket in non-blocking mode\n");
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int
|
||||
kernel_open_socket()
|
||||
{
|
||||
struct sockaddr_nl nl;
|
||||
int fd;
|
||||
|
||||
if (netlink_fd < 0) {
|
||||
netlink_fd = netlink_open_socket();
|
||||
if (netlink_fd < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
fd = netlink_open_socket();
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
/* We monitor IPv4 addresses using RTMGRP_IPV4_ROUTE group
|
||||
* the get the RTN_LOCAL routes which are automatically added
|
||||
* by kernel. This is because:
|
||||
|
|
Loading…
Reference in New Issue