summaryrefslogtreecommitdiff
path: root/sysdep
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2010-03-11 18:55:59 +0100
committerOndrej Zajicek <santiago@crfreenet.org>2010-03-11 18:55:59 +0100
commit54305181f6ee3af57dd3d15d53ea2e851b36ed23 (patch)
treea5aed631b68df033cba372f841d47a0cba5d7021 /sysdep
parente7b76b976084006e430543f4b872f624326dbfe6 (diff)
parentafa9f66c27e2f96b92059131def53cc7b2497705 (diff)
Merge branch 'new' into socket2
Diffstat (limited to 'sysdep')
-rw-r--r--sysdep/bsd/krt-sock.c261
-rw-r--r--sysdep/cf/bsd-v6.h2
-rw-r--r--sysdep/cf/bsd.h2
-rw-r--r--sysdep/linux/netlink/netlink.c151
-rw-r--r--sysdep/linux/sysio.h2
-rw-r--r--sysdep/unix/config.Y2
-rw-r--r--sysdep/unix/io.c15
-rw-r--r--sysdep/unix/krt.c52
-rw-r--r--sysdep/unix/krt.h1
-rw-r--r--sysdep/unix/log.c1
-rw-r--r--sysdep/unix/main.c13
-rw-r--r--sysdep/unix/unix.h5
12 files changed, 253 insertions, 254 deletions
diff --git a/sysdep/bsd/krt-sock.c b/sysdep/bsd/krt-sock.c
index a5279657..1dd09ae9 100644
--- a/sysdep/bsd/krt-sock.c
+++ b/sysdep/bsd/krt-sock.c
@@ -33,39 +33,8 @@
#include "lib/string.h"
#include "lib/socket.h"
-#ifdef IPV6
-#define HOST_MASK 128
-#else
-#define HOST_MASK 32
-#endif
-
int rt_sock = 0;
-#define CHECK_FAMILY(sa) \
- ((((struct sockaddr *)sa)->sa_family) == BIRD_AF)
-
-static struct iface *
-krt_temp_iface_index(struct krt_proto *p, unsigned index)
-{
- struct iface *i, *j;
-
- WALK_LIST(i, p->scan.temp_ifs)
- if (i->index == index)
- return i;
- i = mb_allocz(p->p.pool, sizeof(struct iface));
- if (j = if_find_by_index(index))
- {
- strcpy(i->name, j->name);
- i->addr = j->addr;
- }
- else
- strcpy(i->name, "?");
- i->index = index;
- add_tail(&p->scan.temp_ifs, &i->n);
- return i;
-}
-
-
int
krt_capable(rte *e)
{
@@ -83,7 +52,7 @@ krt_capable(rte *e)
|| a->dest == RTD_UNREACHABLE
#endif
#ifdef RTF_BLACKHOLE
- || a->dest == RTD_BLACKHOLE /* FIXME Prohibited? */
+ || a->dest == RTD_BLACKHOLE
#endif
);
}
@@ -96,6 +65,13 @@ krt_capable(rte *e)
l = ROUNDUP(((struct sockaddr *)&(u))->sa_len);\
memmove(body, &(u), l); body += l;}
+#define GETADDR(p, F) \
+ bzero(p, sizeof(*p));\
+ if ((addrs & (F)) && ((struct sockaddr *)body)->sa_len) {\
+ unsigned int l = ROUNDUP(((struct sockaddr *)body)->sa_len);\
+ memcpy(p, body, (l > sizeof(*p) ? sizeof(*p) : l));\
+ body += l;}
+
static void
krt_sock_send(int cmd, rte *e)
{
@@ -108,7 +84,7 @@ krt_sock_send(int cmd, rte *e)
char *body = (char *)msg.buf;
sockaddr gate, mask, dst;
- DBG("krt-sock: send %I/%d via %I", net->n.prefix, net->n.pxlen, a->gw);
+ DBG("krt-sock: send %I/%d via %I\n", net->n.prefix, net->n.pxlen, a->gw);
fill_in_sockaddr(&dst, net->n.prefix, 0);
fill_in_sockaddr(&mask, ipa_mkmask(net->n.pxlen), 0);
@@ -119,9 +95,9 @@ krt_sock_send(int cmd, rte *e)
msg.rtm.rtm_type = cmd;
msg.rtm.rtm_seq = msg_seq++;
msg.rtm.rtm_addrs = RTA_DST;
- msg.rtm.rtm_flags = RTF_UP;
+ msg.rtm.rtm_flags = RTF_UP | RTF_PROTO1;
- if (net->n.pxlen == HOST_MASK)
+ if (net->n.pxlen == MAX_PREFIX_LENGTH)
{
msg.rtm.rtm_flags |= RTF_HOST;
}
@@ -200,12 +176,12 @@ krt_sock_send(int cmd, rte *e)
msg.rtm.rtm_msglen = l;
if ((l = write(rt_sock, (char *)&msg, l)) < 0) {
- log(L_ERR "KIF: error writting route to socket (%I/%d)", net->n.prefix, net->n.pxlen);
+ log(L_ERR "KIF: Error sending route %I/%d to kernel", net->n.prefix, net->n.pxlen);
}
}
void
-krt_set_notify(struct krt_proto *p UNUSED, net *net UNUSED, rte *new, rte *old)
+krt_set_notify(struct krt_proto *p UNUSED, net *net, rte *new, rte *old)
{
if (old)
{
@@ -258,68 +234,87 @@ krt_set_start(struct krt_proto *x, int first UNUSED)
bug("krt-sock: sk_open failed");
}
+#define SKIP(ARG...) do { DBG("KRT: Ignoring route - " ARG); return; } while(0)
+
static void
krt_read_rt(struct ks_msg *msg, struct krt_proto *p, int scan)
{
- sockaddr gate, mask, dst;
rta a;
rte *e;
net *net;
+ sockaddr dst, gate, mask;
ip_addr idst, igate, imask;
void *body = (char *)msg->buf;
int new = (msg->rtm.rtm_type == RTM_ADD);
int src;
+ char *errmsg = "KRT: Invalid route received";
int flags = msg->rtm.rtm_flags;
int addrs = msg->rtm.rtm_addrs;
- int masklen = -1;
- if (!(flags & RTF_UP))
- {
- DBG("Down.\n");
- return;
- }
+ if (!(flags & RTF_UP) && scan)
+ SKIP("not up in scan\n");
- if (flags & RTF_HOST)
- masklen = HOST_MASK;
+ if (!(flags & RTF_DONE) && !scan)
+ SKIP("not done in async\n");
- if(!CHECK_FAMILY(body)) return;
+ if (flags & RTF_LLINFO)
+ SKIP("link-local\n");
- if(msg->rtm.rtm_flags & RTF_LLINFO) return; /* ARPs etc. */
+ GETADDR(&dst, RTA_DST);
+ GETADDR(&gate, RTA_GATEWAY);
+ GETADDR(&mask, RTA_NETMASK);
-#define GETADDR(p, F) \
- bzero(p, sizeof(*p));\
- if ((addrs & (F)) && ((struct sockaddr *)body)->sa_len) {\
- unsigned int l = ROUNDUP(((struct sockaddr *)body)->sa_len);\
- memcpy(p, body, (l > sizeof(*p) ? sizeof(*p) : l));\
- body += l;}
-
- GETADDR (&dst, RTA_DST);
- GETADDR (&gate, RTA_GATEWAY);
- GETADDR (&mask, RTA_NETMASK);
+ if (sa_family_check(&dst))
+ get_sockaddr(&dst, &idst, NULL, 0);
+ else
+ SKIP("invalid DST");
- idst = IPA_NONE;
- igate = IPA_NONE;
- imask = IPA_NONE;
+ /* We will check later whether we have valid gateway addr */
+ if (sa_family_check(&gate))
+ get_sockaddr(&gate, &igate, NULL, 0);
+ else
+ igate = IPA_NONE;
- get_sockaddr(&dst, &idst, NULL, 0);
- if(CHECK_FAMILY(&gate)) get_sockaddr(&gate, &igate, NULL, 0);
+ /* We do not test family for RTA_NETMASK, because BSD sends us
+ some strange values, but interpreting them as IPv4/IPv6 works */
get_sockaddr(&mask, &imask, NULL, 0);
- if (masklen < 0) masklen = ipa_mklen(imask);
+ int c = ipa_classify_net(idst);
+ if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
+ SKIP("strange class/scope\n");
- if (flags & (RTF_DYNAMIC | RTF_MODIFIED))
- {
- log(L_WARN "krt: Ignoring redirect to %I/%d via %I", idst, masklen, igate);
- return;
- }
+ int pxlen = (flags & RTF_HOST) ? MAX_PREFIX_LENGTH : ipa_mklen(imask);
+ if (pxlen < 0)
+ { log(L_ERR "%s (%I) - netmask %I", errmsg, idst, imask); return; }
- if (masklen < 0)
- {
- log(L_WARN "krt: Got invalid route from kernel!");
- return;
- }
+ if ((flags & RTF_GATEWAY) && ipa_zero(igate))
+ { log(L_ERR "%s (%I/%d) - missing gateway", errmsg, idst, pxlen); return; }
- net = net_get(p->p.table, idst, masklen);
+ u32 self_mask = RTF_PROTO1;
+ u32 alien_mask = RTF_STATIC | RTF_PROTO1;
+
+#ifdef RTF_PROTO2
+ alien_mask |= RTF_PROTO2;
+#endif
+
+#ifdef RTF_PROTO3
+ alien_mask |= RTF_PROTO3;
+#endif
+
+ if (flags & (RTF_DYNAMIC | RTF_MODIFIED))
+ src = KRT_SRC_REDIRECT;
+ else if (flags & self_mask)
+ {
+ if (!scan)
+ SKIP("echo\n");
+ src = KRT_SRC_BIRD;
+ }
+ else if (flags & alien_mask)
+ src = KRT_SRC_ALIEN;
+ else
+ src = KRT_SRC_KERNEL;
+
+ net = net_get(p->p.table, idst, pxlen);
bzero(&a, sizeof(a));
@@ -333,56 +328,56 @@ krt_read_rt(struct ks_msg *msg, struct krt_proto *p, int scan)
a.iface = NULL;
a.eattrs = NULL;
- a.dest = RTD_NONE;
-
- if (flags & RTF_GATEWAY)
- {
- neighbor *ng = neigh_find(&p->p, &igate, 0);
- if (ng && ng->scope)
- a.iface = ng->iface;
- else
- {
- log(L_WARN "Kernel told us to use non-neighbor %I for %I/%d", igate, net->n.prefix, net->n.pxlen);
- return;
- }
-
- a.dest = RTD_ROUTER;
- a.gw = igate;
- }
- else
- {
- a.dest = RTD_DEVICE;
- a.gw = IPA_NONE;
- a.iface = krt_temp_iface_index(p, msg->rtm.rtm_index);
- }
+ /* reject/blackhole routes have also set RTF_GATEWAY,
+ we wil check them first. */
#ifdef RTF_REJECT
if(flags & RTF_REJECT) {
a.dest = RTD_UNREACHABLE;
- a.gw = IPA_NONE;
+ goto done;
}
#endif
#ifdef RTF_BLACKHOLE
if(flags & RTF_BLACKHOLE) {
a.dest = RTD_BLACKHOLE;
- a.gw = IPA_NONE;
+ goto done;
}
#endif
- if (a.dest == RTD_NONE)
+ 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);
+ return;
+ }
+
+ if (flags & RTF_GATEWAY)
{
- log(L_WARN "Kernel reporting unknown route type to %I/%d", net->n.prefix, net->n.pxlen);
- return;
- }
+ neighbor *ng;
+ a.dest = RTD_ROUTER;
+ a.gw = igate;
- src = KRT_SRC_UNKNOWN; /* FIXME */
+ ng = neigh_find2(&p->p, &a.gw, a.iface, 0);
+ if (!ng || (ng->scope == SCOPE_HOST))
+ {
+ log(L_ERR "KRT: Received route %I/%d with strange next-hop %I",
+ net->n.prefix, net->n.pxlen, a.gw);
+ return;
+ }
+ }
+ else
+ a.dest = RTD_DEVICE;
+ done:
e = rte_get_temp(&a);
e->net = net;
e->u.krt.src = src;
- //e->u.krt.proto = i->rtm_protocol;
- //e->u.krt.type = i->rtm_type;
+
+ /* These are probably too Linux-specific */
+ e->u.krt.proto = 0;
+ e->u.krt.type = 0;
e->u.krt.metric = 0;
if (scan)
@@ -471,6 +466,10 @@ krt_read_addr(struct ks_msg *msg)
int scope, masklen = -1;
int new = (ifam->ifam_type == RTM_NEWADDR);
+ /* Strange messages with zero (invalid) ifindex appear on OpenBSD */
+ if (ifam->ifam_index == 0)
+ return;
+
if(!(iface = if_find_by_index(ifam->ifam_index)))
{
log(L_ERR "KIF: Received address message for unknown interface %d", ifam->ifam_index);
@@ -486,7 +485,9 @@ krt_read_addr(struct ks_msg *msg)
GETADDR (&null, RTA_AUTHOR);
GETADDR (&brd, RTA_BRD);
- if(!CHECK_FAMILY(&addr)) return; /* Some other family address */
+ /* Some other family address */
+ if (!sa_family_check(&addr))
+ return;
get_sockaddr(&addr, &iaddr, NULL, 0);
get_sockaddr(&mask, &imask, NULL, 0);
@@ -507,9 +508,6 @@ krt_read_addr(struct ks_msg *msg)
memcpy(&ifa.brd, &ibrd, sizeof(ip_addr));
scope = ipa_classify(ifa.ip);
-
- ifa.prefix = ipa_and(ifa.ip, ipa_mkmask(masklen));
-
if (scope < 0)
{
log(L_ERR "KIF: Invalid interface address %I for %s", ifa.ip, iface->name);
@@ -517,6 +515,14 @@ krt_read_addr(struct ks_msg *msg)
}
ifa.scope = scope & IADDR_SCOPE_MASK;
+ if (iface->flags & IF_MULTIACCESS)
+ ifa.prefix = ipa_and(ifa.ip, ipa_mkmask(masklen));
+ else /* PtP iface */
+ {
+ ifa.flags |= IA_UNNUMBERED;
+ ifa.prefix = ifa.opposite = ifa.brd;
+ }
+
if (new)
ifa_update(&ifa);
else
@@ -593,27 +599,27 @@ krt_sysctl_scan(struct proto *p, pool *pool, byte **buf, size_t *bl, int cmd)
mib[4] = cmd;
mib[5] = 0;
- if( sysctl(mib, 6 , NULL , &needed, NULL, 0) < 0)
+ if (sysctl(mib, 6 , NULL , &needed, NULL, 0) < 0)
{
die("RT scan...");
}
obl = *bl;
- while(needed > *bl) *bl *= 2;
- while(needed < (*bl/2)) *bl /= 2;
+ while (needed > *bl) *bl *= 2;
+ while (needed < (*bl/2)) *bl /= 2;
- if( (obl!=*bl) || !*buf)
+ if ((obl!=*bl) || !*buf)
{
- if(*buf) mb_free(*buf);
- if( (*buf = mb_alloc(pool, *bl)) == NULL ) die("RT scan buf alloc");
+ if (*buf) mb_free(*buf);
+ if ((*buf = mb_alloc(pool, *bl)) == NULL) die("RT scan buf alloc");
}
on = needed;
- if( sysctl(mib, 6 , *buf, &needed, NULL, 0) < 0)
+ if (sysctl(mib, 6 , *buf, &needed, NULL, 0) < 0)
{
- if(on != needed) return; /* The buffer size changed since last sysctl */
+ if (on != needed) return; /* The buffer size changed since last sysctl */
die("RT scan 2");
}
@@ -624,22 +630,23 @@ krt_sysctl_scan(struct proto *p, pool *pool, byte **buf, size_t *bl, int cmd)
}
}
+static byte *krt_buffer = NULL;
+static byte *kif_buffer = NULL;
+static size_t krt_buflen = 32768;
+static size_t kif_buflen = 4096;
+
void
krt_scan_fire(struct krt_proto *p)
{
- static byte *buf = NULL;
- static size_t bl = 32768;
- krt_sysctl_scan((struct proto *)p , p->krt_pool, &buf, &bl, NET_RT_DUMP);
+ krt_sysctl_scan((struct proto *)p, p->krt_pool, &krt_buffer, &krt_buflen, NET_RT_DUMP);
}
void
krt_if_scan(struct kif_proto *p)
{
- static byte *buf = NULL;
- static size_t bl = 4096;
struct proto *P = (struct proto *)p;
if_start_update();
- krt_sysctl_scan(P, P->pool, &buf, &bl, NET_RT_IFLIST);
+ krt_sysctl_scan(P, P->pool, &kif_buffer, &kif_buflen, NET_RT_IFLIST);
if_end_update();
}
@@ -652,7 +659,9 @@ krt_set_construct(struct krt_config *c UNUSED)
void
krt_set_shutdown(struct krt_proto *x UNUSED, int last UNUSED)
{
-}
+ mb_free(krt_buffer);
+ krt_buffer = NULL;
+}
void
krt_if_io_init(void)
@@ -672,5 +681,7 @@ krt_if_start(struct kif_proto *p UNUSED)
void
krt_if_shutdown(struct kif_proto *p UNUSED)
{
+ mb_free(kif_buffer);
+ kif_buffer = NULL;
}
diff --git a/sysdep/cf/bsd-v6.h b/sysdep/cf/bsd-v6.h
index f3aefeb4..66985abf 100644
--- a/sysdep/cf/bsd-v6.h
+++ b/sysdep/cf/bsd-v6.h
@@ -9,7 +9,7 @@
#define IPV6
#define CONFIG_AUTO_ROUTES
-#undef CONFIG_SELF_CONSCIOUS
+#define CONFIG_SELF_CONSCIOUS
#undef CONFIG_MULTIPLE_TABLES
#undef CONFIG_UNIX_IFACE
diff --git a/sysdep/cf/bsd.h b/sysdep/cf/bsd.h
index 72b24720..acd1b58b 100644
--- a/sysdep/cf/bsd.h
+++ b/sysdep/cf/bsd.h
@@ -7,7 +7,7 @@
*/
#define CONFIG_AUTO_ROUTES
-#undef CONFIG_SELF_CONSCIOUS
+#define CONFIG_SELF_CONSCIOUS
#undef CONFIG_MULTIPLE_TABLES
#undef CONFIG_UNIX_IFACE
diff --git a/sysdep/linux/netlink/netlink.c b/sysdep/linux/netlink/netlink.c
index f45fe159..b59b32f3 100644
--- a/sysdep/linux/netlink/netlink.c
+++ b/sysdep/linux/netlink/netlink.c
@@ -52,7 +52,6 @@ struct nl_sock
static struct nl_sock nl_scan = {.fd = -1}; /* Netlink socket for synchronous scan */
static struct nl_sock nl_req = {.fd = -1}; /* Netlink socket for requests */
-
static void
nl_open_sock(struct nl_sock *nl)
{
@@ -555,23 +554,7 @@ krt_set_notify(struct krt_proto *p, net *n UNUSED, rte *new, rte *old)
nl_send_route(p, new, 1);
}
-static struct iface *
-krt_temp_iface(struct krt_proto *p, unsigned index)
-{
- struct iface *i, *j;
-
- WALK_LIST(i, p->scan.temp_ifs)
- if (i->index == index)
- return i;
- i = mb_allocz(p->p.pool, sizeof(struct iface));
- if (j = if_find_by_index(index))
- strcpy(i->name, j->name);
- else
- strcpy(i->name, "?");
- i->index = index;
- add_tail(&p->scan.temp_ifs, &i->n);
- return i;
-}
+#define SKIP(ARG...) do { DBG("KRT: Ignoring route - " ARG); return; } while(0)
static void
nl_parse_route(struct nlmsghdr *h, int scan)
@@ -599,31 +582,7 @@ nl_parse_route(struct nlmsghdr *h, int scan)
#endif
(a[RTA_GATEWAY] && RTA_PAYLOAD(a[RTA_GATEWAY]) != sizeof(ip_addr)))
{
- log(L_ERR "nl_parse_route: Malformed message received");
- return;
- }
-
- p = nl_table_map[i->rtm_table]; /* Do we know this table? */
- if (!p)
- return;
-
-#ifdef IPV6
- if (a[RTA_IIF])
- {
- DBG("KRT: Ignoring route with IIF set\n");
- return;
- }
-#else
- if (i->rtm_tos != 0) /* We don't support TOS */
- {
- DBG("KRT: Ignoring route with TOS %02x\n", i->rtm_tos);
- return;
- }
-#endif
-
- if (scan && !new)
- {
- DBG("KRT: Ignoring route deletion\n");
+ log(L_ERR "KRT: Malformed message received");
return;
}
@@ -634,33 +593,57 @@ nl_parse_route(struct nlmsghdr *h, int scan)
}
else
dst = IPA_NONE;
+
if (a[RTA_OIF])
memcpy(&oif, RTA_DATA(a[RTA_OIF]), sizeof(oif));
else
oif = ~0;
- DBG("Got %I/%d, type=%d, oif=%d, table=%d, prid=%d, proto=%s\n", dst, i->rtm_dst_len, i->rtm_type, oif, i->rtm_table, i->rtm_protocol, p->p.name);
+ DBG("KRT: Got %I/%d, type=%d, oif=%d, table=%d, prid=%d, proto=%s\n", dst, i->rtm_dst_len, i->rtm_type, oif, i->rtm_table, i->rtm_protocol, p->p.name);
+
+ p = nl_table_map[i->rtm_table]; /* Do we know this table? */
+ if (!p)
+ SKIP("unknown table %d", i->rtm_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);
+ if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
+ SKIP("strange class/scope\n");
+
+ // ignore rtm_scope, it is not a real scope
+ // if (i->rtm_scope != RT_SCOPE_UNIVERSE)
+ // SKIP("scope %u\n", i->rtm_scope);
switch (i->rtm_protocol)
{
+ case RTPROT_UNSPEC:
+ SKIP("proto unspec\n");
+
case RTPROT_REDIRECT:
src = KRT_SRC_REDIRECT;
break;
+
case RTPROT_KERNEL:
- DBG("Route originated in kernel, ignoring\n");
+ src = KRT_SRC_KERNEL;
return;
+
case RTPROT_BIRD:
-#ifdef IPV6
- case RTPROT_BOOT:
- /* Current Linux kernels don't remember rtm_protocol for IPv6 routes and supply RTPROT_BOOT instead */
-#endif
if (!scan)
- {
- DBG("Echo of our own route, ignoring\n");
- return;
- }
+ SKIP("echo\n");
src = KRT_SRC_BIRD;
break;
+
+ case RTPROT_BOOT:
default:
src = KRT_SRC_ALIEN;
}
@@ -679,52 +662,48 @@ nl_parse_route(struct nlmsghdr *h, int scan)
switch (i->rtm_type)
{
case RTN_UNICAST:
- if (oif == ~0U)
+ ra.iface = if_find_by_index(oif);
+ if (!ra.iface)
{
- log(L_ERR "KRT: Mysterious route with no OIF (%I/%d)", net->n.prefix, net->n.pxlen);
+ log(L_ERR "KRT: Received route %I/%d with unknown ifindex %u",
+ net->n.prefix, net->n.pxlen, oif);
return;
}
+
if (a[RTA_GATEWAY])
{
- struct iface *ifa = if_find_by_index(oif);
neighbor *ng;
ra.dest = RTD_ROUTER;
memcpy(&ra.gw, RTA_DATA(a[RTA_GATEWAY]), sizeof(ra.gw));
ipa_ntoh(ra.gw);
- if (i->rtm_flags & RTNH_F_ONLINK)
- {
- /* route with 'onlink' attribute */
- ra.iface = if_find_by_index(oif);
- if (ra.iface == NULL)
- {
- log(L_WARN "Kernel told us to use unknown interface %u for %I/%d",
- oif, net->n.prefix, net->n.pxlen);
- return;
- }
- }
- else
+ ng = neigh_find2(&p->p, &ra.gw, ra.iface,
+ (i->rtm_flags & RTNH_F_ONLINK) ? NEF_ONLINK : 0);
+ if (!ng || (ng->scope == SCOPE_HOST))
{
- ng = neigh_find2(&p->p, &ra.gw, ifa, 0);
- if (ng && ng->scope)
- {
- if (ng->iface != ifa)
- log(L_WARN "KRT: Route with unexpected iface for %I/%d", net->n.prefix, net->n.pxlen);
- ra.iface = ng->iface;
- }
- else
- {
- log(L_WARN "Kernel told us to use non-neighbor %I for %I/%d", ra.gw, net->n.prefix, net->n.pxlen);
- return;
- }
-
+ log(L_ERR "KRT: Received route %I/%d with strange next-hop %I",
+ net->n.prefix, net->n.pxlen, ra.gw);
+ return;
}
}
else
{
ra.dest = RTD_DEVICE;
- ra.iface = krt_temp_iface(p, oif);
+
+ /*
+ * In Linux IPv6, 'native' device routes have proto
+ * RTPROT_BOOT and not RTPROT_KERNEL (which they have in
+ * IPv4 and which is expected). We cannot distinguish
+ * 'native' and user defined device routes, so we ignore all
+ * such device routes and for consistency, we have the same
+ * behavior in IPv4. Anyway, users should use RTPROT_STATIC
+ * for their 'alien' routes.
+ */
+
+ if (i->rtm_protocol == RTPROT_BOOT)
+ src = KRT_SRC_KERNEL;
}
+
break;
case RTN_BLACKHOLE:
ra.dest = RTD_BLACKHOLE;
@@ -737,13 +716,7 @@ nl_parse_route(struct nlmsghdr *h, int scan)
break;
/* FIXME: What about RTN_THROW? */
default:
- DBG("KRT: Ignoring route with type=%d\n", i->rtm_type);
- return;
- }
-
- if (i->rtm_scope != RT_SCOPE_UNIVERSE)
- {
- DBG("KRT: Ignoring route with scope=%d\n", i->rtm_scope);
+ SKIP("type %d\n", i->rtm_type);
return;
}
diff --git a/sysdep/linux/sysio.h b/sysdep/linux/sysio.h
index 07f2cb15..94be002f 100644
--- a/sysdep/linux/sysio.h
+++ b/sysdep/linux/sysio.h
@@ -101,7 +101,7 @@ struct ip_mreqn
#define fill_mreq_ifa fill_mreq
#define fill_mreq_grp fill_mreq
-static inline fill_mreq(struct ip_mreqn *m, struct iface *ifa, ip_addr maddr)
+static inline void fill_mreq(struct ip_mreqn *m, struct iface *ifa, ip_addr maddr)
{
bzero(m, sizeof(*m));
m->imr_ifindex = ifa->index;
diff --git a/sysdep/unix/config.Y b/sysdep/unix/config.Y
index 8c2b6903..ac5be7e2 100644
--- a/sysdep/unix/config.Y
+++ b/sysdep/unix/config.Y
@@ -107,7 +107,7 @@ CF_CLI(CONFIGURE SOFT, cfg_name, [\"<file>\"], [[Reload configuration and ignore
{ cmd_reconfig($3, RECONFIG_SOFT); } ;
CF_CLI(DOWN,,, [[Shut the daemon down]])
-{ cli_msg(7, "Shutdown requested"); order_shutdown(); } ;
+{ cmd_shutdown(); } ;
cfg_name:
/* empty */ { $$ = NULL; }
diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c
index 316244d7..c7527c97 100644
--- a/sysdep/unix/io.c
+++ b/sysdep/unix/io.c
@@ -70,7 +70,8 @@ static struct resclass rf_class = {
"FILE",
sizeof(struct rfile),
rf_free,
- rf_dump
+ rf_dump,
+ NULL
};
void *
@@ -195,7 +196,8 @@ static struct resclass tm_class = {
"Timer",
sizeof(timer),
tm_free,
- tm_dump
+ tm_dump,
+ NULL
};
/**
@@ -564,7 +566,8 @@ static struct resclass sk_class = {
"Socket",
sizeof(sock),
sk_free,
- sk_dump
+ sk_dump,
+ NULL
};
/**
@@ -640,7 +643,7 @@ fill_in_sockaddr(sockaddr *sa, ip_addr a, unsigned port)
}
static inline void
-fill_in_sockifa(sockaddr *sa, struct iface *ifa)
+fill_in_sockifa(sockaddr *sa UNUSED, struct iface *ifa UNUSED)
{
}
@@ -660,7 +663,6 @@ get_sockaddr(struct sockaddr_in *sa, ip_addr *a, unsigned *port, int check)
static char *
sk_set_ttl_int(sock *s)
{
- int one = 1;
#ifdef IPV6
if (setsockopt(s->fd, SOL_IPV6, IPV6_UNICAST_HOPS, &s->ttl, sizeof(s->ttl)) < 0)
return "IPV6_UNICAST_HOPS";
@@ -668,6 +670,7 @@ sk_set_ttl_int(sock *s)
if (setsockopt(s->fd, SOL_IP, IP_TTL, &s->ttl, sizeof(s->ttl)) < 0)
return "IP_TTL";
#ifdef CONFIG_UNIX_DONTROUTE
+ int one = 1;
if (s->ttl == 1 && setsockopt(s->fd, SOL_SOCKET, SO_DONTROUTE, &one, sizeof(one)) < 0)
return "SO_DONTROUTE";
#endif
@@ -1012,7 +1015,6 @@ sk_passive_connected(sock *s, struct sockaddr *sa, int al, int type)
}
else if (errno != EINTR && errno != EAGAIN)
{
- log(L_ERR "accept: %m");
s->err_hook(s, errno);
}
return 0;
@@ -1602,7 +1604,6 @@ io_loop(void)
{
sock *s = current_sock;
int e;
- int steps;
if ((s->type < SK_MAGIC) && FD_ISSET(s->fd, &rd) && s->rx_hook)
{
diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c
index 488447b7..c8887b72 100644
--- a/sysdep/unix/krt.c
+++ b/sysdep/unix/krt.c
@@ -139,15 +139,6 @@ kif_shutdown(struct proto *P)
krt_if_shutdown(p);
kif_proto = NULL;
- if_start_update(); /* Remove all interfaces */
- if_end_update();
- /*
- * FIXME: Is it really a good idea? It causes routes to be flushed,
- * but at the same time it avoids sending of these deletions to the kernel,
- * because krt thinks the kernel itself has already removed the route
- * when downing the interface. Sad.
- */
-
return PS_DOWN;
}
@@ -558,32 +549,30 @@ krt_got_route(struct krt_proto *p, rte *e)
rte *old;
net *net = e->net;
int verdict;
-#ifdef KRT_ALLOW_LEARN
- int src = e->u.krt.src;
-#endif
-#ifdef CONFIG_AUTO_ROUTES
- if (e->attrs->dest == RTD_DEVICE)
+#ifdef KRT_ALLOW_LEARN
+ switch (e->u.krt.src)
{
- /* It's a device route. Probably a kernel-generated one. */
+ case KRT_SRC_KERNEL:
verdict = KRF_IGNORE;
goto sentenced;
- }
-#endif
-#ifdef KRT_ALLOW_LEARN
- if (src == KRT_SRC_ALIEN)
- {
+ case KRT_SRC_REDIRECT:
+ verdict = KRF_DELETE;
+ goto sentenced;
+
+ case KRT_SRC_ALIEN:
if (KRT_CF->learn)
krt_learn_scan(p, e);
else
{
- krt_trace_in_rl(&rl_alien_ignored, p, e, "alien route, ignored");
+ krt_trace_in_rl(&rl_alien_ignored, p, e, "[alien] ignored");
rte_free(e);
}
return;
}
#endif
+ /* The rest is for KRT_SRC_BIRD (or KRT_SRC_UNKNOWN) */
if (net->n.flags & KRF_VERDICT_MASK)
{
@@ -605,7 +594,7 @@ krt_got_route(struct krt_proto *p, rte *e)
else
verdict = KRF_DELETE;
-sentenced:
+ sentenced:
krt_trace_in(p, e, ((char *[]) { "?", "seen", "will be updated", "will be removed", "ignored" }) [verdict]);
net->n.flags = (net->n.flags & ~KRF_VERDICT_MASK) | verdict;
if (verdict == KRF_UPDATE || verdict == KRF_DELETE)
@@ -680,19 +669,24 @@ krt_prune(struct krt_proto *p)
}
void
-krt_got_route_async(struct krt_proto *p, rte *e, int new UNUSED)
+krt_got_route_async(struct krt_proto *p, rte *e, int new)
{
net *net = e->net;
- int src = e->u.krt.src;
- switch (src)
+ switch (e->u.krt.src)
{
case KRT_SRC_BIRD:
ASSERT(0); /* Should be filtered by the back end */
+
case KRT_SRC_REDIRECT:
- DBG("It's a redirect, kill him! Kill! Kill!\n");
- krt_set_notify(p, net, NULL, e);
+ if (new)
+ {
+ krt_trace_in(p, e, "[redirect] deleting");
+ krt_set_notify(p, net, NULL, e);
+ }
+ /* If !new, it is probably echo of our deletion */
break;
+
#ifdef KRT_ALLOW_LEARN
case KRT_SRC_ALIEN:
if (KRT_CF->learn)
@@ -742,7 +736,8 @@ krt_scan(timer *t UNUSED)
*/
static void
-krt_notify(struct proto *P, net *net, rte *new, rte *old, struct ea_list *attrs UNUSED)
+krt_notify(struct proto *P, struct rtable *table UNUSED, net *net,
+ rte *new, rte *old, struct ea_list *attrs UNUSED)
{
struct krt_proto *p = (struct krt_proto *) P;
@@ -877,7 +872,6 @@ krt_init(struct proto_config *c)
p->p.accept_ra_types = RA_OPTIMAL;
p->p.rt_notify = krt_notify;
- p->p.min_scope = SCOPE_HOST;
return &p->p;
}
diff --git a/sysdep/unix/krt.h b/sysdep/unix/krt.h
index 607e6993..1d9e1448 100644
--- a/sysdep/unix/krt.h
+++ b/sysdep/unix/krt.h
@@ -83,6 +83,7 @@ void krt_got_route_async(struct krt_proto *p, struct rte *e, int new);
#define KRT_SRC_BIRD 0 /* Our route (not passed in async mode) */
#define KRT_SRC_REDIRECT 1 /* Redirect route, delete it */
#define KRT_SRC_ALIEN 2 /* Route installed by someone else */
+#define KRT_SRC_KERNEL 3 /* Kernel routes, are ignored by krt syncer */
extern struct protocol proto_unix_iface;
diff --git a/sysdep/unix/log.c b/sysdep/unix/log.c
index f227549c..3d3b4337 100644
--- a/sysdep/unix/log.c
+++ b/sysdep/unix/log.c
@@ -19,6 +19,7 @@
#include <stdlib.h>
#include <stdarg.h>
#include <time.h>
+#include <unistd.h>
#include "nest/bird.h"
#include "nest/cli.h"
diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c
index 7a1ef286..2245692c 100644
--- a/sysdep/unix/main.c
+++ b/sysdep/unix/main.c
@@ -141,6 +141,9 @@ cmd_reconfig(char *name, int type)
{
struct config *conf;
+ if (cli_access_restricted())
+ return;
+
if (!name)
name = config_name;
cli_msg(-2, "Reading configuration from %s", name);
@@ -304,6 +307,16 @@ cli_init_unix(void)
*/
void
+cmd_shutdown(void)
+{
+ if (cli_access_restricted())
+ return;
+
+ cli_msg(7, "Shutdown requested");
+ order_shutdown();
+}
+
+void
async_shutdown(void)
{
DBG("Shutting down...\n");
diff --git a/sysdep/unix/unix.h b/sysdep/unix/unix.h
index 83f61af9..0b179e00 100644
--- a/sysdep/unix/unix.h
+++ b/sysdep/unix/unix.h
@@ -9,6 +9,8 @@
#ifndef _BIRD_UNIX_H_
#define _BIRD_UNIX_H_
+#include <sys/socket.h>
+
struct pool;
/* main.c */
@@ -17,6 +19,7 @@ void async_config(void);
void async_dump(void);
void async_shutdown(void);
void cmd_reconfig(char *name, int type);
+void cmd_shutdown(void);
/* io.c */
@@ -28,10 +31,12 @@ volatile int async_shutdown_flag;
#define BIRD_PF PF_INET6
#define BIRD_AF AF_INET6
typedef struct sockaddr_in6 sockaddr;
+static inline int sa_family_check(sockaddr *sa) { return sa->sin6_family == AF_INET6; }
#else
#define BIRD_PF PF_INET
#define BIRD_AF AF_INET
typedef struct sockaddr_in sockaddr;
+static inline int sa_family_check(sockaddr *sa) { return sa->sin_family == AF_INET; }
#endif
#ifndef SUN_LEN