Bug #518 ยป jail-fixaddr.diff
| sys/jail.h 17 Jan 2007 12:45:47 -0000 | ||
|---|---|---|
|
/* Used to store the IPs of the jail */
|
||
|
struct jail_ip_storage {
|
||
|
SLIST_ENTRY(jail_ip_storage) entries;
|
||
|
struct sockaddr_storage ip;
|
||
|
SLIST_ENTRY(jail_ip_storage) entries;
|
||
|
};
|
||
|
/*
|
||
| ... | ... | |
|
struct nchandle pr_root; /* namecache entry of root */
|
||
|
char pr_host[MAXHOSTNAMELEN]; /* host name */
|
||
|
SLIST_HEAD(iplist, jail_ip_storage) pr_ips; /* list of IP addresses */
|
||
|
struct sockaddr_storage *local_ip4; /* cache for a loopback ipv4 address */
|
||
|
struct sockaddr_storage *nonlocal_ip4; /* cache for a non loopback ipv4 address */
|
||
|
struct sockaddr_storage *local_ip6; /* cache for a loopback ipv6 address */
|
||
|
struct sockaddr_storage *nonlocal_ip6; /* cache for a non loopback ipv6 address */
|
||
|
struct sockaddr_in *local_ip4; /* cache for a loopback ipv4 address */
|
||
|
struct sockaddr_in *nonlocal_ip4; /* cache for a non loopback ipv4 address */
|
||
|
struct sockaddr_in6 *local_ip6; /* cache for a loopback ipv6 address */
|
||
|
struct sockaddr_in6 *nonlocal_ip6; /* cache for a non loopback ipv6 address */
|
||
|
void *pr_linux; /* Linux ABI emulation */
|
||
|
int pr_securelevel; /* jail securelevel */
|
||
|
struct varsymset pr_varsymset; /* jail varsyms */
|
||
| ... | ... | |
|
void prison_hold(struct prison *);
|
||
|
void prison_free(struct prison *);
|
||
|
int jailed_ip(struct prison *, struct sockaddr *);
|
||
|
int prison_get_local(struct prison *pr, struct sockaddr *);
|
||
|
int prison_get_nonlocal(struct prison *pr, struct sockaddr *);
|
||
|
struct sockaddr *
|
||
|
prison_get_local(struct prison *pr, sa_family_t, struct sockaddr *);
|
||
|
struct sockaddr *
|
||
|
prison_get_nonlocal(struct prison *pr, sa_family_t, struct sockaddr *);
|
||
|
/*
|
||
|
* Return 1 if the passed credential is in a jail, otherwise 0.
|
||
| kern/kern_jail.c 17 Jan 2007 12:53:16 -0000 | ||
|---|---|---|
|
#include <netinet6/in6_var.h>
|
||
|
static struct prison *prison_find(int);
|
||
|
static void prison_ipcache_init(struct prison *);
|
||
|
MALLOC_DEFINE(M_PRISON, "prison", "Prison structures");
|
||
| ... | ... | |
|
cache_copy(&nd.nl_nch, &pr->pr_root);
|
||
|
varsymset_init(&pr->pr_varsymset, NULL);
|
||
|
prison_ipcache_init(pr);
|
||
|
tryprid = lastprid + 1;
|
||
|
if (tryprid == JAIL_MAX)
|
||
| ... | ... | |
|
return(kern_jail_attach(uap->jid));
|
||
|
}
|
||
|
static void
|
||
|
prison_ipcache_init(struct prison *pr)
|
||
|
{
|
||
|
struct jail_ip_storage *jis;
|
||
|
struct sockaddr_in *ip4;
|
||
|
struct sockaddr_in6 *ip6;
|
||
|
SLIST_FOREACH(jis, &pr->pr_ips, entries) {
|
||
|
switch (jis->ip.ss_family) {
|
||
|
case AF_INET:
|
||
|
ip4 = (struct sockaddr_in *)&jis->ip;
|
||
|
if ((ntohl(ip4->sin_addr.s_addr) >> IN_CLASSA_NSHIFT) ==
|
||
|
IN_LOOPBACKNET) {
|
||
|
/* loopback address */
|
||
|
if (pr->local_ip4 == NULL)
|
||
|
pr->local_ip4 = ip4;
|
||
|
} else {
|
||
|
/* public address */
|
||
|
if (pr->nonlocal_ip4 == NULL)
|
||
|
pr->nonlocal_ip4 = ip4;
|
||
|
}
|
||
|
break;
|
||
|
case AF_INET6:
|
||
|
ip6 = (struct sockaddr_in6 *)&jis->ip;
|
||
|
if (IN6_IS_ADDR_LOOPBACK(&ip6->sin6_addr)) {
|
||
|
/* loopback address */
|
||
|
if (pr->local_ip6 == NULL)
|
||
|
pr->local_ip6 = ip6;
|
||
|
} else {
|
||
|
/* public address */
|
||
|
if (pr->nonlocal_ip6 == NULL)
|
||
|
pr->nonlocal_ip6 = ip6;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
/*
|
||
|
* Changes INADDR_LOOPBACK for a valid jail address.
|
||
|
* ip is in network byte order.
|
||
| ... | ... | |
|
ip4->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) ||
|
||
|
(ip->sa_family == AF_INET6 &&
|
||
|
IN6_IS_ADDR_LOOPBACK(&ip6->sin6_addr))) {
|
||
|
if (!prison_get_local(pr, ip) && !prison_get_nonlocal(pr, ip))
|
||
|
if (!prison_get_local(pr, ip->sa_family, ip) &&
|
||
|
!prison_get_nonlocal(pr, ip->sa_family, ip))
|
||
|
return(0);
|
||
|
else
|
||
|
return(1);
|
||
| ... | ... | |
|
ip4->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) ||
|
||
|
(ip->sa_family == AF_INET6 &&
|
||
|
IN6_IS_ADDR_LOOPBACK(&ip6->sin6_addr))) {
|
||
|
if (!prison_get_local(pr, ip) && !prison_get_nonlocal(pr, ip))
|
||
|
if (!prison_get_local(pr, ip->sa_family, ip) &&
|
||
|
!prison_get_nonlocal(pr, ip->sa_family, ip))
|
||
|
return(0);
|
||
|
else
|
||
|
return(1);
|
||
| ... | ... | |
|
/*
|
||
|
* Prison get non loopback ip:
|
||
|
* Put on *ip the first IP address that is not a loopback address.
|
||
|
* af is the address family of the ip we want (AF_INET|AF_INET6).
|
||
|
* - af is the address family of the ip we want (AF_INET|AF_INET6).
|
||
|
* - If ip != NULL, put the first IP address that is not a loopback address
|
||
|
* into *ip.
|
||
|
*
|
||
|
* ip is in network by order and we don't touch it unless we find a valid ip.
|
||
|
* Return 1 if we've found a non loopback ip, else return 0.
|
||
|
* No matter if ip == NULL or not, we return either a valid struct sockaddr *,
|
||
|
* or NULL. This struct may not be modified.
|
||
|
*/
|
||
|
int
|
||
|
prison_get_nonlocal(struct prison *pr, struct sockaddr *ip)
|
||
|
struct sockaddr *
|
||
|
prison_get_nonlocal(struct prison *pr, sa_family_t af, struct sockaddr *ip)
|
||
|
{
|
||
|
struct jail_ip_storage *jis;
|
||
|
struct sockaddr_in *jip4, *ip4;
|
||
|
struct sockaddr_in6 *jip6, *ip6;
|
||
|
struct sockaddr_in *ip4 = (struct sockaddr_in *)ip;
|
||
|
struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)ip;
|
||
|
ip4 = (struct sockaddr_in *)ip;
|
||
|
ip6 = (struct sockaddr_in6 *)ip;
|
||
|
/* Check if it is cached */
|
||
|
switch(ip->sa_family) {
|
||
|
case AF_INET:
|
||
|
/* -1 Means that we don't have any address */
|
||
|
if (pr->nonlocal_ip4 == (struct sockaddr_storage *)-1)
|
||
|
return(0);
|
||
|
if (pr->nonlocal_ip4 != NULL) {
|
||
|
jip4 = (struct sockaddr_in *) pr->nonlocal_ip4;
|
||
|
ip4->sin_addr.s_addr = jip4->sin_addr.s_addr;
|
||
|
}
|
||
|
break;
|
||
|
case AF_INET6:
|
||
|
/* -1 Means that we don't have any address */
|
||
|
if (pr->nonlocal_ip6 == (struct sockaddr_storage *)-1)
|
||
|
return(0);
|
||
|
if (pr->nonlocal_ip6 != NULL) {
|
||
|
jip6 = (struct sockaddr_in6 *) pr->nonlocal_ip6;
|
||
|
ip6->sin6_addr = jip6->sin6_addr;
|
||
|
}
|
||
|
break;
|
||
|
};
|
||
|
SLIST_FOREACH(jis, &pr->pr_ips, entries) {
|
||
|
switch (ip->sa_family) {
|
||
|
case AF_INET:
|
||
|
jip4 = (struct sockaddr_in *) &jis->ip;
|
||
|
if (jip4->sin_family == AF_INET &&
|
||
|
((ntohl(jip4->sin_addr.s_addr) >> IN_CLASSA_NSHIFT) != IN_LOOPBACKNET)) {
|
||
|
pr->nonlocal_ip4 = &jis->ip;
|
||
|
ip4->sin_addr.s_addr = jip4->sin_addr.s_addr;
|
||
|
return(1);
|
||
|
}
|
||
|
break;
|
||
|
case AF_INET6:
|
||
|
jip6 = (struct sockaddr_in6 *) &jis->ip;
|
||
|
if ( jip6->sin6_family == AF_INET6 &&
|
||
|
!IN6_IS_ADDR_LOOPBACK(&jip6->sin6_addr)) {
|
||
|
pr->nonlocal_ip6 = &jis->ip;
|
||
|
ip6->sin6_addr = jip6->sin6_addr;
|
||
|
return(1);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
switch(af) {
|
||
|
case AF_INET:
|
||
|
if (ip4 != NULL && pr->nonlocal_ip4 != NULL)
|
||
|
ip4->sin_addr.s_addr = pr->nonlocal_ip4->sin_addr.s_addr;
|
||
|
return (struct sockaddr *)pr->nonlocal_ip4;
|
||
|
case AF_INET6:
|
||
|
if (ip6 != NULL && pr->nonlocal_ip6 != NULL)
|
||
|
ip6->sin6_addr = pr->nonlocal_ip6->sin6_addr;
|
||
|
return (struct sockaddr *)pr->nonlocal_ip6;
|
||
|
}
|
||
|
if (ip->sa_family == AF_INET)
|
||
|
pr->nonlocal_ip4 = (struct sockaddr_storage *)-1;
|
||
|
else
|
||
|
pr->nonlocal_ip6 = (struct sockaddr_storage *)-1;
|
||
|
return(0);
|
||
|
/* NOTREACHED */
|
||
|
return NULL;
|
||
|
}
|
||
|
/*
|
||
|
* Prison get loopback ip.
|
||
|
* Put on *ip the first loopback IP address.
|
||
|
* af is the address family of the ip we want (AF_INET|PF_INET).
|
||
|
* *ip is in network by order and we don't touch it unless we find a valid ip.
|
||
|
* return 1 if we've found a loopback ip, else return 0.
|
||
|
* - af is the address family of the ip we want (AF_INET|AF_INET6).
|
||
|
* - If ip != NULL, put the first IP address that is not a loopback address
|
||
|
* into *ip.
|
||
|
*
|
||
|
* ip is in network by order and we don't touch it unless we find a valid ip.
|
||
|
* No matter if ip == NULL or not, we return either a valid struct sockaddr *,
|
||
|
* or NULL. This struct may not be modified.
|
||
|
*/
|
||
|
int
|
||
|
prison_get_local(struct prison *pr, struct sockaddr *ip)
|
||
|
struct sockaddr *
|
||
|
prison_get_local(struct prison *pr, sa_family_t af, struct sockaddr *ip)
|
||
|
{
|
||
|
struct jail_ip_storage *jis;
|
||
|
struct sockaddr_in *jip4, *ip4;
|
||
|
struct sockaddr_in6 *jip6, *ip6;
|
||
|
struct sockaddr_in *ip4 = (struct sockaddr_in *)ip;
|
||
|
struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)ip;
|
||
|
ip4 = (struct sockaddr_in *)ip;
|
||
|
ip6 = (struct sockaddr_in6 *)ip;
|
||
|
/* Check if it is cached */
|
||
|
switch(ip->sa_family) {
|
||
|
case AF_INET:
|
||
|
/* -1 Means that we don't have any address */
|
||
|
if (pr->local_ip4 == (struct sockaddr_storage *)-1)
|
||
|
return(0);
|
||
|
if (pr->local_ip4 != NULL) {
|
||
|
jip4 = (struct sockaddr_in *) pr->local_ip4;
|
||
|
ip4->sin_addr.s_addr = jip4->sin_addr.s_addr;
|
||
|
}
|
||
|
break;
|
||
|
case AF_INET6:
|
||
|
/* -1 Means that we don't have any address */
|
||
|
if (pr->local_ip6 == (struct sockaddr_storage *)-1)
|
||
|
return(0);
|
||
|
if (pr->local_ip6 != NULL) {
|
||
|
jip6 = (struct sockaddr_in6 *) pr->local_ip6;
|
||
|
ip6->sin6_addr = jip6->sin6_addr;
|
||
|
}
|
||
|
break;
|
||
|
};
|
||
|
SLIST_FOREACH(jis, &pr->pr_ips, entries) {
|
||
|
switch(ip->sa_family) {
|
||
|
case AF_INET:
|
||
|
jip4 = (struct sockaddr_in *) &jis->ip;
|
||
|
if (jip4->sin_family == AF_INET &&
|
||
|
((ntohl(jip4->sin_addr.s_addr) >> IN_CLASSA_NSHIFT)
|
||
|
== IN_LOOPBACKNET)) {
|
||
|
pr->local_ip4 = &jis->ip;
|
||
|
ip4->sin_addr.s_addr = jip4->sin_addr.s_addr;
|
||
|
return(1);
|
||
|
}
|
||
|
break;
|
||
|
case AF_INET6:
|
||
|
jip6 = (struct sockaddr_in6 *) &jis->ip;
|
||
|
if (jip6->sin6_family == AF_INET6 &&
|
||
|
IN6_IS_ADDR_LOOPBACK(&jip6->sin6_addr)) {
|
||
|
pr->local_ip6 = &jis->ip;
|
||
|
ip6->sin6_addr = jip6->sin6_addr;
|
||
|
return(1);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
switch(af) {
|
||
|
case AF_INET:
|
||
|
if (ip4 != NULL && pr->local_ip4 != NULL)
|
||
|
ip4->sin_addr.s_addr = pr->local_ip4->sin_addr.s_addr;
|
||
|
return (struct sockaddr *)pr->local_ip4;
|
||
|
case AF_INET6:
|
||
|
if (ip6 != NULL && pr->local_ip6 != NULL)
|
||
|
ip6->sin6_addr = pr->local_ip6->sin6_addr;
|
||
|
return (struct sockaddr *)pr->local_ip6;
|
||
|
}
|
||
|
if (ip->sa_family == AF_INET)
|
||
|
pr->local_ip4 = (struct sockaddr_storage *)-1;
|
||
|
else
|
||
|
pr->local_ip6 = (struct sockaddr_storage *)-1;
|
||
|
return(0);
|
||
|
/* NOTREACHED */
|
||
|
return NULL;
|
||
|
}
|
||
|
/* Check if the IP is among ours, if it is return 1, else 0 */
|
||
| netinet/in_pcb.c 17 Jan 2007 12:58:07 -0000 | ||
|---|---|---|
|
struct in_ifaddr *ia;
|
||
|
struct ucred *cred = NULL;
|
||
|
struct sockaddr_in *sin = (struct sockaddr_in *)nam;
|
||
|
struct sockaddr_in jsin;
|
||
|
struct sockaddr *jsin;
|
||
|
int jailed = 0;
|
||
|
if (nam->sa_len != sizeof *sin)
|
||
| ... | ... | |
|
* Don't do pcblookup call here; return interface in plocal_sin
|
||
|
* and exit to caller, that will do the lookup.
|
||
|
*/
|
||
|
if (jailed) {
|
||
|
jsin.sin_family = AF_INET;
|
||
|
if (!prison_get_nonlocal(cred->cr_prison,
|
||
|
sintosa(&jsin)) &&
|
||
|
!prison_get_local(cred->cr_prison, sintosa(&jsin)))
|
||
|
/* IPv6 only Jail */
|
||
|
return (EADDRNOTAVAIL);
|
||
|
*plocal_sin = &jsin;
|
||
|
if (ia == NULL && jailed) {
|
||
|
if ((jsin = prison_get_nonlocal(cred->cr_prison, AF_INET, NULL)) != NULL ||
|
||
|
(jsin = prison_get_local(cred->cr_prison, AF_INET, NULL)) != NULL)
|
||
|
*plocal_sin = satosin(jsin);
|
||
|
else
|
||
|
/* IPv6 only Jail */
|
||
|
return (EADDRNOTAVAIL);
|
||
|
} else {
|
||
|
*plocal_sin = &ia->ia_addr;
|
||
|
}
|
||