#include "config.h"
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <sys/kern_control.h>
#include <sys/sys_domain.h>
#include "racoon_types.h"
#include "plog.h"
#include <net/if.h>
#include <netinet6/in6_var.h>
#include <netinet6/nd6.h>
#include "var.h"
int ipsec_interface_create(char *name, int name_max_len, int *index, int flags)
{
struct ctl_info kernctl_info;
struct sockaddr_ctl kernctl_addr;
u_int32_t optlen;
int tunsock = -1;
tunsock = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
if (tunsock == -1) {
plog(ASL_LEVEL_ERR, "create_ipsec_interface: cannot create kernel control socket (errno = %d)", errno);
goto fail;
}
bzero(&kernctl_info, sizeof(kernctl_info));
strlcpy(kernctl_info.ctl_name, "com.apple.net.ipsec_control", sizeof(kernctl_info.ctl_name));
if (ioctl(tunsock, CTLIOCGINFO, &kernctl_info)) {
plog(ASL_LEVEL_ERR, "create_ipsec_interface: ioctl failed on kernel control socket (errno = %d)", errno);
goto fail;
}
bzero(&kernctl_addr, sizeof(kernctl_addr)); kernctl_addr.sc_len = sizeof(kernctl_addr);
kernctl_addr.sc_family = AF_SYSTEM;
kernctl_addr.ss_sysaddr = AF_SYS_CONTROL;
kernctl_addr.sc_id = kernctl_info.ctl_id;
kernctl_addr.sc_unit = 0; if (connect(tunsock, (struct sockaddr *)&kernctl_addr, sizeof(kernctl_addr))) {
plog(ASL_LEVEL_ERR, "create_ipsec_interface: connect failed on kernel control socket (errno = %d)", errno);
goto fail;
}
optlen = name_max_len;
if (getsockopt(tunsock, SYSPROTO_CONTROL, 2, name, &optlen)) {
plog(ASL_LEVEL_ERR, "create_ipsec_interface: getsockopt ifname failed on kernel control socket (errno = %d)", errno);
goto fail;
}
*index = if_nametoindex(name);
if (flags) {
int optflags = 0;
optlen = sizeof(u_int32_t);
if (getsockopt(tunsock, SYSPROTO_CONTROL, 1, &optflags, &optlen)) {
plog(ASL_LEVEL_ERR, "create_ipsec_interface: getsockopt flags failed on kernel control socket (errno = %d)", errno);
goto fail;
}
optflags |= flags;
optlen = sizeof(u_int32_t);
if (setsockopt(tunsock, SYSPROTO_CONTROL, 1, &optflags, optlen)) {
plog(ASL_LEVEL_ERR, "create_ipsec_interface: setsockopt flags failed on kernel control socket (errno = %d)", errno);
goto fail;
}
}
return tunsock;
fail:
if (tunsock != -1)
close(tunsock);
return -1;
}
int ipsec_interface_set_mtu(char *ifname, int mtu)
{
struct ifreq ifr;
int ip_sockfd;
ip_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (ip_sockfd < 0) {
plog(ASL_LEVEL_ERR, "sifmtu: cannot create ip socket, %s", strerror(errno));
return 0;
}
strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
ifr.ifr_mtu = mtu;
ioctl(ip_sockfd, SIOCSIFMTU, (caddr_t) &ifr);
close(ip_sockfd);
return 1;
}
void
in6_len2mask(struct in6_addr *mask, int len)
{
int i;
bzero(mask, sizeof(*mask));
for (i = 0; i < len / 8; i++)
mask->s6_addr[i] = 0xff;
if (len % 8)
mask->s6_addr[i] = (0xff00 >> (len % 8)) & 0xff;
}
#define SET_SA_FAMILY(addr, family) \
bzero((char *) &(addr), sizeof(addr)); \
addr.sa_family = (family); \
addr.sa_len = sizeof(addr);
int ipsec_interface_set_addr(char *ifname, struct sockaddr_storage *address, struct sockaddr_storage *netmask, int prefix)
{
int ip_sockfd;
int family = address->ss_family;
if (family == AF_INET) {
struct ifaliasreq ifra __attribute__ ((aligned (4))); ip_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (ip_sockfd < 0) {
plog(ASL_LEVEL_ERR, "Cannot create ip socket, %s", strerror(errno));
return 0;
}
strlcpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
SET_SA_FAMILY(ifra.ifra_addr, AF_INET);
(ALIGNED_CAST(struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = ((struct sockaddr_in*)address)->sin_addr.s_addr;
SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET);
(ALIGNED_CAST(struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = ((struct sockaddr_in*)address)->sin_addr.s_addr;
if (netmask != 0) {
SET_SA_FAMILY(ifra.ifra_mask, AF_INET);
(ALIGNED_CAST(struct sockaddr_in *) &ifra.ifra_mask)->sin_addr.s_addr = ((struct sockaddr_in*)netmask)->sin_addr.s_addr;
}
else
bzero(&ifra.ifra_mask, sizeof(ifra.ifra_mask));
if (ioctl(ip_sockfd, SIOCAIFADDR, (caddr_t) &ifra) < 0) {
if (errno != EEXIST) {
plog(ASL_LEVEL_ERR, "Couldn't set interface address");
close(ip_sockfd);
return 0;
}
plog(ASL_LEVEL_ERR, "Couldn't set interface address, already exists");
}
close(ip_sockfd);
} else if (family == AF_INET6) {
struct in6_aliasreq addreq6;
struct in6_addr mask;
struct in6_addr *addr6 = &((struct sockaddr_in6*)address)->sin6_addr;
ip_sockfd = socket(AF_INET6, SOCK_DGRAM, 0);
if (ip_sockfd < 0) {
plog(ASL_LEVEL_ERR, "Cannot create IPv6 socket, %s", strerror(errno));
return 0;
}
memset(&addreq6, 0, sizeof(addreq6));
strlcpy(addreq6.ifra_name, ifname, sizeof(addreq6.ifra_name));
addreq6.ifra_addr.sin6_family = AF_INET6;
addreq6.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
memcpy(&addreq6.ifra_addr.sin6_addr, addr6, sizeof(struct in6_addr));
addreq6.ifra_prefixmask.sin6_family = AF_INET6;
addreq6.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
in6_len2mask(&mask, prefix);
memcpy(&addreq6.ifra_prefixmask.sin6_addr, &mask, sizeof(struct in6_addr));
addreq6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
addreq6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
if (IN6_IS_ADDR_LINKLOCAL(addr6)) {
if (ioctl(ip_sockfd, SIOCLL_START, &addreq6) < 0) {
plog(ASL_LEVEL_ERR, "Couldn't set link-local IPv6 address, %s", strerror(errno));
close(ip_sockfd);
return 0;
}
} else {
if (ioctl(ip_sockfd, SIOCAIFADDR_IN6, &addreq6) < 0) {
plog(ASL_LEVEL_ERR, "Couldn't set IPv6 address, %s", strerror(errno));
close(ip_sockfd);
return 0;
}
}
close(ip_sockfd);
} else {
return 0;
}
return 1;
}