From 9b136840d90cce887cd139054c3f0a7d8b9f57d2 Mon Sep 17 00:00:00 2001 From: Jan Moskyto Matejka Date: Mon, 7 Dec 2015 16:24:18 +0100 Subject: [PATCH] Netlink and BSD: Integrating IPv4 and IPv6 Squashing and minor changes by Ondrej Santiago Zajicek --- lib/Modules | 1 + lib/net.c | 60 ++++++++- lib/net.h | 5 +- nest/neighbor.c | 8 +- sysdep/bsd/krt-sock.c | 52 +++++--- sysdep/linux/netlink.c | 269 ++++++++++++++++++++++++++++------------- 6 files changed, 287 insertions(+), 108 deletions(-) diff --git a/lib/Modules b/lib/Modules index 745306d9..21830875 100644 --- a/lib/Modules +++ b/lib/Modules @@ -31,3 +31,4 @@ event.h checksum.c checksum.h alloca.h +net.c diff --git a/lib/net.c b/lib/net.c index 87d4aa16..df833e0f 100644 --- a/lib/net.c +++ b/lib/net.c @@ -8,9 +8,9 @@ const u16 net_addr_length[] = { [NET_IP6] = sizeof(net_addr_ip6), [NET_VPN4] = sizeof(net_addr_vpn4), [NET_VPN6] = sizeof(net_addr_vpn6) -} +}; -char * +int net_format(const net_addr *N, char *buf, int buflen) { net_addr_union *n = (void *) N; @@ -27,6 +27,58 @@ net_format(const net_addr *N, char *buf, int buflen) 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 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 @@ -42,6 +94,8 @@ net_classify(const net_addr *N) case NET_IP6: 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; } diff --git a/lib/net.h b/lib/net.h index 378703f7..33686fb5 100644 --- a/lib/net.h +++ b/lib/net.h @@ -131,6 +131,8 @@ static inline uint net6_pxlen(const net_addr *a) static inline uint net_pxlen(const net_addr *a) { return a->pxlen; } +ip_addr net_pxmask(const net_addr *a); + static inline int net_equal(const net_addr *a, const net_addr *b) { 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); int net_validate(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); diff --git a/nest/neighbor.c b/nest/neighbor.c index b8832f2f..14a6b113 100644 --- a/nest/neighbor.c +++ b/nest/neighbor.c @@ -81,15 +81,15 @@ if_connected(ip_addr *a, struct iface *i, struct ifa **ap) { if (ipa_in_netX(*a, &b->prefix)) { -#ifndef IPV6 - if ((b->pxlen < (BITS_PER_IP_ADDRESS - 1)) && - (ipa_equal(*a, b->prefix) || /* Network address */ + /* Do not allow IPv4 network and broadcast addresses */ + if (ipa_is_ip4(*a) && + (net_pxlen(&b->prefix) < (BITS_PER_IP_ADDRESS - 1)) && + (ipa_equal(*a, net_prefix(&b->prefix)) || /* Network address */ ipa_equal(*a, b->brd))) /* Broadcast */ { *ap = NULL; return -1; } -#endif return b->scope; } diff --git a/sysdep/bsd/krt-sock.c b/sysdep/bsd/krt-sock.c index 29203d1b..1db39493 100644 --- a/sysdep/bsd/krt-sock.c +++ b/sysdep/bsd/krt-sock.c @@ -207,7 +207,7 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e) msg.rtm.rtm_addrs = RTA_DST; 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; else 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); #endif - sockaddr_fill(&dst, BIRD_AF, net->n.prefix, NULL, 0); - sockaddr_fill(&mask, BIRD_AF, ipa_mkmask(net->n.pxlen), NULL, 0); - sockaddr_fill(&gate, BIRD_AF, gw, NULL, 0); + int af = AF_UNSPEC; + + 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) { @@ -299,7 +314,7 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e) msg.rtm.rtm_msglen = l; 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; } @@ -335,6 +350,7 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan) net *net; sockaddr dst, gate, mask; ip_addr idst, igate, imask; + net_addr ndst; void *body = (char *)msg->buf; int new = (msg->rtm.rtm_type != RTM_DELETE); 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) { 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)) - { 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 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 src = KRT_SRC_KERNEL; - net = net_get(p->p.table, idst, pxlen); + net = net_get(p->p.table, &ndst); rta a = { .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); if (!a.iface) { - log(L_ERR "KRT: Received route %I/%d with unknown ifindex %u", - net->n.prefix, net->n.pxlen, msg->rtm.rtm_index); + log(L_ERR "KRT: Received route %N with unknown ifindex %u", + net->n.addr, msg->rtm.rtm_index); 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)) return; - log(L_ERR "KRT: Received route %I/%d with strange next-hop %I", - net->n.prefix, net->n.pxlen, a.gw); + log(L_ERR "KRT: Received route %N with strange next-hop %I", + net->n.addr, a.gw); return; } } @@ -652,7 +671,7 @@ krt_read_addr(struct ks_msg *msg, int scan) imask = ipa_from_sa(&mask); ibrd = ipa_from_sa(&brd); - + /* XXXX */ if ((masklen = ipa_masklen(imask)) < 0) { 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)); ifa.iface = iface; ifa.ip = iaddr; - ifa.pxlen = masklen; scope = ipa_classify(ifa.ip); if (scope < 0) @@ -685,7 +703,8 @@ krt_read_addr(struct ks_msg *msg, int scan) 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)) 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)) { - ifa.prefix = ifa.opposite = ibrd; + net_fill_ipa(&ifa.prefix, ibrd, BITS_PER_IP_ADDRESS); + ifa.opposite = ibrd; ifa.flags |= IA_PEER; } else { - ifa.prefix = ifa.ip; + net_fill_ipa(&ifa.prefix, ifa.ip, BITS_PER_IP_ADDRESS); ifa.flags |= IA_HOST; } diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c index e56863cc..7c4c4b2b 100644 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@ -241,7 +241,6 @@ static struct nl_want_attrs ifla_attr_want[BIRD_IFLA_MAX] = { [IFLA_WIRELESS] = { 1, 0, 0 }, }; - #define BIRD_IFA_MAX (IFA_ANYCAST+1) #ifndef IPV6 @@ -257,7 +256,6 @@ static struct nl_want_attrs ifa_attr_want6[BIRD_IFA_MAX] = { }; #endif - #define BIRD_RTA_MAX (RTA_TABLE+1) 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)) { - log(L_ERR "nl_parse_attrs: Malformed message received"); + log(L_ERR "nl_parse_attrs: Malformed attribute received"); 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) { 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 * 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 -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); - nl_add_attr(h, bufsize, code, &ipa, sizeof(ipa)); + if (af == AF_INET) + { + 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 * @@ -408,7 +421,7 @@ nl_add_multipath(struct nlmsghdr *h, unsigned bufsize, struct mpnh *nh) rtnh->rtnh_hops = nh->weight; 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); } @@ -598,39 +611,117 @@ nl_parse_link(struct nlmsghdr *h, int scan) } 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]; - int new = h->nlmsg_type == RTM_NEWADDR; - struct ifa ifa; struct iface *ifi; int scope; - if (!(i = nl_checkin(h, sizeof(*i)))) + if (!nl_parse_attrs(IFA_RTA(i), ifa_attr_want4, a, sizeof(a))) return; - switch (i->ifa_family) + if (!a[IFA_LOCAL]) { -#ifndef IPV6 - case AF_INET: - if (!nl_parse_attrs(IFA_RTA(i), ifa_attr_want4, a, sizeof(a))) - return; - if (!a[IFA_LOCAL]) - { - log(L_ERR "KIF: Malformed message received (missing IFA_LOCAL)"); - return; - } - break; -#else - case AF_INET6: - if (!nl_parse_attrs(IFA_RTA(i), ifa_attr_want6, a, sizeof(a))) - return; - break; -#endif - default: - return; + log(L_ERR "KIF: Malformed message received (missing IFA_LOCAL)"); + return; } + if (!a[IFA_ADDRESS]) + { + log(L_ERR "KIF: Malformed message received (missing IFA_ADDRESS)"); + 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]) { @@ -645,15 +736,16 @@ nl_parse_addr(struct nlmsghdr *h, int scan) return; } + struct ifa ifa; bzero(&ifa, sizeof(ifa)); ifa.iface = ifi; if (i->ifa_flags & IFA_F_SECONDARY) ifa.flags |= IA_SECONDARY; /* 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.pxlen = i->ifa_prefixlen; + + ifa.ip = rta_get_ipa(a[IFA_LOCAL] ? : a[IFA_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); @@ -661,43 +753,25 @@ nl_parse_addr(struct nlmsghdr *h, int scan) } if (i->ifa_prefixlen == BITS_PER_IP_ADDRESS) { - ip_addr addr; - memcpy(&addr, RTA_DATA(a[IFA_ADDRESS]), sizeof(addr)); - ipa_ntoh(addr); - ifa.prefix = ifa.brd = addr; + ifa.brd = rta_get_ipa(a[IFA_ADDRESS]); + net_fill_ip6(&ifa.prefix, rta_get_ip6(a[IFA_ADDRESS]), i->ifa_prefixlen); /* 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; else { ifa.flags |= IA_PEER; - ifa.opposite = addr; + ifa.opposite = ifa.brd; } } else { - ip_addr netmask = ipa_mkmask(ifa.pxlen); - ifa.prefix = ipa_and(ifa.ip, netmask); - ifa.brd = ipa_or(ifa.ip, ipa_not(netmask)); + net_fill_ip6(&ifa.prefix, ipa_to_ip6(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); - -#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); @@ -708,10 +782,10 @@ nl_parse_addr(struct nlmsghdr *h, int scan) } 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, 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) ifa_update(&ifa); @@ -722,6 +796,28 @@ nl_parse_addr(struct nlmsghdr *h, int scan) 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 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)]; } 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.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_flags = NLM_F_REQUEST | NLM_F_ACK | (new ? NLM_F_CREATE|NLM_F_EXCL : 0); - r.r.rtm_family = BIRD_AF; - r.r.rtm_dst_len = net->n.pxlen; + int af = AF_UNSPEC; + + 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_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) 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); 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)) 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: r.r.rtm_type = RTN_UNICAST; 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; case RTD_DEVICE: r.r.rtm_type = RTN_UNICAST; @@ -931,11 +1040,13 @@ nl_parse_route(struct nlmsghdr *h, int scan) struct rtattr *a[BIRD_RTA_MAX]; int new = h->nlmsg_type == RTM_NEWROUTE; - ip_addr dst = IPA_NONE; + net_addr dst = { 0 }; u32 oif = ~0; u32 table; int src; + int ipv6 = 0; + if (!(i = nl_checkin(h, sizeof(*i)))) return; @@ -950,18 +1061,15 @@ nl_parse_route(struct nlmsghdr *h, int scan) case AF_INET6: if (!nl_parse_attrs(RTM_RTA(i), rtm_attr_want6, a, sizeof(a))) return; + ipv6 = 1; break; #endif default: return; } - if (a[RTA_DST]) - { - memcpy(&dst, RTA_DATA(a[RTA_DST]), sizeof(dst)); - ipa_ntoh(dst); - } + net_fill_ipa(&dst, rta_get_ipa(a[RTA_DST]), i->rtm_dst_len); if (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); -#ifdef IPV6 if (a[RTA_IIF]) SKIP("IIF set\n"); -#else if (i->rtm_tos != 0) /* We don't support TOS */ SKIP("TOS %02x\n", i->rtm_tos); -#endif if (scan && !new) 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)) SKIP("strange class/scope\n"); @@ -1020,7 +1125,7 @@ nl_parse_route(struct nlmsghdr *h, int scan) 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 = { .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)); ipa_ntoh(ra.gw); -#ifdef IPV6 /* 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; -#endif ng = neigh_find2(&p->p, &ra.gw, ra.iface, (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]) { - ip_addr ps; - memcpy(&ps, RTA_DATA(a[RTA_PREFSRC]), sizeof(ps)); - ipa_ntoh(ps); + ip_addr ps = rta_get_ipa(a[RTA_PREFSRC]); ea_list *ea = alloca(sizeof(ea_list) + sizeof(eattr)); ea->next = ra.eattrs;