From abels@adviser.com  Wed Jul 14 19:21:42 2004
Return-Path: <abels@adviser.com>
Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125])
	by hub.freebsd.org (Postfix) with ESMTP id DCCF116A4CE
	for <FreeBSD-gnats-submit@freebsd.org>; Wed, 14 Jul 2004 19:21:42 +0000 (GMT)
Received: from pmff.de (pmff.de [217.160.223.88])
	by mx1.FreeBSD.org (Postfix) with ESMTP id 3E4B843D60
	for <FreeBSD-gnats-submit@freebsd.org>; Wed, 14 Jul 2004 19:21:41 +0000 (GMT)
	(envelope-from abels@adviser.com)
Received: from mabels.dyndns.org (p213.54.126.95.tisdip.tiscali.de [213.54.126.95])
	(using TLSv1 with cipher EDH-RSA-DES-CBC3-SHA (168/168 bits))
	(No client certificate requested)
	by pmff.de (Postfix) with ESMTP id A623484040
	for <FreeBSD-gnats-submit@freebsd.org>; Wed, 14 Jul 2004 21:21:37 +0200 (CEST)
Received: from race.abels.adviser.com ([192.168.74.103])
	by mabels.dyndns.org with smtp (Exim 4.34; FreeBSD)
	id 1BkpJq-000A1R-Vw; Wed, 14 Jul 2004 21:21:31 +0200
Received: by race.abels.adviser.com (sSMTP sendmail emulation); Wed, 14 Jul 2004 21:21:30 +0200
Message-Id: <20040714192137.A623484040@pmff.de>
Date: Wed, 14 Jul 2004 21:21:30 +0200
From: "Meno Abels" <abels@adviser.com>
Reply-To: Meno Abels <abels@adviser.com>
To: FreeBSD-gnats-submit@freebsd.org
Cc: Meno Abels <abels@adviser.com>
Subject: No multiple ip4/6's could assigned to a jail.
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         69064
>Category:       kern
>Synopsis:       [jail] [patch] Allow multiple ip4/6's to be assigned to a jail.
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    linimon
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Wed Jul 14 19:30:32 GMT 2004
>Closed-Date:    Mon Jul 23 03:34:49 GMT 2007
>Last-Modified:  Mon Jul 23 03:34:49 GMT 2007
>Originator:     Meno Abels
>Release:        FreeBSD 5.2-CURRENT
>Organization:
Adviser.com
>Environment:
System: FreeBSD race 5.2-CURRENT FreeBSD 5.2-CURRENT #29: Fri May 28 23:44:16 CEST 2004 root@neo.abels.adviser.com:/usr/obj/usr/src/sys/DISKLESS i386

>Description:
	I missed the feature that a jail is able to handle multiple ip
        numbers. Also i want that ipv6 is working with the jail.
>How-To-Repeat:
	no way
>Fix:
	Here is the patch for this feature. 
	I tested it, but I'am not very safe about the ipv6 stuff. 
	I'am not a expert in ipv6 so it could be that
        i missed some checks for the prison. I also change the 
	jail/jls utility.  


