mirror of
https://github.com/rsmarples/dhcpcd.git
synced 2024-11-27 20:14:15 +08:00
After adding an address load the kernel routing table for the interface.
When routes are rebuilt try not to remove any existing routes if they don't need changing.
This commit is contained in:
parent
a3fb51a3dd
commit
a19fe49202
2
defs.h
2
defs.h
@ -28,7 +28,7 @@
|
||||
#define CONFIG_H
|
||||
|
||||
#define PACKAGE "dhcpcd"
|
||||
#define VERSION "6.7.1"
|
||||
#define VERSION "6.7.99.3"
|
||||
|
||||
#ifndef CONFIG
|
||||
# define CONFIG SYSCONFDIR "/" PACKAGE ".conf"
|
||||
|
3
dhcp.c
3
dhcp.c
@ -2990,6 +2990,9 @@ dhcp_init(struct interface *ifp)
|
||||
/* 0 is a valid fd, so init to -1 */
|
||||
state->raw_fd = state->arp_fd = -1;
|
||||
TAILQ_INIT(&state->arp_states);
|
||||
|
||||
/* Now is a good time to find IPv4 routes */
|
||||
if_initrt(ifp);
|
||||
}
|
||||
|
||||
state->state = DHS_INIT;
|
||||
|
1
dhcpcd.h
1
dhcpcd.h
@ -122,6 +122,7 @@ struct dhcpcd_ctx {
|
||||
struct dhcp_opt *dhcp_opts;
|
||||
size_t dhcp_opts_len;
|
||||
struct rt_head *ipv4_routes;
|
||||
struct rt_head *ipv4_kroutes;
|
||||
|
||||
int udp_fd;
|
||||
uint8_t *packet;
|
||||
|
453
if-bsd.c
453
if-bsd.c
@ -93,13 +93,15 @@
|
||||
#define RT_ADVANCE(x, n) (x += RT_ROUNDUP((n)->sa_len))
|
||||
#endif
|
||||
|
||||
#define COPYOUT(sin, sa) \
|
||||
if ((sa) && (sa)->sa_family == AF_INET) \
|
||||
(sin) = ((struct sockaddr_in*)(void *)(sa))->sin_addr
|
||||
#define COPYOUT(sin, sa) do { \
|
||||
if ((sa) && ((sa)->sa_family == AF_INET || (sa)->sa_family == 255)) \
|
||||
(sin) = ((struct sockaddr_in*)(void *)(sa))->sin_addr; \
|
||||
} while (0)
|
||||
|
||||
#define COPYOUT6(sin, sa) \
|
||||
if ((sa) && (sa)->sa_family == AF_INET6) \
|
||||
(sin) = ((struct sockaddr_in6*)(void *)(sa))->sin6_addr
|
||||
#define COPYOUT6(sin, sa) do { \
|
||||
if ((sa) && ((sa)->sa_family == AF_INET6 || (sa)->sa_family == 255)) \
|
||||
(sin) = ((struct sockaddr_in6*)(void *)(sa))->sin6_addr; \
|
||||
} while (0)
|
||||
|
||||
#ifndef CLLADDR
|
||||
# define CLLADDR(s) ((const char *)((s)->sdl_data + (s)->sdl_nlen))
|
||||
@ -259,6 +261,33 @@ if_vimaster(const char *ifname)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
get_addrs(int type, char *cp, struct sockaddr **sa)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < RTAX_MAX; i++) {
|
||||
if (type & (1 << i)) {
|
||||
sa[i] = (struct sockaddr *)cp;
|
||||
RT_ADVANCE(cp, sa[i]);
|
||||
} else
|
||||
sa[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static struct interface *
|
||||
if_findsdl(struct dhcpcd_ctx *ctx, struct sockaddr_dl *sdl)
|
||||
{
|
||||
|
||||
if (sdl->sdl_nlen) {
|
||||
char ifname[IF_NAMESIZE];
|
||||
memcpy(ifname, sdl->sdl_data, sdl->sdl_nlen);
|
||||
ifname[sdl->sdl_nlen] = '\0';
|
||||
return if_find(ctx, ifname);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef INET
|
||||
const char *if_pfname = "Berkley Packet Filter";
|
||||
|
||||
@ -454,8 +483,67 @@ if_address(const struct interface *ifp, const struct in_addr *address,
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
if_copyrt(struct dhcpcd_ctx *ctx, struct rt *rt, struct rt_msghdr *rtm)
|
||||
{
|
||||
char *cp;
|
||||
struct sockaddr *sa, *rti_info[RTAX_MAX];
|
||||
|
||||
cp = (char *)(void *)(rtm + 1);
|
||||
sa = (struct sockaddr *)(void *)cp;
|
||||
if (sa->sa_family != AF_INET)
|
||||
return -1;
|
||||
if (~rtm->rtm_addrs & (RTA_DST | RTA_GATEWAY))
|
||||
return -1;
|
||||
#ifdef RTF_CLONED
|
||||
if (rtm->rtm_flags & RTF_CLONED)
|
||||
return -1;
|
||||
#endif
|
||||
#ifdef RTF_LOCAL
|
||||
if (rtm->rtm_flags & RTF_LOCAL)
|
||||
return -1;
|
||||
#endif
|
||||
#ifdef RTF_BROADCAST
|
||||
if (rtm->rtm_flags & RTF_BROADCAST)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
get_addrs(rtm->rtm_addrs, cp, rti_info);
|
||||
memset(rt, 0, sizeof(*rt));
|
||||
COPYOUT(rt->dest, rti_info[RTAX_DST]);
|
||||
if (rtm->rtm_addrs & RTA_NETMASK)
|
||||
COPYOUT(rt->net, rti_info[RTAX_NETMASK]);
|
||||
else
|
||||
rt->net.s_addr = INADDR_BROADCAST;
|
||||
COPYOUT(rt->gate, rti_info[RTAX_GATEWAY]);
|
||||
#ifdef SIOCGIFPRIORITY
|
||||
rt->metric = rtm->rtm_priority;
|
||||
#endif
|
||||
|
||||
if (rtm->rtm_index)
|
||||
rt->iface = if_findindex(ctx, rtm->rtm_index);
|
||||
else if (rtm->rtm_addrs & RTA_IFP) {
|
||||
struct sockaddr_dl *sdl;
|
||||
|
||||
sdl = (struct sockaddr_dl *)(void *)rti_info[RTAX_IFP];
|
||||
rt->iface = if_findsdl(ctx, sdl);
|
||||
}
|
||||
/* If we don't have an interface and it's a host route, it maybe
|
||||
* to a local ip via the loopback interface. */
|
||||
if (rt->iface == NULL &&
|
||||
!(~rtm->rtm_flags & (RTF_HOST | RTF_GATEWAY)))
|
||||
{
|
||||
struct ipv4_addr *ia;
|
||||
|
||||
if ((ia = ipv4_findaddr(ctx, &rt->dest)))
|
||||
rt->iface = ia->iface;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
if_route(const struct rt *rt, int action)
|
||||
if_route(unsigned char cmd, const struct rt *rt, struct rt *srt)
|
||||
{
|
||||
const struct dhcp_state *state;
|
||||
union sockunion {
|
||||
@ -467,7 +555,7 @@ if_route(const struct rt *rt, int action)
|
||||
struct rtm
|
||||
{
|
||||
struct rt_msghdr hdr;
|
||||
char buffer[sizeof(su) * 5];
|
||||
char buffer[sizeof(su) * RTAX_MAX];
|
||||
} rtm;
|
||||
char *bp = rtm.buffer;
|
||||
size_t l;
|
||||
@ -489,45 +577,53 @@ if_route(const struct rt *rt, int action)
|
||||
ADDSU; \
|
||||
}
|
||||
|
||||
state = D_CSTATE(rt->iface);
|
||||
if (cmd != RTM_DELETE)
|
||||
state = D_CSTATE(rt->iface);
|
||||
else /* appease GCC */
|
||||
state = NULL;
|
||||
memset(&rtm, 0, sizeof(rtm));
|
||||
rtm.hdr.rtm_version = RTM_VERSION;
|
||||
rtm.hdr.rtm_seq = 1;
|
||||
rtm.hdr.rtm_type = cmd;
|
||||
rtm.hdr.rtm_addrs = RTA_DST;
|
||||
if (action == 0)
|
||||
rtm.hdr.rtm_type = RTM_CHANGE;
|
||||
else if (action > 0) {
|
||||
rtm.hdr.rtm_type = RTM_ADD;
|
||||
if (cmd == RTM_ADD || cmd == RTM_CHANGE)
|
||||
rtm.hdr.rtm_addrs |= RTA_GATEWAY;
|
||||
} else
|
||||
rtm.hdr.rtm_type = RTM_DELETE;
|
||||
rtm.hdr.rtm_flags = RTF_UP;
|
||||
#ifdef RTF_PINNED
|
||||
if (rtm.hdr.rtm_type != RTM_ADD)
|
||||
if (cmd != RTM_ADD)
|
||||
rtm.hdr.rtm_flags |= RTF_PINNED;
|
||||
#endif
|
||||
#ifdef SIOCGIFPRIORITY
|
||||
rtm.hdr.rtm_priority = rt->metric;
|
||||
#endif
|
||||
|
||||
/* None interface subnet routes are static. */
|
||||
if (rt->gate.s_addr != INADDR_ANY ||
|
||||
rt->net.s_addr != state->net.s_addr ||
|
||||
rt->dest.s_addr != (state->addr.s_addr & state->net.s_addr))
|
||||
rtm.hdr.rtm_flags |= RTF_STATIC;
|
||||
if (cmd != RTM_DELETE) {
|
||||
rtm.hdr.rtm_addrs |= RTA_IFA | RTA_IFP;
|
||||
/* None interface subnet routes are static. */
|
||||
if (rt->gate.s_addr != INADDR_ANY ||
|
||||
rt->net.s_addr != state->net.s_addr ||
|
||||
rt->dest.s_addr != (state->addr.s_addr & state->net.s_addr))
|
||||
rtm.hdr.rtm_flags |= RTF_STATIC;
|
||||
}
|
||||
if (rt->dest.s_addr == rt->gate.s_addr &&
|
||||
rt->net.s_addr == INADDR_BROADCAST)
|
||||
rtm.hdr.rtm_flags |= RTF_HOST;
|
||||
else if (rt->gate.s_addr == htonl(INADDR_LOOPBACK) &&
|
||||
rt->net.s_addr == INADDR_BROADCAST)
|
||||
{
|
||||
rtm.hdr.rtm_flags |= RTF_HOST | RTF_GATEWAY;
|
||||
else {
|
||||
/* Going via lo0 so remove the interface flags */
|
||||
if (cmd == RTM_ADD)
|
||||
rtm.hdr.rtm_addrs &= ~(RTA_IFA | RTA_IFP);
|
||||
} else {
|
||||
rtm.hdr.rtm_addrs |= RTA_NETMASK;
|
||||
if (rtm.hdr.rtm_flags & RTF_STATIC)
|
||||
rtm.hdr.rtm_flags |= RTF_GATEWAY;
|
||||
if (action >= 0)
|
||||
rtm.hdr.rtm_addrs |= RTA_IFA;
|
||||
}
|
||||
if (((cmd == RTM_ADD || cmd == RTM_CHANGE) &&
|
||||
!(rtm.hdr.rtm_flags & RTF_GATEWAY)) ||
|
||||
cmd == RTM_GET)
|
||||
rtm.hdr.rtm_addrs |= RTA_IFA | RTA_IFP;
|
||||
|
||||
ADDADDR(&rt->dest);
|
||||
if (rtm.hdr.rtm_addrs & RTA_GATEWAY) {
|
||||
@ -544,23 +640,74 @@ if_route(const struct rt *rt, int action)
|
||||
if (rtm.hdr.rtm_addrs & RTA_NETMASK)
|
||||
ADDADDR(&rt->net);
|
||||
|
||||
if (rtm.hdr.rtm_addrs & RTA_IFP) {
|
||||
if_linkaddr(&su.sdl, rt->iface);
|
||||
ADDSU;
|
||||
}
|
||||
if ((cmd == RTM_ADD || cmd == RTM_CHANGE) &&
|
||||
(rtm.hdr.rtm_addrs & (RTA_IFP | RTA_IFA)))
|
||||
{
|
||||
rtm.hdr.rtm_index = (unsigned short)rt->iface->index;
|
||||
if (rtm.hdr.rtm_addrs & RTA_IFP) {
|
||||
if_linkaddr(&su.sdl, rt->iface);
|
||||
ADDSU;
|
||||
}
|
||||
|
||||
if (rtm.hdr.rtm_addrs & RTA_IFA)
|
||||
ADDADDR(&state->addr);
|
||||
if (rtm.hdr.rtm_addrs & RTA_IFA)
|
||||
ADDADDR(&state->addr);
|
||||
}
|
||||
|
||||
#undef ADDADDR
|
||||
#undef ADDSU
|
||||
|
||||
rtm.hdr.rtm_msglen = (unsigned short)(bp - (char *)&rtm);
|
||||
|
||||
retval = write(s, &rtm, rtm.hdr.rtm_msglen) == -1 ? -1 : 0;
|
||||
|
||||
if (cmd == RTM_GET && retval == 0) {
|
||||
retval = read(s, &rtm, sizeof(rtm));
|
||||
if (retval < (int)sizeof(struct rt_msghdr) ||
|
||||
retval < rtm.hdr.rtm_msglen)
|
||||
retval = -1;
|
||||
else
|
||||
retval = if_copyrt(rt->iface->ctx, srt, &rtm.hdr);
|
||||
}
|
||||
|
||||
close(s);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int
|
||||
if_initrt(struct interface *ifp)
|
||||
{
|
||||
struct rt_msghdr *rtm;
|
||||
int mib[6];
|
||||
size_t needed;
|
||||
char *buf, *p, *end;
|
||||
struct rt rt;
|
||||
|
||||
ipv4_freerts(ifp->ctx->ipv4_kroutes);
|
||||
|
||||
mib[0] = CTL_NET;
|
||||
mib[1] = PF_ROUTE;
|
||||
mib[2] = 0;
|
||||
mib[3] = AF_INET;
|
||||
mib[4] = NET_RT_DUMP;
|
||||
mib[5] = 0;
|
||||
|
||||
if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
|
||||
return -1;
|
||||
if (needed == 0)
|
||||
return 0;
|
||||
if ((buf = malloc(needed)) == NULL)
|
||||
return -1;
|
||||
if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1)
|
||||
return -1;
|
||||
|
||||
end = buf + needed;
|
||||
for (p = buf; p < end; p += rtm->rtm_msglen) {
|
||||
rtm = (struct rt_msghdr *)(void *)p;
|
||||
if (if_copyrt(ifp->ctx, &rt, rtm) == 0)
|
||||
ipv4_handlert(ifp->ctx, RTM_ADD, &rt);
|
||||
}
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef INET6
|
||||
@ -642,8 +789,110 @@ if_address6(const struct ipv6_addr *a, int action)
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
if_copyrt6(struct dhcpcd_ctx *ctx, struct rt6 *rt, struct rt_msghdr *rtm)
|
||||
{
|
||||
char *cp;
|
||||
struct sockaddr *sa, *rti_info[RTAX_MAX];
|
||||
|
||||
cp = (char *)(void *)(rtm + 1);
|
||||
sa = (struct sockaddr *)(void *)cp;
|
||||
if (sa->sa_family != AF_INET6)
|
||||
return -1;
|
||||
if (~rtm->rtm_addrs & (RTA_DST | RTA_GATEWAY))
|
||||
return -1;
|
||||
#ifdef RTF_CLONED
|
||||
if (rtm->rtm_flags & (RTF_CLONED | RTF_HOST))
|
||||
return -1;
|
||||
#else
|
||||
if (rtm->rtm_flags & RTF_HOST)
|
||||
return -1;
|
||||
#endif
|
||||
#ifdef RTF_LOCAL
|
||||
if (rtm->rtm_flags & RTF_LOCAL)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
get_addrs(rtm->rtm_addrs, cp, rti_info);
|
||||
memset(rt, 0, sizeof(*rt));
|
||||
COPYOUT6(rt->dest, rti_info[RTAX_DST]);
|
||||
if (rtm->rtm_addrs & RTA_NETMASK) {
|
||||
/*
|
||||
* We need to zero out the struct beyond sin6_len and
|
||||
* ensure it's valid.
|
||||
* I have no idea what the invalid data is for, could be
|
||||
* a kernel bug or actually used for something.
|
||||
* Either way it needs to be zeroed out.
|
||||
*/
|
||||
struct sockaddr_in6 *sin6;
|
||||
size_t e, i, len = 0, final = 0;
|
||||
|
||||
sin6 = (struct sockaddr_in6 *)(void *)rti_info[RTAX_NETMASK];
|
||||
rt->net = sin6->sin6_addr;
|
||||
e = sin6->sin6_len - offsetof(struct sockaddr_in6, sin6_addr);
|
||||
if (e > sizeof(struct in6_addr))
|
||||
e = sizeof(struct in6_addr);
|
||||
for (i = 0; i < e; i++) {
|
||||
switch (rt->net.s6_addr[i] & 0xff) {
|
||||
case 0xff:
|
||||
/* We don't really want the length,
|
||||
* just that it's valid */
|
||||
len++;
|
||||
break;
|
||||
case 0xfe:
|
||||
case 0xfc:
|
||||
case 0xf8:
|
||||
case 0xf0:
|
||||
case 0xe0:
|
||||
case 0xc0:
|
||||
case 0x80:
|
||||
len++;
|
||||
final = 1;
|
||||
break;
|
||||
default:
|
||||
rt->net.s6_addr[i] = 0x00;
|
||||
final = 1;
|
||||
break;
|
||||
}
|
||||
if (final)
|
||||
break;
|
||||
}
|
||||
if (len == 0)
|
||||
i = 0;
|
||||
while (i < sizeof(rt->net.s6_addr))
|
||||
rt->net.s6_addr[i++] = 0x00;
|
||||
} else
|
||||
ipv6_mask(&rt->net, 128);
|
||||
COPYOUT6(rt->gate, rti_info[RTAX_GATEWAY]);
|
||||
#ifdef SIOCGIFPRIORITY
|
||||
rt->metric = rtm->rtm_priority;
|
||||
#endif
|
||||
|
||||
if (rtm->rtm_index)
|
||||
rt->iface = if_findindex(ctx, rtm->rtm_index);
|
||||
else if (rtm->rtm_addrs & RTA_IFP) {
|
||||
struct sockaddr_dl *sdl;
|
||||
|
||||
sdl = (struct sockaddr_dl *)(void *)rti_info[RTAX_IFP];
|
||||
rt->iface = if_findsdl(ctx, sdl);
|
||||
}
|
||||
/* If we don't have an interface and it's a host route, it maybe
|
||||
* to a local ip via the loopback interface. */
|
||||
if (rt->iface == NULL &&
|
||||
!(~rtm->rtm_flags & (RTF_HOST | RTF_GATEWAY)))
|
||||
{
|
||||
struct ipv6_addr *ia;
|
||||
|
||||
if ((ia = ipv6_findaddr(ctx, &rt->dest, 0)))
|
||||
rt->iface = ia->iface;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
if_route6(const struct rt6 *rt, int action)
|
||||
if_route6(unsigned char cmd, const struct rt6 *rt, struct rt6 *srt)
|
||||
{
|
||||
union sockunion {
|
||||
struct sockaddr sa;
|
||||
@ -654,12 +903,11 @@ if_route6(const struct rt6 *rt, int action)
|
||||
struct rtm
|
||||
{
|
||||
struct rt_msghdr hdr;
|
||||
char buffer[sizeof(su) * 5];
|
||||
char buffer[sizeof(su) * RTAX_MAX];
|
||||
} rtm;
|
||||
char *bp = rtm.buffer;
|
||||
size_t l;
|
||||
int s, retval;
|
||||
const struct ipv6_addr *lla;
|
||||
|
||||
if ((s = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
|
||||
return -1;
|
||||
@ -683,12 +931,7 @@ if_route6(const struct rt6 *rt, int action)
|
||||
memset(&rtm, 0, sizeof(rtm));
|
||||
rtm.hdr.rtm_version = RTM_VERSION;
|
||||
rtm.hdr.rtm_seq = 1;
|
||||
if (action == 0)
|
||||
rtm.hdr.rtm_type = RTM_CHANGE;
|
||||
else if (action > 0)
|
||||
rtm.hdr.rtm_type = RTM_ADD;
|
||||
else
|
||||
rtm.hdr.rtm_type = RTM_DELETE;
|
||||
rtm.hdr.rtm_type = cmd;
|
||||
rtm.hdr.rtm_flags = RTF_UP | (int)rt->flags;
|
||||
#ifdef RTF_PINNED
|
||||
if (rtm.hdr.rtm_type != RTM_ADD)
|
||||
@ -706,14 +949,13 @@ if_route6(const struct rt6 *rt, int action)
|
||||
} else
|
||||
rtm.hdr.rtm_flags |= RTF_GATEWAY | RTF_STATIC;
|
||||
|
||||
if (action >= 0) {
|
||||
if (cmd == RTM_ADD)
|
||||
rtm.hdr.rtm_addrs |= RTA_GATEWAY;
|
||||
if (!(rtm.hdr.rtm_flags & RTF_REJECT))
|
||||
rtm.hdr.rtm_addrs |= RTA_IFP | RTA_IFA;
|
||||
}
|
||||
if (cmd == RTM_GET ||
|
||||
(cmd == RTM_ADD && !(rtm.hdr.rtm_flags & RTF_REJECT)))
|
||||
rtm.hdr.rtm_addrs |= RTA_IFP | RTA_IFA;
|
||||
|
||||
ADDADDR(&rt->dest);
|
||||
lla = NULL;
|
||||
if (rtm.hdr.rtm_addrs & RTA_GATEWAY) {
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&rt->gate)) {
|
||||
if_linkaddr(&su.sdl, rt->iface);
|
||||
@ -726,51 +968,86 @@ if_route6(const struct rt6 *rt, int action)
|
||||
if (rtm.hdr.rtm_addrs & RTA_NETMASK)
|
||||
ADDADDR(&rt->net);
|
||||
|
||||
if (rtm.hdr.rtm_addrs & RTA_IFP) {
|
||||
if_linkaddr(&su.sdl, rt->iface);
|
||||
ADDSU;
|
||||
}
|
||||
if ((cmd == RTM_ADD || cmd == RTM_CHANGE) &&
|
||||
(rtm.hdr.rtm_addrs & (RTA_IFP | RTA_IFA)))
|
||||
{
|
||||
rtm.hdr.rtm_index = (unsigned short)rt->iface->index;
|
||||
if (rtm.hdr.rtm_addrs & RTA_IFP) {
|
||||
if_linkaddr(&su.sdl, rt->iface);
|
||||
ADDSU;
|
||||
}
|
||||
|
||||
if (rtm.hdr.rtm_addrs & RTA_IFA) {
|
||||
const struct ipv6_addr *lla;
|
||||
|
||||
if (rtm.hdr.rtm_addrs & RTA_IFA) {
|
||||
if (lla == NULL) {
|
||||
lla = ipv6_linklocal(rt->iface);
|
||||
if (lla == NULL) /* unlikely */
|
||||
return -1;
|
||||
return -1;
|
||||
ADDADDRS(&lla->addr, rt->iface->index);
|
||||
}
|
||||
|
||||
if (rt->mtu) {
|
||||
rtm.hdr.rtm_inits |= RTV_MTU;
|
||||
rtm.hdr.rtm_rmx.rmx_mtu = rt->mtu;
|
||||
}
|
||||
ADDADDRS(&lla->addr, rt->iface->index);
|
||||
}
|
||||
|
||||
#undef ADDADDR
|
||||
#undef ADDSU
|
||||
|
||||
if (action >= 0 && rt->mtu) {
|
||||
rtm.hdr.rtm_inits |= RTV_MTU;
|
||||
rtm.hdr.rtm_rmx.rmx_mtu = rt->mtu;
|
||||
rtm.hdr.rtm_msglen = (unsigned short)(bp - (char *)&rtm);
|
||||
retval = write(s, &rtm, rtm.hdr.rtm_msglen) == -1 ? -1 : 0;
|
||||
|
||||
if (cmd == RTM_GET && retval == 0) {
|
||||
retval = read(s, &rtm, sizeof(rtm));
|
||||
if (retval < (int)sizeof(struct rt_msghdr) ||
|
||||
retval < rtm.hdr.rtm_msglen)
|
||||
retval = -1;
|
||||
else
|
||||
retval = if_copyrt6(rt->iface->ctx, srt, &rtm.hdr);
|
||||
}
|
||||
|
||||
rtm.hdr.rtm_msglen = (unsigned short)(bp - (char *)&rtm);
|
||||
|
||||
retval = write(s, &rtm, rtm.hdr.rtm_msglen) == -1 ? -1 : 0;
|
||||
close(s);
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
get_addrs(int type, char *cp, struct sockaddr **sa)
|
||||
int
|
||||
if_initrt6(struct interface *ifp)
|
||||
{
|
||||
int i;
|
||||
struct rt_msghdr *rtm;
|
||||
int mib[6];
|
||||
size_t needed;
|
||||
char *buf, *p, *end;
|
||||
struct rt6 rt;
|
||||
|
||||
for (i = 0; i < RTAX_MAX; i++) {
|
||||
if (type & (1 << i)) {
|
||||
sa[i] = (struct sockaddr *)cp;
|
||||
RT_ADVANCE(cp, sa[i]);
|
||||
} else
|
||||
sa[i] = NULL;
|
||||
ipv6_freerts(&ifp->ctx->ipv6->kroutes);
|
||||
|
||||
mib[0] = CTL_NET;
|
||||
mib[1] = PF_ROUTE;
|
||||
mib[2] = 0;
|
||||
mib[3] = AF_INET6;
|
||||
mib[4] = NET_RT_DUMP;
|
||||
mib[5] = 0;
|
||||
|
||||
if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
|
||||
return -1;
|
||||
if (needed == 0)
|
||||
return 0;
|
||||
if ((buf = malloc(needed)) == NULL)
|
||||
return -1;
|
||||
if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1)
|
||||
return -1;
|
||||
|
||||
end = buf + needed;
|
||||
for (p = buf; p < end; p += rtm->rtm_msglen) {
|
||||
rtm = (struct rt_msghdr *)(void *)p;
|
||||
if (if_copyrt6(ifp->ctx, &rt, rtm) == 0)
|
||||
ipv6_handlert(ifp->ctx, RTM_ADD, &rt);
|
||||
}
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef INET6
|
||||
int
|
||||
if_addrflags6(const struct in6_addr *addr, const struct interface *ifp)
|
||||
{
|
||||
@ -862,11 +1139,8 @@ if_managelink(struct dhcpcd_ctx *ctx)
|
||||
int ifa_flags;
|
||||
#endif
|
||||
|
||||
bytes = read(ctx->link_fd, msg, sizeof(msg));
|
||||
if (bytes == -1)
|
||||
if ((bytes = read(ctx->link_fd, msg, sizeof(msg))) == -1)
|
||||
return -1;
|
||||
if (bytes == 0)
|
||||
return 0;
|
||||
e = msg + bytes;
|
||||
for (p = msg; p < e; p += rtm->rtm_msglen) {
|
||||
rtm = (struct rt_msghdr *)(void *)p;
|
||||
@ -919,27 +1193,16 @@ if_managelink(struct dhcpcd_ctx *ctx)
|
||||
case RTM_DELETE:
|
||||
cp = (char *)(void *)(rtm + 1);
|
||||
sa = (struct sockaddr *)(void *)cp;
|
||||
get_addrs(rtm->rtm_addrs, cp, rti_info);
|
||||
switch (sa->sa_family) {
|
||||
#ifdef INET
|
||||
case AF_INET:
|
||||
if (rtm->rtm_type != RTM_DELETE)
|
||||
break;
|
||||
if (~rtm->rtm_addrs &
|
||||
(RTA_DST | RTA_GATEWAY | RTA_NETMASK))
|
||||
break;
|
||||
memset(&rt, 0, sizeof(rt));
|
||||
rt.iface = NULL;
|
||||
COPYOUT(rt.dest, rti_info[RTAX_DST]);
|
||||
COPYOUT(rt.net, rti_info[RTAX_NETMASK]);
|
||||
COPYOUT(rt.gate, rti_info[RTAX_GATEWAY]);
|
||||
ipv4_routedeleted(ctx, &rt);
|
||||
if (if_copyrt(ctx, &rt, rtm) == 0)
|
||||
ipv4_handlert(ctx, rtm->rtm_type, &rt);
|
||||
break;
|
||||
#endif
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
if (~rtm->rtm_addrs &
|
||||
(RTA_DST | RTA_GATEWAY))
|
||||
if (~rtm->rtm_addrs & (RTA_DST | RTA_GATEWAY))
|
||||
break;
|
||||
/*
|
||||
* BSD caches host routes in the
|
||||
@ -949,6 +1212,7 @@ if_managelink(struct dhcpcd_ctx *ctx)
|
||||
* with a hardware address
|
||||
*/
|
||||
if (rtm->rtm_flags & (RTF_HOST)) {
|
||||
get_addrs(rtm->rtm_addrs, cp, rti_info);
|
||||
COPYOUT6(ia6, rti_info[RTAX_DST]);
|
||||
DESCOPE(&ia6);
|
||||
if (rti_info[RTAX_GATEWAY]->sa_family
|
||||
@ -965,16 +1229,8 @@ if_managelink(struct dhcpcd_ctx *ctx)
|
||||
break;
|
||||
}
|
||||
|
||||
if (rtm->rtm_type != RTM_DELETE)
|
||||
break;
|
||||
if (!(rtm->rtm_addrs & RTA_NETMASK))
|
||||
break;
|
||||
memset(&rt6, 0, sizeof(rt6));
|
||||
rt6.iface = NULL;
|
||||
COPYOUT6(rt6.dest, rti_info[RTAX_DST]);
|
||||
COPYOUT6(rt6.net, rti_info[RTAX_NETMASK]);
|
||||
COPYOUT6(rt6.gate, rti_info[RTAX_GATEWAY]);
|
||||
ipv6_routedeleted(ctx, &rt6);
|
||||
if (if_copyrt6(ctx, &rt6, rtm) == 0)
|
||||
ipv6_handlert(ctx, rtm->rtm_type, &rt6);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
@ -1042,7 +1298,6 @@ if_managelink(struct dhcpcd_ctx *ctx)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
432
if-linux.c
432
if-linux.c
@ -320,7 +320,8 @@ err_netlink(struct nlmsghdr *nlm)
|
||||
|
||||
static int
|
||||
get_netlink(struct dhcpcd_ctx *ctx, struct interface *ifp, int fd, int flags,
|
||||
int (*callback)(struct dhcpcd_ctx *, struct interface *,struct nlmsghdr *))
|
||||
int (*callback)(struct dhcpcd_ctx *, struct interface *,
|
||||
struct nlmsghdr *, void *), void *data)
|
||||
{
|
||||
char *buf = NULL, *nbuf;
|
||||
ssize_t bytes;
|
||||
@ -363,8 +364,10 @@ get_netlink(struct dhcpcd_ctx *ctx, struct interface *ifp, int fd, int flags,
|
||||
goto eexit;
|
||||
}
|
||||
/* Ignore message if it is not from kernel */
|
||||
if (nladdr.nl_pid != 0)
|
||||
if (nladdr.nl_pid != 0) {
|
||||
r = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (nlm = (struct nlmsghdr *)(void *)buf;
|
||||
nlm && NLMSG_OK(nlm, (size_t)bytes);
|
||||
@ -376,7 +379,7 @@ get_netlink(struct dhcpcd_ctx *ctx, struct interface *ifp, int fd, int flags,
|
||||
if (r)
|
||||
continue;
|
||||
if (callback) {
|
||||
r = callback(ctx, ifp, nlm);
|
||||
r = callback(ctx, ifp, nlm, data);
|
||||
if (r != 0)
|
||||
goto eexit;
|
||||
}
|
||||
@ -388,6 +391,113 @@ eexit:
|
||||
return r;
|
||||
}
|
||||
|
||||
#ifdef INET
|
||||
static int
|
||||
if_copyrt(struct dhcpcd_ctx *ctx, struct rt *rt, struct nlmsghdr *nlm)
|
||||
{
|
||||
size_t len;
|
||||
struct rtmsg *rtm;
|
||||
struct rtattr *rta;
|
||||
struct in_addr prefsrc;
|
||||
|
||||
len = nlm->nlmsg_len - sizeof(*nlm);
|
||||
if (len < sizeof(*rtm)) {
|
||||
errno = EBADMSG;
|
||||
return -1;
|
||||
}
|
||||
rtm = (struct rtmsg *)NLMSG_DATA(nlm);
|
||||
if (rtm->rtm_table != RT_TABLE_MAIN || rtm->rtm_family != AF_INET)
|
||||
return -1;
|
||||
|
||||
memset(rt, 0, sizeof(*rt));
|
||||
prefsrc.s_addr = INADDR_ANY;
|
||||
rta = (struct rtattr *)RTM_RTA(rtm);
|
||||
len = RTM_PAYLOAD(nlm);
|
||||
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_PREFSRC:
|
||||
memcpy(&prefsrc.s_addr, RTA_DATA(rta),
|
||||
sizeof(prefsrc.s_addr));
|
||||
break;
|
||||
case RTA_OIF:
|
||||
rt->iface = if_findindex(ctx,
|
||||
*(unsigned int *)RTA_DATA(rta));
|
||||
break;
|
||||
case RTA_PRIORITY:
|
||||
rt->metric = *(unsigned int *)RTA_DATA(rta);
|
||||
break;
|
||||
}
|
||||
rta = RTA_NEXT(rta, len);
|
||||
}
|
||||
|
||||
inet_cidrtoaddr(rtm->rtm_dst_len, &rt->net);
|
||||
if (rt->iface == NULL && prefsrc.s_addr != INADDR_ANY) {
|
||||
struct ipv4_addr *ap;
|
||||
|
||||
/* For some reason the default route comes back with the
|
||||
* loopback interface in RTA_OIF? Lets find it by
|
||||
* preferred source address */
|
||||
if ((ap = ipv4_findaddr(ctx, &prefsrc)))
|
||||
rt->iface = ap->iface;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef INET6
|
||||
static int
|
||||
if_copyrt6(struct dhcpcd_ctx *ctx, struct rt6 *rt, struct nlmsghdr *nlm)
|
||||
{
|
||||
size_t len;
|
||||
struct rtmsg *rtm;
|
||||
struct rtattr *rta;
|
||||
|
||||
len = nlm->nlmsg_len - sizeof(*nlm);
|
||||
if (len < sizeof(*rtm)) {
|
||||
errno = EBADMSG;
|
||||
return -1;
|
||||
}
|
||||
rtm = (struct rtmsg *)NLMSG_DATA(nlm);
|
||||
if (rtm->rtm_table != RT_TABLE_MAIN || rtm->rtm_family != AF_INET6)
|
||||
return -1;
|
||||
|
||||
memset(rt, 0, sizeof(*rt));
|
||||
rta = (struct rtattr *)RTM_RTA(rtm);
|
||||
len = RTM_PAYLOAD(nlm);
|
||||
while (RTA_OK(rta, len)) {
|
||||
switch (rta->rta_type) {
|
||||
case RTA_DST:
|
||||
memcpy(&rt->dest.s6_addr, RTA_DATA(rta),
|
||||
sizeof(rt->dest.s6_addr));
|
||||
break;
|
||||
case RTA_GATEWAY:
|
||||
memcpy(&rt->gate.s6_addr, RTA_DATA(rta),
|
||||
sizeof(rt->gate.s6_addr));
|
||||
break;
|
||||
case RTA_OIF:
|
||||
rt->iface = if_findindex(ctx,
|
||||
*(unsigned int *)RTA_DATA(rta));
|
||||
break;
|
||||
case RTA_PRIORITY:
|
||||
rt->metric = *(unsigned int *)RTA_DATA(rta);
|
||||
break;
|
||||
}
|
||||
rta = RTA_NEXT(rta, len);
|
||||
}
|
||||
|
||||
ipv6_mask(&rt->net, rtm->rtm_dst_len);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Work out the maximum pid size */
|
||||
static inline long long
|
||||
get_max_pid_t()
|
||||
@ -405,29 +515,31 @@ link_route(struct dhcpcd_ctx *ctx, __unused struct interface *ifp,
|
||||
struct nlmsghdr *nlm)
|
||||
{
|
||||
size_t len;
|
||||
unsigned int metric;
|
||||
struct rtattr *rta;
|
||||
struct rtmsg *rtm;
|
||||
int cmd;
|
||||
#ifdef INET
|
||||
struct rt rt;
|
||||
#endif
|
||||
#ifdef INET6
|
||||
struct rt6 rt6;
|
||||
#endif
|
||||
|
||||
if (nlm->nlmsg_type != RTM_DELROUTE)
|
||||
switch (nlm->nlmsg_type) {
|
||||
case RTM_NEWROUTE:
|
||||
cmd = RTM_ADD;
|
||||
break;
|
||||
case RTM_DELROUTE:
|
||||
cmd = RTM_DELETE;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
len = nlm->nlmsg_len - sizeof(*nlm);
|
||||
if (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 && rtm->rtm_family != AF_INET6))
|
||||
return 1;
|
||||
|
||||
/* Ignore messages generated by us.
|
||||
* For some reason we get messages generated by us
|
||||
* with a very large value in nlmsg_pid that seems to be
|
||||
@ -435,83 +547,23 @@ link_route(struct dhcpcd_ctx *ctx, __unused struct interface *ifp,
|
||||
if (nlm->nlmsg_pid > get_max_pid_t())
|
||||
return 1;
|
||||
|
||||
rta = (struct rtattr *)(void *)((char *)rtm +NLMSG_ALIGN(sizeof(*rtm)));
|
||||
len = NLMSG_PAYLOAD(nlm, sizeof(*rtm));
|
||||
#ifdef INET
|
||||
if (rtm->rtm_family == AF_INET)
|
||||
memset(&rt, 0, sizeof(rt));
|
||||
#endif
|
||||
#ifdef INET6
|
||||
if (rtm->rtm_family == AF_INET6)
|
||||
memset(&rt6, 0, sizeof(rt6));
|
||||
#endif
|
||||
metric = 0;
|
||||
while (RTA_OK(rta, len)) {
|
||||
switch (rtm->rtm_family) {
|
||||
#ifdef INET
|
||||
case AF_INET:
|
||||
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:
|
||||
rt.iface = if_findindex(ctx,
|
||||
*(unsigned int *)RTA_DATA(rta));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
switch (rta->rta_type) {
|
||||
case RTA_DST:
|
||||
memcpy(&rt6.dest.s6_addr, RTA_DATA(rta),
|
||||
sizeof(rt6.dest.s6_addr));
|
||||
break;
|
||||
case RTA_GATEWAY:
|
||||
memcpy(&rt6.gate.s6_addr, RTA_DATA(rta),
|
||||
sizeof(rt6.gate.s6_addr));
|
||||
break;
|
||||
case RTA_OIF:
|
||||
rt6.iface = if_findindex(ctx,
|
||||
*(unsigned int *)RTA_DATA(rta));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
switch (rta->rta_type) {
|
||||
case RTA_PRIORITY:
|
||||
metric = *(unsigned int *)RTA_DATA(rta);
|
||||
break;
|
||||
}
|
||||
rta = RTA_NEXT(rta, len);
|
||||
}
|
||||
|
||||
rtm = NLMSG_DATA(nlm);
|
||||
switch (rtm->rtm_family) {
|
||||
#ifdef INET
|
||||
case AF_INET:
|
||||
if (rt.iface != NULL && metric == rt.iface->metric) {
|
||||
inet_cidrtoaddr(rtm->rtm_dst_len, &rt.net);
|
||||
ipv4_routedeleted(ctx, &rt);
|
||||
}
|
||||
break;
|
||||
case AF_INET:
|
||||
if (if_copyrt(ctx, &rt, nlm) == 0)
|
||||
ipv4_handlert(ctx, cmd, &rt);
|
||||
break;
|
||||
#endif
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
if (rt6.iface != NULL && metric == rt6.iface->metric) {
|
||||
ipv6_mask(&rt6.net, rtm->rtm_dst_len);
|
||||
ipv6_routedeleted(ctx, &rt6);
|
||||
}
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (if_copyrt6(ctx, &rt6, nlm) == 0)
|
||||
ipv6_handlert(ctx, cmd, &rt6);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -541,7 +593,7 @@ link_addr(struct dhcpcd_ctx *ctx, struct interface *ifp, struct nlmsghdr *nlm)
|
||||
* so it's not really an error */
|
||||
return 1;
|
||||
}
|
||||
rta = (struct rtattr *) IFA_RTA(ifa);
|
||||
rta = (struct rtattr *)IFA_RTA(ifa);
|
||||
len = NLMSG_PAYLOAD(nlm, sizeof(*ifa));
|
||||
switch (ifa->ifa_family) {
|
||||
#ifdef INET
|
||||
@ -585,7 +637,7 @@ link_addr(struct dhcpcd_ctx *ctx, struct interface *ifp, struct nlmsghdr *nlm)
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
@ -665,13 +717,13 @@ link_neigh(struct dhcpcd_ctx *ctx, __unused struct interface *ifp,
|
||||
ipv6nd_neighbour(ctx, &addr6, flags);
|
||||
}
|
||||
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
link_netlink(struct dhcpcd_ctx *ctx, struct interface *ifp,
|
||||
struct nlmsghdr *nlm)
|
||||
struct nlmsghdr *nlm, __unused void *data)
|
||||
{
|
||||
int r;
|
||||
size_t len;
|
||||
@ -700,7 +752,7 @@ link_netlink(struct dhcpcd_ctx *ctx, struct interface *ifp,
|
||||
}
|
||||
ifi = NLMSG_DATA(nlm);
|
||||
if (ifi->ifi_flags & IFF_LOOPBACK)
|
||||
return 1;
|
||||
return 0;
|
||||
rta = (struct rtattr *)(void *)((char *)ifi +NLMSG_ALIGN(sizeof(*ifi)));
|
||||
len = NLMSG_PAYLOAD(nlm, sizeof(*ifi));
|
||||
*ifn = '\0';
|
||||
@ -712,7 +764,7 @@ link_netlink(struct dhcpcd_ctx *ctx, struct interface *ifp,
|
||||
/* Ignore wireless messages */
|
||||
if (nlm->nlmsg_type == RTM_NEWLINK &&
|
||||
ifi->ifi_change == 0)
|
||||
return 1;
|
||||
return 0;
|
||||
break;
|
||||
case IFLA_IFNAME:
|
||||
strlcpy(ifn, RTA_DATA(rta), sizeof(ifn));
|
||||
@ -726,7 +778,7 @@ link_netlink(struct dhcpcd_ctx *ctx, struct interface *ifp,
|
||||
|
||||
if (nlm->nlmsg_type == RTM_DELLINK) {
|
||||
dhcpcd_handleinterface(ctx, -1, ifn);
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Virtual interfaces may not get a valid hardware address
|
||||
@ -735,12 +787,12 @@ link_netlink(struct dhcpcd_ctx *ctx, struct interface *ifp,
|
||||
* that that don't exist until they have one. */
|
||||
if (ifi->ifi_flags & IFF_MASTER && !hwaddr) {
|
||||
dhcpcd_handleinterface(ctx, -1, ifn);
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check for interface name change */
|
||||
if (handle_rename(ctx, (unsigned int)ifi->ifi_index, ifn))
|
||||
return 1;
|
||||
return 0;
|
||||
|
||||
/* Check for a new interface */
|
||||
ifp = if_find(ctx, ifn);
|
||||
@ -749,7 +801,7 @@ link_netlink(struct dhcpcd_ctx *ctx, struct interface *ifp,
|
||||
* the interface rather than the kernel. */
|
||||
if (dev_listening(ctx) < 1)
|
||||
dhcpcd_handleinterface(ctx, 1, ifn);
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Re-read hardware address and friends */
|
||||
@ -764,7 +816,7 @@ link_netlink(struct dhcpcd_ctx *ctx, struct interface *ifp,
|
||||
dhcpcd_handlecarrier(ctx,
|
||||
ifi->ifi_flags & IFF_RUNNING ? LINK_UP : LINK_DOWN,
|
||||
ifi->ifi_flags, ifn);
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
@ -772,13 +824,14 @@ if_managelink(struct dhcpcd_ctx *ctx)
|
||||
{
|
||||
|
||||
return get_netlink(ctx, NULL,
|
||||
ctx->link_fd, MSG_DONTWAIT, &link_netlink);
|
||||
ctx->link_fd, MSG_DONTWAIT, &link_netlink, NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
send_netlink(struct dhcpcd_ctx *ctx, struct interface *ifp,
|
||||
int protocol, struct nlmsghdr *hdr,
|
||||
int (*callback)(struct dhcpcd_ctx *, struct interface *,struct nlmsghdr *))
|
||||
int (*callback)(struct dhcpcd_ctx *, struct interface *,
|
||||
struct nlmsghdr *, void *), void *data)
|
||||
{
|
||||
int s, r;
|
||||
struct sockaddr_nl snl;
|
||||
@ -802,7 +855,7 @@ send_netlink(struct dhcpcd_ctx *ctx, struct interface *ifp,
|
||||
hdr->nlmsg_seq = ++seq;
|
||||
|
||||
if (sendmsg(s, &msg, 0) != -1)
|
||||
r = get_netlink(ctx, ifp, s, 0, callback);
|
||||
r = get_netlink(ctx, ifp, s, 0, callback, data);
|
||||
else
|
||||
r = -1;
|
||||
close(s);
|
||||
@ -861,7 +914,7 @@ nla_next(struct nlattr *nla, size_t *rem)
|
||||
{
|
||||
|
||||
*rem -= NLA_ALIGN(nla->nla_len);
|
||||
return (struct nlattr *)((char *)nla + NLA_ALIGN(nla->nla_len));
|
||||
return (struct nlattr *)(void *)((char *)nla + NLA_ALIGN(nla->nla_len));
|
||||
}
|
||||
|
||||
#define NLA_TYPE(nla) ((nla)->nla_type & NLA_TYPE_MASK)
|
||||
@ -935,7 +988,7 @@ gnl_parse(struct nlmsghdr *nlm, struct nlattr *tb[], int maxtype)
|
||||
|
||||
memset(tb, 0, sizeof(*tb) * ((unsigned int)maxtype + 1));
|
||||
ghdr = NLMSG_DATA(nlm);
|
||||
head = (struct nlattr *)((char *) ghdr + GENL_HDRLEN);
|
||||
head = (struct nlattr *)(void *)((char *) ghdr + GENL_HDRLEN);
|
||||
len = nlm->nlmsg_len - GENL_HDRLEN - NLMSG_HDRLEN;
|
||||
NLA_FOR_EACH_ATTR(nla, head, len, rem) {
|
||||
type = NLA_TYPE(nla);
|
||||
@ -948,7 +1001,7 @@ gnl_parse(struct nlmsghdr *nlm, struct nlattr *tb[], int maxtype)
|
||||
|
||||
static int
|
||||
_gnl_getfamily(__unused struct dhcpcd_ctx *ctx, __unused struct interface *ifp,
|
||||
struct nlmsghdr *nlm)
|
||||
struct nlmsghdr *nlm, __unused void *data)
|
||||
{
|
||||
struct nlattr *tb[CTRL_ATTR_FAMILY_ID + 1];
|
||||
uint16_t family;
|
||||
@ -959,7 +1012,7 @@ _gnl_getfamily(__unused struct dhcpcd_ctx *ctx, __unused struct interface *ifp,
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
family = *(uint16_t *)NLA_DATA(tb[CTRL_ATTR_FAMILY_ID]);
|
||||
family = *(uint16_t *)(void *)NLA_DATA(tb[CTRL_ATTR_FAMILY_ID]);
|
||||
return (int)family;
|
||||
}
|
||||
|
||||
@ -978,12 +1031,12 @@ gnl_getfamily(struct dhcpcd_ctx *ctx, const char *name)
|
||||
CTRL_ATTR_FAMILY_NAME, name) == -1)
|
||||
return -1;
|
||||
return send_netlink(ctx, NULL, NETLINK_GENERIC, &nlm.hdr,
|
||||
&_gnl_getfamily);
|
||||
&_gnl_getfamily, NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
_if_getssid(__unused struct dhcpcd_ctx *ctx, struct interface *ifp,
|
||||
struct nlmsghdr *nlm)
|
||||
struct nlmsghdr *nlm, __unused void *data)
|
||||
{
|
||||
struct nlattr *tb[NL80211_ATTR_SSID + 1];
|
||||
|
||||
@ -1028,7 +1081,7 @@ if_getssid_nl80211(struct interface *ifp)
|
||||
nla_put_32(&nlm.hdr, sizeof(nlm), NL80211_ATTR_IFINDEX, ifp->index);
|
||||
|
||||
return send_netlink(ifp->ctx, ifp,
|
||||
NETLINK_GENERIC, &nlm.hdr, &_if_getssid);
|
||||
NETLINK_GENERIC, &nlm.hdr, &_if_getssid, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1246,13 +1299,22 @@ if_address(const struct interface *iface,
|
||||
add_attr_l(&nlm.hdr, sizeof(nlm), IFA_BROADCAST,
|
||||
&broadcast->s_addr, sizeof(broadcast->s_addr));
|
||||
|
||||
if (send_netlink(iface->ctx, NULL, NETLINK_ROUTE, &nlm.hdr, NULL) == -1)
|
||||
if (send_netlink(iface->ctx, NULL, NETLINK_ROUTE, &nlm.hdr,
|
||||
NULL, NULL) == -1)
|
||||
retval = -1;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int
|
||||
_if_copyrt(struct dhcpcd_ctx *ctx, __unused struct interface *ifp,
|
||||
struct nlmsghdr *nlm, void *data)
|
||||
{
|
||||
|
||||
return if_copyrt(ctx, (struct rt *)data, nlm);
|
||||
}
|
||||
|
||||
int
|
||||
if_route(const struct rt *rt, int action)
|
||||
if_route(unsigned char cmd, const struct rt *rt, struct rt *srt)
|
||||
{
|
||||
struct nlmr nlm;
|
||||
int retval = 0;
|
||||
@ -1260,22 +1322,30 @@ if_route(const struct rt *rt, int action)
|
||||
|
||||
memset(&nlm, 0, sizeof(nlm));
|
||||
nlm.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
|
||||
nlm.hdr.nlmsg_type = RTM_NEWROUTE;
|
||||
if (action == 0)
|
||||
nlm.hdr.nlmsg_flags = NLM_F_REPLACE;
|
||||
else if (action == 1)
|
||||
switch (cmd) {
|
||||
case RTM_GET:
|
||||
nlm.hdr.nlmsg_type = RTM_GETROUTE;
|
||||
break;
|
||||
case RTM_CHANGE:
|
||||
nlm.hdr.nlmsg_type = RTM_NEWROUTE;
|
||||
nlm.hdr.nlmsg_flags = NLM_F_CREATE | NLM_F_REPLACE;
|
||||
break;
|
||||
case RTM_ADD:
|
||||
nlm.hdr.nlmsg_type = RTM_NEWROUTE;
|
||||
nlm.hdr.nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL;
|
||||
else
|
||||
break;
|
||||
case RTM_DELETE:
|
||||
nlm.hdr.nlmsg_type = RTM_DELROUTE;
|
||||
break;
|
||||
}
|
||||
nlm.hdr.nlmsg_flags |= NLM_F_REQUEST;
|
||||
nlm.rt.rtm_family = AF_INET;
|
||||
nlm.rt.rtm_table = RT_TABLE_MAIN;
|
||||
|
||||
state = D_STATE(rt->iface);
|
||||
if (action == -1 || action == -2)
|
||||
if (cmd == RTM_DELETE)
|
||||
nlm.rt.rtm_scope = RT_SCOPE_NOWHERE;
|
||||
else {
|
||||
nlm.hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
|
||||
/* We only change route metrics for kernel routes */
|
||||
if (rt->dest.s_addr ==
|
||||
(state->addr.s_addr & state->net.s_addr) &&
|
||||
@ -1302,20 +1372,53 @@ if_route(const struct rt *rt, int action)
|
||||
&state->addr.s_addr, sizeof(state->addr.s_addr));
|
||||
}
|
||||
/* If destination == gateway then don't add the gateway */
|
||||
if (rt->dest.s_addr != rt->gate.s_addr ||
|
||||
rt->net.s_addr != INADDR_BROADCAST)
|
||||
if ((cmd == RTM_ADD || cmd == RTM_CHANGE) &&
|
||||
(rt->dest.s_addr != rt->gate.s_addr ||
|
||||
rt->net.s_addr != INADDR_BROADCAST))
|
||||
add_attr_l(&nlm.hdr, sizeof(nlm), RTA_GATEWAY,
|
||||
&rt->gate.s_addr, sizeof(rt->gate.s_addr));
|
||||
|
||||
if (rt->gate.s_addr != htonl(INADDR_LOOPBACK))
|
||||
add_attr_32(&nlm.hdr, sizeof(nlm), RTA_OIF, rt->iface->index);
|
||||
add_attr_32(&nlm.hdr, sizeof(nlm), RTA_PRIORITY, rt->metric);
|
||||
if (rt->metric)
|
||||
add_attr_32(&nlm.hdr, sizeof(nlm), RTA_PRIORITY, rt->metric);
|
||||
|
||||
if (send_netlink(rt->iface->ctx, NULL,
|
||||
NETLINK_ROUTE, &nlm.hdr, NULL) == -1)
|
||||
NETLINK_ROUTE, &nlm.hdr, &_if_copyrt, srt) == -1)
|
||||
retval = -1;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int
|
||||
_if_initrt(struct dhcpcd_ctx *ctx, __unused struct interface *ifp,
|
||||
struct nlmsghdr *nlm, __unused void *data)
|
||||
{
|
||||
struct rt rt;
|
||||
|
||||
if (if_copyrt(ctx, &rt, nlm) == 0)
|
||||
ipv4_handlert(ctx, RTM_ADD, &rt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
if_initrt(struct interface *ifp)
|
||||
{
|
||||
struct nlmr nlm;
|
||||
|
||||
ipv4_freerts(ifp->ctx->ipv4_kroutes);
|
||||
|
||||
memset(&nlm, 0, sizeof(nlm));
|
||||
nlm.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
|
||||
nlm.hdr.nlmsg_type = RTM_GETROUTE;
|
||||
nlm.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH;
|
||||
nlm.hdr.nlmsg_flags |= NLM_F_REQUEST;
|
||||
nlm.rt.rtm_family = AF_INET;
|
||||
nlm.rt.rtm_table = RT_TABLE_MAIN;
|
||||
add_attr_32(&nlm.hdr, sizeof(nlm), RTA_OIF, ifp->index);
|
||||
|
||||
return send_netlink(ifp->ctx, ifp,
|
||||
NETLINK_ROUTE, &nlm.hdr, &_if_initrt, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef INET6
|
||||
@ -1327,7 +1430,7 @@ if_address6(const struct ipv6_addr *ap, int action)
|
||||
int retval = 0;
|
||||
/* IFA_FLAGS is not a define, but is was added at the same time
|
||||
* IFA_F_NOPREFIXROUTE was do use that. */
|
||||
#ifdef IFA_F_NOPREFIXROUTE
|
||||
#if defined(IFA_F_NOPREFIXROUTE) || defined(IFA_F_MANAGETEMPADDR)
|
||||
uint32_t flags = 0;
|
||||
#endif
|
||||
|
||||
@ -1374,13 +1477,13 @@ if_address6(const struct ipv6_addr *ap, int action)
|
||||
if (!IN6_IS_ADDR_LINKLOCAL(&ap->addr))
|
||||
flags |= IFA_F_NOPREFIXROUTE;
|
||||
#endif
|
||||
#ifdef IFA_F_NOPREFIXROUTE
|
||||
#if defined(IFA_F_NOPREFIXROUTE) || defined(IFA_F_MANAGETEMPADDR)
|
||||
if (flags)
|
||||
add_attr_32(&nlm.hdr, sizeof(nlm), IFA_FLAGS, flags);
|
||||
#endif
|
||||
|
||||
if (send_netlink(ap->iface->ctx, NULL,
|
||||
NETLINK_ROUTE, &nlm.hdr, NULL) == -1)
|
||||
NETLINK_ROUTE, &nlm.hdr, NULL, NULL) == -1)
|
||||
retval = -1;
|
||||
return retval;
|
||||
}
|
||||
@ -1397,7 +1500,8 @@ rta_add_attr_32(struct rtattr *rta, unsigned short maxlen,
|
||||
return -1;
|
||||
}
|
||||
|
||||
subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
|
||||
subrta = (struct rtattr*)(void *)
|
||||
(((char*)rta) + RTA_ALIGN(rta->rta_len));
|
||||
subrta->rta_type = type;
|
||||
subrta->rta_len = len;
|
||||
memcpy(RTA_DATA(subrta), &data, sizeof(data));
|
||||
@ -1405,31 +1509,45 @@ rta_add_attr_32(struct rtattr *rta, unsigned short maxlen,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_if_copyrt6(struct dhcpcd_ctx *ctx, __unused struct interface *ifp,
|
||||
struct nlmsghdr *nlm, void *data)
|
||||
{
|
||||
|
||||
return if_copyrt6(ctx, (struct rt6 *)data, nlm);
|
||||
}
|
||||
|
||||
int
|
||||
if_route6(const struct rt6 *rt, int action)
|
||||
if_route6(unsigned char cmd, const struct rt6 *rt, struct rt6 *srt)
|
||||
{
|
||||
struct nlmr nlm;
|
||||
char metricsbuf[32];
|
||||
struct rtattr *metrics = (void *)metricsbuf;
|
||||
int retval = 0;
|
||||
|
||||
memset(&nlm, 0, sizeof(nlm));
|
||||
nlm.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
|
||||
nlm.hdr.nlmsg_type = RTM_NEWROUTE;
|
||||
nlm.hdr.nlmsg_flags = NLM_F_REQUEST;
|
||||
if (action == 0)
|
||||
nlm.hdr.nlmsg_flags |= NLM_F_REPLACE;
|
||||
else if (action == 1)
|
||||
nlm.hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
|
||||
else
|
||||
switch (cmd) {
|
||||
case RTM_GET:
|
||||
nlm.hdr.nlmsg_type = RTM_GETROUTE;
|
||||
break;
|
||||
case RTM_CHANGE:
|
||||
nlm.hdr.nlmsg_type = RTM_NEWROUTE;
|
||||
nlm.hdr.nlmsg_flags = NLM_F_CREATE | NLM_F_REPLACE;
|
||||
break;
|
||||
case RTM_ADD:
|
||||
nlm.hdr.nlmsg_type = RTM_NEWROUTE;
|
||||
nlm.hdr.nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL;
|
||||
break;
|
||||
case RTM_DELETE:
|
||||
nlm.hdr.nlmsg_type = RTM_DELROUTE;
|
||||
break;
|
||||
}
|
||||
nlm.hdr.nlmsg_flags |= NLM_F_REQUEST;
|
||||
nlm.rt.rtm_family = AF_INET6;
|
||||
nlm.rt.rtm_table = RT_TABLE_MAIN;
|
||||
|
||||
if (action == -1 || action == -2)
|
||||
if (cmd == RTM_DELETE)
|
||||
nlm.rt.rtm_scope = RT_SCOPE_NOWHERE;
|
||||
else {
|
||||
nlm.hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
|
||||
/* None interface subnet routes are static. */
|
||||
if (rt->iface->flags & IFF_LOOPBACK)
|
||||
nlm.rt.rtm_scope = RT_SCOPE_HOST;
|
||||
@ -1448,29 +1566,65 @@ if_route6(const struct rt6 *rt, int action)
|
||||
add_attr_l(&nlm.hdr, sizeof(nlm), RTA_DST,
|
||||
&rt->dest.s6_addr, sizeof(rt->dest.s6_addr));
|
||||
|
||||
if (action >= 0 && !IN6_IS_ADDR_UNSPECIFIED(&rt->gate))
|
||||
if (cmd == RTM_ADD && !IN6_IS_ADDR_UNSPECIFIED(&rt->gate))
|
||||
add_attr_l(&nlm.hdr, sizeof(nlm), RTA_GATEWAY,
|
||||
&rt->gate.s6_addr, sizeof(rt->gate.s6_addr));
|
||||
|
||||
if (!(rt->flags & RTF_REJECT)) {
|
||||
add_attr_32(&nlm.hdr, sizeof(nlm), RTA_OIF, rt->iface->index);
|
||||
add_attr_32(&nlm.hdr, sizeof(nlm), RTA_PRIORITY, rt->metric);
|
||||
if (rt->metric)
|
||||
add_attr_32(&nlm.hdr, sizeof(nlm),
|
||||
RTA_PRIORITY, rt->metric);
|
||||
}
|
||||
|
||||
if (rt->mtu) {
|
||||
if (cmd == RTM_ADD && rt->mtu) {
|
||||
char metricsbuf[32];
|
||||
struct rtattr *metrics = (void *)metricsbuf;
|
||||
|
||||
metrics->rta_type = RTA_METRICS;
|
||||
metrics->rta_len = RTA_LENGTH(0);
|
||||
rta_add_attr_32(metrics, sizeof(metricsbuf), RTAX_MTU, rt->mtu);
|
||||
add_attr_l(&nlm.hdr, sizeof(nlm), RTA_METRICS,
|
||||
RTA_DATA(metrics), RTA_PAYLOAD(metrics));
|
||||
RTA_DATA(metrics), (unsigned short)RTA_PAYLOAD(metrics));
|
||||
}
|
||||
|
||||
if (send_netlink(rt->iface->ctx, NULL,
|
||||
NETLINK_ROUTE, &nlm.hdr, NULL) == -1)
|
||||
NETLINK_ROUTE, &nlm.hdr, &_if_copyrt6, srt) == -1)
|
||||
retval = -1;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int
|
||||
_if_initrt6(struct dhcpcd_ctx *ctx, __unused struct interface *ifp,
|
||||
struct nlmsghdr *nlm, __unused void *data)
|
||||
{
|
||||
struct rt6 rt;
|
||||
|
||||
if (if_copyrt6(ctx, &rt, nlm) == 0)
|
||||
ipv6_handlert(ctx, RTM_ADD, &rt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
if_initrt6(struct interface *ifp)
|
||||
{
|
||||
struct nlmr nlm;
|
||||
|
||||
ipv6_freerts(&ifp->ctx->ipv6->kroutes);
|
||||
|
||||
memset(&nlm, 0, sizeof(nlm));
|
||||
nlm.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
|
||||
nlm.hdr.nlmsg_type = RTM_GETROUTE;
|
||||
nlm.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH;
|
||||
nlm.hdr.nlmsg_flags |= NLM_F_REQUEST;
|
||||
nlm.rt.rtm_family = AF_INET6;
|
||||
nlm.rt.rtm_table = RT_TABLE_MAIN;
|
||||
add_attr_32(&nlm.hdr, sizeof(nlm), RTA_OIF, ifp->index);
|
||||
|
||||
return send_netlink(ifp->ctx, ifp,
|
||||
NETLINK_ROUTE, &nlm.hdr, &_if_initrt6, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
if_addrflags6(const struct in6_addr *addr, const struct interface *ifp)
|
||||
{
|
||||
@ -1570,7 +1724,7 @@ if_disable_autolinklocal(struct dhcpcd_ctx *ctx, int ifindex)
|
||||
add_attr_nest_end(&nlm.hdr, afs6);
|
||||
add_attr_nest_end(&nlm.hdr, afs);
|
||||
|
||||
return send_netlink(ctx, NULL, NETLINK_ROUTE, &nlm.hdr, NULL);
|
||||
return send_netlink(ctx, NULL, NETLINK_ROUTE, &nlm.hdr, NULL, NULL);
|
||||
}
|
||||
|
||||
static const char *prefix = "/proc/sys/net/ipv6/conf";
|
||||
|
33
if.h
33
if.h
@ -31,23 +31,21 @@
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <net/if.h>
|
||||
//#include <net/route.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "dhcpcd.h"
|
||||
#include "ipv4.h"
|
||||
#include "ipv6.h"
|
||||
|
||||
/* Some systems have route metrics */
|
||||
#ifndef HAVE_ROUTE_METRIC
|
||||
# if defined(__linux__) || defined(SIOCGIFPRIORITY)
|
||||
# define HAVE_ROUTE_METRIC 1
|
||||
# endif
|
||||
# ifndef HAVE_ROUTE_METRIC
|
||||
# define HAVE_ROUTE_METRIC 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include "dhcpcd.h"
|
||||
#include "ipv4.h"
|
||||
#include "ipv6.h"
|
||||
|
||||
#define EUI64_ADDR_LEN 8
|
||||
#define INFINIBAND_ADDR_LEN 20
|
||||
|
||||
@ -102,6 +100,13 @@ int if_vimaster(const char *);
|
||||
int if_openlinksocket(void);
|
||||
int if_managelink(struct dhcpcd_ctx *);
|
||||
|
||||
#ifndef RTM_ADD
|
||||
#define RTM_ADD 0x1 /* Add Route */
|
||||
#define RTM_DELETE 0x2 /* Delete Route */
|
||||
#define RTM_CHANGE 0x3 /* Change Metrics or flags */
|
||||
#define RTM_GET 0x4 /* Report Metrics */
|
||||
#endif
|
||||
|
||||
#ifdef INET
|
||||
extern const char *if_pfname;
|
||||
int if_openrawsocket(struct interface *, int);
|
||||
@ -117,10 +122,8 @@ int if_address(const struct interface *,
|
||||
#define if_deladdress(ifp, addr, net) \
|
||||
if_address(ifp, addr, net, NULL, -1)
|
||||
|
||||
int if_route(const struct rt *rt, int);
|
||||
#define if_addroute(rt) if_route(rt, 1)
|
||||
#define if_chgroute(rt) if_route(rt, 0)
|
||||
#define if_delroute(rt) if_route(rt, -1)
|
||||
int if_route(unsigned char, const struct rt *rt, struct rt *);
|
||||
int if_initrt(struct interface *);
|
||||
#endif
|
||||
|
||||
#ifdef INET6
|
||||
@ -140,10 +143,8 @@ int if_address6(const struct ipv6_addr *, int);
|
||||
int if_addrflags6(const struct in6_addr *, const struct interface *);
|
||||
int if_getlifetime6(struct ipv6_addr *);
|
||||
|
||||
int if_route6(const struct rt6 *rt, int);
|
||||
#define if_addroute6(rt) if_route6(rt, 1)
|
||||
#define if_chgroute6(rt) if_route6(rt, 0)
|
||||
#define if_delroute6(rt) if_route6(rt, -1)
|
||||
int if_route6(unsigned char, const struct rt6 *rt, struct rt6 *);
|
||||
int if_initrt6(struct interface *);
|
||||
#else
|
||||
#define if_checkipv6(a, b, c) (-1)
|
||||
#endif
|
||||
|
230
ipv4.c
230
ipv4.c
@ -180,13 +180,9 @@ ipv4_addrexists(struct dhcpcd_ctx *ctx, const struct in_addr *addr)
|
||||
void
|
||||
ipv4_freeroutes(struct rt_head *rts)
|
||||
{
|
||||
struct rt *r;
|
||||
|
||||
if (rts) {
|
||||
while ((r = TAILQ_FIRST(rts))) {
|
||||
TAILQ_REMOVE(rts, r, next);
|
||||
free(r);
|
||||
}
|
||||
ipv4_freerts(rts);
|
||||
free(rts);
|
||||
}
|
||||
}
|
||||
@ -201,10 +197,15 @@ ipv4_init(struct dhcpcd_ctx *ctx)
|
||||
return -1;
|
||||
TAILQ_INIT(ctx->ipv4_routes);
|
||||
}
|
||||
if (ctx->ipv4_kroutes == NULL) {
|
||||
ctx->ipv4_kroutes = malloc(sizeof(*ctx->ipv4_kroutes));
|
||||
if (ctx->ipv4_kroutes == NULL)
|
||||
return -1;
|
||||
TAILQ_INIT(ctx->ipv4_kroutes);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Interface comparer for working out ordering. */
|
||||
static int
|
||||
ipv4_ifcmp(const struct interface *si, const struct interface *ti)
|
||||
@ -291,7 +292,7 @@ find_route(struct rt_head *rts, const struct rt *r, const struct rt *srt)
|
||||
return NULL;
|
||||
TAILQ_FOREACH(rt, rts, next) {
|
||||
if (rt->dest.s_addr == r->dest.s_addr &&
|
||||
#if HAVE_ROUTE_METRIC
|
||||
#ifdef HAVE_ROUTE_METRIC
|
||||
(srt || (!rt->iface ||
|
||||
rt->iface->metric == r->iface->metric)) &&
|
||||
#endif
|
||||
@ -328,27 +329,78 @@ desc_route(const char *cmd, const struct rt *rt)
|
||||
addr, inet_ntocidr(rt->net), inet_ntoa(rt->gate));
|
||||
}
|
||||
|
||||
static struct rt *
|
||||
ipv4_findrt(struct dhcpcd_ctx *ctx, const struct rt *rt, int flags)
|
||||
{
|
||||
struct rt *r;
|
||||
|
||||
if (ctx->ipv4_kroutes == NULL)
|
||||
return NULL;
|
||||
TAILQ_FOREACH(r, ctx->ipv4_kroutes, next) {
|
||||
if (rt->dest.s_addr == r->dest.s_addr &&
|
||||
(!flags || rt->iface == r->iface) &&
|
||||
#ifdef HAVE_ROUTE_METRIC
|
||||
(!flags || rt->metric == r->metric) &&
|
||||
#endif
|
||||
rt->net.s_addr == r->net.s_addr)
|
||||
return r;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
ipv4_freerts(struct rt_head *routes)
|
||||
{
|
||||
struct rt *rt;
|
||||
|
||||
while ((rt = TAILQ_FIRST(routes))) {
|
||||
TAILQ_REMOVE(routes, rt, next);
|
||||
free(rt);
|
||||
}
|
||||
}
|
||||
|
||||
/* If something other than dhcpcd removes a route,
|
||||
* we need to remove it from our internal table. */
|
||||
int
|
||||
ipv4_routedeleted(struct dhcpcd_ctx *ctx, const struct rt *rt)
|
||||
ipv4_handlert(struct dhcpcd_ctx *ctx, int cmd, struct rt *rt)
|
||||
{
|
||||
struct rt *f;
|
||||
|
||||
f = find_route(ctx->ipv4_routes, rt, NULL);
|
||||
if (f == NULL)
|
||||
return 0;
|
||||
desc_route("removing", f);
|
||||
TAILQ_REMOVE(ctx->ipv4_routes, f, next);
|
||||
free(f);
|
||||
return 1;
|
||||
f = ipv4_findrt(ctx, rt, 1);
|
||||
switch (cmd) {
|
||||
case RTM_ADD:
|
||||
if (f == NULL) {
|
||||
if ((f = malloc(sizeof(*f))) == NULL)
|
||||
return -1;
|
||||
*f = *rt;
|
||||
TAILQ_INSERT_TAIL(ctx->ipv4_kroutes, f, next);
|
||||
}
|
||||
break;
|
||||
case RTM_DELETE:
|
||||
if (f) {
|
||||
TAILQ_REMOVE(ctx->ipv4_kroutes, f, next);
|
||||
free(f);
|
||||
}
|
||||
|
||||
/* If we manage the route, remove it */
|
||||
if ((f = find_route(rt->iface->ctx->ipv4_routes, rt, NULL))) {
|
||||
desc_route("removing", f);
|
||||
TAILQ_REMOVE(rt->iface->ctx->ipv4_routes, f, next);
|
||||
free(f);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define n_route(a) nc_route(1, a, a)
|
||||
#define c_route(a, b) nc_route(0, a, b)
|
||||
#define n_route(a) nc_route(NULL, a)
|
||||
#define c_route(a, b) nc_route(a, b)
|
||||
static int
|
||||
nc_route(int add, struct rt *ort, struct rt *nrt)
|
||||
nc_route(struct rt *ort, struct rt *nrt)
|
||||
{
|
||||
#ifdef HAVE_ROUTE_METRIC
|
||||
int retval;
|
||||
#endif
|
||||
|
||||
/* Don't set default routes if not asked to */
|
||||
if (nrt->dest.s_addr == 0 &&
|
||||
@ -356,17 +408,44 @@ nc_route(int add, struct rt *ort, struct rt *nrt)
|
||||
!(nrt->iface->options->options & DHCPCD_GATEWAY))
|
||||
return -1;
|
||||
|
||||
desc_route(add ? "adding" : "changing", nrt);
|
||||
/* We delete and add the route so that we can change metric and
|
||||
* prefer the interface.
|
||||
* This also has the nice side effect of flushing ARP entries so
|
||||
* we don't have to do that manually. */
|
||||
if (if_delroute(ort) == -1 && errno != ESRCH)
|
||||
syslog(LOG_ERR, "%s: ipv4_delroute: %m", ort->iface->name);
|
||||
if (!if_addroute(nrt))
|
||||
desc_route(ort == NULL ? "adding" : "changing", nrt);
|
||||
|
||||
if (ort == NULL) {
|
||||
ort = ipv4_findrt(nrt->iface->ctx, nrt, 0);
|
||||
if (ort && ort->iface == nrt->iface &&
|
||||
#ifdef HAVE_ROUTE_METRIC
|
||||
ort->metric == nrt->metric &&
|
||||
#endif
|
||||
ort->gate.s_addr == nrt->gate.s_addr)
|
||||
return 0;
|
||||
} else if (ort->flags & STATE_FAKE && !(nrt->flags & STATE_FAKE) &&
|
||||
ort->iface == nrt->iface &&
|
||||
#ifdef HAVE_ROUTE_METRIC
|
||||
ort->metric == nrt->metric &&
|
||||
#endif
|
||||
ort->dest.s_addr == nrt->dest.s_addr &&
|
||||
ort->net.s_addr == nrt->net.s_addr &&
|
||||
ort->gate.s_addr == nrt->gate.s_addr)
|
||||
return 0;
|
||||
syslog(LOG_ERR, "%s: if_addroute: %m", nrt->iface->name);
|
||||
|
||||
#ifdef HAVE_ROUTE_METRIC
|
||||
/* With route metrics, we can safely add the new route before
|
||||
* deleting the old route. */
|
||||
if ((retval = if_route(RTM_ADD, nrt, NULL)) == -1)
|
||||
syslog(LOG_ERR, "if_route (ADD): %m");
|
||||
if (ort && if_route(RTM_DELETE, ort, NULL) == -1 && errno != ESRCH)
|
||||
syslog(LOG_ERR, "if_route (DEL): %m");
|
||||
return retval;
|
||||
#else
|
||||
/* No route metrics, we need to delete the old route before
|
||||
* adding the new one. */
|
||||
if (ort && if_route(RTM_DELETE, ort, NULL) == -1 && errno != ESRCH)
|
||||
syslog(LOG_ERR, "if_route (DEL): %m");
|
||||
if (if_route(RTM_ADD, nrt, NULL) == 0)
|
||||
return 0;
|
||||
syslog(LOG_ERR, "if_route (ADD): %m");
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
@ -375,57 +454,44 @@ d_route(struct rt *rt)
|
||||
int retval;
|
||||
|
||||
desc_route("deleting", rt);
|
||||
retval = if_delroute(rt);
|
||||
retval = if_route(RTM_DELETE, rt, NULL);
|
||||
if (retval != 0 && errno != ENOENT && errno != ESRCH)
|
||||
syslog(LOG_ERR,"%s: if_delroute: %m", rt->iface->name);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static struct rt *
|
||||
get_subnet_route(struct dhcpcd_ctx *ctx, struct dhcp_message *dhcp)
|
||||
make_subnet_route(const struct interface *ifp)
|
||||
{
|
||||
in_addr_t addr;
|
||||
struct in_addr net;
|
||||
struct rt *rt;
|
||||
const struct dhcp_state *s;
|
||||
struct rt *r;
|
||||
|
||||
addr = dhcp->yiaddr;
|
||||
if (addr == 0)
|
||||
addr = dhcp->ciaddr;
|
||||
/* Ensure we have all the needed values */
|
||||
if (get_option_addr(ctx, &net, dhcp, DHO_SUBNETMASK) == -1)
|
||||
net.s_addr = ipv4_getnetmask(addr);
|
||||
if (net.s_addr == INADDR_BROADCAST || net.s_addr == INADDR_ANY)
|
||||
s = D_CSTATE(ifp);
|
||||
if (s->net.s_addr == INADDR_BROADCAST ||
|
||||
s->net.s_addr == INADDR_ANY)
|
||||
return NULL;
|
||||
rt = malloc(sizeof(*rt));
|
||||
rt->dest.s_addr = addr & net.s_addr;
|
||||
rt->net.s_addr = net.s_addr;
|
||||
rt->gate.s_addr = 0;
|
||||
return rt;
|
||||
|
||||
r = malloc(sizeof(*r));
|
||||
if (r == NULL) {
|
||||
syslog(LOG_ERR, "%s: %m", __func__);
|
||||
return NULL;
|
||||
}
|
||||
r->dest.s_addr = s->addr.s_addr & s->net.s_addr;
|
||||
r->net.s_addr = s->net.s_addr;
|
||||
r->gate.s_addr = INADDR_ANY;
|
||||
return r;
|
||||
}
|
||||
|
||||
static struct rt_head *
|
||||
add_subnet_route(struct rt_head *rt, const struct interface *ifp)
|
||||
{
|
||||
struct rt *r;
|
||||
const struct dhcp_state *s;
|
||||
|
||||
if (rt == NULL) /* earlier malloc failed */
|
||||
return NULL;
|
||||
|
||||
s = D_CSTATE(ifp);
|
||||
if (s->net.s_addr == INADDR_BROADCAST ||
|
||||
s->net.s_addr == INADDR_ANY)
|
||||
return rt;
|
||||
|
||||
r = malloc(sizeof(*r));
|
||||
if (r == NULL) {
|
||||
syslog(LOG_ERR, "%s: %m", __func__);
|
||||
ipv4_freeroutes(rt);
|
||||
if ((r = make_subnet_route(ifp)) == NULL)
|
||||
return NULL;
|
||||
}
|
||||
r->dest.s_addr = s->addr.s_addr & s->net.s_addr;
|
||||
r->net.s_addr = s->net.s_addr;
|
||||
r->gate.s_addr = 0;
|
||||
TAILQ_INSERT_HEAD(rt, r, next);
|
||||
return rt;
|
||||
}
|
||||
@ -598,6 +664,7 @@ ipv4_buildroutes(struct dhcpcd_ctx *ctx)
|
||||
return;
|
||||
}
|
||||
TAILQ_INIT(nrs);
|
||||
|
||||
TAILQ_FOREACH(ifp, ctx->ifaces, next) {
|
||||
state = D_CSTATE(ifp);
|
||||
if (state == NULL || state->new == NULL || !state->added)
|
||||
@ -616,7 +683,10 @@ ipv4_buildroutes(struct dhcpcd_ctx *ctx)
|
||||
continue;
|
||||
TAILQ_FOREACH_SAFE(rt, dnr, next, rtn) {
|
||||
rt->iface = ifp;
|
||||
#ifdef HAVE_ROUTE_METRIC
|
||||
rt->metric = ifp->metric;
|
||||
#endif
|
||||
rt->flags = state->added & STATE_FAKE;
|
||||
/* Is this route already in our table? */
|
||||
if ((find_route(nrs, rt, NULL)) != NULL)
|
||||
continue;
|
||||
@ -627,9 +697,11 @@ ipv4_buildroutes(struct dhcpcd_ctx *ctx)
|
||||
continue;
|
||||
if (or->flags & STATE_FAKE ||
|
||||
or->iface != ifp ||
|
||||
#ifdef HAVE_ROUTE_METRIC
|
||||
rt->metric != or->metric ||
|
||||
#endif
|
||||
or->src.s_addr != state->addr.s_addr ||
|
||||
rt->gate.s_addr != or->gate.s_addr ||
|
||||
rt->metric != or->metric)
|
||||
rt->gate.s_addr != or->gate.s_addr)
|
||||
{
|
||||
if (c_route(or, rt) != 0)
|
||||
continue;
|
||||
@ -637,13 +709,15 @@ ipv4_buildroutes(struct dhcpcd_ctx *ctx)
|
||||
TAILQ_REMOVE(ctx->ipv4_routes, or, next);
|
||||
free(or);
|
||||
} else {
|
||||
if (!(state->added & STATE_FAKE) &&
|
||||
n_route(rt) != 0)
|
||||
continue;
|
||||
if (state->added & STATE_FAKE) {
|
||||
if (!ipv4_findrt(ctx, rt, 1))
|
||||
continue;
|
||||
} else {
|
||||
if (n_route(rt) != 0)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
rt->flags = STATE_ADDED;
|
||||
if (state->added & STATE_FAKE)
|
||||
rt->flags |= STATE_FAKE;
|
||||
rt->flags |= STATE_ADDED;
|
||||
TAILQ_REMOVE(dnr, rt, next);
|
||||
TAILQ_INSERT_TAIL(nrs, rt, next);
|
||||
}
|
||||
@ -659,7 +733,6 @@ ipv4_buildroutes(struct dhcpcd_ctx *ctx)
|
||||
d_route(rt);
|
||||
}
|
||||
ipv4_freeroutes(ctx->ipv4_routes);
|
||||
|
||||
ctx->ipv4_routes = nrs;
|
||||
}
|
||||
|
||||
@ -724,6 +797,7 @@ ipv4_getstate(struct interface *ifp)
|
||||
return NULL;
|
||||
}
|
||||
TAILQ_INIT(&state->addrs);
|
||||
TAILQ_INIT(&state->routes);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
@ -762,8 +836,7 @@ ipv4_applyaddr(void *arg)
|
||||
struct dhcp_lease *lease;
|
||||
struct if_options *ifo = ifp->options;
|
||||
struct ipv4_addr *ap;
|
||||
struct ipv4_state *istate;
|
||||
struct rt *rt;
|
||||
struct ipv4_state *istate = NULL;
|
||||
int r;
|
||||
|
||||
/* As we are now adjusting an interface, we need to ensure
|
||||
@ -866,6 +939,7 @@ ipv4_applyaddr(void *arg)
|
||||
return;
|
||||
istate = ipv4_getstate(ifp);
|
||||
ap = malloc(sizeof(*ap));
|
||||
ap->iface = ifp;
|
||||
ap->addr = lease->addr;
|
||||
ap->net = lease->net;
|
||||
ap->dst.s_addr = INADDR_ANY;
|
||||
@ -883,18 +957,11 @@ ipv4_applyaddr(void *arg)
|
||||
state->addr.s_addr = lease->addr.s_addr;
|
||||
state->net.s_addr = lease->net.s_addr;
|
||||
|
||||
/* We need to delete the subnet route to have our metric or
|
||||
* prefer the interface. */
|
||||
rt = get_subnet_route(ifp->ctx, dhcp);
|
||||
if (rt != NULL) {
|
||||
rt->iface = ifp;
|
||||
rt->metric = 0;
|
||||
if (!find_route(ifp->ctx->ipv4_routes, rt, NULL))
|
||||
if_delroute(rt);
|
||||
free(rt);
|
||||
}
|
||||
|
||||
routes:
|
||||
/* Find any freshly added routes, such as the subnet route.
|
||||
* We do this because we cannot rely on recieving the kernel
|
||||
* notification right now via our link socket. */
|
||||
if_initrt(ifp);
|
||||
ipv4_buildroutes(ifp->ctx);
|
||||
script_runreason(ifp, state->reason);
|
||||
}
|
||||
@ -941,6 +1008,7 @@ ipv4_handleifa(struct dhcpcd_ctx *ctx,
|
||||
syslog(LOG_ERR, "%s: %m", __func__);
|
||||
return;
|
||||
}
|
||||
ap->iface = ifp;
|
||||
ap->addr.s_addr = addr->s_addr;
|
||||
ap->net.s_addr = net->s_addr;
|
||||
if (dst)
|
||||
@ -971,6 +1039,7 @@ ipv4_free(struct interface *ifp)
|
||||
TAILQ_REMOVE(&state->addrs, addr, next);
|
||||
free(addr);
|
||||
}
|
||||
ipv4_freerts(&state->routes);
|
||||
free(state);
|
||||
}
|
||||
}
|
||||
@ -981,4 +1050,5 @@ ipv4_ctxfree(struct dhcpcd_ctx *ctx)
|
||||
{
|
||||
|
||||
ipv4_freeroutes(ctx->ipv4_routes);
|
||||
ipv4_freeroutes(ctx->ipv4_kroutes);
|
||||
}
|
||||
|
7
ipv4.h
7
ipv4.h
@ -36,7 +36,9 @@ struct rt {
|
||||
struct in_addr net;
|
||||
struct in_addr gate;
|
||||
const struct interface *iface;
|
||||
#ifdef HAVE_ROUTE_METRIC
|
||||
unsigned int metric;
|
||||
#endif
|
||||
struct in_addr src;
|
||||
uint8_t flags;
|
||||
};
|
||||
@ -47,11 +49,13 @@ struct ipv4_addr {
|
||||
struct in_addr addr;
|
||||
struct in_addr net;
|
||||
struct in_addr dst;
|
||||
struct interface *iface;
|
||||
};
|
||||
TAILQ_HEAD(ipv4_addrhead, ipv4_addr);
|
||||
|
||||
struct ipv4_state {
|
||||
struct ipv4_addrhead addrs;
|
||||
struct rt_head routes;
|
||||
};
|
||||
|
||||
#define IPV4_STATE(ifp) \
|
||||
@ -72,7 +76,8 @@ int ipv4_addrexists(struct dhcpcd_ctx *, const struct in_addr *);
|
||||
|
||||
void ipv4_buildroutes(struct dhcpcd_ctx *);
|
||||
void ipv4_applyaddr(void *);
|
||||
int ipv4_routedeleted(struct dhcpcd_ctx *, const struct rt *);
|
||||
int ipv4_handlert(struct dhcpcd_ctx *, int, struct rt *);
|
||||
void ipv4_freerts(struct rt_head *);
|
||||
|
||||
struct ipv4_addr *ipv4_iffindaddr(struct interface *,
|
||||
const struct in_addr *, const struct in_addr *);
|
||||
|
182
ipv6.c
182
ipv6.c
@ -58,10 +58,10 @@
|
||||
|
||||
#define ELOOP_QUEUE 7
|
||||
#include "common.h"
|
||||
#include "if.h"
|
||||
#include "dhcpcd.h"
|
||||
#include "dhcp6.h"
|
||||
#include "eloop.h"
|
||||
#include "if.h"
|
||||
#include "ipv6.h"
|
||||
#include "ipv6nd.h"
|
||||
|
||||
@ -151,6 +151,8 @@ ipv6_init(struct dhcpcd_ctx *dhcpcd_ctx)
|
||||
}
|
||||
TAILQ_INIT(ctx->ra_routers);
|
||||
|
||||
TAILQ_INIT(&ctx->kroutes);
|
||||
|
||||
ctx->sndhdr.msg_namelen = sizeof(struct sockaddr_in6);
|
||||
ctx->sndhdr.msg_iov = ctx->sndiov;
|
||||
ctx->sndhdr.msg_iovlen = 1;
|
||||
@ -725,9 +727,6 @@ ipv6_addaddr(struct ipv6_addr *ap, const struct timeval *now)
|
||||
ap->flags |= IPV6_AF_ADDED;
|
||||
if (ap->delegating_iface)
|
||||
ap->flags |= IPV6_AF_DELEGATED;
|
||||
if (ap->iface->options->options & DHCPCD_IPV6RA_OWN &&
|
||||
ipv6_removesubnet(ap->iface, ap) == -1)
|
||||
syslog(LOG_ERR,"ipv6_removesubnet: %m");
|
||||
|
||||
#ifdef IPV6_POLLADDRFLAG
|
||||
eloop_timeout_delete(ap->iface->ctx->eloop,
|
||||
@ -1223,6 +1222,9 @@ ipv6_start(struct interface *ifp)
|
||||
|
||||
if (ap == NULL && ipv6_addlinklocal(ifp) == -1)
|
||||
return -1;
|
||||
|
||||
/* Load existing routes */
|
||||
if_initrt6(ifp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1256,17 +1258,14 @@ ipv6_freedrop(struct interface *ifp, int drop)
|
||||
void
|
||||
ipv6_ctxfree(struct dhcpcd_ctx *ctx)
|
||||
{
|
||||
struct rt6 *rt;
|
||||
|
||||
if (ctx->ipv6 == NULL)
|
||||
return;
|
||||
|
||||
while ((rt = TAILQ_FIRST(ctx->ipv6->routes))) {
|
||||
TAILQ_REMOVE(ctx->ipv6->routes, rt, next);
|
||||
free(rt);
|
||||
}
|
||||
ipv6_freerts(ctx->ipv6->routes);
|
||||
free(ctx->ipv6->routes);
|
||||
free(ctx->ipv6->ra_routers);
|
||||
ipv6_freerts(&ctx->ipv6->kroutes);
|
||||
free(ctx->ipv6);
|
||||
}
|
||||
|
||||
@ -1693,7 +1692,7 @@ find_route6(struct rt6_head *rts, const struct rt6 *r)
|
||||
|
||||
TAILQ_FOREACH(rt, rts, next) {
|
||||
if (IN6_ARE_ADDR_EQUAL(&rt->dest, &r->dest) &&
|
||||
#if HAVE_ROUTE_METRIC
|
||||
#ifdef HAVE_ROUTE_METRIC
|
||||
(r->iface == NULL || rt->iface == NULL ||
|
||||
rt->iface->metric == r->iface->metric) &&
|
||||
#endif
|
||||
@ -1726,30 +1725,75 @@ desc_route(const char *cmd, const struct rt6 *rt)
|
||||
dest, ipv6_prefixlen(&rt->net), gate);
|
||||
}
|
||||
|
||||
static struct rt6*
|
||||
ipv6_findrt(struct dhcpcd_ctx *ctx, const struct rt6 *rt, int flags)
|
||||
{
|
||||
struct rt6 *r;
|
||||
|
||||
TAILQ_FOREACH(r, &ctx->ipv6->kroutes, next) {
|
||||
if (IN6_ARE_ADDR_EQUAL(&rt->dest, &r->dest) &&
|
||||
(!flags || rt->iface == r->iface) &&
|
||||
#ifdef HAVE_ROUTE_METRIC
|
||||
(!flags || rt->metric == r->metric) &&
|
||||
#endif
|
||||
IN6_ARE_ADDR_EQUAL(&rt->net, &r->net))
|
||||
return r;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
ipv6_freerts(struct rt6_head *routes)
|
||||
{
|
||||
struct rt6 *rt;
|
||||
|
||||
while ((rt = TAILQ_FIRST(routes))) {
|
||||
TAILQ_REMOVE(routes, rt, next);
|
||||
free(rt);
|
||||
}
|
||||
}
|
||||
|
||||
/* If something other than dhcpcd removes a route,
|
||||
* we need to remove it from our internal table. */
|
||||
int
|
||||
ipv6_routedeleted(struct dhcpcd_ctx *ctx, const struct rt6 *rt)
|
||||
ipv6_handlert(struct dhcpcd_ctx *ctx, int cmd, struct rt6 *rt)
|
||||
{
|
||||
struct rt6 *f;
|
||||
|
||||
if (ctx->ipv6 == NULL)
|
||||
return 0;
|
||||
|
||||
f = find_route6(ctx->ipv6->routes, rt);
|
||||
if (f == NULL)
|
||||
return 0;
|
||||
desc_route("removing", f);
|
||||
TAILQ_REMOVE(ctx->ipv6->routes, f, next);
|
||||
free(f);
|
||||
return 1;
|
||||
f = ipv6_findrt(ctx, rt, 1);
|
||||
switch(cmd) {
|
||||
case RTM_ADD:
|
||||
if (f == NULL) {
|
||||
if ((f = malloc(sizeof(*f))) == NULL)
|
||||
return -1;
|
||||
*f = *rt;
|
||||
TAILQ_INSERT_TAIL(&ctx->ipv6->kroutes, f, next);
|
||||
}
|
||||
break;
|
||||
case RTM_DELETE:
|
||||
if (f) {
|
||||
TAILQ_REMOVE(&ctx->ipv6->kroutes, f, next);
|
||||
free(f);
|
||||
}
|
||||
/* If we manage the route, remove it */
|
||||
if ((f = find_route6(ctx->ipv6->routes, rt))) {
|
||||
desc_route("removing", f);
|
||||
TAILQ_REMOVE(ctx->ipv6->routes, f, next);
|
||||
free(f);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define n_route(a) nc_route(1, a, a)
|
||||
#define c_route(a, b) nc_route(0, a, b)
|
||||
#define n_route(a) nc_route(NULL, a)
|
||||
#define c_route(a, b) nc_route(a, b)
|
||||
static int
|
||||
nc_route(int add, struct rt6 *ort, struct rt6 *nrt)
|
||||
nc_route(struct rt6 *ort, struct rt6 *nrt)
|
||||
{
|
||||
#ifdef HAVE_ROUTE_METRIC
|
||||
int retval;
|
||||
#endif
|
||||
|
||||
/* Don't set default routes if not asked to */
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&nrt->dest) &&
|
||||
@ -1757,15 +1801,37 @@ nc_route(int add, struct rt6 *ort, struct rt6 *nrt)
|
||||
!(nrt->iface->options->options & DHCPCD_GATEWAY))
|
||||
return -1;
|
||||
|
||||
desc_route(add ? "adding" : "changing", nrt);
|
||||
/* We delete and add the route so that we can change metric and
|
||||
* prefer the interface. */
|
||||
if (if_delroute6(ort) == -1 && errno != ESRCH)
|
||||
syslog(LOG_ERR, "%s: if_delroute6: %m", ort->iface->name);
|
||||
if (if_addroute6(nrt) == 0)
|
||||
desc_route(ort == NULL ? "adding" : "changing", nrt);
|
||||
|
||||
if (ort == NULL) {
|
||||
ort = ipv6_findrt(nrt->iface->ctx, nrt, 0);
|
||||
if (ort && ort->iface == nrt->iface &&
|
||||
#ifdef HAVE_ROUTE_METRIC
|
||||
ort->metric == nrt->metric &&
|
||||
#endif
|
||||
IN6_ARE_ADDR_EQUAL(&ort->gate, &nrt->gate))
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_ROUTE_METRIC
|
||||
/* With route metrics, we can safely add the new route before
|
||||
* deleting the old route. */
|
||||
if ((retval = if_route6(RTM_ADD, nrt, NULL)) == -1)
|
||||
syslog(LOG_ERR, "if_route6 (ADD): %m");
|
||||
if (ort && if_route6(RTM_DELETE, ort, NULL) == -1 &&
|
||||
errno != ESRCH)
|
||||
syslog(LOG_ERR, "if_route6 (DEL): %m");
|
||||
return retval;
|
||||
#else
|
||||
/* No route metrics, we need to delete the old route before
|
||||
* adding the new one. */
|
||||
if (ort && if_route6(RTM_DELETE, ort, NULL) == -1 && errno != ESRCH)
|
||||
syslog(LOG_ERR, "if_route6: %m");
|
||||
if (if_route6(RTM_ADD, nrt, NULL) == 0)
|
||||
return 0;
|
||||
syslog(LOG_ERR, "%s: if_addroute6: %m", nrt->iface->name);
|
||||
syslog(LOG_ERR, "if_route6 (ADD): %m");
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1774,7 +1840,7 @@ d_route(struct rt6 *rt)
|
||||
int retval;
|
||||
|
||||
desc_route("deleting", rt);
|
||||
retval = if_delroute6(rt);
|
||||
retval = if_route6(RTM_DELETE, rt, NULL);
|
||||
if (retval != 0 && errno != ENOENT && errno != ESRCH)
|
||||
syslog(LOG_ERR,"%s: if_delroute6: %m", rt->iface->name);
|
||||
return retval;
|
||||
@ -1791,7 +1857,9 @@ make_route(const struct interface *ifp, const struct ra *rap)
|
||||
return NULL;
|
||||
}
|
||||
r->iface = ifp;
|
||||
#ifdef HAVE_ROUTE_METRIC
|
||||
r->metric = ifp->metric;
|
||||
#endif
|
||||
if (rap)
|
||||
r->mtu = rap->mtu;
|
||||
else
|
||||
@ -1848,45 +1916,6 @@ make_router(const struct ra *rap)
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
ipv6_removesubnet(struct interface *ifp, struct ipv6_addr *addr)
|
||||
{
|
||||
struct rt6 *rt;
|
||||
#if HAVE_ROUTE_METRIC
|
||||
struct rt6 *ort;
|
||||
#endif
|
||||
int r;
|
||||
|
||||
/* We need to delete the subnet route to have our metric or
|
||||
* prefer the interface. */
|
||||
r = 0;
|
||||
rt = make_prefix(ifp, NULL, addr);
|
||||
if (rt) {
|
||||
rt->iface = ifp;
|
||||
#ifdef __linux__
|
||||
rt->metric = 256;
|
||||
#else
|
||||
rt->metric = 0;
|
||||
#endif
|
||||
#if HAVE_ROUTE_METRIC
|
||||
/* For some reason, Linux likes to re-add the subnet
|
||||
route under the original metric.
|
||||
I would love to find a way of stopping this! */
|
||||
if ((ort = find_route6(ifp->ctx->ipv6->routes, rt)) == NULL ||
|
||||
ort->metric != rt->metric)
|
||||
#else
|
||||
if (!find_route6(ifp->ctx->ipv6->routes, rt))
|
||||
#endif
|
||||
{
|
||||
r = if_delroute6(rt);
|
||||
if (r == -1 && errno == ESRCH)
|
||||
r = 0;
|
||||
}
|
||||
free(rt);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
#define RT_IS_DEFAULT(rtp) \
|
||||
(IN6_ARE_ADDR_EQUAL(&((rtp)->dest), &in6addr_any) && \
|
||||
IN6_ARE_ADDR_EQUAL(&((rtp)->net), &in6addr_any))
|
||||
@ -1951,7 +1980,7 @@ ipv6_buildroutes(struct dhcpcd_ctx *ctx)
|
||||
|
||||
/* First add reachable routers and their prefixes */
|
||||
ipv6_build_ra_routes(ctx->ipv6, &dnr, 0);
|
||||
#if HAVE_ROUTE_METRIC
|
||||
#ifdef HAVE_ROUTE_METRIC
|
||||
have_default = (TAILQ_FIRST(&dnr) != NULL);
|
||||
#endif
|
||||
|
||||
@ -1961,7 +1990,7 @@ ipv6_buildroutes(struct dhcpcd_ctx *ctx)
|
||||
ipv6_build_dhcp_routes(ctx, &dnr, DH6S_BOUND);
|
||||
ipv6_build_dhcp_routes(ctx, &dnr, DH6S_DELEGATED);
|
||||
|
||||
#if HAVE_ROUTE_METRIC
|
||||
#ifdef HAVE_ROUTE_METRIC
|
||||
/* If we have an unreachable router, we really do need to remove the
|
||||
* route to it beause it could be a lower metric than a reachable
|
||||
* router. Of course, we should at least have some routers if all
|
||||
@ -1980,6 +2009,7 @@ ipv6_buildroutes(struct dhcpcd_ctx *ctx)
|
||||
}
|
||||
TAILQ_INIT(nrs);
|
||||
have_default = 0;
|
||||
|
||||
TAILQ_FOREACH_SAFE(rt, &dnr, next, rtn) {
|
||||
/* Is this route already in our table? */
|
||||
if (find_route6(nrs, rt) != NULL)
|
||||
@ -1988,9 +2018,11 @@ ipv6_buildroutes(struct dhcpcd_ctx *ctx)
|
||||
/* Do we already manage it? */
|
||||
if ((or = find_route6(ctx->ipv6->routes, rt))) {
|
||||
if (or->iface != rt->iface ||
|
||||
#ifdef HAVE_ROUTE_METRIC
|
||||
rt->metric != or->metric ||
|
||||
#endif
|
||||
// or->src.s_addr != ifp->addr.s_addr ||
|
||||
!IN6_ARE_ADDR_EQUAL(&rt->gate, &or->gate) ||
|
||||
rt->metric != or->metric)
|
||||
!IN6_ARE_ADDR_EQUAL(&rt->gate, &or->gate))
|
||||
{
|
||||
if (c_route(or, rt) != 0)
|
||||
continue;
|
||||
|
8
ipv6.h
8
ipv6.h
@ -146,7 +146,9 @@ struct rt6 {
|
||||
struct in6_addr gate;
|
||||
const struct interface *iface;
|
||||
unsigned int flags;
|
||||
#ifdef HAVE_ROUTE_METRIC
|
||||
unsigned int metric;
|
||||
#endif
|
||||
unsigned int mtu;
|
||||
};
|
||||
TAILQ_HEAD(rt6_head, rt6);
|
||||
@ -218,6 +220,8 @@ struct ipv6_ctx {
|
||||
struct ra_head *ra_routers;
|
||||
struct rt6_head *routes;
|
||||
|
||||
struct rt6_head kroutes;
|
||||
|
||||
int dhcp_fd;
|
||||
};
|
||||
|
||||
@ -266,8 +270,8 @@ void ipv6_addtempaddrs(struct interface *, const struct timeval *);
|
||||
|
||||
int ipv6_start(struct interface *);
|
||||
void ipv6_ctxfree(struct dhcpcd_ctx *);
|
||||
int ipv6_routedeleted(struct dhcpcd_ctx *, const struct rt6 *);
|
||||
int ipv6_removesubnet(struct interface *, struct ipv6_addr *);
|
||||
int ipv6_handlert(struct dhcpcd_ctx *, int cmd, struct rt6 *);
|
||||
void ipv6_freerts(struct rt6_head *);
|
||||
void ipv6_buildroutes(struct dhcpcd_ctx *);
|
||||
|
||||
#else
|
||||
|
6
ipv6nd.c
6
ipv6nd.c
@ -1118,6 +1118,12 @@ extra_opt:
|
||||
#ifdef IPV6_MANAGETEMPADDR
|
||||
ipv6_addtempaddrs(ifp, &rap->received);
|
||||
#endif
|
||||
|
||||
/* Find any freshly added routes, such as the subnet route.
|
||||
* We do this because we cannot rely on recieving the kernel
|
||||
* notification right now via our link socket. */
|
||||
if_initrt6(ifp);
|
||||
|
||||
ipv6_buildroutes(ifp->ctx);
|
||||
if (ipv6nd_scriptrun(rap))
|
||||
return;
|
||||
|
Loading…
Reference in New Issue
Block a user