#include <unistd.h>
#endif
#include <launch.h>
+#include <launch_priv.h>
+#include <fcntl.h>
#include "var.h"
#include "misc.h"
#include "isakmp_inf.h"
#include "session.h"
#include "gcmalloc.h"
+#include "isakmp_cfg.h"
+#include "sainfo.h"
#ifdef ENABLE_VPNCONTROL_PORT
char *vpncontrolsock_path = VPNCONTROLSOCK_PATH;
checklaunchd()
{
launch_data_t checkin_response = NULL;
- launch_data_t checkin_request = NULL;
launch_data_t sockets_dict, listening_fd_array;
launch_data_t listening_fd;
struct sockaddr_storage fdsockaddr;
int fd;
/* check in with launchd */
- if ((checkin_request = launch_data_new_string(LAUNCH_KEY_CHECKIN)) == NULL) {
+ if ((checkin_response = launch_socket_service_check_in()) == NULL) {
plog(LLV_ERROR, LOCATION, NULL,
- "failed to launch_data_new_string.\n");
- goto done;
- }
- if ((checkin_response = launch_msg(checkin_request)) == NULL) {
- plog(LLV_ERROR, LOCATION, NULL,
- "failed to launch_msg.\n");
+ "failed to launch_socket_service_check_in.\n");
goto done;
}
if (LAUNCH_DATA_ERRNO == launch_data_get_type(checkin_response)) {
for (i = 0; i < listenerct; i++) {
listening_fd = launch_data_array_get_index(listening_fd_array, i);
fd = launch_data_get_fd( listening_fd );
- if ( getsockname( fd , (struct sockaddr*)&fdsockaddr, &fdsockaddrlen)){
+ if ( getsockname( fd , (struct sockaddr *)&fdsockaddr, &fdsockaddrlen)){
continue;
}
/* Is this the VPN control socket? */
- if ( (((struct sockaddr*)&fdsockaddr)->sa_family) == AF_UNIX &&
+ if ( fdsockaddr.ss_family == AF_UNIX &&
(!(strcmp(vpncontrolsock_path, ((struct sockaddr_un *)&fdsockaddr)->sun_path))))
{
plog(LLV_INFO, LOCATION, NULL,
}
done:
- if (checkin_request)
- launch_data_free(checkin_request);
if (checkin_response)
launch_data_free(checkin_response);
return(returnval);
{
struct vpnctl_hdr hdr;
char *combuf = NULL;
- int len;
+ ssize_t len;
/* get buffer length */
while ((len = recv(elem->sock, (char *)&hdr, sizeof(hdr), MSG_PEEK)) < 0) {
if (len == 0) {
plog(LLV_DEBUG, LOCATION, NULL,
"vpn_control socket closed by peer.\n");
+ /* kill all related connections */
+ vpncontrol_disconnect_all(elem, ike_session_stopped_by_controller_comm_lost);
vpncontrol_close_comm(elem);
return -1;
}
vpncontrol_process(struct vpnctl_socket_elem *elem, char *combuf)
{
u_int16_t error = 0;
- struct vpnctl_hdr *hdr = (struct vpnctl_hdr *)combuf;
+ struct vpnctl_hdr *hdr = ALIGNED_CAST(struct vpnctl_hdr *)combuf;
switch (ntohs(hdr->msg_type)) {
case VPNCTL_CMD_BIND:
{
- struct vpnctl_cmd_bind *pkt = (struct vpnctl_cmd_bind *)combuf;
+ struct vpnctl_cmd_bind *pkt = ALIGNED_CAST(struct vpnctl_cmd_bind *)combuf;
struct bound_addr *addr;
plog(LLV_DEBUG, LOCATION, NULL,
case VPNCTL_CMD_UNBIND:
{
- struct vpnctl_cmd_unbind *pkt = (struct vpnctl_cmd_unbind *)combuf;
+ struct vpnctl_cmd_unbind *pkt = ALIGNED_CAST(struct vpnctl_cmd_unbind *)combuf;
struct bound_addr *addr;
struct bound_addr *t_addr;
case VPNCTL_CMD_REDIRECT:
{
- struct vpnctl_cmd_redirect *redirect_msg = (struct vpnctl_cmd_redirect *)combuf;
+ struct vpnctl_cmd_redirect *redirect_msg = ALIGNED_CAST(struct vpnctl_cmd_redirect *)combuf;
struct redirect *raddr;
struct redirect *t_raddr;
int found = 0;
case VPNCTL_CMD_XAUTH_INFO:
{
- struct vpnctl_cmd_xauth_info *pkt = (struct vpnctl_cmd_xauth_info *)combuf;
+ struct vpnctl_cmd_xauth_info *pkt = ALIGNED_CAST(struct vpnctl_cmd_xauth_info *)combuf;
struct bound_addr *addr;
struct bound_addr *t_addr;
void *attr_list;
case VPNCTL_CMD_CONNECT:
{
- struct vpnctl_cmd_connect *pkt = (struct vpnctl_cmd_connect *)combuf;
+ struct vpnctl_cmd_connect *pkt = ALIGNED_CAST(struct vpnctl_cmd_connect *)combuf;
struct bound_addr *addr;
struct bound_addr *t_addr;
LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
if (pkt->address == addr->address) {
/* start the connection */
- error = vpn_connect(addr);
+ error = vpn_connect(addr, VPN_STARTED_BY_API);
break;
}
}
case VPNCTL_CMD_DISCONNECT:
{
- struct vpnctl_cmd_connect *pkt = (struct vpnctl_cmd_connect *)combuf;
+ struct vpnctl_cmd_connect *pkt = ALIGNED_CAST(struct vpnctl_cmd_connect *)combuf;
struct bound_addr *addr;
struct bound_addr *t_addr;
LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
if (pkt->address == addr->address) {
/* stop the connection */
- error = vpn_disconnect(addr);
+ error = vpn_disconnect(addr, ike_session_stopped_by_vpn_disconnect);
break;
}
}
case VPNCTL_CMD_START_PH2:
{
- struct vpnctl_cmd_start_ph2 *pkt = (struct vpnctl_cmd_start_ph2 *)combuf;
+ struct vpnctl_cmd_start_ph2 *pkt = ALIGNED_CAST(struct vpnctl_cmd_start_ph2 *)combuf;
struct bound_addr *addr;
struct bound_addr *t_addr;
case VPNCTL_CMD_START_DPD:
{
- struct vpnctl_cmd_start_dpd *pkt = (struct vpnctl_cmd_start_dpd *)combuf;
+ struct vpnctl_cmd_start_dpd *pkt = ALIGNED_CAST(struct vpnctl_cmd_start_dpd *)combuf;
struct bound_addr *srv;
struct bound_addr *t_addr;
"received start_dpd command on vpn control socket.\n");
LIST_FOREACH_SAFE(srv, &elem->bound_addresses, chain, t_addr) {
if (pkt->address == srv->address) {
- struct sockaddr_in daddr;
+ union { // Wcast-align fix - force alignment
+ struct sockaddr_storage ss;
+ struct sockaddr_in addr_in;
+ } daddr;
- bzero(&daddr, sizeof(daddr));
- daddr.sin_len = sizeof(daddr);
- daddr.sin_addr.s_addr = srv->address;
- daddr.sin_port = 0;
- daddr.sin_family = AF_INET;
+ bzero(&daddr, sizeof(struct sockaddr_in));
+ daddr.addr_in.sin_len = sizeof(struct sockaddr_in);
+ daddr.addr_in.sin_addr.s_addr = srv->address;
+ daddr.addr_in.sin_port = 0;
+ daddr.addr_in.sin_family = AF_INET;
/* start the dpd */
- error = ph1_force_dpd(&daddr);
+ error = ph1_force_dpd(&daddr.ss);
break;
}
}
}
break;
+ case VPNCTL_CMD_ASSERT:
+ {
+ struct vpnctl_cmd_assert *pkt = ALIGNED_CAST(struct vpnctl_cmd_assert *)combuf;
+// struct bound_addr *addr;
+// struct bound_addr *t_addr;
+ struct sockaddr_in saddr;
+ struct sockaddr_in daddr;
+
+ plog(LLV_DEBUG, LOCATION, NULL,
+ "received assert command on vpn control socket.\n");
+ plogdump(LLV_DEBUG2, pkt, ntohs(hdr->len) + sizeof(struct vpnctl_hdr));
+// LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
+// if (pkt->dst_address == addr->address) {
+ bzero(&saddr, sizeof(saddr));
+ saddr.sin_len = sizeof(saddr);
+ saddr.sin_addr.s_addr = pkt->src_address;
+ saddr.sin_port = 0;
+ saddr.sin_family = AF_INET;
+ bzero(&daddr, sizeof(daddr));
+ daddr.sin_len = sizeof(daddr);
+ daddr.sin_addr.s_addr = pkt->dst_address;
+ daddr.sin_port = 0;
+ daddr.sin_family = AF_INET;
+
+ error = vpn_assert((struct sockaddr_storage *)&saddr, (struct sockaddr_storage *)&daddr);
+ break;
+// }
+// }
+ }
+ break;
+
+ case VPNCTL_CMD_RECONNECT:
+ {
+ struct vpnctl_cmd_connect *pkt = ALIGNED_CAST(struct vpnctl_cmd_connect *)combuf;
+ struct bound_addr *addr;
+ struct bound_addr *t_addr;
+
+ plog(LLV_DEBUG, LOCATION, NULL,
+ "received reconnect command on vpn control socket.\n");
+ LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
+ if (pkt->address == addr->address) {
+ /* start the connection */
+ error = vpn_connect(addr, VPN_RESTARTED_BY_API);
+ break;
+ }
+ }
+ }
+ break;
+
default:
plog(LLV_ERROR, LOCATION, NULL,
"invalid command: %d\n", ntohs(hdr->msg_type));
static int
vpncontrol_reply(int so, char *combuf)
{
- size_t tlen;
+ ssize_t tlen;
tlen = send(so, combuf, sizeof(struct vpnctl_hdr), 0);
if (tlen < 0) {
struct vpnctl_status_need_authinfo *msg = NULL;
struct vpnctl_socket_elem *sock_elem;
struct bound_addr *bound_addr;
- size_t tlen, msg_size;
+ size_t msg_size;
+ ssize_t tlen;
u_int32_t address;
void *ptr;
}
msg->hdr.flags = 0;
- if (iph1->remote->sa_family == AF_INET)
+ if (iph1->remote->ss_family == AF_INET)
address = ((struct sockaddr_in *)iph1->remote)->sin_addr.s_addr;
else
goto end; // for now
struct vpnctl_status_failed *msg = NULL;
struct vpnctl_socket_elem *sock_elem;
struct bound_addr *bound_addr;
- size_t tlen, len;
+ size_t len;
+ ssize_t tlen;
len = sizeof(struct vpnctl_status_failed) + data_len;
struct vpnctl_status_phase_change *msg;
struct vpnctl_socket_elem *sock_elem;
struct bound_addr *bound_addr;
- size_t tlen, msg_size;
+ ssize_t tlen;
+ size_t msg_size;
u_int32_t address;
plog(LLV_DEBUG, LOCATION, NULL,
"sending vpn_control phase change status\n");
- if (iph1 && !start && iph1->mode_cfg) {
+ if (iph1 && !start && iph1->mode_cfg && iph1->mode_cfg->xauth.status != XAUTHST_OK) {
if (vpn_get_config(iph1, &msg, &msg_size) == 1)
return 0; /* mode config not finished yet */
} else {
return -1;
}
if (iph1) {
- if (iph1->remote->sa_family == AF_INET)
+ if (iph1->remote->ss_family == AF_INET)
address = ((struct sockaddr_in *)iph1->remote)->sin_addr.s_addr;
else
goto end; // for now
(from == FROM_LOCAL ? VPNCTL_STATUS_PH1_START_US : VPNCTL_STATUS_PH1_START_PEER)
: VPNCTL_STATUS_PH1_ESTABLISHED);
} else {
- if (iph2->dst->sa_family == AF_INET)
+ if (iph2->dst->ss_family == AF_INET)
address = ((struct sockaddr_in *)iph2->dst)->sin_addr.s_addr;
else
goto end; // for now
return 0;
}
+static int
+vpncontrol_notify_peer_resp (u_int16_t notify_code, u_int32_t address)
+{
+ struct vpnctl_status_peer_resp msg;
+ struct vpnctl_socket_elem *sock_elem;
+ struct bound_addr *bound_addr;
+ ssize_t tlen;
+ int rc = -1;
+
+ bzero(&msg, sizeof(msg));
+ msg.hdr.msg_type = htons(VPNCTL_STATUS_PEER_RESP);
+ msg.hdr.cookie = msg.hdr.reserved = msg.hdr.result = 0;
+ msg.hdr.len = htons(sizeof(msg) - sizeof(msg.hdr));
+ msg.address = address;
+ msg.ike_code = notify_code;
+ plog(LLV_DEBUG, LOCATION, NULL,
+ "sending vpn_control status (peer response) message - code=%d addr=%x.\n", notify_code, address);
+
+ LIST_FOREACH(sock_elem, &lcconf->vpnctl_comm_socks, chain) {
+ LIST_FOREACH(bound_addr, &sock_elem->bound_addresses, chain) {
+ if (bound_addr->address == 0xFFFFFFFF ||
+ bound_addr->address == address) {
+ tlen = send(sock_elem->sock, &msg, sizeof(msg), 0);
+ if (tlen < 0) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "unable to send vpn_control status (peer response): %s\n", strerror(errno));
+ } else {
+ rc = 0;
+ }
+ break;
+ }
+ }
+ }
+
+ return rc;
+}
+
+int
+vpncontrol_notify_peer_resp_ph1 (u_int16_t notify_code, struct ph1handle *iph1)
+{
+ u_int32_t address;
+ int rc;
+
+ if (iph1 && iph1->parent_session && iph1->parent_session->controller_awaiting_peer_resp) {
+ if (iph1->remote->ss_family == AF_INET)
+ address = ((struct sockaddr_in *)iph1->remote)->sin_addr.s_addr;
+ else
+ address = 0;
+ } else {
+ return 0;
+ }
+
+ if ((rc = vpncontrol_notify_peer_resp(notify_code, address)) == 0) {
+ iph1->parent_session->controller_awaiting_peer_resp = 0;
+ }
+ return rc;
+}
+
+int
+vpncontrol_notify_peer_resp_ph2 (u_int16_t notify_code, struct ph2handle *iph2)
+{
+ u_int32_t address;
+ int rc;
+
+ if (iph2 && iph2->parent_session && iph2->parent_session->controller_awaiting_peer_resp) {
+ if (iph2->dst->ss_family == AF_INET)
+ address = ((struct sockaddr_in *)iph2->dst)->sin_addr.s_addr;
+ else
+ address = 0;
+ } else {
+ return 0;
+ }
+
+ if ((rc = vpncontrol_notify_peer_resp(notify_code, address)) == 0) {
+ iph2->parent_session->controller_awaiting_peer_resp = 0;
+ }
+ return rc;
+}
int
vpncontrol_init()
return -1;
}
+ if (fcntl(lcconf->sock_vpncontrol, F_SETFL, O_NONBLOCK) == -1) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to put VPN-Control socket in non-blocking mode\n");
+ }
+
unlink(sunaddr.sun_path);
if (bind(lcconf->sock_vpncontrol, (struct sockaddr *)&sunaddr,
sizeof(sunaddr)) != 0) {
}
}
+void
+vpncontrol_disconnect_all(struct vpnctl_socket_elem *elem, const char *reason)
+{
+ struct bound_addr *addr;
+ struct bound_addr *t_addr;
+
+ plog(LLV_DEBUG, LOCATION, NULL,
+ "received disconnect all command.\n");
+
+ LIST_FOREACH_SAFE(addr, &elem->bound_addresses, chain, t_addr) {
+ /* stop any connections */
+ vpn_disconnect(addr, reason);
+ }
+}
+
void
vpncontrol_close()