Index: sys/kern/kern_fork.c
===================================================================
RCS file: /usr/freebsd.cvs/src/sys/kern/kern_fork.c,v
retrieving revision 1.228
diff -r1.228 kern_fork.c
303c303
< 	if ((nprocs >= maxproc - 10 && suser(td->td_ucred) != 0) ||
---
> 	if ((nprocs >= maxproc - 10 && suser(td) != 0) ||
Index: sys/kern/kern_jail.c
===================================================================
RCS file: /usr/freebsd.cvs/src/sys/kern/kern_jail.c,v
retrieving revision 1.44
diff -r1.44 kern_jail.c
35a36
> #include <netinet6/in6_var.h>
37a39,40
> MALLOC_DEFINE(M_PRISON_IP4, "prison", "Prison ipv4 addresses");
> MALLOC_DEFINE(M_PRISON_IP6, "prison", "Prison ipv6 addresses");
77a81,85
> 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);
98,99c106,107
< 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)
100a109
> 	int error;
102,105d110
< 	struct prison *pr, *tpr;
< 	struct jail j;
< 	struct jail_attach_args jaa;
< 	int error, tryprid;
107c112,115
< 	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);
109,116c117,118
< 		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);
118a121,125
> 	if (prison_check_duplicate((*pr)->pr_host, (*pr)->pr_path)) {
> 		error = EAGAIN;
> 		goto e_killmtx;
> 	}
> 
120c127
< 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, pr->pr_path, td);
---
> 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, (*pr)->pr_path, td);
126c133
< 	pr->pr_root = nd.ni_vp;
---
> 	(*pr)->pr_root = nd.ni_vp;
130,135d136
< 	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;
136a138,278
> 	(*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 */
149c291,292
< 				goto e_dropvnref;
---
> 				jail_dropvnref(pr);
> 				return error;
166a310
> 
172,178c316
< 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);
250a389,414
> /* 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;
> }
> 
> 
301a466,469
> 	if (pr->pr_ip4 != NULL)
> 		FREE(pr->pr_ip4, M_PRISON_IP4);
> 	if (pr->pr_ip6 != NULL)
> 		FREE(pr->pr_ip6, M_PRISON_IP6);
316,317c484,485
< u_int32_t
< prison_getip(struct ucred *cred)
---
> int
> prison_first_ip4(struct ucred *cred, struct in_addr *out)
318a487,495
> 	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;
> }
320c497,507
< 	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;
324c511
< prison_ip(struct ucred *cred, int flag, u_int32_t *ip)
---
> prison_match_ip4(struct ucred *cred, struct in_addr *ip)
330,345c517,537
< 	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];
348,350c540,544
< 	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);
353,354c547,548
< void
< prison_remote_ip(struct ucred *cred, int flag, u_int32_t *ip)
---
> int
> prison_match_ip6(struct ucred *cred, struct in6_addr *ip)
358a553,588
> 		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))
360,368c590,607
< 	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];
377,378c616
< 	struct sockaddr_in *sai;
< 	int ok;
---
> 	int ok = 0;
380,381c618,619
< 	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)
383,388c621,652
< 	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;
> 				}
> 			}
> 		}
> 	}
409a674,805
>  * 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;	
> }
> 
> 
> /*
454a851
> 	int prcount;
461c858,868
< 	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;
> 		}
> 	}
466a874
> 	/*printf("jls:count=%d:%d\n", count, prcount);*/
469c877
< 	if (count != prisoncount) {
---
> 	if (prcount != prisoncount) {
476,483c884,911
< 		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++;
> 		}
Index: sys/net/rtsock.c
===================================================================
RCS file: /usr/freebsd.cvs/src/sys/net/rtsock.c,v
retrieving revision 1.112
diff -r1.112 rtsock.c
325c325,326
< 	struct sockaddr_in jail;
---
> 	struct sockaddr_in  jail4;
> 	struct sockaddr_in6 jail6;
440,446c441,466
< 						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;
> 						}
Index: sys/netinet/in_pcb.c
===================================================================
RCS file: /usr/freebsd.cvs/src/sys/netinet/in_pcb.c,v
retrieving revision 1.150
diff -r1.150 in_pcb.c
293c293
< 			if (prison_ip(cred, 0, &sin->sin_addr.s_addr))
---
> 			if (prison_redirect_ip4(cred, &sin->sin_addr)) 
358c358
< 			if (prison && prison_ip(cred, 0, &sin->sin_addr.s_addr))
---
> 			if (prison && prison_redirect_ip4(cred, &sin->sin_addr)) 
387c387
< 			if (prison_ip(cred, 0, &laddr.s_addr))
---
> 			if (prison_redirect_ip4(cred, &laddr)) 
450c450
< 	if (prison_ip(cred, 0, &laddr.s_addr))
---
> 	if (prison_redirect_ip4(cred, &laddr)) 
557c557,559
< 		sa.sin_addr.s_addr = htonl(prison_getip(socred));
---
> 		error = prison_first_ip4(socred, &sa.sin_addr);
> 		if (error)
> 			return (error);
Index: sys/netinet/raw_ip.c
===================================================================
RCS file: /usr/freebsd.cvs/src/sys/netinet/raw_ip.c,v
retrieving revision 1.135
diff -r1.135 raw_ip.c
215a216
> 		
217,218c218
< 			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))) 
275,276c275,284
< 			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;
> 		}
289,290c297
< 			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)) {
660a668
> 		int error;
662,664c670,672
< 			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)) 
Index: sys/netinet/tcp_usrreq.c
===================================================================
RCS file: /usr/freebsd.cvs/src/sys/netinet/tcp_usrreq.c,v
retrieving revision 1.103
diff -r1.103 tcp_usrreq.c
359c359
< 		prison_remote_ip(td->td_ucred, 0, &sinp->sin_addr.s_addr);
---
> 		prison_remote_ip4(td->td_ucred, &sinp->sin_addr); 
386a387,389
> 
> 	if (td && jailed(td->td_ucred))
> 		prison_remote_ip6(td->td_ucred, &sin6p->sin6_addr); 
Index: sys/netinet/udp_usrreq.c
===================================================================
RCS file: /usr/freebsd.cvs/src/sys/netinet/udp_usrreq.c,v
retrieving revision 1.156
diff -r1.156 udp_usrreq.c
809c809
< 			prison_remote_ip(td->td_ucred, 0, &sin->sin_addr.s_addr);
---
> 			prison_remote_ip4(td->td_ucred, &sin->sin_addr); 
1005c1005
< 		prison_remote_ip(td->td_ucred, 0, &sin->sin_addr.s_addr);
---
> 		prison_remote_ip4(td->td_ucred, &sin->sin_addr);
Index: sys/netinet6/in6_pcb.c
===================================================================
RCS file: /usr/freebsd.cvs/src/sys/netinet6/in6_pcb.c,v
retrieving revision 1.52
diff -r1.52 in6_pcb.c
130a131
> 	int prison = 0;
148a150,153
> 		if (!IN6_ARE_ADDR_EQUAL(&in6addr_any, &sin6->sin6_addr)) 
> 			if (prison_redirect_ip6(cred, &sin6->sin6_addr)) 
> 				return (EINVAL);
> 
191a197
> 			prison = jailed(cred); 
196c202
< 				    INPLOOKUP_WILDCARD);
---
> 				    prison ? 0 : INPLOOKUP_WILDCARD);
238a245,246
> 			if (prison && prison_redirect_ip6(cred, &sin6->sin6_addr))
> 				return (EADDRNOTAVAIL);
240c248
< 						lport, wild);
---
> 						lport, prison ? 0 : wild);
Index: sys/netinet6/raw_ip6.c
===================================================================
RCS file: /usr/freebsd.cvs/src/sys/netinet6/raw_ip6.c,v
retrieving revision 1.41
diff -r1.41 raw_ip6.c
70a71
> #include <sys/jail.h>
171a173,177
> 
> 		if (jailed(in6p->in6p_socket->so_cred))
> 			if (prison_match_ip6(in6p->in6p_socket->so_cred, &(ip6->ip6_dst)))
> 				continue;
> 
416c422,435
< 	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;
> 
555a575,578
> 	if (td && jailed(td->td_ucred) && !jail_allow_raw_sockets) {
> 		return (EPERM);
> 	}
> 
620a644,653
> 
> 	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);
> 	}
Index: sys/netinet6/udp6_output.c
===================================================================
RCS file: /usr/freebsd.cvs/src/sys/netinet6/udp6_output.c,v
retrieving revision 1.18
diff -r1.18 udp6_output.c
69a70
> #include <sys/jail.h>
168a170,171
> 		if (td && jailed(td->td_ucred))
> 			prison_remote_ip6(td->td_ucred, &sin6->sin6_addr); 
Index: sys/netinet6/udp6_usrreq.c
===================================================================
RCS file: /usr/freebsd.cvs/src/sys/netinet6/udp6_usrreq.c,v
retrieving revision 1.48
diff -r1.48 udp6_usrreq.c
69a70
> #include <sys/jail.h>
590a592
> 	struct sockaddr_in6 *sin6_p;
597,598d598
< 		struct sockaddr_in6 *sin6_p;
< 
620a621,624
> 	sin6_p = (struct sockaddr_in6 *)nam;
> 	if (td && jailed(td->td_ucred))
> 		prison_remote_ip6(td->td_ucred, &sin6_p->sin6_addr); 
> 
Index: sys/sys/jail.h
===================================================================
RCS file: /usr/freebsd.cvs/src/sys/sys/jail.h,v
retrieving revision 1.21
diff -r1.21 jail.h
9c9
<  * $FreeBSD$
---
>  * $FreeBSD: src/sys/sys/jail.h,v 1.18 2003/04/09 02:55:18 mike Exp $
15a16,27
> #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
>  */
17,20c29,61
< 	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;
28c69,72
< 	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 */
30c74
< #define	XPRISON_VERSION	1
---
> #define	XPRISON_VERSION	6
39a84
> #include <sys/_task.h>
42d86
< #include <sys/_task.h>
57a102
>  *   (d) set only during destruction of jail, no mutex needed
60d104
<  *   (d) set only during destruction of jail, no mutex needed
61a106,107
> 
> struct mtx;
69c115,119
< 	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 */
72d121
< 	struct task	 pr_task;			/* (d) destroy task */
80a130,131
> extern int      jail_getfsstat_jailrootonly;
> extern int      jail_allow_raw_sockets;
84,85d134
< extern int	jail_getfsstat_jailrootonly;
< extern int	jail_allow_raw_sockets;
94d142
< struct mount;
95a144
> struct mount;
98d146
< int prison_check(struct ucred *cred1, struct ucred *cred2);
99a148
> int prison_check(struct ucred *cred1, struct ucred *cred2);
101c150,153
< 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); 
104,105c156,160
< 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);
> 
Index: usr.sbin/jail/jail.8
===================================================================
RCS file: /usr/freebsd.cvs/src/usr.sbin/jail/jail.8,v
retrieving revision 1.57
diff -r1.57 jail.8
46c46,49
< .Ar path hostname ip-number command ...
---
> .Op Fl j Ar jail identifier
> .Op Fl a Ar ip4 or ip6 address
> .Op Fl d Ar ip4 or ip6 address
> .Ar path hostname [ip4|ip6] command ...
55c58
< Output the jail identifier of the newly created jail.
---
> Output the jail identifier of the newly created jail. Only valid without -j.
61c64,73
< The user name from jailed environment as whom the
---
> The user name from jailed environment as whom the. Only valid without -j.
> .It Fl j Ar jail identifier
> This options set the jail identifier which is modified with -a oder -d.
> The jail identifier could be retrieved with jls.
> .It Fl a Ar ip4 or ip6
> This options add the specified ip number to the jail that is give with -j. You
> can only have one -a per call. 
> .It Fl d Ar ip4 or ip6
> This options deletes the specified ip number from the jail that is give with -j.
> You can only have one -d per call.
69c81
< IP number assigned to the prison.
---
> IP4 or IP6 number assigned to the prison.
Index: usr.sbin/jail/jail.c
===================================================================
RCS file: /usr/freebsd.cvs/src/usr.sbin/jail/jail.c,v
retrieving revision 1.16
diff -r1.16 jail.c
15a16,17
> #include <sys/types.h>
> #include <sys/socket.h>
18a21
> 
53c56
< 	struct in_addr in;
---
> 	int jid = 0;
55a59,62
>         char *address;
>         int add = 0;
>         int del = 0;
> 
60c67
< 	while ((ch = getopt(argc, argv, "iu:U:")) != -1) {
---
> 	while ((ch = getopt(argc, argv, "iu:U:j:a:d:")) != -1) {
72a80,91
>                 case 'j':
>                         jid = atol(optarg);
>                         break;
>                 case 'a':
>                         add = 1;
>                         address = optarg;
>                         break;
>                 case 'd':
>                         del = 1;
>                         address = optarg;
>                         break;
> 
79c98,101
< 	if (argc < 4)
---
> 	if ((jid == 0 && argc < 4) ||
>             (jid < 1 && (add || del)) ||
>             (add && del) ||
>             (jid > 0 && !(add || del)))
80a103,122
>         if (jid > 0) {
> 		int function;
>                 if (inet_pton(AF_INET, address, &j.u.v2.u.add_del.v4_6.ip4_num) > 0) {
>                         function = add ? ADDIP4 : DELIP4;
>                 }
>                 else if (inet_pton(AF_INET6, address, &j.u.v2.u.add_del.v4_6.ip6_num) > 0) {
>                         function = add ? ADDIP6 : DELIP6;
>                 }
>                 else {
>                         err(1, "inet_pton: %s", address);
>                 }
> 		j.version = XPRISON_VERSION;
> 		j.u.v2.function = function;
> 		j.u.v2.u.add_del.id = jid;
> 		i = jail(&j);
> 		if (i == -1)
> 			err(1, "jail(%d)", function);
>                 exit (0);
>         }
> 
90,95c132,148
< 	j.version = 0;
< 	j.path = path;
< 	j.hostname = argv[1];
< 	if (inet_aton(argv[2], &in) == 0)
< 		errx(1, "Could not make sense of ip-number: %s", argv[2]);
< 	j.ip_number = ntohl(in.s_addr);
---
> 	j.version = XPRISON_VERSION;
> 	j.u.v2.function = CREATEJAIL;
> 	j.u.v2.u.createjail.path     = path;
> 	j.u.v2.u.createjail.hostname = argv[1];
> 	jid = i = jail(&j);
> 	if (i == -1)
> 		err(1, "jail(CREATEJAIL)");
> 
> 	j.version = XPRISON_VERSION;
> 	j.u.v2.u.add_del.id = i;
> 	j.u.v2.function = ADDIP4;
> 	if (inet_pton(AF_INET, address, &j.u.v2.u.add_del.v4_6.ip4_num) <= 0) {
> 		j.u.v2.function = ADDIP6;
> 		if (inet_pton(AF_INET6, address, &j.u.v2.u.add_del.v4_6.ip6_num) <= 0) {
> 			errx(1, "Could not make sense of ip-number: %s", argv[2]);
> 		}
> 	}
98c151,152
< 		err(1, "jail");
---
> 		err(1, "jail(%d)", j.u.v2.function);
> 
100c154
< 		printf("%d\n", i);
---
> 		printf("%d\n", jid);
124,127c178,180
< 	(void)fprintf(stderr, "%s%s\n",
< 	     "usage: jail [-i] [-u username | -U username]",
< 	     " path hostname ip-number command ...");
< 	exit(1);
---
>         (void)fprintf(stderr,
>         "usage: jail [-i] [-u username] [-j id] [[-a [ip4|ip6]|[-d [ip4|ip6]] [path hostname [ip4|ip6] command ...]\n");
>         exit(1);
Index: usr.sbin/jls/jls.8
===================================================================
RCS file: /usr/freebsd.cvs/src/usr.sbin/jls/jls.8,v
retrieving revision 1.1
diff -r1.1 jls.8
35a36,37
> .Op Fl a
> .Op Fl 6
39a42,52
> .Pp
> The options are as follows:
> .Bl -tag -width ".Fl a "
> .It Fl a 
> output all ip4 assigments to the jail identifier(JID). Each ip4 gets
> one line in output. If no ip4 address is assigned 0.0.0.0 is the output.
> .It Fl 6 
> output ip6 address also a new column is generated between IP Address 
> and Hostname. If no ip6 address is assigned :: is the output.
> .El
> .Pp
Index: usr.sbin/jls/jls.c
===================================================================
RCS file: /usr/freebsd.cvs/src/usr.sbin/jls/jls.c,v
retrieving revision 1.3
diff -r1.3 jls.c
32a33,35
> #include <sys/types.h>
> #include <sys/socket.h>
> #include <netinet/in.h>
33a37
> 
38a43,53
> #include <unistd.h>
> 
> static int
> usage(void)
> {
> 	fprintf(stderr, "%s\n%s\n%s\n",
> 	     "usage: jls [-a] [-6]",
> 	     " -a output all jail assigned ip addresses",
> 	     " -6 output includes ipv6 addresses");
> 	exit(1);
> }
42c57
< main(void)
---
> main(int argc, char **argv)
45d59
< 	struct in_addr in;
46a61,78
> 	int allflag = 0;
> 	int ip6flag = 0;
> 	int ch;
> 
> 	while ((ch = getopt(argc, argv, "a6")) != -1) {
> 		switch (ch) {
> 		case 'a':
> 			allflag = 1;
> 			break;
> 		case '6':
> 			ip6flag = 1;
> 			break;
> 		default:
> 			usage();
> 		}
> 	}
> 	argc -= optind;
> 	argv += optind;
68c100,103
< 	printf("   JID  IP Address      Hostname                      Path\n");
---
> 	if (ip6flag)
> 		printf("   JID  IP4 Address     IP6 Address            Hostname                      Path\n");
> 	else
> 		printf("   JID  IP Address      Hostname                      Path\n");
70,72c105,119
< 		in.s_addr = ntohl(xp->pr_ip);
< 		printf("%6d  %-15.15s %-29.29s %.74s\n",
< 		    xp->pr_id, inet_ntoa(in), xp->pr_host, xp->pr_path);
---
> 		if (allflag || xp->pr4_id == 0) {
> 			if (ip6flag) {
> 				char buffer[128];
> 				printf("%6d  %-15.15s %-22.22s %-29.29s %.74s\n",
> 				    xp->pr_id, 
> 				    inet_ntoa(xp->pr4_num),
> 				    inet_ntop(AF_INET6, xp->pr6_num.s6_addr, buffer, sizeof(buffer)),
> 				    xp->pr_host, 
>                                     xp->pr_path);
> 			}
> 			else {
> 				printf("%6d  %-15.15s %-29.29s %.74s\n",
> 				    xp->pr_id, inet_ntoa(xp->pr4_num), xp->pr_host, xp->pr_path);
> 			}
> 		}

>Release-Note:
>Audit-Trail:

From: "Meno Abels" <abels@adviser.com>
To: FreeBSD-gnats-submit@freebsd.org
Cc: Max Laier <max@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_ */
 

From: "Meno Abels" <abels@adviser.com>
To: FreeBSD-gnats-submit@freebsd.org
Cc:  
Subject: Re: kern/69064: No multiple ip4/6's could assigned to a jail.
Date: Sat, 31 Jul 2004 10:35:21 +0200

 sorry I missed to convert the userland tools in the unified diff
 format. Here they are.
 
 regards 
 
 meno
 
 Index: usr.sbin/jail/jail.8
 ===================================================================
 RCS file: /usr/freebsd.cvs/src/usr.sbin/jail/jail.8,v
 retrieving revision 1.57
 diff -u -r1.57 jail.8
 --- usr.sbin/jail/jail.8	2 Jul 2004 23:12:45 -0000	1.57
 +++ usr.sbin/jail/jail.8	14 Jul 2004 19:09:14 -0000
 @@ -43,7 +43,10 @@
  .Nm
  .Op Fl i
  .Op Fl u Ar username | Fl U Ar username
 -.Ar path hostname ip-number command ...
 +.Op Fl j Ar jail identifier
 +.Op Fl a Ar ip4 or ip6 address
 +.Op Fl d Ar ip4 or ip6 address
 +.Ar path hostname [ip4|ip6] command ...
  .Sh DESCRIPTION
  The
  .Nm
 @@ -52,13 +55,22 @@
  The options are as follows:
  .Bl -tag -width ".Fl u Ar username"
  .It Fl i
 -Output the jail identifier of the newly created jail.
 +Output the jail identifier of the newly created jail. Only valid without -j.
  .It Fl u Ar username
  The user name from host environment as whom the
  .Ar command
  should run.
  .It Fl U Ar username
 -The user name from jailed environment as whom the
 +The user name from jailed environment as whom the. Only valid without -j.
 +.It Fl j Ar jail identifier
 +This options set the jail identifier which is modified with -a oder -d.
 +The jail identifier could be retrieved with jls.
 +.It Fl a Ar ip4 or ip6
 +This options add the specified ip number to the jail that is give with -j. You
 +can only have one -a per call. 
 +.It Fl d Ar ip4 or ip6
 +This options deletes the specified ip number from the jail that is give with -j.
 +You can only have one -d per call.
  .Ar command
  should run.
  .It Ar path
 @@ -66,7 +78,7 @@
  .It Ar hostname
  Hostname of the prison.
  .It Ar ip-number
 -IP number assigned to the prison.
 +IP4 or IP6 number assigned to the prison.
  .It Ar command
  Pathname of the program which is to be executed.
  .El
 Index: usr.sbin/jail/jail.c
 ===================================================================
 RCS file: /usr/freebsd.cvs/src/usr.sbin/jail/jail.c,v
 retrieving revision 1.16
 diff -u -r1.16 jail.c
 --- usr.sbin/jail/jail.c	27 Jun 2004 10:10:16 -0000	1.16
 +++ usr.sbin/jail/jail.c	14 Jul 2004 17:49:51 -0000
 @@ -13,9 +13,12 @@
  #include <sys/param.h>
  #include <sys/jail.h>
  
 +#include <sys/types.h>
 +#include <sys/socket.h>
  #include <netinet/in.h>
  #include <arpa/inet.h>
  
 +
  #include <err.h>
  #include <errno.h>
  #include <grp.h>
 @@ -50,14 +53,18 @@
  	login_cap_t *lcap;
  	struct jail j;
  	struct passwd *pwd;
 -	struct in_addr in;
 +	int jid = 0;
  	int ch, groups[NGROUPS], i, iflag, ngroups, uflag, Uflag;
  	char path[PATH_MAX], *username;
 +        char *address;
 +        int add = 0;
 +        int del = 0;
 +
  
  	iflag = uflag = Uflag = 0;
  	username = NULL;
  
 -	while ((ch = getopt(argc, argv, "iu:U:")) != -1) {
 +	while ((ch = getopt(argc, argv, "iu:U:j:a:d:")) != -1) {
  		switch (ch) {
  		case 'i':
  			iflag = 1;
 @@ -70,14 +77,49 @@
  			username = optarg;
  			Uflag = 1;
  			break;
 +                case 'j':
 +                        jid = atol(optarg);
 +                        break;
 +                case 'a':
 +                        add = 1;
 +                        address = optarg;
 +                        break;
 +                case 'd':
 +                        del = 1;
 +                        address = optarg;
 +                        break;
 +
  		default:
  			usage();
  		}
  	}
  	argc -= optind;
  	argv += optind;
 -	if (argc < 4)
 +	if ((jid == 0 && argc < 4) ||
 +            (jid < 1 && (add || del)) ||
 +            (add && del) ||
 +            (jid > 0 && !(add || del)))
  		usage();
 +        if (jid > 0) {
 +		int function;
 +                if (inet_pton(AF_INET, address, &j.u.v2.u.add_del.v4_6.ip4_num) > 0) {
 +                        function = add ? ADDIP4 : DELIP4;
 +                }
 +                else if (inet_pton(AF_INET6, address, &j.u.v2.u.add_del.v4_6.ip6_num) > 0) {
 +                        function = add ? ADDIP6 : DELIP6;
 +                }
 +                else {
 +                        err(1, "inet_pton: %s", address);
 +                }
 +		j.version = XPRISON_VERSION;
 +		j.u.v2.function = function;
 +		j.u.v2.u.add_del.id = jid;
 +		i = jail(&j);
 +		if (i == -1)
 +			err(1, "jail(%d)", function);
 +                exit (0);
 +        }
 +
  	if (uflag && Uflag)
  		usage();
  	if (uflag)
 @@ -87,17 +129,29 @@
  	if (chdir(path) != 0)
  		err(1, "chdir: %s", path);
  	memset(&j, 0, sizeof(j));
 -	j.version = 0;
 -	j.path = path;
 -	j.hostname = argv[1];
 -	if (inet_aton(argv[2], &in) == 0)
 -		errx(1, "Could not make sense of ip-number: %s", argv[2]);
 -	j.ip_number = ntohl(in.s_addr);
 +	j.version = XPRISON_VERSION;
 +	j.u.v2.function = CREATEJAIL;
 +	j.u.v2.u.createjail.path     = path;
 +	j.u.v2.u.createjail.hostname = argv[1];
 +	jid = i = jail(&j);
 +	if (i == -1)
 +		err(1, "jail(CREATEJAIL)");
 +
 +	j.version = XPRISON_VERSION;
 +	j.u.v2.u.add_del.id = i;
 +	j.u.v2.function = ADDIP4;
 +	if (inet_pton(AF_INET, address, &j.u.v2.u.add_del.v4_6.ip4_num) <= 0) {
 +		j.u.v2.function = ADDIP6;
 +		if (inet_pton(AF_INET6, address, &j.u.v2.u.add_del.v4_6.ip6_num) <= 0) {
 +			errx(1, "Could not make sense of ip-number: %s", argv[2]);
 +		}
 +	}
  	i = jail(&j);
  	if (i == -1)
 -		err(1, "jail");
 +		err(1, "jail(%d)", j.u.v2.function);
 +
  	if (iflag) {
 -		printf("%d\n", i);
 +		printf("%d\n", jid);
  		fflush(stdout);
  	}
  	if (username != NULL) {
 @@ -121,8 +175,7 @@
  usage(void)
  {
  
 -	(void)fprintf(stderr, "%s%s\n",
 -	     "usage: jail [-i] [-u username | -U username]",
 -	     " path hostname ip-number command ...");
 -	exit(1);
 +        (void)fprintf(stderr,
 +        "usage: jail [-i] [-u username] [-j id] [[-a [ip4|ip6]|[-d [ip4|ip6]] [path hostname [ip4|ip6] command ...]\n");
 +        exit(1);
  }
 Index: usr.sbin/jls/jls.8
 ===================================================================
 RCS file: /usr/freebsd.cvs/src/usr.sbin/jls/jls.8,v
 retrieving revision 1.1
 diff -u -r1.1 jls.8
 --- usr.sbin/jls/jls.8	9 Apr 2003 03:04:12 -0000	1.1
 +++ usr.sbin/jls/jls.8	14 Jul 2004 19:00:53 -0000
 @@ -33,10 +33,23 @@
  .Nd "list active jails"
  .Sh SYNOPSIS
  .Nm
 +.Op Fl a
 +.Op Fl 6
  .Sh DESCRIPTION
  The
  .Nm
  utility lists all active jails.
 +.Pp
 +The options are as follows:
 +.Bl -tag -width ".Fl a "
 +.It Fl a 
 +output all ip4 assigments to the jail identifier(JID). Each ip4 gets
 +one line in output. If no ip4 address is assigned 0.0.0.0 is the output.
 +.It Fl 6 
 +output ip6 address also a new column is generated between IP Address 
 +and Hostname. If no ip6 address is assigned :: is the output.
 +.El
 +.Pp
  Each jail is represented by one row which contains the following columns:
  jail identifier (JID), IP address, hostname, and path.
  .Sh SEE ALSO
 Index: usr.sbin/jls/jls.c
 ===================================================================
 RCS file: /usr/freebsd.cvs/src/usr.sbin/jls/jls.c,v
 retrieving revision 1.3
 diff -u -r1.3 jls.c
 --- usr.sbin/jls/jls.c	22 Apr 2003 13:24:56 -0000	1.3
 +++ usr.sbin/jls/jls.c	14 Jul 2004 08:37:32 -0000
 @@ -30,20 +30,52 @@
  #include <sys/jail.h>
  #include <sys/sysctl.h>
  
 +#include <sys/types.h>
 +#include <sys/socket.h>
 +#include <netinet/in.h>
  #include <arpa/inet.h>
 +
  #include <err.h>
  #include <errno.h>
  #include <limits.h>
  #include <stdio.h>
  #include <stdlib.h>
 +#include <unistd.h>
 +
 +static int
 +usage(void)
 +{
 +	fprintf(stderr, "%s\n%s\n%s\n",
 +	     "usage: jls [-a] [-6]",
 +	     " -a output all jail assigned ip addresses",
 +	     " -6 output includes ipv6 addresses");
 +	exit(1);
 +}
  
  
  int
 -main(void)
 +main(int argc, char **argv)
  { 
  	struct xprison *sxp, *xp;
 -	struct in_addr in;
  	size_t i, len;
 +	int allflag = 0;
 +	int ip6flag = 0;
 +	int ch;
 +
 +	while ((ch = getopt(argc, argv, "a6")) != -1) {
 +		switch (ch) {
 +		case 'a':
 +			allflag = 1;
 +			break;
 +		case '6':
 +			ip6flag = 1;
 +			break;
 +		default:
 +			usage();
 +		}
 +	}
 +	argc -= optind;
 +	argv += optind;
  
  	if (sysctlbyname("security.jail.list", NULL, &len, NULL, 0) == -1)
  		err(1, "sysctlbyname(): security.jail.list");
 @@ -65,11 +97,26 @@
  	    xp->pr_version != XPRISON_VERSION)
  		errx(1, "Kernel and userland out of sync");
  
 -	printf("   JID  IP Address      Hostname                      Path\n");
 +	if (ip6flag)
 +		printf("   JID  IP4 Address     IP6 Address            Hostname                      Path\n");
 +	else
 +		printf("   JID  IP Address      Hostname                      Path\n");
  	for (i = 0; i < len / sizeof(*xp); i++) {
 -		in.s_addr = ntohl(xp->pr_ip);
 -		printf("%6d  %-15.15s %-29.29s %.74s\n",
 -		    xp->pr_id, inet_ntoa(in), xp->pr_host, xp->pr_path);
 +		if (allflag || xp->pr4_id == 0) {
 +			if (ip6flag) {
 +				char buffer[128];
 +				printf("%6d  %-15.15s %-22.22s %-29.29s %.74s\n",
 +				    xp->pr_id, 
 +				    inet_ntoa(xp->pr4_num),
 +				    inet_ntop(AF_INET6, xp->pr6_num.s6_addr, buffer, sizeof(buffer)),
 +				    xp->pr_host, 
 +                                    xp->pr_path);
 +			}
 +			else {
 +				printf("%6d  %-15.15s %-29.29s %.74s\n",
 +				    xp->pr_id, inet_ntoa(xp->pr4_num), xp->pr_host, xp->pr_path);
 +			}
 +		}
  		xp++;
  	}
  	free(sxp);

From: "Meno Abels" <meno.abels@adviser.com>
To: <freebsd-gnats-submit@FreeBSD.org>, <abels@adviser.com>
Cc:  
Subject: Re: kern/69064: [patch] No multiple ip4/6's could assigned to a jail.
Date: Thu, 2 Dec 2004 23:16:04 +0100

 Now the patch works agains RELEASE_5_3 and i fixed some usage problems =
 and a
 stall in the kernel which was cause by illegal parameters in the jail =
 system
 call.
 The jail tool now can handle this:
 
  jail path hostname ip,ip,ip /bin/sh /etc/rc
 This allows to use it without change from /etc/rc.d/jail
 
 Here is the complete patch against RELEASE_5_3:
 
 # This is a shell archive.  Save it in a file, remove anything before
 # this line, and then unpack it by entering "sh file".  Note, it may
 # create directories; files and directories will be owned by you and
 # have default permissions.
 #
 # This archive contains:
 #
 #	ipv6.jail.patch
 #
 echo x - ipv6.jail.patch
 sed 's/^X//' >ipv6.jail.patch << 'END-of-ipv6.jail.patch'
 XIndex: usr.sbin/jail/jail.8
 X=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
 XRCS file: /usr/freebsd.cvs/src/usr.sbin/jail/jail.8,v
 Xretrieving revision 1.58
 Xdiff -c -r1.58 jail.8
 X*** usr.sbin/jail/jail.8	15 Aug 2004 08:21:50 -0000	1.58
 X--- usr.sbin/jail/jail.8	2 Dec 2004 21:17:28 -0000
 X***************
 X*** 43,49 ****
 X  .Nm
 X  .Op Fl i
 X  .Op Fl l Fl u Ar username | Fl U Ar username
 X! .Ar path hostname ip-number command ...
 X  .Sh DESCRIPTION
 X  The
 X  .Nm
 X--- 43,52 ----
 X  .Nm
 X  .Op Fl i
 X  .Op Fl l Fl u Ar username | Fl U Ar username
 X! .Op Fl j Ar jail identifier
 X! .Op Fl a Ar ip4 or ip6 address
 X! .Op Fl d Ar ip4 or ip6 address
 X! .Ar path hostname [ip4|ip6] command ...
 X  .Sh DESCRIPTION
 X  The
 X  .Nm
 X***************
 X*** 52,58 ****
 X  The options are as follows:
 X  .Bl -tag -width ".Fl u Ar username"
 X  .It Fl i
 X! Output the jail identifier of the newly created jail.
 X  .It Fl l
 X  Run program in the clean environment.
 X  The environment is discarded except for
 X--- 55,61 ----
 X  The options are as follows:
 X  .Bl -tag -width ".Fl u Ar username"
 X  .It Fl i
 X! Output the jail identifier of the newly created jail. Only valid =
 without
 -j.
 X  .It Fl l
 X  Run program in the clean environment.
 X  The environment is discarded except for
 X***************
 X*** 76,82 ****
 X  .Ar command
 X  should run.
 X  .It Fl U Ar username
 X! The user name from jailed environment as whom the
 X  .Ar command
 X  should run.
 X  .It Ar path
 X--- 79,95 ----
 X  .Ar command
 X  should run.
 X  .It Fl U Ar username
 X!=20
 X! The user name from jailed environment as whom the. Only valid without =
 -j.
 X! .It Fl j Ar jail identifier
 X! This options set the jail identifier which is modified with -a oder =
 -d.
 X! The jail identifier could be retrieved with jls.
 X! .It Fl a Ar ip4 or ip6
 X! This options add the specified ip number to the jail that is give =
 with
 -j. You
 X! can only have one -a per call.=20
 X! .It Fl d Ar ip4 or ip6
 X! This options deletes the specified ip number from the jail that is =
 give
 with -j.
 X! You can only have one -d per call.
 X  .Ar command
 X  should run.
 X  .It Ar path
 X***************
 X*** 84,90 ****
 X  .It Ar hostname
 X  Hostname of the prison.
 X  .It Ar ip-number
 X! IP number assigned to the prison.
 X  .It Ar command
 X  Pathname of the program which is to be executed.
 X  .El
 X--- 97,103 ----
 X  .It Ar hostname
 X  Hostname of the prison.
 X  .It Ar ip-number
 X! IP4 or IP6 number assigned to the prison.
 X  .It Ar command
 X  Pathname of the program which is to be executed.
 X  .El
 XIndex: usr.sbin/jail/jail.c
 X=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
 XRCS file: /usr/freebsd.cvs/src/usr.sbin/jail/jail.c,v
 Xretrieving revision 1.17
 Xdiff -c -r1.17 jail.c
 X*** usr.sbin/jail/jail.c	15 Aug 2004 08:21:50 -0000	1.17
 X--- usr.sbin/jail/jail.c	2 Dec 2004 21:31:38 -0000
 X***************
 X*** 13,21 ****
 X--- 13,24 ----
 X  #include <sys/param.h>
 X  #include <sys/jail.h>
 X =20
 X+ #include <sys/types.h>
 X+ #include <sys/socket.h>
 X  #include <netinet/in.h>
 X  #include <arpa/inet.h>
 X =20
 X+=20
 X  #include <err.h>
 X  #include <errno.h>
 X  #include <grp.h>
 X***************
 X*** 52,67 ****
 X  	login_cap_t *lcap;
 X  	struct jail j;
 X  	struct passwd *pwd;
 X! 	struct in_addr in;
 X  	int ch, groups[NGROUPS], i, iflag, lflag, ngroups, uflag, Uflag;
 X  	char path[PATH_MAX], *username;
 X  	static char *cleanenv;
 X  	const char *shell, *p;
 X =20
 X  	iflag =3D lflag =3D uflag =3D Uflag =3D 0;
 X  	username =3D cleanenv =3D NULL;
 X =20
 X! 	while ((ch =3D getopt(argc, argv, "ilu:U:")) !=3D -1) {
 X  		switch (ch) {
 X  		case 'i':
 X  			iflag =3D 1;
 X--- 55,73 ----
 X  	login_cap_t *lcap;
 X  	struct jail j;
 X  	struct passwd *pwd;
 X!  	int jid =3D 0;
 X  	int ch, groups[NGROUPS], i, iflag, lflag, ngroups, uflag, Uflag;
 X  	char path[PATH_MAX], *username;
 X  	static char *cleanenv;
 X  	const char *shell, *p;
 X+         const char *address =3D 0;
 X+         int add =3D 0;
 X+         int del =3D 0;
 X =20
 X  	iflag =3D lflag =3D uflag =3D Uflag =3D 0;
 X  	username =3D cleanenv =3D NULL;
 X =20
 X!  	while ((ch =3D getopt(argc, argv, "iu:U:j:a:d:")) !=3D -1) {
 X  		switch (ch) {
 X  		case 'i':
 X  			iflag =3D 1;
 X***************
 X*** 77,90 ****
 X  		case 'l':
 X  			lflag =3D 1;
 X  			break;
 X  		default:
 X  			usage();
 X  		}
 X  	}
 X  	argc -=3D optind;
 X  	argv +=3D optind;
 X! 	if (argc < 4)
 X  		usage();
 X  	if (uflag && Uflag)
 X  		usage();
 X  	if (lflag && username =3D=3D NULL)
 X--- 83,135 ----
 X  		case 'l':
 X  			lflag =3D 1;
 X  			break;
 X+                 case 'j':
 X+                         jid =3D atol(optarg);
 X+                         break;
 X+                 case 'a':
 X+                         add =3D 1;
 X+                         address =3D optarg;
 X+                         break;
 X+                 case 'd':
 X+                         del =3D 1;
 X+                         address =3D optarg;
 X+                         break;
 X+=20
 X  		default:
 X  			usage();
 X  		}
 X  	}
 X  	argc -=3D optind;
 X  	argv +=3D optind;
 X! 	if ((jid =3D=3D 0 && argc < 4) ||
 X!             (jid < 1 && (add || del)) ||
 X!             (add && del) ||
 X!             (jid > 0 && !(add || del)))
 X  		usage();
 X+         if (jid > 0) {
 X+ 		if (!address)
 X+ 		{
 X+                         err(1, "jail: address has to be specified");
 X+ 		}
 X+ 		int function;
 X+                 if (inet_pton(AF_INET, address,
 &j.u.v2.u.add_del.v4_6.ip4_num) > 0) {
 X+                         function =3D add ? ADDIP4 : DELIP4;
 X+                 }
 X+                 else if (inet_pton(AF_INET6, address,
 &j.u.v2.u.add_del.v4_6.ip6_num) > 0) {
 X+                         function =3D add ? ADDIP6 : DELIP6;
 X+                 }
 X+                 else {
 X+                         err(1, "inet_pton: %s", address);
 X+                 }
 X+ 		j.version =3D XPRISON_VERSION;
 X+ 		j.u.v2.function =3D function;
 X+ 		j.u.v2.u.add_del.id =3D jid;
 X+ 		i =3D jail(&j);
 X+ 		if (i =3D=3D -1)
 X+ 			err(1, "jail(%d)", function);
 X+                 exit (0);
 X+         }
 X+=20
 X  	if (uflag && Uflag)
 X  		usage();
 X  	if (lflag && username =3D=3D NULL)
 X***************
 X*** 96,114 ****
 X  	if (chdir(path) !=3D 0)
 X  		err(1, "chdir: %s", path);
 X  	memset(&j, 0, sizeof(j));
 X! 	j.version =3D 0;
 X! 	j.path =3D path;
 X! 	j.hostname =3D argv[1];
 X! 	if (inet_aton(argv[2], &in) =3D=3D 0)
 X! 		errx(1, "Could not make sense of ip-number: %s", argv[2]);
 X! 	j.ip_number =3D ntohl(in.s_addr);
 X! 	i =3D jail(&j);
 X  	if (i =3D=3D -1)
 X! 		err(1, "jail");
 X  	if (iflag) {
 X! 		printf("%d\n", i);
 X  		fflush(stdout);
 X  	}
 X  	if (username !=3D NULL) {
 X  		if (Uflag)
 X  			GET_USER_INFO;
 X--- 141,177 ----
 X  	if (chdir(path) !=3D 0)
 X  		err(1, "chdir: %s", path);
 X  	memset(&j, 0, sizeof(j));
 X! 	j.version =3D XPRISON_VERSION;
 X! 	j.u.v2.function =3D CREATEJAIL;
 X! 	j.u.v2.u.createjail.path     =3D path;
 X! 	j.u.v2.u.createjail.hostname =3D argv[1];
 X! 	jid =3D i =3D jail(&j);
 X  	if (i =3D=3D -1)
 X! 		err(1, "jail(CREATEJAIL)");
 X!=20
 X  	if (iflag) {
 X! 		printf("%d\n", jid);
 X  		fflush(stdout);
 X  	}
 X+=20
 X+ 	const char *tok;
 X+ 	for (tok =3D strtok(argv[2], ","); tok; tok =3D strtok(0, ","))
 X+ 	{
 X+ 		j.version =3D XPRISON_VERSION;
 X+ 		j.u.v2.u.add_del.id =3Djid;
 X+ 		j.u.v2.function =3D ADDIP4;
 X+ 		address =3D tok;
 X+ 		if (inet_pton(AF_INET, address,
 &j.u.v2.u.add_del.v4_6.ip4_num) <=3D 0) {
 X+ 			j.u.v2.function =3D ADDIP6;
 X+ 			if (inet_pton(AF_INET6, address,
 &j.u.v2.u.add_del.v4_6.ip6_num) <=3D 0) {
 X+ 				errx(1, "Could not make sense of ip-number:
 %s", argv[2]);
 X+ 			}
 X+ 		}
 X+ 		i =3D jail(&j);
 X+ 		if (i =3D=3D -1)
 X+ 			err(1, "jail(%d)", j.u.v2.function);
 X+=20
 X+ 	}
 X  	if (username !=3D NULL) {
 X  		if (Uflag)
 X  			GET_USER_INFO;
 X***************
 X*** 147,154 ****
 X  usage(void)
 X  {
 X =20
 X! 	(void)fprintf(stderr, "%s%s\n",
 X! 	     "usage: jail [-i] [-l -u username | -U username]",
 X! 	     " path hostname ip-number command ...");
 X! 	exit(1);
 X  }
 X--- 210,216 ----
 X  usage(void)
 X  {
 X =20
 X!        (void)fprintf(stderr,
 X!         "usage: jail [-i] [-u username] [-j id] [[-a [ip4|ip6]|[-d
 [ip4|ip6]] [path hostname {[ip4|ip6],} command ...]\n");
 X!         exit(1);
 X  }
 XIndex: usr.sbin/jls/jls.8
 X=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
 XRCS file: /usr/freebsd.cvs/src/usr.sbin/jls/jls.8,v
 Xretrieving revision 1.1
 Xdiff -c -r1.1 jls.8
 X*** usr.sbin/jls/jls.8	9 Apr 2003 03:04:12 -0000	1.1
 X--- usr.sbin/jls/jls.8	24 Nov 2004 23:41:10 -0000
 X***************
 X*** 33,42 ****
 X--- 33,55 ----
 X  .Nd "list active jails"
 X  .Sh SYNOPSIS
 X  .Nm
 X+ .Op Fl a
 X+ .Op Fl 6
 X  .Sh DESCRIPTION
 X  The
 X  .Nm
 X  utility lists all active jails.
 X+ .Pp
 X+ The options are as follows:
 X+ .Bl -tag -width ".Fl a "
 X+ .It Fl a=20
 X+ output all ip4 assigments to the jail identifier(JID). Each ip4 gets
 X+ one line in output. If no ip4 address is assigned 0.0.0.0 is the =
 output.
 X+ .It Fl 6=20
 X+ output ip6 address also a new column is generated between IP Address=20
 X+ and Hostname. If no ip6 address is assigned :: is the output.
 X+ .El
 X+ .Pp
 X  Each jail is represented by one row which contains the following =
 columns:
 X  jail identifier (JID), IP address, hostname, and path.
 X  .Sh SEE ALSO
 XIndex: usr.sbin/jls/jls.c
 X=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
 XRCS file: /usr/freebsd.cvs/src/usr.sbin/jls/jls.c,v
 Xretrieving revision 1.3
 Xdiff -c -r1.3 jls.c
 X*** usr.sbin/jls/jls.c	22 Apr 2003 13:24:56 -0000	1.3
 X--- usr.sbin/jls/jls.c	24 Nov 2004 23:41:10 -0000
 X***************
 X*** 30,49 ****
 X  #include <sys/jail.h>
 X  #include <sys/sysctl.h>
 X =20
 X  #include <arpa/inet.h>
 X  #include <err.h>
 X  #include <errno.h>
 X  #include <limits.h>
 X  #include <stdio.h>
 X  #include <stdlib.h>
 X =20
 X =20
 X  int
 X! main(void)
 X  {=20
 X  	struct xprison *sxp, *xp;
 X- 	struct in_addr in;
 X  	size_t i, len;
 X =20
 X  	if (sysctlbyname("security.jail.list", NULL, &len, NULL, 0) =3D=3D =
 -1)
 X  		err(1, "sysctlbyname(): security.jail.list");
 X--- 30,81 ----
 X  #include <sys/jail.h>
 X  #include <sys/sysctl.h>
 X =20
 X+ #include <sys/types.h>
 X+ #include <sys/socket.h>
 X+ #include <netinet/in.h>
 X  #include <arpa/inet.h>
 X+=20
 X  #include <err.h>
 X  #include <errno.h>
 X  #include <limits.h>
 X  #include <stdio.h>
 X  #include <stdlib.h>
 X+ #include <unistd.h>
 X+=20
 X+ static int
 X+ usage(void)
 X+ {
 X+ 	fprintf(stderr, "%s\n%s\n%s\n",
 X+ 	     "usage: jls [-a] [-6]",
 X+ 	     " -a output all jail assigned ip addresses",
 X+ 	     " -6 output includes ipv6 addresses");
 X+ 	exit(1);
 X+ }
 X =20
 X =20
 X  int
 X! main(int argc, char **argv)
 X  {=20
 X  	struct xprison *sxp, *xp;
 X  	size_t i, len;
 X+ 	int allflag =3D 0;
 X+ 	int ip6flag =3D 0;
 X+ 	int ch;
 X+=20
 X+ 	while ((ch =3D getopt(argc, argv, "a6")) !=3D -1) {
 X+ 		switch (ch) {
 X+ 		case 'a':
 X+ 			allflag =3D 1;
 X+ 			break;
 X+ 		case '6':
 X+ 			ip6flag =3D 1;
 X+ 			break;
 X+ 		default:
 X+ 			usage();
 X+ 		}
 X+ 	}
 X+ 	argc -=3D optind;
 X+ 	argv +=3D optind;
 X =20
 X  	if (sysctlbyname("security.jail.list", NULL, &len, NULL, 0) =3D=3D =
 -1)
 X  		err(1, "sysctlbyname(): security.jail.list");
 X***************
 X*** 65,75 ****
 X  	    xp->pr_version !=3D XPRISON_VERSION)
 X  		errx(1, "Kernel and userland out of sync");
 X =20
 X! 	printf("   JID  IP Address      Hostname
 Path\n");
 X  	for (i =3D 0; i < len / sizeof(*xp); i++) {
 X! 		in.s_addr =3D ntohl(xp->pr_ip);
 X! 		printf("%6d  %-15.15s %-29.29s %.74s\n",
 X! 		    xp->pr_id, inet_ntoa(in), xp->pr_host, xp->pr_path);
 X  		xp++;
 X  	}
 X  	free(sxp);
 X--- 97,122 ----
 X  	    xp->pr_version !=3D XPRISON_VERSION)
 X  		errx(1, "Kernel and userland out of sync");
 X =20
 X! 	if (ip6flag)
 X! 		printf("   JID  IP4 Address     IP6 Address
 Hostname                      Path\n");
 X! 	else
 X! 		printf("   JID  IP Address      Hostname
 Path\n");
 X  	for (i =3D 0; i < len / sizeof(*xp); i++) {
 X! 		if (allflag || xp->pr4_id =3D=3D 0) {
 X! 			if (ip6flag) {
 X! 				char buffer[128];
 X! 				printf("%6d  %-15.15s %-22.22s %-29.29s
 %.74s\n",
 X! 				    xp->pr_id,=20
 X! 				    inet_ntoa(xp->pr4_num),
 X! 				    inet_ntop(AF_INET6, xp->pr6_num.s6_addr,
 buffer, sizeof(buffer)),
 X! 				    xp->pr_host,=20
 X!                                     xp->pr_path);
 X! 			}
 X! 			else {
 X! 				printf("%6d  %-15.15s %-29.29s %.74s\n",
 X! 				    xp->pr_id, inet_ntoa(xp->pr4_num),
 xp->pr_host, xp->pr_path);
 X! 			}
 X! 		}
 X  		xp++;
 X  	}
 X  	free(sxp);
 XIndex: sys/kern/kern_jail.c
 X=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
 XRCS file: /usr/freebsd.cvs/src/sys/kern/kern_jail.c,v
 Xretrieving revision 1.44
 Xdiff -c -r1.44 kern_jail.c
 X*** sys/kern/kern_jail.c	27 Jun 2004 09:03:21 -0000	1.44
 X--- sys/kern/kern_jail.c	2 Dec 2004 21:35:54 -0000
 X***************
 X*** 33,40 ****
 X--- 33,43 ----
 X  #include <sys/vnode.h>
 X  #include <net/if.h>
 X  #include <netinet/in.h>
 X+ #include <netinet6/in6_var.h>
 X =20
 X  MALLOC_DEFINE(M_PRISON, "prison", "Prison structures");
 X+ MALLOC_DEFINE(M_PRISON_IP4, "prison", "Prison ipv4 addresses");
 X+ MALLOC_DEFINE(M_PRISON_IP6, "prison", "Prison ipv6 addresses");
 X =20
 X  SYSCTL_DECL(_security);
 X  SYSCTL_NODE(_security, OID_AUTO, jail, CTLFLAG_RW, 0,
 X***************
 X*** 75,80 ****
 X--- 78,88 ----
 X =20
 X  static void		 init_prison(void *);
 X  static void		 prison_complete(void *context, int pending);
 X+ static int 		 prison_add_ip4(struct in_addr *tmpv4, struct prison
 *pr, void *pr_new, void **pr_old);
 X+ static int 		 prison_add_ip6(struct in6_addr *tmpv4, struct
 prison *pr, void *pr_new, void **pr_old);
 X+ static int 		 prison_del_ip4(struct in_addr *tmpv4, struct prison
 *pr, void *pr_new, void **pr_old);
 X+ static int 		 prison_del_ip6(struct in6_addr *tmpv4, struct
 prison *pr, void *pr_new, void **pr_old);
 X+ static int               prison_check_duplicate(char *hostname, char
 *path);
 X  static struct prison	*prison_find(int);
 X  static int		 sysctl_jail_list(SYSCTL_HANDLER_ARGS);
 X =20
 X***************
 X*** 95,139 ****
 X   *	struct jail *jail;
 X   * };
 X   */
 X! int
 X! jail(struct thread *td, struct jail_args *uap)
 X  {
 X  	struct nameidata nd;
 X- 	struct prison *pr, *tpr;
 X- 	struct jail j;
 X- 	struct jail_attach_args jaa;
 X- 	int error, tryprid;
 X =20
 X! 	error =3D copyin(uap->jail, &j, sizeof(j));
 X  	if (error)
 X! 		return (error);
 X! 	if (j.version !=3D 0)
 X! 		return (EINVAL);
 X!=20
 X! 	MALLOC(pr, struct prison *, sizeof(*pr), M_PRISON, M_WAITOK |
 M_ZERO);
 X! 	mtx_init(&pr->pr_mtx, "jail mutex", NULL, MTX_DEF);
 X! 	pr->pr_ref =3D 1;
 X! 	error =3D copyinstr(j.path, &pr->pr_path, sizeof(pr->pr_path), 0);
 X  	if (error)
 X  		goto e_killmtx;
 X  	mtx_lock(&Giant);
 X! 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, pr->pr_path,
 td);
 X  	error =3D namei(&nd);
 X  	if (error) {
 X  		mtx_unlock(&Giant);
 X  		goto e_killmtx;
 X  	}
 X! 	pr->pr_root =3D nd.ni_vp;
 X  	VOP_UNLOCK(nd.ni_vp, 0, td);
 X  	NDFREE(&nd, NDF_ONLY_PNBUF);
 X  	mtx_unlock(&Giant);
 X- 	error =3D copyinstr(j.hostname, &pr->pr_host, sizeof(pr->pr_host), =
 0);
 X- 	if (error)
 X- 		goto e_dropvnref;
 X- 	pr->pr_ip =3D j.ip_number;
 X- 	pr->pr_linux =3D NULL;
 X- 	pr->pr_securelevel =3D securelevel;
 X =20
 X  	/* Determine next pr_id and add prison to allprison list. */
 X  	mtx_lock(&allprison_mtx);
 X  	tryprid =3D lastprid + 1;
 X--- 103,281 ----
 X   *	struct jail *jail;
 X   * };
 X   */
 X! static int=20
 X! jail_createjail(struct thread *td, char *user_hostname, char =
 *user_path,
 struct prison **pr)
 X  {
 X+ 	int error;
 X  	struct nameidata nd;
 X =20
 X! 	MALLOC(*pr, struct prison *, sizeof(**pr), M_PRISON, M_WAITOK |
 M_ZERO);
 X! 	mtx_init(&(*pr)->pr_mtx, "jail mutex", NULL, MTX_DEF);
 X! 	(*pr)->pr_ref =3D 1;
 X! 	error =3D copyinstr(user_path, &(*pr)->pr_path,
 sizeof((*pr)->pr_path), 0);
 X  	if (error)
 X! 		goto e_killmtx;
 X! 	error =3D copyinstr(user_hostname, &(*pr)->pr_host,
 sizeof((*pr)->pr_host), 0);
 X  	if (error)
 X  		goto e_killmtx;
 X+ 	if (prison_check_duplicate((*pr)->pr_host, (*pr)->pr_path)) {
 X+ 		error =3D EAGAIN;
 X+ 		goto e_killmtx;
 X+ 	}
 X+=20
 X  	mtx_lock(&Giant);
 X! 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, (*pr)->pr_path,
 td);
 X  	error =3D namei(&nd);
 X  	if (error) {
 X  		mtx_unlock(&Giant);
 X  		goto e_killmtx;
 X  	}
 X! 	(*pr)->pr_root =3D nd.ni_vp;
 X  	VOP_UNLOCK(nd.ni_vp, 0, td);
 X  	NDFREE(&nd, NDF_ONLY_PNBUF);
 X  	mtx_unlock(&Giant);
 X =20
 X+ 	(*pr)->pr_linux =3D NULL;
 X+ 	(*pr)->pr_securelevel =3D securelevel;
 X+ 	return (0);
 X+=20
 X+ e_killmtx:
 X+ 	mtx_destroy(&(*pr)->pr_mtx);
 X+ 	FREE(*pr, M_PRISON);
 X+ 	return (error);
 X+=20
 X+ }
 X+=20
 X+=20
 X+ static void=20
 X+ jail_dropvnref(struct prison *pr)
 X+ {
 X+ 	mtx_lock(&Giant);
 X+ 	vrele(pr->pr_root);
 X+ 	mtx_unlock(&Giant);
 X+ }
 X+=20
 X+ int
 X+ jail(struct thread *td, struct jail_args *uap)
 X+ {
 X+ 	struct prison *pr, *tpr;
 X+ 	struct jail j;
 X+ 	struct jail_attach_args jaa;
 X+ 	int error, tryprid;
 X+ 	void *pr_new =3D 0;
 X+ 	void *pr_old =3D 0;
 X+=20
 X+ 	error =3D copyin(uap->jail, &j, sizeof(j));
 X+ 	if (error)
 X+ 		return (error);
 X+ 	if (j.version < XPRISON_VERSION)
 X+ 	{
 X+ 		struct in_addr tmpv4;
 X+=20
 X+ 		error =3D jail_createjail(td, j.u.v1.hostname, j.u.v1.path,
 &pr);
 X+ 		if (error) {
 X+ 			return error;
 X+ 		}
 X+ 		MALLOC(pr_new, void *, sizeof(struct in_addr)*1,
 M_PRISON_IP4, M_WAITOK | M_ZERO);
 X+ 		tmpv4.s_addr =3D htonl(j.u.v1.ip_number);	=09
 X+ 		mtx_lock(&pr->pr_mtx);
 X+ 		error =3D prison_add_ip4(&tmpv4, pr, pr_new, &pr_old);
 X+ 		mtx_unlock(&pr->pr_mtx);
 X+ 		if (error) {
 X+ 			jail_dropvnref(pr);
 X+ 		}
 X+ 	}
 X+ 	else
 X+ 	{
 X+ 		if (j.u.v2.function =3D=3D CREATEJAIL) {
 X+ 			error =3D jail_createjail(td,
 j.u.v2.u.createjail.hostname, j.u.v2.u.createjail.path, &pr);
 X+ 			if (error) {
 X+ 				return error;
 X+ 			}
 X+ 		}
 X+ 		else {
 X+ 			int cnt =3D 0;
 X+ 			struct malloc_type *alloc_type;
 X+ retry_alloc:
 X+ 			mtx_lock(&allprison_mtx);
 X+ 			pr =3D prison_find(j.u.v2.u.add_del.id);
 X+ 			if (pr) {
 X+ 				cnt =3D (j.u.v2.function =3D=3D ADDIP4 ||
 j.u.v2.function =3D=3D DELIP4) ?=20
 X+ 					pr->pr_ip4s : pr->pr_ip6s;=09
 X+ 				mtx_unlock(&pr->pr_mtx);
 X+ 			}
 X+ 			mtx_unlock(&allprison_mtx);
 X+ 			if (pr =3D=3D NULL) {
 X+ 				return (EINVAL);
 X+ 			}
 X+ 			if (j.u.v2.function =3D=3D ADDIP4 || j.u.v2.function =3D=3D
 DELIP4) {
 X+ 				alloc_type=3DM_PRISON_IP4;
 X+ 				if (pr->pr_ip4s >=3D (j.u.v2.function =3D=3D
 DELIP4 ? 2 : 0)) {
 X+ 					MALLOC(pr_new, void *,=20
 X+ 						sizeof(struct
 in_addr)*(pr->pr_ip4s+
 X+ 						(j.u.v2.function =3D=3D DELIP4 ?
 -1 : +1)),
 X+ 						alloc_type, M_WAITOK |
 M_ZERO);
 X+ 					/*printf("pr_ip4s:%d\n",
 pr->pr_ip4s);*/
 X+ 				}
 X+ 			}
 X+ 			else {
 X+ 				alloc_type=3DM_PRISON_IP6;
 X+ 				if (pr->pr_ip6s >=3D (j.u.v2.function =3D=3D
 DELIP6 ? 2 : 0)) {
 X+ 					MALLOC(pr_new, void *,=20
 X+ 						sizeof(struct
 in6_addr)*(pr->pr_ip6s+
 X+ 						(j.u.v2.function =3D=3D DELIP6 ?
 -1 : +1)),
 X+ 						alloc_type, M_WAITOK |
 M_ZERO);
 X+ 					/*printf("pr_ip4s:%d\n",
 pr->pr_ip6s);*/
 X+ 				}
 X+ 			}
 X+ 			mtx_lock(&allprison_mtx);
 X+ 			pr =3D prison_find(j.u.v2.u.add_del.id);
 X+ 			if (pr)
 X+ 			{
 X+ 				if (cnt !=3D ((j.u.v2.function =3D=3D ADDIP4 ||
 j.u.v2.function =3D=3D DELIP4) ?=20
 X+ 					pr->pr_ip4s : pr->pr_ip6s))=09
 X+ 				{
 X+ 					/* should i sleep ? */
 X+ 					mtx_unlock(&pr->pr_mtx);
 X+ 					mtx_unlock(&allprison_mtx);
 X+ 					FREE(pr_new, alloc_type);
 X+ 					/*printf("jail retry alloc\n");*/
 X+ 					goto retry_alloc;
 X+ 				}
 X+ 				mtx_unlock(&allprison_mtx);
 X+ 			}
 X+ 			else
 X+ 			{
 X+ 				mtx_unlock(&allprison_mtx);
 X+ 				return (EINVAL);
 X+ 			}
 X+ 		=09
 X+ 			switch (j.u.v2.function) {
 X+ 			case ADDIP4:
 X+ 				error =3D
 prison_add_ip4(&j.u.v2.u.add_del.v4_6.ip4_num, pr, pr_new, &pr_old);
 X+ 				break;
 X+ 			case ADDIP6:
 X+ 				error =3D
 prison_add_ip6(&j.u.v2.u.add_del.v4_6.ip6_num, pr, pr_new, &pr_old);
 X+ 				break;
 X+ 			case DELIP4:
 X+ 				error =3D
 prison_del_ip4(&j.u.v2.u.add_del.v4_6.ip4_num, pr, pr_new, &pr_old);
 X+ 				break;
 X+ 			case DELIP6:
 X+ 				error =3D
 prison_del_ip6(&j.u.v2.u.add_del.v4_6.ip6_num, pr, pr_new, &pr_old);
 X+ 				break;
 X+ 			default:
 X+ 				mtx_unlock(&pr->pr_mtx);
 X+ 				return EINVAL;
 X+ 			}
 X+ 			mtx_unlock(&pr->pr_mtx);
 X+ 			if (pr_old) {
 X+ 				/*printf("jail free:%p\n", pr_old);*/
 X+ 				FREE(pr_old, alloc_type);
 X+ 			}
 X+ 			return (error);
 X+ 		}
 X+ 	}
 X+ 	/* REST of Create Code */
 X  	/* Determine next pr_id and add prison to allprison list. */
 X  	mtx_lock(&allprison_mtx);
 X  	tryprid =3D lastprid + 1;
 X***************
 X*** 146,152 ****
 X  			if (tryprid =3D=3D JAIL_MAX) {
 X  				mtx_unlock(&allprison_mtx);
 X  				error =3D EAGAIN;
 X! 				goto e_dropvnref;
 X  			}
 X  			goto next;
 X  		}
 X--- 288,295 ----
 X  			if (tryprid =3D=3D JAIL_MAX) {
 X  				mtx_unlock(&allprison_mtx);
 X  				error =3D EAGAIN;
 X! 				jail_dropvnref(pr);
 X! 				return error;
 X  			}
 X  			goto next;
 X  		}
 X***************
 X*** 164,181 ****
 X  	mtx_unlock(&pr->pr_mtx);
 X  	td->td_retval[0] =3D jaa.jid;
 X  	return (0);
 X  e_dropprref:
 X  	mtx_lock(&allprison_mtx);
 X  	LIST_REMOVE(pr, pr_list);
 X  	prisoncount--;
 X  	mtx_unlock(&allprison_mtx);
 X! e_dropvnref:
 X! 	mtx_lock(&Giant);
 X! 	vrele(pr->pr_root);
 X! 	mtx_unlock(&Giant);
 X! e_killmtx:
 X! 	mtx_destroy(&pr->pr_mtx);
 X! 	FREE(pr, M_PRISON);
 X  	return (error);
 X  }
 X =20
 X--- 307,319 ----
 X  	mtx_unlock(&pr->pr_mtx);
 X  	td->td_retval[0] =3D jaa.jid;
 X  	return (0);
 X+=20
 X  e_dropprref:
 X  	mtx_lock(&allprison_mtx);
 X  	LIST_REMOVE(pr, pr_list);
 X  	prisoncount--;
 X  	mtx_unlock(&allprison_mtx);
 X! 	jail_dropvnref(pr);
 X  	return (error);
 X  }
 X =20
 X***************
 X*** 248,253 ****
 X--- 386,417 ----
 X  	return (error);
 X  }
 X =20
 X+ /* return 0 on not duplicate */
 X+ static int
 X+ prison_check_duplicate(char *hostname, char *path)
 X+ {
 X+ 	struct prison *pr;
 X+ 	mtx_lock(&allprison_mtx);
 X+ 	LIST_FOREACH(pr, &allprison, pr_list) {
 X+ 		if (!strncmp(hostname, pr->pr_host, sizeof(pr->pr_host))) {
 X+ 			mtx_unlock(&allprison_mtx);
 X+ 			return 1;
 X+ 		}
 X+ 		/* this is not perfect remove of trailing / or duplicated //
 X+                    should be done, who knows the kernel method for
 this-:)
 X+                  */
 X+ /*
 X+ 		if (!strncmp(path, pr->pr_path, sizeof(pr->pr_path))) {
 X+ 			mtx_unlock(&allprison_mtx);
 X+ 			return 1;
 X+ 		}
 X+ */
 X+ 	}
 X+ 	mtx_unlock(&allprison_mtx);
 X+ 	return 0;
 X+ }
 X+=20
 X+=20
 X  /*
 X   * Returns a locked prison instance, or NULL on failure.
 X   */
 X***************
 X*** 299,304 ****
 X--- 463,472 ----
 X  	mtx_unlock(&Giant);
 X =20
 X  	mtx_destroy(&pr->pr_mtx);
 X+ 	if (pr->pr_ip4 !=3D NULL)
 X+ 		FREE(pr->pr_ip4, M_PRISON_IP4);
 X+ 	if (pr->pr_ip6 !=3D NULL)
 X+ 		FREE(pr->pr_ip6, M_PRISON_IP6);
 X  	if (pr->pr_linux !=3D NULL)
 X  		FREE(pr->pr_linux, M_PRISON);
 X  	FREE(pr, M_PRISON);
 X***************
 X*** 313,371 ****
 X  	mtx_unlock(&pr->pr_mtx);
 X  }
 X =20
 X! u_int32_t
 X! prison_getip(struct ucred *cred)
 X  {
 X =20
 X! 	return (cred->cr_prison->pr_ip);
 X  }
 X =20
 X  int
 X! prison_ip(struct ucred *cred, int flag, u_int32_t *ip)
 X  {
 X  	u_int32_t tmp;
 X =20
 X  	if (!jailed(cred))
 X  		return (0);
 X! 	if (flag)=20
 X! 		tmp =3D *ip;
 X! 	else
 X! 		tmp =3D ntohl(*ip);
 X! 	if (tmp =3D=3D INADDR_ANY) {
 X! 		if (flag)=20
 X! 			*ip =3D cred->cr_prison->pr_ip;
 X! 		else
 X! 			*ip =3D htonl(cred->cr_prison->pr_ip);
 X! 		return (0);
 X! 	}
 X! 	if (tmp =3D=3D INADDR_LOOPBACK) {
 X! 		if (flag)
 X! 			*ip =3D cred->cr_prison->pr_ip;
 X! 		else
 X! 			*ip =3D htonl(cred->cr_prison->pr_ip);
 X  		return (0);
 X  	}
 X! 	if (cred->cr_prison->pr_ip !=3D tmp)
 X! 		return (1);
 X! 	return (0);
 X  }
 X =20
 X! void
 X! prison_remote_ip(struct ucred *cred, int flag, u_int32_t *ip)
 X  {
 X  	u_int32_t tmp;
 X =20
 X  	if (!jailed(cred))
 X  		return;
 X! 	if (flag)
 X! 		tmp =3D *ip;
 X! 	else
 X! 		tmp =3D ntohl(*ip);
 X! 	if (tmp =3D=3D INADDR_LOOPBACK) {
 X! 		if (flag)
 X! 			*ip =3D cred->cr_prison->pr_ip;
 X! 		else
 X! 			*ip =3D htonl(cred->cr_prison->pr_ip);
 X  		return;
 X  	}
 X  	return;
 X--- 481,610 ----
 X  	mtx_unlock(&pr->pr_mtx);
 X  }
 X =20
 X! int
 X! prison_first_ip4(struct ucred *cred, struct in_addr *out)
 X  {
 X+ 	int errno =3D 0;
 X+ 	mtx_lock(&cred->cr_prison->pr_mtx);
 X+ 	if (cred->cr_prison->pr_ip4s)=20
 X+ 		*out =3D cred->cr_prison->pr_ip4[0];
 X+ 	else
 X+ 		errno =3D EADDRNOTAVAIL;
 X+ 	mtx_unlock(&cred->cr_prison->pr_mtx);
 X+ 	return errno;
 X+ }
 X =20
 X! int
 X! prison_first_ip6(struct ucred *cred, struct in6_addr *out)
 X! {
 X! 	int errno =3D 0;
 X! 	mtx_lock(&cred->cr_prison->pr_mtx);
 X! 	if (cred->cr_prison->pr_ip6s)
 X! 		*out =3D cred->cr_prison->pr_ip6[0];
 X! 	else
 X! 		errno =3D EADDRNOTAVAIL;
 X! 	mtx_unlock(&cred->cr_prison->pr_mtx);
 X! 	return errno;
 X  }
 X =20
 X  int
 X! prison_match_ip4(struct ucred *cred, struct in_addr *ip)
 X  {
 X  	u_int32_t tmp;
 X =20
 X  	if (!jailed(cred))
 X  		return (0);
 X!=20
 X! 	for (tmp =3D 0; tmp < cred->cr_prison->pr_ip4s; ++tmp)
 X! 	{
 X! 		if (cred->cr_prison->pr_ip4[tmp].s_addr =3D=3D ip->s_addr)
 X! 		{
 X! 			return 0;
 X! 		}
 X! 	}
 X! 	return (1);
 X! }
 X!=20
 X! int
 X! prison_redirect_ip4(struct ucred *cred, struct in_addr *ip)
 X! {
 X! 	if (!jailed(cred))
 X! 		return (0);
 X! 	if (cred->cr_prison->pr_ip4s <=3D 0)
 X! 		return (0);
 X!=20
 X! 	if (ip->s_addr =3D=3D htonl(INADDR_ANY)) {
 X! 		*ip =3D cred->cr_prison->pr_ip4[0];
 X  		return (0);
 X  	}
 X! 	if (ip->s_addr =3D=3D htonl(INADDR_LOOPBACK)) {
 X! 		*ip =3D cred->cr_prison->pr_ip4[0];
 X! 		return (0);
 X! 	}
 X! 	return prison_match_ip4(cred, ip);
 X  }
 X =20
 X! int
 X! prison_match_ip6(struct ucred *cred, struct in6_addr *ip)
 X  {
 X  	u_int32_t tmp;
 X =20
 X  	if (!jailed(cred))
 X+ 		return (0);
 X+=20
 X+ 	for (tmp =3D 0; tmp < cred->cr_prison->pr_ip6s; ++tmp)
 X+ 	{
 X+ 		if (IN6_ARE_ADDR_EQUAL(&(cred->cr_prison->pr_ip6[tmp]), ip))
 X+ 		{
 X+ 			return 0;
 X+ 		}
 X+ 	}
 X+ 	return (1);
 X+ }
 X+=20
 X+=20
 X+ int
 X+ prison_redirect_ip6(struct ucred *cred, struct in6_addr *ip)
 X+ {
 X+ 	if (!jailed(cred))
 X+ 		return (0);
 X+ 	if (cred->cr_prison->pr_ip6s <=3D 0)
 X+ 		return (0);
 X+=20
 X+ 	if (IN6_ARE_ADDR_EQUAL(ip, &in6addr_any)) {
 X+ 		*ip =3D cred->cr_prison->pr_ip6[0];
 X+ 		return (0);
 X+ 	}
 X+ 	if (IN6_IS_ADDR_LOOPBACK(ip)) {
 X+ 		*ip =3D cred->cr_prison->pr_ip6[0];
 X+ 		return (0);
 X+ 	}
 X+ 	return prison_match_ip6(cred, ip);
 X+ }
 X+=20
 X+ void
 X+ prison_remote_ip4(struct ucred *cred, struct in_addr *ip)
 X+ {
 X+ 	if (!jailed(cred))
 X  		return;
 X! 	if (cred->cr_prison->pr_ip4s <=3D 0)
 X! 		return;
 X! 	if (ip->s_addr =3D=3D INADDR_LOOPBACK) {
 X! 		*ip =3D cred->cr_prison->pr_ip4[0];
 X! 		return;
 X! 	}
 X! 	return;
 X! }
 X!=20
 X! void
 X! prison_remote_ip6(struct ucred *cred, struct in6_addr *ip)
 X! {
 X! 	if (!jailed(cred))
 X! 		return;
 X! 	if (cred->cr_prison->pr_ip6s <=3D 0)
 X! 		return;
 X! 	if (IN6_IS_ADDR_LOOPBACK(ip)) {
 X! 		*ip =3D cred->cr_prison->pr_ip6[0];
 X  		return;
 X  	}
 X  	return;
 X***************
 X*** 374,391 ****
 X  int
 X  prison_if(struct ucred *cred, struct sockaddr *sa)
 X  {
 X! 	struct sockaddr_in *sai;
 X! 	int ok;
 X =20
 X! 	sai =3D (struct sockaddr_in *)sa;
 X! 	if ((sai->sin_family !=3D AF_INET) && jail_socket_unixiproute_only)
 X  		ok =3D 1;
 X! 	else if (sai->sin_family !=3D AF_INET)
 X! 		ok =3D 0;
 X! 	else if (cred->cr_prison->pr_ip !=3D ntohl(sai->sin_addr.s_addr))
 X! 		ok =3D 1;
 X! 	else
 X! 		ok =3D 0;
 X  	return (ok);
 X  }
 X =20
 X--- 613,655 ----
 X  int
 X  prison_if(struct ucred *cred, struct sockaddr *sa)
 X  {
 X! 	int ok =3D 0;
 X =20
 X! 	if (!(sa->sa_family =3D=3D AF_INET || sa->sa_family =3D=3D AF_INET6) =
 
 X! 	    && jail_socket_unixiproute_only)
 X  		ok =3D 1;
 X! 	else=20
 X! 	{
 X! 		if (sa->sa_family =3D=3D AF_INET)
 X! 		{
 X! 			int tmp;
 X! 			struct sockaddr_in *sai =3D (struct sockaddr_in *)sa;
 X! 			ok =3D 1;
 X! 			for (tmp =3D 0; tmp < cred->cr_prison->pr_ip4s; ++tmp)
 X! 			{
 X! 				if (cred->cr_prison->pr_ip4[tmp].s_addr =3D=3D
 sai->sin_addr.s_addr)
 X! 				{
 X! 					ok =3D 0;
 X! 					break;
 X! 				}
 X! 			}
 X! 		}
 X! 		else if (sa->sa_family =3D=3D AF_INET6)
 X! 		{
 X! 			struct sockaddr_in6 *sa6 =3D (struct sockaddr_in6
 *)sa;
 X! 			int tmp;
 X! 			ok =3D 1;
 X! 			for (tmp =3D 0; tmp < cred->cr_prison->pr_ip6s; ++tmp)
 X! 			{
 X! 				if
 (IN6_ARE_ADDR_EQUAL(&(cred->cr_prison->pr_ip6[tmp]),=20
 X! 							&(sa6->sin6_addr)))
 X! 				{
 X! 					ok =3D 0;
 X! 					break;
 X! 				}
 X! 			}
 X! 		}
 X! 	}
 X  	return (ok);
 X  }
 X =20
 X***************
 X*** 407,412 ****
 X--- 671,808 ----
 X  }
 X =20
 X  /*
 X+  * assumes that mtx_lock (pr->mtx)  is done
 X+  */
 X+ static int
 X+ prison_add_ip4(struct in_addr *ip, struct prison *pr, void *vpr_new, =
 void
 **pr_free)
 X+ {
 X+ 	struct in_addr *pr_new =3D vpr_new;
 X+ 	struct in_addr *wrk_new;
 X+=20
 X+ 	wrk_new =3D pr_new;
 X+ 	if (pr->pr_ip4s > 0)
 X+ 	{
 X+ 		struct in_addr *pr_old =3D pr->pr_ip4;
 X+ 		for (;pr_old < &(pr->pr_ip4[pr->pr_ip4s]) ; ++pr_old)
 X+ 		{
 X+ 			if (pr_old->s_addr =3D=3D ip->s_addr)
 X+ 			{
 X+ 				*pr_free =3D pr_new;
 X+ 				return 0;
 X+ 			}
 X+ 			*wrk_new++ =3D *pr_old;
 X+ 		}=20
 X+ 	}
 X+ 	*wrk_new =3D *ip;
 X+ 	++(pr->pr_ip4s);
 X+ 	if (pr->pr_ip4)
 X+ 		*pr_free =3D pr->pr_ip4;
 X+ 	pr->pr_ip4 =3D pr_new;
 X+ 	return 0;=09
 X+ }
 X+=20
 X+ static int
 X+ prison_add_ip6(struct in6_addr *ip, struct prison *pr, void *vpr_new,
 void **pr_free)
 X+ {
 X+ 	struct in6_addr *pr_new =3D vpr_new;
 X+ 	struct in6_addr *wrk_new;
 X+=20
 X+ 	wrk_new =3D pr_new;
 X+ 	if (pr->pr_ip6s > 0)
 X+ 	{
 X+ 		struct in6_addr *pr_old =3D pr->pr_ip6;
 X+ 		for (;pr_old < &(pr->pr_ip6[pr->pr_ip6s]) ; ++pr_old)
 X+ 		{
 X+ 			if (IN6_ARE_ADDR_EQUAL(pr_old, ip))
 X+ 			{
 X+ 				*pr_free =3D pr_new;
 X+ 				return 0;
 X+ 			}
 X+ 			*wrk_new++ =3D *pr_old;
 X+ 		}=20
 X+ 	}
 X+ 	*wrk_new =3D *ip;
 X+ 	++(pr->pr_ip6s);
 X+ 	if (pr->pr_ip6)
 X+ 		*pr_free =3D pr->pr_ip6;
 X+ 	pr->pr_ip6 =3D pr_new;
 X+ 	return 0;=09
 X+ }
 X+=20
 X+ static int
 X+ prison_del_ip4(struct in_addr *ip, struct prison *pr, void *vpr_new, =
 void
 **pr_free)
 X+ {
 X+ 	struct in_addr *pr_new =3D vpr_new;
 X+ 	struct in_addr *wrk_new;
 X+ 	int errno =3D ENOENT;
 X+=20
 X+ 	wrk_new =3D pr_new;
 X+ 	if (pr->pr_ip4s > 0)
 X+ 	{
 X+ 		struct in_addr *pr_old =3D pr->pr_ip4;
 X+ 		for (;pr_old < &(pr->pr_ip4[pr->pr_ip4s]) ; ++pr_old)
 X+ 		{
 X+ 			if (pr_old->s_addr !=3D ip->s_addr)
 X+ 			{
 X+ 				if (wrk_new) { /* remove only if one or more
 elements remaining */
 X+ 					*wrk_new++ =3D *pr_old;
 X+ 				}
 X+ 			}
 X+ 			else
 X+ 			{
 X+ 				errno =3D 0; /* found element to delete */
 X+ 			}
 X+ 		}=20
 X+ 	}
 X+ 	if (errno =3D=3D 0)
 X+ 	{
 X+ 		--(pr->pr_ip4s);
 X+ 		/* attach new array */
 X+ 		if (pr->pr_ip4)
 X+ 			*pr_free =3D pr->pr_ip4;
 X+ 		pr->pr_ip4 =3D pr_new;
 X+ 	}
 X+ 	return errno;=09
 X+ }
 X+=20
 X+ static int
 X+ prison_del_ip6(struct in6_addr *ip, struct prison *pr, void *vpr_new,
 void **pr_free)
 X+ {
 X+ 	struct in6_addr *pr_new =3D vpr_new;
 X+ 	struct in6_addr *wrk_new;
 X+ 	int errno =3D ENOENT;
 X+=20
 X+ 	wrk_new =3D pr_new;
 X+ 	if (pr->pr_ip6s > 0)
 X+ 	{
 X+ 		struct in6_addr *pr_old =3D pr->pr_ip6;
 X+ 		for (;pr_old < &(pr->pr_ip6[pr->pr_ip6s]) ; ++pr_old)
 X+ 		{
 X+ 			if (!IN6_ARE_ADDR_EQUAL(pr_old, ip))
 X+ 			{
 X+ 				if (wrk_new) { /* remove only if one or more
 elements remaining */
 X+ 					*wrk_new++ =3D *pr_old;
 X+ 				}
 X+ 			}
 X+ 			else
 X+ 			{
 X+ 				errno =3D 0; /* found element to delete */
 X+ 			}
 X+ 		}=20
 X+ 	}
 X+ 	if (errno =3D=3D 0)
 X+ 	{
 X+ 		--(pr->pr_ip6s);
 X+ 		/* attach new array */
 X+ 		if (pr->pr_ip6)
 X+ 			*pr_free =3D pr->pr_ip6;
 X+ 		pr->pr_ip6 =3D pr_new;
 X+ 	}
 X+ 	return errno;=09
 X+ }
 X+=20
 X+=20
 X+ /*
 X   * Return 1 if the passed credential is in a jail, otherwise 0.
 X   */
 X  int
 X***************
 X*** 452,486 ****
 X  	struct xprison *xp, *sxp;
 X  	struct prison *pr;
 X  	int count, error;
 X =20
 X  	mtx_assert(&Giant, MA_OWNED);
 X  	if (jailed(req->td->td_ucred))
 X  		return (0);
 X  retry:
 X  	mtx_lock(&allprison_mtx);
 X! 	count =3D prisoncount;
 X  	mtx_unlock(&allprison_mtx);
 X =20
 X  	if (count =3D=3D 0)
 X  		return (0);
 X =20
 X  	sxp =3D xp =3D malloc(sizeof(*xp) * count, M_TEMP, M_WAITOK | =
 M_ZERO);
 X  	mtx_lock(&allprison_mtx);
 X! 	if (count !=3D prisoncount) {
 X  		mtx_unlock(&allprison_mtx);
 X  		free(sxp, M_TEMP);
 X  		goto retry;
 X  	}
 X  =09
 X  	LIST_FOREACH(pr, &allprison, pr_list) {
 X! 		mtx_lock(&pr->pr_mtx);
 X! 		xp->pr_version =3D XPRISON_VERSION;
 X! 		xp->pr_id =3D pr->pr_id;
 X! 		strlcpy(xp->pr_path, pr->pr_path, sizeof(xp->pr_path));
 X! 		strlcpy(xp->pr_host, pr->pr_host, sizeof(xp->pr_host));
 X! 		xp->pr_ip =3D pr->pr_ip;
 X! 		mtx_unlock(&pr->pr_mtx);
 X! 		xp++;
 X  	}
 X  	mtx_unlock(&allprison_mtx);
 X =20
 X--- 848,914 ----
 X  	struct xprison *xp, *sxp;
 X  	struct prison *pr;
 X  	int count, error;
 X+ 	int prcount;
 X =20
 X  	mtx_assert(&Giant, MA_OWNED);
 X  	if (jailed(req->td->td_ucred))
 X  		return (0);
 X  retry:
 X  	mtx_lock(&allprison_mtx);
 X! 	count =3D 0;
 X! 	prcount =3D 0;
 X! 	LIST_FOREACH(pr, &allprison, pr_list) {
 X! 		++prcount;
 X! 		if (pr->pr_ip4s || pr->pr_ip6s) {
 X! 			count +=3D max(pr->pr_ip4s, pr->pr_ip6s);
 X! 		}=09
 X! 		else {
 X! 			++count;
 X! 		}
 X! 	}
 X  	mtx_unlock(&allprison_mtx);
 X =20
 X  	if (count =3D=3D 0)
 X  		return (0);
 X =20
 X+ 	/*printf("jls:count=3D%d:%d\n", count, prcount);*/
 X  	sxp =3D xp =3D malloc(sizeof(*xp) * count, M_TEMP, M_WAITOK | =
 M_ZERO);
 X  	mtx_lock(&allprison_mtx);
 X! 	if (prcount !=3D prisoncount) {
 X  		mtx_unlock(&allprison_mtx);
 X  		free(sxp, M_TEMP);
 X  		goto retry;
 X  	}
 X  =09
 X  	LIST_FOREACH(pr, &allprison, pr_list) {
 X! 		int id =3D 0;
 X! 		int i;
 X! 		int maxcnt =3D max(pr->pr_ip4s, pr->pr_ip6s);
 X! 		/*printf("jls:maxcnt=3D%d\n", maxcnt);*/
 X! 		for (i =3D 0; i < (maxcnt ? maxcnt : 1) ; ++i)
 X! 		{=09
 X! 			/*printf("jls:-0-:%d:%d\n", i, maxcnt);*/
 X! 			mtx_lock(&pr->pr_mtx);
 X! 			xp->pr_version =3D XPRISON_VERSION;
 X! 			xp->pr_id =3D pr->pr_id;
 X! 			strlcpy(xp->pr_path, pr->pr_path,
 sizeof(xp->pr_path));
 X! 			strlcpy(xp->pr_host, pr->pr_host,
 sizeof(xp->pr_host));
 X! 			if (i < pr->pr_ip4s) {
 X! 				xp->pr4_id  =3D id;
 X! 				xp->pr4_num =3D pr->pr_ip4[i];
 X! 			}
 X! 			else
 X! 				xp->pr4_id  =3D -1;
 X! 			if (i < pr->pr_ip6s) {
 X! 				xp->pr6_id  =3D id;
 X! 				xp->pr6_num =3D pr->pr_ip6[i];
 X! 			}
 X! 			else
 X! 				xp->pr6_id  =3D -1;
 X! 			++id;
 X! 			mtx_unlock(&pr->pr_mtx);
 X! 			xp++;
 X! 		}
 X  	}
 X  	mtx_unlock(&allprison_mtx);
 X =20
 XIndex: sys/net/rtsock.c
 X=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
 XRCS file: /usr/freebsd.cvs/src/sys/net/rtsock.c,v
 Xretrieving revision 1.113.2.3
 Xdiff -c -r1.113.2.3 rtsock.c
 X*** sys/net/rtsock.c	15 Sep 2004 15:14:18 -0000	1.113.2.3
 X--- sys/net/rtsock.c	24 Nov 2004 23:41:10 -0000
 X***************
 X*** 329,335 ****
 X  	int len, error =3D 0;
 X  	struct ifnet *ifp =3D NULL;
 X  	struct ifaddr *ifa =3D NULL;
 X! 	struct sockaddr_in jail;
 X =20
 X  #define senderr(e) { error =3D e; goto flush;}
 X  	if (m =3D=3D NULL || ((m->m_len < sizeof(long)) &&
 X--- 329,336 ----
 X  	int len, error =3D 0;
 X  	struct ifnet *ifp =3D NULL;
 X  	struct ifaddr *ifa =3D NULL;
 X! 	struct sockaddr_in  jail4;
 X! 	struct sockaddr_in6 jail6;
 X =20
 X  #define senderr(e) { error =3D e; goto flush;}
 X  	if (m =3D=3D NULL || ((m->m_len < sizeof(long)) &&
 X***************
 X*** 444,456 ****
 X  					info.rti_info[RTAX_IFP] =3D
 X
 ifaddr_byindex(ifp->if_index)->ifa_addr;
 X  					if (jailed(so->so_cred)) {
 X! 						bzero(&jail, sizeof(jail));
 X! 						jail.sin_family =3D PF_INET;
 X! 						jail.sin_len =3D sizeof(jail);
 X! 						jail.sin_addr.s_addr =3D
 X!
 htonl(prison_getip(so->so_cred));
 X! 						info.rti_info[RTAX_IFA] =3D
 X! 						    (struct sockaddr
 *)&jail;
 X  					} else
 X  						info.rti_info[RTAX_IFA] =3D
 X  						    rt->rt_ifa->ifa_addr;
 X--- 445,476 ----
 X  					info.rti_info[RTAX_IFP] =3D
 X
 ifaddr_byindex(ifp->if_index)->ifa_addr;
 X  					if (jailed(so->so_cred)) {
 X! 						if
 (rt->rt_ifa->ifa_addr->sa_family =3D=3D PF_INET) {
 X! 							bzero(&jail4,
 sizeof(jail4));
 X! 							jail4.sin_family =3D
 PF_INET;
 X! 							jail4.sin_len =3D
 sizeof(jail4);
 X! 							error =3D
 prison_first_ip4(so->so_cred,=20
 X!
 &jail4.sin_addr);=20
 X! 							if (error)
 X!
 senderr(error);
 X!
 info.rti_info[RTAX_IFA] =3D
 X! 							    (struct sockaddr
 *)&jail4;
 X! 						}
 X! 						else if
 (rt->rt_ifa->ifa_addr->sa_family =3D=3D PF_INET6) {
 X! 							bzero(&jail6,
 sizeof(jail6));
 X! 							jail6.sin6_family =3D
 PF_INET6;
 X! 							jail6.sin6_len =3D
 sizeof(jail6);
 X! 							error =3D
 prison_first_ip6(so->so_cred,=20
 X!
 &jail6.sin6_addr);=20
 X! 							if (error)
 X!
 senderr(error);
 X!
 info.rti_info[RTAX_IFA] =3D
 X! 							    (struct sockaddr
 *)&jail6;
 X! 						}
 X! 						else {
 X!
 info.rti_info[RTAX_IFA] =3D
 X!
 rt->rt_ifa->ifa_addr;
 X! 						}
 X  					} else
 X  						info.rti_info[RTAX_IFA] =3D
 X  						    rt->rt_ifa->ifa_addr;
 XIndex: sys/netinet/in_pcb.c
 X=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
 XRCS file: /usr/freebsd.cvs/src/sys/netinet/in_pcb.c,v
 Xretrieving revision 1.153.2.1.2.1
 Xdiff -c -r1.153.2.1.2.1 in_pcb.c
 X*** sys/netinet/in_pcb.c	21 Oct 2004 09:30:47 -0000
 1.153.2.1.2.1
 X--- sys/netinet/in_pcb.c	24 Nov 2004 23:41:10 -0000
 X***************
 X*** 290,296 ****
 X  			return (EAFNOSUPPORT);
 X  #endif
 X  		if (sin->sin_addr.s_addr !=3D INADDR_ANY)
 X! 			if (prison_ip(cred, 0, &sin->sin_addr.s_addr))
 X  				return(EINVAL);
 X  		if (sin->sin_port !=3D *lportp) {
 X  			/* Don't allow the port to change. */
 X--- 290,296 ----
 X  			return (EAFNOSUPPORT);
 X  #endif
 X  		if (sin->sin_addr.s_addr !=3D INADDR_ANY)
 X! 			if (prison_redirect_ip4(cred, &sin->sin_addr))=20
 X  				return(EINVAL);
 X  		if (sin->sin_port !=3D *lportp) {
 X  			/* Don't allow the port to change. */
 X***************
 X*** 346,352 ****
 X  				     t->inp_socket->so_cred->cr_uid))
 X  					return (EADDRINUSE);
 X  			}
 X! 			if (prison && prison_ip(cred, 0,
 &sin->sin_addr.s_addr))
 X  				return (EADDRNOTAVAIL);
 X  			t =3D in_pcblookup_local(pcbinfo, sin->sin_addr,
 X  			    lport, prison ? 0 : wild);
 X--- 346,352 ----
 X  				     t->inp_socket->so_cred->cr_uid))
 X  					return (EADDRINUSE);
 X  			}
 X! 			if (prison && prison_redirect_ip4(cred,
 &sin->sin_addr))=20
 X  				return (EADDRNOTAVAIL);
 X  			t =3D in_pcblookup_local(pcbinfo, sin->sin_addr,
 X  			    lport, prison ? 0 : wild);
 X***************
 X*** 375,381 ****
 X  		int count;
 X =20
 X  		if (laddr.s_addr !=3D INADDR_ANY)
 X! 			if (prison_ip(cred, 0, &laddr.s_addr))
 X  				return (EINVAL);
 X =20
 X  		if (inp->inp_flags & INP_HIGHPORT) {
 X--- 375,381 ----
 X  		int count;
 X =20
 X  		if (laddr.s_addr !=3D INADDR_ANY)
 X! 			if (prison_redirect_ip4(cred, &laddr))=20
 X  				return (EINVAL);
 X =20
 X  		if (inp->inp_flags & INP_HIGHPORT) {
 X***************
 X*** 438,444 ****
 X  			    wild));
 X  		}
 X  	}
 X! 	if (prison_ip(cred, 0, &laddr.s_addr))
 X  		return (EINVAL);
 X  	*laddrp =3D laddr.s_addr;
 X  	*lportp =3D lport;
 X--- 438,444 ----
 X  			    wild));
 X  		}
 X  	}
 X! 	if (prison_redirect_ip4(cred, &laddr))=20
 X  		return (EINVAL);
 X  	*laddrp =3D laddr.s_addr;
 X  	*lportp =3D lport;
 X***************
 X*** 551,557 ****
 X  	socred =3D inp->inp_socket->so_cred;
 X  	if (laddr.s_addr =3D=3D INADDR_ANY && jailed(socred)) {
 X  		bzero(&sa, sizeof(sa));
 X! 		sa.sin_addr.s_addr =3D htonl(prison_getip(socred));
 X  		sa.sin_len =3D sizeof(sa);
 X  		sa.sin_family =3D AF_INET;
 X  		error =3D in_pcbbind_setup(inp, (struct sockaddr *)&sa,
 X--- 551,559 ----
 X  	socred =3D inp->inp_socket->so_cred;
 X  	if (laddr.s_addr =3D=3D INADDR_ANY && jailed(socred)) {
 X  		bzero(&sa, sizeof(sa));
 X! 		error =3D prison_first_ip4(socred, &sa.sin_addr);
 X! 		if (error)
 X! 			return (error);
 X  		sa.sin_len =3D sizeof(sa);
 X  		sa.sin_family =3D AF_INET;
 X  		error =3D in_pcbbind_setup(inp, (struct sockaddr *)&sa,
 XIndex: sys/netinet/raw_ip.c
 X=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
 XRCS file: /usr/freebsd.cvs/src/sys/netinet/raw_ip.c,v
 Xretrieving revision 1.142.2.2
 Xdiff -c -r1.142.2.2 raw_ip.c
 X*** sys/netinet/raw_ip.c	14 Oct 2004 11:45:26 -0000	1.142.2.2
 X--- sys/netinet/raw_ip.c	24 Nov 2004 23:41:10 -0000
 X***************
 X*** 212,220 ****
 X  		if (inp->inp_faddr.s_addr &&
 X  		    inp->inp_faddr.s_addr !=3D ip->ip_src.s_addr)
 X  			goto docontinue;
 X  		if (jailed(inp->inp_socket->so_cred))
 X! 			if (htonl(prison_getip(inp->inp_socket->so_cred)) !=3D
 X! 			    ip->ip_dst.s_addr)
 X  				goto docontinue;
 X  		if (last) {
 X  			struct mbuf *n;
 X--- 212,220 ----
 X  		if (inp->inp_faddr.s_addr &&
 X  		    inp->inp_faddr.s_addr !=3D ip->ip_src.s_addr)
 X  			goto docontinue;
 X+ 	=09
 X  		if (jailed(inp->inp_socket->so_cred))
 X! 			if (prison_match_ip4(inp->inp_socket->so_cred,
 &(ip->ip_dst)))=20
 X  				goto docontinue;
 X  		if (last) {
 X  			struct mbuf *n;
 X***************
 X*** 271,278 ****
 X  		ip->ip_p =3D inp->inp_ip_p;
 X  		ip->ip_len =3D m->m_pkthdr.len;
 X  		if (jailed(inp->inp_socket->so_cred))
 X! 			ip->ip_src.s_addr =3D
 X! 			    htonl(prison_getip(inp->inp_socket->so_cred));
 X  		else
 X  			ip->ip_src =3D inp->inp_laddr;
 X  		ip->ip_dst.s_addr =3D dst;
 X--- 271,286 ----
 X  		ip->ip_p =3D inp->inp_ip_p;
 X  		ip->ip_len =3D m->m_pkthdr.len;
 X  		if (jailed(inp->inp_socket->so_cred))
 X! 		{
 X! 			/* fallback to first ip */
 X! 			if (prison_match_ip4(inp->inp_socket->so_cred,
 &inp->inp_laddr)) {
 X! 				if ((error =3D
 prison_first_ip4(inp->inp_socket->so_cred,=20
 X! 					                     &ip->ip_src))
 !=3D 0)
 X! 					return error;
 X! 			}
 X! 			else
 X! 				ip->ip_src =3D inp->inp_laddr;
 X! 		}
 X  		else
 X  			ip->ip_src =3D inp->inp_laddr;
 X  		ip->ip_dst.s_addr =3D dst;
 X***************
 X*** 285,292 ****
 X  		INP_LOCK(inp);
 X  		ip =3D mtod(m, struct ip *);
 X  		if (jailed(inp->inp_socket->so_cred)) {
 X! 			if (ip->ip_src.s_addr !=3D
 X! 			    htonl(prison_getip(inp->inp_socket->so_cred))) {
 X  				INP_UNLOCK(inp);
 X  				m_freem(m);
 X  				return (EPERM);
 X--- 293,299 ----
 X  		INP_LOCK(inp);
 X  		ip =3D mtod(m, struct ip *);
 X  		if (jailed(inp->inp_socket->so_cred)) {
 X! 			if (prison_match_ip4(inp->inp_socket->so_cred,
 &ip->ip_src)) {
 X  				INP_UNLOCK(inp);
 X  				m_freem(m);
 X  				return (EPERM);
 X***************
 X*** 684,693 ****
 X  		return EINVAL;
 X =20
 X  	if (jailed(td->td_ucred)) {
 X  		if (addr->sin_addr.s_addr =3D=3D INADDR_ANY)
 X! 			addr->sin_addr.s_addr =3D
 X! 			    htonl(prison_getip(td->td_ucred));
 X! 		if (htonl(prison_getip(td->td_ucred)) !=3D
 addr->sin_addr.s_addr)
 X  			return (EADDRNOTAVAIL);
 X  	}
 X =20
 X--- 691,701 ----
 X  		return EINVAL;
 X =20
 X  	if (jailed(td->td_ucred)) {
 X+ 		int error;
 X  		if (addr->sin_addr.s_addr =3D=3D INADDR_ANY)
 X! 			if ((error =3D prison_first_ip4(td->td_ucred,
 &addr->sin_addr)) !=3D 0)
 X! 				return error;
 X! 		if (prison_match_ip4(td->td_ucred, &addr->sin_addr))=20
 X  			return (EADDRNOTAVAIL);
 X  	}
 X =20
 XIndex: sys/netinet/tcp_usrreq.c
 X=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
 XRCS file: /usr/freebsd.cvs/src/sys/netinet/tcp_usrreq.c,v
 Xretrieving revision 1.107
 Xdiff -c -r1.107 tcp_usrreq.c
 X*** sys/netinet/tcp_usrreq.c	16 Aug 2004 18:32:07 -0000	1.107
 X--- sys/netinet/tcp_usrreq.c	24 Nov 2004 23:41:10 -0000
 X***************
 X*** 356,362 ****
 X  	    && IN_MULTICAST(ntohl(sinp->sin_addr.s_addr)))
 X  		return (EAFNOSUPPORT);
 X  	if (td && jailed(td->td_ucred))
 X! 		prison_remote_ip(td->td_ucred, 0, &sinp->sin_addr.s_addr);
 X =20
 X  	COMMON_START();
 X  	if ((error =3D tcp_connect(tp, nam, td)) !=3D 0)
 X--- 356,362 ----
 X  	    && IN_MULTICAST(ntohl(sinp->sin_addr.s_addr)))
 X  		return (EAFNOSUPPORT);
 X  	if (td && jailed(td->td_ucred))
 X! 		prison_remote_ip4(td->td_ucred, &sinp->sin_addr);=20
 X =20
 X  	COMMON_START();
 X  	if ((error =3D tcp_connect(tp, nam, td)) !=3D 0)
 X***************
 X*** 385,390 ****
 X--- 385,393 ----
 X  	    && IN6_IS_ADDR_MULTICAST(&sin6p->sin6_addr))
 X  		return (EAFNOSUPPORT);
 X =20
 X+ 	if (td && jailed(td->td_ucred))
 X+ 		prison_remote_ip6(td->td_ucred, &sin6p->sin6_addr);=20
 X+=20
 X  	COMMON_START();
 X  	if (IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) {
 X  		struct sockaddr_in sin;
 XIndex: sys/netinet/udp_usrreq.c
 X=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
 XRCS file: /usr/freebsd.cvs/src/sys/netinet/udp_usrreq.c,v
 Xretrieving revision 1.162.2.3
 Xdiff -c -r1.162.2.3 udp_usrreq.c
 X*** sys/netinet/udp_usrreq.c	14 Oct 2004 11:49:25 -0000	1.162.2.3
 X--- sys/netinet/udp_usrreq.c	24 Nov 2004 23:41:10 -0000
 X***************
 X*** 822,828 ****
 X  	if (addr) {
 X  		sin =3D (struct sockaddr_in *)addr;
 X  		if (td && jailed(td->td_ucred))
 X! 			prison_remote_ip(td->td_ucred, 0,
 &sin->sin_addr.s_addr);
 X  		if (inp->inp_faddr.s_addr !=3D INADDR_ANY) {
 X  			error =3D EISCONN;
 X  			goto release;
 X--- 822,828 ----
 X  	if (addr) {
 X  		sin =3D (struct sockaddr_in *)addr;
 X  		if (td && jailed(td->td_ucred))
 X! 			prison_remote_ip4(td->td_ucred, &sin->sin_addr);=20
 X  		if (inp->inp_faddr.s_addr !=3D INADDR_ANY) {
 X  			error =3D EISCONN;
 X  			goto release;
 X***************
 X*** 1029,1035 ****
 X  	s =3D splnet();
 X  	sin =3D (struct sockaddr_in *)nam;
 X  	if (td && jailed(td->td_ucred))
 X! 		prison_remote_ip(td->td_ucred, 0, &sin->sin_addr.s_addr);
 X  	error =3D in_pcbconnect(inp, nam, td->td_ucred);
 X  	splx(s);
 X  	if (error =3D=3D 0)
 X--- 1029,1035 ----
 X  	s =3D splnet();
 X  	sin =3D (struct sockaddr_in *)nam;
 X  	if (td && jailed(td->td_ucred))
 X! 		prison_remote_ip4(td->td_ucred, &sin->sin_addr);
 X  	error =3D in_pcbconnect(inp, nam, td->td_ucred);
 X  	splx(s);
 X  	if (error =3D=3D 0)
 XIndex: sys/netinet6/in6_pcb.c
 X=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
 XRCS file: /usr/freebsd.cvs/src/sys/netinet6/in6_pcb.c,v
 Xretrieving revision 1.59.2.1.2.1
 Xdiff -c -r1.59.2.1.2.1 in6_pcb.c
 X*** sys/netinet6/in6_pcb.c	21 Oct 2004 09:30:47 -0000	1.59.2.1.2.1
 X--- sys/netinet6/in6_pcb.c	24 Nov 2004 23:41:10 -0000
 X***************
 X*** 127,132 ****
 X--- 127,133 ----
 X  	struct sockaddr_in6 *sin6 =3D (struct sockaddr_in6 *)NULL;
 X  	struct inpcbinfo *pcbinfo =3D inp->inp_pcbinfo;
 X  	u_short	lport =3D 0;
 X+ 	int prison =3D 0;
 X  	int wild =3D 0, reuseport =3D (so->so_options & SO_REUSEPORT);
 X =20
 X  	INP_INFO_WLOCK_ASSERT(pcbinfo);
 X***************
 X*** 148,153 ****
 X--- 149,158 ----
 X  		if (nam->sa_family !=3D AF_INET6)
 X  			return (EAFNOSUPPORT);
 X =20
 X+ 		if (!IN6_ARE_ADDR_EQUAL(&in6addr_any, &sin6->sin6_addr))=20
 X+ 			if (prison_redirect_ip6(cred, &sin6->sin6_addr))=20
 X+ 				return (EINVAL);
 X+=20
 X  		/* KAME hack: embed scopeid */
 X  		if (in6_embedscope(&sin6->sin6_addr, sin6, inp, NULL) !=3D 0)
 X  			return EINVAL;
 X***************
 X*** 191,202 ****
 X  			if (ntohs(lport) < IPV6PORT_RESERVED &&
 X  			    suser_cred(cred, SUSER_ALLOWJAIL))
 X  				return (EACCES);
 X  			if (so->so_cred->cr_uid !=3D 0 &&
 X  			    !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
 X  				t =3D in6_pcblookup_local(pcbinfo,
 X  				    &sin6->sin6_addr, lport,
 X! 				    INPLOOKUP_WILDCARD);
 X! 				if (t &&
 X  				    ((t->inp_vflag & INP_TIMEWAIT) =3D=3D 0) &&
 X  				    (so->so_type !=3D SOCK_STREAM ||
 X
 IN6_IS_ADDR_UNSPECIFIED(&t->in6p_faddr)) &&
 X--- 196,215 ----
 X  			if (ntohs(lport) < IPV6PORT_RESERVED &&
 X  			    suser_cred(cred, SUSER_ALLOWJAIL))
 X  				return (EACCES);
 X+ 			prison =3D jailed(cred);=20
 X  			if (so->so_cred->cr_uid !=3D 0 &&
 X  			    !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
 X  				t =3D in6_pcblookup_local(pcbinfo,
 X  				    &sin6->sin6_addr, lport,
 X! 				    prison ? 0 : INPLOOKUP_WILDCARD);
 X! 				if (t && (t->inp_vflag & INP_TIMEWAIT)) {
 X! 					if
 ((!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) ||
 X!
 !IN6_IS_ADDR_UNSPECIFIED(&t->in6p_laddr) ||
 X! 					    !(intotw(t)->tw_so_options &
 SO_REUSEPORT))
 X! 					    && so->so_cred->cr_uid !=3D=20
 X! 					    intotw(t)->tw_cred->cr_uid)
 X! 						return (EADDRINUSE);
 X! 				} else if (t &&
 X  				    ((t->inp_vflag & INP_TIMEWAIT) =3D=3D 0) &&
 X  				    (so->so_type !=3D SOCK_STREAM ||
 X
 IN6_IS_ADDR_UNSPECIFIED(&t->in6p_faddr)) &&
 X***************
 X*** 225,232 ****
 X  						return (EADDRINUSE);
 X  				}
 X  			}
 X  			t =3D in6_pcblookup_local(pcbinfo, &sin6->sin6_addr,
 X! 						lport, wild);
 X  			if (t && (reuseport & ((t->inp_vflag & INP_TIMEWAIT)
 ?
 X  			    intotw(t)->tw_so_options :=20
 X  			    t->inp_socket->so_options)) =3D=3D 0)
 X--- 238,247 ----
 X  						return (EADDRINUSE);
 X  				}
 X  			}
 X+ 			if (prison && prison_redirect_ip6(cred,
 &sin6->sin6_addr))
 X+ 				return (EADDRNOTAVAIL);
 X  			t =3D in6_pcblookup_local(pcbinfo, &sin6->sin6_addr,
 X! 						lport, prison ? 0 : wild);
 X  			if (t && (reuseport & ((t->inp_vflag & INP_TIMEWAIT)
 ?
 X  			    intotw(t)->tw_so_options :=20
 X  			    t->inp_socket->so_options)) =3D=3D 0)
 XIndex: sys/netinet6/raw_ip6.c
 X=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
 XRCS file: /usr/freebsd.cvs/src/sys/netinet6/raw_ip6.c,v
 Xretrieving revision 1.45.2.1
 Xdiff -c -r1.45.2.1 raw_ip6.c
 X*** sys/netinet6/raw_ip6.c	2 Sep 2004 21:18:09 -0000	1.45.2.1
 X--- sys/netinet6/raw_ip6.c	24 Nov 2004 23:41:10 -0000
 X***************
 X*** 68,73 ****
 X--- 68,74 ----
 X  #include <sys/lock.h>
 X  #include <sys/malloc.h>
 X  #include <sys/mbuf.h>
 X+ #include <sys/jail.h>
 X  #include <sys/proc.h>
 X  #include <sys/protosw.h>
 X  #include <sys/signalvar.h>
 X***************
 X*** 174,179 ****
 X--- 175,185 ----
 X  				goto docontinue;
 X  			}
 X  		}
 X+=20
 X+ 		if (jailed(in6p->in6p_socket->so_cred))
 X+ 			if (prison_match_ip6(in6p->in6p_socket->so_cred,
 &(ip6->ip6_dst)))
 X+ 				continue;
 X+=20
 X  		if (last) {
 X  			struct mbuf *n =3D m_copy(m, 0, (int)M_COPYALL);
 X =20
 X***************
 X*** 433,439 ****
 X  			error =3D EADDRNOTAVAIL;
 X  		goto bad;
 X  	}
 X! 	ip6->ip6_src =3D *in6a;
 X  	ip6->ip6_flow =3D (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) |
 X  		(in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK);
 X  	ip6->ip6_vfc =3D (ip6->ip6_vfc & ~IPV6_VERSION_MASK) |
 X--- 439,458 ----
 X  			error =3D EADDRNOTAVAIL;
 X  		goto bad;
 X  	}
 X! 	if (jailed(in6p->in6p_socket->so_cred))
 X! 	{
 X! 		/* fallback to first ip */
 X! 		if (prison_match_ip6(in6p->in6p_socket->so_cred, in6a)) {
 X! 			if ((error =3D
 prison_first_ip6(in6p->in6p_socket->so_cred,=20
 X! 				&ip6->ip6_src)) !=3D 0)
 X! 				return error;
 X! 		}
 X! 		else
 X! 			ip6->ip6_src =3D *in6a;
 X! 	}
 X! 	else
 X! 		ip6->ip6_src =3D *in6a;
 X!=20
 X  	ip6->ip6_flow =3D (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) |
 X  		(in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK);
 X  	ip6->ip6_vfc =3D (ip6->ip6_vfc & ~IPV6_VERSION_MASK) |
 X***************
 X*** 578,583 ****
 X--- 597,606 ----
 X  		INP_INFO_WUNLOCK(&ripcbinfo);
 X  		return error;
 X  	}
 X+ 	if (td && jailed(td->td_ucred) && !jail_allow_raw_sockets) {
 X+ 		return (EPERM);
 X+ 	}
 X+=20
 X  	error =3D soreserve(so, rip_sendspace, rip_recvspace);
 X  	if (error) {
 X  		INP_INFO_WUNLOCK(&ripcbinfo);
 X***************
 X*** 655,660 ****
 X--- 678,693 ----
 X =20
 X  	if (nam->sa_len !=3D sizeof(*addr))
 X  		return EINVAL;
 X+=20
 X+ 	if (jailed(td->td_ucred)) {
 X+ 		if (IN6_ARE_ADDR_EQUAL(&(addr->sin6_addr), &in6addr_any)) {
 X+ 			int error;
 X+ 			if ((error =3D prison_first_ip6(td->td_ucred,
 &addr->sin6_addr)) !=3D 0)
 X+ 				return error;
 X+ 		}
 X+ 		if (prison_match_ip6(td->td_ucred, &addr->sin6_addr))=20
 X+ 			return (EADDRNOTAVAIL);
 X+ 	}
 X  	if (TAILQ_EMPTY(&ifnet) || addr->sin6_family !=3D AF_INET6)
 X  		return EADDRNOTAVAIL;
 X  #ifdef ENABLE_DEFAULT_SCOPE
 XIndex: sys/netinet6/udp6_output.c
 X=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
 XRCS file: /usr/freebsd.cvs/src/sys/netinet6/udp6_output.c,v
 Xretrieving revision 1.18
 Xdiff -c -r1.18 udp6_output.c
 X*** sys/netinet6/udp6_output.c	7 Apr 2004 20:46:16 -0000	1.18
 X--- sys/netinet6/udp6_output.c	24 Nov 2004 23:41:10 -0000
 X***************
 X*** 67,72 ****
 X--- 67,73 ----
 X =20
 X  #include <sys/param.h>
 X  #include <sys/proc.h>
 X+ #include <sys/jail.h>
 X  #include <sys/malloc.h>
 X  #include <sys/mbuf.h>
 X  #include <sys/protosw.h>
 X***************
 X*** 166,171 ****
 X--- 167,174 ----
 X  			error =3D EISCONN;
 X  			goto release;
 X  		}
 X+ 		if (td && jailed(td->td_ucred))
 X+ 			prison_remote_ip6(td->td_ucred, &sin6->sin6_addr);=20
 X =20
 X  		/* protect *sin6 from overwrites */
 X  		tmp =3D *sin6;
 XIndex: sys/netinet6/udp6_usrreq.c
 X=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
 XRCS file: /usr/freebsd.cvs/src/sys/netinet6/udp6_usrreq.c,v
 Xretrieving revision 1.51
 Xdiff -c -r1.51 udp6_usrreq.c
 X*** sys/netinet6/udp6_usrreq.c	6 Aug 2004 03:45:45 -0000	1.51
 X--- sys/netinet6/udp6_usrreq.c	24 Nov 2004 23:41:10 -0000
 X***************
 X*** 67,72 ****
 X--- 67,73 ----
 X =20
 X  #include <sys/param.h>
 X  #include <sys/errno.h>
 X+ #include <sys/jail.h>
 X  #include <sys/kernel.h>
 X  #include <sys/lock.h>
 X  #include <sys/mbuf.h>
 X***************
 X*** 604,609 ****
 X--- 605,611 ----
 X  {
 X  	struct inpcb *inp;
 X  	int s, error;
 X+ 	struct sockaddr_in6 *sin6_p;
 X =20
 X  	INP_INFO_WLOCK(&udbinfo);
 X  	inp =3D sotoinpcb(so);
 X***************
 X*** 614,621 ****
 X  	INP_LOCK(inp);
 X =20
 X  	if ((inp->inp_flags & IN6P_IPV6_V6ONLY) =3D=3D 0) {
 X- 		struct sockaddr_in6 *sin6_p;
 X-=20
 X  		sin6_p =3D (struct sockaddr_in6 *)nam;
 X  		if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
 X  			struct sockaddr_in sin;
 X--- 616,621 ----
 X***************
 X*** 640,645 ****
 X--- 640,649 ----
 X  		goto out;
 X  	}
 X  	s =3D splnet();
 X+ 	sin6_p =3D (struct sockaddr_in6 *)nam;
 X+ 	if (td && jailed(td->td_ucred))
 X+ 		prison_remote_ip6(td->td_ucred, &sin6_p->sin6_addr);=20
 X+=20
 X  	error =3D in6_pcbconnect(inp, nam, td->td_ucred);
 X  	splx(s);
 X  	if (error =3D=3D 0) {
 XIndex: sys/nfsclient/nfs_vfsops.c
 X=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
 XRCS file: /usr/freebsd.cvs/src/sys/nfsclient/nfs_vfsops.c,v
 Xretrieving revision 1.158
 Xdiff -c -r1.158 nfs_vfsops.c
 X*** sys/nfsclient/nfs_vfsops.c	30 Jul 2004 22:08:52 -0000	1.158
 X--- sys/nfsclient/nfs_vfsops.c	24 Nov 2004 23:41:10 -0000
 X***************
 X*** 507,512 ****
 X--- 507,513 ----
 X  	mp->mnt_kern_flag =3D 0;
 X  	mp->mnt_flag =3D mountflag;
 X  	nam =3D sodupsockaddr((struct sockaddr *)sin, M_WAITOK);
 X+ 	args->flags|=3DNFSMNT_NOLOCKD;
 X  	if ((error =3D mountnfs(args, mp, nam, which, path, vpp,
 X  	    td->td_ucred)) !=3D 0) {
 X  		printf("nfs_mountroot: mount %s on %s: %d", path, which,
 error);
 XIndex: sys/sys/jail.h
 X=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
 XRCS file: /usr/freebsd.cvs/src/sys/sys/jail.h,v
 Xretrieving revision 1.21
 Xdiff -c -r1.21 jail.h
 X*** sys/sys/jail.h	26 Apr 2004 19:46:52 -0000	1.21
 X--- sys/sys/jail.h	24 Nov 2004 23:41:10 -0000
 X***************
 X*** 6,23 ****
 X   * this stuff is worth it, you can buy me a beer in return.
 Poul-Henning Kamp
 X   *
 -------------------------------------------------------------------------=
 ---
 X   *
 X!  * $FreeBSD$
 X   *
 X   */
 X =20
 X  #ifndef _SYS_JAIL_H_
 X  #define _SYS_JAIL_H_
 X =20
 X  struct jail {
 X! 	u_int32_t	version;
 X! 	char		*path;
 X! 	char		*hostname;
 X! 	u_int32_t	ip_number;
 X  };
 X =20
 X  struct xprison {
 X--- 6,64 ----
 X   * this stuff is worth it, you can buy me a beer in return.
 Poul-Henning Kamp
 X   *
 -------------------------------------------------------------------------=
 ---
 X   *
 X!  * $FreeBSD: src/sys/sys/jail.h,v 1.18 2003/04/09 02:55:18 mike Exp $
 X   *
 X   */
 X =20
 X  #ifndef _SYS_JAIL_H_
 X  #define _SYS_JAIL_H_
 X =20
 X+ #include <netinet/in.h>
 X+=20
 X+ /*
 X+  * to safe a system call i reuse the jail systemcall to=20
 X+  * to modify a jail. I will enable the ability to add
 X+  * and remove ip4/6 numbers to a jail.
 X+  * To get rid of it i playing around with version and=20
 X+  * function numbers.
 X+  * A jail id is only create on setup path and hostname
 X+  * these values are inmutable. The function number is
 X+  * CREATEJAIL
 X+  */
 X  struct jail {
 X! 	u_int32_t       version;
 X! 	union {
 X! 	struct v1_s {
 X! 		char            *path;
 X! 		char            *hostname;
 X! 		u_int32_t       ip_number;
 X! 	} v1;
 X! 	struct v2_s {
 X! 		u_int32_t       function;
 X! 	#define CREATEJAIL 1
 X! 	#define ADDIP4 2
 X! 	#define DELIP4 3
 X! 	#define ADDIP6 4
 X! 	#define DELIP6 5
 X! 		union
 X! 		{
 X! 			struct=20
 X! 			{
 X! 				char		*path;
 X! 				char		*hostname;
 X! 			} createjail;
 X! 			struct=20
 X! 			{
 X! 				int id;
 X! 				union=20
 X! 				{
 X! 					struct in_addr 	ip4_num;
 X! 					struct in6_addr ip6_num;
 X! 				} v4_6;
 X! 			} add_del;
 X! 		} u;
 X! 	} v2;
 X! 	} u;
 X  };
 X =20
 X  struct xprison {
 X***************
 X*** 25,33 ****
 X  	int		 pr_id;
 X  	char		 pr_path[MAXPATHLEN];
 X  	char 		 pr_host[MAXHOSTNAMELEN];
 X! 	u_int32_t	 pr_ip;
 X  };
 X! #define	XPRISON_VERSION	1
 X =20
 X  #ifndef _KERNEL
 X =20
 X--- 66,77 ----
 X  	int		 pr_id;
 X  	char		 pr_path[MAXPATHLEN];
 X  	char 		 pr_host[MAXHOSTNAMELEN];
 X! 	int		 pr4_id;
 X! 	struct in_addr 	 pr4_num; /* null is empty */
 X! 	int		 pr6_id;
 X! 	struct in6_addr  pr6_num; /* null is empty */
 X  };
 X! #define	XPRISON_VERSION	6
 X =20
 X  #ifndef _KERNEL
 X =20
 X***************
 X*** 37,45 ****
 X  #else /* _KERNEL */
 X =20
 X  #include <sys/queue.h>
 X  #include <sys/_lock.h>
 X  #include <sys/_mutex.h>
 X- #include <sys/_task.h>
 X =20
 X  #define JAIL_MAX	999999
 X =20
 X--- 81,89 ----
 X  #else /* _KERNEL */
 X =20
 X  #include <sys/queue.h>
 X+ #include <sys/_task.h>
 X  #include <sys/_lock.h>
 X  #include <sys/_mutex.h>
 X =20
 X  #define JAIL_MAX	999999
 X =20
 X***************
 X*** 55,64 ****
 X   * Lock key:
 X   *   (a) allprison_mutex
 X   *   (p) locked by pr_mutex
 X   *   (c) set only during creation before the structure is shared, no
 mutex
 X   *       required to read
 X-  *   (d) set only during destruction of jail, no mutex needed
 X   */
 X  struct prison {
 X  	LIST_ENTRY(prison) pr_list;			/* (a) all prisons
 */
 X  	int		 pr_id;				/* (c) prison id */
 X--- 99,110 ----
 X   * Lock key:
 X   *   (a) allprison_mutex
 X   *   (p) locked by pr_mutex
 X+  *   (d) set only during destruction of jail, no mutex needed
 X   *   (c) set only during creation before the structure is shared, no
 mutex
 X   *       required to read
 X   */
 X+=20
 X+ struct mtx;
 X  struct prison {
 X  	LIST_ENTRY(prison) pr_list;			/* (a) all prisons
 */
 X  	int		 pr_id;				/* (c) prison id */
 X***************
 X*** 66,75 ****
 X  	char		 pr_path[MAXPATHLEN];		/* (c) chroot path
 */
 X  	struct vnode	*pr_root;			/* (c) vnode to rdir
 */
 X  	char 		 pr_host[MAXHOSTNAMELEN];	/* (p) jail hostname
 */
 X! 	u_int32_t	 pr_ip;				/* (c) ip addr host
 */
 X  	void		*pr_linux;			/* (p) linux abi */
 X  	int		 pr_securelevel;		/* (p) securelevel
 */
 X- 	struct task	 pr_task;			/* (d) destroy task
 */
 X  	struct mtx	 pr_mtx;
 X  };
 X =20
 X--- 112,124 ----
 X  	char		 pr_path[MAXPATHLEN];		/* (c) chroot path
 */
 X  	struct vnode	*pr_root;			/* (c) vnode to rdir
 */
 X  	char 		 pr_host[MAXHOSTNAMELEN];	/* (p) jail hostname
 */
 X! 	int		 pr_ip4s; 			/* (p) ipv4 addr
 count */
 X! 	struct in_addr	*pr_ip4;			/* (p) ipv4 addr
 host */
 X! 	int		 pr_ip6s; 			/* (p) ipv6 addr
 count */
 X! 	struct in6_addr *pr_ip6;			/* (p) ipv6 addr
 host */
 X!         struct task      pr_task;                       /* (d) =
 destroy
 task */
 X  	void		*pr_linux;			/* (p) linux abi */
 X  	int		 pr_securelevel;		/* (p) securelevel
 */
 X  	struct mtx	 pr_mtx;
 X  };
 X =20
 X***************
 X*** 78,88 ****
 X   *
 X   * XXX MIB entries will need to be protected by a mutex.
 X   */
 X  extern int	jail_set_hostname_allowed;
 X  extern int	jail_socket_unixiproute_only;
 X  extern int	jail_sysvipc_allowed;
 X- extern int	jail_getfsstat_jailrootonly;
 X- extern int	jail_allow_raw_sockets;
 X =20
 X  LIST_HEAD(prisonlist, prison);
 X  extern struct	prisonlist allprison;
 X--- 127,137 ----
 X   *
 X   * XXX MIB entries will need to be protected by a mutex.
 X   */
 X+ extern int      jail_getfsstat_jailrootonly;
 X+ extern int      jail_allow_raw_sockets;
 X  extern int	jail_set_hostname_allowed;
 X  extern int	jail_socket_unixiproute_only;
 X  extern int	jail_sysvipc_allowed;
 X =20
 X  LIST_HEAD(prisonlist, prison);
 X  extern struct	prisonlist allprison;
 X***************
 X*** 91,108 ****
 X   * Kernel support functions for jail().
 X   */
 X  struct ucred;
 X- struct mount;
 X  struct sockaddr;
 X  int jailed(struct ucred *cred);
 X  void getcredhostname(struct ucred *cred, char *, size_t);
 X- int prison_check(struct ucred *cred1, struct ucred *cred2);
 X  int prison_check_mount(struct ucred *cred, struct mount *mp);
 X  void prison_free(struct prison *pr);
 X! u_int32_t prison_getip(struct ucred *cred);
 X  void prison_hold(struct prison *pr);
 X  int prison_if(struct ucred *cred, struct sockaddr *sa);
 X! int prison_ip(struct ucred *cred, int flag, u_int32_t *ip);
 X! void prison_remote_ip(struct ucred *cred, int flags, u_int32_t *ip);
 X =20
 X  #endif /* !_KERNEL */
 X  #endif /* !_SYS_JAIL_H_ */
 X--- 140,163 ----
 X   * Kernel support functions for jail().
 X   */
 X  struct ucred;
 X  struct sockaddr;
 X+ struct mount;
 X  int jailed(struct ucred *cred);
 X  void getcredhostname(struct ucred *cred, char *, size_t);
 X  int prison_check_mount(struct ucred *cred, struct mount *mp);
 X+ int prison_check(struct ucred *cred1, struct ucred *cred2);
 X  void prison_free(struct prison *pr);
 X! int  prison_first_ip6(struct ucred *cred, struct in6_addr *out);=20
 X! int  prison_first_ip4(struct ucred *cred, struct in_addr *out);=20
 X! int  prison_match_ip4(struct ucred *cred, struct in_addr *in);=20
 X! int  prison_match_ip6(struct ucred *cred, struct in6_addr *in);=20
 X  void prison_hold(struct prison *pr);
 X  int prison_if(struct ucred *cred, struct sockaddr *sa);
 X! int prison_redirect_ip4(struct ucred *cred, struct in_addr *ip);
 X! int prison_redirect_ip6(struct ucred *cred, struct in6_addr *ip);
 X! void prison_remote_ip4(struct ucred *cred, struct in_addr *ip);
 X! void prison_remote_ip6(struct ucred *cred, struct in6_addr *ip);
 X!=20
 X =20
 X  #endif /* !_KERNEL */
 X  #endif /* !_SYS_JAIL_H_ */
 END-of-ipv6.jail.patch
 exit
 
 
State-Changed-From-To: open->feedback 
State-Changed-By: linimon 
State-Changed-When: Tue Jun 19 01:17:01 UTC 2007 
State-Changed-Why:  
To submitter: do you have a patch that applies to -CURRENT by any chance? 


Responsible-Changed-From-To: freebsd-bugs->linimon 
Responsible-Changed-By: linimon 
Responsible-Changed-When: Tue Jun 19 01:17:01 UTC 2007 
Responsible-Changed-Why:  
Track this, I have someone interested in this feature. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=69064 
State-Changed-From-To: feedback->closed 
State-Changed-By: linimon 
State-Changed-When: Mon Jul 23 03:33:44 UTC 2007 
State-Changed-Why:  
There is a much better patch that was written by pjd and modified by 
bz; however, I have taken some of your work on the mapages and will 
add them to that patch and try to put the whole thing in Perforce. 
But thanks for the contribution. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=69064 
>Unformatted:
