10ce1624dSStephen J. Kiernan /*- 20ce1624dSStephen J. Kiernan * Copyright (c) 1999 Poul-Henning Kamp. 30ce1624dSStephen J. Kiernan * Copyright (c) 2008 Bjoern A. Zeeb. 40ce1624dSStephen J. Kiernan * Copyright (c) 2009 James Gritton. 50ce1624dSStephen J. Kiernan * All rights reserved. 60ce1624dSStephen J. Kiernan * 70ce1624dSStephen J. Kiernan * Redistribution and use in source and binary forms, with or without 80ce1624dSStephen J. Kiernan * modification, are permitted provided that the following conditions 90ce1624dSStephen J. Kiernan * are met: 100ce1624dSStephen J. Kiernan * 1. Redistributions of source code must retain the above copyright 110ce1624dSStephen J. Kiernan * notice, this list of conditions and the following disclaimer. 120ce1624dSStephen J. Kiernan * 2. Redistributions in binary form must reproduce the above copyright 130ce1624dSStephen J. Kiernan * notice, this list of conditions and the following disclaimer in the 140ce1624dSStephen J. Kiernan * documentation and/or other materials provided with the distribution. 150ce1624dSStephen J. Kiernan * 160ce1624dSStephen J. Kiernan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 170ce1624dSStephen J. Kiernan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 180ce1624dSStephen J. Kiernan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 190ce1624dSStephen J. Kiernan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 200ce1624dSStephen J. Kiernan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 210ce1624dSStephen J. Kiernan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 220ce1624dSStephen J. Kiernan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 230ce1624dSStephen J. Kiernan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 240ce1624dSStephen J. Kiernan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 250ce1624dSStephen J. Kiernan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 260ce1624dSStephen J. Kiernan * SUCH DAMAGE. 270ce1624dSStephen J. Kiernan */ 280ce1624dSStephen J. Kiernan 290ce1624dSStephen J. Kiernan #include <sys/cdefs.h> 300ce1624dSStephen J. Kiernan __FBSDID("$FreeBSD$"); 310ce1624dSStephen J. Kiernan 320ce1624dSStephen J. Kiernan #include "opt_compat.h" 330ce1624dSStephen J. Kiernan #include "opt_ddb.h" 340ce1624dSStephen J. Kiernan #include "opt_inet.h" 350ce1624dSStephen J. Kiernan #include "opt_inet6.h" 360ce1624dSStephen J. Kiernan 370ce1624dSStephen J. Kiernan #include <sys/param.h> 380ce1624dSStephen J. Kiernan #include <sys/types.h> 390ce1624dSStephen J. Kiernan #include <sys/kernel.h> 400ce1624dSStephen J. Kiernan #include <sys/systm.h> 410ce1624dSStephen J. Kiernan #include <sys/errno.h> 420ce1624dSStephen J. Kiernan #include <sys/sysproto.h> 430ce1624dSStephen J. Kiernan #include <sys/malloc.h> 440ce1624dSStephen J. Kiernan #include <sys/osd.h> 450ce1624dSStephen J. Kiernan #include <sys/priv.h> 460ce1624dSStephen J. Kiernan #include <sys/proc.h> 470ce1624dSStephen J. Kiernan #include <sys/taskqueue.h> 480ce1624dSStephen J. Kiernan #include <sys/fcntl.h> 490ce1624dSStephen J. Kiernan #include <sys/jail.h> 500ce1624dSStephen J. Kiernan #include <sys/lock.h> 510ce1624dSStephen J. Kiernan #include <sys/mutex.h> 520ce1624dSStephen J. Kiernan #include <sys/racct.h> 530ce1624dSStephen J. Kiernan #include <sys/refcount.h> 540ce1624dSStephen J. Kiernan #include <sys/sx.h> 550ce1624dSStephen J. Kiernan #include <sys/sysent.h> 560ce1624dSStephen J. Kiernan #include <sys/namei.h> 570ce1624dSStephen J. Kiernan #include <sys/mount.h> 580ce1624dSStephen J. Kiernan #include <sys/queue.h> 590ce1624dSStephen J. Kiernan #include <sys/socket.h> 600ce1624dSStephen J. Kiernan #include <sys/syscallsubr.h> 610ce1624dSStephen J. Kiernan #include <sys/sysctl.h> 620ce1624dSStephen J. Kiernan #include <sys/vnode.h> 630ce1624dSStephen J. Kiernan 640ce1624dSStephen J. Kiernan #include <net/if.h> 650ce1624dSStephen J. Kiernan #include <net/vnet.h> 660ce1624dSStephen J. Kiernan 670ce1624dSStephen J. Kiernan #include <netinet/in.h> 680ce1624dSStephen J. Kiernan 690ce1624dSStephen J. Kiernan int 700ce1624dSStephen J. Kiernan prison_qcmp_v6(const void *ip1, const void *ip2) 710ce1624dSStephen J. Kiernan { 720ce1624dSStephen J. Kiernan const struct in6_addr *ia6a, *ia6b; 730ce1624dSStephen J. Kiernan int i, rc; 740ce1624dSStephen J. Kiernan 750ce1624dSStephen J. Kiernan ia6a = (const struct in6_addr *)ip1; 760ce1624dSStephen J. Kiernan ia6b = (const struct in6_addr *)ip2; 770ce1624dSStephen J. Kiernan 780ce1624dSStephen J. Kiernan rc = 0; 790ce1624dSStephen J. Kiernan for (i = 0; rc == 0 && i < sizeof(struct in6_addr); i++) { 800ce1624dSStephen J. Kiernan if (ia6a->s6_addr[i] > ia6b->s6_addr[i]) 810ce1624dSStephen J. Kiernan rc = 1; 820ce1624dSStephen J. Kiernan else if (ia6a->s6_addr[i] < ia6b->s6_addr[i]) 830ce1624dSStephen J. Kiernan rc = -1; 840ce1624dSStephen J. Kiernan } 850ce1624dSStephen J. Kiernan return (rc); 860ce1624dSStephen J. Kiernan } 870ce1624dSStephen J. Kiernan 880ce1624dSStephen J. Kiernan int 890ce1624dSStephen J. Kiernan prison_restrict_ip6(struct prison *pr, struct in6_addr *newip6) 900ce1624dSStephen J. Kiernan { 910ce1624dSStephen J. Kiernan int ii, ij, used; 920ce1624dSStephen J. Kiernan struct prison *ppr; 930ce1624dSStephen J. Kiernan 940ce1624dSStephen J. Kiernan ppr = pr->pr_parent; 950ce1624dSStephen J. Kiernan if (!(pr->pr_flags & PR_IP6_USER)) { 960ce1624dSStephen J. Kiernan /* This has no user settings, so just copy the parent's list. */ 970ce1624dSStephen J. Kiernan if (pr->pr_ip6s < ppr->pr_ip6s) { 980ce1624dSStephen J. Kiernan /* 990ce1624dSStephen J. Kiernan * There's no room for the parent's list. Use the 1000ce1624dSStephen J. Kiernan * new list buffer, which is assumed to be big enough 1010ce1624dSStephen J. Kiernan * (if it was passed). If there's no buffer, try to 1020ce1624dSStephen J. Kiernan * allocate one. 1030ce1624dSStephen J. Kiernan */ 1040ce1624dSStephen J. Kiernan used = 1; 1050ce1624dSStephen J. Kiernan if (newip6 == NULL) { 1060ce1624dSStephen J. Kiernan newip6 = malloc(ppr->pr_ip6s * sizeof(*newip6), 1070ce1624dSStephen J. Kiernan M_PRISON, M_NOWAIT); 1080ce1624dSStephen J. Kiernan if (newip6 != NULL) 1090ce1624dSStephen J. Kiernan used = 0; 1100ce1624dSStephen J. Kiernan } 1110ce1624dSStephen J. Kiernan if (newip6 != NULL) { 1120ce1624dSStephen J. Kiernan bcopy(ppr->pr_ip6, newip6, 1130ce1624dSStephen J. Kiernan ppr->pr_ip6s * sizeof(*newip6)); 1140ce1624dSStephen J. Kiernan free(pr->pr_ip6, M_PRISON); 1150ce1624dSStephen J. Kiernan pr->pr_ip6 = newip6; 1160ce1624dSStephen J. Kiernan pr->pr_ip6s = ppr->pr_ip6s; 1170ce1624dSStephen J. Kiernan } 1180ce1624dSStephen J. Kiernan return (used); 1190ce1624dSStephen J. Kiernan } 1200ce1624dSStephen J. Kiernan pr->pr_ip6s = ppr->pr_ip6s; 1210ce1624dSStephen J. Kiernan if (pr->pr_ip6s > 0) 1220ce1624dSStephen J. Kiernan bcopy(ppr->pr_ip6, pr->pr_ip6, 1230ce1624dSStephen J. Kiernan pr->pr_ip6s * sizeof(*newip6)); 1240ce1624dSStephen J. Kiernan else if (pr->pr_ip6 != NULL) { 1250ce1624dSStephen J. Kiernan free(pr->pr_ip6, M_PRISON); 1260ce1624dSStephen J. Kiernan pr->pr_ip6 = NULL; 1270ce1624dSStephen J. Kiernan } 1280ce1624dSStephen J. Kiernan } else if (pr->pr_ip6s > 0) { 1290ce1624dSStephen J. Kiernan /* Remove addresses that aren't in the parent. */ 1300ce1624dSStephen J. Kiernan for (ij = 0; ij < ppr->pr_ip6s; ij++) 1310ce1624dSStephen J. Kiernan if (IN6_ARE_ADDR_EQUAL(&pr->pr_ip6[0], 1320ce1624dSStephen J. Kiernan &ppr->pr_ip6[ij])) 1330ce1624dSStephen J. Kiernan break; 1340ce1624dSStephen J. Kiernan if (ij < ppr->pr_ip6s) 1350ce1624dSStephen J. Kiernan ii = 1; 1360ce1624dSStephen J. Kiernan else { 1370ce1624dSStephen J. Kiernan bcopy(pr->pr_ip6 + 1, pr->pr_ip6, 1380ce1624dSStephen J. Kiernan --pr->pr_ip6s * sizeof(*pr->pr_ip6)); 1390ce1624dSStephen J. Kiernan ii = 0; 1400ce1624dSStephen J. Kiernan } 1410ce1624dSStephen J. Kiernan for (ij = 1; ii < pr->pr_ip6s; ) { 1420ce1624dSStephen J. Kiernan if (IN6_ARE_ADDR_EQUAL(&pr->pr_ip6[ii], 1430ce1624dSStephen J. Kiernan &ppr->pr_ip6[0])) { 1440ce1624dSStephen J. Kiernan ii++; 1450ce1624dSStephen J. Kiernan continue; 1460ce1624dSStephen J. Kiernan } 1470ce1624dSStephen J. Kiernan switch (ij >= ppr->pr_ip6s ? -1 : 1480ce1624dSStephen J. Kiernan prison_qcmp_v6(&pr->pr_ip6[ii], &ppr->pr_ip6[ij])) { 1490ce1624dSStephen J. Kiernan case -1: 1500ce1624dSStephen J. Kiernan bcopy(pr->pr_ip6 + ii + 1, pr->pr_ip6 + ii, 1510ce1624dSStephen J. Kiernan (--pr->pr_ip6s - ii) * sizeof(*pr->pr_ip6)); 1520ce1624dSStephen J. Kiernan break; 1530ce1624dSStephen J. Kiernan case 0: 1540ce1624dSStephen J. Kiernan ii++; 1550ce1624dSStephen J. Kiernan ij++; 1560ce1624dSStephen J. Kiernan break; 1570ce1624dSStephen J. Kiernan case 1: 1580ce1624dSStephen J. Kiernan ij++; 1590ce1624dSStephen J. Kiernan break; 1600ce1624dSStephen J. Kiernan } 1610ce1624dSStephen J. Kiernan } 1620ce1624dSStephen J. Kiernan if (pr->pr_ip6s == 0) { 1630ce1624dSStephen J. Kiernan free(pr->pr_ip6, M_PRISON); 1640ce1624dSStephen J. Kiernan pr->pr_ip6 = NULL; 1650ce1624dSStephen J. Kiernan } 1660ce1624dSStephen J. Kiernan } 1670ce1624dSStephen J. Kiernan return 0; 1680ce1624dSStephen J. Kiernan } 1690ce1624dSStephen J. Kiernan 1700ce1624dSStephen J. Kiernan /* 1710ce1624dSStephen J. Kiernan * Pass back primary IPv6 address for this jail. 1720ce1624dSStephen J. Kiernan * 1730ce1624dSStephen J. Kiernan * If not restricted return success but do not alter the address. Caller has 1740ce1624dSStephen J. Kiernan * to make sure to initialize it correctly (e.g. IN6ADDR_ANY_INIT). 1750ce1624dSStephen J. Kiernan * 1760ce1624dSStephen J. Kiernan * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv6. 1770ce1624dSStephen J. Kiernan */ 1780ce1624dSStephen J. Kiernan int 1790ce1624dSStephen J. Kiernan prison_get_ip6(struct ucred *cred, struct in6_addr *ia6) 1800ce1624dSStephen J. Kiernan { 1810ce1624dSStephen J. Kiernan struct prison *pr; 1820ce1624dSStephen J. Kiernan 1830ce1624dSStephen J. Kiernan KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 1840ce1624dSStephen J. Kiernan KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 1850ce1624dSStephen J. Kiernan 1860ce1624dSStephen J. Kiernan pr = cred->cr_prison; 1870ce1624dSStephen J. Kiernan if (!(pr->pr_flags & PR_IP6)) 1880ce1624dSStephen J. Kiernan return (0); 1890ce1624dSStephen J. Kiernan mtx_lock(&pr->pr_mtx); 1900ce1624dSStephen J. Kiernan if (!(pr->pr_flags & PR_IP6)) { 1910ce1624dSStephen J. Kiernan mtx_unlock(&pr->pr_mtx); 1920ce1624dSStephen J. Kiernan return (0); 1930ce1624dSStephen J. Kiernan } 1940ce1624dSStephen J. Kiernan if (pr->pr_ip6 == NULL) { 1950ce1624dSStephen J. Kiernan mtx_unlock(&pr->pr_mtx); 1960ce1624dSStephen J. Kiernan return (EAFNOSUPPORT); 1970ce1624dSStephen J. Kiernan } 1980ce1624dSStephen J. Kiernan 1990ce1624dSStephen J. Kiernan bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr)); 2000ce1624dSStephen J. Kiernan mtx_unlock(&pr->pr_mtx); 2010ce1624dSStephen J. Kiernan return (0); 2020ce1624dSStephen J. Kiernan } 2030ce1624dSStephen J. Kiernan 2040ce1624dSStephen J. Kiernan /* 2050ce1624dSStephen J. Kiernan * Return 1 if we should do proper source address selection or are not jailed. 2060ce1624dSStephen J. Kiernan * We will return 0 if we should bypass source address selection in favour 2070ce1624dSStephen J. Kiernan * of the primary jail IPv6 address. Only in this case *ia will be updated and 2080ce1624dSStephen J. Kiernan * returned in NBO. 2090ce1624dSStephen J. Kiernan * Return EAFNOSUPPORT, in case this jail does not allow IPv6. 2100ce1624dSStephen J. Kiernan */ 2110ce1624dSStephen J. Kiernan int 2120ce1624dSStephen J. Kiernan prison_saddrsel_ip6(struct ucred *cred, struct in6_addr *ia6) 2130ce1624dSStephen J. Kiernan { 2140ce1624dSStephen J. Kiernan struct prison *pr; 2150ce1624dSStephen J. Kiernan struct in6_addr lia6; 2160ce1624dSStephen J. Kiernan int error; 2170ce1624dSStephen J. Kiernan 2180ce1624dSStephen J. Kiernan KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 2190ce1624dSStephen J. Kiernan KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 2200ce1624dSStephen J. Kiernan 2210ce1624dSStephen J. Kiernan if (!jailed(cred)) 2220ce1624dSStephen J. Kiernan return (1); 2230ce1624dSStephen J. Kiernan 2240ce1624dSStephen J. Kiernan pr = cred->cr_prison; 2250ce1624dSStephen J. Kiernan if (pr->pr_flags & PR_IP6_SADDRSEL) 2260ce1624dSStephen J. Kiernan return (1); 2270ce1624dSStephen J. Kiernan 2280ce1624dSStephen J. Kiernan lia6 = in6addr_any; 2290ce1624dSStephen J. Kiernan error = prison_get_ip6(cred, &lia6); 2300ce1624dSStephen J. Kiernan if (error) 2310ce1624dSStephen J. Kiernan return (error); 2320ce1624dSStephen J. Kiernan if (IN6_IS_ADDR_UNSPECIFIED(&lia6)) 2330ce1624dSStephen J. Kiernan return (1); 2340ce1624dSStephen J. Kiernan 2350ce1624dSStephen J. Kiernan bcopy(&lia6, ia6, sizeof(struct in6_addr)); 2360ce1624dSStephen J. Kiernan return (0); 2370ce1624dSStephen J. Kiernan } 2380ce1624dSStephen J. Kiernan 2390ce1624dSStephen J. Kiernan /* 2400ce1624dSStephen J. Kiernan * Return true if pr1 and pr2 have the same IPv6 address restrictions. 2410ce1624dSStephen J. Kiernan */ 2420ce1624dSStephen J. Kiernan int 2430ce1624dSStephen J. Kiernan prison_equal_ip6(struct prison *pr1, struct prison *pr2) 2440ce1624dSStephen J. Kiernan { 2450ce1624dSStephen J. Kiernan 2460ce1624dSStephen J. Kiernan if (pr1 == pr2) 2470ce1624dSStephen J. Kiernan return (1); 2480ce1624dSStephen J. Kiernan 2490ce1624dSStephen J. Kiernan while (pr1 != &prison0 && 2500ce1624dSStephen J. Kiernan #ifdef VIMAGE 2510ce1624dSStephen J. Kiernan !(pr1->pr_flags & PR_VNET) && 2520ce1624dSStephen J. Kiernan #endif 2530ce1624dSStephen J. Kiernan !(pr1->pr_flags & PR_IP6_USER)) 2540ce1624dSStephen J. Kiernan pr1 = pr1->pr_parent; 2550ce1624dSStephen J. Kiernan while (pr2 != &prison0 && 2560ce1624dSStephen J. Kiernan #ifdef VIMAGE 2570ce1624dSStephen J. Kiernan !(pr2->pr_flags & PR_VNET) && 2580ce1624dSStephen J. Kiernan #endif 2590ce1624dSStephen J. Kiernan !(pr2->pr_flags & PR_IP6_USER)) 2600ce1624dSStephen J. Kiernan pr2 = pr2->pr_parent; 2610ce1624dSStephen J. Kiernan return (pr1 == pr2); 2620ce1624dSStephen J. Kiernan } 2630ce1624dSStephen J. Kiernan 2640ce1624dSStephen J. Kiernan /* 2650ce1624dSStephen J. Kiernan * Make sure our (source) address is set to something meaningful to this jail. 2660ce1624dSStephen J. Kiernan * 2670ce1624dSStephen J. Kiernan * v6only should be set based on (inp->inp_flags & IN6P_IPV6_V6ONLY != 0) 2680ce1624dSStephen J. Kiernan * when needed while binding. 2690ce1624dSStephen J. Kiernan * 2700ce1624dSStephen J. Kiernan * Returns 0 if jail doesn't restrict IPv6 or if address belongs to jail, 2710ce1624dSStephen J. Kiernan * EADDRNOTAVAIL if the address doesn't belong, or EAFNOSUPPORT if the jail 2720ce1624dSStephen J. Kiernan * doesn't allow IPv6. 2730ce1624dSStephen J. Kiernan */ 2740ce1624dSStephen J. Kiernan int 2750ce1624dSStephen J. Kiernan prison_local_ip6(struct ucred *cred, struct in6_addr *ia6, int v6only) 2760ce1624dSStephen J. Kiernan { 2770ce1624dSStephen J. Kiernan struct prison *pr; 2780ce1624dSStephen J. Kiernan int error; 2790ce1624dSStephen J. Kiernan 2800ce1624dSStephen J. Kiernan KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 2810ce1624dSStephen J. Kiernan KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 2820ce1624dSStephen J. Kiernan 2830ce1624dSStephen J. Kiernan pr = cred->cr_prison; 2840ce1624dSStephen J. Kiernan if (!(pr->pr_flags & PR_IP6)) 2850ce1624dSStephen J. Kiernan return (0); 2860ce1624dSStephen J. Kiernan mtx_lock(&pr->pr_mtx); 2870ce1624dSStephen J. Kiernan if (!(pr->pr_flags & PR_IP6)) { 2880ce1624dSStephen J. Kiernan mtx_unlock(&pr->pr_mtx); 2890ce1624dSStephen J. Kiernan return (0); 2900ce1624dSStephen J. Kiernan } 2910ce1624dSStephen J. Kiernan if (pr->pr_ip6 == NULL) { 2920ce1624dSStephen J. Kiernan mtx_unlock(&pr->pr_mtx); 2930ce1624dSStephen J. Kiernan return (EAFNOSUPPORT); 2940ce1624dSStephen J. Kiernan } 2950ce1624dSStephen J. Kiernan 2960ce1624dSStephen J. Kiernan if (IN6_IS_ADDR_UNSPECIFIED(ia6)) { 2970ce1624dSStephen J. Kiernan /* 2980ce1624dSStephen J. Kiernan * In case there is only 1 IPv6 address, and v6only is true, 2990ce1624dSStephen J. Kiernan * then bind directly. 3000ce1624dSStephen J. Kiernan */ 3010ce1624dSStephen J. Kiernan if (v6only != 0 && pr->pr_ip6s == 1) 3020ce1624dSStephen J. Kiernan bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr)); 3030ce1624dSStephen J. Kiernan mtx_unlock(&pr->pr_mtx); 3040ce1624dSStephen J. Kiernan return (0); 3050ce1624dSStephen J. Kiernan } 3060ce1624dSStephen J. Kiernan 3070ce1624dSStephen J. Kiernan error = prison_check_ip6_locked(pr, ia6); 308*4d806fc6SSteven Hartland if (error == EADDRNOTAVAIL && IN6_IS_ADDR_LOOPBACK(ia6)) { 309*4d806fc6SSteven Hartland bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr)); 310*4d806fc6SSteven Hartland error = 0; 311*4d806fc6SSteven Hartland } 312*4d806fc6SSteven Hartland 3130ce1624dSStephen J. Kiernan mtx_unlock(&pr->pr_mtx); 3140ce1624dSStephen J. Kiernan return (error); 3150ce1624dSStephen J. Kiernan } 3160ce1624dSStephen J. Kiernan 3170ce1624dSStephen J. Kiernan /* 3180ce1624dSStephen J. Kiernan * Rewrite destination address in case we will connect to loopback address. 3190ce1624dSStephen J. Kiernan * 3200ce1624dSStephen J. Kiernan * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv6. 3210ce1624dSStephen J. Kiernan */ 3220ce1624dSStephen J. Kiernan int 3230ce1624dSStephen J. Kiernan prison_remote_ip6(struct ucred *cred, struct in6_addr *ia6) 3240ce1624dSStephen J. Kiernan { 3250ce1624dSStephen J. Kiernan struct prison *pr; 3260ce1624dSStephen J. Kiernan 3270ce1624dSStephen J. Kiernan KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 3280ce1624dSStephen J. Kiernan KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 3290ce1624dSStephen J. Kiernan 3300ce1624dSStephen J. Kiernan pr = cred->cr_prison; 3310ce1624dSStephen J. Kiernan if (!(pr->pr_flags & PR_IP6)) 3320ce1624dSStephen J. Kiernan return (0); 3330ce1624dSStephen J. Kiernan mtx_lock(&pr->pr_mtx); 3340ce1624dSStephen J. Kiernan if (!(pr->pr_flags & PR_IP6)) { 3350ce1624dSStephen J. Kiernan mtx_unlock(&pr->pr_mtx); 3360ce1624dSStephen J. Kiernan return (0); 3370ce1624dSStephen J. Kiernan } 3380ce1624dSStephen J. Kiernan if (pr->pr_ip6 == NULL) { 3390ce1624dSStephen J. Kiernan mtx_unlock(&pr->pr_mtx); 3400ce1624dSStephen J. Kiernan return (EAFNOSUPPORT); 3410ce1624dSStephen J. Kiernan } 3420ce1624dSStephen J. Kiernan 343*4d806fc6SSteven Hartland if (IN6_IS_ADDR_LOOPBACK(ia6) && 344*4d806fc6SSteven Hartland prison_check_ip6_locked(pr, ia6) == EADDRNOTAVAIL) { 3450ce1624dSStephen J. Kiernan bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr)); 3460ce1624dSStephen J. Kiernan mtx_unlock(&pr->pr_mtx); 3470ce1624dSStephen J. Kiernan return (0); 3480ce1624dSStephen J. Kiernan } 3490ce1624dSStephen J. Kiernan 3500ce1624dSStephen J. Kiernan /* 3510ce1624dSStephen J. Kiernan * Return success because nothing had to be changed. 3520ce1624dSStephen J. Kiernan */ 3530ce1624dSStephen J. Kiernan mtx_unlock(&pr->pr_mtx); 3540ce1624dSStephen J. Kiernan return (0); 3550ce1624dSStephen J. Kiernan } 3560ce1624dSStephen J. Kiernan 3570ce1624dSStephen J. Kiernan /* 3580ce1624dSStephen J. Kiernan * Check if given address belongs to the jail referenced by cred/prison. 3590ce1624dSStephen J. Kiernan * 360*4d806fc6SSteven Hartland * Returns 0 if address belongs to jail, 361*4d806fc6SSteven Hartland * EADDRNOTAVAIL if the address doesn't belong to the jail. 3620ce1624dSStephen J. Kiernan */ 3630ce1624dSStephen J. Kiernan int 3640ce1624dSStephen J. Kiernan prison_check_ip6_locked(const struct prison *pr, const struct in6_addr *ia6) 3650ce1624dSStephen J. Kiernan { 3660ce1624dSStephen J. Kiernan int i, a, z, d; 3670ce1624dSStephen J. Kiernan 3680ce1624dSStephen J. Kiernan /* 3690ce1624dSStephen J. Kiernan * Check the primary IP. 3700ce1624dSStephen J. Kiernan */ 3710ce1624dSStephen J. Kiernan if (IN6_ARE_ADDR_EQUAL(&pr->pr_ip6[0], ia6)) 3720ce1624dSStephen J. Kiernan return (0); 3730ce1624dSStephen J. Kiernan 3740ce1624dSStephen J. Kiernan /* 3750ce1624dSStephen J. Kiernan * All the other IPs are sorted so we can do a binary search. 3760ce1624dSStephen J. Kiernan */ 3770ce1624dSStephen J. Kiernan a = 0; 3780ce1624dSStephen J. Kiernan z = pr->pr_ip6s - 2; 3790ce1624dSStephen J. Kiernan while (a <= z) { 3800ce1624dSStephen J. Kiernan i = (a + z) / 2; 3810ce1624dSStephen J. Kiernan d = prison_qcmp_v6(&pr->pr_ip6[i+1], ia6); 3820ce1624dSStephen J. Kiernan if (d > 0) 3830ce1624dSStephen J. Kiernan z = i - 1; 3840ce1624dSStephen J. Kiernan else if (d < 0) 3850ce1624dSStephen J. Kiernan a = i + 1; 3860ce1624dSStephen J. Kiernan else 3870ce1624dSStephen J. Kiernan return (0); 3880ce1624dSStephen J. Kiernan } 3890ce1624dSStephen J. Kiernan 3900ce1624dSStephen J. Kiernan return (EADDRNOTAVAIL); 3910ce1624dSStephen J. Kiernan } 3920ce1624dSStephen J. Kiernan 3930ce1624dSStephen J. Kiernan int 3940ce1624dSStephen J. Kiernan prison_check_ip6(const struct ucred *cred, const struct in6_addr *ia6) 3950ce1624dSStephen J. Kiernan { 3960ce1624dSStephen J. Kiernan struct prison *pr; 3970ce1624dSStephen J. Kiernan int error; 3980ce1624dSStephen J. Kiernan 3990ce1624dSStephen J. Kiernan KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); 4000ce1624dSStephen J. Kiernan KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); 4010ce1624dSStephen J. Kiernan 4020ce1624dSStephen J. Kiernan pr = cred->cr_prison; 4030ce1624dSStephen J. Kiernan if (!(pr->pr_flags & PR_IP6)) 4040ce1624dSStephen J. Kiernan return (0); 4050ce1624dSStephen J. Kiernan mtx_lock(&pr->pr_mtx); 4060ce1624dSStephen J. Kiernan if (!(pr->pr_flags & PR_IP6)) { 4070ce1624dSStephen J. Kiernan mtx_unlock(&pr->pr_mtx); 4080ce1624dSStephen J. Kiernan return (0); 4090ce1624dSStephen J. Kiernan } 4100ce1624dSStephen J. Kiernan if (pr->pr_ip6 == NULL) { 4110ce1624dSStephen J. Kiernan mtx_unlock(&pr->pr_mtx); 4120ce1624dSStephen J. Kiernan return (EAFNOSUPPORT); 4130ce1624dSStephen J. Kiernan } 4140ce1624dSStephen J. Kiernan 4150ce1624dSStephen J. Kiernan error = prison_check_ip6_locked(pr, ia6); 4160ce1624dSStephen J. Kiernan mtx_unlock(&pr->pr_mtx); 4170ce1624dSStephen J. Kiernan return (error); 4180ce1624dSStephen J. Kiernan } 419