1/* 2 * Copyright (c) 2012 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_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. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24#include "config.h" 25#include <sys/types.h> 26#include <sys/param.h> 27#include <sys/socket.h> 28#include <sys/ioctl.h> 29 30#include <stdio.h> 31#include <sys/kern_control.h> 32#include <sys/sys_domain.h> 33#include "racoon_types.h" 34#include "plog.h" 35#include <net/if.h> 36#include <netinet6/in6_var.h> 37#include <netinet6/nd6.h> 38 39#include "var.h" 40 41int ipsec_interface_create(char *name, int name_max_len, int *index, int flags) 42{ 43 44 struct ctl_info kernctl_info; 45 struct sockaddr_ctl kernctl_addr; 46 u_int32_t optlen; 47 int tunsock = -1; 48 49 tunsock = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL); 50 if (tunsock == -1) { 51 plog(ASL_LEVEL_ERR, "create_ipsec_interface: cannot create kernel control socket (errno = %d)", errno); 52 goto fail; 53 } 54 55 bzero(&kernctl_info, sizeof(kernctl_info)); 56 strlcpy(kernctl_info.ctl_name, "com.apple.net.ipsec_control", sizeof(kernctl_info.ctl_name)); 57 if (ioctl(tunsock, CTLIOCGINFO, &kernctl_info)) { 58 plog(ASL_LEVEL_ERR, "create_ipsec_interface: ioctl failed on kernel control socket (errno = %d)", errno); 59 goto fail; 60 } 61 62 bzero(&kernctl_addr, sizeof(kernctl_addr)); // sets the sc_unit field to 0 63 kernctl_addr.sc_len = sizeof(kernctl_addr); 64 kernctl_addr.sc_family = AF_SYSTEM; 65 kernctl_addr.ss_sysaddr = AF_SYS_CONTROL; 66 kernctl_addr.sc_id = kernctl_info.ctl_id; 67 kernctl_addr.sc_unit = 0; // we will get the unit number from getpeername 68 if (connect(tunsock, (struct sockaddr *)&kernctl_addr, sizeof(kernctl_addr))) { 69 plog(ASL_LEVEL_ERR, "create_ipsec_interface: connect failed on kernel control socket (errno = %d)", errno); 70 goto fail; 71 } 72 73 optlen = name_max_len; 74 if (getsockopt(tunsock, SYSPROTO_CONTROL, 2, name, &optlen)) { 75 plog(ASL_LEVEL_ERR, "create_ipsec_interface: getsockopt ifname failed on kernel control socket (errno = %d)", errno); 76 goto fail; 77 } 78 79 *index = if_nametoindex(name); 80 81 if (flags) { 82 int optflags = 0; 83 optlen = sizeof(u_int32_t); 84 if (getsockopt(tunsock, SYSPROTO_CONTROL, 1, &optflags, &optlen)) { 85 plog(ASL_LEVEL_ERR, "create_ipsec_interface: getsockopt flags failed on kernel control socket (errno = %d)", errno); 86 goto fail; 87 } 88 89 optflags |= flags; 90 optlen = sizeof(u_int32_t); 91 if (setsockopt(tunsock, SYSPROTO_CONTROL, 1, &optflags, optlen)) { 92 plog(ASL_LEVEL_ERR, "create_ipsec_interface: setsockopt flags failed on kernel control socket (errno = %d)", errno); 93 goto fail; 94 } 95 } 96 97 return tunsock; 98 99fail: 100 if (tunsock != -1) 101 close(tunsock); 102 return -1; 103 104} 105 106int ipsec_interface_set_mtu(char *ifname, int mtu) 107{ 108 struct ifreq ifr; 109 int ip_sockfd; 110 111 ip_sockfd = socket(AF_INET, SOCK_DGRAM, 0); 112 if (ip_sockfd < 0) { 113 plog(ASL_LEVEL_ERR, "sifmtu: cannot create ip socket, %s", strerror(errno)); 114 return 0; 115 } 116 117 strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); 118 ifr.ifr_mtu = mtu; 119 ioctl(ip_sockfd, SIOCSIFMTU, (caddr_t) &ifr); 120 121 close(ip_sockfd); 122 return 1; 123} 124 125void 126in6_len2mask(struct in6_addr *mask, int len) 127{ 128 int i; 129 bzero(mask, sizeof(*mask)); 130 for (i = 0; i < len / 8; i++) 131 mask->s6_addr[i] = 0xff; 132 if (len % 8) 133 mask->s6_addr[i] = (0xff00 >> (len % 8)) & 0xff; 134} 135 136#define SET_SA_FAMILY(addr, family) \ 137bzero((char *) &(addr), sizeof(addr)); \ 138addr.sa_family = (family); \ 139addr.sa_len = sizeof(addr); 140int ipsec_interface_set_addr(char *ifname, struct sockaddr_storage *address, struct sockaddr_storage *netmask, int prefix) 141{ 142 int ip_sockfd; 143 144 int family = address->ss_family; 145 146 if (family == AF_INET) { 147 struct ifaliasreq ifra __attribute__ ((aligned (4))); // Wcast-align fix - force alignment 148 ip_sockfd = socket(AF_INET, SOCK_DGRAM, 0); 149 if (ip_sockfd < 0) { 150 plog(ASL_LEVEL_ERR, "Cannot create ip socket, %s", strerror(errno)); 151 return 0; 152 } 153 154 strlcpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name)); 155 156 SET_SA_FAMILY(ifra.ifra_addr, AF_INET); 157 (ALIGNED_CAST(struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = ((struct sockaddr_in*)address)->sin_addr.s_addr; 158 159 SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET); 160 (ALIGNED_CAST(struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = ((struct sockaddr_in*)address)->sin_addr.s_addr; 161 162 if (netmask != 0) { 163 SET_SA_FAMILY(ifra.ifra_mask, AF_INET); 164 (ALIGNED_CAST(struct sockaddr_in *) &ifra.ifra_mask)->sin_addr.s_addr = ((struct sockaddr_in*)netmask)->sin_addr.s_addr; 165 } 166 else 167 bzero(&ifra.ifra_mask, sizeof(ifra.ifra_mask)); 168 169 if (ioctl(ip_sockfd, SIOCAIFADDR, (caddr_t) &ifra) < 0) { 170 if (errno != EEXIST) { 171 plog(ASL_LEVEL_ERR, "Couldn't set interface address"); 172 close(ip_sockfd); 173 return 0; 174 } 175 plog(ASL_LEVEL_ERR, "Couldn't set interface address, already exists"); 176 } 177 close(ip_sockfd); 178 } else if (family == AF_INET6) { 179 struct in6_aliasreq addreq6; 180 struct in6_addr mask; 181 struct in6_addr *addr6 = &((struct sockaddr_in6*)address)->sin6_addr; 182 183 ip_sockfd = socket(AF_INET6, SOCK_DGRAM, 0); 184 if (ip_sockfd < 0) { 185 plog(ASL_LEVEL_ERR, "Cannot create IPv6 socket, %s", strerror(errno)); 186 return 0; 187 } 188 189 memset(&addreq6, 0, sizeof(addreq6)); 190 strlcpy(addreq6.ifra_name, ifname, sizeof(addreq6.ifra_name)); 191 /* my addr */ 192 addreq6.ifra_addr.sin6_family = AF_INET6; 193 addreq6.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); 194 memcpy(&addreq6.ifra_addr.sin6_addr, addr6, sizeof(struct in6_addr)); 195 196 /* prefix mask: 128bit */ 197 addreq6.ifra_prefixmask.sin6_family = AF_INET6; 198 addreq6.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 199 in6_len2mask(&mask, prefix); 200 memcpy(&addreq6.ifra_prefixmask.sin6_addr, &mask, sizeof(struct in6_addr)); 201 202 /* address lifetime (infty) */ 203 addreq6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; 204 addreq6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; 205 if (IN6_IS_ADDR_LINKLOCAL(addr6)) { 206 if (ioctl(ip_sockfd, SIOCLL_START, &addreq6) < 0) { 207 plog(ASL_LEVEL_ERR, "Couldn't set link-local IPv6 address, %s", strerror(errno)); 208 close(ip_sockfd); 209 return 0; 210 } 211 } else { 212 if (ioctl(ip_sockfd, SIOCAIFADDR_IN6, &addreq6) < 0) { 213 plog(ASL_LEVEL_ERR, "Couldn't set IPv6 address, %s", strerror(errno)); 214 close(ip_sockfd); 215 return 0; 216 } 217 } 218 close(ip_sockfd); 219 } else { 220 return 0; 221 } 222 223 return 1; 224} 225