1/* 2 * Copyright (c) 2011-2013 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29#include <sys/param.h> 30#include <sys/types.h> 31#include <sys/kpi_mbuf.h> 32#include <sys/socket.h> 33#include <sys/kern_control.h> 34#include <sys/mcache.h> 35#include <sys/socketvar.h> 36 37#include <kern/debug.h> 38 39#include <libkern/libkern.h> 40 41#include <net/if.h> 42#include <net/route.h> 43 44#include <netinet/in.h> 45#include <netinet/ip.h> 46#include <netinet/ip_var.h> 47#include <netinet/in_var.h> 48#include <netinet/ip6.h> 49#include <netinet6/ip6_var.h> 50 51#include <net/netsrc.h> 52 53static errno_t netsrc_ctlsend(kern_ctl_ref, uint32_t, void *, mbuf_t, int); 54static errno_t netsrc_ctlconnect(kern_ctl_ref, struct sockaddr_ctl *, void **); 55static errno_t netsrc_ipv4(kern_ctl_ref, uint32_t, struct netsrc_req *); 56static errno_t netsrc_ipv6(kern_ctl_ref, uint32_t, struct netsrc_req *); 57 58static kern_ctl_ref netsrc_ctlref = NULL; 59 60__private_extern__ void 61netsrc_init(void) 62{ 63 errno_t error; 64 struct kern_ctl_reg netsrc_ctl = { 65 .ctl_connect = netsrc_ctlconnect, 66 .ctl_send = netsrc_ctlsend, 67 }; 68 69 strlcpy(netsrc_ctl.ctl_name, NETSRC_CTLNAME, sizeof(NETSRC_CTLNAME)); 70 71 if ((error = ctl_register(&netsrc_ctl, &netsrc_ctlref))) 72 printf("%s: ctl_register failed %d\n", __func__, error); 73} 74 75static errno_t 76netsrc_ctlconnect(kern_ctl_ref kctl, struct sockaddr_ctl *sac, void **uinfo) 77{ 78#pragma unused(kctl, sac, uinfo) 79 80 /* 81 * We don't need to do anything here. This callback is only necessary 82 * for ctl_register() to succeed. 83 */ 84 return (0); 85} 86 87static errno_t 88netsrc_ctlsend(kern_ctl_ref kctl, uint32_t unit, void *uinfo, mbuf_t m, 89 int flags) 90{ 91#pragma unused(uinfo, flags) 92 errno_t error; 93 struct netsrc_req *nrq, storage; 94 95 if (mbuf_pkthdr_len(m) < sizeof(*nrq)) { 96 error = EINVAL; 97 goto out; 98 } 99 if (mbuf_len(m) >= sizeof(*nrq)) 100 nrq = mbuf_data(m); 101 else { 102 mbuf_copydata(m, 0, sizeof(storage), &storage); 103 nrq = &storage; 104 } 105 /* We only have one version right now. */ 106 if (nrq->nrq_ver != NETSRC_VERSION1) { 107 error = EINVAL; 108 goto out; 109 } 110 switch (nrq->nrq_sin.sin_family) { 111 case AF_INET: 112 error = netsrc_ipv4(kctl, unit, nrq); 113 break; 114 case AF_INET6: 115 error = netsrc_ipv6(kctl, unit, nrq); 116 break; 117 default: 118 printf("%s: invalid family\n", __func__); 119 error = EINVAL; 120 } 121out: 122 mbuf_freem(m); 123 124 return (error); 125 126} 127 128static errno_t 129netsrc_ipv4(kern_ctl_ref kctl, uint32_t unit, struct netsrc_req *nrq) 130{ 131 errno_t error = EHOSTUNREACH; 132 struct sockaddr_in *dstsin; 133 struct rtentry *rt; 134 struct in_ifaddr *ia; 135 struct netsrc_rep nrp; 136 struct sockaddr_in6 v4entry = { 137 .sin6_family = AF_INET6, 138 .sin6_len = sizeof(struct sockaddr_in6), 139 .sin6_addr = IN6ADDR_V4MAPPED_INIT, 140 }; 141 struct in6_addrpolicy *policy; 142 143 dstsin = &nrq->nrq_sin; 144 145 if (dstsin->sin_len < sizeof (*dstsin) || 146 dstsin->sin_addr.s_addr == INADDR_ANY) 147 return (EINVAL); 148 149 lck_mtx_lock(rnh_lock); 150 rt = rt_lookup(TRUE, (struct sockaddr *)dstsin, NULL, 151 rt_tables[AF_INET], nrq->nrq_ifscope); 152 lck_mtx_unlock(rnh_lock); 153 if (!rt) 154 return (EHOSTUNREACH); 155 lck_rw_lock_shared(in_ifaddr_rwlock); 156 TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) { 157 IFA_LOCK_SPIN(&ia->ia_ifa); 158 if (ia->ia_ifp == rt->rt_ifp) { 159 memset(&nrp, 0, sizeof(nrp)); 160 memcpy(&nrp.nrp_sin, IA_SIN(ia), sizeof(nrp.nrp_sin)); 161 IFA_UNLOCK(&ia->ia_ifa); 162 v4entry.sin6_addr.s6_addr32[3] = 163 nrp.nrp_sin.sin_addr.s_addr; 164 policy = in6_addrsel_lookup_policy(&v4entry); 165 if (policy->label != -1) { 166 nrp.nrp_label = policy->label; 167 nrp.nrp_precedence = policy->preced; 168 /* XXX might not be true */ 169 nrp.nrp_dstlabel = policy->label; 170 nrp.nrp_dstprecedence = policy->preced; 171 } 172 error = ctl_enqueuedata(kctl, unit, &nrp, 173 sizeof(nrp), CTL_DATA_EOR); 174 break; 175 } 176 IFA_UNLOCK(&ia->ia_ifa); 177 } 178 lck_rw_done(in_ifaddr_rwlock); 179 if (rt) 180 rtfree(rt); 181 182 return (error); 183} 184 185static errno_t 186netsrc_ipv6(kern_ctl_ref kctl, uint32_t unit, struct netsrc_req *nrq) 187{ 188 struct sockaddr_in6 *dstsin6; 189 struct in6_addr *in6, storage; 190 struct in6_ifaddr *ia; 191 struct route_in6 ro; 192 int error = EHOSTUNREACH; 193 struct netsrc_rep nrp; 194 195 dstsin6 = &nrq->nrq_sin6; 196 197 if (dstsin6->sin6_len < sizeof (*dstsin6) || 198 IN6_IS_ADDR_UNSPECIFIED(&dstsin6->sin6_addr)) 199 return (EINVAL); 200 201 memset(&ro, 0, sizeof(ro)); 202 lck_mtx_lock(rnh_lock); 203 ro.ro_rt = rt_lookup(TRUE, (struct sockaddr *)dstsin6, NULL, 204 rt_tables[AF_INET6], nrq->nrq_ifscope); 205 lck_mtx_unlock(rnh_lock); 206 if (!ro.ro_rt) 207 return (EHOSTUNREACH); 208 in6 = in6_selectsrc(dstsin6, NULL, NULL, &ro, NULL, &storage, 209 nrq->nrq_ifscope, &error); 210 ROUTE_RELEASE(&ro); 211 if (!in6 || error) 212 return (error); 213 memset(&nrp, 0, sizeof(nrp)); 214 nrp.nrp_sin6.sin6_family = AF_INET6; 215 nrp.nrp_sin6.sin6_len = sizeof(nrp.nrp_sin6); 216 memcpy(&nrp.nrp_sin6.sin6_addr, in6, sizeof(nrp.nrp_sin6.sin6_addr)); 217 lck_rw_lock_shared(&in6_ifaddr_rwlock); 218 for (ia = in6_ifaddrs; ia; ia = ia->ia_next) { 219 if (memcmp(&ia->ia_addr.sin6_addr, in6, sizeof(*in6)) == 0) { 220 struct sockaddr_in6 sin6; 221 struct in6_addrpolicy *policy; 222 223 if (ia->ia6_flags & IN6_IFF_TEMPORARY) 224 nrp.nrp_flags |= NETSRC_IP6_FLAG_TEMPORARY; 225 if (ia->ia6_flags & IN6_IFF_TENTATIVE) 226 nrp.nrp_flags |= NETSRC_IP6_FLAG_TENTATIVE; 227 if (ia->ia6_flags & IN6_IFF_DEPRECATED) 228 nrp.nrp_flags |= NETSRC_IP6_FLAG_DEPRECATED; 229 if (ia->ia6_flags & IN6_IFF_OPTIMISTIC) 230 nrp.nrp_flags |= NETSRC_IP6_FLAG_OPTIMISTIC; 231 if (ia->ia6_flags & IN6_IFF_SECURED) 232 nrp.nrp_flags |= NETSRC_IP6_FLAG_SECURED; 233 sin6.sin6_family = AF_INET6; 234 sin6.sin6_len = sizeof(sin6); 235 memcpy(&sin6.sin6_addr, in6, sizeof(*in6)); 236 policy = in6_addrsel_lookup_policy(&sin6); 237 if (policy->label != -1) { 238 nrp.nrp_label = policy->label; 239 nrp.nrp_precedence = policy->preced; 240 } 241 memcpy(&sin6.sin6_addr, &dstsin6->sin6_addr, 242 sizeof(dstsin6->sin6_addr)); 243 policy = in6_addrsel_lookup_policy(&sin6); 244 if (policy->label != -1) { 245 nrp.nrp_dstlabel = policy->label; 246 nrp.nrp_dstprecedence = policy->preced; 247 } 248 break; 249 } 250 } 251 lck_rw_done(&in6_ifaddr_rwlock); 252 error = ctl_enqueuedata(kctl, unit, &nrp, sizeof(nrp), 253 CTL_DATA_EOR); 254 255 return (error); 256} 257