diff options
Diffstat (limited to 'sysdep/bsd/krt-sock.c')
-rw-r--r-- | sysdep/bsd/krt-sock.c | 192 |
1 files changed, 119 insertions, 73 deletions
diff --git a/sysdep/bsd/krt-sock.c b/sysdep/bsd/krt-sock.c index f2ae81c3..3440ed63 100644 --- a/sysdep/bsd/krt-sock.c +++ b/sysdep/bsd/krt-sock.c @@ -28,9 +28,9 @@ #include "nest/route.h" #include "nest/protocol.h" #include "nest/iface.h" -#include "lib/timer.h" -#include "lib/unix.h" -#include "lib/krt.h" +#include "sysdep/unix/timer.h" +#include "sysdep/unix/unix.h" +#include "sysdep/unix/krt.h" #include "lib/string.h" #include "lib/socket.h" @@ -72,7 +72,6 @@ #endif - /* Dynamic max number of tables */ int krt_max_tables; @@ -136,7 +135,7 @@ extern int setfib(int fib); /* table_id -> krt_proto map */ #ifdef KRT_SHARED_SOCKET -static struct krt_proto *krt_table_map[KRT_MAX_TABLES]; +static struct krt_proto *krt_table_map[KRT_MAX_TABLES][2]; #endif @@ -207,7 +206,8 @@ 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) + /* XXXX */ + if (net_pxlen(net->n.addr) == net_max_prefix_length[net->n.addr->type]) msg.rtm.rtm_flags |= RTF_HOST; else msg.rtm.rtm_addrs |= RTA_NETMASK; @@ -245,15 +245,28 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e) gw = a->gw; -#ifdef IPV6 /* Embed interface ID to link-local address */ if (ipa_is_link_local(gw)) _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) { @@ -281,7 +294,7 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e) return -1; } - sockaddr_fill(&gate, BIRD_AF, i->addr->ip, NULL, 0); + sockaddr_fill(&gate, ipa_is_ip4(i->addr->ip) ? AF_INET : AF_INET6, i->addr->ip, NULL, 0); msg.rtm.rtm_addrs |= RTA_GATEWAY; } break; @@ -299,7 +312,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; } @@ -331,10 +344,12 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan) { /* p is NULL iff KRT_SHARED_SOCKET and !scan */ + int ipv6; rte *e; 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"; @@ -352,42 +367,64 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan) if (flags & RTF_LLINFO) SKIP("link-local\n"); -#ifdef KRT_SHARED_SOCKET - if (!scan) - { - int table_id = msg->rtm.rtm_tableid; - p = (table_id < KRT_MAX_TABLES) ? krt_table_map[table_id] : NULL; - - if (!p) - SKIP("unknown table id %d\n", table_id); - } -#endif - GETADDR(&dst, RTA_DST); GETADDR(&gate, RTA_GATEWAY); GETADDR(&mask, RTA_NETMASK); - if (dst.sa.sa_family != BIRD_AF) - SKIP("invalid DST"); + switch (dst.sa.sa_family) { + case AF_INET: + ipv6 = 0; + break; + case AF_INET6: + ipv6 = 1; + break; + default: + SKIP("invalid DST"); + } + + /* We do not test family for RTA_NETMASK, because BSD sends us + some strange values, but interpreting them as IPv4/IPv6 works */ + mask.sa.sa_family = dst.sa.sa_family; idst = ipa_from_sa(&dst); imask = ipa_from_sa(&mask); - igate = (gate.sa.sa_family == BIRD_AF) ? ipa_from_sa(&gate) : IPA_NONE; + igate = (gate.sa.sa_family == dst.sa.sa_family) ? ipa_from_sa(&gate) : IPA_NONE; - /* We do not test family for RTA_NETMASK, because BSD sends us - some strange values, but interpreting them as IPv4/IPv6 works */ +#ifdef KRT_SHARED_SOCKET + if (!scan) + { + int table_id = msg->rtm.rtm_tableid; + p = (table_id < KRT_MAX_TABLES) ? krt_table_map[table_id][ipv6] : NULL; + if (!p) + SKIP("unknown table id %d\n", table_id); + } +#endif + if ((!ipv6) && (p->p.main_channel->table->addr_type != NET_IP4)) + SKIP("reading only IPv4 routes"); + if ( ipv6 && (p->p.main_channel->table->addr_type != NET_IP6)) + SKIP("reading only IPv6 routes"); int c = ipa_classify_net(idst); if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK)) SKIP("strange class/scope\n"); - int pxlen = (flags & RTF_HOST) ? MAX_PREFIX_LENGTH : ipa_masklen(imask); + int pxlen; + if (ipv6) + pxlen = (flags & RTF_HOST) ? IP6_MAX_PREFIX_LENGTH : ip6_masklen(&ipa_to_ip6(imask)); + else + pxlen = (flags & RTF_HOST) ? IP4_MAX_PREFIX_LENGTH : ip4_masklen(ipa_to_ip4(imask)); + if (pxlen < 0) { log(L_ERR "%s (%I) - netmask %I", errmsg, idst, imask); return; } + if (ipv6) + net_fill_ip6(&ndst, ipa_to_ip6(idst), pxlen); + else + net_fill_ip4(&ndst, ipa_to_ip4(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 +463,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.main_channel->table, &ndst); rta a = { .src = p->p.main_source, @@ -455,8 +492,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; } @@ -466,11 +503,9 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan) a.dest = RTD_ROUTER; a.gw = igate; -#ifdef IPV6 /* Clean up embedded interface ID returned in link-local address */ if (ipa_is_link_local(a.gw)) _I0(a.gw) = 0xfe800000; -#endif ng = neigh_find2(&p->p, &a.gw, a.iface, 0); if (!ng || (ng->scope == SCOPE_HOST)) @@ -480,8 +515,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; } } @@ -643,22 +678,24 @@ krt_read_addr(struct ks_msg *msg, int scan) GETADDR (&null, RTA_AUTHOR); GETADDR (&brd, RTA_BRD); - /* Some other family address */ - if (addr.sa.sa_family != BIRD_AF) - return; + /* Is addr family IP4 or IP6? */ + int ipv6; + switch (addr.sa.sa_family) { + case AF_INET: ipv6 = 0; break; + case AF_INET6: ipv6 = 1; break; + default: return; + } iaddr = ipa_from_sa(&addr); imask = ipa_from_sa(&mask); ibrd = ipa_from_sa(&brd); - - if ((masklen = ipa_masklen(imask)) < 0) + if ((ipv6 ? (masklen = ip6_masklen(&ipa_to_ip6(imask))) : (masklen = ip4_masklen(ipa_to_ip4(imask)))) < 0) { - log(L_ERR "KIF: Invalid masklen %I for %s", imask, iface->name); + log(L_ERR "KIF: Invalid mask %I for %s", imask, iface->name); return; } -#ifdef IPV6 /* Clean up embedded interface ID returned in link-local address */ if (ipa_is_link_local(iaddr)) @@ -666,13 +703,11 @@ krt_read_addr(struct ks_msg *msg, int scan) if (ipa_is_link_local(ibrd)) _I0(ibrd) = 0xfe800000; -#endif bzero(&ifa, sizeof(ifa)); ifa.iface = iface; ifa.ip = iaddr; - ifa.pxlen = masklen; scope = ipa_classify(ifa.ip); if (scope < 0) @@ -682,17 +717,16 @@ krt_read_addr(struct ks_msg *msg, int scan) } ifa.scope = scope & IADDR_SCOPE_MASK; - if (masklen < BITS_PER_IP_ADDRESS) + if (masklen < (ipv6 ? IP6_MAX_PREFIX_LENGTH : IP4_MAX_PREFIX_LENGTH)) { - 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 == ((ipv6 ? IP6_MAX_PREFIX_LENGTH : IP4_MAX_PREFIX_LENGTH) - 1)) ifa.opposite = ipa_opposite_m1(ifa.ip); -#ifndef IPV6 - if (masklen == (BITS_PER_IP_ADDRESS - 2)) + if ((!ipv6) && (masklen == IP4_MAX_PREFIX_LENGTH - 2)) ifa.opposite = ipa_opposite_m2(ifa.ip); -#endif if (iface->flags & IF_BROADCAST) ifa.brd = ibrd; @@ -702,12 +736,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, (ipv6 ? IP6_MAX_PREFIX_LENGTH : IP4_MAX_PREFIX_LENGTH)); + ifa.opposite = ibrd; ifa.flags |= IA_PEER; } else { - ifa.prefix = ifa.ip; + net_fill_ipa(&ifa.prefix, ifa.ip, (ipv6 ? IP6_MAX_PREFIX_LENGTH : IP4_MAX_PREFIX_LENGTH)); ifa.flags |= IA_HOST; } @@ -804,7 +839,7 @@ krt_sysctl_scan(struct proto *p, int cmd, int table_id) mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; - mib[3] = BIRD_AF; + mib[3] = 0; // Set AF to 0 for all available families mib[4] = cmd; mib[5] = 0; mcnt = 6; @@ -948,6 +983,7 @@ krt_sock_open(pool *pool, void *data, int table_id) return sk; } +static u32 krt_table_cf[(KRT_MAX_TABLES+31) / 32][2]; #ifdef KRT_SHARED_SOCKET @@ -979,7 +1015,17 @@ krt_sock_close_shared(void) int krt_sys_start(struct krt_proto *p) { - krt_table_map[KRT_CF->sys.table_id] = p; + int id = KRT_CF->sys.table_id; + + if (krt_table_cf[id/32][!!(p->af == AF_INET6)] & (1 << (id%32))) + { + log(L_ERR "%s: Multiple kernel syncers defined for table #%d", p->p.name, id); + return 0; + } + + krt_table_cf[id/32][!!(p->af == AF_INET6)] |= (1 << (id%32)); + + krt_table_map[KRT_CF->sys.table_id][!!(p->af == AF_INET6)] = p; krt_sock_open_shared(); p->sys.sk = krt_sock; @@ -990,10 +1036,12 @@ krt_sys_start(struct krt_proto *p) void krt_sys_shutdown(struct krt_proto *p) { + krt_table_cf[(KRT_CF->sys.table_id)/32][!!(p->af == AF_INET6)] &= ~(1 << ((KRT_CF->sys.table_id)%32)); + krt_sock_close_shared(); p->sys.sk = NULL; - krt_table_map[KRT_CF->sys.table_id] = NULL; + krt_table_map[KRT_CF->sys.table_id][!!(p->af == AF_INET6)] = NULL; krt_buffer_release(&p->p); } @@ -1003,6 +1051,16 @@ krt_sys_shutdown(struct krt_proto *p) int krt_sys_start(struct krt_proto *p) { + int id = KRT_CF->sys.table_id; + + if (krt_table_cf[id/32][!!(p->af == AF_INET6)] & (1 << (id%32))) + { + log(L_ERR "%s: Multiple kernel syncers defined for table #%d", p->p.name, id); + return 0; + } + + krt_table_cf[id/32][!!(p->af == AF_INET6)] |= (1 << (id%32)); + p->sys.sk = krt_sock_open(p->p.pool, p, KRT_CF->sys.table_id); return 1; } @@ -1010,6 +1068,8 @@ krt_sys_start(struct krt_proto *p) void krt_sys_shutdown(struct krt_proto *p) { + krt_table_cf[(KRT_CF->sys.table_id)/32][!!(p->af == AF_INET6)] &= ~(1 << ((KRT_CF->sys.table_id)%32)); + rfree(p->sys.sk); p->sys.sk = NULL; @@ -1021,8 +1081,6 @@ krt_sys_shutdown(struct krt_proto *p) /* KRT configuration callbacks */ -static u32 krt_table_cf[(KRT_MAX_TABLES+31) / 32]; - int krt_sys_reconfigure(struct krt_proto *p UNUSED, struct krt_config *n, struct krt_config *o) { @@ -1036,18 +1094,6 @@ krt_sys_preconfig(struct config *c UNUSED) bzero(&krt_table_cf, sizeof(krt_table_cf)); } -void -krt_sys_postconfig(struct krt_config *x) -{ - u32 *tbl = krt_table_cf; - int id = x->sys.table_id; - - if (tbl[id/32] & (1 << (id%32))) - cf_error("Multiple kernel syncers defined for table #%d", id); - - tbl[id/32] |= (1 << (id%32)); -} - void krt_sys_init_config(struct krt_config *c) { c->sys.table_id = 0; /* Default table */ @@ -1076,7 +1122,7 @@ kif_sys_shutdown(struct kif_proto *p) struct ifa * kif_get_primary_ip(struct iface *i) { -#ifndef IPV6 +#if 0 static int fd = -1; if (fd < 0) |