From b1a1fabac70201e9b05aeb9fd6af703f0fbffdb4 Mon Sep 17 00:00:00 2001 From: Ondrej Filip Date: Mon, 31 May 2004 13:25:00 +0000 Subject: [PATCH] *BSD port added. (Tested on FreeBSD and NetBSD) --- sysdep/autoconf.h.in | 10 + sysdep/bsd/Modules | 6 + sysdep/bsd/krt-iface.h | 17 + sysdep/bsd/krt-scan.c | 137 ++++++++ sysdep/bsd/krt-scan.h | 21 ++ sysdep/bsd/krt-set.h | 17 + sysdep/bsd/krt-sock.c | 703 ++++++++++++++++++++++++++++++++++++++++ sysdep/bsd/krt-sock.h | 47 +++ sysdep/bsd/sysio.h | 83 +++++ sysdep/cf/bsd-v6.h | 24 ++ sysdep/cf/bsd.h | 22 ++ sysdep/unix/io.c | 45 ++- sysdep/unix/krt-iface.c | 54 +-- sysdep/unix/krt-set.c | 9 +- sysdep/unix/main.c | 2 +- sysdep/unix/unix.h | 2 +- 16 files changed, 1145 insertions(+), 54 deletions(-) create mode 100644 sysdep/bsd/Modules create mode 100644 sysdep/bsd/krt-iface.h create mode 100644 sysdep/bsd/krt-scan.c create mode 100644 sysdep/bsd/krt-scan.h create mode 100644 sysdep/bsd/krt-set.h create mode 100644 sysdep/bsd/krt-sock.c create mode 100644 sysdep/bsd/krt-sock.h create mode 100644 sysdep/bsd/sysio.h create mode 100644 sysdep/cf/bsd-v6.h create mode 100644 sysdep/cf/bsd.h diff --git a/sysdep/autoconf.h.in b/sysdep/autoconf.h.in index ca86ff43..2827ff49 100644 --- a/sysdep/autoconf.h.in +++ b/sysdep/autoconf.h.in @@ -41,5 +41,15 @@ /* We have and syslog() */ #undef HAVE_SYSLOG +/* We have */ +#undef HAVE_ALLOCA_H + /* Are we using dmalloc? */ #undef HAVE_LIBDMALLOC + +/* Readline stuff */ +#undef HAVE_RL_CRLF +#undef HAVE_RL_DING + +/* struct sockaddr_in(6) */ +#undef HAVE_SIN_LEN diff --git a/sysdep/bsd/Modules b/sysdep/bsd/Modules new file mode 100644 index 00000000..84abffdb --- /dev/null +++ b/sysdep/bsd/Modules @@ -0,0 +1,6 @@ +krt-scan.h +krt-iface.h +sysio.h +krt-set.h +krt-sock.c +krt-sock.h diff --git a/sysdep/bsd/krt-iface.h b/sysdep/bsd/krt-iface.h new file mode 100644 index 00000000..aa2eb857 --- /dev/null +++ b/sysdep/bsd/krt-iface.h @@ -0,0 +1,17 @@ +/* + * BIRD -- Unix Kernel Socket Route Syncer -- Dummy Include File + * + * (c) 2004 Ondrej Filip + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#ifndef _BIRD_KRT_IFACE_H_ +#define _BIRD_KRT_IFACE_H_ + +/* + * We don't have split iface/scan/set parts. See krt-sock.h. + */ +static inline int kif_params_same(struct krt_if_params *old, struct krt_if_params *new) { return 1; } + +#endif diff --git a/sysdep/bsd/krt-scan.c b/sysdep/bsd/krt-scan.c new file mode 100644 index 00000000..e68df318 --- /dev/null +++ b/sysdep/bsd/krt-scan.c @@ -0,0 +1,137 @@ +/* + * BIRD -- *BSD Table Scanning + * + * (c) 2004 Ondrej Filip + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef LOCAL_DEBUG +#define LOCAL_DEBUG + +#include "nest/bird.h" +#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 "lib/string.h" + +static int krt_scan_fd = -1; + +struct iface * +krt_temp_iface(struct krt_proto *p, char *name) +{ + struct iface *i; + + WALK_LIST(i, p->scan.temp_ifs) + if (!strcmp(i->name, name)) + return i; + i = mb_allocz(p->p.pool, sizeof(struct iface)); + strcpy(i->name, name); + add_tail(&p->scan.temp_ifs, &i->n); + return i; +} + + +void +krt_scan_construct(struct krt_config *c) +{ +} + +void +krt_scan_preconfig(struct config *c) +{ +} + +void +krt_scan_postconfig(struct krt_config *c) +{ +} + +void +krt_scan_start(struct krt_proto *x, int first) +{ + init_list(&x->scan.temp_ifs); +} + +void +krt_scan_shutdown(struct krt_proto *x, int last) +{ +} + +void +krt_sysctl_scan(struct proto *p, pool *pool, byte **buf, int *bl, int cmd) +{ + byte *next; + int obl, needed, mib[6], on; + struct ks_msg *m; + + mib[0] = CTL_NET; + mib[1] = PF_ROUTE; + mib[2] = 0; + mib[3] = BIRD_PF; + mib[4] = cmd; + mib[5] = 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; + + if( (obl!=*bl) || !*buf) + { + 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(on != needed) return; /* The buffer size changed since last sysctl */ + die("RT scan 2"); + } + + for (next = *buf; next < (*buf + needed); next += m->rtm.rtm_msglen) + { + m = (struct ks_msg *)next; + krt_read_msg(p, m, 1); + } +} + +void +krt_scan_fire(struct krt_proto *p) +{ + static byte *buf = NULL; + static int bl = 32768; + krt_sysctl_scan((struct proto *)p , p->krt_pool, &buf, &bl, NET_RT_DUMP); +} + +void +krt_if_scan(struct kif_proto *p) +{ + static byte *buf = NULL; + static int bl = 4096; + struct proto *P = (struct proto *)p; + if_start_update(); + krt_sysctl_scan(P, P->pool, &buf, &bl, NET_RT_IFLIST); + if_end_update(); +} + diff --git a/sysdep/bsd/krt-scan.h b/sysdep/bsd/krt-scan.h new file mode 100644 index 00000000..e06f57f3 --- /dev/null +++ b/sysdep/bsd/krt-scan.h @@ -0,0 +1,21 @@ +/* + * BIRD -- *BSD Kernel Route Syncer -- Scanning + * + * (c) 2004 Ondrej Filip + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#ifndef _BIRD_KRT_SCAN_H_ +#define _BIRD_KRT_SCAN_H_ + +struct krt_scan_params { +}; + +struct krt_scan_status { + list temp_ifs; /* Temporary interfaces */ +}; + +static inline int krt_scan_params_same(struct krt_scan_params *o, struct krt_scan_params *n) { return 1; } + +#endif diff --git a/sysdep/bsd/krt-set.h b/sysdep/bsd/krt-set.h new file mode 100644 index 00000000..b5453d4b --- /dev/null +++ b/sysdep/bsd/krt-set.h @@ -0,0 +1,17 @@ +/* + * BIRD -- Unix Kernel Socket Route Syncer -- Dummy Include File + * + * (c) 2004 Ondrej Filip + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#ifndef _BIRD_KRT_SET_H_ +#define _BIRD_KRT_SET_H_ + +/* + * We don't have split iface/scan/set parts. See krt-sock.h. + */ +#include "lib/krt-sock.h" + +#endif diff --git a/sysdep/bsd/krt-sock.c b/sysdep/bsd/krt-sock.c new file mode 100644 index 00000000..e1d4ff6a --- /dev/null +++ b/sysdep/bsd/krt-sock.c @@ -0,0 +1,703 @@ +/* + * BIRD -- Unix Routing Table Syncing + * + * (c) 2004 Ondrej Filip + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef LOCAL_DEBUG + +#include "nest/bird.h" +#include "nest/iface.h" +#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 "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) + +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) +{ + rta *a = e->attrs; + +#ifdef CONFIG_AUTO_ROUTES + if (a->source == RTS_DEVICE) + return 0; +#endif + return + a->cast == RTC_UNICAST && + (a->dest == RTD_ROUTER + || a->dest == RTD_DEVICE +#ifdef RTF_REJECT + || a->dest == RTD_UNREACHABLE +#endif +#ifdef RTF_BLACKHOLE + || a->dest == RTD_BLACKHOLE /* FIXME Prohibited? */ +#endif + ); +} + +#define ROUNDUP(a) \ + ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) + +#define NEXTADDR(w, u) \ + if (msg.rtm.rtm_addrs & (w)) {\ + l = ROUNDUP(((struct sockaddr *)&(u))->sa_len);\ + memmove(body, &(u), l); body += l;} + +static void +krt_sock_send(int cmd, rte *e, char *name) +{ + net *net = e->net; + rta *a = e->attrs; + static int msg_seq; + struct iface *j, *i = a->iface; + int l; + struct ks_msg msg; + char *body = (char *)msg.buf; + sockaddr gate, mask, dst; + + log("KRT sock send: %I/%d via %I", 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); + fill_in_sockaddr(&gate, a->gw, 0); + + memset (&msg, 0, sizeof (struct rt_msghdr)); + msg.rtm.rtm_version = RTM_VERSION; + msg.rtm.rtm_type = cmd; + msg.rtm.rtm_seq = msg_seq++; + msg.rtm.rtm_addrs = RTA_DST; + msg.rtm.rtm_flags = RTF_UP; + + if (net->n.pxlen == HOST_MASK) + { + msg.rtm.rtm_flags |= RTF_HOST; + } + else + { + msg.rtm.rtm_addrs |= RTA_NETMASK; + } + +#ifdef RTF_REJECT + if(a->dest == RTD_UNREACHABLE) + msg.rtm.rtm_flags |= RTF_REJECT; +#endif +#ifdef RTF_BLACKHOLE + if(a->dest == RTD_BLACKHOLE) + msg.rtm.rtm_flags |= RTF_BLACKHOLE; +#endif + + /* This is really very nasty, but I'm not able + * to add "(reject|blackhole)" route without + * gateway set + */ + if(!i) + { + i = HEAD(iface_list); + + WALK_LIST(j, iface_list) + { + if (j->flags & IF_LOOPBACK) + { + i = j; + break; + } + } + } + + switch (a->dest) + { + case RTD_ROUTER: + msg.rtm.rtm_flags |= RTF_GATEWAY; + msg.rtm.rtm_addrs |= RTA_GATEWAY; + break; +#ifdef RTF_REJECT + case RTD_UNREACHABLE: +#endif +#ifdef RTF_BLACKHOLE + case RTD_BLACKHOLE: +#endif + case RTD_DEVICE: + if(i) + { + if (cmd == RTM_ADD && (i->flags & IF_MULTIACCESS) != IF_MULTIACCESS) /* PTP */ + msg.rtm.rtm_flags |= RTF_CLONING; + + if(!i->addr) { + log(L_ERR "KIF: interface \"%s\" has no IP addess", i->name); + return; + } + + fill_in_sockaddr(&gate, i->addr->ip, 0); + msg.rtm.rtm_addrs |= RTA_GATEWAY; + } + else + { + bug("krt-sock: interface route %I/%d without interface", net->n.prefix, net->n.pxlen); + } + break; + default: + bug("krt-sock: unknown flags, but not filtered"); + } + + if(i) msg.rtm.rtm_index = i->index; + + NEXTADDR(RTA_DST, dst); + NEXTADDR(RTA_GATEWAY, gate); + NEXTADDR(RTA_NETMASK, mask); + + l = body - (char *)&msg; + 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); + } +} + +void +krt_set_notify(struct krt_proto *p, net *net, rte *new, rte *old) +{ + if (old) + { + DBG("krt_remove_route(%I/%d)\n", net->n.prefix, net->n.pxlen); + krt_sock_send(RTM_DELETE, old, "RTM_DELETE"); + + } + if (new) + { + DBG("krt_add_route(%I/%d)\n", net->n.prefix, net->n.pxlen); + krt_sock_send(RTM_ADD, new, "RTM_ADD"); + } +} + +void +krt_set_start(struct krt_proto *x, int first) +{ + sock *sk_rt; + static int ks_open_tried = 0; + + if (ks_open_tried) + return; + + ks_open_tried = 1; + + DBG("KRT: Opening kernel socket\n"); + + if( (rt_sock = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC)) < 0) + die("Cannot open kernel socket for routes"); + + sk_rt = sk_new(krt_pool); + sk_rt->type = SK_MAGIC; + sk_rt->rx_hook = krt_set_hook; + sk_rt->fd = rt_sock; + sk_rt->data = x; + if (sk_open(sk_rt)) + bug("Krt_sock: sk_rt_open failed"); +} + +static int +krt_set_hook(sock *sk, int size) +{ + int l; + struct ks_msg msg; + + l = read(sk->fd, (char *)&msg, sizeof(msg)); + + krt_read_msg((struct proto *)sk->data, &msg, 0); + return 0; +} + +void +krt_read_rt(struct ks_msg *msg, struct krt_proto *p, int scan) +{ + sockaddr gate, mask, dst; + rta a; + rte *e; + net *net; + u32 oif; + ip_addr idst, igate, imask; + void *body = (char *)msg->buf; + int new = (msg->rtm.rtm_type == RTM_ADD); + int src; + 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_HOST) + masklen = HOST_MASK; + + if(!CHECK_FAMILY(body)) return; + + if(msg->rtm.rtm_flags & RTF_LLINFO) return; /* ARPs etc. */ + +#define GETADDR(p, F) \ + memset(p, 0, 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); + + idst = IPA_NONE; + igate = IPA_NONE; + imask = IPA_NONE; + + get_sockaddr(&dst, &idst, NULL, 0); + if(CHECK_FAMILY(&gate)) get_sockaddr(&gate, &igate, NULL, 0); + get_sockaddr(&mask, &imask, NULL, 0); + + if (masklen < 0) masklen = ipa_mklen(imask); + + if (flags & (RTF_DYNAMIC | RTF_MODIFIED)) + { + log(L_WARN "krt: Ignoring redirect to %I/%d via %I", idst, masklen, igate); + return; + } + + if (masklen < 0) + { + log(L_WARN "krt: Got invalid route from kernel!"); + return; + } + + net = net_get(p->p.table, idst, masklen); + + memset(&a, 0, sizeof(a)); + + a.proto = &p->p; + a.source = RTS_INHERIT; + a.scope = SCOPE_UNIVERSE; + a.cast = RTC_UNICAST; + a.flags = a.aflags = 0; + a.from = IPA_NONE; + a.gw = IPA_NONE; + 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); + + 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); + } + +#ifdef RTF_REJECT + if(flags & RTF_REJECT) { + a.dest = RTD_UNREACHABLE; + a.gw = IPA_NONE; + } +#endif + +#ifdef RTF_BLACKHOLE + if(flags & RTF_BLACKHOLE) { + a.dest = RTD_BLACKHOLE; + a.gw = IPA_NONE; + } +#endif + + if (a.dest == RTD_NONE) + { + log(L_WARN "Kernel reporting unknown route type to %I/%d", net->n.prefix, net->n.pxlen); + return; + } + + src = KRT_SRC_UNKNOWN; /* FIXME */ + + + + 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; + e->u.krt.metric = 0; + + if (scan) + krt_got_route(p, e); + else + krt_got_route_async(p, e, new); +} + +void +krt_read_ifinfo(struct ks_msg *msg) +{ + struct if_msghdr *ifm = (struct if_msghdr *)&msg->rtm; + void *body = (void *)(ifm + 1); + struct sockaddr_dl *dl = NULL; + unsigned int i; + struct iface *iface = NULL, f; + char *ifname = "(none)"; + int fl = ifm->ifm_flags; + + for(i = 1; i!=0; i <<= 1) + { + if((i & ifm->ifm_addrs) && (i == RTA_IFP)) + { + if( i == RTA_IFP) + { + dl = (struct sockaddr_dl *)body; + break; + } + body += ROUNDUP(((struct sockaddr *)&(body))->sa_len);\ + } + } + + if(dl && (dl->sdl_family != AF_LINK)) + { + log("Ignoring strange IFINFO"); + return; + } + + if(dl) ifname = dl->sdl_data; + + iface = if_find_by_index(ifm->ifm_index); + + if(!iface) + { + /* New interface */ + if(!dl) return; /* No interface name, ignoring */ + DBG("New interface \"%s\" found", ifname); + bzero(&f, sizeof(f)); + f.index = ifm->ifm_index; + strncpy(f.name, ifname, sizeof(f.name) -1); + } + else + { + memcpy(&f, iface, sizeof(struct iface)); + } + + f.mtu = ifm->ifm_data.ifi_mtu; + f.flags = 0; + + if (fl & IFF_UP) + { + //f.flags |= IF_UP; /* FIXME */ + f.flags |= IF_LINK_UP; + } + if (fl & IFF_LOOPBACK) /* Loopback */ + f.flags |= IF_MULTIACCESS | IF_LOOPBACK | IF_IGNORE; + else if (fl & IFF_POINTOPOINT) /* PtP */ + f.flags |= IF_MULTICAST; + else if (fl & IFF_BROADCAST) /* Broadcast */ + f.flags |= IF_MULTIACCESS | IF_BROADCAST | IF_MULTICAST; + else + f.flags |= IF_MULTIACCESS; /* NBMA */ + + if((!iface) || memcmp(&f, iface, sizeof(struct iface))) + if_update(&f); /* Just if something happens */ +} + +void +krt_read_addr(struct ks_msg *msg) +{ + struct ifa_msghdr *ifam = (struct ifa_msghdr *)&msg->rtm; + void *body = (void *)(ifam + 1); + sockaddr addr, mask, brd; + unsigned int i; + struct iface *iface = NULL; + struct ifa ifa; + struct sockaddr null; + ip_addr iaddr, imask, ibrd; + int addrs = ifam->ifam_addrs; + int scope, masklen = -1; + int new = (ifam->ifam_type == RTM_NEWADDR); + int fl = ifam->ifam_flags; + + if(!(iface = if_find_by_index(ifam->ifam_index))) + { + log(L_ERR "KIF: Received address message for unknown interface %d", ifam->ifam_index); + return; + } + + GETADDR (&null, RTA_DST); + GETADDR (&null, RTA_GATEWAY); + GETADDR (&mask, RTA_NETMASK); + GETADDR (&null, RTA_GENMASK); + GETADDR (&null, RTA_IFP); + GETADDR (&addr, RTA_IFA); + GETADDR (&null, RTA_AUTHOR); + GETADDR (&brd, RTA_BRD); + + if(!CHECK_FAMILY(&addr)) return; /* Some other family address */ + + get_sockaddr(&addr, &iaddr, NULL, 0); + get_sockaddr(&mask, &imask, NULL, 0); + get_sockaddr(&brd, &ibrd, NULL, 0); + + if ((masklen = ipa_mklen(imask)) < 0) + { + log("Invalid masklen"); + return; + } + + memset(&ifa, 0, sizeof(ifa)); + + ifa.iface = iface; + + memcpy(&ifa.ip, &iaddr, sizeof(ip_addr)); + ifa.pxlen = masklen; + 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); + return; + } + ifa.scope = scope & IADDR_SCOPE_MASK; + + if (new) + ifa_update(&ifa); + else + ifa_delete(&ifa); +} + + +void +krt_read_msg(struct proto *p, struct ks_msg *msg, int scan) +{ + switch (msg->rtm.rtm_type) + { + case RTM_GET: + if(!scan) return; + case RTM_ADD: + case RTM_DELETE: + //log("KRT_ADD/DELETE"); + krt_read_rt(msg, (struct krt_proto *)p, scan); + break; + case RTM_IFINFO: + //log("KRT_IFINFO"); + krt_read_ifinfo(msg); + break; + case RTM_NEWADDR: + case RTM_DELADDR: + //log("KRT_NEWADDR/DELADDR"); + krt_read_addr(msg); + break; +#ifdef RTM_IFANNOUNCE + case RTM_IFANNOUNCE: + log("KRT_IFANNOUNCE"); + //ifan_read (&buf.ian.ifan); + break; +#endif /* RTM_IFANNOUNCE */ + default: + log("Unprocessed RTM_type: %d", msg->rtm.rtm_type); + break; + } +} + + +struct iface * +krt_temp_iface(struct krt_proto *p, char *name) +{ + struct iface *i; + + WALK_LIST(i, p->scan.temp_ifs) + if (!strcmp(i->name, name)) + return i; + i = mb_allocz(p->p.pool, sizeof(struct iface)); + strcpy(i->name, name); + add_tail(&p->scan.temp_ifs, &i->n); + return i; +} + + +void +krt_scan_construct(struct krt_config *c) +{ +} + +void +krt_scan_preconfig(struct config *c) +{ +} + +void +krt_scan_postconfig(struct krt_config *c) +{ +} + +void +krt_scan_start(struct krt_proto *x, int first) +{ + init_list(&x->scan.temp_ifs); +} + +void +krt_scan_shutdown(struct krt_proto *x, int last) +{ +} + +void +krt_sysctl_scan(struct proto *p, pool *pool, byte **buf, int *bl, int cmd) +{ + byte *next; + int obl, needed, mib[6], on; + struct ks_msg *m; + + mib[0] = CTL_NET; + mib[1] = PF_ROUTE; + mib[2] = 0; + mib[3] = BIRD_PF; + mib[4] = cmd; + mib[5] = 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; + + if( (obl!=*bl) || !*buf) + { + 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(on != needed) return; /* The buffer size changed since last sysctl */ + die("RT scan 2"); + } + + for (next = *buf; next < (*buf + needed); next += m->rtm.rtm_msglen) + { + m = (struct ks_msg *)next; + krt_read_msg(p, m, 1); + } +} + +void +krt_scan_fire(struct krt_proto *p) +{ + static byte *buf = NULL; + static int bl = 32768; + krt_sysctl_scan((struct proto *)p , p->krt_pool, &buf, &bl, NET_RT_DUMP); +} + +void +krt_if_scan(struct kif_proto *p) +{ + static byte *buf = NULL; + static int bl = 4096; + struct proto *P = (struct proto *)p; + if_start_update(); + krt_sysctl_scan(P, P->pool, &buf, &bl, NET_RT_IFLIST); + if_end_update(); +} + + +void +krt_set_construct(struct krt_config *c) +{ +} + +void +krt_set_shutdown(struct krt_proto *x, int last) +{ +} + +void +krt_if_io_init(void) +{ +} + +void +krt_if_construct(struct kif_config *c) +{ +} + +void +krt_if_start(struct kif_proto *p) +{ +} + +void +krt_if_shutdown(struct kif_proto *p) +{ +} + diff --git a/sysdep/bsd/krt-sock.h b/sysdep/bsd/krt-sock.h new file mode 100644 index 00000000..41ff9c5e --- /dev/null +++ b/sysdep/bsd/krt-sock.h @@ -0,0 +1,47 @@ +/* + * BIRD -- Unix Kernel Route Syncer -- Setting + * + * (c) 2004 Ondrej Filip + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#ifndef _BIRD_KRT_SOCK_H_ +#define _BIRD_KRT_SOCK_H_ + +#include +#include +#include "lib/socket.h" + +#ifndef RTAX_MAX +#define RTAX_MAX 8 +#endif + + +struct ks_msg +{ + struct rt_msghdr rtm; + struct sockaddr_storage buf[RTAX_MAX]; +}; + + + +extern int krt_set_sock; + +struct krt_set_params { +}; + +struct krt_set_status { +}; + +struct krt_if_params { +}; + +struct krt_if_status { +}; + +static int krt_set_hook(sock *sk, int size); +static inline int krt_set_params_same(struct krt_set_params *o, struct krt_set_params *n) { return 1; } +void krt_read_msg(struct proto *p, struct ks_msg *msg, int scan); + +#endif diff --git a/sysdep/bsd/sysio.h b/sysdep/bsd/sysio.h new file mode 100644 index 00000000..db69b97d --- /dev/null +++ b/sysdep/bsd/sysio.h @@ -0,0 +1,83 @@ +/* + * BIRD Internet Routing Daemon -- NetBSD Multicasting and Network Includes + * + * (c) 2004 Ondrej Filip + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#ifdef IPV6 + +static inline void +set_inaddr(struct in6_addr * ia, ip_addr a) +{ + ipa_hton(a); + memcpy(ia, &a, sizeof(a)); +} + +#else + +#include + +static inline void +set_inaddr(struct in_addr * ia, ip_addr a) +{ + ipa_hton(a); + memcpy(&ia->s_addr, &a, sizeof(a)); +} + +static inline char * +sysio_mcast_setup(sock * s) +{ + u8 zero = 0; + u8 one = 1; + + if (ipa_nonzero(s->daddr)) { + + if (setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_LOOP, &zero, sizeof(zero)) < 0) { + log("IP_MULTICAST_LOOP"); + return "IP_MULTICAST_LOOP"; + } + + if (setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_TTL, &one, sizeof(one)) < 0) { + log("IP_MULTICAST_TTL"); + return "IP_MULTICAST_TTL"; + } + } + return NULL; +} + + +static inline char * +sysio_mcast_join(sock * s) +{ + struct in_addr m; + struct ip_mreq mreq; + char *err; + + set_inaddr(&m, s->iface->addr->ip ); + + memset(&mreq, 0, sizeof(mreq)); + set_inaddr(&mreq.imr_interface, s->iface->addr->ip); + set_inaddr(&mreq.imr_multiaddr, s->daddr); + + /* And this one sets interface for _receiving_ multicasts from */ + if (ipa_nonzero(s->daddr) && setsockopt(s->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) { + log("IP_ADD_MEMBERSHIP"); + return "IP_ADD_MEMBERSHIP"; + } + + + /* This defines where should we send _outgoing_ multicasts */ + if (ipa_nonzero(s->daddr) && setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_IF, &m, sizeof(m)) < 0) { + log("IP_MULTICAST_IF"); + return "IP_MULTICAST_IF"; + } + + if (err = sysio_mcast_setup(s)) + return err; + + return NULL; +} + +#endif diff --git a/sysdep/cf/bsd-v6.h b/sysdep/cf/bsd-v6.h new file mode 100644 index 00000000..5f66e562 --- /dev/null +++ b/sysdep/cf/bsd-v6.h @@ -0,0 +1,24 @@ +/* + * Configuration for *BSD based systems (tested on FreeBSD and NetBSD) + * + * (c) 2004 Ondrej Filip + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#define IPV6 + +#define CONFIG_AUTO_ROUTES +#undef CONFIG_SELF_CONSCIOUS +#undef CONFIG_MULTIPLE_TABLES + +#undef CONFIG_UNIX_IFACE +#undef CONFIG_UNIX_SET + +#define CONFIG_ALL_MULTICAST +#define CONFIG_UNNUM_MULTICAST + +/* +Link: sysdep/unix +Link: sysdep/bsd + */ diff --git a/sysdep/cf/bsd.h b/sysdep/cf/bsd.h new file mode 100644 index 00000000..cfce773e --- /dev/null +++ b/sysdep/cf/bsd.h @@ -0,0 +1,22 @@ +/* + * Configuration for *BSD based systems (tested on FreeBSD and NetBSD) + * + * (c) 2004 Ondrej Filip + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#define CONFIG_AUTO_ROUTES +#undef CONFIG_SELF_CONSCIOUS +#undef CONFIG_MULTIPLE_TABLES + +#undef CONFIG_UNIX_IFACE +#undef CONFIG_UNIX_SET + +#define CONFIG_ALL_MULTICAST +#define CONFIG_UNNUM_MULTICAST + +/* +Link: sysdep/unix +Link: sysdep/bsd + */ diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index cec1c20a..f667801f 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -2,6 +2,7 @@ * BIRD Internet Routing Daemon -- Unix I/O * * (c) 1998--2000 Martin Mares + * (c) 2004 Ondrej Filip * * Can be freely distributed and used under the terms of the GNU GPL. */ @@ -29,6 +30,7 @@ #include "lib/unix.h" #include "lib/sysio.h" +#define LOCAL_DEBUG /* * Tracked Files */ @@ -399,6 +401,14 @@ tm_format_reltime(char *x, bird_clock_t t) #define SOL_IP IPPROTO_IP #endif +#ifndef SOL_IPV6 +#define SOL_IPV6 IPPROTO_IPV6 +#endif + +#ifndef IPV6_ADD_MEMBERSHIP +#define IPV6_ADD_MEMBERSHIP IP_ADD_MEMBERSHIP +#endif + static list sock_list; static void @@ -476,17 +486,21 @@ sk_new(pool *p) void fill_in_sockaddr(sockaddr *sa, ip_addr a, unsigned port) { + memset (sa, 0, sizeof (struct sockaddr_in6)); sa->sin6_family = AF_INET6; sa->sin6_port = htons(port); sa->sin6_flowinfo = 0; +#ifdef HAVE_SIN_LEN + sa->sin6_len = sizeof(struct sockaddr_in6); +#endif set_inaddr(&sa->sin6_addr, a); } void -get_sockaddr(sockaddr *sa, ip_addr *a, unsigned *port) +get_sockaddr(struct sockaddr_in6 *sa, ip_addr *a, unsigned *port, int check) { - if (sa->sin6_family != AF_INET6) - bug("get_sockaddr called for wrong address family"); + if (check && sa->sin6_family != AF_INET6) + bug("get_sockaddr called for wrong address family (%d)", sa->sin6_family); if (port) *port = ntohs(sa->sin6_port); memcpy(a, &sa->sin6_addr, sizeof(*a)); @@ -498,16 +512,20 @@ get_sockaddr(sockaddr *sa, ip_addr *a, unsigned *port) void fill_in_sockaddr(sockaddr *sa, ip_addr a, unsigned port) { + memset (sa, 0, sizeof (struct sockaddr_in)); sa->sin_family = AF_INET; sa->sin_port = htons(port); +#ifdef HAVE_SIN_LEN + sa->sin_len = sizeof(struct sockaddr_in); +#endif set_inaddr(&sa->sin_addr, a); } void -get_sockaddr(sockaddr *sa, ip_addr *a, unsigned *port) +get_sockaddr(struct sockaddr_in *sa, ip_addr *a, unsigned *port, int check) { - if (sa->sin_family != AF_INET) - bug("get_sockaddr called for wrong address family"); + if (check && sa->sin_family != AF_INET) + bug("get_sockaddr called for wrong address family (%d)", sa->sin_family); if (port) *port = ntohs(sa->sin_port); memcpy(a, &sa->sin_addr.s_addr, sizeof(*a)); @@ -536,8 +554,8 @@ sk_setup(sock *s) WARN("IP_TOS"); if (s->ttl >= 0 && setsockopt(fd, SOL_IP, IP_TTL, &s->ttl, sizeof(s->ttl)) < 0) ERR("IP_TTL"); - if (s->ttl == 1 && setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &one, sizeof(one)) < 0) - ERR("SO_DONTROUTE"); + //if (s->ttl == 1 && setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &one, sizeof(one)) < 0) + // ERR("SO_DONTROUTE"); #endif err = NULL; bad: @@ -578,7 +596,7 @@ sk_passive_connected(sock *s, struct sockaddr *sa, int al, int type) t->rbsize = s->rbsize; t->tbsize = s->tbsize; if (type == SK_TCP) - get_sockaddr((sockaddr *) sa, &t->daddr, &t->dport); + get_sockaddr((sockaddr *) sa, &t->daddr, &t->dport, 1); add_tail(&sock_list, &t->n); if (err = sk_setup(t)) { @@ -645,7 +663,9 @@ sk_open(sock *s) s->fd = fd; if (err = sk_setup(s)) + { goto bad; + } switch (type) { case SK_UDP: @@ -683,7 +703,7 @@ sk_open(sock *s) mreq.ipv6mr_ifindex = s->iface->index; #else mreq.ipv6mr_interface = s->iface->index; -#endif +#endif /* CONFIG_IPV6_GLIBC_20 */ if (setsockopt(fd, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) ERR("IPV6_ADD_MEMBERSHIP"); } @@ -692,7 +712,7 @@ sk_open(sock *s) ASSERT(s->iface && s->iface->addr); if (err = sysio_mcast_join(s)) goto bad; -#endif +#endif /* IPV6 */ break; } } @@ -842,6 +862,7 @@ sk_maybe_write(sock *s) if (s->tbuf == s->tpos) return 1; fill_in_sockaddr(&sa, s->faddr, s->fport); + e = sendto(s->fd, s->tbuf, s->tpos - s->tbuf, 0, (struct sockaddr *) &sa, sizeof(sa)); if (e < 0) { @@ -955,7 +976,7 @@ sk_read(sock *s) return 0; } s->rpos = s->rbuf + e; - get_sockaddr(&sa, &s->faddr, &s->fport); + get_sockaddr(&sa, &s->faddr, &s->fport, 1); s->rx_hook(s, e); return 1; } diff --git a/sysdep/unix/krt-iface.c b/sysdep/unix/krt-iface.c index ddd70e99..5cc78807 100644 --- a/sysdep/unix/krt-iface.c +++ b/sysdep/unix/krt-iface.c @@ -2,6 +2,7 @@ * BIRD -- Unix Interface Scanning and Syncing * * (c) 1998--2000 Martin Mares + * (c) 2004 Ondrej Filip * * Can be freely distributed and used under the terms of the GNU GPL. */ @@ -36,6 +37,7 @@ scan_ifs(struct ifreq *r, int cnt) unsigned fl; ip_addr netmask; int l, scope; + sockaddr *sa; if_start_update(); for (cnt /= sizeof(struct ifreq); cnt; cnt--, r++) @@ -43,7 +45,6 @@ scan_ifs(struct ifreq *r, int cnt) int sec = 0; bzero(&i, sizeof(i)); bzero(&a, sizeof(a)); - DBG("%s\n", r->ifr_name); if (colon = strchr(r->ifr_name, ':')) { /* It's an alias -- let's interpret it as a secondary interface address */ @@ -51,7 +52,10 @@ scan_ifs(struct ifreq *r, int cnt) *colon = 0; } strncpy(i.name, r->ifr_name, sizeof(i.name) - 1); - get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &a.ip, NULL); + + if(ioctl(if_scan_sock, SIOCGIFADDR,r)<0) continue; + + get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &a.ip, NULL, 1); if (ipa_nonzero(a.ip)) { l = ipa_classify(a.ip); @@ -83,11 +87,11 @@ scan_ifs(struct ifreq *r, int cnt) if (ioctl(if_scan_sock, SIOCGIFNETMASK, r) < 0) { err = "SIOCGIFNETMASK"; goto faulty; } - get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &netmask, NULL); + get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &netmask, NULL, 0); l = ipa_mklen(netmask); if (l < 0 || l == 31) { - log(L_ERR "%s: Invalid netmask", i.name); + log(L_ERR "%s: Invalid netmask (%x)", i.name, netmask); goto bad; } a.pxlen = l; @@ -97,7 +101,7 @@ scan_ifs(struct ifreq *r, int cnt) a.flags |= IA_UNNUMBERED; if (ioctl(if_scan_sock, SIOCGIFDSTADDR, r) < 0) { err = "SIOCGIFDSTADDR"; goto faulty; } - get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &a.opposite, NULL); + get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &a.opposite, NULL, 1); a.prefix = a.opposite; a.pxlen = BITS_PER_IP_ADDRESS; } @@ -188,40 +192,17 @@ krt_if_scan(struct kif_proto *p) for(;;) { - if (last_ifbuf_size) - { - struct ifreq *r = alloca(last_ifbuf_size); - ic.ifc_ifcu.ifcu_req = r; - ic.ifc_len = last_ifbuf_size; - res = ioctl(if_scan_sock, SIOCGIFCONF, &ic); - if (res < 0 && errno != EFAULT) - die("SIOCCGIFCONF: %m"); - if (res >= 0 && ic.ifc_len < last_ifbuf_size) - { - scan_ifs(r, ic.ifc_len); - break; - } - } -#if 0 - /* - * Linux 2.1 and higher supports this, but it's not needed since - * we prefer to use Netlink there anyway. - */ - ic.ifc_req = NULL; - ic.ifc_len = 999999999; - if (ioctl(if_scan_sock, SIOCGIFCONF, &ic) < 0) - die("SIOCIFCONF: %m"); - ic.ifc_len += sizeof(struct ifreq); - if (last_ifbuf_size < ic.ifc_len) - { - last_ifbuf_size = ic.ifc_len; - DBG("Increased ifconf buffer size to %d\n", last_ifbuf_size); - } -#else + ic.ifc_buf = alloca(last_ifbuf_size); + ic.ifc_len = last_ifbuf_size; + res = ioctl(if_scan_sock, SIOCGIFCONF, &ic); + if (res < 0 && errno != EFAULT) + die("SIOCCGIFCONF: %m"); + if (res >= 0 && ic.ifc_len <= last_ifbuf_size) + break; last_ifbuf_size *= 2; DBG("Increased ifconf buffer size to %d\n", last_ifbuf_size); -#endif } + scan_ifs(ic.ifc_req, ic.ifc_len); } void @@ -247,3 +228,4 @@ krt_if_io_init(void) if (if_scan_sock < 0) die("Cannot create scanning socket: %m"); } + diff --git a/sysdep/unix/krt-set.c b/sysdep/unix/krt-set.c index bd564486..67f32b89 100644 --- a/sysdep/unix/krt-set.c +++ b/sysdep/unix/krt-set.c @@ -13,6 +13,7 @@ #include #undef LOCAL_DEBUG +#define LOCAL_DEBUG #include "nest/bird.h" #include "nest/iface.h" @@ -36,7 +37,7 @@ krt_capable(rte *e) (a->dest == RTD_ROUTER || a->dest == RTD_DEVICE #ifdef RTF_REJECT - || a->dest == RTD_UNREACHABLE + || a->dest == RTD_UNREACHABLE /* FIXME Blackhole, prohibited?? */ #endif ); } @@ -45,12 +46,12 @@ static void krt_ioctl(int ioc, rte *e, char *name) { net *net = e->net; - struct rtentry re; + struct ortentry re; rta *a = e->attrs; bzero(&re, sizeof(re)); fill_in_sockaddr((struct sockaddr_in *) &re.rt_dst, net->n.prefix, 0); - fill_in_sockaddr((struct sockaddr_in *) &re.rt_genmask, ipa_mkmask(net->n.pxlen), 0); + //fill_in_sockaddr((struct sockaddr_in *) &re.rt_genmask, ipa_mkmask(net->n.pxlen), 0); re.rt_flags = RTF_UP; if (net->n.pxlen == 32) re.rt_flags |= RTF_HOST; @@ -61,7 +62,7 @@ krt_ioctl(int ioc, rte *e, char *name) re.rt_flags |= RTF_GATEWAY; break; case RTD_DEVICE: - re.rt_dev = a->iface->name; + //re.rt_dev = a->iface->name; break; #ifdef RTF_REJECT case RTD_UNREACHABLE: diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c index 2e10521b..e16eb699 100644 --- a/sysdep/unix/main.c +++ b/sysdep/unix/main.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include "nest/bird.h" #include "lib/lists.h" diff --git a/sysdep/unix/unix.h b/sysdep/unix/unix.h index da06345e..72b6ef56 100644 --- a/sysdep/unix/unix.h +++ b/sysdep/unix/unix.h @@ -43,7 +43,7 @@ struct birdsock; void io_init(void); void io_loop(void); void fill_in_sockaddr(sockaddr *sa, ip_addr a, unsigned port); -void get_sockaddr(sockaddr *sa, ip_addr *a, unsigned *port); +void get_sockaddr(sockaddr *sa, ip_addr *a, unsigned *port, int check); int sk_open_unix(struct birdsock *s, char *name); void *tracked_fopen(struct pool *, char *name, char *mode);