);
}
+static int
+rt_to_af(int rt)
+{
+ if (rt == RT_IPV4)
+ return AF_INET;
+ else if (rt == RT_IPV6)
+ return AF_INET6;
+
+ /* RT_IP (0) maps to 0 (every AF) */
+
+ return 0;
+}
+
+
#define ROUNDUP(a) \
((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
rta *a = e->attrs;
static int msg_seq;
struct iface *j, *i = a->iface;
- int l;
+ int af = 0, l;
struct ks_msg msg;
char *body = (char *)msg.buf;
- sockaddr gate, mask, dst;
+ struct sockaddr_in6 gate, mask, dst;
ip_addr gw;
DBG("krt-sock: send %F via %I\n", &net->n, a->gw);
gw = a->gw;
-#ifdef IPV6
- /* Embed interface ID to link-local address */
- if (ipa_has_link_scope(gw))
- _I0(gw) = 0xfe800000 | (i->index & 0x0000ffff);
-#endif
+ switch (net->n.addr_type)
+ {
+ case RT_IPV4:
+ af = AF_INET;
+ dst.sin6_family = mask.sin6_family = gate.sin6_family = af;
+ sockaddr_fill((struct sockaddr *)&dst, *FPREFIX_IP(&net->n), NULL, 0);
+ sockaddr_fill((struct sockaddr *)&mask, ipa_mkmask(net->n.pxlen), NULL, 0);
+ sockaddr_fill((struct sockaddr *)&gate, gw, NULL, 0);
+
+ if (net->n.pxlen == MAX_PREFIX_LENGTH)
+ msg.rtm.rtm_flags |= RTF_HOST;
+ else
+ msg.rtm.rtm_addrs |= RTA_NETMASK;
+ break;
+
+ case RT_IPV6:
+ af = AF_INET6;
- fill_in_sockaddr(&dst, net->n.prefix, NULL, 0);
- fill_in_sockaddr(&mask, ipa_mkmask(net->n.pxlen), NULL, 0);
- fill_in_sockaddr(&gate, gw, NULL, 0);
- /* XXXX from patch
- if (net->n.addr_type == RT_IP)
- {
- fill_in_sockaddr(&dst, *FPREFIX_IP(&net->n), 0);
- fill_in_sockaddr(&mask, ipa_mkmask(net->n.pxlen), 0);
-
- if (net->n.pxlen == MAX_PREFIX_LENGTH)
- msg.rtm.rtm_flags |= RTF_HOST;
- else
- msg.rtm.rtm_addrs |= RTA_NETMASK;
- }
- */
-
-
+ /* Embed interface ID to link-local address */
+ if (ipa_is_link_local(gw))
+ _I0(gw) = 0xfe800000 | (i->index & 0x0000ffff);
+
+ dst.sin6_family = mask.sin6_family = gate.sin6_family = af;
+ sockaddr_fill((struct sockaddr *)&dst, *FPREFIX_IP(&net->n), NULL, 0);
+ sockaddr_fill((struct sockaddr *)&mask, ipa_mkmask(net->n.pxlen), NULL, 0);
+ sockaddr_fill((struct sockaddr *)&gate, gw, NULL, 0);
+
+ if (net->n.pxlen == MAX_PREFIX_LENGTH)
+ msg.rtm.rtm_flags |= RTF_HOST;
+ else
+ msg.rtm.rtm_addrs |= RTA_NETMASK;
+ break;
+
+ default:
+ log(L_ERR "Unsupported address family: %F", FPREFIX_IP(&net->n));
+ return -1;
+ }
switch (a->dest)
{
msg.rtm.rtm_flags |= RTF_CLONING;
#endif
+ // XXXX: find proper IPv4 / IPv6 address ?
if(!i->addr) {
- log(L_ERR "KRT: interface %s has no IP addess", i->name);
+ log(L_ERR "KRT: interface %s has no IP address", i->name);
return -1;
}
- fill_in_sockaddr(&gate, i->addr->ip, NULL, 0);
+ sockaddr_fill((struct sockaddr *)&gate, i->addr->ip, NULL, 0);
msg.rtm.rtm_addrs |= RTA_GATEWAY;
}
break;
{
rte *e;
net *net;
- sockaddr dst, gate, mask;
+ struct sockaddr_in6 dst, gate, mask;
ip_addr idst, igate, imask;
void *body = (char *)msg->buf;
int new = (msg->rtm.rtm_type == RTM_ADD);
- char *errmsg = "KRT: Invalid route received";
int flags = msg->rtm.rtm_flags;
int addrs = msg->rtm.rtm_addrs;
- int src;
+ int af, pxlen, src;
byte src2;
+ char *errmsg = "KRT: Invalid route received";
if (!(flags & RTF_UP) && scan)
SKIP("not up in scan\n");
GETADDR(&gate, RTA_GATEWAY);
GETADDR(&mask, RTA_NETMASK);
- if (sa_family_check(&dst))
- get_sockaddr(&dst, &idst, NULL, NULL, 0);
- else
- SKIP("invalid DST");
+ af = dst.sin6_family;
+
+ /* XXX: AF_MPLS */
+
+ switch (af)
+ {
+ case AF_INET:
+ /* Silently discard */
+ if (p->addr_type != RT_IPV4)
+ return;
+ break;
+
+ case AF_INET6:
+ /* Silently discard */
+ if (p->addr_type != RT_IPV6)
+ return;
+ break;
+
+ default:
+ SKIP("Invalid DST");
+ }
+
+ sockaddr_read((struct sockaddr *)&dst, &idst, NULL, NULL, 1);
/* We will check later whether we have valid gateway addr */
- if (sa_family_check(&gate))
- get_sockaddr(&gate, &igate, NULL, NULL, 0);
+ if (gate.sin6_family == af)
+ sockaddr_read((struct sockaddr *)&gate, &igate, NULL, NULL, 0);
else
igate = IPA_NONE;
/* 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, NULL, 0);
+ mask.sin6_family = dst.sin6_family;
+
+ sockaddr_read((struct sockaddr *)&mask, &imask, NULL, NULL, 1);
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_mklen(imask);
+ if (af == AF_INET6)
+ pxlen = (flags & RTF_HOST) ? MAX_PREFIX_LENGTH : ip6_masklen(&imask);
+ else
+ pxlen = (flags & RTF_HOST) ? MAX_PREFIX_LENGTH :
+ (ip4_masklen(ipa_to_ip4(imask)) + 96); // XXXX: Hack
+
if (pxlen < 0)
{ log(L_ERR "%s (%I) - netmask %I", errmsg, idst, imask); return; }
a.dest = RTD_ROUTER;
a.gw = igate;
-#ifdef IPV6
- /* Clean up embedded interface ID returned in link-local address */
- if (ipa_has_link_scope(a.gw))
- _I0(a.gw) = 0xfe800000;
-#endif
+ if (af == AF_INET6)
+ {
+ /* Clean up embedded interface ID returned in link-local address */
+ if (ipa_is_link_local(a.gw))
+ _I0(a.gw) = 0xfe800000;
+ }
ng = neigh_find2(&p->p, &a.gw, a.iface, 0);
if (!ng || (ng->scope == SCOPE_HOST))
{
struct ifa_msghdr *ifam = (struct ifa_msghdr *)&msg->rtm;
void *body = (void *)(ifam + 1);
- sockaddr addr, mask, brd;
+ struct sockaddr_in6 addr, mask, brd;
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 ipv4, scope, masklen = -1, maxlen;
int new = (ifam->ifam_type == RTM_NEWADDR);
/* Strange messages with zero (invalid) ifindex appear on OpenBSD */
GETADDR (&null, RTA_AUTHOR);
GETADDR (&brd, RTA_BRD);
- /* Some other family address */
- if (!sa_family_check(&addr))
+ /* Basic family check */
+ if (addr.sin6_family != AF_INET && addr.sin6_family != AF_INET6)
return;
- get_sockaddr(&addr, &iaddr, NULL, NULL, 0);
- get_sockaddr(&mask, &imask, NULL, NULL, 0);
- get_sockaddr(&brd, &ibrd, NULL, NULL, 0);
+ ipv4 = (addr.sin6_family == AF_INET) ? 1 : 0;
- if ((masklen = ipa_mklen(imask)) < 0)
+ /*
+ * Work around (Free?)BSD bug with netmask
+ * family not being filled in IPv6 case.
+ * FreeBSD fix: r250815.
+ */
+ if (addr.sin6_family == AF_INET6 && mask.sin6_family == 0)
+ mask.sin6_family = AF_INET6;
+
+ sockaddr_read((struct sockaddr *)&addr, &iaddr, NULL, NULL, 0);
+ sockaddr_read((struct sockaddr *)&mask, &imask, NULL, NULL, 0);
+ sockaddr_read((struct sockaddr *)&brd, &ibrd, NULL, NULL, 0);
+
+ masklen = ipv4 ? (ip4_masklen(ipa_to_ip4(imask)) + 96) : ip6_masklen(&imask); // XXXX: Hack
+ if (masklen < 0)
{
log("Invalid masklen");
return;
}
+ // log("got %I/%I (%d)", iaddr, imask, masklen);
+
bzero(&ifa, sizeof(ifa));
ifa.iface = iface;
}
ifa.scope = scope & IADDR_SCOPE_MASK;
-#ifdef IPV6
/* Clean up embedded interface ID returned in link-local address */
- if (ipa_has_link_scope(ifa.ip))
+ if (scope & SCOPE_LINK)
_I0(ifa.ip) = 0xfe800000;
-#endif
-#ifdef IPV6
- /* Why not the same check also for IPv4? */
- if ((iface->flags & IF_MULTIACCESS) || (masklen != BITS_PER_IP_ADDRESS))
-#else
- if (iface->flags & IF_MULTIACCESS)
-#endif
+ // maxlen = ipv4 ? BITS_PER_IP_ADDRESS4 : BITS_PER_IP_ADDRESS6;
+ maxlen = BITS_PER_IP_ADDRESS; // XXXX: Hack
+
+ if ((iface->flags & IF_MULTIACCESS) || (masklen != maxlen))
{
ifa.prefix = ipa_and(ifa.ip, ipa_mkmask(masklen));
- if (masklen == BITS_PER_IP_ADDRESS)
+ if (masklen == maxlen)
ifa.flags |= IA_HOST;
- if (masklen == (BITS_PER_IP_ADDRESS - 1))
+ if (masklen == (maxlen - 1))
ifa.opposite = ipa_opposite_m1(ifa.ip);
-#ifndef IPV6
- if (masklen == (BITS_PER_IP_ADDRESS - 2))
+ if (ipv4 && masklen == (maxlen - 2))
ifa.opposite = ipa_opposite_m2(ifa.ip);
-#endif
}
else /* PtP iface */
{
}
static void
-krt_sysctl_scan(struct proto *p, pool *pool, byte **buf, size_t *bl, int cmd)
+krt_sysctl_scan(struct proto *p, pool *pool, byte **buf, size_t *bl, int cmd, int af)
{
byte *next;
int mib[6];
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
- mib[3] = BIRD_PF;
+ mib[3] = af;
mib[4] = cmd;
mib[5] = 0;
void
krt_do_scan(struct krt_proto *p)
{
- krt_sysctl_scan((struct proto *)p, p->krt_pool, &krt_buffer, &krt_buflen, NET_RT_DUMP);
+ krt_sysctl_scan((struct proto *)p, p->krt_pool, &krt_buffer, &krt_buflen,
+ NET_RT_DUMP, rt_to_af(p->addr_type));
}
void
{
struct proto *P = (struct proto *)p;
if_start_update();
- krt_sysctl_scan(P, P->pool, &kif_buffer, &kif_buflen, NET_RT_IFLIST);
+ krt_sysctl_scan(P, P->pool, &kif_buffer, &kif_buflen, NET_RT_IFLIST, 0);
if_end_update();
}
krt_buffer = NULL;
}
+static u32 tables;
+
+void
+krt_sys_preconfig(struct config *c UNUSED)
+{
+ tables = 0;
+}
+
+void
+krt_sys_postconfig(struct krt_config *x)
+{
+ u32 id = x->c.table->addr_type;
+
+ if (tables & (1 << id))
+ cf_error("Multiple kernel protocols defined for AF %d", id);
+ tables |= (1 << id);
+}
+
void
kif_sys_start(struct kif_proto *p UNUSED)
#ifdef __DragonFly__
#define TCP_MD5SIG TCP_SIGNATURE_ENABLE
#endif
-#ifdef IPV6
-
-static inline void
-set_inaddr(struct in6_addr * ia, ip_addr a)
-{
- ipa_hton(a);
- memcpy(ia, &a, sizeof(a));
-}
-
-static inline void
-get_inaddr(ip_addr *a, struct in6_addr *ia)
-{
- memcpy(a, ia, sizeof(*a));
- ipa_ntoh(*a);
-}
static inline char *
-sysio_bind_to_iface(sock *s)
+sk_bind_to_iface(sock *s)
{
/* Unfortunately not available */
return NULL;
}
-#else
-
#include <net/if.h>
#include <net/if_dl.h>
-static inline void
-set_inaddr(struct in_addr * ia, ip_addr a)
-{
- ipa_hton(a);
- memcpy(&ia->s_addr, &a, sizeof(a));
-}
-
-static inline void
-get_inaddr(ip_addr *a, struct in_addr *ia)
-{
- memcpy(a, &ia->s_addr, sizeof(*a));
- ipa_ntoh(*a);
-}
-
-
/* BSD Multicast handling for IPv4 */
static inline char *
-sysio_setup_multicast(sock *s)
+sk_setup_multicast4(sock *s)
{
struct in_addr m;
u8 zero = 0;
return "IP_MULTICAST_TTL";
/* This defines where should we send _outgoing_ multicasts */
- set_inaddr(&m, s->iface->addr->ip);
+ ipa_put_in4(&m, s->iface->addr->ip);
if (setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_IF, &m, sizeof(m)) < 0)
return "IP_MULTICAST_IF";
static inline char *
-sysio_join_group(sock *s, ip_addr maddr)
+sk_join_group4(sock *s, ip_addr maddr)
{
struct ip_mreq mreq;
bzero(&mreq, sizeof(mreq));
- set_inaddr(&mreq.imr_interface, s->iface->addr->ip);
- set_inaddr(&mreq.imr_multiaddr, maddr);
+ ipa_put_in4(&mreq.imr_interface, s->iface->addr->ip);
+ ipa_put_in4(&mreq.imr_multiaddr, maddr);
/* And this one sets interface for _receiving_ multicasts from */
if (setsockopt(s->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
}
static inline char *
-sysio_leave_group(sock *s, ip_addr maddr)
+sk_leave_group4(sock *s, ip_addr maddr)
{
struct ip_mreq mreq;
bzero(&mreq, sizeof(mreq));
- set_inaddr(&mreq.imr_interface, s->iface->addr->ip);
- set_inaddr(&mreq.imr_multiaddr, maddr);
+ ipa_put_in4(&mreq.imr_interface, s->iface->addr->ip);
+ ipa_put_in4(&mreq.imr_multiaddr, maddr);
/* And this one sets interface for _receiving_ multicasts from */
if (setsockopt(s->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
#define CMSG_TX_SPACE CMSG_SPACE(sizeof(struct in_addr))
static char *
-sysio_register_cmsgs(sock *s)
+sk_request_pktinfo4(sock *s)
{
int ok = 1;
if (s->flags & SKF_LADDR_RX)
}
static void
-sysio_process_rx_cmsgs(sock *s, struct msghdr *msg)
+sk_process_rx_cmsg4(sock *s, struct cmsghdr *cm)
{
- struct cmsghdr *cm;
-
- if (!(s->flags & SKF_LADDR_RX))
- return;
-
- s->laddr = IPA_NONE;
- s->lifindex = 0;
-
- for (cm = CMSG_FIRSTHDR(msg); cm != NULL; cm = CMSG_NXTHDR(msg, cm))
+ if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_RECVDSTADDR)
{
- if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_RECVDSTADDR)
- {
- struct in_addr *ra = (struct in_addr *) CMSG_DATA(cm);
- get_inaddr(&s->laddr, ra);
- }
+ struct in_addr *ra = (struct in_addr *) CMSG_DATA(cm);
+ s->laddr = ipa_get_in4(ra);
+ }
- if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_RECVIF)
- {
- struct sockaddr_dl *ri = (struct sockaddr_dl *) CMSG_DATA(cm);
- s->lifindex = ri->sdl_index;
- }
+ if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_RECVIF)
+ {
+ struct sockaddr_dl *ri = (struct sockaddr_dl *) CMSG_DATA(cm);
+ s->lifindex = ri->sdl_index;
}
// log(L_WARN "RX %I %d", s->laddr, s->lifindex);
}
*/
-#endif
-
#include <netinet/tcp.h>
#ifndef TCP_KEYLEN_MAX
*/
static int
-sk_set_md5_auth_int(sock *s, sockaddr *sa, char *passwd)
+sk_set_md5_auth_int(sock *s, struct sockaddr *sa, int sa_len, char *passwd)
{
int enable = 0;
if (passwd)
}
-#ifndef IPV6
-
#ifdef IP_MINTTL
-static int
+static inline char *
sk_set_min_ttl4(sock *s, int ttl)
{
if (setsockopt(s->fd, IPPROTO_IP, IP_MINTTL, &ttl, sizeof(ttl)) < 0)
- {
- if (errno == ENOPROTOOPT)
- log(L_ERR "Kernel does not support IPv4 TTL security");
- else
- log(L_ERR "sk_set_min_ttl4: setsockopt: %m");
+ return "IP_MINTTL";
- return -1;
- }
-
- return 0;
+ return NULL;
}
#else /* no IP_MINTTL */
-static int
+static inline char *
sk_set_min_ttl4(sock *s, int ttl)
{
- log(L_ERR "IPv4 TTL security not supported");
- return -1;
+ errno = ENOPROTOOPT;
+ return "IP_MINTTL";
}
#endif
-#else /* IPv6 */
-
-static int
+static inline char *
sk_set_min_ttl6(sock *s, int ttl)
{
- log(L_ERR "IPv6 TTL security not supported");
- return -1;
+ errno = ENOPROTOOPT;
+ return "IP_MINTTL";
}
-#endif
-