]> git.saurik.com Git - apple/ipsec.git/blob - ipsec-tools/racoon/ipsec_interface.c
70866a17e063069bac74b59e33e241bf37f04f11
[apple/ipsec.git] / ipsec-tools / racoon / ipsec_interface.c
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
41 int 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
99 fail:
100 if (tunsock != -1)
101 close(tunsock);
102 return -1;
103
104 }
105
106 int 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
125 void
126 in6_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) \
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)
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 }