mirror of
https://github.com/rsmarples/dhcpcd.git
synced 2024-11-24 18:44:10 +08:00
Add IPv4 address selection from route code so platform handlers don't
have to work it out.
This commit is contained in:
parent
a73798528c
commit
641cce4378
43
if-bsd.c
43
if-bsd.c
@ -508,8 +508,6 @@ if_copyrt(struct dhcpcd_ctx *ctx, struct rt *rt, struct rt_msghdr *rtm)
|
||||
int
|
||||
if_route(unsigned char cmd, const struct rt *rt)
|
||||
{
|
||||
const struct dhcp_state *state;
|
||||
const struct ipv4ll_state *istate;
|
||||
union sockunion {
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_in sin;
|
||||
@ -522,6 +520,7 @@ if_route(unsigned char cmd, const struct rt *rt)
|
||||
} rtm;
|
||||
char *bp = rtm.buffer;
|
||||
size_t l;
|
||||
struct in_addr src_addr;
|
||||
|
||||
#define ADDSU { \
|
||||
l = RT_ROUNDUP(su.sa.sa_len); \
|
||||
@ -536,47 +535,35 @@ if_route(unsigned char cmd, const struct rt *rt)
|
||||
ADDSU; \
|
||||
}
|
||||
|
||||
if (cmd != RTM_DELETE) {
|
||||
state = D_CSTATE(rt->iface);
|
||||
istate = IPV4LL_CSTATE(rt->iface);
|
||||
} else {
|
||||
/* appease GCC */
|
||||
state = NULL;
|
||||
istate = 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 (cmd == RTM_ADD || cmd == RTM_CHANGE)
|
||||
rtm.hdr.rtm_addrs |= RTA_GATEWAY;
|
||||
rtm.hdr.rtm_flags = RTF_UP;
|
||||
#ifdef RTF_PINNED
|
||||
if (cmd != RTM_ADD)
|
||||
rtm.hdr.rtm_flags |= RTF_PINNED;
|
||||
#endif
|
||||
|
||||
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)) &&
|
||||
(istate == NULL ||
|
||||
rt->dest.s_addr !=
|
||||
(istate->addr.s_addr & inaddr_llmask.s_addr) ||
|
||||
rt->net.s_addr != inaddr_llmask.s_addr))
|
||||
rtm.hdr.rtm_flags |= RTF_STATIC;
|
||||
else {
|
||||
if (cmd == RTM_ADD || cmd == RTM_CHANGE) {
|
||||
int subnet;
|
||||
|
||||
rtm.hdr.rtm_addrs |= RTA_GATEWAY | RTA_IFA | RTA_IFP;
|
||||
/* Subnet routes are clonning or connected if supported.
|
||||
* All other routes are static. */
|
||||
subnet = ipv4_srcaddr(rt, &src_addr);
|
||||
if (subnet == 1) {
|
||||
#ifdef RTF_CLONING
|
||||
rtm.hdr.rtm_flags |= RTF_CLONING;
|
||||
#endif
|
||||
#ifdef RTP_CONNECTED
|
||||
rtm.hdr.rtm_priority = RTP_CONNECTED;
|
||||
#endif
|
||||
}
|
||||
} else
|
||||
rtm.hdr.rtm_flags |= RTF_STATIC;
|
||||
if (subnet == -1) /* unikely */
|
||||
rtm.hdr.rtm_addrs &= ~RTA_IFA;
|
||||
}
|
||||
if (rt->net.s_addr == htonl(INADDR_BROADCAST) &&
|
||||
rt->gate.s_addr == htonl(INADDR_ANY))
|
||||
@ -607,7 +594,7 @@ if_route(unsigned char cmd, const struct rt *rt)
|
||||
}
|
||||
if ((cmd == RTM_ADD || cmd == RTM_CHANGE) &&
|
||||
!(rtm.hdr.rtm_flags & RTF_GATEWAY))
|
||||
rtm.hdr.rtm_addrs |= RTA_IFA | RTA_IFP;
|
||||
rtm.hdr.rtm_addrs |= RTA_IFP;
|
||||
|
||||
ADDADDR(&rt->dest);
|
||||
if (rtm.hdr.rtm_addrs & RTA_GATEWAY) {
|
||||
@ -638,7 +625,7 @@ if_route(unsigned char cmd, const struct rt *rt)
|
||||
}
|
||||
|
||||
if (rtm.hdr.rtm_addrs & RTA_IFA)
|
||||
ADDADDR(istate == NULL ? &state->addr : &istate->addr);
|
||||
ADDADDR(&src_addr);
|
||||
|
||||
if (rt->mtu) {
|
||||
rtm.hdr.rtm_inits |= RTV_MTU;
|
||||
|
87
if-linux.c
87
if-linux.c
@ -1329,9 +1329,8 @@ int
|
||||
if_route(unsigned char cmd, const struct rt *rt)
|
||||
{
|
||||
struct nlmr nlm;
|
||||
int retval = 0;
|
||||
const struct dhcp_state *state;
|
||||
const struct ipv4ll_state *istate;
|
||||
struct in_addr src_addr;
|
||||
int subnet;
|
||||
|
||||
memset(&nlm, 0, sizeof(nlm));
|
||||
nlm.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
|
||||
@ -1352,18 +1351,12 @@ if_route(unsigned char cmd, const struct rt *rt)
|
||||
nlm.rt.rtm_family = AF_INET;
|
||||
nlm.rt.rtm_table = RT_TABLE_MAIN;
|
||||
|
||||
state = D_CSTATE(rt->iface);
|
||||
istate = IPV4LL_CSTATE(rt->iface);
|
||||
if (cmd == RTM_DELETE)
|
||||
if (cmd == RTM_DELETE) {
|
||||
nlm.rt.rtm_scope = RT_SCOPE_NOWHERE;
|
||||
else {
|
||||
/* We only change route metrics for kernel routes */
|
||||
if ((rt->dest.s_addr ==
|
||||
(state->addr.s_addr & state->net.s_addr) &&
|
||||
rt->net.s_addr == state->net.s_addr) ||
|
||||
(istate && rt->dest.s_addr ==
|
||||
(istate->addr.s_addr & inaddr_llmask.s_addr) &&
|
||||
rt->net.s_addr == inaddr_llmask.s_addr))
|
||||
subnet = -1;
|
||||
} else {
|
||||
/* Subnet routes are RTPROT_KERNEL otherwise RTPROT_BOOT */
|
||||
if ((subnet = ipv4_srcaddr(rt, &src_addr)) == 1)
|
||||
nlm.rt.rtm_protocol = RTPROT_KERNEL;
|
||||
else
|
||||
nlm.rt.rtm_protocol = RTPROT_BOOT;
|
||||
@ -1381,37 +1374,37 @@ if_route(unsigned char cmd, const struct rt *rt)
|
||||
nlm.rt.rtm_dst_len = inet_ntocidr(rt->net);
|
||||
add_attr_l(&nlm.hdr, sizeof(nlm), RTA_DST,
|
||||
&rt->dest.s_addr, sizeof(rt->dest.s_addr));
|
||||
if (nlm.rt.rtm_protocol == RTPROT_KERNEL) {
|
||||
add_attr_l(&nlm.hdr, sizeof(nlm), RTA_PREFSRC,
|
||||
istate == NULL ? &state->addr.s_addr : &istate->addr.s_addr,
|
||||
sizeof(state->addr.s_addr));
|
||||
}
|
||||
/* If a host route then don't add the gateway */
|
||||
if ((cmd == RTM_ADD || cmd == RTM_CHANGE) &&
|
||||
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 (cmd == RTM_ADD || cmd == RTM_CHANGE) {
|
||||
if (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);
|
||||
if (subnet != -1) {
|
||||
add_attr_l(&nlm.hdr, sizeof(nlm), RTA_PREFSRC,
|
||||
&src_addr.s_addr, sizeof(src_addr.s_addr));
|
||||
}
|
||||
if (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),
|
||||
(unsigned short)RTA_PAYLOAD(metrics));
|
||||
}
|
||||
}
|
||||
|
||||
if (rt->gate.s_addr != htonl(INADDR_LOOPBACK))
|
||||
add_attr_32(&nlm.hdr, sizeof(nlm), RTA_OIF, rt->iface->index);
|
||||
if (rt->metric)
|
||||
add_attr_32(&nlm.hdr, sizeof(nlm), RTA_PRIORITY, rt->metric);
|
||||
|
||||
if (cmd != RTM_DELETE && 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), (unsigned short)RTA_PAYLOAD(metrics));
|
||||
}
|
||||
|
||||
if (send_netlink(rt->iface->ctx, NULL,
|
||||
NETLINK_ROUTE, &nlm.hdr, NULL) == -1)
|
||||
retval = -1;
|
||||
return retval;
|
||||
return send_netlink(rt->iface->ctx, NULL,
|
||||
NETLINK_ROUTE, &nlm.hdr, NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1461,7 +1454,6 @@ if_address6(const struct ipv6_addr *ia, int action)
|
||||
{
|
||||
struct nlma nlm;
|
||||
struct ifa_cacheinfo cinfo;
|
||||
int retval = 0;
|
||||
/* IFA_FLAGS is not a define, but is was added at the same time
|
||||
* IFA_F_NOPREFIXROUTE was do use that. */
|
||||
#if defined(IFA_F_NOPREFIXROUTE) || defined(IFA_F_MANAGETEMPADDR)
|
||||
@ -1517,17 +1509,14 @@ if_address6(const struct ipv6_addr *ia, int action)
|
||||
add_attr_32(&nlm.hdr, sizeof(nlm), IFA_FLAGS, flags);
|
||||
#endif
|
||||
|
||||
if (send_netlink(ia->iface->ctx, NULL, NETLINK_ROUTE, &nlm.hdr,
|
||||
NULL) == -1)
|
||||
retval = -1;
|
||||
return retval;
|
||||
return send_netlink(ia->iface->ctx, NULL,
|
||||
NETLINK_ROUTE, &nlm.hdr, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
if_route6(unsigned char cmd, const struct rt6 *rt)
|
||||
{
|
||||
struct nlmr nlm;
|
||||
int retval = 0;
|
||||
|
||||
memset(&nlm, 0, sizeof(nlm));
|
||||
nlm.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
|
||||
@ -1590,10 +1579,8 @@ if_route6(unsigned char cmd, const struct rt6 *rt)
|
||||
RTA_DATA(metrics), (unsigned short)RTA_PAYLOAD(metrics));
|
||||
}
|
||||
|
||||
if (send_netlink(rt->iface->ctx, NULL,
|
||||
NETLINK_ROUTE, &nlm.hdr, NULL) == -1)
|
||||
retval = -1;
|
||||
return retval;
|
||||
return send_netlink(rt->iface->ctx, NULL,
|
||||
NETLINK_ROUTE, &nlm.hdr, NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
|
55
ipv4.c
55
ipv4.c
@ -159,6 +159,51 @@ ipv4_findaddr(struct dhcpcd_ctx *ctx, const struct in_addr *addr)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
ipv4_srcaddr(const struct rt *rt, struct in_addr *addr)
|
||||
{
|
||||
const struct dhcp_state *dstate;
|
||||
const struct ipv4ll_state *istate;
|
||||
|
||||
if (rt->iface == NULL) {
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Prefer DHCP source address if matching */
|
||||
dstate = D_CSTATE(rt->iface);
|
||||
if (dstate &&
|
||||
rt->net.s_addr == dstate->net.s_addr &&
|
||||
rt->dest.s_addr == (dstate->addr.s_addr & dstate->net.s_addr))
|
||||
{
|
||||
*addr = dstate->addr;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Then IPv4LL source address if matching */
|
||||
istate = IPV4LL_CSTATE(rt->iface);
|
||||
if (istate &&
|
||||
rt->net.s_addr == inaddr_llmask.s_addr &&
|
||||
rt->dest.s_addr == (istate->addr.s_addr & inaddr_llmask.s_addr))
|
||||
{
|
||||
*addr = istate->addr;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* If neither match, return DHCP then IPv4LL */
|
||||
if (dstate) {
|
||||
*addr = dstate->addr;
|
||||
return 0;
|
||||
}
|
||||
if (istate) {
|
||||
*addr = istate->addr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
errno = ESRCH;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
ipv4_hasaddr(const struct interface *ifp)
|
||||
{
|
||||
@ -434,7 +479,7 @@ nc_route(struct rt *ort, struct rt *nrt)
|
||||
#endif
|
||||
|
||||
if (change) {
|
||||
if (if_route(RTM_CHANGE, nrt) == 0)
|
||||
if (if_route(RTM_CHANGE, nrt) != -1)
|
||||
return 0;
|
||||
if (errno != ESRCH)
|
||||
logger(nrt->iface->ctx, LOG_ERR, "if_route (CHG): %m");
|
||||
@ -448,7 +493,7 @@ nc_route(struct rt *ort, struct rt *nrt)
|
||||
#ifdef HAVE_ROUTE_METRIC
|
||||
/* With route metrics, we can safely add the new route before
|
||||
* deleting the old route. */
|
||||
if (if_route(RTM_ADD, nrt) == 0) {
|
||||
if (if_route(RTM_ADD, nrt) != -1) {
|
||||
if (ort && if_route(RTM_DELETE, ort) == -1 && errno != ESRCH)
|
||||
logger(nrt->iface->ctx, LOG_ERR, "if_route (DEL): %m");
|
||||
return 0;
|
||||
@ -464,7 +509,7 @@ nc_route(struct rt *ort, struct rt *nrt)
|
||||
* adding the new one. */
|
||||
if (ort && if_route(RTM_DELETE, ort) == -1 && errno != ESRCH)
|
||||
logger(nrt->iface->ctx, LOG_ERR, "if_route (DEL): %m");
|
||||
if (if_route(RTM_ADD, nrt) == 0)
|
||||
if (if_route(RTM_ADD, nrt) != -1)
|
||||
return 0;
|
||||
#ifdef HAVE_ROUTE_METRIC
|
||||
logerr:
|
||||
@ -479,8 +524,8 @@ d_route(struct rt *rt)
|
||||
int retval;
|
||||
|
||||
desc_route("deleting", rt);
|
||||
retval = if_route(RTM_DELETE, rt);
|
||||
if (retval != 0 && errno != ENOENT && errno != ESRCH)
|
||||
retval = if_route(RTM_DELETE, rt) == -1 ? -1 : 0;
|
||||
if (retval == -1 && errno != ENOENT && errno != ESRCH)
|
||||
logger(rt->iface->ctx, LOG_ERR,
|
||||
"%s: if_delroute: %m", rt->iface->name);
|
||||
return retval;
|
||||
|
1
ipv4.h
1
ipv4.h
@ -121,6 +121,7 @@ struct ipv4_addr *ipv4_iffindaddr(struct interface *,
|
||||
const struct in_addr *, const struct in_addr *);
|
||||
struct ipv4_addr *ipv4_iffindlladdr(struct interface *);
|
||||
struct ipv4_addr *ipv4_findaddr(struct dhcpcd_ctx *, const struct in_addr *);
|
||||
int ipv4_srcaddr(const struct rt *, struct in_addr *);
|
||||
void ipv4_handleifa(struct dhcpcd_ctx *, int, struct if_head *, const char *,
|
||||
const struct in_addr *, const struct in_addr *, const struct in_addr *,
|
||||
int);
|
||||
|
Loading…
Reference in New Issue
Block a user