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