mirror of
https://github.com/rsmarples/dhcpcd.git
synced 2024-11-24 10:35:03 +08:00
Add route removal detection to Linux.
This involved a rejig of the socket code so we can detect if we removed the route or not.
This commit is contained in:
parent
16687a3be1
commit
fa344ba2b1
16
configure.c
16
configure.c
@ -392,22 +392,14 @@ desc_route(const char *cmd, const struct rt *rt, const char *ifname)
|
||||
/* If something other than dhcpcd removes a route,
|
||||
* we need to remove it from our internal table. */
|
||||
int
|
||||
route_deleted(const struct in_addr *dst,
|
||||
const struct in_addr *net,
|
||||
const struct in_addr *gate)
|
||||
route_deleted(const struct rt *rt)
|
||||
{
|
||||
struct rt rt, *f, *l;
|
||||
struct rt *f, *l;
|
||||
|
||||
rt.dest.s_addr = dst->s_addr;
|
||||
rt.net.s_addr = net->s_addr;
|
||||
rt.gate.s_addr = gate->s_addr;
|
||||
rt.iface = NULL;
|
||||
rt.next = NULL;
|
||||
|
||||
f = find_route(routes, &rt, &l, NULL);
|
||||
f = find_route(routes, rt, &l, NULL);
|
||||
if (f == NULL)
|
||||
return 0;
|
||||
desc_route("removing", f, f->iface->name);
|
||||
desc_route("removing", f, rt->iface->name);
|
||||
if (l)
|
||||
l->next = f->next;
|
||||
else
|
||||
|
@ -33,8 +33,5 @@
|
||||
int send_interface(int, const struct interface *);
|
||||
int run_script(const struct interface *);
|
||||
int configure(struct interface *);
|
||||
int route_deleted(const struct in_addr *,
|
||||
const struct in_addr *,
|
||||
const struct in_addr *);
|
||||
|
||||
int route_deleted(const struct rt *);
|
||||
#endif
|
||||
|
25
dhcpcd.c
25
dhcpcd.c
@ -78,9 +78,9 @@ static char **margv;
|
||||
static int margc;
|
||||
static char **ifv;
|
||||
static int ifc;
|
||||
static int linkfd = -1;
|
||||
static char *cffile;
|
||||
static char *pidfile;
|
||||
static int linkfd = -1;
|
||||
|
||||
struct dhcp_op {
|
||||
uint8_t value;
|
||||
@ -214,6 +214,16 @@ close_sockets(struct interface *iface)
|
||||
}
|
||||
}
|
||||
|
||||
struct interface *
|
||||
find_interface(const char *ifname)
|
||||
{
|
||||
struct interface *ifp;
|
||||
|
||||
for (ifp = ifaces; ifp; ifp = ifp->next)
|
||||
if (strcmp(ifp->name, ifname) == 0)
|
||||
return ifp;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
stop_interface(struct interface *iface)
|
||||
@ -1024,11 +1034,11 @@ handle_new_interface(const char *ifname)
|
||||
if (ifn)
|
||||
continue;
|
||||
init_state(ifp, 2, UNCONST(argv));
|
||||
start_interface(ifp);
|
||||
if (ifl)
|
||||
ifl->next = ifp;
|
||||
else
|
||||
ifaces = ifp;
|
||||
start_interface(ifp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1038,11 +1048,9 @@ handle_remove_interface(const char *ifname)
|
||||
{
|
||||
struct interface *iface;
|
||||
|
||||
for (iface = ifaces; iface; iface = iface->next)
|
||||
if (strcmp(iface->name, ifname) == 0) {
|
||||
stop_interface(iface);
|
||||
break;
|
||||
}
|
||||
iface = find_interface(ifname);
|
||||
if (iface != NULL)
|
||||
stop_interface(iface);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
@ -1395,7 +1403,7 @@ main(int argc, char **argv)
|
||||
|
||||
syslog(LOG_INFO, "version " VERSION " starting");
|
||||
|
||||
if ((signal_fd =signal_init()) == -1)
|
||||
if ((signal_fd = signal_init()) == -1)
|
||||
exit(EXIT_FAILURE);
|
||||
if (signal_setup() == -1)
|
||||
exit(EXIT_FAILURE);
|
||||
@ -1408,6 +1416,7 @@ main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
init_socket();
|
||||
if (ifo->options & DHCPCD_LINK) {
|
||||
linkfd = open_link_socket();
|
||||
if (linkfd == -1)
|
||||
|
1
dhcpcd.h
1
dhcpcd.h
@ -116,6 +116,7 @@ extern int ifdc;
|
||||
extern char **ifdv;
|
||||
extern struct interface *ifaces;
|
||||
|
||||
struct interface *find_interface(const char *);
|
||||
int handle_args(struct fd_list *, int, char **);
|
||||
void handle_exit_timeout(void *);
|
||||
void start_interface(void *);
|
||||
|
47
if-bsd.c
47
if-bsd.c
@ -67,10 +67,25 @@
|
||||
1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
|
||||
#endif
|
||||
|
||||
static int a_fd = -1;
|
||||
static int r_fd = -1;
|
||||
|
||||
int
|
||||
init_socket(void)
|
||||
{
|
||||
if ((a_fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
return -1;
|
||||
set_cloexec(a_fd);
|
||||
if ((r_fd = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
|
||||
return -1;
|
||||
set_cloexec(a_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
getifssid(const char *ifname, char *ssid)
|
||||
{
|
||||
int s, retval = -1;
|
||||
int retval = -1;
|
||||
#if defined(SIOCG80211NWID)
|
||||
struct ifreq ifr;
|
||||
struct ieee80211_nwid nwid;
|
||||
@ -79,14 +94,12 @@ getifssid(const char *ifname, char *ssid)
|
||||
char nwid[IEEE80211_NWID_LEN + 1];
|
||||
#endif
|
||||
|
||||
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
return retval;
|
||||
#if defined(SIOCG80211NWID) /* NetBSD */
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
|
||||
memset(&nwid, 0, sizeof(nwid));
|
||||
ifr.ifr_data = (void *)&nwid;
|
||||
if (ioctl(s, SIOCG80211NWID, &ifr) == 0) {
|
||||
if (ioctl(a_fd, SIOCG80211NWID, &ifr) == 0) {
|
||||
retval = nwid.i_len;
|
||||
memcpy(ssid, nwid.i_nwid, nwid.i_len);
|
||||
ssid[nwid.i_len] = '\0';
|
||||
@ -97,13 +110,12 @@ getifssid(const char *ifname, char *ssid)
|
||||
ireq.i_type = IEEE80211_IOC_SSID;
|
||||
ireq.i_val = -1;
|
||||
ireq.i_data = &nwid;
|
||||
if (ioctl(s, SIOCG80211, &ireq) == 0) {
|
||||
if (ioctl(a_fd, SIOCG80211, &ireq) == 0) {
|
||||
retval = ireq.i_len;
|
||||
memcpy(ssid, nwid, ireq.i_len);
|
||||
ssid[ireq.i_len] = '\0';
|
||||
}
|
||||
#endif
|
||||
close(s);
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -112,7 +124,6 @@ if_address(const struct interface *iface, const struct in_addr *address,
|
||||
const struct in_addr *netmask, const struct in_addr *broadcast,
|
||||
int action)
|
||||
{
|
||||
int s;
|
||||
int retval;
|
||||
struct ifaliasreq ifa;
|
||||
union {
|
||||
@ -120,9 +131,6 @@ if_address(const struct interface *iface, const struct in_addr *address,
|
||||
struct sockaddr_in *sin;
|
||||
} _s;
|
||||
|
||||
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
return -1;
|
||||
|
||||
memset(&ifa, 0, sizeof(ifa));
|
||||
strlcpy(ifa.ifra_name, iface->name, sizeof(ifa.ifra_name));
|
||||
|
||||
@ -141,10 +149,9 @@ if_address(const struct interface *iface, const struct in_addr *address,
|
||||
#undef ADDADDR
|
||||
|
||||
if (action < 0)
|
||||
retval = ioctl(s, SIOCDIFADDR, &ifa);
|
||||
retval = ioctl(a_fd, SIOCDIFADDR, &ifa);
|
||||
else
|
||||
retval = ioctl(s, SIOCAIFADDR, &ifa);
|
||||
close(s);
|
||||
retval = ioctl(a_fd, SIOCAIFADDR, &ifa);
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -154,7 +161,6 @@ if_route(const struct interface *iface, const struct in_addr *dest,
|
||||
const struct in_addr *net, const struct in_addr *gate,
|
||||
_unused int metric, int action)
|
||||
{
|
||||
int s;
|
||||
union sockunion {
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_in sin;
|
||||
@ -186,9 +192,6 @@ if_route(const struct interface *iface, const struct in_addr *dest,
|
||||
ADDSU(su); \
|
||||
}
|
||||
|
||||
if ((s = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
|
||||
return -1;
|
||||
|
||||
memset(&rtm, 0, sizeof(rtm));
|
||||
rtm.hdr.rtm_version = RTM_VERSION;
|
||||
rtm.hdr.rtm_seq = 1;
|
||||
@ -244,22 +247,19 @@ if_route(const struct interface *iface, const struct in_addr *dest,
|
||||
ADDADDR(&iface->addr);
|
||||
|
||||
rtm.hdr.rtm_msglen = l = bp - (char *)&rtm;
|
||||
if (write(s, &rtm, l) == -1)
|
||||
if (write(r_fd, &rtm, l) == -1)
|
||||
retval = -1;
|
||||
close(s);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int
|
||||
arp_flush(void)
|
||||
{
|
||||
int s, mib[6], retval = 0;
|
||||
int mib[6], retval = 0;
|
||||
size_t buffer_len = 0;
|
||||
char *buffer, *e, *p;
|
||||
struct rt_msghdr *rtm;
|
||||
|
||||
if ((s = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
|
||||
return -1;
|
||||
mib[0] = CTL_NET;
|
||||
mib[1] = PF_ROUTE;
|
||||
mib[2] = 0;
|
||||
@ -280,13 +280,12 @@ arp_flush(void)
|
||||
if (rtm->rtm_flags & RTF_STATIC)
|
||||
continue;
|
||||
rtm->rtm_type = RTM_DELETE;
|
||||
if (write(s, rtm, rtm->rtm_msglen) == -1) {
|
||||
if (write(r_fd, rtm, rtm->rtm_msglen) == -1) {
|
||||
retval = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(buffer);
|
||||
close(s);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
112
if-linux.c
112
if-linux.c
@ -66,6 +66,7 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "common.h"
|
||||
#include "configure.h"
|
||||
#include "dhcp.h"
|
||||
#include "net.h"
|
||||
|
||||
@ -75,6 +76,9 @@ static void (*nl_carrier)(const char *);
|
||||
static void (*nl_add)(const char *);
|
||||
static void (*nl_remove)(const char *);
|
||||
|
||||
static int sock_fd;
|
||||
static struct sockaddr_nl sock_nl;
|
||||
|
||||
int
|
||||
getifssid(const char *ifname, char *ssid)
|
||||
{
|
||||
@ -96,23 +100,37 @@ getifssid(const char *ifname, char *ssid)
|
||||
return retval;
|
||||
}
|
||||
|
||||
int
|
||||
open_link_socket(void)
|
||||
static int
|
||||
_open_link_socket(struct sockaddr_nl *nl)
|
||||
{
|
||||
int fd;
|
||||
struct sockaddr_nl nl;
|
||||
|
||||
if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1)
|
||||
return -1;
|
||||
memset(&nl, 0, sizeof(nl));
|
||||
nl.nl_family = AF_NETLINK;
|
||||
nl.nl_groups = RTMGRP_LINK;
|
||||
if (bind(fd, (struct sockaddr *)&nl, sizeof(nl)) == -1)
|
||||
nl->nl_family = AF_NETLINK;
|
||||
if (bind(fd, (struct sockaddr *)nl, sizeof(*nl)) == -1)
|
||||
return -1;
|
||||
set_cloexec(fd);
|
||||
return fd;
|
||||
}
|
||||
|
||||
int
|
||||
init_socket(void)
|
||||
{
|
||||
sock_fd = _open_link_socket(&sock_nl);
|
||||
return sock_fd;
|
||||
}
|
||||
|
||||
int
|
||||
open_link_socket(void)
|
||||
{
|
||||
struct sockaddr_nl snl;
|
||||
|
||||
memset(&snl, 0, sizeof(snl));
|
||||
snl.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE;
|
||||
return _open_link_socket(&snl);
|
||||
}
|
||||
|
||||
static int
|
||||
get_netlink(int fd, int flags,
|
||||
int (*callback)(struct nlmsghdr *))
|
||||
@ -169,6 +187,63 @@ err_netlink(struct nlmsghdr *nlm)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
link_delroute(struct nlmsghdr *nlm)
|
||||
{
|
||||
int len, idx, metric;
|
||||
struct rtattr *rta;
|
||||
struct rtmsg *rtm;
|
||||
struct rt rt;
|
||||
char ifn[IF_NAMESIZE + 1];
|
||||
|
||||
len = nlm->nlmsg_len - sizeof(*nlm);
|
||||
if ((size_t)len < sizeof(*rtm)) {
|
||||
errno = EBADMSG;
|
||||
return -1;
|
||||
}
|
||||
rtm = NLMSG_DATA(nlm);
|
||||
if (rtm->rtm_type != RTN_UNICAST ||
|
||||
rtm->rtm_table != RT_TABLE_MAIN ||
|
||||
rtm->rtm_family != AF_INET ||
|
||||
nlm->nlmsg_pid == (uint32_t)getpid())
|
||||
return 1;
|
||||
rta = (struct rtattr *) ((char *)rtm + NLMSG_ALIGN(sizeof(*rtm)));
|
||||
len = NLMSG_PAYLOAD(nlm, sizeof(*rtm));
|
||||
rt.iface = NULL;
|
||||
rt.next = NULL;
|
||||
metric = 0;
|
||||
while (RTA_OK(rta, len)) {
|
||||
switch (rta->rta_type) {
|
||||
case RTA_DST:
|
||||
memcpy(&rt.dest.s_addr, RTA_DATA(rta),
|
||||
sizeof(rt.dest.s_addr));
|
||||
break;
|
||||
case RTA_GATEWAY:
|
||||
memcpy(&rt.gate.s_addr, RTA_DATA(rta),
|
||||
sizeof(rt.gate.s_addr));
|
||||
break;
|
||||
case RTA_OIF:
|
||||
idx = *(int *)RTA_DATA(rta);
|
||||
if (if_indextoname(idx, ifn))
|
||||
rt.iface = find_interface(ifn);
|
||||
break;
|
||||
case RTA_PRIORITY:
|
||||
metric = *(int *)RTA_DATA(rta);
|
||||
break;
|
||||
}
|
||||
rta = RTA_NEXT(rta, len);
|
||||
}
|
||||
if (rt.iface != NULL) {
|
||||
if (metric == rt.iface->metric) {
|
||||
if (rt.dest.s_addr == INADDR_BROADCAST)
|
||||
rt.dest.s_addr = INADDR_ANY;
|
||||
inet_cidrtoaddr(rtm->rtm_dst_len, &rt.net);
|
||||
route_deleted(&rt);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
link_netlink(struct nlmsghdr *nlm)
|
||||
{
|
||||
@ -177,6 +252,9 @@ link_netlink(struct nlmsghdr *nlm)
|
||||
struct ifinfomsg *ifi;
|
||||
char ifn[IF_NAMESIZE + 1];
|
||||
|
||||
if (nlm->nlmsg_type == RTM_DELROUTE)
|
||||
return link_delroute(nlm);
|
||||
|
||||
if (nlm->nlmsg_type != RTM_NEWLINK && nlm->nlmsg_type != RTM_DELLINK)
|
||||
return 0;
|
||||
len = nlm->nlmsg_len - sizeof(*nlm);
|
||||
@ -234,37 +312,27 @@ manage_link(int fd,
|
||||
static int
|
||||
send_netlink(struct nlmsghdr *hdr)
|
||||
{
|
||||
int fd, r;
|
||||
struct sockaddr_nl nl;
|
||||
int r;
|
||||
struct iovec iov;
|
||||
struct msghdr msg;
|
||||
static unsigned int seq;
|
||||
|
||||
if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1)
|
||||
return -1;
|
||||
memset(&nl, 0, sizeof(nl));
|
||||
nl.nl_family = AF_NETLINK;
|
||||
if (bind(fd, (struct sockaddr *)&nl, sizeof(nl)) == -1) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
memset(&iov, 0, sizeof(iov));
|
||||
iov.iov_base = hdr;
|
||||
iov.iov_len = hdr->nlmsg_len;
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.msg_name = &nl;
|
||||
msg.msg_namelen = sizeof(nl);
|
||||
msg.msg_name = &sock_nl;
|
||||
msg.msg_namelen = sizeof(sock_nl);
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
/* Request a reply */
|
||||
hdr->nlmsg_flags |= NLM_F_ACK;
|
||||
hdr->nlmsg_seq = ++seq;
|
||||
|
||||
if (sendmsg(fd, &msg, 0) != -1)
|
||||
r = get_netlink(fd, 0, &err_netlink);
|
||||
if (sendmsg(sock_fd, &msg, 0) != -1)
|
||||
r = get_netlink(sock_fd, 0, &err_netlink);
|
||||
else
|
||||
r = -1;
|
||||
close(fd);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user