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