Netlink and BSD: Integrating IPv4 and IPv6
Squashing and minor changes by Ondrej Santiago Zajicek
This commit is contained in:
parent
04ae8ddaa1
commit
9b136840d9
6 changed files with 287 additions and 108 deletions
|
@ -31,3 +31,4 @@ event.h
|
||||||
checksum.c
|
checksum.c
|
||||||
checksum.h
|
checksum.h
|
||||||
alloca.h
|
alloca.h
|
||||||
|
net.c
|
||||||
|
|
60
lib/net.c
60
lib/net.c
|
@ -8,9 +8,9 @@ const u16 net_addr_length[] = {
|
||||||
[NET_IP6] = sizeof(net_addr_ip6),
|
[NET_IP6] = sizeof(net_addr_ip6),
|
||||||
[NET_VPN4] = sizeof(net_addr_vpn4),
|
[NET_VPN4] = sizeof(net_addr_vpn4),
|
||||||
[NET_VPN6] = sizeof(net_addr_vpn6)
|
[NET_VPN6] = sizeof(net_addr_vpn6)
|
||||||
}
|
};
|
||||||
|
|
||||||
char *
|
int
|
||||||
net_format(const net_addr *N, char *buf, int buflen)
|
net_format(const net_addr *N, char *buf, int buflen)
|
||||||
{
|
{
|
||||||
net_addr_union *n = (void *) N;
|
net_addr_union *n = (void *) N;
|
||||||
|
@ -27,6 +27,58 @@ net_format(const net_addr *N, char *buf, int buflen)
|
||||||
case NET_VPN6:
|
case NET_VPN6:
|
||||||
return bsnprintf(buf, buflen, "%u:%u %I/%d", (u32) (n->vpn6.rd >> 32), (u32) n->vpn6.rd, n->vpn6.prefix, n->vpn6.pxlen);
|
return bsnprintf(buf, buflen, "%u:%u %I/%d", (u32) (n->vpn6.rd >> 32), (u32) n->vpn6.rd, n->vpn6.prefix, n->vpn6.pxlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ip_addr
|
||||||
|
net_pxmask(const net_addr *a)
|
||||||
|
{
|
||||||
|
switch (a->type)
|
||||||
|
{
|
||||||
|
case NET_IP4:
|
||||||
|
case NET_VPN4:
|
||||||
|
return ipa_from_ip4(ip4_mkmask(net4_pxlen(a)));
|
||||||
|
|
||||||
|
case NET_IP6:
|
||||||
|
case NET_VPN6:
|
||||||
|
return ipa_from_ip6(ip6_mkmask(net6_pxlen(a)));
|
||||||
|
|
||||||
|
default:
|
||||||
|
return IPA_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline int net_validate_ip4(const net_addr_ip4 *n)
|
||||||
|
{
|
||||||
|
return (n->pxlen <= IP4_MAX_PREFIX_LENGTH) &&
|
||||||
|
ip4_zero(ip4_and(n->prefix, ip4_not(ip4_mkmask(n->pxlen))));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int net_validate_ip6(const net_addr_ip6 *n)
|
||||||
|
{
|
||||||
|
return (n->pxlen <= IP6_MAX_PREFIX_LENGTH) &&
|
||||||
|
ip6_zero(ip6_and(n->prefix, ip6_not(ip6_mkmask(n->pxlen))));
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
net_validate(const net_addr *N)
|
||||||
|
{
|
||||||
|
switch (a->type)
|
||||||
|
{
|
||||||
|
case NET_IP4:
|
||||||
|
case NET_VPN4:
|
||||||
|
return net_validate_ip4((net_addr_ip4 *) N);
|
||||||
|
|
||||||
|
case NET_IP6:
|
||||||
|
case NET_VPN6:
|
||||||
|
return net_validate_ip6((net_addr_ip6 *) N);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -42,6 +94,8 @@ net_classify(const net_addr *N)
|
||||||
|
|
||||||
case NET_IP6:
|
case NET_IP6:
|
||||||
case NET_VPN6:
|
case NET_VPN6:
|
||||||
return ip6_zero(n->ip6.prefix) ? (IADDR_HOST | SCOPE_UNIVERSE) : ip6_classify(n->ip6.prefix);
|
return ip6_zero(n->ip6.prefix) ? (IADDR_HOST | SCOPE_UNIVERSE) : ip6_classify(&n->ip6.prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,6 +131,8 @@ static inline uint net6_pxlen(const net_addr *a)
|
||||||
static inline uint net_pxlen(const net_addr *a)
|
static inline uint net_pxlen(const net_addr *a)
|
||||||
{ return a->pxlen; }
|
{ return a->pxlen; }
|
||||||
|
|
||||||
|
ip_addr net_pxmask(const net_addr *a);
|
||||||
|
|
||||||
|
|
||||||
static inline int net_equal(const net_addr *a, const net_addr *b)
|
static inline int net_equal(const net_addr *a, const net_addr *b)
|
||||||
{ return (a->length == b->length) && !memcmp(a, b, a->length); }
|
{ return (a->length == b->length) && !memcmp(a, b, a->length); }
|
||||||
|
@ -203,8 +205,9 @@ static inline void net_normalize_ip6(net_addr_ip6 *n)
|
||||||
void net_normalize(net_addr *N);
|
void net_normalize(net_addr *N);
|
||||||
|
|
||||||
int net_validate(const net_addr *N);
|
int net_validate(const net_addr *N);
|
||||||
|
|
||||||
int net_classify(const net_addr *N);
|
int net_classify(const net_addr *N);
|
||||||
char * net_format(const net_addr *N, char *buf, int buflen);
|
int net_format(const net_addr *N, char *buf, int buflen);
|
||||||
|
|
||||||
|
|
||||||
int ipa_in_netX(const ip_addr A, const net_addr *N);
|
int ipa_in_netX(const ip_addr A, const net_addr *N);
|
||||||
|
|
|
@ -81,15 +81,15 @@ if_connected(ip_addr *a, struct iface *i, struct ifa **ap)
|
||||||
{
|
{
|
||||||
if (ipa_in_netX(*a, &b->prefix))
|
if (ipa_in_netX(*a, &b->prefix))
|
||||||
{
|
{
|
||||||
#ifndef IPV6
|
/* Do not allow IPv4 network and broadcast addresses */
|
||||||
if ((b->pxlen < (BITS_PER_IP_ADDRESS - 1)) &&
|
if (ipa_is_ip4(*a) &&
|
||||||
(ipa_equal(*a, b->prefix) || /* Network address */
|
(net_pxlen(&b->prefix) < (BITS_PER_IP_ADDRESS - 1)) &&
|
||||||
|
(ipa_equal(*a, net_prefix(&b->prefix)) || /* Network address */
|
||||||
ipa_equal(*a, b->brd))) /* Broadcast */
|
ipa_equal(*a, b->brd))) /* Broadcast */
|
||||||
{
|
{
|
||||||
*ap = NULL;
|
*ap = NULL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
return b->scope;
|
return b->scope;
|
||||||
}
|
}
|
||||||
|
|
|
@ -207,7 +207,7 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e)
|
||||||
msg.rtm.rtm_addrs = RTA_DST;
|
msg.rtm.rtm_addrs = RTA_DST;
|
||||||
msg.rtm.rtm_flags = RTF_UP | RTF_PROTO1;
|
msg.rtm.rtm_flags = RTF_UP | RTF_PROTO1;
|
||||||
|
|
||||||
if (net->n.pxlen == MAX_PREFIX_LENGTH)
|
if (net_prefix(net->n.addr) == MAX_PREFIX_LENGTH)
|
||||||
msg.rtm.rtm_flags |= RTF_HOST;
|
msg.rtm.rtm_flags |= RTF_HOST;
|
||||||
else
|
else
|
||||||
msg.rtm.rtm_addrs |= RTA_NETMASK;
|
msg.rtm.rtm_addrs |= RTA_NETMASK;
|
||||||
|
@ -251,9 +251,24 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e)
|
||||||
_I0(gw) = 0xfe800000 | (i->index & 0x0000ffff);
|
_I0(gw) = 0xfe800000 | (i->index & 0x0000ffff);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
sockaddr_fill(&dst, BIRD_AF, net->n.prefix, NULL, 0);
|
int af = AF_UNSPEC;
|
||||||
sockaddr_fill(&mask, BIRD_AF, ipa_mkmask(net->n.pxlen), NULL, 0);
|
|
||||||
sockaddr_fill(&gate, BIRD_AF, gw, NULL, 0);
|
switch (net->n.addr->type) {
|
||||||
|
case NET_IP4:
|
||||||
|
af = AF_INET;
|
||||||
|
break;
|
||||||
|
case NET_IP6:
|
||||||
|
af = AF_INET6;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
log(L_ERR "KRT: Not sending VPN route %N to kernel", net->n.addr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sockaddr_fill(&dst, af, net_prefix(net->n.addr), NULL, 0);
|
||||||
|
sockaddr_fill(&mask, af, net_pxmask(net->n.addr), NULL, 0);
|
||||||
|
sockaddr_fill(&gate, af, gw, NULL, 0);
|
||||||
|
|
||||||
switch (a->dest)
|
switch (a->dest)
|
||||||
{
|
{
|
||||||
|
@ -299,7 +314,7 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e)
|
||||||
msg.rtm.rtm_msglen = l;
|
msg.rtm.rtm_msglen = l;
|
||||||
|
|
||||||
if ((l = write(p->sys.sk->fd, (char *)&msg, l)) < 0) {
|
if ((l = write(p->sys.sk->fd, (char *)&msg, l)) < 0) {
|
||||||
log(L_ERR "KRT: Error sending route %I/%d to kernel: %m", net->n.prefix, net->n.pxlen);
|
log(L_ERR "KRT: Error sending route %N to kernel: %m", net->n.addr);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -335,6 +350,7 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan)
|
||||||
net *net;
|
net *net;
|
||||||
sockaddr dst, gate, mask;
|
sockaddr dst, gate, mask;
|
||||||
ip_addr idst, igate, imask;
|
ip_addr idst, igate, imask;
|
||||||
|
net_addr ndst;
|
||||||
void *body = (char *)msg->buf;
|
void *body = (char *)msg->buf;
|
||||||
int new = (msg->rtm.rtm_type != RTM_DELETE);
|
int new = (msg->rtm.rtm_type != RTM_DELETE);
|
||||||
char *errmsg = "KRT: Invalid route received";
|
char *errmsg = "KRT: Invalid route received";
|
||||||
|
@ -386,8 +402,11 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan)
|
||||||
if (pxlen < 0)
|
if (pxlen < 0)
|
||||||
{ log(L_ERR "%s (%I) - netmask %I", errmsg, idst, imask); return; }
|
{ log(L_ERR "%s (%I) - netmask %I", errmsg, idst, imask); return; }
|
||||||
|
|
||||||
|
/* XXXX */
|
||||||
|
net_fill_ipa(&ndst, idst, pxlen);
|
||||||
|
|
||||||
if ((flags & RTF_GATEWAY) && ipa_zero(igate))
|
if ((flags & RTF_GATEWAY) && ipa_zero(igate))
|
||||||
{ log(L_ERR "%s (%I/%d) - missing gateway", errmsg, idst, pxlen); return; }
|
{ log(L_ERR "%s (%N) - missing gateway", errmsg, ndst); return; }
|
||||||
|
|
||||||
u32 self_mask = RTF_PROTO1;
|
u32 self_mask = RTF_PROTO1;
|
||||||
u32 alien_mask = RTF_STATIC | RTF_PROTO1 | RTF_GATEWAY;
|
u32 alien_mask = RTF_STATIC | RTF_PROTO1 | RTF_GATEWAY;
|
||||||
|
@ -426,7 +445,7 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan)
|
||||||
else
|
else
|
||||||
src = KRT_SRC_KERNEL;
|
src = KRT_SRC_KERNEL;
|
||||||
|
|
||||||
net = net_get(p->p.table, idst, pxlen);
|
net = net_get(p->p.table, &ndst);
|
||||||
|
|
||||||
rta a = {
|
rta a = {
|
||||||
.src = p->p.main_source,
|
.src = p->p.main_source,
|
||||||
|
@ -455,8 +474,8 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan)
|
||||||
a.iface = if_find_by_index(msg->rtm.rtm_index);
|
a.iface = if_find_by_index(msg->rtm.rtm_index);
|
||||||
if (!a.iface)
|
if (!a.iface)
|
||||||
{
|
{
|
||||||
log(L_ERR "KRT: Received route %I/%d with unknown ifindex %u",
|
log(L_ERR "KRT: Received route %N with unknown ifindex %u",
|
||||||
net->n.prefix, net->n.pxlen, msg->rtm.rtm_index);
|
net->n.addr, msg->rtm.rtm_index);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -480,8 +499,8 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan)
|
||||||
if (ipa_classify(a.gw) == (IADDR_HOST | SCOPE_HOST))
|
if (ipa_classify(a.gw) == (IADDR_HOST | SCOPE_HOST))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
log(L_ERR "KRT: Received route %I/%d with strange next-hop %I",
|
log(L_ERR "KRT: Received route %N with strange next-hop %I",
|
||||||
net->n.prefix, net->n.pxlen, a.gw);
|
net->n.addr, a.gw);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -652,7 +671,7 @@ krt_read_addr(struct ks_msg *msg, int scan)
|
||||||
imask = ipa_from_sa(&mask);
|
imask = ipa_from_sa(&mask);
|
||||||
ibrd = ipa_from_sa(&brd);
|
ibrd = ipa_from_sa(&brd);
|
||||||
|
|
||||||
|
/* XXXX */
|
||||||
if ((masklen = ipa_masklen(imask)) < 0)
|
if ((masklen = ipa_masklen(imask)) < 0)
|
||||||
{
|
{
|
||||||
log(L_ERR "KIF: Invalid masklen %I for %s", imask, iface->name);
|
log(L_ERR "KIF: Invalid masklen %I for %s", imask, iface->name);
|
||||||
|
@ -673,7 +692,6 @@ krt_read_addr(struct ks_msg *msg, int scan)
|
||||||
bzero(&ifa, sizeof(ifa));
|
bzero(&ifa, sizeof(ifa));
|
||||||
ifa.iface = iface;
|
ifa.iface = iface;
|
||||||
ifa.ip = iaddr;
|
ifa.ip = iaddr;
|
||||||
ifa.pxlen = masklen;
|
|
||||||
|
|
||||||
scope = ipa_classify(ifa.ip);
|
scope = ipa_classify(ifa.ip);
|
||||||
if (scope < 0)
|
if (scope < 0)
|
||||||
|
@ -685,7 +703,8 @@ krt_read_addr(struct ks_msg *msg, int scan)
|
||||||
|
|
||||||
if (masklen < BITS_PER_IP_ADDRESS)
|
if (masklen < BITS_PER_IP_ADDRESS)
|
||||||
{
|
{
|
||||||
ifa.prefix = ipa_and(ifa.ip, ipa_mkmask(masklen));
|
net_fill_ipa(&ifa.prefix, ifa.ip, masklen);
|
||||||
|
net_normalize(&ifa.prefix);
|
||||||
|
|
||||||
if (masklen == (BITS_PER_IP_ADDRESS - 1))
|
if (masklen == (BITS_PER_IP_ADDRESS - 1))
|
||||||
ifa.opposite = ipa_opposite_m1(ifa.ip);
|
ifa.opposite = ipa_opposite_m1(ifa.ip);
|
||||||
|
@ -703,12 +722,13 @@ krt_read_addr(struct ks_msg *msg, int scan)
|
||||||
}
|
}
|
||||||
else if (!(iface->flags & IF_MULTIACCESS) && ipa_nonzero(ibrd))
|
else if (!(iface->flags & IF_MULTIACCESS) && ipa_nonzero(ibrd))
|
||||||
{
|
{
|
||||||
ifa.prefix = ifa.opposite = ibrd;
|
net_fill_ipa(&ifa.prefix, ibrd, BITS_PER_IP_ADDRESS);
|
||||||
|
ifa.opposite = ibrd;
|
||||||
ifa.flags |= IA_PEER;
|
ifa.flags |= IA_PEER;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ifa.prefix = ifa.ip;
|
net_fill_ipa(&ifa.prefix, ifa.ip, BITS_PER_IP_ADDRESS);
|
||||||
ifa.flags |= IA_HOST;
|
ifa.flags |= IA_HOST;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -241,7 +241,6 @@ static struct nl_want_attrs ifla_attr_want[BIRD_IFLA_MAX] = {
|
||||||
[IFLA_WIRELESS] = { 1, 0, 0 },
|
[IFLA_WIRELESS] = { 1, 0, 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#define BIRD_IFA_MAX (IFA_ANYCAST+1)
|
#define BIRD_IFA_MAX (IFA_ANYCAST+1)
|
||||||
|
|
||||||
#ifndef IPV6
|
#ifndef IPV6
|
||||||
|
@ -257,7 +256,6 @@ static struct nl_want_attrs ifa_attr_want6[BIRD_IFA_MAX] = {
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define BIRD_RTA_MAX (RTA_TABLE+1)
|
#define BIRD_RTA_MAX (RTA_TABLE+1)
|
||||||
|
|
||||||
static struct nl_want_attrs mpnh_attr_want4[BIRD_RTA_MAX] = {
|
static struct nl_want_attrs mpnh_attr_want4[BIRD_RTA_MAX] = {
|
||||||
|
@ -304,7 +302,7 @@ nl_parse_attrs(struct rtattr *a, struct nl_want_attrs *want, struct rtattr **k,
|
||||||
|
|
||||||
if (want[a->rta_type].checksize && (RTA_PAYLOAD(a) != want[a->rta_type].size))
|
if (want[a->rta_type].checksize && (RTA_PAYLOAD(a) != want[a->rta_type].size))
|
||||||
{
|
{
|
||||||
log(L_ERR "nl_parse_attrs: Malformed message received");
|
log(L_ERR "nl_parse_attrs: Malformed attribute received");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,6 +327,13 @@ static inline ip4_addr rta_get_ip4(struct rtattr *a)
|
||||||
static inline ip6_addr rta_get_ip6(struct rtattr *a)
|
static inline ip6_addr rta_get_ip6(struct rtattr *a)
|
||||||
{ return ip6_ntoh(*(ip6_addr *) RTA_DATA(a)); }
|
{ return ip6_ntoh(*(ip6_addr *) RTA_DATA(a)); }
|
||||||
|
|
||||||
|
static inline ip_addr rta_get_ipa(struct rtattr *a)
|
||||||
|
{
|
||||||
|
if (RTA_PAYLOAD(a) == sizeof(ip4_addr))
|
||||||
|
return ipa_from_ip4(rta_get_ip4(a));
|
||||||
|
else
|
||||||
|
return ipa_from_ip6(rta_get_ip6(a));
|
||||||
|
}
|
||||||
|
|
||||||
struct rtattr *
|
struct rtattr *
|
||||||
nl_add_attr(struct nlmsghdr *h, uint bufsize, uint code, const void *data, uint dlen)
|
nl_add_attr(struct nlmsghdr *h, uint bufsize, uint code, const void *data, uint dlen)
|
||||||
|
@ -357,10 +362,18 @@ nl_add_attr_u32(struct nlmsghdr *h, unsigned bufsize, int code, u32 data)
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
nl_add_attr_ipa(struct nlmsghdr *h, unsigned bufsize, int code, ip_addr ipa)
|
nl_add_attr_ipa(struct nlmsghdr *h, unsigned bufsize, int code, ip_addr ipa, int af)
|
||||||
{
|
{
|
||||||
ipa_hton(ipa);
|
if (af == AF_INET)
|
||||||
nl_add_attr(h, bufsize, code, &ipa, sizeof(ipa));
|
{
|
||||||
|
ip4_addr ip4 = ip4_hton(ipa_to_ip4(ipa));
|
||||||
|
nl_add_attr(h, bufsize, code, &ip4, sizeof(ip4));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ip6_addr ip6 = ip6_hton(ipa_to_ip6(ipa));
|
||||||
|
nl_add_attr(h, bufsize, code, &ip6, sizeof(ip6));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct rtattr *
|
static inline struct rtattr *
|
||||||
|
@ -408,7 +421,7 @@ nl_add_multipath(struct nlmsghdr *h, unsigned bufsize, struct mpnh *nh)
|
||||||
rtnh->rtnh_hops = nh->weight;
|
rtnh->rtnh_hops = nh->weight;
|
||||||
rtnh->rtnh_ifindex = nh->iface->index;
|
rtnh->rtnh_ifindex = nh->iface->index;
|
||||||
|
|
||||||
nl_add_attr_ipa(h, bufsize, RTA_GATEWAY, nh->gw);
|
nl_add_attr_ipa(h, bufsize, RTA_GATEWAY, nh->gw, AF_INET);
|
||||||
|
|
||||||
nl_close_nexthop(h, rtnh);
|
nl_close_nexthop(h, rtnh);
|
||||||
}
|
}
|
||||||
|
@ -598,40 +611,118 @@ nl_parse_link(struct nlmsghdr *h, int scan)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
nl_parse_addr(struct nlmsghdr *h, int scan)
|
nl_parse_addr4(struct ifaddrmsg *i, int scan, int new)
|
||||||
{
|
{
|
||||||
struct ifaddrmsg *i;
|
|
||||||
struct rtattr *a[BIRD_IFA_MAX];
|
struct rtattr *a[BIRD_IFA_MAX];
|
||||||
int new = h->nlmsg_type == RTM_NEWADDR;
|
|
||||||
struct ifa ifa;
|
|
||||||
struct iface *ifi;
|
struct iface *ifi;
|
||||||
int scope;
|
int scope;
|
||||||
|
|
||||||
if (!(i = nl_checkin(h, sizeof(*i))))
|
|
||||||
return;
|
|
||||||
|
|
||||||
switch (i->ifa_family)
|
|
||||||
{
|
|
||||||
#ifndef IPV6
|
|
||||||
case AF_INET:
|
|
||||||
if (!nl_parse_attrs(IFA_RTA(i), ifa_attr_want4, a, sizeof(a)))
|
if (!nl_parse_attrs(IFA_RTA(i), ifa_attr_want4, a, sizeof(a)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!a[IFA_LOCAL])
|
if (!a[IFA_LOCAL])
|
||||||
{
|
{
|
||||||
log(L_ERR "KIF: Malformed message received (missing IFA_LOCAL)");
|
log(L_ERR "KIF: Malformed message received (missing IFA_LOCAL)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
if (!a[IFA_ADDRESS])
|
||||||
#else
|
{
|
||||||
case AF_INET6:
|
log(L_ERR "KIF: Malformed message received (missing IFA_ADDRESS)");
|
||||||
if (!nl_parse_attrs(IFA_RTA(i), ifa_attr_want6, a, sizeof(a)))
|
|
||||||
return;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ifi = if_find_by_index(i->ifa_index);
|
||||||
|
if (!ifi)
|
||||||
|
{
|
||||||
|
log(L_ERR "KIF: Received address message for unknown interface %d", i->ifa_index);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ifa ifa;
|
||||||
|
bzero(&ifa, sizeof(ifa));
|
||||||
|
ifa.iface = ifi;
|
||||||
|
if (i->ifa_flags & IFA_F_SECONDARY)
|
||||||
|
ifa.flags |= IA_SECONDARY;
|
||||||
|
|
||||||
|
ifa.ip = rta_get_ipa(a[IFA_LOCAL]);
|
||||||
|
|
||||||
|
if (i->ifa_prefixlen > BITS_PER_IP_ADDRESS)
|
||||||
|
{
|
||||||
|
log(L_ERR "KIF: Invalid prefix length for interface %s: %d", ifi->name, i->ifa_prefixlen);
|
||||||
|
new = 0;
|
||||||
|
}
|
||||||
|
if (i->ifa_prefixlen == BITS_PER_IP_ADDRESS)
|
||||||
|
{
|
||||||
|
ifa.brd = rta_get_ipa(a[IFA_ADDRESS]);
|
||||||
|
net_fill_ip4(&ifa.prefix, rta_get_ip4(a[IFA_ADDRESS]), i->ifa_prefixlen);
|
||||||
|
|
||||||
|
/* It is either a host address or a peer address */
|
||||||
|
if (ipa_equal(ifa.ip, ifa.brd))
|
||||||
|
ifa.flags |= IA_HOST;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ifa.flags |= IA_PEER;
|
||||||
|
ifa.opposite = ifa.brd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
net_fill_ip4(&ifa.prefix, ipa_to_ip4(ifa.ip), i->ifa_prefixlen);
|
||||||
|
net_normalize(&ifa.prefix);
|
||||||
|
|
||||||
|
if (i->ifa_prefixlen == BITS_PER_IP_ADDRESS - 1)
|
||||||
|
ifa.opposite = ipa_opposite_m1(ifa.ip);
|
||||||
|
|
||||||
|
if (i->ifa_prefixlen == BITS_PER_IP_ADDRESS - 2)
|
||||||
|
ifa.opposite = ipa_opposite_m2(ifa.ip);
|
||||||
|
|
||||||
|
if ((ifi->flags & IF_BROADCAST) && a[IFA_BROADCAST])
|
||||||
|
{
|
||||||
|
ip4_addr xbrd = rta_get_ip4(a[IFA_BROADCAST]);
|
||||||
|
ip4_addr ybrd = ip4_or(ipa_to_ip4(ifa.ip), ip4_not(ip4_mkmask(i->ifa_prefixlen)));
|
||||||
|
|
||||||
|
if (ip4_equal(xbrd, net4_prefix(&ifa.prefix)) || ip4_equal(xbrd, ybrd))
|
||||||
|
ifa.brd = ipa_from_ip4(xbrd);
|
||||||
|
else if (ifi->flags & IF_TMP_DOWN) /* Complain only during the first scan */
|
||||||
|
{
|
||||||
|
log(L_ERR "KIF: Invalid broadcast address %I for %s", xbrd, ifi->name);
|
||||||
|
ifa.brd = ipa_from_ip4(ybrd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scope = ipa_classify(ifa.ip);
|
||||||
|
if (scope < 0)
|
||||||
|
{
|
||||||
|
log(L_ERR "KIF: Invalid interface address %I for %s", ifa.ip, ifi->name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ifa.scope = scope & IADDR_SCOPE_MASK;
|
||||||
|
|
||||||
|
DBG("KIF: IF%d(%s): %s IPA %I, flg %x, net %N, brd %I, opp %I\n",
|
||||||
|
ifi->index, ifi->name,
|
||||||
|
new ? "added" : "removed",
|
||||||
|
ifa.ip, ifa.flags, ifa.prefix, ifa.brd, ifa.opposite);
|
||||||
|
|
||||||
|
if (new)
|
||||||
|
ifa_update(&ifa);
|
||||||
|
else
|
||||||
|
ifa_delete(&ifa);
|
||||||
|
|
||||||
|
if (!scan)
|
||||||
|
if_end_partial_update(ifi);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nl_parse_addr6(struct ifaddrmsg *i, int scan, int new)
|
||||||
|
{
|
||||||
|
struct rtattr *a[BIRD_IFA_MAX];
|
||||||
|
struct iface *ifi;
|
||||||
|
int scope;
|
||||||
|
|
||||||
|
if (!nl_parse_attrs(IFA_RTA(i), ifa_attr_want6, a, sizeof(a)))
|
||||||
|
return;
|
||||||
|
|
||||||
if (!a[IFA_ADDRESS])
|
if (!a[IFA_ADDRESS])
|
||||||
{
|
{
|
||||||
log(L_ERR "KIF: Malformed message received (missing IFA_ADDRESS)");
|
log(L_ERR "KIF: Malformed message received (missing IFA_ADDRESS)");
|
||||||
|
@ -645,15 +736,16 @@ nl_parse_addr(struct nlmsghdr *h, int scan)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ifa ifa;
|
||||||
bzero(&ifa, sizeof(ifa));
|
bzero(&ifa, sizeof(ifa));
|
||||||
ifa.iface = ifi;
|
ifa.iface = ifi;
|
||||||
if (i->ifa_flags & IFA_F_SECONDARY)
|
if (i->ifa_flags & IFA_F_SECONDARY)
|
||||||
ifa.flags |= IA_SECONDARY;
|
ifa.flags |= IA_SECONDARY;
|
||||||
|
|
||||||
/* IFA_LOCAL can be unset for IPv6 interfaces */
|
/* IFA_LOCAL can be unset for IPv6 interfaces */
|
||||||
memcpy(&ifa.ip, RTA_DATA(a[IFA_LOCAL] ? : a[IFA_ADDRESS]), sizeof(ifa.ip));
|
|
||||||
ipa_ntoh(ifa.ip);
|
ifa.ip = rta_get_ipa(a[IFA_LOCAL] ? : a[IFA_ADDRESS]);
|
||||||
ifa.pxlen = i->ifa_prefixlen;
|
|
||||||
if (i->ifa_prefixlen > BITS_PER_IP_ADDRESS)
|
if (i->ifa_prefixlen > BITS_PER_IP_ADDRESS)
|
||||||
{
|
{
|
||||||
log(L_ERR "KIF: Invalid prefix length for interface %s: %d", ifi->name, i->ifa_prefixlen);
|
log(L_ERR "KIF: Invalid prefix length for interface %s: %d", ifi->name, i->ifa_prefixlen);
|
||||||
|
@ -661,43 +753,25 @@ nl_parse_addr(struct nlmsghdr *h, int scan)
|
||||||
}
|
}
|
||||||
if (i->ifa_prefixlen == BITS_PER_IP_ADDRESS)
|
if (i->ifa_prefixlen == BITS_PER_IP_ADDRESS)
|
||||||
{
|
{
|
||||||
ip_addr addr;
|
ifa.brd = rta_get_ipa(a[IFA_ADDRESS]);
|
||||||
memcpy(&addr, RTA_DATA(a[IFA_ADDRESS]), sizeof(addr));
|
net_fill_ip6(&ifa.prefix, rta_get_ip6(a[IFA_ADDRESS]), i->ifa_prefixlen);
|
||||||
ipa_ntoh(addr);
|
|
||||||
ifa.prefix = ifa.brd = addr;
|
|
||||||
|
|
||||||
/* It is either a host address or a peer address */
|
/* It is either a host address or a peer address */
|
||||||
if (ipa_equal(ifa.ip, addr))
|
if (ipa_equal(ifa.ip, ifa.brd))
|
||||||
ifa.flags |= IA_HOST;
|
ifa.flags |= IA_HOST;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ifa.flags |= IA_PEER;
|
ifa.flags |= IA_PEER;
|
||||||
ifa.opposite = addr;
|
ifa.opposite = ifa.brd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ip_addr netmask = ipa_mkmask(ifa.pxlen);
|
net_fill_ip6(&ifa.prefix, ipa_to_ip6(ifa.ip), i->ifa_prefixlen);
|
||||||
ifa.prefix = ipa_and(ifa.ip, netmask);
|
net_normalize(&ifa.prefix);
|
||||||
ifa.brd = ipa_or(ifa.ip, ipa_not(netmask));
|
|
||||||
if (i->ifa_prefixlen == BITS_PER_IP_ADDRESS - 1)
|
if (i->ifa_prefixlen == BITS_PER_IP_ADDRESS - 1)
|
||||||
ifa.opposite = ipa_opposite_m1(ifa.ip);
|
ifa.opposite = ipa_opposite_m1(ifa.ip);
|
||||||
|
|
||||||
#ifndef IPV6
|
|
||||||
if (i->ifa_prefixlen == BITS_PER_IP_ADDRESS - 2)
|
|
||||||
ifa.opposite = ipa_opposite_m2(ifa.ip);
|
|
||||||
|
|
||||||
if ((ifi->flags & IF_BROADCAST) && a[IFA_BROADCAST])
|
|
||||||
{
|
|
||||||
ip_addr xbrd;
|
|
||||||
memcpy(&xbrd, RTA_DATA(a[IFA_BROADCAST]), sizeof(xbrd));
|
|
||||||
ipa_ntoh(xbrd);
|
|
||||||
if (ipa_equal(xbrd, ifa.prefix) || ipa_equal(xbrd, ifa.brd))
|
|
||||||
ifa.brd = xbrd;
|
|
||||||
else if (ifi->flags & IF_TMP_DOWN) /* Complain only during the first scan */
|
|
||||||
log(L_ERR "KIF: Invalid broadcast address %I for %s", xbrd, ifi->name);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
scope = ipa_classify(ifa.ip);
|
scope = ipa_classify(ifa.ip);
|
||||||
|
@ -708,10 +782,10 @@ nl_parse_addr(struct nlmsghdr *h, int scan)
|
||||||
}
|
}
|
||||||
ifa.scope = scope & IADDR_SCOPE_MASK;
|
ifa.scope = scope & IADDR_SCOPE_MASK;
|
||||||
|
|
||||||
DBG("KIF: IF%d(%s): %s IPA %I, flg %x, net %I/%d, brd %I, opp %I\n",
|
DBG("KIF: IF%d(%s): %s IPA %I, flg %x, net %N, brd %I, opp %I\n",
|
||||||
ifi->index, ifi->name,
|
ifi->index, ifi->name,
|
||||||
new ? "added" : "removed",
|
new ? "added" : "removed",
|
||||||
ifa.ip, ifa.flags, ifa.prefix, ifa.pxlen, ifa.brd, ifa.opposite);
|
ifa.ip, ifa.flags, ifa.prefix, ifa.brd, ifa.opposite);
|
||||||
|
|
||||||
if (new)
|
if (new)
|
||||||
ifa_update(&ifa);
|
ifa_update(&ifa);
|
||||||
|
@ -722,6 +796,28 @@ nl_parse_addr(struct nlmsghdr *h, int scan)
|
||||||
if_end_partial_update(ifi);
|
if_end_partial_update(ifi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nl_parse_addr(struct nlmsghdr *h, int scan)
|
||||||
|
{
|
||||||
|
struct ifaddrmsg *i;
|
||||||
|
|
||||||
|
if (!(i = nl_checkin(h, sizeof(*i))))
|
||||||
|
return;
|
||||||
|
|
||||||
|
int new = (h->nlmsg_type == RTM_NEWADDR);
|
||||||
|
|
||||||
|
switch (i->ifa_family)
|
||||||
|
{
|
||||||
|
#ifndef IPV6
|
||||||
|
case AF_INET:
|
||||||
|
return nl_parse_addr4(i, scan, new);
|
||||||
|
#else
|
||||||
|
case AF_INET6:
|
||||||
|
return nl_parse_addr6(i, scan, new);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
kif_do_scan(struct kif_proto *p UNUSED)
|
kif_do_scan(struct kif_proto *p UNUSED)
|
||||||
{
|
{
|
||||||
|
@ -814,7 +910,7 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int new)
|
||||||
char buf[128 + KRT_METRICS_MAX*8 + nh_bufsize(a->nexthops)];
|
char buf[128 + KRT_METRICS_MAX*8 + nh_bufsize(a->nexthops)];
|
||||||
} r;
|
} r;
|
||||||
|
|
||||||
DBG("nl_send_route(%I/%d,new=%d)\n", net->n.prefix, net->n.pxlen, new);
|
DBG("nl_send_route(%N,new=%d)\n", net->n.addr, new);
|
||||||
|
|
||||||
bzero(&r.h, sizeof(r.h));
|
bzero(&r.h, sizeof(r.h));
|
||||||
bzero(&r.r, sizeof(r.r));
|
bzero(&r.r, sizeof(r.r));
|
||||||
|
@ -822,11 +918,24 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int new)
|
||||||
r.h.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
|
r.h.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
|
||||||
r.h.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | (new ? NLM_F_CREATE|NLM_F_EXCL : 0);
|
r.h.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | (new ? NLM_F_CREATE|NLM_F_EXCL : 0);
|
||||||
|
|
||||||
r.r.rtm_family = BIRD_AF;
|
int af = AF_UNSPEC;
|
||||||
r.r.rtm_dst_len = net->n.pxlen;
|
|
||||||
|
switch(net->n.addr->type) {
|
||||||
|
case NET_IP4:
|
||||||
|
af = AF_INET;
|
||||||
|
break;
|
||||||
|
case NET_IP6:
|
||||||
|
af = AF_INET6;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
bug("should not send vpn route to kernel");
|
||||||
|
}
|
||||||
|
|
||||||
|
r.r.rtm_family = af;
|
||||||
|
r.r.rtm_dst_len = net_pxlen(net->n.addr);
|
||||||
r.r.rtm_protocol = RTPROT_BIRD;
|
r.r.rtm_protocol = RTPROT_BIRD;
|
||||||
r.r.rtm_scope = RT_SCOPE_UNIVERSE;
|
r.r.rtm_scope = RT_SCOPE_UNIVERSE;
|
||||||
nl_add_attr_ipa(&r.h, sizeof(r), RTA_DST, net->n.prefix);
|
nl_add_attr_ipa(&r.h, sizeof(r), RTA_DST, net_prefix(net->n.addr), af);
|
||||||
|
|
||||||
if (krt_table_id(p) < 256)
|
if (krt_table_id(p) < 256)
|
||||||
r.r.rtm_table = krt_table_id(p);
|
r.r.rtm_table = krt_table_id(p);
|
||||||
|
@ -842,7 +951,7 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int new)
|
||||||
nl_add_attr_u32(&r.h, sizeof(r), RTA_PRIORITY, ea->u.data);
|
nl_add_attr_u32(&r.h, sizeof(r), RTA_PRIORITY, ea->u.data);
|
||||||
|
|
||||||
if (ea = ea_find(eattrs, EA_KRT_PREFSRC))
|
if (ea = ea_find(eattrs, EA_KRT_PREFSRC))
|
||||||
nl_add_attr_ipa(&r.h, sizeof(r), RTA_PREFSRC, *(ip_addr *)ea->u.ptr->data);
|
nl_add_attr_ipa(&r.h, sizeof(r), RTA_PREFSRC, *(ip_addr *)ea->u.ptr->data, af);
|
||||||
|
|
||||||
if (ea = ea_find(eattrs, EA_KRT_REALM))
|
if (ea = ea_find(eattrs, EA_KRT_REALM))
|
||||||
nl_add_attr_u32(&r.h, sizeof(r), RTA_FLOW, ea->u.data);
|
nl_add_attr_u32(&r.h, sizeof(r), RTA_FLOW, ea->u.data);
|
||||||
|
@ -870,7 +979,7 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int new)
|
||||||
case RTD_ROUTER:
|
case RTD_ROUTER:
|
||||||
r.r.rtm_type = RTN_UNICAST;
|
r.r.rtm_type = RTN_UNICAST;
|
||||||
nl_add_attr_u32(&r.h, sizeof(r), RTA_OIF, a->iface->index);
|
nl_add_attr_u32(&r.h, sizeof(r), RTA_OIF, a->iface->index);
|
||||||
nl_add_attr_ipa(&r.h, sizeof(r), RTA_GATEWAY, a->gw);
|
nl_add_attr_ipa(&r.h, sizeof(r), RTA_GATEWAY, a->gw, af);
|
||||||
break;
|
break;
|
||||||
case RTD_DEVICE:
|
case RTD_DEVICE:
|
||||||
r.r.rtm_type = RTN_UNICAST;
|
r.r.rtm_type = RTN_UNICAST;
|
||||||
|
@ -931,11 +1040,13 @@ nl_parse_route(struct nlmsghdr *h, int scan)
|
||||||
struct rtattr *a[BIRD_RTA_MAX];
|
struct rtattr *a[BIRD_RTA_MAX];
|
||||||
int new = h->nlmsg_type == RTM_NEWROUTE;
|
int new = h->nlmsg_type == RTM_NEWROUTE;
|
||||||
|
|
||||||
ip_addr dst = IPA_NONE;
|
net_addr dst = { 0 };
|
||||||
u32 oif = ~0;
|
u32 oif = ~0;
|
||||||
u32 table;
|
u32 table;
|
||||||
int src;
|
int src;
|
||||||
|
|
||||||
|
int ipv6 = 0;
|
||||||
|
|
||||||
if (!(i = nl_checkin(h, sizeof(*i))))
|
if (!(i = nl_checkin(h, sizeof(*i))))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -950,18 +1061,15 @@ nl_parse_route(struct nlmsghdr *h, int scan)
|
||||||
case AF_INET6:
|
case AF_INET6:
|
||||||
if (!nl_parse_attrs(RTM_RTA(i), rtm_attr_want6, a, sizeof(a)))
|
if (!nl_parse_attrs(RTM_RTA(i), rtm_attr_want6, a, sizeof(a)))
|
||||||
return;
|
return;
|
||||||
|
ipv6 = 1;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (a[RTA_DST])
|
if (a[RTA_DST])
|
||||||
{
|
net_fill_ipa(&dst, rta_get_ipa(a[RTA_DST]), i->rtm_dst_len);
|
||||||
memcpy(&dst, RTA_DATA(a[RTA_DST]), sizeof(dst));
|
|
||||||
ipa_ntoh(dst);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (a[RTA_OIF])
|
if (a[RTA_OIF])
|
||||||
oif = rta_get_u32(a[RTA_OIF]);
|
oif = rta_get_u32(a[RTA_OIF]);
|
||||||
|
@ -977,18 +1085,15 @@ nl_parse_route(struct nlmsghdr *h, int scan)
|
||||||
SKIP("unknown table %d\n", table);
|
SKIP("unknown table %d\n", table);
|
||||||
|
|
||||||
|
|
||||||
#ifdef IPV6
|
|
||||||
if (a[RTA_IIF])
|
if (a[RTA_IIF])
|
||||||
SKIP("IIF set\n");
|
SKIP("IIF set\n");
|
||||||
#else
|
|
||||||
if (i->rtm_tos != 0) /* We don't support TOS */
|
if (i->rtm_tos != 0) /* We don't support TOS */
|
||||||
SKIP("TOS %02x\n", i->rtm_tos);
|
SKIP("TOS %02x\n", i->rtm_tos);
|
||||||
#endif
|
|
||||||
|
|
||||||
if (scan && !new)
|
if (scan && !new)
|
||||||
SKIP("RTM_DELROUTE in scan\n");
|
SKIP("RTM_DELROUTE in scan\n");
|
||||||
|
|
||||||
int c = ipa_classify_net(dst);
|
int c = net_classify(&dst);
|
||||||
if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
|
if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
|
||||||
SKIP("strange class/scope\n");
|
SKIP("strange class/scope\n");
|
||||||
|
|
||||||
|
@ -1020,7 +1125,7 @@ nl_parse_route(struct nlmsghdr *h, int scan)
|
||||||
src = KRT_SRC_ALIEN;
|
src = KRT_SRC_ALIEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
net *net = net_get(p->p.table, dst, i->rtm_dst_len);
|
net *net = net_get(p->p.table, &dst);
|
||||||
|
|
||||||
rta ra = {
|
rta ra = {
|
||||||
.src= p->p.main_source,
|
.src= p->p.main_source,
|
||||||
|
@ -1060,11 +1165,9 @@ nl_parse_route(struct nlmsghdr *h, int scan)
|
||||||
memcpy(&ra.gw, RTA_DATA(a[RTA_GATEWAY]), sizeof(ra.gw));
|
memcpy(&ra.gw, RTA_DATA(a[RTA_GATEWAY]), sizeof(ra.gw));
|
||||||
ipa_ntoh(ra.gw);
|
ipa_ntoh(ra.gw);
|
||||||
|
|
||||||
#ifdef IPV6
|
|
||||||
/* Silently skip strange 6to4 routes */
|
/* Silently skip strange 6to4 routes */
|
||||||
if (ipa_in_net(ra.gw, IPA_NONE, 96))
|
if (ipv6 && ipa_in_net(ra.gw, IPA_NONE, 96))
|
||||||
return;
|
return;
|
||||||
#endif
|
|
||||||
|
|
||||||
ng = neigh_find2(&p->p, &ra.gw, ra.iface,
|
ng = neigh_find2(&p->p, &ra.gw, ra.iface,
|
||||||
(i->rtm_flags & RTNH_F_ONLINK) ? NEF_ONLINK : 0);
|
(i->rtm_flags & RTNH_F_ONLINK) ? NEF_ONLINK : 0);
|
||||||
|
@ -1107,9 +1210,7 @@ nl_parse_route(struct nlmsghdr *h, int scan)
|
||||||
|
|
||||||
if (a[RTA_PREFSRC])
|
if (a[RTA_PREFSRC])
|
||||||
{
|
{
|
||||||
ip_addr ps;
|
ip_addr ps = rta_get_ipa(a[RTA_PREFSRC]);
|
||||||
memcpy(&ps, RTA_DATA(a[RTA_PREFSRC]), sizeof(ps));
|
|
||||||
ipa_ntoh(ps);
|
|
||||||
|
|
||||||
ea_list *ea = alloca(sizeof(ea_list) + sizeof(eattr));
|
ea_list *ea = alloca(sizeof(ea_list) + sizeof(eattr));
|
||||||
ea->next = ra.eattrs;
|
ea->next = ra.eattrs;
|
||||||
|
|
Loading…
Reference in a new issue