2 * Copyright (c) 2012 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 #include <sys/types.h>
26 #include <sys/param.h>
27 #include <sys/socket.h>
28 #include <sys/ioctl.h>
31 #include <sys/kern_control.h>
32 #include <sys/sys_domain.h>
33 #include "racoon_types.h"
36 #include <netinet6/in6_var.h>
37 #include <netinet6/nd6.h>
41 int ipsec_interface_create(char *name
, int name_max_len
, int *index
, int flags
)
44 struct ctl_info kernctl_info
;
45 struct sockaddr_ctl kernctl_addr
;
49 tunsock
= socket(PF_SYSTEM
, SOCK_DGRAM
, SYSPROTO_CONTROL
);
51 plog(ASL_LEVEL_ERR
, "create_ipsec_interface: cannot create kernel control socket (errno = %d)", errno
);
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
);
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
);
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
);
79 *index
= if_nametoindex(name
);
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
);
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
);
106 int ipsec_interface_set_mtu(char *ifname
, int mtu
)
111 ip_sockfd
= socket(AF_INET
, SOCK_DGRAM
, 0);
113 plog(ASL_LEVEL_ERR
, "sifmtu: cannot create ip socket, %s", strerror(errno
));
117 strlcpy(ifr
.ifr_name
, ifname
, sizeof (ifr
.ifr_name
));
119 ioctl(ip_sockfd
, SIOCSIFMTU
, (caddr_t
) &ifr
);
126 in6_len2mask(struct in6_addr
*mask
, int len
)
129 bzero(mask
, sizeof(*mask
));
130 for (i
= 0; i
< len
/ 8; i
++)
131 mask
->s6_addr
[i
] = 0xff;
133 mask
->s6_addr
[i
] = (0xff00 >> (len
% 8)) & 0xff;
136 #define SET_SA_FAMILY(addr, family) \
137 bzero((char *) &(addr), sizeof(addr)); \
138 addr.sa_family = (family); \
139 addr.sa_len = sizeof(addr);
140 int ipsec_interface_set_addr(char *ifname
, struct sockaddr_storage
*address
, struct sockaddr_storage
*netmask
, int prefix
)
144 int family
= address
->ss_family
;
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);
150 plog(ASL_LEVEL_ERR
, "Cannot create ip socket, %s", strerror(errno
));
154 strlcpy(ifra
.ifra_name
, ifname
, sizeof(ifra
.ifra_name
));
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
;
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
;
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
;
167 bzero(&ifra
.ifra_mask
, sizeof(ifra
.ifra_mask
));
169 if (ioctl(ip_sockfd
, SIOCAIFADDR
, (caddr_t
) &ifra
) < 0) {
170 if (errno
!= EEXIST
) {
171 plog(ASL_LEVEL_ERR
, "Couldn't set interface address");
175 plog(ASL_LEVEL_ERR
, "Couldn't set interface address, already exists");
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
;
183 ip_sockfd
= socket(AF_INET6
, SOCK_DGRAM
, 0);
185 plog(ASL_LEVEL_ERR
, "Cannot create IPv6 socket, %s", strerror(errno
));
189 memset(&addreq6
, 0, sizeof(addreq6
));
190 strlcpy(addreq6
.ifra_name
, ifname
, sizeof(addreq6
.ifra_name
));
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
));
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
));
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
));
212 if (ioctl(ip_sockfd
, SIOCAIFADDR_IN6
, &addreq6
) < 0) {
213 plog(ASL_LEVEL_ERR
, "Couldn't set IPv6 address, %s", strerror(errno
));