📄 in6_src.c
字号:
wild &= ~INPLOOKUP_WILDCARD6;
#endif
#endif
#if 0
t = in_pcblookup_bind(&tcbtable,
(struct in_addr *)&in6p->in6p_laddr.s6_addr32[3],
lport);
#else
t = NULL;
#endif
} else {
#ifdef HAVE_NRL_INPCB
#ifdef INPLOOKUP_WILDCARD4
wild &= ~INPLOOKUP_WILDCARD4;
#endif
/* XXX: ugly cast... */
t = in_pcblookup(head, (struct in_addr *)&zeroin6_addr,
0, (struct in_addr *)laddr,
lport, wild | INPLOOKUP_IPV6);
#else
t = in6_pcblookup(head, &zeroin6_addr, 0, laddr,
lport, wild);
#endif
}
if (t == 0)
break;
startover:
if (head->in6p_lport >= max)
head->in6p_lport = min;
else
head->in6p_lport++;
if (head->in6p_lport == last_port)
return (EADDRINUSE);
}
in6p->in6p_lport = lport;
return(0); /* success */
}
#ifdef HAVE_NRL_INPCB
#undef in6pcb
#undef in6p_socket
#undef in6p_lport
#undef in6p_head
#undef in6p_flags
#undef IN6PLOOKUP_WILDCARD
#endif
#endif /* !FreeBSD3 && !OpenBSD*/
#if (defined(__FreeBSD__) && __FreeBSD__ >= 3)
/*
* XXX: this is borrowed from in6_pcbbind(). If possible, we should
* share this function by all *bsd*...
*/
int
in6_pcbsetport(struct in6_addr *laddr, struct inpcb *inp, struct proc *p)
{
struct socket *so = inp->inp_socket;
u_int16_t lport = 0, first, last, *lastport;
int count, wild = 0;
struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
/* XXX: this is redundant when called from in6_pcbbind */
if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0)
wild = INPLOOKUP_WILDCARD;
inp->inp_flags |= INP_ANONPORT;
if (inp->inp_flags & INP_HIGHPORT) {
first = ipport_hifirstauto; /* sysctl */
last = ipport_hilastauto;
lastport = &pcbinfo->lasthi;
} else if (inp->inp_flags & INP_LOWPORT) {
first = ipport_lowfirstauto; /* 1023 */
last = ipport_lowlastauto; /* 600 */
lastport = &pcbinfo->lastlow;
} else {
first = ipport_firstauto; /* sysctl */
last = ipport_lastauto;
lastport = &pcbinfo->lastport;
}
/*
* Simple check to ensure all ports are not used up causing
* a deadlock here.
*
* We split the two cases (up and down) so that the direction
* is not being tested on each round of the loop.
*/
if (first > last) {
/*
* counting down
*/
count = first - last;
do {
if (count-- < 0) { /* completely used? */
/*
* Undo any address bind that may have
* occurred above.
*/
inp->in6p_laddr = in6addr_any;
return (EAGAIN);
}
--*lastport;
if (*lastport > first || *lastport < last)
*lastport = first;
lport = htons(*lastport);
} while (in6_pcblookup_local(pcbinfo,
&inp->in6p_laddr, lport, wild));
} else {
/*
* counting up
*/
count = last - first;
do {
if (count-- < 0) { /* completely used? */
/*
* Undo any address bind that may have
* occurred above.
*/
inp->in6p_laddr = in6addr_any;
return (EAGAIN);
}
++*lastport;
if (*lastport < first || *lastport > last)
*lastport = first;
lport = htons(*lastport);
} while (in6_pcblookup_local(pcbinfo,
&inp->in6p_laddr, lport, wild));
}
inp->inp_lport = lport;
if (in_pcbinshash(inp) != 0) {
inp->in6p_laddr = in6addr_any;
inp->inp_lport = 0;
return (EAGAIN);
}
return(0);
}
#endif
/*
* Generate kernel-internal form (scopeid embedded into s6_addr16[1]).
* If the address scope of is interface-local or link-local, embed the
* interface index in the address.
*
* This function should be nuked in the future, when we get rid of embedded
* scopeid thing.
*/
int
in6_embedscope(in6, sin6)
struct in6_addr *in6;
const struct sockaddr_in6 *sin6;
{
#ifdef SCOPEDROUTING
/*
* XXX: the SCOPEDROUTING code path is NOT expected to work at this
* moment (20011112). We added this just in case.
*/
return(0); /* do nothing */
#else
struct ifnet *ifp;
u_int32_t zoneid = sin6->sin6_scope_id;
*in6 = sin6->sin6_addr;
/*
* don't try to read sin6->sin6_addr beyond here, since the caller may
* ask us to overwrite existing sockaddr_in6
*/
if (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_INTFACELOCAL(in6)) {
/* KAME assumption: link id == interface id */
if (zoneid) {
if (if_index < zoneid)
return(ENXIO); /* XXX EINVAL? */
#if defined(__FreeBSD__) && __FreeBSD__ >= 5
ifp = ifnet_byindex(zoneid);
#else
ifp = ifindex2ifnet[zoneid];
#endif
if (ifp == NULL) /* XXX: this can happen for some OS */
return(ENXIO);
/* XXX assignment to 16bit from 32bit variable */
in6->s6_addr16[1] = htons(zoneid & 0xffff);
}
}
return 0;
#endif
}
/*
* generate standard sockaddr_in6 from embedded form.
* touches sin6_addr and sin6_scope_id only.
*
* this function should be nuked in the future, when we get rid of
* embedded scopeid thing.
*/
int
in6_recoverscope(sin6, in6, ifp)
struct sockaddr_in6 *sin6;
const struct in6_addr *in6;
struct ifnet *ifp;
{
u_int32_t zoneid;
sin6->sin6_addr = *in6;
/*
* don't try to read *in6 beyond here, since the caller may
* ask us to overwrite existing sockaddr_in6
*/
sin6->sin6_scope_id = 0;
if (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_INTFACELOCAL(in6)) {
/*
* KAME assumption: link id == interface id
*/
zoneid = ntohs(sin6->sin6_addr.s6_addr16[1]);
if (zoneid) {
/* sanity check */
if (zoneid < 0 || if_index < zoneid)
return ENXIO;
if (ifp && ifp->if_index != zoneid)
return ENXIO;
sin6->sin6_addr.s6_addr16[1] = 0;
sin6->sin6_scope_id = zoneid;
}
}
return 0;
}
/*
* just clear the embedded scope identifer.
* XXX: currently used for bsdi4 only as a supplement function.
*/
void
in6_clearscope(addr)
struct in6_addr *addr;
{
if (IN6_IS_SCOPE_LINKLOCAL(addr) || IN6_IS_ADDR_MC_INTFACELOCAL(addr))
addr->s6_addr16[1] = 0;
}
void
addrsel_policy_init()
{
init_policy_queue();
/* initialize the "last resort" policy */
bzero(&defaultaddrpolicy, sizeof(defaultaddrpolicy));
defaultaddrpolicy.label = ADDR_LABEL_NOTAPP;
}
static struct in6_addrpolicy *
lookup_addrsel_policy(key)
struct sockaddr_in6 *key;
{
struct in6_addrpolicy *match = NULL;
match = match_addrsel_policy(key);
if (match == NULL)
match = &defaultaddrpolicy;
else
match->use++;
return(match);
}
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;
/* 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);
return(0);
}
static int
delete_addrsel_policyent(key)
struct in6_addrpolicy *key;
{
struct addrsel_policyent *pol;
/* 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);
return(0);
}
void
_show_addrsel_policy(void)
{
struct addrsel_policyent *pol;
log(LOG_ADDR, "IPv6 address policy table\n");
for (pol = TAILQ_FIRST(&addrsel_policytab); pol;
pol = TAILQ_NEXT(pol, ape_entry)) {
log(LOG_ADDR, "Addr: \n");
log_dump(LOG_ADDR, &pol->ape_policy.addr, 16);
log(LOG_ADDR, "Mask:\n");
log_dump(LOG_ADDR, &pol->ape_policy.addrmask, 16);
}
}
static struct in6_addrpolicy *
match_addrsel_policy(key)
struct sockaddr_in6 *key;
{
struct addrsel_policyent *pent;
struct in6_addrpolicy *bestpol = NULL, *pol;
int matchlen, bestmatchlen = -1;
u_char *mp, *ep, *k, *p, m;
for (pent = TAILQ_FIRST(&addrsel_policytab); pent;
pent = TAILQ_NEXT(pent, ape_entry)) {
matchlen = 0;
pol = &pent->ape_policy;
mp = (u_char *)&pol->addrmask.sin6_addr;
ep = mp + 16; /* XXX: scope field? */
k = (u_char *)&key->sin6_addr;
p = (u_char *)&pol->addr.sin6_addr;
for (; mp < ep && *mp; mp++, k++, p++) {
m = *mp;
if ((*k & m) != *p)
goto next; /* not match */
if (m == 0xff) /* short cut for a typical case */
matchlen += 8;
else {
while(m >= 0x80) {
matchlen++;
m <<= 1;
}
}
}
/* matched. check if this is better than the current best. */
if (bestpol == NULL ||
matchlen > bestmatchlen) {
bestpol = pol;
bestmatchlen = matchlen;
}
next:
continue;
}
return(bestpol);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -