kern/69064: No multiple ip4/6's could assigned to a jail.

Meno Abels abels at adviser.com
Sat Jul 31 01:01:17 PDT 2004


The following reply was made to PR kern/69064; it has been noted by GNATS.

From: "Meno Abels" <abels at adviser.com>
To: FreeBSD-gnats-submit at freebsd.org
Cc: Max Laier <max at love2party.net>
Subject: Re: kern/69064: No multiple ip4/6's could assigned to a jail.
Date: Sat, 31 Jul 2004 09:54:15 +0200

 I chosen the wrong patch format so here it again as a unified diff.
 It is a little diffrent to the last patch in fact i resolved some clashes with
 other changes to -CURRENT
 
 Meno
 
 
 Index: sys/kern/kern_jail.c
 ===================================================================
 RCS file: /usr/freebsd.cvs/src/sys/kern/kern_jail.c,v
 retrieving revision 1.44
 diff -u -r1.44 kern_jail.c
 --- sys/kern/kern_jail.c	27 Jun 2004 09:03:21 -0000	1.44
 +++ sys/kern/kern_jail.c	14 Jul 2004 19:12:39 -0000
 @@ -33,8 +33,11 @@
  #include <sys/vnode.h>
  #include <net/if.h>
  #include <netinet/in.h>
 +#include <netinet6/in6_var.h>
  
  MALLOC_DEFINE(M_PRISON, "prison", "Prison structures");
 +MALLOC_DEFINE(M_PRISON_IP4, "prison", "Prison ipv4 addresses");
 +MALLOC_DEFINE(M_PRISON_IP6, "prison", "Prison ipv6 addresses");
  
  SYSCTL_DECL(_security);
  SYSCTL_NODE(_security, OID_AUTO, jail, CTLFLAG_RW, 0,
 @@ -75,6 +78,11 @@
  
  static void		 init_prison(void *);
  static void		 prison_complete(void *context, int pending);
 +static int 		 prison_add_ip4(struct in_addr *tmpv4, struct prison *pr, void *pr_new, void **pr_old);
 +static int 		 prison_add_ip6(struct in6_addr *tmpv4, struct prison *pr, void *pr_new, void **pr_old);
 +static int 		 prison_del_ip4(struct in_addr *tmpv4, struct prison *pr, void *pr_new, void **pr_old);
 +static int 		 prison_del_ip6(struct in6_addr *tmpv4, struct prison *pr, void *pr_new, void **pr_old);
 +static int               prison_check_duplicate(char *hostname, char *path);
  static struct prison	*prison_find(int);
  static int		 sysctl_jail_list(SYSCTL_HANDLER_ARGS);
  
 @@ -95,45 +103,179 @@
   *	struct jail *jail;
   * };
   */
 -int
 -jail(struct thread *td, struct jail_args *uap)
 +static int 
 +jail_createjail(struct thread *td, char *user_hostname, char *user_path, struct prison **pr)
  {
 +	int error;
  	struct nameidata nd;
 -	struct prison *pr, *tpr;
 -	struct jail j;
 -	struct jail_attach_args jaa;
 -	int error, tryprid;
  
 -	error = copyin(uap->jail, &j, sizeof(j));
 +	MALLOC(*pr, struct prison *, sizeof(**pr), M_PRISON, M_WAITOK | M_ZERO);
 +	mtx_init(&(*pr)->pr_mtx, "jail mutex", NULL, MTX_DEF);
 +	(*pr)->pr_ref = 1;
 +	error = copyinstr(user_path, &(*pr)->pr_path, sizeof((*pr)->pr_path), 0);
  	if (error)
 -		return (error);
 -	if (j.version != 0)
 -		return (EINVAL);
 -
 -	MALLOC(pr, struct prison *, sizeof(*pr), M_PRISON, M_WAITOK | M_ZERO);
 -	mtx_init(&pr->pr_mtx, "jail mutex", NULL, MTX_DEF);
 -	pr->pr_ref = 1;
 -	error = copyinstr(j.path, &pr->pr_path, sizeof(pr->pr_path), 0);
 +		goto e_killmtx;
 +	error = copyinstr(user_hostname, &(*pr)->pr_host, sizeof((*pr)->pr_host), 0);
  	if (error)
  		goto e_killmtx;
 +	if (prison_check_duplicate((*pr)->pr_host, (*pr)->pr_path)) {
 +		error = EAGAIN;
 +		goto e_killmtx;
 +	}
 +
  	mtx_lock(&Giant);
 -	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, pr->pr_path, td);
 +	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, (*pr)->pr_path, td);
  	error = namei(&nd);
  	if (error) {
  		mtx_unlock(&Giant);
  		goto e_killmtx;
  	}
 -	pr->pr_root = nd.ni_vp;
 +	(*pr)->pr_root = nd.ni_vp;
  	VOP_UNLOCK(nd.ni_vp, 0, td);
  	NDFREE(&nd, NDF_ONLY_PNBUF);
  	mtx_unlock(&Giant);
 -	error = copyinstr(j.hostname, &pr->pr_host, sizeof(pr->pr_host), 0);
 -	if (error)
 -		goto e_dropvnref;
 -	pr->pr_ip = j.ip_number;
 -	pr->pr_linux = NULL;
 -	pr->pr_securelevel = securelevel;
  
 +	(*pr)->pr_linux = NULL;
 +	(*pr)->pr_securelevel = securelevel;
 +	return (0);
 +
 +e_killmtx:
 +	mtx_destroy(&(*pr)->pr_mtx);
 +	FREE(*pr, M_PRISON);
 +	return (error);
 +
 +}
 +
 +
 +static void 
 +jail_dropvnref(struct prison *pr)
 +{
 +	mtx_lock(&Giant);
 +	vrele(pr->pr_root);
 +	mtx_unlock(&Giant);
 +}
 +
 +int
 +jail(struct thread *td, struct jail_args *uap)
 +{
 +	struct prison *pr, *tpr;
 +	struct jail j;
 +	struct jail_attach_args jaa;
 +	int error, tryprid;
 +	void *pr_new = 0;
 +	void *pr_old = 0;
 +
 +	error = copyin(uap->jail, &j, sizeof(j));
 +	if (error)
 +		return (error);
 +	if (j.version < XPRISON_VERSION)
 +	{
 +		struct in_addr tmpv4;
 +
 +		error = jail_createjail(td, j.u.v1.hostname, j.u.v1.path, &pr);
 +		if (error) {
 +			return error;
 +		}
 +		MALLOC(pr_new, void *, sizeof(struct in_addr)*1, M_PRISON_IP4, M_WAITOK | M_ZERO);
 +		tmpv4.s_addr = htonl(j.u.v1.ip_number);		
 +		mtx_lock(&pr->pr_mtx);
 +		error = prison_add_ip4(&tmpv4, pr, pr_new, &pr_old);
 +		mtx_unlock(&pr->pr_mtx);
 +		if (error) {
 +			jail_dropvnref(pr);
 +		}
 +	}
 +	else
 +	{
 +		if (j.u.v2.function == CREATEJAIL) {
 +			error = jail_createjail(td, j.u.v2.u.createjail.hostname, j.u.v2.u.createjail.path, &pr);
 +			if (error) {
 +				return error;
 +			}
 +		}
 +		else {
 +			int cnt = 0;
 +			struct malloc_type *alloc_type;
 +retry_alloc:
 +			mtx_lock(&allprison_mtx);
 +			pr = prison_find(j.u.v2.u.add_del.id);
 +			if (pr) {
 +				cnt = (j.u.v2.function == ADDIP4 || j.u.v2.function == DELIP4) ? 
 +					pr->pr_ip4s : pr->pr_ip6s;	
 +			}
 +			mtx_unlock(&pr->pr_mtx);
 +			mtx_unlock(&allprison_mtx);
 +			if (pr == NULL) {
 +				return (EINVAL);
 +			}
 +			if (j.u.v2.function == ADDIP4 || j.u.v2.function == DELIP4) {
 +				alloc_type=M_PRISON_IP4;
 +				if (pr->pr_ip4s >= (j.u.v2.function == DELIP4 ? 2 : 0)) {
 +					MALLOC(pr_new, void *, 
 +						sizeof(struct in_addr)*(pr->pr_ip4s+
 +						(j.u.v2.function == DELIP4 ? -1 : +1)),
 +						alloc_type, M_WAITOK | M_ZERO);
 +					/*printf("pr_ip4s:%d\n", pr->pr_ip4s);*/
 +				}
 +			}
 +			else {
 +				alloc_type=M_PRISON_IP6;
 +				if (pr->pr_ip6s >= (j.u.v2.function == DELIP6 ? 2 : 0)) {
 +					MALLOC(pr_new, void *, 
 +						sizeof(struct in6_addr)*(pr->pr_ip6s+
 +						(j.u.v2.function == DELIP6 ? -1 : +1)),
 +						alloc_type, M_WAITOK | M_ZERO);
 +					/*printf("pr_ip4s:%d\n", pr->pr_ip6s);*/
 +				}
 +			}
 +			mtx_lock(&allprison_mtx);
 +			pr = prison_find(j.u.v2.u.add_del.id);
 +			if (pr)
 +			{
 +				if (cnt != ((j.u.v2.function == ADDIP4 || j.u.v2.function == DELIP4) ? 
 +					pr->pr_ip4s : pr->pr_ip6s))	
 +				{
 +					/* should i sleep ? */
 +					mtx_unlock(&pr->pr_mtx);
 +					mtx_unlock(&allprison_mtx);
 +					FREE(pr_new, alloc_type);
 +					/*printf("jail retry alloc\n");*/
 +					goto retry_alloc;
 +				}
 +				mtx_unlock(&allprison_mtx);
 +			}
 +			else
 +			{
 +				mtx_unlock(&allprison_mtx);
 +				return (EINVAL);
 +			}
 +			
 +			switch (j.u.v2.function) {
 +			case ADDIP4:
 +				error = prison_add_ip4(&j.u.v2.u.add_del.v4_6.ip4_num, pr, pr_new, &pr_old);
 +				break;
 +			case ADDIP6:
 +				error = prison_add_ip6(&j.u.v2.u.add_del.v4_6.ip6_num, pr, pr_new, &pr_old);
 +				break;
 +			case DELIP4:
 +				error = prison_del_ip4(&j.u.v2.u.add_del.v4_6.ip4_num, pr, pr_new, &pr_old);
 +				break;
 +			case DELIP6:
 +				error = prison_del_ip6(&j.u.v2.u.add_del.v4_6.ip6_num, pr, pr_new, &pr_old);
 +				break;
 +			default:
 +				mtx_unlock(&pr->pr_mtx);
 +				return EINVAL;
 +			}
 +			mtx_unlock(&pr->pr_mtx);
 +			if (pr_old) {
 +				/*printf("jail free:%p\n", pr_old);*/
 +				FREE(pr_old, alloc_type);
 +			}
 +			return (error);
 +		}
 +	}
 +	/* REST of Create Code */
  	/* Determine next pr_id and add prison to allprison list. */
  	mtx_lock(&allprison_mtx);
  	tryprid = lastprid + 1;
 @@ -146,7 +288,8 @@
  			if (tryprid == JAIL_MAX) {
  				mtx_unlock(&allprison_mtx);
  				error = EAGAIN;
 -				goto e_dropvnref;
 +				jail_dropvnref(pr);
 +				return error;
  			}
  			goto next;
  		}
 @@ -164,18 +307,13 @@
  	mtx_unlock(&pr->pr_mtx);
  	td->td_retval[0] = jaa.jid;
  	return (0);
 +
  e_dropprref:
  	mtx_lock(&allprison_mtx);
  	LIST_REMOVE(pr, pr_list);
  	prisoncount--;
  	mtx_unlock(&allprison_mtx);
 -e_dropvnref:
 -	mtx_lock(&Giant);
 -	vrele(pr->pr_root);
 -	mtx_unlock(&Giant);
 -e_killmtx:
 -	mtx_destroy(&pr->pr_mtx);
 -	FREE(pr, M_PRISON);
 +	jail_dropvnref(pr);
  	return (error);
  }
  
 @@ -248,6 +386,32 @@
  	return (error);
  }
  
 +/* return 0 on not duplicate */
 +static int
 +prison_check_duplicate(char *hostname, char *path)
 +{
 +	struct prison *pr;
 +	mtx_lock(&allprison_mtx);
 +	LIST_FOREACH(pr, &allprison, pr_list) {
 +		if (!strncmp(hostname, pr->pr_host, sizeof(pr->pr_host))) {
 +			mtx_unlock(&allprison_mtx);
 +			return 1;
 +		}
 +		/* this is not perfect remove of trailing / or duplicated //
 +                   should be done, who knows the kernel method for this-:)
 +                 */
 +/*
 +		if (!strncmp(path, pr->pr_path, sizeof(pr->pr_path))) {
 +			mtx_unlock(&allprison_mtx);
 +			return 1;
 +		}
 +*/
 +	}
 +	mtx_unlock(&allprison_mtx);
 +	return 0;
 +}
 +
 +
  /*
   * Returns a locked prison instance, or NULL on failure.
   */
 @@ -299,6 +463,10 @@
  	mtx_unlock(&Giant);
  
  	mtx_destroy(&pr->pr_mtx);
 +	if (pr->pr_ip4 != NULL)
 +		FREE(pr->pr_ip4, M_PRISON_IP4);
 +	if (pr->pr_ip6 != NULL)
 +		FREE(pr->pr_ip6, M_PRISON_IP6);
  	if (pr->pr_linux != NULL)
  		FREE(pr->pr_linux, M_PRISON);
  	FREE(pr, M_PRISON);
 @@ -313,59 +481,130 @@
  	mtx_unlock(&pr->pr_mtx);
  }
  
 -u_int32_t
 -prison_getip(struct ucred *cred)
 +int
 +prison_first_ip4(struct ucred *cred, struct in_addr *out)
  {
 +	int errno = 0;
 +	mtx_lock(&cred->cr_prison->pr_mtx);
 +	if (cred->cr_prison->pr_ip4s) 
 +		*out = cred->cr_prison->pr_ip4[0];
 +	else
 +		errno = EADDRNOTAVAIL;
 +	mtx_unlock(&cred->cr_prison->pr_mtx);
 +	return errno;
 +}
  
 -	return (cred->cr_prison->pr_ip);
 +int
 +prison_first_ip6(struct ucred *cred, struct in6_addr *out)
 +{
 +	int errno = 0;
 +	mtx_lock(&cred->cr_prison->pr_mtx);
 +	if (cred->cr_prison->pr_ip6s)
 +		*out = cred->cr_prison->pr_ip6[0];
 +	else
 +		errno = EADDRNOTAVAIL;
 +	mtx_unlock(&cred->cr_prison->pr_mtx);
 +	return errno;
  }
  
  int
 -prison_ip(struct ucred *cred, int flag, u_int32_t *ip)
 +prison_match_ip4(struct ucred *cred, struct in_addr *ip)
  {
  	u_int32_t tmp;
  
  	if (!jailed(cred))
  		return (0);
 -	if (flag) 
 -		tmp = *ip;
 -	else
 -		tmp = ntohl(*ip);
 -	if (tmp == INADDR_ANY) {
 -		if (flag) 
 -			*ip = cred->cr_prison->pr_ip;
 -		else
 -			*ip = htonl(cred->cr_prison->pr_ip);
 -		return (0);
 -	}
 -	if (tmp == INADDR_LOOPBACK) {
 -		if (flag)
 -			*ip = cred->cr_prison->pr_ip;
 -		else
 -			*ip = htonl(cred->cr_prison->pr_ip);
 +
 +	for (tmp = 0; tmp < cred->cr_prison->pr_ip4s; ++tmp)
 +	{
 +		if (cred->cr_prison->pr_ip4[tmp].s_addr == ip->s_addr)
 +		{
 +			return 0;
 +		}
 +	}
 +	return (1);
 +}
 +
 +int
 +prison_redirect_ip4(struct ucred *cred, struct in_addr *ip)
 +{
 +	if (!jailed(cred))
 +		return (0);
 +	if (cred->cr_prison->pr_ip4s <= 0)
 +		return (0);
 +
 +	if (ip->s_addr == htonl(INADDR_ANY)) {
 +		*ip = cred->cr_prison->pr_ip4[0];
  		return (0);
  	}
 -	if (cred->cr_prison->pr_ip != tmp)
 -		return (1);
 -	return (0);
 +	if (ip->s_addr == htonl(INADDR_LOOPBACK)) {
 +		*ip = cred->cr_prison->pr_ip4[0];
 +		return (0);
 +	}
 +	return prison_match_ip4(cred, ip);
  }
  
 -void
 -prison_remote_ip(struct ucred *cred, int flag, u_int32_t *ip)
 +int
 +prison_match_ip6(struct ucred *cred, struct in6_addr *ip)
  {
  	u_int32_t tmp;
  
  	if (!jailed(cred))
 +		return (0);
 +
 +	for (tmp = 0; tmp < cred->cr_prison->pr_ip6s; ++tmp)
 +	{
 +		if (IN6_ARE_ADDR_EQUAL(&(cred->cr_prison->pr_ip6[tmp]), ip))
 +		{
 +			return 0;
 +		}
 +	}
 +	return (1);
 +}
 +
 +
 +int
 +prison_redirect_ip6(struct ucred *cred, struct in6_addr *ip)
 +{
 +	if (!jailed(cred))
 +		return (0);
 +	if (cred->cr_prison->pr_ip6s <= 0)
 +		return (0);
 +
 +	if (IN6_ARE_ADDR_EQUAL(ip, &in6addr_any)) {
 +		*ip = cred->cr_prison->pr_ip6[0];
 +		return (0);
 +	}
 +	if (IN6_IS_ADDR_LOOPBACK(ip)) {
 +		*ip = cred->cr_prison->pr_ip6[0];
 +		return (0);
 +	}
 +	return prison_match_ip6(cred, ip);
 +}
 +
 +void
 +prison_remote_ip4(struct ucred *cred, struct in_addr *ip)
 +{
 +	if (!jailed(cred))
  		return;
 -	if (flag)
 -		tmp = *ip;
 -	else
 -		tmp = ntohl(*ip);
 -	if (tmp == INADDR_LOOPBACK) {
 -		if (flag)
 -			*ip = cred->cr_prison->pr_ip;
 -		else
 -			*ip = htonl(cred->cr_prison->pr_ip);
 +	if (cred->cr_prison->pr_ip4s <= 0)
 +		return;
 +	if (ip->s_addr == INADDR_LOOPBACK) {
 +		*ip = cred->cr_prison->pr_ip4[0];
 +		return;
 +	}
 +	return;
 +}
 +
 +void
 +prison_remote_ip6(struct ucred *cred, struct in6_addr *ip)
 +{
 +	if (!jailed(cred))
 +		return;
 +	if (cred->cr_prison->pr_ip6s <= 0)
 +		return;
 +	if (IN6_IS_ADDR_LOOPBACK(ip)) {
 +		*ip = cred->cr_prison->pr_ip6[0];
  		return;
  	}
  	return;
 @@ -374,18 +613,43 @@
  int
  prison_if(struct ucred *cred, struct sockaddr *sa)
  {
 -	struct sockaddr_in *sai;
 -	int ok;
 +	int ok = 0;
  
 -	sai = (struct sockaddr_in *)sa;
 -	if ((sai->sin_family != AF_INET) && jail_socket_unixiproute_only)
 +	if (!(sa->sa_family == AF_INET || sa->sa_family == AF_INET6) 
 +	    && jail_socket_unixiproute_only)
  		ok = 1;
 -	else if (sai->sin_family != AF_INET)
 -		ok = 0;
 -	else if (cred->cr_prison->pr_ip != ntohl(sai->sin_addr.s_addr))
 -		ok = 1;
 -	else
 -		ok = 0;
 +	else 
 +	{
 +		if (sa->sa_family == AF_INET)
 +		{
 +			int tmp;
 +			struct sockaddr_in *sai = (struct sockaddr_in *)sa;
 +			ok = 1;
 +			for (tmp = 0; tmp < cred->cr_prison->pr_ip4s; ++tmp)
 +			{
 +				if (cred->cr_prison->pr_ip4[tmp].s_addr == sai->sin_addr.s_addr)
 +				{
 +					ok = 0;
 +					break;
 +				}
 +			}
 +		}
 +		else if (sa->sa_family == AF_INET6)
 +		{
 +			struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
 +			int tmp;
 +			ok = 1;
 +			for (tmp = 0; tmp < cred->cr_prison->pr_ip6s; ++tmp)
 +			{
 +				if (IN6_ARE_ADDR_EQUAL(&(cred->cr_prison->pr_ip6[tmp]), 
 +							&(sa6->sin6_addr)))
 +				{
 +					ok = 0;
 +					break;
 +				}
 +			}
 +		}
 +	}
  	return (ok);
  }
  
 @@ -407,6 +671,138 @@
  }
  
  /*
 + * assumes that mtx_lock (pr->mtx)  is done
 + */
 +static int
 +prison_add_ip4(struct in_addr *ip, struct prison *pr, void *vpr_new, void **pr_free)
 +{
 +	struct in_addr *pr_new = vpr_new;
 +	struct in_addr *wrk_new;
 +
 +	wrk_new = pr_new;
 +	if (pr->pr_ip4s > 0)
 +	{
 +		struct in_addr *pr_old = pr->pr_ip4;
 +		for (;pr_old < &(pr->pr_ip4[pr->pr_ip4s]) ; ++pr_old)
 +		{
 +			if (pr_old->s_addr == ip->s_addr)
 +			{
 +				*pr_free = pr_new;
 +				return 0;
 +			}
 +			*wrk_new++ = *pr_old;
 +		} 
 +	}
 +	*wrk_new = *ip;
 +	++(pr->pr_ip4s);
 +	if (pr->pr_ip4)
 +		*pr_free = pr->pr_ip4;
 +	pr->pr_ip4 = pr_new;
 +	return 0;	
 +}
 +
 +static int
 +prison_add_ip6(struct in6_addr *ip, struct prison *pr, void *vpr_new, void **pr_free)
 +{
 +	struct in6_addr *pr_new = vpr_new;
 +	struct in6_addr *wrk_new;
 +
 +	wrk_new = pr_new;
 +	if (pr->pr_ip6s > 0)
 +	{
 +		struct in6_addr *pr_old = pr->pr_ip6;
 +		for (;pr_old < &(pr->pr_ip6[pr->pr_ip6s]) ; ++pr_old)
 +		{
 +			if (IN6_ARE_ADDR_EQUAL(pr_old, ip))
 +			{
 +				*pr_free = pr_new;
 +				return 0;
 +			}
 +			*wrk_new++ = *pr_old;
 +		} 
 +	}
 +	*wrk_new = *ip;
 +	++(pr->pr_ip6s);
 +	if (pr->pr_ip6)
 +		*pr_free = pr->pr_ip6;
 +	pr->pr_ip6 = pr_new;
 +	return 0;	
 +}
 +
 +static int
 +prison_del_ip4(struct in_addr *ip, struct prison *pr, void *vpr_new, void **pr_free)
 +{
 +	struct in_addr *pr_new = vpr_new;
 +	struct in_addr *wrk_new;
 +	int errno = ENOENT;
 +
 +	wrk_new = pr_new;
 +	if (pr->pr_ip4s > 0)
 +	{
 +		struct in_addr *pr_old = pr->pr_ip4;
 +		for (;pr_old < &(pr->pr_ip4[pr->pr_ip4s]) ; ++pr_old)
 +		{
 +			if (pr_old->s_addr != ip->s_addr)
 +			{
 +				if (wrk_new) { /* remove only if one or more elements remaining */
 +					*wrk_new++ = *pr_old;
 +				}
 +			}
 +			else
 +			{
 +				errno = 0; /* found element to delete */
 +			}
 +		} 
 +	}
 +	if (errno == 0)
 +	{
 +		--(pr->pr_ip4s);
 +		/* attach new array */
 +		if (pr->pr_ip4)
 +			*pr_free = pr->pr_ip4;
 +		pr->pr_ip4 = pr_new;
 +	}
 +	return errno;	
 +}
 +
 +static int
 +prison_del_ip6(struct in6_addr *ip, struct prison *pr, void *vpr_new, void **pr_free)
 +{
 +	struct in6_addr *pr_new = vpr_new;
 +	struct in6_addr *wrk_new;
 +	int errno = ENOENT;
 +
 +	wrk_new = pr_new;
 +	if (pr->pr_ip6s > 0)
 +	{
 +		struct in6_addr *pr_old = pr->pr_ip6;
 +		for (;pr_old < &(pr->pr_ip6[pr->pr_ip6s]) ; ++pr_old)
 +		{
 +			if (!IN6_ARE_ADDR_EQUAL(pr_old, ip))
 +			{
 +				if (wrk_new) { /* remove only if one or more elements remaining */
 +					*wrk_new++ = *pr_old;
 +				}
 +			}
 +			else
 +			{
 +				errno = 0; /* found element to delete */
 +			}
 +		} 
 +	}
 +	if (errno == 0)
 +	{
 +		--(pr->pr_ip6s);
 +		/* attach new array */
 +		if (pr->pr_ip6)
 +			*pr_free = pr->pr_ip6;
 +		pr->pr_ip6 = pr_new;
 +	}
 +	return errno;	
 +}
 +
 +
 +/*
   * Return 1 if the passed credential is in a jail, otherwise 0.
   */
  int
 @@ -452,35 +848,67 @@
  	struct xprison *xp, *sxp;
  	struct prison *pr;
  	int count, error;
 +	int prcount;
  
  	mtx_assert(&Giant, MA_OWNED);
  	if (jailed(req->td->td_ucred))
  		return (0);
  retry:
  	mtx_lock(&allprison_mtx);
 -	count = prisoncount;
 +	count = 0;
 +	prcount = 0;
 +	LIST_FOREACH(pr, &allprison, pr_list) {
 +		++prcount;
 +		if (pr->pr_ip4s || pr->pr_ip6s) {
 +			count += max(pr->pr_ip4s, pr->pr_ip6s);
 +		}	
 +		else {
 +			++count;
 +		}
 +	}
  	mtx_unlock(&allprison_mtx);
  
  	if (count == 0)
  		return (0);
  
 +	/*printf("jls:count=%d:%d\n", count, prcount);*/
  	sxp = xp = malloc(sizeof(*xp) * count, M_TEMP, M_WAITOK | M_ZERO);
  	mtx_lock(&allprison_mtx);
 -	if (count != prisoncount) {
 +	if (prcount != prisoncount) {
  		mtx_unlock(&allprison_mtx);
  		free(sxp, M_TEMP);
  		goto retry;
  	}
  	
  	LIST_FOREACH(pr, &allprison, pr_list) {
 -		mtx_lock(&pr->pr_mtx);
 -		xp->pr_version = XPRISON_VERSION;
 -		xp->pr_id = pr->pr_id;
 -		strlcpy(xp->pr_path, pr->pr_path, sizeof(xp->pr_path));
 -		strlcpy(xp->pr_host, pr->pr_host, sizeof(xp->pr_host));
 -		xp->pr_ip = pr->pr_ip;
 -		mtx_unlock(&pr->pr_mtx);
 -		xp++;
 +		int id = 0;
 +		int i;
 +		int maxcnt = max(pr->pr_ip4s, pr->pr_ip6s);
 +		/*printf("jls:maxcnt=%d\n", maxcnt);*/
 +		for (i = 0; i < (maxcnt ? maxcnt : 1) ; ++i)
 +		{	
 +			/*printf("jls:-0-:%d:%d\n", i, maxcnt);*/
 +			mtx_lock(&pr->pr_mtx);
 +			xp->pr_version = XPRISON_VERSION;
 +			xp->pr_id = pr->pr_id;
 +			strlcpy(xp->pr_path, pr->pr_path, sizeof(xp->pr_path));
 +			strlcpy(xp->pr_host, pr->pr_host, sizeof(xp->pr_host));
 +			if (i < pr->pr_ip4s) {
 +				xp->pr4_id  = id;
 +				xp->pr4_num = pr->pr_ip4[i];
 +			}
 +			else
 +				xp->pr4_id  = -1;
 +			if (i < pr->pr_ip6s) {
 +				xp->pr6_id  = id;
 +				xp->pr6_num = pr->pr_ip6[i];
 +			}
 +			else
 +				xp->pr6_id  = -1;
 +			++id;
 +			mtx_unlock(&pr->pr_mtx);
 +			xp++;
 +		}
  	}
  	mtx_unlock(&allprison_mtx);
  
 Index: sys/net/rtsock.c
 ===================================================================
 RCS file: /usr/freebsd.cvs/src/sys/net/rtsock.c,v
 retrieving revision 1.112
 diff -u -r1.112 rtsock.c
 --- sys/net/rtsock.c	6 Jul 2004 03:29:41 -0000	1.112
 +++ sys/net/rtsock.c	14 Jul 2004 17:52:25 -0000
 @@ -322,7 +322,8 @@
  	int len, error = 0;
  	struct ifnet *ifp = NULL;
  	struct ifaddr *ifa = NULL;
 -	struct sockaddr_in jail;
 +	struct sockaddr_in  jail4;
 +	struct sockaddr_in6 jail6;
  
  #define senderr(e) { error = e; goto flush;}
  	if (m == NULL || ((m->m_len < sizeof(long)) &&
 @@ -437,13 +438,32 @@
  					info.rti_info[RTAX_IFP] =
  					    ifaddr_byindex(ifp->if_index)->ifa_addr;
  					if (jailed(so->so_cred)) {
 -						bzero(&jail, sizeof(jail));
 -						jail.sin_family = PF_INET;
 -						jail.sin_len = sizeof(jail);
 -						jail.sin_addr.s_addr =
 -						htonl(prison_getip(so->so_cred));
 -						info.rti_info[RTAX_IFA] =
 -						    (struct sockaddr *)&jail;
 +						if (rt->rt_ifa->ifa_addr->sa_family == PF_INET) {
 +							bzero(&jail4, sizeof(jail4));
 +							jail4.sin_family = PF_INET;
 +							jail4.sin_len = sizeof(jail4);
 +							error = prison_first_ip4(so->so_cred, 
 +									&jail4.sin_addr); 
 +							if (error)
 +								senderr(error);
 +							info.rti_info[RTAX_IFA] =
 +							    (struct sockaddr *)&jail4;
 +						}
 +						else if (rt->rt_ifa->ifa_addr->sa_family == PF_INET6) {
 +							bzero(&jail6, sizeof(jail6));
 +							jail6.sin6_family = PF_INET6;
 +							jail6.sin6_len = sizeof(jail6);
 +							error = prison_first_ip6(so->so_cred, 
 +									&jail6.sin6_addr); 
 +							if (error)
 +								senderr(error);
 +							info.rti_info[RTAX_IFA] =
 +							    (struct sockaddr *)&jail6;
 +						}
 +						else {
 +							info.rti_info[RTAX_IFA] =
 +							    rt->rt_ifa->ifa_addr;
 +						}
  					} else
  						info.rti_info[RTAX_IFA] =
  						    rt->rt_ifa->ifa_addr;
 Index: sys/netinet/in_pcb.c
 ===================================================================
 RCS file: /usr/freebsd.cvs/src/sys/netinet/in_pcb.c,v
 retrieving revision 1.152
 diff -u -r1.152 in_pcb.c
 --- sys/netinet/in_pcb.c	28 Jul 2004 13:03:07 -0000	1.152
 +++ sys/netinet/in_pcb.c	30 Jul 2004 22:46:26 -0000
 @@ -290,7 +290,7 @@
  			return (EAFNOSUPPORT);
  #endif
  		if (sin->sin_addr.s_addr != INADDR_ANY)
 -			if (prison_ip(cred, 0, &sin->sin_addr.s_addr))
 +			if (prison_redirect_ip4(cred, &sin->sin_addr)) 
  				return(EINVAL);
  		if (sin->sin_port != *lportp) {
  			/* Don't allow the port to change. */
 @@ -346,7 +346,7 @@
  				     t->inp_socket->so_cred->cr_uid))
  					return (EADDRINUSE);
  			}
 -			if (prison && prison_ip(cred, 0, &sin->sin_addr.s_addr))
 +			if (prison && prison_redirect_ip4(cred, &sin->sin_addr)) 
  				return (EADDRNOTAVAIL);
  			t = in_pcblookup_local(pcbinfo, sin->sin_addr,
  			    lport, prison ? 0 : wild);
 @@ -375,7 +375,7 @@
  		int count;
  
  		if (laddr.s_addr != INADDR_ANY)
 -			if (prison_ip(cred, 0, &laddr.s_addr))
 +			if (prison_redirect_ip4(cred, &laddr)) 
  				return (EINVAL);
  
  		if (inp->inp_flags & INP_HIGHPORT) {
 @@ -438,7 +438,7 @@
  			    wild));
  		}
  	}
 -	if (prison_ip(cred, 0, &laddr.s_addr))
 +	if (prison_redirect_ip4(cred, &laddr)) 
  		return (EINVAL);
  	*laddrp = laddr.s_addr;
  	*lportp = lport;
 @@ -545,7 +545,9 @@
  	socred = inp->inp_socket->so_cred;
  	if (laddr.s_addr == INADDR_ANY && jailed(socred)) {
  		bzero(&sa, sizeof(sa));
 -		sa.sin_addr.s_addr = htonl(prison_getip(socred));
 +		error = prison_first_ip4(socred, &sa.sin_addr);
 +		if (error)
 +			return (error);
  		sa.sin_len = sizeof(sa);
  		sa.sin_family = AF_INET;
  		error = in_pcbbind_setup(inp, (struct sockaddr *)&sa,
 Index: sys/netinet/raw_ip.c
 ===================================================================
 RCS file: /usr/freebsd.cvs/src/sys/netinet/raw_ip.c,v
 retrieving revision 1.137
 diff -u -r1.137 raw_ip.c
 --- sys/netinet/raw_ip.c	26 Jul 2004 07:24:03 -0000	1.137
 +++ sys/netinet/raw_ip.c	30 Jul 2004 22:46:26 -0000
 @@ -213,9 +213,9 @@
  		if (inp->inp_faddr.s_addr &&
                      inp->inp_faddr.s_addr != ip->ip_src.s_addr)
  			goto docontinue;
 +		
  		if (jailed(inp->inp_socket->so_cred))
 -			if (htonl(prison_getip(inp->inp_socket->so_cred)) !=
 -			    ip->ip_dst.s_addr)
 +			if (prison_match_ip4(inp->inp_socket->so_cred, &(ip->ip_dst))) 
  				goto docontinue;
  		if (last) {
  			struct mbuf *n;
 @@ -272,8 +272,16 @@
  		ip->ip_p = inp->inp_ip_p;
  		ip->ip_len = m->m_pkthdr.len;
  		if (jailed(inp->inp_socket->so_cred))
 -			ip->ip_src.s_addr =
 -			    htonl(prison_getip(inp->inp_socket->so_cred));
 +		{
 +			/* fallback to first ip */
 +			if (prison_match_ip4(inp->inp_socket->so_cred, &inp->inp_laddr)) {
 +				if ((error = prison_first_ip4(inp->inp_socket->so_cred, 
 +					                     &ip->ip_src)) != 0)
 +					return error;
 +			}
 +			else
 +				ip->ip_src = inp->inp_laddr;
 +		}
  		else
  			ip->ip_src = inp->inp_laddr;
  		ip->ip_dst.s_addr = dst;
 @@ -286,8 +294,7 @@
  		INP_LOCK(inp);
  		ip = mtod(m, struct ip *);
  		if (jailed(inp->inp_socket->so_cred)) {
 -			if (ip->ip_src.s_addr !=
 -			    htonl(prison_getip(inp->inp_socket->so_cred))) {
 +			if (prison_match_ip4(inp->inp_socket->so_cred, &ip->ip_src)) {
  				INP_UNLOCK(inp);
  				m_freem(m);
  				return (EPERM);
 @@ -658,10 +665,11 @@
  		return EINVAL;
  
  	if (jailed(td->td_ucred)) {
 +		int error;
  		if (addr->sin_addr.s_addr == INADDR_ANY)
 -			addr->sin_addr.s_addr =
 -			    htonl(prison_getip(td->td_ucred));
 -		if (htonl(prison_getip(td->td_ucred)) != addr->sin_addr.s_addr)
 +			if ((error = prison_first_ip4(td->td_ucred, &addr->sin_addr)) != 0)
 +				return error;
 +		if (prison_match_ip4(td->td_ucred, &addr->sin_addr)) 
  			return (EADDRNOTAVAIL);
  	}
  
 Index: sys/netinet/tcp_usrreq.c
 ===================================================================
 RCS file: /usr/freebsd.cvs/src/sys/netinet/tcp_usrreq.c,v
 retrieving revision 1.105
 diff -u -r1.105 tcp_usrreq.c
 --- sys/netinet/tcp_usrreq.c	26 Jul 2004 21:29:56 -0000	1.105
 +++ sys/netinet/tcp_usrreq.c	30 Jul 2004 22:46:27 -0000
 @@ -357,7 +357,7 @@
  	    && IN_MULTICAST(ntohl(sinp->sin_addr.s_addr)))
  		return (EAFNOSUPPORT);
  	if (td && jailed(td->td_ucred))
 -		prison_remote_ip(td->td_ucred, 0, &sinp->sin_addr.s_addr);
 +		prison_remote_ip4(td->td_ucred, &sinp->sin_addr); 
  
  	COMMON_START();
  	if ((error = tcp_connect(tp, nam, td)) != 0)
 @@ -386,6 +386,9 @@
  	    && IN6_IS_ADDR_MULTICAST(&sin6p->sin6_addr))
  		return (EAFNOSUPPORT);
  
 +	if (td && jailed(td->td_ucred))
 +		prison_remote_ip6(td->td_ucred, &sin6p->sin6_addr); 
 +
  	COMMON_START();
  	if (IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) {
  		struct sockaddr_in sin;
 Index: sys/netinet/udp_usrreq.c
 ===================================================================
 RCS file: /usr/freebsd.cvs/src/sys/netinet/udp_usrreq.c,v
 retrieving revision 1.157
 diff -u -r1.157 udp_usrreq.c
 --- sys/netinet/udp_usrreq.c	26 Jul 2004 07:24:03 -0000	1.157
 +++ sys/netinet/udp_usrreq.c	30 Jul 2004 22:46:27 -0000
 @@ -806,7 +806,7 @@
  	if (addr) {
  		sin = (struct sockaddr_in *)addr;
  		if (td && jailed(td->td_ucred))
 -			prison_remote_ip(td->td_ucred, 0, &sin->sin_addr.s_addr);
 +			prison_remote_ip4(td->td_ucred, &sin->sin_addr); 
  		if (inp->inp_faddr.s_addr != INADDR_ANY) {
  			error = EISCONN;
  			goto release;
 @@ -1002,7 +1002,7 @@
  	s = splnet();
  	sin = (struct sockaddr_in *)nam;
  	if (td && jailed(td->td_ucred))
 -		prison_remote_ip(td->td_ucred, 0, &sin->sin_addr.s_addr);
 +		prison_remote_ip4(td->td_ucred, &sin->sin_addr);
  	error = in_pcbconnect(inp, nam, td->td_ucred);
  	splx(s);
  	if (error == 0)
 Index: sys/netinet6/in6_pcb.c
 ===================================================================
 RCS file: /usr/freebsd.cvs/src/sys/netinet6/in6_pcb.c,v
 retrieving revision 1.57
 diff -u -r1.57 in6_pcb.c
 --- sys/netinet6/in6_pcb.c	28 Jul 2004 13:03:07 -0000	1.57
 +++ sys/netinet6/in6_pcb.c	31 Jul 2004 07:38:54 -0000
 @@ -128,6 +128,7 @@
  	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)NULL;
  	struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
  	u_short	lport = 0;
 +	int prison = 0;
  	int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
  
  	INP_INFO_WLOCK_ASSERT(pcbinfo);
 @@ -149,6 +150,10 @@
  		if (nam->sa_family != AF_INET6)
  			return (EAFNOSUPPORT);
  
 +		if (!IN6_ARE_ADDR_EQUAL(&in6addr_any, &sin6->sin6_addr)) 
 +			if (prison_redirect_ip6(cred, &sin6->sin6_addr)) 
 +				return (EINVAL);
 +
  		/* KAME hack: embed scopeid */
  		if (in6_embedscope(&sin6->sin6_addr, sin6, inp, NULL) != 0)
  			return EINVAL;
 @@ -192,12 +197,20 @@
  			if (ntohs(lport) < IPV6PORT_RESERVED &&
  			    suser_cred(cred, SUSER_ALLOWJAIL))
  				return (EACCES);
 +			prison = jailed(cred); 
  			if (so->so_cred->cr_uid != 0 &&
  			    !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
  				t = in6_pcblookup_local(pcbinfo,
  				    &sin6->sin6_addr, lport,
 -				    INPLOOKUP_WILDCARD);
 -				if (t &&
 +				    prison ? 0 : INPLOOKUP_WILDCARD);
 +				if (t && (t->inp_vflag & INP_TIMEWAIT)) {
 +					if ((!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) ||
 +					    !IN6_IS_ADDR_UNSPECIFIED(&t->in6p_laddr) ||
 +					    !(intotw(t)->tw_so_options & SO_REUSEPORT))
 +					    && so->so_cred->cr_uid != 
 +					    intotw(t)->tw_cred->cr_uid)
 +						return (EADDRINUSE);
 +				} else if (t &&
  				    ((t->inp_vflag & INP_TIMEWAIT) == 0) &&
  				    (so->so_type != SOCK_STREAM ||
  				     IN6_IS_ADDR_UNSPECIFIED(&t->in6p_faddr)) &&
 @@ -226,8 +239,10 @@
  						return (EADDRINUSE);
  				}
  			}
 +			if (prison && prison_redirect_ip6(cred, &sin6->sin6_addr))
 +				return (EADDRNOTAVAIL);
  			t = in6_pcblookup_local(pcbinfo, &sin6->sin6_addr,
 -						lport, wild);
 +						lport, prison ? 0 : wild);
  			if (t && (reuseport & ((t->inp_vflag & INP_TIMEWAIT) ?
  			    intotw(t)->tw_so_options : 
  			    t->inp_socket->so_options)) == 0)
 Index: sys/netinet6/raw_ip6.c
 ===================================================================
 RCS file: /usr/freebsd.cvs/src/sys/netinet6/raw_ip6.c,v
 retrieving revision 1.43
 diff -u -r1.43 raw_ip6.c
 --- sys/netinet6/raw_ip6.c	27 Jul 2004 23:45:19 -0000	1.43
 +++ sys/netinet6/raw_ip6.c	31 Jul 2004 07:41:50 -0000
 @@ -68,6 +68,7 @@
  #include <sys/lock.h>
  #include <sys/malloc.h>
  #include <sys/mbuf.h>
 +#include <sys/jail.h>
  #include <sys/proc.h>
  #include <sys/protosw.h>
  #include <sys/signalvar.h>
 @@ -174,6 +175,11 @@
  				goto docontinue;
  			}
  		}
 +
 +		if (jailed(in6p->in6p_socket->so_cred))
 +			if (prison_match_ip6(in6p->in6p_socket->so_cred, &(ip6->ip6_dst)))
 +				continue;
 +
  		if (last) {
  			struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
  
 @@ -428,7 +434,20 @@
  			error = EADDRNOTAVAIL;
  		goto bad;
  	}
 -	ip6->ip6_src = *in6a;
 +	if (jailed(in6p->in6p_socket->so_cred))
 +	{
 +		/* fallback to first ip */
 +		if (prison_match_ip6(in6p->in6p_socket->so_cred, in6a)) {
 +			if ((error = prison_first_ip6(in6p->in6p_socket->so_cred, 
 +				&ip6->ip6_src)) != 0)
 +				return error;
 +		}
 +		else
 +			ip6->ip6_src = *in6a;
 +	}
 +	else
 +		ip6->ip6_src = *in6a;
 +
  	ip6->ip6_flow = (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) |
  		(in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK);
  	ip6->ip6_vfc = (ip6->ip6_vfc & ~IPV6_VERSION_MASK) |
 @@ -573,6 +592,10 @@
  		INP_INFO_WUNLOCK(&ripcbinfo);
  		return error;
  	}
 +	if (td && jailed(td->td_ucred) && !jail_allow_raw_sockets) {
 +		return (EPERM);
 +	}
 +
  	error = soreserve(so, rip_sendspace, rip_recvspace);
  	if (error) {
  		INP_INFO_WUNLOCK(&ripcbinfo);
 @@ -650,6 +673,16 @@
  
  	if (nam->sa_len != sizeof(*addr))
  		return EINVAL;
 +
 +	if (jailed(td->td_ucred)) {
 +		if (IN6_ARE_ADDR_EQUAL(&(addr->sin6_addr), &in6addr_any)) {
 +			int error;
 +			if ((error = prison_first_ip6(td->td_ucred, &addr->sin6_addr)) != 0)
 +				return error;
 +		}
 +		if (prison_match_ip6(td->td_ucred, &addr->sin6_addr)) 
 +			return (EADDRNOTAVAIL);
 +	}
  	if (TAILQ_EMPTY(&ifnet) || addr->sin6_family != AF_INET6)
  		return EADDRNOTAVAIL;
  #ifdef ENABLE_DEFAULT_SCOPE
 Index: sys/netinet6/udp6_output.c
 ===================================================================
 RCS file: /usr/freebsd.cvs/src/sys/netinet6/udp6_output.c,v
 retrieving revision 1.18
 diff -u -r1.18 udp6_output.c
 --- sys/netinet6/udp6_output.c	7 Apr 2004 20:46:16 -0000	1.18
 +++ sys/netinet6/udp6_output.c	14 Jul 2004 18:48:13 -0000
 @@ -67,6 +67,7 @@
  
  #include <sys/param.h>
  #include <sys/proc.h>
 +#include <sys/jail.h>
  #include <sys/malloc.h>
  #include <sys/mbuf.h>
  #include <sys/protosw.h>
 @@ -166,6 +167,8 @@
  			error = EISCONN;
  			goto release;
  		}
 +		if (td && jailed(td->td_ucred))
 +			prison_remote_ip6(td->td_ucred, &sin6->sin6_addr); 
  
  		/* protect *sin6 from overwrites */
  		tmp = *sin6;
 Index: sys/netinet6/udp6_usrreq.c
 ===================================================================
 RCS file: /usr/freebsd.cvs/src/sys/netinet6/udp6_usrreq.c,v
 retrieving revision 1.50
 diff -u -r1.50 udp6_usrreq.c
 --- sys/netinet6/udp6_usrreq.c	27 Jul 2004 23:45:19 -0000	1.50
 +++ sys/netinet6/udp6_usrreq.c	30 Jul 2004 22:46:27 -0000
 @@ -67,6 +67,7 @@
  
  #include <sys/param.h>
  #include <sys/errno.h>
 +#include <sys/jail.h>
  #include <sys/kernel.h>
  #include <sys/lock.h>
  #include <sys/mbuf.h>
 @@ -604,6 +605,7 @@
  {
  	struct inpcb *inp;
  	int s, error;
 +	struct sockaddr_in6 *sin6_p;
  
  	INP_INFO_WLOCK(&udbinfo);
  	inp = sotoinpcb(so);
 @@ -614,8 +616,6 @@
  	INP_LOCK(inp);
  
  	if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
 -		struct sockaddr_in6 *sin6_p;
 -
  		sin6_p = (struct sockaddr_in6 *)nam;
  		if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
  			struct sockaddr_in sin;
 @@ -640,6 +640,10 @@
  		goto out;
  	}
  	s = splnet();
 +	sin6_p = (struct sockaddr_in6 *)nam;
 +	if (td && jailed(td->td_ucred))
 +		prison_remote_ip6(td->td_ucred, &sin6_p->sin6_addr); 
 +
  	error = in6_pcbconnect(inp, nam, td->td_ucred);
  	splx(s);
  	if (error == 0) {
 Index: sys/nfsclient/nfs_vfsops.c
 ===================================================================
 RCS file: /usr/freebsd.cvs/src/sys/nfsclient/nfs_vfsops.c,v
 retrieving revision 1.157
 diff -u -r1.157 nfs_vfsops.c
 --- sys/nfsclient/nfs_vfsops.c	28 Jul 2004 20:21:04 -0000	1.157
 +++ sys/nfsclient/nfs_vfsops.c	30 Jul 2004 22:46:29 -0000
 @@ -507,6 +507,7 @@
  	mp->mnt_kern_flag = 0;
  	mp->mnt_flag = mountflag;
  	nam = sodupsockaddr((struct sockaddr *)sin, M_WAITOK);
 +	args->flags|=NFSMNT_NOLOCKD;
  	if ((error = mountnfs(args, mp, nam, which, path, vpp,
  	    td->td_ucred)) != 0) {
  		printf("nfs_mountroot: mount %s on %s: %d", path, which, error);
 Index: sys/sys/jail.h
 ===================================================================
 RCS file: /usr/freebsd.cvs/src/sys/sys/jail.h,v
 retrieving revision 1.21
 diff -u -r1.21 jail.h
 --- sys/sys/jail.h	26 Apr 2004 19:46:52 -0000	1.21
 +++ sys/sys/jail.h	14 Jul 2004 18:36:05 -0000
 @@ -6,18 +6,59 @@
   * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
   * ----------------------------------------------------------------------------
   *
 - * $FreeBSD$
 + * $FreeBSD: src/sys/sys/jail.h,v 1.18 2003/04/09 02:55:18 mike Exp $
   *
   */
  
  #ifndef _SYS_JAIL_H_
  #define _SYS_JAIL_H_
  
 +#include <netinet/in.h>
 +
 +/*
 + * to safe a system call i reuse the jail systemcall to 
 + * to modify a jail. I will enable the ability to add
 + * and remove ip4/6 numbers to a jail.
 + * To get rid of it i playing around with version and 
 + * function numbers.
 + * A jail id is only create on setup path and hostname
 + * these values are inmutable. The function number is
 + * CREATEJAIL
 + */
  struct jail {
 -	u_int32_t	version;
 -	char		*path;
 -	char		*hostname;
 -	u_int32_t	ip_number;
 +	u_int32_t       version;
 +	union {
 +	struct v1_s {
 +		char            *path;
 +		char            *hostname;
 +		u_int32_t       ip_number;
 +	} v1;
 +	struct v2_s {
 +		u_int32_t       function;
 +	#define CREATEJAIL 1
 +	#define ADDIP4 2
 +	#define DELIP4 3
 +	#define ADDIP6 4
 +	#define DELIP6 5
 +		union
 +		{
 +			struct 
 +			{
 +				char		*path;
 +				char		*hostname;
 +			} createjail;
 +			struct 
 +			{
 +				int id;
 +				union 
 +				{
 +					struct in_addr 	ip4_num;
 +					struct in6_addr ip6_num;
 +				} v4_6;
 +			} add_del;
 +		} u;
 +	} v2;
 +	} u;
  };
  
  struct xprison {
 @@ -25,9 +66,12 @@
  	int		 pr_id;
  	char		 pr_path[MAXPATHLEN];
  	char 		 pr_host[MAXHOSTNAMELEN];
 -	u_int32_t	 pr_ip;
 +	int		 pr4_id;
 +	struct in_addr 	 pr4_num; /* null is empty */
 +	int		 pr6_id;
 +	struct in6_addr  pr6_num; /* null is empty */
  };
 -#define	XPRISON_VERSION	1
 +#define	XPRISON_VERSION	6
  
  #ifndef _KERNEL
  
 @@ -37,9 +81,9 @@
  #else /* _KERNEL */
  
  #include <sys/queue.h>
 +#include <sys/_task.h>
  #include <sys/_lock.h>
  #include <sys/_mutex.h>
 -#include <sys/_task.h>
  
  #define JAIL_MAX	999999
  
 @@ -55,10 +99,12 @@
   * Lock key:
   *   (a) allprison_mutex
   *   (p) locked by pr_mutex
 + *   (d) set only during destruction of jail, no mutex needed
   *   (c) set only during creation before the structure is shared, no mutex
   *       required to read
 - *   (d) set only during destruction of jail, no mutex needed
   */
 +
 +struct mtx;
  struct prison {
  	LIST_ENTRY(prison) pr_list;			/* (a) all prisons */
  	int		 pr_id;				/* (c) prison id */
 @@ -66,10 +112,13 @@
  	char		 pr_path[MAXPATHLEN];		/* (c) chroot path */
  	struct vnode	*pr_root;			/* (c) vnode to rdir */
  	char 		 pr_host[MAXHOSTNAMELEN];	/* (p) jail hostname */
 -	u_int32_t	 pr_ip;				/* (c) ip addr host */
 +	int		 pr_ip4s; 			/* (p) ipv4 addr count */
 +	struct in_addr	*pr_ip4;			/* (p) ipv4 addr host */
 +	int		 pr_ip6s; 			/* (p) ipv6 addr count */
 +	struct in6_addr *pr_ip6;			/* (p) ipv6 addr host */
 +        struct task      pr_task;                       /* (d) destroy task */
  	void		*pr_linux;			/* (p) linux abi */
  	int		 pr_securelevel;		/* (p) securelevel */
 -	struct task	 pr_task;			/* (d) destroy task */
  	struct mtx	 pr_mtx;
  };
  
 @@ -78,11 +127,11 @@
   *
   * XXX MIB entries will need to be protected by a mutex.
   */
 +extern int      jail_getfsstat_jailrootonly;
 +extern int      jail_allow_raw_sockets;
  extern int	jail_set_hostname_allowed;
  extern int	jail_socket_unixiproute_only;
  extern int	jail_sysvipc_allowed;
 -extern int	jail_getfsstat_jailrootonly;
 -extern int	jail_allow_raw_sockets;
  
  LIST_HEAD(prisonlist, prison);
  extern struct	prisonlist allprison;
 @@ -91,18 +140,24 @@
   * Kernel support functions for jail().
   */
  struct ucred;
 -struct mount;
  struct sockaddr;
 +struct mount;
  int jailed(struct ucred *cred);
  void getcredhostname(struct ucred *cred, char *, size_t);
 -int prison_check(struct ucred *cred1, struct ucred *cred2);
  int prison_check_mount(struct ucred *cred, struct mount *mp);
 +int prison_check(struct ucred *cred1, struct ucred *cred2);
  void prison_free(struct prison *pr);
 -u_int32_t prison_getip(struct ucred *cred);
 +int  prison_first_ip6(struct ucred *cred, struct in6_addr *out); 
 +int  prison_first_ip4(struct ucred *cred, struct in_addr *out); 
 +int  prison_match_ip4(struct ucred *cred, struct in_addr *in); 
 +int  prison_match_ip6(struct ucred *cred, struct in6_addr *in); 
  void prison_hold(struct prison *pr);
  int prison_if(struct ucred *cred, struct sockaddr *sa);
 -int prison_ip(struct ucred *cred, int flag, u_int32_t *ip);
 -void prison_remote_ip(struct ucred *cred, int flags, u_int32_t *ip);
 +int prison_redirect_ip4(struct ucred *cred, struct in_addr *ip);
 +int prison_redirect_ip6(struct ucred *cred, struct in6_addr *ip);
 +void prison_remote_ip4(struct ucred *cred, struct in_addr *ip);
 +void prison_remote_ip6(struct ucred *cred, struct in6_addr *ip);
 +
  
  #endif /* !_KERNEL */
  #endif /* !_SYS_JAIL_H_ */
 


More information about the freebsd-bugs mailing list