1*0ce1624dSStephen J. Kiernan /*- 2*0ce1624dSStephen J. Kiernan * Copyright (c) 1999 Poul-Henning Kamp. 3*0ce1624dSStephen J. Kiernan * Copyright (c) 2008 Bjoern A. Zeeb. 4*0ce1624dSStephen J. Kiernan * Copyright (c) 2009 James Gritton. 5*0ce1624dSStephen J. Kiernan * All rights reserved. 6*0ce1624dSStephen J. Kiernan * 7*0ce1624dSStephen J. Kiernan * Redistribution and use in source and binary forms, with or without 8*0ce1624dSStephen J. Kiernan * modification, are permitted provided that the following conditions 9*0ce1624dSStephen J. Kiernan * are met: 10*0ce1624dSStephen J. Kiernan * 1. Redistributions of source code must retain the above copyright 11*0ce1624dSStephen J. Kiernan * notice, this list of conditions and the following disclaimer. 12*0ce1624dSStephen J. Kiernan * 2. Redistributions in binary form must reproduce the above copyright 13*0ce1624dSStephen J. Kiernan * notice, this list of conditions and the following disclaimer in the 14*0ce1624dSStephen J. Kiernan * documentation and/or other materials provided with the distribution. 15*0ce1624dSStephen J. Kiernan * 16*0ce1624dSStephen J. Kiernan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17*0ce1624dSStephen J. Kiernan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18*0ce1624dSStephen J. Kiernan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19*0ce1624dSStephen J. Kiernan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20*0ce1624dSStephen J. Kiernan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21*0ce1624dSStephen J. Kiernan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22*0ce1624dSStephen J. Kiernan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23*0ce1624dSStephen J. Kiernan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24*0ce1624dSStephen J. Kiernan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25*0ce1624dSStephen J. Kiernan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26*0ce1624dSStephen J. Kiernan * SUCH DAMAGE. 27*0ce1624dSStephen J. Kiernan */ 28*0ce1624dSStephen J. Kiernan 29*0ce1624dSStephen J. Kiernan #include <sys/cdefs.h> 30*0ce1624dSStephen J. Kiernan __FBSDID("$FreeBSD$"); 31*0ce1624dSStephen J. Kiernan 32*0ce1624dSStephen J. Kiernan #include "opt_compat.h" 33*0ce1624dSStephen J. Kiernan #include "opt_ddb.h" 34*0ce1624dSStephen J. Kiernan #include "opt_inet.h" 35*0ce1624dSStephen J. Kiernan #include "opt_inet6.h" 36*0ce1624dSStephen J. Kiernan 37*0ce1624dSStephen J. Kiernan #include <sys/param.h> 38*0ce1624dSStephen J. Kiernan #include <sys/types.h> 39*0ce1624dSStephen J. Kiernan #include <sys/kernel.h> 40*0ce1624dSStephen J. Kiernan #include <sys/systm.h> 41*0ce1624dSStephen J. Kiernan #include <sys/errno.h> 42*0ce1624dSStephen J. Kiernan #include <sys/sysproto.h> 43*0ce1624dSStephen J. Kiernan #include <sys/malloc.h> 44*0ce1624dSStephen J. Kiernan #include <sys/osd.h> 45*0ce1624dSStephen J. Kiernan #include <sys/priv.h> 46*0ce1624dSStephen J. Kiernan #include <sys/proc.h> 47*0ce1624dSStephen J. Kiernan #include <sys/taskqueue.h> 48*0ce1624dSStephen J. Kiernan #include <sys/fcntl.h> 49*0ce1624dSStephen J. Kiernan #include <sys/jail.h> 50*0ce1624dSStephen J. Kiernan #include <sys/lock.h> 51*0ce1624dSStephen J. Kiernan #include <sys/mutex.h> 52*0ce1624dSStephen J. Kiernan #include <sys/racct.h> 53*0ce1624dSStephen J. Kiernan #include <sys/refcount.h> 54*0ce1624dSStephen J. Kiernan #include <sys/sx.h> 55*0ce1624dSStephen J. Kiernan #include <sys/sysent.h> 56*0ce1624dSStephen J. Kiernan #include <sys/namei.h> 57*0ce1624dSStephen J. Kiernan #include <sys/mount.h> 58*0ce1624dSStephen J. Kiernan #include <sys/queue.h> 59*0ce1624dSStephen J. Kiernan #include <sys/socket.h> 60*0ce1624dSStephen J. Kiernan #include <sys/syscallsubr.h> 61*0ce1624dSStephen J. Kiernan #include <sys/sysctl.h> 62*0ce1624dSStephen J. Kiernan #include <sys/vnode.h> 63*0ce1624dSStephen J. Kiernan 64*0ce1624dSStephen J. Kiernan #include <net/if.h> 65*0ce1624dSStephen J. Kiernan #include <net/vnet.h> 66*0ce1624dSStephen J. Kiernan 67*0ce1624dSStephen J. Kiernan #include <netinet/in.h> 68*0ce1624dSStephen J. Kiernan 69*0ce1624dSStephen J. Kiernan int 70*0ce1624dSStephen J. Kiernan prison_qcmp_v6(const void *ip1, const void *ip2) 71*0ce1624dSStephen J. Kiernan { 72*0ce1624dSStephen J. Kiernan const struct in6_addr *ia6a, *ia6b; 73*0ce1624dSStephen J. Kiernan int i, rc; 74*0ce1624dSStephen J. Kiernan 75*0ce1624dSStephen J. Kiernan ia6a = (const struct in6_addr *)ip1; 76*0ce1624dSStephen J. Kiernan ia6b = (const struct in6_addr *)ip2; 77*0ce1624dSStephen J. Kiernan 78*0ce1624dSStephen J. Kiernan rc = 0; 79*0ce1624dSStephen J. Kiernan for (i = 0; rc == 0 && i < sizeof(struct in6_addr); i++) { 80*0ce1624dSStephen J. Kiernan if (ia6a->s6_addr[i] > ia6b->s6_addr[i]) 81*0ce1624dSStephen J. Kiernan rc = 1; 82*0ce1624dSStephen J. Kiernan else if (ia6a->s6_addr[i] < ia6b->s6_addr[i]) 83*0ce1624dSStephen J. Kiernan rc = -1; 84*0ce1624dSStephen J. Kiernan } 85*0ce1624dSStephen J. Kiernan return (rc); 86*0ce1624dSStephen J. Kiernan } 87*0ce1624dSStephen J. Kiernan 88*0ce1624dSStephen J. Kiernan int 89*0ce1624dSStephen J. Kiernan prison_restrict_ip6(struct prison *pr, struct in6_addr *newip6) 90*0ce1624dSStephen J. Kiernan { 91*0ce1624dSStephen J. Kiernan int ii, ij, used; 92*0ce1624dSStephen J. Kiernan struct prison *ppr; 93*0ce1624dSStephen J. Kiernan 94*0ce1624dSStephen J. Kiernan ppr = pr->pr_parent; 95*0ce1624dSStephen J. Kiernan if (!(pr->pr_flags & PR_IP6_USER)) { 96*0ce1624dSStephen J. Kiernan /* This has no user settings, so just copy the parent's list. */ 97*0ce1624dSStephen J. Kiernan if (pr->pr_ip6s < ppr->pr_ip6s) { 98*0ce1624dSStephen J. Kiernan /* 99*0ce1624dSStephen J. Kiernan * There's no room for the parent's list. Use the 100*0ce1624dSStephen J. Kiernan * new list buffer, which is assumed to be big enough 101*0ce1624dSStephen J. Kiernan * (if it was passed). If there's no buffer, try to 102*0ce1624dSStephen J. Kiernan * allocate one. 103*0ce1624dSStephen J. Kiernan */ 104*0ce1624dSStephen J. Kiernan used = 1; 105*0ce1624dSStephen J. Kiernan if (newip6 == NULL) { 106*0ce1624dSStephen J. Kiernan newip6 = malloc(ppr->pr_ip6s * sizeof(*newip6), 107*0ce1624dSStephen J. Kiernan M_PRISON, M_NOWAIT); 108*0ce1624dSStephen J. Kiernan if (newip6 != NULL) 109*0ce1624dSStephen J. Kiernan used = 0; 110*0ce1624dSStephen J. Kiernan } 111*0ce1624dSStephen J. Kiernan if (newip6 != NULL) { 112*0ce1624dSStephen J. Kiernan bcopy(ppr->pr_ip6, newip6, 113*0ce1624dSStephen J. Kiernan ppr->pr_ip6s * sizeof(*newip6)); 114*0ce1624dSStephen J. Kiernan free(pr->pr_ip6, M_PRISON); 115*0ce1624dSStephen J. Kiernan pr->pr_ip6 = newip6; 116*0ce1624dSStephen J. Kiernan pr->pr_ip6s = ppr->pr_ip6s; 117*0ce1624dSStephen J. Kiernan } 118*0ce1624dSStephen J. Kiernan return (used); 119*0ce1624dSStephen J. Kiernan } 120*0ce1624dSStephen J. Kiernan pr->pr_ip6s = ppr->pr_ip6s; 121*0ce1624dSStephen J. Kiernan if (pr->pr_ip6s > 0) 122*0ce1624dSStephen J. Kiernan bcopy(ppr->pr_ip6, pr->pr_ip6, 123*0ce1624dSStephen J. Kiernan pr->pr_ip6s * sizeof(*newip6)); 124*0ce1624dSStephen J. Kiernan else if (pr->pr_ip6 != NULL) { 125*0ce1624dSStephen J. Kiernan free(pr->pr_ip6, M_PRISON); 126*0ce1624dSStephen J. Kiernan pr->pr_ip6 = NULL; 127*0ce1624dSStephen J. Kiernan } 128*0ce1624dSStephen J. Kiernan } else if (pr->pr_ip6s > 0) { 129*0ce1624dSStephen J. Kiernan /* Remove addresses that aren't in the parent. */ 130*0ce1624dSStephen J. Kiernan for (ij = 0; ij < ppr->pr_ip6s; ij++) 131*0ce1624dSStephen J. Kiernan if (IN6_ARE_ADDR_EQUAL(&pr->pr_ip6[0], 132*0ce1624dSStephen J. Kiernan &ppr->pr_ip6[ij])) 133*0ce1624dSStephen J. Kiernan break; 134*0ce1624dSStephen J. Kiernan if (ij < ppr->pr_ip6s) 135*0ce1624dSStephen J. Kiernan ii = 1; 136*0ce1624dSStephen J. Kiernan else { 137*0ce1624dSStephen J. Kiernan bcopy(pr->pr_ip6 + 1, pr->pr_ip6, 138*0ce1624dSStephen J. Kiernan --pr->pr_ip6s * sizeof(*pr->pr_ip6)); 139*0ce1624dSStephen J. Kiernan ii = 0; 140*0ce1624dSStephen J. Kiernan } 141*0ce1624dSStephen J. Kiernan for (ij = 1; ii < pr->pr_ip6s; ) { 142*0ce1624dSStephen J. Kiernan if (IN6_ARE_ADDR_EQUAL(&pr->pr_ip6[ii], 143*0ce1624dSStephen J. Kiernan &ppr->pr_ip6[0])) { 144*0ce1624dSStephen J. Kiernan ii++; 145*0ce1624dSStephen J. Kiernan continue; 146*0ce1624dSStephen J. Kiernan } 147*0ce1624dSStephen J. Kiernan switch (ij >= ppr->pr_ip6s ? -1 : 148*0ce1624dSStephen J. Kiernan prison_qcmp_v6(&pr->pr_ip6[ii], &ppr->pr_ip6[ij])) { 149*0ce1624dSStephen J. Kiernan case -1: 150*0ce1624dSStephen J. Kiernan bcopy(pr->pr_ip6 + ii + 1, pr->pr_ip6 + ii, 151*0ce1624dSStephen J. Kiernan (--pr->pr_ip6s - ii) * sizeof(*pr->pr_ip6)); 152*0ce1624dSStephen J. Kiernan break; 153*0ce1624dSStephen J. Kiernan case 0: 154*0ce1624dSStephen J. Kiernan ii++; 155*0ce1624dSStephen J. Kiernan ij++; 156*0ce1624dSStephen J. Kiernan break; 157*0ce1624dSStephen J. Kiernan case 1: 158*0ce1624dSStephen J. Kiernan ij++; 159*0ce1624dSStephen J. Kiernan break; 160*0ce1624dSStephen J. Kiernan } 161*0ce1624dSStephen J. Kiernan } 162*0ce1624dSStephen J. Kiernan if (pr->pr_ip6s == 0) { 163*0ce1624dSStephen J. Kiernan free(pr->pr_ip6, M_PRISON); 164*0ce1624dSStephen J. Kiernan pr->pr_ip6 = NULL; 165*0ce1624dSStephen J. Kiernan } 166*0ce1624dSStephen J. Kiernan } 167*0ce1624dSStephen J. Kiernan return 0; 168*0ce1624dSStephen J. Kiernan } 169*0ce1624dSStephen J. Kiernan 170*0ce1624dSStephen J. Kiernan /* 171*0ce1624dSStephen J. Kiernan * Pass back primary IPv6 address for this jail. 172*0ce1624dSStephen J. Kiernan * 173*0ce1624dSStephen J. Kiernan * If not restricted return success but do not alter the address. Caller has 174*0ce1624dSStephen J. Kiernan * to make sure to initialize it correctly (e.g. IN6ADDR_ANY_INIT). 175*0ce1624dSStephen J. Kiernan * 176*0ce1624dSStephen J. Kiernan * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv6. 177*0ce1624dSStephen J. Kiernan */ 178*0ce1624dSStephen J. Kiernan int 179*0ce1624dSStephen J. Kiernan prison_get_ip6(struct ucred *cred, struct in6_addr *ia6) 180*0ce1624dSStephen J. Kiernan { 181*0ce1624dSStephen J. Kiernan struct prison *pr; 182*0ce1624dSStephen J. Kiernan 183*0ce1624dSStephen J. Kiernan KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 184*0ce1624dSStephen J. Kiernan KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 185*0ce1624dSStephen J. Kiernan 186*0ce1624dSStephen J. Kiernan pr = cred->cr_prison; 187*0ce1624dSStephen J. Kiernan if (!(pr->pr_flags & PR_IP6)) 188*0ce1624dSStephen J. Kiernan return (0); 189*0ce1624dSStephen J. Kiernan mtx_lock(&pr->pr_mtx); 190*0ce1624dSStephen J. Kiernan if (!(pr->pr_flags & PR_IP6)) { 191*0ce1624dSStephen J. Kiernan mtx_unlock(&pr->pr_mtx); 192*0ce1624dSStephen J. Kiernan return (0); 193*0ce1624dSStephen J. Kiernan } 194*0ce1624dSStephen J. Kiernan if (pr->pr_ip6 == NULL) { 195*0ce1624dSStephen J. Kiernan mtx_unlock(&pr->pr_mtx); 196*0ce1624dSStephen J. Kiernan return (EAFNOSUPPORT); 197*0ce1624dSStephen J. Kiernan } 198*0ce1624dSStephen J. Kiernan 199*0ce1624dSStephen J. Kiernan bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr)); 200*0ce1624dSStephen J. Kiernan mtx_unlock(&pr->pr_mtx); 201*0ce1624dSStephen J. Kiernan return (0); 202*0ce1624dSStephen J. Kiernan } 203*0ce1624dSStephen J. Kiernan 204*0ce1624dSStephen J. Kiernan /* 205*0ce1624dSStephen J. Kiernan * Return 1 if we should do proper source address selection or are not jailed. 206*0ce1624dSStephen J. Kiernan * We will return 0 if we should bypass source address selection in favour 207*0ce1624dSStephen J. Kiernan * of the primary jail IPv6 address. Only in this case *ia will be updated and 208*0ce1624dSStephen J. Kiernan * returned in NBO. 209*0ce1624dSStephen J. Kiernan * Return EAFNOSUPPORT, in case this jail does not allow IPv6. 210*0ce1624dSStephen J. Kiernan */ 211*0ce1624dSStephen J. Kiernan int 212*0ce1624dSStephen J. Kiernan prison_saddrsel_ip6(struct ucred *cred, struct in6_addr *ia6) 213*0ce1624dSStephen J. Kiernan { 214*0ce1624dSStephen J. Kiernan struct prison *pr; 215*0ce1624dSStephen J. Kiernan struct in6_addr lia6; 216*0ce1624dSStephen J. Kiernan int error; 217*0ce1624dSStephen J. Kiernan 218*0ce1624dSStephen J. Kiernan KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 219*0ce1624dSStephen J. Kiernan KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 220*0ce1624dSStephen J. Kiernan 221*0ce1624dSStephen J. Kiernan if (!jailed(cred)) 222*0ce1624dSStephen J. Kiernan return (1); 223*0ce1624dSStephen J. Kiernan 224*0ce1624dSStephen J. Kiernan pr = cred->cr_prison; 225*0ce1624dSStephen J. Kiernan if (pr->pr_flags & PR_IP6_SADDRSEL) 226*0ce1624dSStephen J. Kiernan return (1); 227*0ce1624dSStephen J. Kiernan 228*0ce1624dSStephen J. Kiernan lia6 = in6addr_any; 229*0ce1624dSStephen J. Kiernan error = prison_get_ip6(cred, &lia6); 230*0ce1624dSStephen J. Kiernan if (error) 231*0ce1624dSStephen J. Kiernan return (error); 232*0ce1624dSStephen J. Kiernan if (IN6_IS_ADDR_UNSPECIFIED(&lia6)) 233*0ce1624dSStephen J. Kiernan return (1); 234*0ce1624dSStephen J. Kiernan 235*0ce1624dSStephen J. Kiernan bcopy(&lia6, ia6, sizeof(struct in6_addr)); 236*0ce1624dSStephen J. Kiernan return (0); 237*0ce1624dSStephen J. Kiernan } 238*0ce1624dSStephen J. Kiernan 239*0ce1624dSStephen J. Kiernan /* 240*0ce1624dSStephen J. Kiernan * Return true if pr1 and pr2 have the same IPv6 address restrictions. 241*0ce1624dSStephen J. Kiernan */ 242*0ce1624dSStephen J. Kiernan int 243*0ce1624dSStephen J. Kiernan prison_equal_ip6(struct prison *pr1, struct prison *pr2) 244*0ce1624dSStephen J. Kiernan { 245*0ce1624dSStephen J. Kiernan 246*0ce1624dSStephen J. Kiernan if (pr1 == pr2) 247*0ce1624dSStephen J. Kiernan return (1); 248*0ce1624dSStephen J. Kiernan 249*0ce1624dSStephen J. Kiernan while (pr1 != &prison0 && 250*0ce1624dSStephen J. Kiernan #ifdef VIMAGE 251*0ce1624dSStephen J. Kiernan !(pr1->pr_flags & PR_VNET) && 252*0ce1624dSStephen J. Kiernan #endif 253*0ce1624dSStephen J. Kiernan !(pr1->pr_flags & PR_IP6_USER)) 254*0ce1624dSStephen J. Kiernan pr1 = pr1->pr_parent; 255*0ce1624dSStephen J. Kiernan while (pr2 != &prison0 && 256*0ce1624dSStephen J. Kiernan #ifdef VIMAGE 257*0ce1624dSStephen J. Kiernan !(pr2->pr_flags & PR_VNET) && 258*0ce1624dSStephen J. Kiernan #endif 259*0ce1624dSStephen J. Kiernan !(pr2->pr_flags & PR_IP6_USER)) 260*0ce1624dSStephen J. Kiernan pr2 = pr2->pr_parent; 261*0ce1624dSStephen J. Kiernan return (pr1 == pr2); 262*0ce1624dSStephen J. Kiernan } 263*0ce1624dSStephen J. Kiernan 264*0ce1624dSStephen J. Kiernan /* 265*0ce1624dSStephen J. Kiernan * Make sure our (source) address is set to something meaningful to this jail. 266*0ce1624dSStephen J. Kiernan * 267*0ce1624dSStephen J. Kiernan * v6only should be set based on (inp->inp_flags & IN6P_IPV6_V6ONLY != 0) 268*0ce1624dSStephen J. Kiernan * when needed while binding. 269*0ce1624dSStephen J. Kiernan * 270*0ce1624dSStephen J. Kiernan * Returns 0 if jail doesn't restrict IPv6 or if address belongs to jail, 271*0ce1624dSStephen J. Kiernan * EADDRNOTAVAIL if the address doesn't belong, or EAFNOSUPPORT if the jail 272*0ce1624dSStephen J. Kiernan * doesn't allow IPv6. 273*0ce1624dSStephen J. Kiernan */ 274*0ce1624dSStephen J. Kiernan int 275*0ce1624dSStephen J. Kiernan prison_local_ip6(struct ucred *cred, struct in6_addr *ia6, int v6only) 276*0ce1624dSStephen J. Kiernan { 277*0ce1624dSStephen J. Kiernan struct prison *pr; 278*0ce1624dSStephen J. Kiernan int error; 279*0ce1624dSStephen J. Kiernan 280*0ce1624dSStephen J. Kiernan KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 281*0ce1624dSStephen J. Kiernan KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 282*0ce1624dSStephen J. Kiernan 283*0ce1624dSStephen J. Kiernan pr = cred->cr_prison; 284*0ce1624dSStephen J. Kiernan if (!(pr->pr_flags & PR_IP6)) 285*0ce1624dSStephen J. Kiernan return (0); 286*0ce1624dSStephen J. Kiernan mtx_lock(&pr->pr_mtx); 287*0ce1624dSStephen J. Kiernan if (!(pr->pr_flags & PR_IP6)) { 288*0ce1624dSStephen J. Kiernan mtx_unlock(&pr->pr_mtx); 289*0ce1624dSStephen J. Kiernan return (0); 290*0ce1624dSStephen J. Kiernan } 291*0ce1624dSStephen J. Kiernan if (pr->pr_ip6 == NULL) { 292*0ce1624dSStephen J. Kiernan mtx_unlock(&pr->pr_mtx); 293*0ce1624dSStephen J. Kiernan return (EAFNOSUPPORT); 294*0ce1624dSStephen J. Kiernan } 295*0ce1624dSStephen J. Kiernan 296*0ce1624dSStephen J. Kiernan if (IN6_IS_ADDR_LOOPBACK(ia6)) { 297*0ce1624dSStephen J. Kiernan bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr)); 298*0ce1624dSStephen J. Kiernan mtx_unlock(&pr->pr_mtx); 299*0ce1624dSStephen J. Kiernan return (0); 300*0ce1624dSStephen J. Kiernan } 301*0ce1624dSStephen J. Kiernan 302*0ce1624dSStephen J. Kiernan if (IN6_IS_ADDR_UNSPECIFIED(ia6)) { 303*0ce1624dSStephen J. Kiernan /* 304*0ce1624dSStephen J. Kiernan * In case there is only 1 IPv6 address, and v6only is true, 305*0ce1624dSStephen J. Kiernan * then bind directly. 306*0ce1624dSStephen J. Kiernan */ 307*0ce1624dSStephen J. Kiernan if (v6only != 0 && pr->pr_ip6s == 1) 308*0ce1624dSStephen J. Kiernan bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr)); 309*0ce1624dSStephen J. Kiernan mtx_unlock(&pr->pr_mtx); 310*0ce1624dSStephen J. Kiernan return (0); 311*0ce1624dSStephen J. Kiernan } 312*0ce1624dSStephen J. Kiernan 313*0ce1624dSStephen J. Kiernan error = prison_check_ip6_locked(pr, ia6); 314*0ce1624dSStephen J. Kiernan mtx_unlock(&pr->pr_mtx); 315*0ce1624dSStephen J. Kiernan return (error); 316*0ce1624dSStephen J. Kiernan } 317*0ce1624dSStephen J. Kiernan 318*0ce1624dSStephen J. Kiernan /* 319*0ce1624dSStephen J. Kiernan * Rewrite destination address in case we will connect to loopback address. 320*0ce1624dSStephen J. Kiernan * 321*0ce1624dSStephen J. Kiernan * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv6. 322*0ce1624dSStephen J. Kiernan */ 323*0ce1624dSStephen J. Kiernan int 324*0ce1624dSStephen J. Kiernan prison_remote_ip6(struct ucred *cred, struct in6_addr *ia6) 325*0ce1624dSStephen J. Kiernan { 326*0ce1624dSStephen J. Kiernan struct prison *pr; 327*0ce1624dSStephen J. Kiernan 328*0ce1624dSStephen J. Kiernan KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 329*0ce1624dSStephen J. Kiernan KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 330*0ce1624dSStephen J. Kiernan 331*0ce1624dSStephen J. Kiernan pr = cred->cr_prison; 332*0ce1624dSStephen J. Kiernan if (!(pr->pr_flags & PR_IP6)) 333*0ce1624dSStephen J. Kiernan return (0); 334*0ce1624dSStephen J. Kiernan mtx_lock(&pr->pr_mtx); 335*0ce1624dSStephen J. Kiernan if (!(pr->pr_flags & PR_IP6)) { 336*0ce1624dSStephen J. Kiernan mtx_unlock(&pr->pr_mtx); 337*0ce1624dSStephen J. Kiernan return (0); 338*0ce1624dSStephen J. Kiernan } 339*0ce1624dSStephen J. Kiernan if (pr->pr_ip6 == NULL) { 340*0ce1624dSStephen J. Kiernan mtx_unlock(&pr->pr_mtx); 341*0ce1624dSStephen J. Kiernan return (EAFNOSUPPORT); 342*0ce1624dSStephen J. Kiernan } 343*0ce1624dSStephen J. Kiernan 344*0ce1624dSStephen J. Kiernan if (IN6_IS_ADDR_LOOPBACK(ia6)) { 345*0ce1624dSStephen J. Kiernan bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr)); 346*0ce1624dSStephen J. Kiernan mtx_unlock(&pr->pr_mtx); 347*0ce1624dSStephen J. Kiernan return (0); 348*0ce1624dSStephen J. Kiernan } 349*0ce1624dSStephen J. Kiernan 350*0ce1624dSStephen J. Kiernan /* 351*0ce1624dSStephen J. Kiernan * Return success because nothing had to be changed. 352*0ce1624dSStephen J. Kiernan */ 353*0ce1624dSStephen J. Kiernan mtx_unlock(&pr->pr_mtx); 354*0ce1624dSStephen J. Kiernan return (0); 355*0ce1624dSStephen J. Kiernan } 356*0ce1624dSStephen J. Kiernan 357*0ce1624dSStephen J. Kiernan /* 358*0ce1624dSStephen J. Kiernan * Check if given address belongs to the jail referenced by cred/prison. 359*0ce1624dSStephen J. Kiernan * 360*0ce1624dSStephen J. Kiernan * Returns 0 if jail doesn't restrict IPv6 or if address belongs to jail, 361*0ce1624dSStephen J. Kiernan * EADDRNOTAVAIL if the address doesn't belong, or EAFNOSUPPORT if the jail 362*0ce1624dSStephen J. Kiernan * doesn't allow IPv6. 363*0ce1624dSStephen J. Kiernan */ 364*0ce1624dSStephen J. Kiernan int 365*0ce1624dSStephen J. Kiernan prison_check_ip6_locked(const struct prison *pr, const struct in6_addr *ia6) 366*0ce1624dSStephen J. Kiernan { 367*0ce1624dSStephen J. Kiernan int i, a, z, d; 368*0ce1624dSStephen J. Kiernan 369*0ce1624dSStephen J. Kiernan /* 370*0ce1624dSStephen J. Kiernan * Check the primary IP. 371*0ce1624dSStephen J. Kiernan */ 372*0ce1624dSStephen J. Kiernan if (IN6_ARE_ADDR_EQUAL(&pr->pr_ip6[0], ia6)) 373*0ce1624dSStephen J. Kiernan return (0); 374*0ce1624dSStephen J. Kiernan 375*0ce1624dSStephen J. Kiernan /* 376*0ce1624dSStephen J. Kiernan * All the other IPs are sorted so we can do a binary search. 377*0ce1624dSStephen J. Kiernan */ 378*0ce1624dSStephen J. Kiernan a = 0; 379*0ce1624dSStephen J. Kiernan z = pr->pr_ip6s - 2; 380*0ce1624dSStephen J. Kiernan while (a <= z) { 381*0ce1624dSStephen J. Kiernan i = (a + z) / 2; 382*0ce1624dSStephen J. Kiernan d = prison_qcmp_v6(&pr->pr_ip6[i+1], ia6); 383*0ce1624dSStephen J. Kiernan if (d > 0) 384*0ce1624dSStephen J. Kiernan z = i - 1; 385*0ce1624dSStephen J. Kiernan else if (d < 0) 386*0ce1624dSStephen J. Kiernan a = i + 1; 387*0ce1624dSStephen J. Kiernan else 388*0ce1624dSStephen J. Kiernan return (0); 389*0ce1624dSStephen J. Kiernan } 390*0ce1624dSStephen J. Kiernan 391*0ce1624dSStephen J. Kiernan return (EADDRNOTAVAIL); 392*0ce1624dSStephen J. Kiernan } 393*0ce1624dSStephen J. Kiernan 394*0ce1624dSStephen J. Kiernan int 395*0ce1624dSStephen J. Kiernan prison_check_ip6(const struct ucred *cred, const struct in6_addr *ia6) 396*0ce1624dSStephen J. Kiernan { 397*0ce1624dSStephen J. Kiernan struct prison *pr; 398*0ce1624dSStephen J. Kiernan int error; 399*0ce1624dSStephen J. Kiernan 400*0ce1624dSStephen J. Kiernan KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 401*0ce1624dSStephen J. Kiernan KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 402*0ce1624dSStephen J. Kiernan 403*0ce1624dSStephen J. Kiernan pr = cred->cr_prison; 404*0ce1624dSStephen J. Kiernan if (!(pr->pr_flags & PR_IP6)) 405*0ce1624dSStephen J. Kiernan return (0); 406*0ce1624dSStephen J. Kiernan mtx_lock(&pr->pr_mtx); 407*0ce1624dSStephen J. Kiernan if (!(pr->pr_flags & PR_IP6)) { 408*0ce1624dSStephen J. Kiernan mtx_unlock(&pr->pr_mtx); 409*0ce1624dSStephen J. Kiernan return (0); 410*0ce1624dSStephen J. Kiernan } 411*0ce1624dSStephen J. Kiernan if (pr->pr_ip6 == NULL) { 412*0ce1624dSStephen J. Kiernan mtx_unlock(&pr->pr_mtx); 413*0ce1624dSStephen J. Kiernan return (EAFNOSUPPORT); 414*0ce1624dSStephen J. Kiernan } 415*0ce1624dSStephen J. Kiernan 416*0ce1624dSStephen J. Kiernan error = prison_check_ip6_locked(pr, ia6); 417*0ce1624dSStephen J. Kiernan mtx_unlock(&pr->pr_mtx); 418*0ce1624dSStephen J. Kiernan return (error); 419*0ce1624dSStephen J. Kiernan } 420