add management part of address selection policy described in
RFC3484. Obtained from: KAME
This commit is contained in:
parent
3b328d67f3
commit
9dab5c9bc0
@ -346,6 +346,14 @@ in6_control(so, cmd, data, ifp, td)
|
||||
return (mrt6_ioctl(cmd, data));
|
||||
}
|
||||
|
||||
switch(cmd) {
|
||||
case SIOCAADDRCTL_POLICY:
|
||||
case SIOCDADDRCTL_POLICY:
|
||||
if (!privileged)
|
||||
return (EPERM);
|
||||
return (in6_src_ioctl(cmd, data));
|
||||
}
|
||||
|
||||
if (ifp == NULL)
|
||||
return (EOPNOTSUPP);
|
||||
|
||||
|
@ -593,6 +593,8 @@ struct ip6_mtuinfo {
|
||||
#define IPV6CTL_AUTO_LINKLOCAL 35 /* automatic link-local addr assign */
|
||||
#define IPV6CTL_RIP6STATS 36 /* raw_ip6 stats */
|
||||
|
||||
#define IPV6CTL_ADDRCTLPOLICY 38 /* get/set address selection policy */
|
||||
|
||||
#define IPV6CTL_MAXFRAGS 41 /* max fragments */
|
||||
|
||||
/* New entries should be added here from current IPV6CTL_MAXID value. */
|
||||
@ -626,6 +628,7 @@ void in6_sin_2_v4mapsin6 __P((struct sockaddr_in *sin,
|
||||
struct sockaddr_in6 *sin6));
|
||||
void in6_sin6_2_sin_in_sock __P((struct sockaddr *nam));
|
||||
void in6_sin_2_v4mapsin6_in_sock __P((struct sockaddr **nam));
|
||||
extern void addrsel_policy_init __P((void));
|
||||
|
||||
#define satosin6(sa) ((struct sockaddr_in6 *)(sa))
|
||||
#define sin6tosa(sin6) ((struct sockaddr *)(sin6))
|
||||
|
@ -75,6 +75,8 @@
|
||||
#include <sys/protosw.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/socketvar.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
@ -97,6 +99,22 @@
|
||||
|
||||
#include <net/net_osdep.h>
|
||||
|
||||
static struct mtx addrsel_lock;
|
||||
#define ADDRSEL_LOCK_INIT() mtx_init(&addrsel_lock, "addrsel_lock", NULL, MTX_DEF)
|
||||
#define ADDRSEL_LOCK() mtx_lock(&addrsel_lock)
|
||||
#define ADDRSEL_UNLOCK() mtx_unlock(&addrsel_lock)
|
||||
#define ADDRSEL_LOCK_ASSERT() mtx_assert(&addrsel_lock, MA_OWNED)
|
||||
|
||||
#define ADDR_LABEL_NOTAPP (-1)
|
||||
struct in6_addrpolicy defaultaddrpolicy;
|
||||
|
||||
static void init_policy_queue __P((void));
|
||||
static int add_addrsel_policyent __P((struct in6_addrpolicy *));
|
||||
static int delete_addrsel_policyent __P((struct in6_addrpolicy *));
|
||||
static int walk_addrsel_policy __P((int (*)(struct in6_addrpolicy *, void *),
|
||||
void *));
|
||||
static int dump_addrsel_policyent __P((struct in6_addrpolicy *, void *));
|
||||
|
||||
/*
|
||||
* Return an IPv6 address, which is the most appropriate for a given
|
||||
* destination and user specified options.
|
||||
@ -528,3 +546,187 @@ in6_clearscope(addr)
|
||||
if (IN6_IS_SCOPE_LINKLOCAL(addr) || IN6_IS_ADDR_MC_INTFACELOCAL(addr))
|
||||
addr->s6_addr16[1] = 0;
|
||||
}
|
||||
|
||||
void
|
||||
addrsel_policy_init()
|
||||
{
|
||||
ADDRSEL_LOCK_INIT();
|
||||
|
||||
init_policy_queue();
|
||||
|
||||
/* initialize the "last resort" policy */
|
||||
bzero(&defaultaddrpolicy, sizeof(defaultaddrpolicy));
|
||||
defaultaddrpolicy.label = ADDR_LABEL_NOTAPP;
|
||||
}
|
||||
|
||||
/*
|
||||
* Subroutines to manage the address selection policy table via sysctl.
|
||||
*/
|
||||
struct walkarg {
|
||||
struct sysctl_req *w_req;
|
||||
};
|
||||
|
||||
static int in6_src_sysctl(SYSCTL_HANDLER_ARGS);
|
||||
SYSCTL_DECL(_net_inet6_ip6);
|
||||
SYSCTL_NODE(_net_inet6_ip6, IPV6CTL_ADDRCTLPOLICY, addrctlpolicy,
|
||||
CTLFLAG_RD, in6_src_sysctl, "");
|
||||
|
||||
static int
|
||||
in6_src_sysctl(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
struct walkarg w;
|
||||
|
||||
if (req->newptr)
|
||||
return EPERM;
|
||||
|
||||
bzero(&w, sizeof(w));
|
||||
w.w_req = req;
|
||||
|
||||
return (walk_addrsel_policy(dump_addrsel_policyent, &w));
|
||||
}
|
||||
|
||||
int
|
||||
in6_src_ioctl(cmd, data)
|
||||
u_long cmd;
|
||||
caddr_t data;
|
||||
{
|
||||
int i;
|
||||
struct in6_addrpolicy ent0;
|
||||
|
||||
if (cmd != SIOCAADDRCTL_POLICY && cmd != SIOCDADDRCTL_POLICY)
|
||||
return (EOPNOTSUPP); /* check for safety */
|
||||
|
||||
ent0 = *(struct in6_addrpolicy *)data;
|
||||
|
||||
if (ent0.label == ADDR_LABEL_NOTAPP)
|
||||
return (EINVAL);
|
||||
/* check if the prefix mask is consecutive. */
|
||||
if (in6_mask2len(&ent0.addrmask.sin6_addr, NULL) < 0)
|
||||
return (EINVAL);
|
||||
/* clear trailing garbages (if any) of the prefix address. */
|
||||
for (i = 0; i < 4; i++) {
|
||||
ent0.addr.sin6_addr.s6_addr32[i] &=
|
||||
ent0.addrmask.sin6_addr.s6_addr32[i];
|
||||
}
|
||||
ent0.use = 0;
|
||||
|
||||
switch (cmd) {
|
||||
case SIOCAADDRCTL_POLICY:
|
||||
return (add_addrsel_policyent(&ent0));
|
||||
case SIOCDADDRCTL_POLICY:
|
||||
return (delete_addrsel_policyent(&ent0));
|
||||
}
|
||||
|
||||
return (0); /* XXX: compromise compilers */
|
||||
}
|
||||
|
||||
/*
|
||||
* The followings are implementation of the policy table using a
|
||||
* simple tail queue.
|
||||
* XXX such details should be hidden.
|
||||
* XXX implementation using binary tree should be more efficient.
|
||||
*/
|
||||
struct addrsel_policyent {
|
||||
TAILQ_ENTRY(addrsel_policyent) ape_entry;
|
||||
struct in6_addrpolicy ape_policy;
|
||||
};
|
||||
|
||||
TAILQ_HEAD(addrsel_policyhead, addrsel_policyent);
|
||||
|
||||
struct addrsel_policyhead addrsel_policytab;
|
||||
|
||||
static void
|
||||
init_policy_queue()
|
||||
{
|
||||
TAILQ_INIT(&addrsel_policytab);
|
||||
}
|
||||
|
||||
static int
|
||||
add_addrsel_policyent(newpolicy)
|
||||
struct in6_addrpolicy *newpolicy;
|
||||
{
|
||||
struct addrsel_policyent *new, *pol;
|
||||
|
||||
ADDRSEL_LOCK();
|
||||
|
||||
/* duplication check */
|
||||
for (pol = TAILQ_FIRST(&addrsel_policytab); pol;
|
||||
pol = TAILQ_NEXT(pol, ape_entry)) {
|
||||
if (SA6_ARE_ADDR_EQUAL(&newpolicy->addr,
|
||||
&pol->ape_policy.addr) &&
|
||||
SA6_ARE_ADDR_EQUAL(&newpolicy->addrmask,
|
||||
&pol->ape_policy.addrmask)) {
|
||||
return (EEXIST); /* or override it? */
|
||||
}
|
||||
}
|
||||
|
||||
MALLOC(new, struct addrsel_policyent *, sizeof(*new), M_IFADDR,
|
||||
M_WAITOK);
|
||||
bzero(new, sizeof(*new));
|
||||
|
||||
/* XXX: should validate entry */
|
||||
new->ape_policy = *newpolicy;
|
||||
|
||||
TAILQ_INSERT_TAIL(&addrsel_policytab, new, ape_entry);
|
||||
ADDRSEL_UNLOCK();
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
delete_addrsel_policyent(key)
|
||||
struct in6_addrpolicy *key;
|
||||
{
|
||||
struct addrsel_policyent *pol;
|
||||
|
||||
ADDRSEL_LOCK();
|
||||
|
||||
/* search for the entry in the table */
|
||||
for (pol = TAILQ_FIRST(&addrsel_policytab); pol;
|
||||
pol = TAILQ_NEXT(pol, ape_entry)) {
|
||||
if (SA6_ARE_ADDR_EQUAL(&key->addr, &pol->ape_policy.addr) &&
|
||||
SA6_ARE_ADDR_EQUAL(&key->addrmask,
|
||||
&pol->ape_policy.addrmask)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pol == NULL)
|
||||
return (ESRCH);
|
||||
|
||||
TAILQ_REMOVE(&addrsel_policytab, pol, ape_entry);
|
||||
ADDRSEL_UNLOCK();
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
walk_addrsel_policy(callback, w)
|
||||
int (*callback) __P((struct in6_addrpolicy *, void *));
|
||||
void *w;
|
||||
{
|
||||
struct addrsel_policyent *pol;
|
||||
int error = 0;
|
||||
|
||||
ADDRSEL_LOCK();
|
||||
for (pol = TAILQ_FIRST(&addrsel_policytab); pol;
|
||||
pol = TAILQ_NEXT(pol, ape_entry)) {
|
||||
if ((error = (*callback)(&pol->ape_policy, w)) != 0)
|
||||
return (error);
|
||||
}
|
||||
ADDRSEL_UNLOCK();
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
dump_addrsel_policyent(pol, arg)
|
||||
struct in6_addrpolicy *pol;
|
||||
void *arg;
|
||||
{
|
||||
int error = 0;
|
||||
struct walkarg *w = arg;
|
||||
|
||||
error = SYSCTL_OUT(w->w_req, pol, sizeof(*pol));
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
@ -118,6 +118,15 @@ struct in6_ifaddr {
|
||||
struct nd_prefix *ia6_ndpr;
|
||||
};
|
||||
|
||||
/* control structure to manage address selection policy */
|
||||
struct in6_addrpolicy {
|
||||
struct sockaddr_in6 addr; /* prefix address */
|
||||
struct sockaddr_in6 addrmask; /* prefix mask */
|
||||
int preced; /* precedence */
|
||||
int label; /* matching label */
|
||||
u_quad_t use; /* statistics */
|
||||
};
|
||||
|
||||
/*
|
||||
* IPv6 interface statistics, as defined in RFC2465 Ipv6IfStatsEntry (p12).
|
||||
*/
|
||||
@ -432,6 +441,9 @@ struct in6_rrenumreq {
|
||||
#define SIOCGETMIFCNT_IN6 _IOWR('u', 107, \
|
||||
struct sioc_mif_req6) /* get pkt cnt per if */
|
||||
|
||||
#define SIOCAADDRCTL_POLICY _IOW('u', 108, struct in6_addrpolicy)
|
||||
#define SIOCDADDRCTL_POLICY _IOW('u', 109, struct in6_addrpolicy)
|
||||
|
||||
#define IN6_IFF_ANYCAST 0x01 /* anycast address */
|
||||
#define IN6_IFF_TENTATIVE 0x02 /* tentative address */
|
||||
#define IN6_IFF_DUPLICATED 0x04 /* DAD detected duplicate */
|
||||
@ -604,6 +616,7 @@ int in6_embedscope __P((struct in6_addr *, const struct sockaddr_in6 *,
|
||||
int in6_recoverscope __P((struct sockaddr_in6 *, const struct in6_addr *,
|
||||
struct ifnet *));
|
||||
void in6_clearscope __P((struct in6_addr *));
|
||||
int in6_src_ioctl __P((u_long, caddr_t));
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#endif /* _NETINET6_IN6_VAR_H_ */
|
||||
|
@ -198,6 +198,7 @@ ip6_init()
|
||||
mtx_init(&ip6intrq.ifq_mtx, "ip6_inq", NULL, MTX_DEF);
|
||||
netisr_register(NETISR_IPV6, ip6_input, &ip6intrq);
|
||||
scope6_init();
|
||||
addrsel_policy_init();
|
||||
nd6_init();
|
||||
frag6_init();
|
||||
#ifndef RANDOM_IP_ID
|
||||
|
Loading…
Reference in New Issue
Block a user