Index: sys/jail.h =================================================================== RCS file: /home/dcvs/src/sys/sys/jail.h,v retrieving revision 1.9 diff -u -p -r1.9 jail.h --- sys/jail.h 29 Dec 2006 18:02:56 -0000 1.9 +++ sys/jail.h 17 Jan 2007 12:45:47 -0000 @@ -68,8 +68,8 @@ MALLOC_DECLARE(M_PRISON); /* Used to store the IPs of the jail */ struct jail_ip_storage { - SLIST_ENTRY(jail_ip_storage) entries; struct sockaddr_storage ip; + SLIST_ENTRY(jail_ip_storage) entries; }; /* @@ -85,10 +85,10 @@ struct prison { struct nchandle pr_root; /* namecache entry of root */ char pr_host[MAXHOSTNAMELEN]; /* host name */ SLIST_HEAD(iplist, jail_ip_storage) pr_ips; /* list of IP addresses */ - struct sockaddr_storage *local_ip4; /* cache for a loopback ipv4 address */ - struct sockaddr_storage *nonlocal_ip4; /* cache for a non loopback ipv4 address */ - struct sockaddr_storage *local_ip6; /* cache for a loopback ipv6 address */ - struct sockaddr_storage *nonlocal_ip6; /* cache for a non loopback ipv6 address */ + struct sockaddr_in *local_ip4; /* cache for a loopback ipv4 address */ + struct sockaddr_in *nonlocal_ip4; /* cache for a non loopback ipv4 address */ + struct sockaddr_in6 *local_ip6; /* cache for a loopback ipv6 address */ + struct sockaddr_in6 *nonlocal_ip6; /* cache for a non loopback ipv6 address */ void *pr_linux; /* Linux ABI emulation */ int pr_securelevel; /* jail securelevel */ struct varsymset pr_varsymset; /* jail varsyms */ @@ -105,8 +105,10 @@ extern int jail_chflags_allowed; void prison_hold(struct prison *); void prison_free(struct prison *); int jailed_ip(struct prison *, struct sockaddr *); -int prison_get_local(struct prison *pr, struct sockaddr *); -int prison_get_nonlocal(struct prison *pr, struct sockaddr *); +struct sockaddr * + prison_get_local(struct prison *pr, sa_family_t, struct sockaddr *); +struct sockaddr * + prison_get_nonlocal(struct prison *pr, sa_family_t, struct sockaddr *); /* * Return 1 if the passed credential is in a jail, otherwise 0. Index: kern/kern_jail.c =================================================================== RCS file: /home/dcvs/src/sys/kern/kern_jail.c,v retrieving revision 1.16 diff -u -p -r1.16 kern_jail.c --- kern/kern_jail.c 1 Jan 2007 19:45:54 -0000 1.16 +++ kern/kern_jail.c 17 Jan 2007 12:53:16 -0000 @@ -59,6 +59,7 @@ #include static struct prison *prison_find(int); +static void prison_ipcache_init(struct prison *); MALLOC_DEFINE(M_PRISON, "prison", "Prison structures"); @@ -195,6 +196,7 @@ sys_jail(struct jail_args *uap) cache_copy(&nd.nl_nch, &pr->pr_root); varsymset_init(&pr->pr_varsymset, NULL); + prison_ipcache_init(pr); tryprid = lastprid + 1; if (tryprid == JAIL_MAX) @@ -255,6 +257,45 @@ sys_jail_attach(struct jail_attach_args return(kern_jail_attach(uap->jid)); } +static void +prison_ipcache_init(struct prison *pr) +{ + struct jail_ip_storage *jis; + struct sockaddr_in *ip4; + struct sockaddr_in6 *ip6; + + SLIST_FOREACH(jis, &pr->pr_ips, entries) { + switch (jis->ip.ss_family) { + case AF_INET: + ip4 = (struct sockaddr_in *)&jis->ip; + if ((ntohl(ip4->sin_addr.s_addr) >> IN_CLASSA_NSHIFT) == + IN_LOOPBACKNET) { + /* loopback address */ + if (pr->local_ip4 == NULL) + pr->local_ip4 = ip4; + } else { + /* public address */ + if (pr->nonlocal_ip4 == NULL) + pr->nonlocal_ip4 = ip4; + } + break; + + case AF_INET6: + ip6 = (struct sockaddr_in6 *)&jis->ip; + if (IN6_IS_ADDR_LOOPBACK(&ip6->sin6_addr)) { + /* loopback address */ + if (pr->local_ip6 == NULL) + pr->local_ip6 = ip6; + } else { + /* public address */ + if (pr->nonlocal_ip6 == NULL) + pr->nonlocal_ip6 = ip6; + } + break; + } + } +} + /* * Changes INADDR_LOOPBACK for a valid jail address. * ip is in network byte order. @@ -284,7 +325,8 @@ prison_replace_wildcards(struct thread * ip4->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) || (ip->sa_family == AF_INET6 && IN6_IS_ADDR_LOOPBACK(&ip6->sin6_addr))) { - if (!prison_get_local(pr, ip) && !prison_get_nonlocal(pr, ip)) + if (!prison_get_local(pr, ip->sa_family, ip) && + !prison_get_nonlocal(pr, ip->sa_family, ip)) return(0); else return(1); @@ -309,7 +351,8 @@ prison_remote_ip(struct thread *td, stru ip4->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) || (ip->sa_family == AF_INET6 && IN6_IS_ADDR_LOOPBACK(&ip6->sin6_addr))) { - if (!prison_get_local(pr, ip) && !prison_get_nonlocal(pr, ip)) + if (!prison_get_local(pr, ip->sa_family, ip) && + !prison_get_nonlocal(pr, ip->sa_family, ip)) return(0); else return(1); @@ -319,135 +362,68 @@ prison_remote_ip(struct thread *td, stru /* * Prison get non loopback ip: - * Put on *ip the first IP address that is not a loopback address. - * af is the address family of the ip we want (AF_INET|AF_INET6). + * - af is the address family of the ip we want (AF_INET|AF_INET6). + * - If ip != NULL, put the first IP address that is not a loopback address + * into *ip. + * * ip is in network by order and we don't touch it unless we find a valid ip. - * Return 1 if we've found a non loopback ip, else return 0. + * No matter if ip == NULL or not, we return either a valid struct sockaddr *, + * or NULL. This struct may not be modified. */ -int -prison_get_nonlocal(struct prison *pr, struct sockaddr *ip) +struct sockaddr * +prison_get_nonlocal(struct prison *pr, sa_family_t af, struct sockaddr *ip) { - struct jail_ip_storage *jis; - struct sockaddr_in *jip4, *ip4; - struct sockaddr_in6 *jip6, *ip6; + struct sockaddr_in *ip4 = (struct sockaddr_in *)ip; + struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)ip; - ip4 = (struct sockaddr_in *)ip; - ip6 = (struct sockaddr_in6 *)ip; /* Check if it is cached */ - switch(ip->sa_family) { - case AF_INET: - /* -1 Means that we don't have any address */ - if (pr->nonlocal_ip4 == (struct sockaddr_storage *)-1) - return(0); - if (pr->nonlocal_ip4 != NULL) { - jip4 = (struct sockaddr_in *) pr->nonlocal_ip4; - ip4->sin_addr.s_addr = jip4->sin_addr.s_addr; - } - break; - case AF_INET6: - /* -1 Means that we don't have any address */ - if (pr->nonlocal_ip6 == (struct sockaddr_storage *)-1) - return(0); - if (pr->nonlocal_ip6 != NULL) { - jip6 = (struct sockaddr_in6 *) pr->nonlocal_ip6; - ip6->sin6_addr = jip6->sin6_addr; - } - break; - }; - SLIST_FOREACH(jis, &pr->pr_ips, entries) { - switch (ip->sa_family) { - case AF_INET: - jip4 = (struct sockaddr_in *) &jis->ip; - if (jip4->sin_family == AF_INET && - ((ntohl(jip4->sin_addr.s_addr) >> IN_CLASSA_NSHIFT) != IN_LOOPBACKNET)) { - pr->nonlocal_ip4 = &jis->ip; - ip4->sin_addr.s_addr = jip4->sin_addr.s_addr; - return(1); - } - break; - case AF_INET6: - jip6 = (struct sockaddr_in6 *) &jis->ip; - if ( jip6->sin6_family == AF_INET6 && - !IN6_IS_ADDR_LOOPBACK(&jip6->sin6_addr)) { - pr->nonlocal_ip6 = &jis->ip; - ip6->sin6_addr = jip6->sin6_addr; - return(1); - } - break; - } + switch(af) { + case AF_INET: + if (ip4 != NULL && pr->nonlocal_ip4 != NULL) + ip4->sin_addr.s_addr = pr->nonlocal_ip4->sin_addr.s_addr; + return (struct sockaddr *)pr->nonlocal_ip4; + + case AF_INET6: + if (ip6 != NULL && pr->nonlocal_ip6 != NULL) + ip6->sin6_addr = pr->nonlocal_ip6->sin6_addr; + return (struct sockaddr *)pr->nonlocal_ip6; } - if (ip->sa_family == AF_INET) - pr->nonlocal_ip4 = (struct sockaddr_storage *)-1; - else - pr->nonlocal_ip6 = (struct sockaddr_storage *)-1; - return(0); + + /* NOTREACHED */ + return NULL; } /* * Prison get loopback ip. - * Put on *ip the first loopback IP address. - * af is the address family of the ip we want (AF_INET|PF_INET). - * *ip is in network by order and we don't touch it unless we find a valid ip. - * return 1 if we've found a loopback ip, else return 0. + * - af is the address family of the ip we want (AF_INET|AF_INET6). + * - If ip != NULL, put the first IP address that is not a loopback address + * into *ip. + * + * ip is in network by order and we don't touch it unless we find a valid ip. + * No matter if ip == NULL or not, we return either a valid struct sockaddr *, + * or NULL. This struct may not be modified. */ -int -prison_get_local(struct prison *pr, struct sockaddr *ip) +struct sockaddr * +prison_get_local(struct prison *pr, sa_family_t af, struct sockaddr *ip) { - struct jail_ip_storage *jis; - struct sockaddr_in *jip4, *ip4; - struct sockaddr_in6 *jip6, *ip6; + struct sockaddr_in *ip4 = (struct sockaddr_in *)ip; + struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)ip; - ip4 = (struct sockaddr_in *)ip; - ip6 = (struct sockaddr_in6 *)ip; /* Check if it is cached */ - switch(ip->sa_family) { - case AF_INET: - /* -1 Means that we don't have any address */ - if (pr->local_ip4 == (struct sockaddr_storage *)-1) - return(0); - if (pr->local_ip4 != NULL) { - jip4 = (struct sockaddr_in *) pr->local_ip4; - ip4->sin_addr.s_addr = jip4->sin_addr.s_addr; - } - break; - case AF_INET6: - /* -1 Means that we don't have any address */ - if (pr->local_ip6 == (struct sockaddr_storage *)-1) - return(0); - if (pr->local_ip6 != NULL) { - jip6 = (struct sockaddr_in6 *) pr->local_ip6; - ip6->sin6_addr = jip6->sin6_addr; - } - break; - }; - SLIST_FOREACH(jis, &pr->pr_ips, entries) { - switch(ip->sa_family) { - case AF_INET: - jip4 = (struct sockaddr_in *) &jis->ip; - if (jip4->sin_family == AF_INET && - ((ntohl(jip4->sin_addr.s_addr) >> IN_CLASSA_NSHIFT) - == IN_LOOPBACKNET)) { - pr->local_ip4 = &jis->ip; - ip4->sin_addr.s_addr = jip4->sin_addr.s_addr; - return(1); - } - break; - case AF_INET6: - jip6 = (struct sockaddr_in6 *) &jis->ip; - if (jip6->sin6_family == AF_INET6 && - IN6_IS_ADDR_LOOPBACK(&jip6->sin6_addr)) { - pr->local_ip6 = &jis->ip; - ip6->sin6_addr = jip6->sin6_addr; - return(1); - } - break; - } + switch(af) { + case AF_INET: + if (ip4 != NULL && pr->local_ip4 != NULL) + ip4->sin_addr.s_addr = pr->local_ip4->sin_addr.s_addr; + return (struct sockaddr *)pr->local_ip4; + + case AF_INET6: + if (ip6 != NULL && pr->local_ip6 != NULL) + ip6->sin6_addr = pr->local_ip6->sin6_addr; + return (struct sockaddr *)pr->local_ip6; } - if (ip->sa_family == AF_INET) - pr->local_ip4 = (struct sockaddr_storage *)-1; - else - pr->local_ip6 = (struct sockaddr_storage *)-1; - return(0); + + /* NOTREACHED */ + return NULL; } /* Check if the IP is among ours, if it is return 1, else 0 */ Index: netinet/in_pcb.c =================================================================== RCS file: /home/dcvs/src/sys/netinet/in_pcb.c,v retrieving revision 1.41 diff -u -p -r1.41 in_pcb.c --- netinet/in_pcb.c 29 Dec 2006 18:02:56 -0000 1.41 +++ netinet/in_pcb.c 17 Jan 2007 12:58:07 -0000 @@ -457,7 +457,7 @@ in_pcbladdr(struct inpcb *inp, struct so struct in_ifaddr *ia; struct ucred *cred = NULL; struct sockaddr_in *sin = (struct sockaddr_in *)nam; - struct sockaddr_in jsin; + struct sockaddr *jsin; int jailed = 0; if (nam->sa_len != sizeof *sin) @@ -579,14 +579,13 @@ in_pcbladdr(struct inpcb *inp, struct so * Don't do pcblookup call here; return interface in plocal_sin * and exit to caller, that will do the lookup. */ - if (jailed) { - jsin.sin_family = AF_INET; - if (!prison_get_nonlocal(cred->cr_prison, - sintosa(&jsin)) && - !prison_get_local(cred->cr_prison, sintosa(&jsin))) - /* IPv6 only Jail */ - return (EADDRNOTAVAIL); - *plocal_sin = &jsin; + if (ia == NULL && jailed) { + if ((jsin = prison_get_nonlocal(cred->cr_prison, AF_INET, NULL)) != NULL || + (jsin = prison_get_local(cred->cr_prison, AF_INET, NULL)) != NULL) + *plocal_sin = satosin(jsin); + else + /* IPv6 only Jail */ + return (EADDRNOTAVAIL); } else { *plocal_sin = &ia->ia_addr; }