add management part of address selection policy described in

RFC3484.

Obtained from:	KAME
This commit is contained in:
ume 2003-10-30 15:29:17 +00:00
parent 3b328d67f3
commit 9dab5c9bc0
5 changed files with 227 additions and 0 deletions

View File

@ -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);

View File

@ -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))

View File

@ -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);
}

View File

@ -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_ */

View File

@ -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