1*92270c32Shshoexer /* $OpenBSD: pfkey.c,v 1.49 2008/12/22 17:00:37 hshoexer Exp $ */ 2f484f2cfShshoexer /* 3f484f2cfShshoexer * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 4f484f2cfShshoexer * Copyright (c) 2003, 2004 Markus Friedl <markus@openbsd.org> 5f484f2cfShshoexer * Copyright (c) 2004, 2005 Hans-Joerg Hoexer <hshoexer@openbsd.org> 6f484f2cfShshoexer * 7f484f2cfShshoexer * Permission to use, copy, modify, and distribute this software for any 8f484f2cfShshoexer * purpose with or without fee is hereby granted, provided that the above 9f484f2cfShshoexer * copyright notice and this permission notice appear in all copies. 10f484f2cfShshoexer * 11f484f2cfShshoexer * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12f484f2cfShshoexer * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13f484f2cfShshoexer * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14f484f2cfShshoexer * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15f484f2cfShshoexer * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16f484f2cfShshoexer * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17f484f2cfShshoexer * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18f484f2cfShshoexer */ 19f484f2cfShshoexer 20f484f2cfShshoexer #include <sys/types.h> 21f484f2cfShshoexer #include <sys/queue.h> 22f484f2cfShshoexer #include <sys/uio.h> 23f484f2cfShshoexer #include <sys/socket.h> 24f484f2cfShshoexer #include <netinet/in.h> 25f484f2cfShshoexer #include <netinet/ip_ipsp.h> 26f484f2cfShshoexer #include <net/pfkeyv2.h> 27f484f2cfShshoexer 28f484f2cfShshoexer #include <err.h> 29f484f2cfShshoexer #include <errno.h> 30f484f2cfShshoexer #include <stdio.h> 31f484f2cfShshoexer #include <string.h> 32f484f2cfShshoexer #include <stdlib.h> 33f484f2cfShshoexer #include <unistd.h> 34f484f2cfShshoexer 35f484f2cfShshoexer #include "ipsecctl.h" 361edc1b9aShshoexer #include "pfkey.h" 37f484f2cfShshoexer 38f484f2cfShshoexer #define ROUNDUP(x) (((x) + (PFKEYV2_CHUNK - 1)) & ~(PFKEYV2_CHUNK - 1)) 39f484f2cfShshoexer #define IOV_CNT 20 40f484f2cfShshoexer 41f484f2cfShshoexer static int fd; 42f484f2cfShshoexer static u_int32_t sadb_msg_seq = 1; 43f484f2cfShshoexer 449182219dSmarkus static int pfkey_flow(int, u_int8_t, u_int8_t, u_int8_t, u_int8_t, 4557f58d0dSnaddy struct ipsec_addr_wrap *, u_int16_t, 4657f58d0dSnaddy struct ipsec_addr_wrap *, u_int16_t, 47435bb41eSmarkus struct ipsec_addr_wrap *, struct ipsec_addr_wrap *, 48435bb41eSmarkus struct ipsec_auth *, u_int8_t); 49f032086dShshoexer static int pfkey_sa(int, u_int8_t, u_int8_t, u_int32_t, 5091f765ddShshoexer struct ipsec_addr_wrap *, struct ipsec_addr_wrap *, 51375db29dShshoexer struct ipsec_transforms *, struct ipsec_key *, 52a38d220fShshoexer struct ipsec_key *, u_int8_t); 538065703bShshoexer static int pfkey_sagroup(int, u_int8_t, u_int8_t, u_int8_t, 548065703bShshoexer struct ipsec_addr_wrap *, u_int32_t, 558065703bShshoexer struct ipsec_addr_wrap *, u_int32_t); 568a87fca6Smsf static int pfkey_reply(int, u_int8_t **, ssize_t *); 57e225c210Shshoexer int pfkey_parse(struct sadb_msg *, struct ipsec_rule *); 58f484f2cfShshoexer int pfkey_ipsec_flush(void); 59356121f6Shshoexer int pfkey_ipsec_establish(int, struct ipsec_rule *); 60f484f2cfShshoexer int pfkey_init(void); 61f484f2cfShshoexer 62f484f2cfShshoexer static int 63f484f2cfShshoexer pfkey_flow(int sd, u_int8_t satype, u_int8_t action, u_int8_t direction, 6457f58d0dSnaddy u_int8_t proto, struct ipsec_addr_wrap *src, u_int16_t sport, 6557f58d0dSnaddy struct ipsec_addr_wrap *dst, u_int16_t dport, 66435bb41eSmarkus struct ipsec_addr_wrap *local, struct ipsec_addr_wrap *peer, 67435bb41eSmarkus struct ipsec_auth *auth, u_int8_t flowtype) 68f484f2cfShshoexer { 69f484f2cfShshoexer struct sadb_msg smsg; 70435bb41eSmarkus struct sadb_address sa_src, sa_dst, sa_local, sa_peer, sa_smask, 71435bb41eSmarkus sa_dmask; 72f484f2cfShshoexer struct sadb_protocol sa_flowtype, sa_protocol; 73f484f2cfShshoexer struct sadb_ident *sa_srcid, *sa_dstid; 74435bb41eSmarkus struct sockaddr_storage ssrc, sdst, slocal, speer, smask, dmask; 75f484f2cfShshoexer struct iovec iov[IOV_CNT]; 76f484f2cfShshoexer ssize_t n; 77f484f2cfShshoexer int iov_cnt, len, ret = 0; 78f484f2cfShshoexer 79f484f2cfShshoexer sa_srcid = sa_dstid = NULL; 80f484f2cfShshoexer 81f484f2cfShshoexer bzero(&ssrc, sizeof(ssrc)); 82f484f2cfShshoexer bzero(&smask, sizeof(smask)); 832099bcdfStodd ssrc.ss_family = smask.ss_family = src->af; 84f484f2cfShshoexer switch (src->af) { 85f484f2cfShshoexer case AF_INET: 86712e78baShshoexer ((struct sockaddr_in *)&ssrc)->sin_addr = src->address.v4; 87f484f2cfShshoexer ssrc.ss_len = sizeof(struct sockaddr_in); 88712e78baShshoexer ((struct sockaddr_in *)&smask)->sin_addr = src->mask.v4; 8957f58d0dSnaddy if (sport) { 9057f58d0dSnaddy ((struct sockaddr_in *)&ssrc)->sin_port = sport; 9157f58d0dSnaddy ((struct sockaddr_in *)&smask)->sin_port = 0xffff; 9257f58d0dSnaddy } 93f484f2cfShshoexer break; 94f484f2cfShshoexer case AF_INET6: 952099bcdfStodd ((struct sockaddr_in6 *)&ssrc)->sin6_addr = src->address.v6; 962099bcdfStodd ssrc.ss_len = sizeof(struct sockaddr_in6); 972099bcdfStodd ((struct sockaddr_in6 *)&smask)->sin6_addr = src->mask.v6; 9857f58d0dSnaddy if (sport) { 9957f58d0dSnaddy ((struct sockaddr_in6 *)&ssrc)->sin6_port = sport; 10057f58d0dSnaddy ((struct sockaddr_in6 *)&smask)->sin6_port = 0xffff; 10157f58d0dSnaddy } 1022099bcdfStodd break; 103f484f2cfShshoexer default: 104f484f2cfShshoexer warnx("unsupported address family %d", src->af); 105f484f2cfShshoexer return -1; 106f484f2cfShshoexer } 107f484f2cfShshoexer smask.ss_len = ssrc.ss_len; 108f484f2cfShshoexer 109f484f2cfShshoexer bzero(&sdst, sizeof(sdst)); 110f484f2cfShshoexer bzero(&dmask, sizeof(dmask)); 1112099bcdfStodd sdst.ss_family = dmask.ss_family = dst->af; 112f484f2cfShshoexer switch (dst->af) { 113f484f2cfShshoexer case AF_INET: 114712e78baShshoexer ((struct sockaddr_in *)&sdst)->sin_addr = dst->address.v4; 115f484f2cfShshoexer sdst.ss_len = sizeof(struct sockaddr_in); 116712e78baShshoexer ((struct sockaddr_in *)&dmask)->sin_addr = dst->mask.v4; 11757f58d0dSnaddy if (dport) { 11857f58d0dSnaddy ((struct sockaddr_in *)&sdst)->sin_port = dport; 11957f58d0dSnaddy ((struct sockaddr_in *)&dmask)->sin_port = 0xffff; 12057f58d0dSnaddy } 121f484f2cfShshoexer break; 122f484f2cfShshoexer case AF_INET6: 1232099bcdfStodd ((struct sockaddr_in6 *)&sdst)->sin6_addr = dst->address.v6; 1242099bcdfStodd sdst.ss_len = sizeof(struct sockaddr_in6); 1252099bcdfStodd ((struct sockaddr_in6 *)&dmask)->sin6_addr = dst->mask.v6; 12657f58d0dSnaddy if (dport) { 12757f58d0dSnaddy ((struct sockaddr_in6 *)&sdst)->sin6_port = dport; 12857f58d0dSnaddy ((struct sockaddr_in6 *)&dmask)->sin6_port = 0xffff; 12957f58d0dSnaddy } 1302099bcdfStodd break; 131f484f2cfShshoexer default: 132f484f2cfShshoexer warnx("unsupported address family %d", dst->af); 133f484f2cfShshoexer return -1; 134f484f2cfShshoexer } 135f484f2cfShshoexer dmask.ss_len = sdst.ss_len; 136f484f2cfShshoexer 137435bb41eSmarkus bzero(&slocal, sizeof(slocal)); 138435bb41eSmarkus if (local) { 1392099bcdfStodd slocal.ss_family = local->af; 140435bb41eSmarkus switch (local->af) { 141435bb41eSmarkus case AF_INET: 142435bb41eSmarkus ((struct sockaddr_in *)&slocal)->sin_addr = 143435bb41eSmarkus local->address.v4; 144435bb41eSmarkus slocal.ss_len = sizeof(struct sockaddr_in); 145435bb41eSmarkus break; 146435bb41eSmarkus case AF_INET6: 1472099bcdfStodd ((struct sockaddr_in6 *)&slocal)->sin6_addr = 1482099bcdfStodd local->address.v6; 1492099bcdfStodd slocal.ss_len = sizeof(struct sockaddr_in6); 1502099bcdfStodd break; 151435bb41eSmarkus default: 152435bb41eSmarkus warnx("unsupported address family %d", local->af); 153435bb41eSmarkus return -1; 154435bb41eSmarkus } 155435bb41eSmarkus } 156435bb41eSmarkus 157f484f2cfShshoexer bzero(&speer, sizeof(speer)); 15822a29ad6Shshoexer if (peer) { 1592099bcdfStodd speer.ss_family = peer->af; 160f484f2cfShshoexer switch (peer->af) { 161f484f2cfShshoexer case AF_INET: 162712e78baShshoexer ((struct sockaddr_in *)&speer)->sin_addr = 163712e78baShshoexer peer->address.v4; 164f484f2cfShshoexer speer.ss_len = sizeof(struct sockaddr_in); 165f484f2cfShshoexer break; 166f484f2cfShshoexer case AF_INET6: 1672099bcdfStodd ((struct sockaddr_in6 *)&speer)->sin6_addr = 1682099bcdfStodd peer->address.v6; 1692099bcdfStodd speer.ss_len = sizeof(struct sockaddr_in6); 1702099bcdfStodd break; 171f484f2cfShshoexer default: 172f484f2cfShshoexer warnx("unsupported address family %d", peer->af); 173f484f2cfShshoexer return -1; 174f484f2cfShshoexer } 17522a29ad6Shshoexer } 176f484f2cfShshoexer 177f484f2cfShshoexer bzero(&smsg, sizeof(smsg)); 178f484f2cfShshoexer smsg.sadb_msg_version = PF_KEY_V2; 179f484f2cfShshoexer smsg.sadb_msg_seq = sadb_msg_seq++; 180f484f2cfShshoexer smsg.sadb_msg_pid = getpid(); 181f484f2cfShshoexer smsg.sadb_msg_len = sizeof(smsg) / 8; 182f484f2cfShshoexer smsg.sadb_msg_type = action; 183f484f2cfShshoexer smsg.sadb_msg_satype = satype; 184f484f2cfShshoexer 185f484f2cfShshoexer bzero(&sa_flowtype, sizeof(sa_flowtype)); 186f484f2cfShshoexer sa_flowtype.sadb_protocol_exttype = SADB_X_EXT_FLOW_TYPE; 187f484f2cfShshoexer sa_flowtype.sadb_protocol_len = sizeof(sa_flowtype) / 8; 188f484f2cfShshoexer sa_flowtype.sadb_protocol_direction = direction; 18926df514dShshoexer 190e1ffbfafShshoexer switch (flowtype) { 191e1ffbfafShshoexer case TYPE_USE: 19226df514dShshoexer sa_flowtype.sadb_protocol_proto = SADB_X_FLOW_TYPE_USE; 193e1ffbfafShshoexer break; 194b7a16601Shshoexer case TYPE_ACQUIRE: 195b7a16601Shshoexer sa_flowtype.sadb_protocol_proto = SADB_X_FLOW_TYPE_ACQUIRE; 196b7a16601Shshoexer break; 197e1ffbfafShshoexer case TYPE_REQUIRE: 198f484f2cfShshoexer sa_flowtype.sadb_protocol_proto = SADB_X_FLOW_TYPE_REQUIRE; 199e1ffbfafShshoexer break; 2007c7fb9e5Sreyk case TYPE_DENY: 2017c7fb9e5Sreyk sa_flowtype.sadb_protocol_proto = SADB_X_FLOW_TYPE_DENY; 2027c7fb9e5Sreyk break; 2037c7fb9e5Sreyk case TYPE_BYPASS: 2047c7fb9e5Sreyk sa_flowtype.sadb_protocol_proto = SADB_X_FLOW_TYPE_BYPASS; 2057c7fb9e5Sreyk break; 206b7a16601Shshoexer case TYPE_DONTACQ: 207b7a16601Shshoexer sa_flowtype.sadb_protocol_proto = SADB_X_FLOW_TYPE_DONTACQ; 208b7a16601Shshoexer break; 209e1ffbfafShshoexer default: 210e1ffbfafShshoexer warnx("unsupported flowtype %d", flowtype); 211e1ffbfafShshoexer return -1; 212e1ffbfafShshoexer } 213f484f2cfShshoexer 214f484f2cfShshoexer bzero(&sa_protocol, sizeof(sa_protocol)); 215f484f2cfShshoexer sa_protocol.sadb_protocol_exttype = SADB_X_EXT_PROTOCOL; 216f484f2cfShshoexer sa_protocol.sadb_protocol_len = sizeof(sa_protocol) / 8; 217f484f2cfShshoexer sa_protocol.sadb_protocol_direction = 0; 2189182219dSmarkus sa_protocol.sadb_protocol_proto = proto; 219f484f2cfShshoexer 220f484f2cfShshoexer bzero(&sa_src, sizeof(sa_src)); 221f484f2cfShshoexer sa_src.sadb_address_exttype = SADB_X_EXT_SRC_FLOW; 222f484f2cfShshoexer sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(ssrc.ss_len)) / 8; 223f484f2cfShshoexer 224f484f2cfShshoexer bzero(&sa_smask, sizeof(sa_smask)); 225f484f2cfShshoexer sa_smask.sadb_address_exttype = SADB_X_EXT_SRC_MASK; 226f484f2cfShshoexer sa_smask.sadb_address_len = 227f484f2cfShshoexer (sizeof(sa_smask) + ROUNDUP(smask.ss_len)) / 8; 228f484f2cfShshoexer 229f484f2cfShshoexer bzero(&sa_dst, sizeof(sa_dst)); 230f484f2cfShshoexer sa_dst.sadb_address_exttype = SADB_X_EXT_DST_FLOW; 231f484f2cfShshoexer sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(sdst.ss_len)) / 8; 232f484f2cfShshoexer 233f484f2cfShshoexer bzero(&sa_dmask, sizeof(sa_dmask)); 234f484f2cfShshoexer sa_dmask.sadb_address_exttype = SADB_X_EXT_DST_MASK; 235f484f2cfShshoexer sa_dmask.sadb_address_len = 236f484f2cfShshoexer (sizeof(sa_dmask) + ROUNDUP(dmask.ss_len)) / 8; 237f484f2cfShshoexer 238435bb41eSmarkus if (local) { 239435bb41eSmarkus bzero(&sa_local, sizeof(sa_local)); 240435bb41eSmarkus sa_local.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; 241435bb41eSmarkus sa_local.sadb_address_len = 242435bb41eSmarkus (sizeof(sa_local) + ROUNDUP(slocal.ss_len)) / 8; 243435bb41eSmarkus } 244435bb41eSmarkus if (peer) { 245f484f2cfShshoexer bzero(&sa_peer, sizeof(sa_peer)); 246f484f2cfShshoexer sa_peer.sadb_address_exttype = SADB_EXT_ADDRESS_DST; 247f484f2cfShshoexer sa_peer.sadb_address_len = 248f484f2cfShshoexer (sizeof(sa_peer) + ROUNDUP(speer.ss_len)) / 8; 249435bb41eSmarkus } 250f484f2cfShshoexer 251abe65127Shshoexer if (auth && auth->srcid) { 252abe65127Shshoexer len = ROUNDUP(strlen(auth->srcid) + 1) + sizeof(*sa_srcid); 253f484f2cfShshoexer 254f484f2cfShshoexer sa_srcid = calloc(len, sizeof(u_int8_t)); 255f484f2cfShshoexer if (sa_srcid == NULL) 256bd828a90Shshoexer err(1, "pfkey_flow: calloc"); 257f484f2cfShshoexer 2582281ca6dSmarkus sa_srcid->sadb_ident_type = auth->srcid_type; 259f484f2cfShshoexer sa_srcid->sadb_ident_len = len / 8; 260f484f2cfShshoexer sa_srcid->sadb_ident_exttype = SADB_EXT_IDENTITY_SRC; 261f484f2cfShshoexer 262abe65127Shshoexer strlcpy((char *)(sa_srcid + 1), auth->srcid, 263abe65127Shshoexer ROUNDUP(strlen(auth->srcid) + 1)); 264f484f2cfShshoexer } 265abe65127Shshoexer if (auth && auth->dstid) { 266abe65127Shshoexer len = ROUNDUP(strlen(auth->dstid) + 1) + sizeof(*sa_dstid); 267f484f2cfShshoexer 268f484f2cfShshoexer sa_dstid = calloc(len, sizeof(u_int8_t)); 269f484f2cfShshoexer if (sa_dstid == NULL) 270bd828a90Shshoexer err(1, "pfkey_flow: calloc"); 271f484f2cfShshoexer 2722281ca6dSmarkus sa_dstid->sadb_ident_type = auth->dstid_type; 273f484f2cfShshoexer sa_dstid->sadb_ident_len = len / 8; 274f484f2cfShshoexer sa_dstid->sadb_ident_exttype = SADB_EXT_IDENTITY_DST; 275f484f2cfShshoexer 276abe65127Shshoexer strlcpy((char *)(sa_dstid + 1), auth->dstid, 277abe65127Shshoexer ROUNDUP(strlen(auth->dstid) + 1)); 278f484f2cfShshoexer } 279f484f2cfShshoexer 280f484f2cfShshoexer iov_cnt = 0; 281f484f2cfShshoexer 282f484f2cfShshoexer /* header */ 283f484f2cfShshoexer iov[iov_cnt].iov_base = &smsg; 284f484f2cfShshoexer iov[iov_cnt].iov_len = sizeof(smsg); 285f484f2cfShshoexer iov_cnt++; 286f484f2cfShshoexer 28789ad8c34Shshoexer /* add flow type */ 28889ad8c34Shshoexer iov[iov_cnt].iov_base = &sa_flowtype; 28989ad8c34Shshoexer iov[iov_cnt].iov_len = sizeof(sa_flowtype); 29089ad8c34Shshoexer smsg.sadb_msg_len += sa_flowtype.sadb_protocol_len; 29189ad8c34Shshoexer iov_cnt++; 29289ad8c34Shshoexer 293435bb41eSmarkus /* local ip */ 294435bb41eSmarkus if (local) { 295435bb41eSmarkus iov[iov_cnt].iov_base = &sa_local; 296435bb41eSmarkus iov[iov_cnt].iov_len = sizeof(sa_local); 297435bb41eSmarkus iov_cnt++; 298435bb41eSmarkus iov[iov_cnt].iov_base = &slocal; 299435bb41eSmarkus iov[iov_cnt].iov_len = ROUNDUP(slocal.ss_len); 300435bb41eSmarkus smsg.sadb_msg_len += sa_local.sadb_address_len; 301435bb41eSmarkus iov_cnt++; 302435bb41eSmarkus } 303435bb41eSmarkus 304f484f2cfShshoexer /* remote peer */ 30522a29ad6Shshoexer if (peer) { 306f484f2cfShshoexer iov[iov_cnt].iov_base = &sa_peer; 307f484f2cfShshoexer iov[iov_cnt].iov_len = sizeof(sa_peer); 308f484f2cfShshoexer iov_cnt++; 309f484f2cfShshoexer iov[iov_cnt].iov_base = &speer; 310f484f2cfShshoexer iov[iov_cnt].iov_len = ROUNDUP(speer.ss_len); 311f484f2cfShshoexer smsg.sadb_msg_len += sa_peer.sadb_address_len; 312f484f2cfShshoexer iov_cnt++; 31322a29ad6Shshoexer } 314f484f2cfShshoexer 31589ad8c34Shshoexer /* src addr */ 31689ad8c34Shshoexer iov[iov_cnt].iov_base = &sa_src; 31789ad8c34Shshoexer iov[iov_cnt].iov_len = sizeof(sa_src); 31889ad8c34Shshoexer iov_cnt++; 31989ad8c34Shshoexer iov[iov_cnt].iov_base = &ssrc; 32089ad8c34Shshoexer iov[iov_cnt].iov_len = ROUNDUP(ssrc.ss_len); 32189ad8c34Shshoexer smsg.sadb_msg_len += sa_src.sadb_address_len; 322f484f2cfShshoexer iov_cnt++; 323f484f2cfShshoexer 32489ad8c34Shshoexer /* src mask */ 325f484f2cfShshoexer iov[iov_cnt].iov_base = &sa_smask; 326f484f2cfShshoexer iov[iov_cnt].iov_len = sizeof(sa_smask); 327f484f2cfShshoexer iov_cnt++; 328f484f2cfShshoexer iov[iov_cnt].iov_base = &smask; 329f484f2cfShshoexer iov[iov_cnt].iov_len = ROUNDUP(smask.ss_len); 330f484f2cfShshoexer smsg.sadb_msg_len += sa_smask.sadb_address_len; 331f484f2cfShshoexer iov_cnt++; 332f484f2cfShshoexer 333f484f2cfShshoexer /* dest addr */ 334f484f2cfShshoexer iov[iov_cnt].iov_base = &sa_dst; 335f484f2cfShshoexer iov[iov_cnt].iov_len = sizeof(sa_dst); 336f484f2cfShshoexer iov_cnt++; 337f484f2cfShshoexer iov[iov_cnt].iov_base = &sdst; 338f484f2cfShshoexer iov[iov_cnt].iov_len = ROUNDUP(sdst.ss_len); 339f484f2cfShshoexer smsg.sadb_msg_len += sa_dst.sadb_address_len; 340f484f2cfShshoexer iov_cnt++; 341f484f2cfShshoexer 34289ad8c34Shshoexer /* dst mask */ 34389ad8c34Shshoexer iov[iov_cnt].iov_base = &sa_dmask; 34489ad8c34Shshoexer iov[iov_cnt].iov_len = sizeof(sa_dmask); 345f484f2cfShshoexer iov_cnt++; 34689ad8c34Shshoexer iov[iov_cnt].iov_base = &dmask; 34789ad8c34Shshoexer iov[iov_cnt].iov_len = ROUNDUP(dmask.ss_len); 34889ad8c34Shshoexer smsg.sadb_msg_len += sa_dmask.sadb_address_len; 34989ad8c34Shshoexer iov_cnt++; 35089ad8c34Shshoexer 35189ad8c34Shshoexer /* add protocol */ 35289ad8c34Shshoexer iov[iov_cnt].iov_base = &sa_protocol; 35389ad8c34Shshoexer iov[iov_cnt].iov_len = sizeof(sa_protocol); 35489ad8c34Shshoexer smsg.sadb_msg_len += sa_protocol.sadb_protocol_len; 355f484f2cfShshoexer iov_cnt++; 356f484f2cfShshoexer 357f484f2cfShshoexer if (sa_srcid) { 358f484f2cfShshoexer /* src identity */ 359f484f2cfShshoexer iov[iov_cnt].iov_base = sa_srcid; 360f484f2cfShshoexer iov[iov_cnt].iov_len = sa_srcid->sadb_ident_len * 8; 361f484f2cfShshoexer smsg.sadb_msg_len += sa_srcid->sadb_ident_len; 362f484f2cfShshoexer iov_cnt++; 363f484f2cfShshoexer } 364f484f2cfShshoexer if (sa_dstid) { 365f484f2cfShshoexer /* dst identity */ 366f484f2cfShshoexer iov[iov_cnt].iov_base = sa_dstid; 367f484f2cfShshoexer iov[iov_cnt].iov_len = sa_dstid->sadb_ident_len * 8; 368f484f2cfShshoexer smsg.sadb_msg_len += sa_dstid->sadb_ident_len; 369f484f2cfShshoexer iov_cnt++; 370f484f2cfShshoexer } 371f484f2cfShshoexer len = smsg.sadb_msg_len * 8; 37289d271caShenning 37389d271caShenning do { 37489d271caShenning n = writev(sd, iov, iov_cnt); 37589d271caShenning } while (n == -1 && (errno == EAGAIN || errno == EINTR)); 37689d271caShenning if (n == -1) { 377f484f2cfShshoexer warn("writev failed"); 378f484f2cfShshoexer ret = -1; 379f484f2cfShshoexer } 380f484f2cfShshoexer 381f484f2cfShshoexer if (sa_srcid) 382f484f2cfShshoexer free(sa_srcid); 383f484f2cfShshoexer if (sa_dstid) 384f484f2cfShshoexer free(sa_dstid); 385f484f2cfShshoexer 386f484f2cfShshoexer return ret; 387f484f2cfShshoexer } 388f484f2cfShshoexer 389f484f2cfShshoexer static int 39091f765ddShshoexer pfkey_sa(int sd, u_int8_t satype, u_int8_t action, u_int32_t spi, 39191f765ddShshoexer struct ipsec_addr_wrap *src, struct ipsec_addr_wrap *dst, 39291f765ddShshoexer struct ipsec_transforms *xfs, struct ipsec_key *authkey, 393a38d220fShshoexer struct ipsec_key *enckey, u_int8_t tmode) 394f032086dShshoexer { 395f032086dShshoexer struct sadb_msg smsg; 396f032086dShshoexer struct sadb_sa sa; 397f032086dShshoexer struct sadb_address sa_src, sa_dst; 398881e2068Shshoexer struct sadb_key sa_authkey, sa_enckey; 399f032086dShshoexer struct sockaddr_storage ssrc, sdst; 400f032086dShshoexer struct iovec iov[IOV_CNT]; 401f032086dShshoexer ssize_t n; 402f032086dShshoexer int iov_cnt, len, ret = 0; 403f032086dShshoexer 404f032086dShshoexer bzero(&ssrc, sizeof(ssrc)); 4052099bcdfStodd ssrc.ss_family = src->af; 406f032086dShshoexer switch (src->af) { 407f032086dShshoexer case AF_INET: 408712e78baShshoexer ((struct sockaddr_in *)&ssrc)->sin_addr = src->address.v4; 409f032086dShshoexer ssrc.ss_len = sizeof(struct sockaddr_in); 410f032086dShshoexer break; 411f032086dShshoexer case AF_INET6: 4122099bcdfStodd ((struct sockaddr_in6 *)&ssrc)->sin6_addr = src->address.v6; 4132099bcdfStodd ssrc.ss_len = sizeof(struct sockaddr_in6); 4142099bcdfStodd break; 415f032086dShshoexer default: 416f032086dShshoexer warnx("unsupported address family %d", src->af); 417f032086dShshoexer return -1; 418f032086dShshoexer } 419f032086dShshoexer 420f032086dShshoexer bzero(&sdst, sizeof(sdst)); 4212099bcdfStodd sdst.ss_family = dst->af; 422f032086dShshoexer switch (dst->af) { 423f032086dShshoexer case AF_INET: 424712e78baShshoexer ((struct sockaddr_in *)&sdst)->sin_addr = dst->address.v4; 425f032086dShshoexer sdst.ss_len = sizeof(struct sockaddr_in); 426f032086dShshoexer break; 427f032086dShshoexer case AF_INET6: 4282099bcdfStodd ((struct sockaddr_in6 *)&sdst)->sin6_addr = dst->address.v6; 4292099bcdfStodd sdst.ss_len = sizeof(struct sockaddr_in6); 4302099bcdfStodd break; 431f032086dShshoexer default: 432f032086dShshoexer warnx("unsupported address family %d", dst->af); 433f032086dShshoexer return -1; 434f032086dShshoexer } 435f032086dShshoexer 436f032086dShshoexer bzero(&smsg, sizeof(smsg)); 437f032086dShshoexer smsg.sadb_msg_version = PF_KEY_V2; 438f032086dShshoexer smsg.sadb_msg_seq = sadb_msg_seq++; 439f032086dShshoexer smsg.sadb_msg_pid = getpid(); 440f032086dShshoexer smsg.sadb_msg_len = sizeof(smsg) / 8; 441f032086dShshoexer smsg.sadb_msg_type = action; 442f032086dShshoexer smsg.sadb_msg_satype = satype; 443f032086dShshoexer 444f032086dShshoexer bzero(&sa, sizeof(sa)); 445f032086dShshoexer sa.sadb_sa_len = sizeof(sa) / 8; 446f032086dShshoexer sa.sadb_sa_exttype = SADB_EXT_SA; 447f032086dShshoexer sa.sadb_sa_spi = htonl(spi); 448f032086dShshoexer sa.sadb_sa_state = SADB_SASTATE_MATURE; 449f032086dShshoexer 45088a8cceeSmarkus if (satype != SADB_X_SATYPE_IPIP && tmode == IPSEC_TUNNEL) 451a38d220fShshoexer sa.sadb_sa_flags |= SADB_X_SAFLAGS_TUNNEL; 452a38d220fShshoexer 453375db29dShshoexer if (xfs && xfs->authxf) { 454375db29dShshoexer switch (xfs->authxf->id) { 455881e2068Shshoexer case AUTHXF_NONE: 456881e2068Shshoexer break; 457881e2068Shshoexer case AUTHXF_HMAC_MD5: 458881e2068Shshoexer sa.sadb_sa_auth = SADB_AALG_MD5HMAC; 459881e2068Shshoexer break; 460881e2068Shshoexer case AUTHXF_HMAC_RIPEMD160: 461881e2068Shshoexer sa.sadb_sa_auth = SADB_X_AALG_RIPEMD160HMAC; 462881e2068Shshoexer break; 463881e2068Shshoexer case AUTHXF_HMAC_SHA1: 464881e2068Shshoexer sa.sadb_sa_auth = SADB_AALG_SHA1HMAC; 465881e2068Shshoexer break; 466881e2068Shshoexer case AUTHXF_HMAC_SHA2_256: 467881e2068Shshoexer sa.sadb_sa_auth = SADB_X_AALG_SHA2_256; 468881e2068Shshoexer break; 469881e2068Shshoexer case AUTHXF_HMAC_SHA2_384: 470881e2068Shshoexer sa.sadb_sa_auth = SADB_X_AALG_SHA2_384; 471881e2068Shshoexer break; 472881e2068Shshoexer case AUTHXF_HMAC_SHA2_512: 473881e2068Shshoexer sa.sadb_sa_auth = SADB_X_AALG_SHA2_512; 474881e2068Shshoexer break; 475881e2068Shshoexer default: 476881e2068Shshoexer warnx("unsupported authentication algorithm %d", 477375db29dShshoexer xfs->authxf->id); 478881e2068Shshoexer } 479881e2068Shshoexer } 480375db29dShshoexer if (xfs && xfs->encxf) { 481375db29dShshoexer switch (xfs->encxf->id) { 482881e2068Shshoexer case ENCXF_NONE: 483881e2068Shshoexer break; 484881e2068Shshoexer case ENCXF_3DES_CBC: 485881e2068Shshoexer sa.sadb_sa_encrypt = SADB_EALG_3DESCBC; 486881e2068Shshoexer break; 487881e2068Shshoexer case ENCXF_DES_CBC: 488881e2068Shshoexer sa.sadb_sa_encrypt = SADB_EALG_DESCBC; 489881e2068Shshoexer break; 490881e2068Shshoexer case ENCXF_AES: 491881e2068Shshoexer sa.sadb_sa_encrypt = SADB_X_EALG_AES; 492881e2068Shshoexer break; 493881e2068Shshoexer case ENCXF_AESCTR: 494881e2068Shshoexer sa.sadb_sa_encrypt = SADB_X_EALG_AESCTR; 495881e2068Shshoexer break; 496881e2068Shshoexer case ENCXF_BLOWFISH: 497881e2068Shshoexer sa.sadb_sa_encrypt = SADB_X_EALG_BLF; 498881e2068Shshoexer break; 499881e2068Shshoexer case ENCXF_CAST128: 500881e2068Shshoexer sa.sadb_sa_encrypt = SADB_X_EALG_CAST; 501881e2068Shshoexer break; 502881e2068Shshoexer case ENCXF_NULL: 503881e2068Shshoexer sa.sadb_sa_encrypt = SADB_EALG_NULL; 504881e2068Shshoexer break; 505881e2068Shshoexer case ENCXF_SKIPJACK: 506881e2068Shshoexer sa.sadb_sa_encrypt = SADB_X_EALG_SKIPJACK; 507881e2068Shshoexer break; 508881e2068Shshoexer default: 509375db29dShshoexer warnx("unsupported encryption algorithm %d", 510375db29dShshoexer xfs->encxf->id); 511881e2068Shshoexer } 512881e2068Shshoexer } 51372e25333Shshoexer if (xfs && xfs->compxf) { 51472e25333Shshoexer switch (xfs->compxf->id) { 51572e25333Shshoexer case COMPXF_DEFLATE: 51672e25333Shshoexer sa.sadb_sa_encrypt = SADB_X_CALG_DEFLATE; 51772e25333Shshoexer break; 51872e25333Shshoexer case COMPXF_LZS: 51972e25333Shshoexer sa.sadb_sa_encrypt = SADB_X_CALG_LZS; 52072e25333Shshoexer break; 52172e25333Shshoexer default: 52272e25333Shshoexer warnx("unsupported compression algorithm %d", 52372e25333Shshoexer xfs->compxf->id); 52472e25333Shshoexer } 52572e25333Shshoexer } 526881e2068Shshoexer 527f032086dShshoexer bzero(&sa_src, sizeof(sa_src)); 528f032086dShshoexer sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(ssrc.ss_len)) / 8; 529f032086dShshoexer sa_src.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; 530f032086dShshoexer 531f032086dShshoexer bzero(&sa_dst, sizeof(sa_dst)); 532f032086dShshoexer sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(sdst.ss_len)) / 8; 533f032086dShshoexer sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST; 534f032086dShshoexer 53572e25333Shshoexer if (action == SADB_ADD && !authkey && !enckey && satype != 53688a8cceeSmarkus SADB_X_SATYPE_IPCOMP && satype != SADB_X_SATYPE_IPIP) { /* XXX ENCNULL */ 5370813ab45Shshoexer warnx("no key specified"); 5380813ab45Shshoexer return -1; 5390813ab45Shshoexer } 540881e2068Shshoexer if (authkey) { 541881e2068Shshoexer bzero(&sa_authkey, sizeof(sa_authkey)); 542881e2068Shshoexer sa_authkey.sadb_key_len = (sizeof(sa_authkey) + 543881e2068Shshoexer ((authkey->len + 7) / 8) * 8) / 8; 544881e2068Shshoexer sa_authkey.sadb_key_exttype = SADB_EXT_KEY_AUTH; 545881e2068Shshoexer sa_authkey.sadb_key_bits = 8 * authkey->len; 546881e2068Shshoexer } 547881e2068Shshoexer if (enckey) { 548881e2068Shshoexer bzero(&sa_enckey, sizeof(sa_enckey)); 549881e2068Shshoexer sa_enckey.sadb_key_len = (sizeof(sa_enckey) + 550881e2068Shshoexer ((enckey->len + 7) / 8) * 8) / 8; 551881e2068Shshoexer sa_enckey.sadb_key_exttype = SADB_EXT_KEY_ENCRYPT; 552881e2068Shshoexer sa_enckey.sadb_key_bits = 8 * enckey->len; 553f032086dShshoexer } 554f032086dShshoexer 555f032086dShshoexer iov_cnt = 0; 556f032086dShshoexer 557f032086dShshoexer /* header */ 558f032086dShshoexer iov[iov_cnt].iov_base = &smsg; 559f032086dShshoexer iov[iov_cnt].iov_len = sizeof(smsg); 560f032086dShshoexer iov_cnt++; 561f032086dShshoexer 562f032086dShshoexer /* sa */ 563f032086dShshoexer iov[iov_cnt].iov_base = &sa; 564f032086dShshoexer iov[iov_cnt].iov_len = sizeof(sa); 565f032086dShshoexer smsg.sadb_msg_len += sa.sadb_sa_len; 566f032086dShshoexer iov_cnt++; 567f032086dShshoexer 568f032086dShshoexer /* src addr */ 569f032086dShshoexer iov[iov_cnt].iov_base = &sa_src; 570f032086dShshoexer iov[iov_cnt].iov_len = sizeof(sa_src); 571f032086dShshoexer iov_cnt++; 572f032086dShshoexer iov[iov_cnt].iov_base = &ssrc; 573f032086dShshoexer iov[iov_cnt].iov_len = ROUNDUP(ssrc.ss_len); 574f032086dShshoexer smsg.sadb_msg_len += sa_src.sadb_address_len; 575f032086dShshoexer iov_cnt++; 576f032086dShshoexer 577f032086dShshoexer /* dst addr */ 578f032086dShshoexer iov[iov_cnt].iov_base = &sa_dst; 579f032086dShshoexer iov[iov_cnt].iov_len = sizeof(sa_dst); 580f032086dShshoexer iov_cnt++; 581f032086dShshoexer iov[iov_cnt].iov_base = &sdst; 582f032086dShshoexer iov[iov_cnt].iov_len = ROUNDUP(sdst.ss_len); 583f032086dShshoexer smsg.sadb_msg_len += sa_dst.sadb_address_len; 584f032086dShshoexer iov_cnt++; 585f032086dShshoexer 586881e2068Shshoexer if (authkey) { 587881e2068Shshoexer /* authentication key */ 588881e2068Shshoexer iov[iov_cnt].iov_base = &sa_authkey; 589881e2068Shshoexer iov[iov_cnt].iov_len = sizeof(sa_authkey); 590f032086dShshoexer iov_cnt++; 591881e2068Shshoexer iov[iov_cnt].iov_base = authkey->data; 592881e2068Shshoexer iov[iov_cnt].iov_len = ((authkey->len + 7) / 8) * 8; 593881e2068Shshoexer smsg.sadb_msg_len += sa_authkey.sadb_key_len; 594881e2068Shshoexer iov_cnt++; 595881e2068Shshoexer } 596881e2068Shshoexer if (enckey) { 597881e2068Shshoexer /* encryption key */ 598881e2068Shshoexer iov[iov_cnt].iov_base = &sa_enckey; 599881e2068Shshoexer iov[iov_cnt].iov_len = sizeof(sa_enckey); 600881e2068Shshoexer iov_cnt++; 601881e2068Shshoexer iov[iov_cnt].iov_base = enckey->data; 602881e2068Shshoexer iov[iov_cnt].iov_len = ((enckey->len + 7) / 8) * 8; 603881e2068Shshoexer smsg.sadb_msg_len += sa_enckey.sadb_key_len; 604f032086dShshoexer iov_cnt++; 605f032086dShshoexer } 606f032086dShshoexer 607f032086dShshoexer len = smsg.sadb_msg_len * 8; 608f032086dShshoexer if ((n = writev(sd, iov, iov_cnt)) == -1) { 609f032086dShshoexer warn("writev failed"); 610f032086dShshoexer ret = -1; 611f032086dShshoexer } else if (n != len) { 612f032086dShshoexer warnx("short write"); 613f032086dShshoexer ret = -1; 614f032086dShshoexer } 615f032086dShshoexer 616f032086dShshoexer return ret; 617f032086dShshoexer } 618f032086dShshoexer 619f032086dShshoexer static int 6208065703bShshoexer pfkey_sagroup(int sd, u_int8_t satype, u_int8_t satype2, u_int8_t action, 6218065703bShshoexer struct ipsec_addr_wrap *dst, u_int32_t spi, struct ipsec_addr_wrap *dst2, 6228065703bShshoexer u_int32_t spi2) 6238f2109caShshoexer { 6248f2109caShshoexer struct sadb_msg smsg; 6258f2109caShshoexer struct sadb_sa sa1, sa2; 6268f2109caShshoexer struct sadb_address sa_dst, sa_dst2; 6278f2109caShshoexer struct sockaddr_storage sdst, sdst2; 6288f2109caShshoexer struct sadb_protocol sa_proto; 6298f2109caShshoexer struct iovec iov[IOV_CNT]; 6308f2109caShshoexer ssize_t n; 6318f2109caShshoexer int iov_cnt, len, ret = 0; 6328f2109caShshoexer 6338f2109caShshoexer bzero(&sdst, sizeof(sdst)); 6348f2109caShshoexer sdst.ss_family = dst->af; 6358f2109caShshoexer switch (dst->af) { 6368f2109caShshoexer case AF_INET: 6378f2109caShshoexer ((struct sockaddr_in *)&sdst)->sin_addr = dst->address.v4; 6388f2109caShshoexer sdst.ss_len = sizeof(struct sockaddr_in); 6398f2109caShshoexer break; 6408f2109caShshoexer case AF_INET6: 6418f2109caShshoexer ((struct sockaddr_in6 *)&sdst)->sin6_addr = dst->address.v6; 6428f2109caShshoexer sdst.ss_len = sizeof(struct sockaddr_in6); 6438f2109caShshoexer break; 6448f2109caShshoexer default: 6458f2109caShshoexer warnx("unsupported address family %d", dst->af); 6468f2109caShshoexer return -1; 6478f2109caShshoexer } 6488f2109caShshoexer 6498f2109caShshoexer bzero(&sdst2, sizeof(sdst2)); 6508f2109caShshoexer sdst2.ss_family = dst2->af; 6518f2109caShshoexer switch (dst2->af) { 6528f2109caShshoexer case AF_INET: 6538f2109caShshoexer ((struct sockaddr_in *)&sdst2)->sin_addr = dst2->address.v4; 6548f2109caShshoexer sdst2.ss_len = sizeof(struct sockaddr_in); 6558f2109caShshoexer break; 6568f2109caShshoexer case AF_INET6: 6578f2109caShshoexer ((struct sockaddr_in6 *)&sdst2)->sin6_addr = dst2->address.v6; 6588f2109caShshoexer sdst2.ss_len = sizeof(struct sockaddr_in6); 6598f2109caShshoexer break; 6608f2109caShshoexer default: 6618f2109caShshoexer warnx("unsupported address family %d", dst2->af); 6628f2109caShshoexer return -1; 6638f2109caShshoexer } 6648f2109caShshoexer 6658f2109caShshoexer bzero(&smsg, sizeof(smsg)); 6668f2109caShshoexer smsg.sadb_msg_version = PF_KEY_V2; 6678f2109caShshoexer smsg.sadb_msg_seq = sadb_msg_seq++; 6688f2109caShshoexer smsg.sadb_msg_pid = getpid(); 6698f2109caShshoexer smsg.sadb_msg_len = sizeof(smsg) / 8; 6708f2109caShshoexer smsg.sadb_msg_type = action; 6718f2109caShshoexer smsg.sadb_msg_satype = satype; 6728f2109caShshoexer 6738f2109caShshoexer bzero(&sa1, sizeof(sa1)); 6748f2109caShshoexer sa1.sadb_sa_len = sizeof(sa1) / 8; 6758f2109caShshoexer sa1.sadb_sa_exttype = SADB_EXT_SA; 6768f2109caShshoexer sa1.sadb_sa_spi = htonl(spi); 6778f2109caShshoexer sa1.sadb_sa_state = SADB_SASTATE_MATURE; 6788f2109caShshoexer 6798f2109caShshoexer bzero(&sa2, sizeof(sa2)); 6808f2109caShshoexer sa2.sadb_sa_len = sizeof(sa2) / 8; 6818f2109caShshoexer sa2.sadb_sa_exttype = SADB_X_EXT_SA2; 6828f2109caShshoexer sa2.sadb_sa_spi = htonl(spi2); 6838f2109caShshoexer sa2.sadb_sa_state = SADB_SASTATE_MATURE; 6848f2109caShshoexer iov_cnt = 0; 6858f2109caShshoexer 6868f2109caShshoexer bzero(&sa_dst, sizeof(sa_dst)); 6878f2109caShshoexer sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST; 6888f2109caShshoexer sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(sdst.ss_len)) / 8; 6898f2109caShshoexer 6908f2109caShshoexer bzero(&sa_dst2, sizeof(sa_dst2)); 6918f2109caShshoexer sa_dst2.sadb_address_exttype = SADB_X_EXT_DST2; 6928f2109caShshoexer sa_dst2.sadb_address_len = (sizeof(sa_dst2) + ROUNDUP(sdst2.ss_len)) / 8; 6938f2109caShshoexer 6948f2109caShshoexer bzero(&sa_proto, sizeof(sa_proto)); 6958f2109caShshoexer sa_proto.sadb_protocol_exttype = SADB_X_EXT_PROTOCOL; 6968f2109caShshoexer sa_proto.sadb_protocol_len = sizeof(sa_proto) / 8; 6978f2109caShshoexer sa_proto.sadb_protocol_direction = 0; 6988065703bShshoexer sa_proto.sadb_protocol_proto = satype2; 6998f2109caShshoexer 7008f2109caShshoexer /* header */ 7018f2109caShshoexer iov[iov_cnt].iov_base = &smsg; 7028f2109caShshoexer iov[iov_cnt].iov_len = sizeof(smsg); 7038f2109caShshoexer iov_cnt++; 7048f2109caShshoexer 7058f2109caShshoexer /* sa */ 7068f2109caShshoexer iov[iov_cnt].iov_base = &sa1; 7078f2109caShshoexer iov[iov_cnt].iov_len = sizeof(sa1); 7088f2109caShshoexer smsg.sadb_msg_len += sa1.sadb_sa_len; 7098f2109caShshoexer iov_cnt++; 7108f2109caShshoexer 7118f2109caShshoexer /* dst addr */ 7128f2109caShshoexer iov[iov_cnt].iov_base = &sa_dst; 7138f2109caShshoexer iov[iov_cnt].iov_len = sizeof(sa_dst); 7148f2109caShshoexer iov_cnt++; 7158f2109caShshoexer iov[iov_cnt].iov_base = &sdst; 7168f2109caShshoexer iov[iov_cnt].iov_len = ROUNDUP(sdst.ss_len); 7178f2109caShshoexer smsg.sadb_msg_len += sa_dst.sadb_address_len; 7188f2109caShshoexer iov_cnt++; 7198f2109caShshoexer 7208f2109caShshoexer /* second sa */ 7218f2109caShshoexer iov[iov_cnt].iov_base = &sa2; 7228f2109caShshoexer iov[iov_cnt].iov_len = sizeof(sa2); 7238f2109caShshoexer smsg.sadb_msg_len += sa2.sadb_sa_len; 7248f2109caShshoexer iov_cnt++; 7258f2109caShshoexer 7268f2109caShshoexer /* second dst addr */ 7278f2109caShshoexer iov[iov_cnt].iov_base = &sa_dst2; 7288f2109caShshoexer iov[iov_cnt].iov_len = sizeof(sa_dst2); 7298f2109caShshoexer iov_cnt++; 7308f2109caShshoexer iov[iov_cnt].iov_base = &sdst2; 7318f2109caShshoexer iov[iov_cnt].iov_len = ROUNDUP(sdst2.ss_len); 7328f2109caShshoexer smsg.sadb_msg_len += sa_dst2.sadb_address_len; 7338f2109caShshoexer iov_cnt++; 7348f2109caShshoexer 7358f2109caShshoexer /* SA type */ 7368f2109caShshoexer iov[iov_cnt].iov_base = &sa_proto; 7378f2109caShshoexer iov[iov_cnt].iov_len = sizeof(sa_proto); 7388f2109caShshoexer smsg.sadb_msg_len += sa_proto.sadb_protocol_len; 7398f2109caShshoexer iov_cnt++; 7408f2109caShshoexer 7418f2109caShshoexer len = smsg.sadb_msg_len * 8; 7428f2109caShshoexer if ((n = writev(sd, iov, iov_cnt)) == -1) { 7438f2109caShshoexer warn("writev failed"); 7448f2109caShshoexer ret = -1; 7458f2109caShshoexer } else if (n != len) { 7468f2109caShshoexer warnx("short write"); 7478f2109caShshoexer ret = -1; 7488f2109caShshoexer } 7498f2109caShshoexer 7508f2109caShshoexer return (ret); 7518f2109caShshoexer } 7528f2109caShshoexer 7538f2109caShshoexer static int 7548a87fca6Smsf pfkey_reply(int sd, u_int8_t **datap, ssize_t *lenp) 755f484f2cfShshoexer { 756f484f2cfShshoexer struct sadb_msg hdr; 757f484f2cfShshoexer ssize_t len; 758f484f2cfShshoexer u_int8_t *data; 759f484f2cfShshoexer 760f484f2cfShshoexer if (recv(sd, &hdr, sizeof(hdr), MSG_PEEK) != sizeof(hdr)) { 761f484f2cfShshoexer warnx("short read"); 762f484f2cfShshoexer return -1; 763f484f2cfShshoexer } 764f484f2cfShshoexer len = hdr.sadb_msg_len * PFKEYV2_CHUNK; 765f484f2cfShshoexer if ((data = malloc(len)) == NULL) 766bd828a90Shshoexer err(1, "pfkey_reply: malloc"); 767f484f2cfShshoexer if (read(sd, data, len) != len) { 768f484f2cfShshoexer warn("PF_KEY short read"); 769f484f2cfShshoexer bzero(data, len); 770f484f2cfShshoexer free(data); 771f484f2cfShshoexer return -1; 772f484f2cfShshoexer } 7738a87fca6Smsf if (datap) { 7748a87fca6Smsf *datap = data; 7758a87fca6Smsf if (lenp) 7768a87fca6Smsf *lenp = len; 7778a87fca6Smsf } else { 778f484f2cfShshoexer bzero(data, len); 779f484f2cfShshoexer free(data); 7808a87fca6Smsf } 781011122f7Smarkus if (datap == NULL && hdr.sadb_msg_errno != 0) { 782011122f7Smarkus errno = hdr.sadb_msg_errno; 783*92270c32Shshoexer if (errno != EEXIST) { 784011122f7Smarkus warn("PF_KEY failed"); 785011122f7Smarkus return -1; 786011122f7Smarkus } 787*92270c32Shshoexer } 788f484f2cfShshoexer return 0; 789f484f2cfShshoexer } 790f484f2cfShshoexer 791f484f2cfShshoexer int 7921edc1b9aShshoexer pfkey_parse(struct sadb_msg *msg, struct ipsec_rule *rule) 7931edc1b9aShshoexer { 7941edc1b9aShshoexer struct sadb_ext *ext; 7951edc1b9aShshoexer struct sadb_address *saddr; 7961edc1b9aShshoexer struct sadb_protocol *sproto; 7971edc1b9aShshoexer struct sadb_ident *sident; 7981edc1b9aShshoexer struct sockaddr *sa; 799712e78baShshoexer struct sockaddr_in *sa_in; 8002099bcdfStodd struct sockaddr_in6 *sa_in6; 8011edc1b9aShshoexer int len; 8021edc1b9aShshoexer 8031edc1b9aShshoexer switch (msg->sadb_msg_satype) { 804b26a6cb5Shshoexer case SADB_SATYPE_ESP: 8059182219dSmarkus rule->satype = IPSEC_ESP; 8061edc1b9aShshoexer break; 807b26a6cb5Shshoexer case SADB_SATYPE_AH: 8089182219dSmarkus rule->satype = IPSEC_AH; 8091edc1b9aShshoexer break; 810b26a6cb5Shshoexer case SADB_X_SATYPE_IPCOMP: 8119182219dSmarkus rule->satype = IPSEC_IPCOMP; 812a29da9d0Shshoexer break; 81388a8cceeSmarkus case SADB_X_SATYPE_IPIP: 8149182219dSmarkus rule->satype = IPSEC_IPIP; 81588a8cceeSmarkus break; 8161edc1b9aShshoexer default: 8171edc1b9aShshoexer return (1); 8181edc1b9aShshoexer } 8191edc1b9aShshoexer 8201edc1b9aShshoexer for (ext = (struct sadb_ext *)(msg + 1); 8211edc1b9aShshoexer (size_t)((u_int8_t *)ext - (u_int8_t *)msg) < 822d5d1799eShshoexer msg->sadb_msg_len * PFKEYV2_CHUNK && ext->sadb_ext_len > 0; 8231edc1b9aShshoexer ext = (struct sadb_ext *)((u_int8_t *)ext + 8241edc1b9aShshoexer ext->sadb_ext_len * PFKEYV2_CHUNK)) { 8251edc1b9aShshoexer switch (ext->sadb_ext_type) { 8261edc1b9aShshoexer case SADB_EXT_ADDRESS_SRC: 8271edc1b9aShshoexer saddr = (struct sadb_address *)ext; 8281edc1b9aShshoexer sa = (struct sockaddr *)(saddr + 1); 8291edc1b9aShshoexer 83091f765ddShshoexer rule->local = calloc(1, sizeof(struct ipsec_addr_wrap)); 831d5d1799eShshoexer if (rule->local == NULL) 832a1059f6aStodd err(1, "pfkey_parse: calloc"); 8331edc1b9aShshoexer 8342099bcdfStodd rule->local->af = sa->sa_family; 8351edc1b9aShshoexer switch (sa->sa_family) { 8361edc1b9aShshoexer case AF_INET: 8371edc1b9aShshoexer bcopy(&((struct sockaddr_in *)sa)->sin_addr, 83891f765ddShshoexer &rule->local->address.v4, 839712e78baShshoexer sizeof(struct in_addr)); 8402099bcdfStodd set_ipmask(rule->local, 32); 8412099bcdfStodd break; 8422099bcdfStodd case AF_INET6: 8432099bcdfStodd bcopy(&((struct sockaddr_in6 *)sa)->sin6_addr, 8442099bcdfStodd &rule->local->address.v6, 8452099bcdfStodd sizeof(struct in6_addr)); 8462099bcdfStodd set_ipmask(rule->local, 128); 8471edc1b9aShshoexer break; 8481edc1b9aShshoexer default: 8491edc1b9aShshoexer return (1); 8501edc1b9aShshoexer } 8511edc1b9aShshoexer break; 8521edc1b9aShshoexer 8531edc1b9aShshoexer 8541edc1b9aShshoexer case SADB_EXT_ADDRESS_DST: 8551edc1b9aShshoexer saddr = (struct sadb_address *)ext; 8561edc1b9aShshoexer sa = (struct sockaddr *)(saddr + 1); 8571edc1b9aShshoexer 85891f765ddShshoexer rule->peer = calloc(1, sizeof(struct ipsec_addr_wrap)); 8591edc1b9aShshoexer if (rule->peer == NULL) 860a1059f6aStodd err(1, "pfkey_parse: calloc"); 8611edc1b9aShshoexer 8622099bcdfStodd rule->peer->af = sa->sa_family; 8631edc1b9aShshoexer switch (sa->sa_family) { 8641edc1b9aShshoexer case AF_INET: 8651edc1b9aShshoexer bcopy(&((struct sockaddr_in *)sa)->sin_addr, 866712e78baShshoexer &rule->peer->address.v4, 867712e78baShshoexer sizeof(struct in_addr)); 8682099bcdfStodd set_ipmask(rule->peer, 32); 8692099bcdfStodd break; 8702099bcdfStodd case AF_INET6: 8712099bcdfStodd bcopy(&((struct sockaddr_in6 *)sa)->sin6_addr, 8722099bcdfStodd &rule->peer->address.v6, 8732099bcdfStodd sizeof(struct in6_addr)); 8742099bcdfStodd set_ipmask(rule->peer, 128); 8751edc1b9aShshoexer break; 8761edc1b9aShshoexer default: 8771edc1b9aShshoexer return (1); 8781edc1b9aShshoexer } 8791edc1b9aShshoexer break; 8801edc1b9aShshoexer 8811edc1b9aShshoexer case SADB_EXT_IDENTITY_SRC: 8821edc1b9aShshoexer sident = (struct sadb_ident *)ext; 8831edc1b9aShshoexer len = (sident->sadb_ident_len * sizeof(uint64_t)) - 8841edc1b9aShshoexer sizeof(struct sadb_ident); 8851edc1b9aShshoexer 8869382ed8fShshoexer if (rule->auth == NULL) { 8879382ed8fShshoexer rule->auth = calloc(1, sizeof(struct 8889382ed8fShshoexer ipsec_auth)); 8899382ed8fShshoexer if (rule->auth == NULL) 890bd828a90Shshoexer err(1, "pfkey_parse: calloc"); 8919382ed8fShshoexer } 8929382ed8fShshoexer 893abe65127Shshoexer rule->auth->srcid = calloc(1, len); 894abe65127Shshoexer if (rule->auth->srcid == NULL) 895bd828a90Shshoexer err(1, "pfkey_parse: calloc"); 8961edc1b9aShshoexer 897abe65127Shshoexer strlcpy(rule->auth->srcid, (char *)(sident + 1), len); 8981edc1b9aShshoexer break; 8991edc1b9aShshoexer 9001edc1b9aShshoexer case SADB_EXT_IDENTITY_DST: 9011edc1b9aShshoexer sident = (struct sadb_ident *)ext; 9021edc1b9aShshoexer len = (sident->sadb_ident_len * sizeof(uint64_t)) - 9031edc1b9aShshoexer sizeof(struct sadb_ident); 9041edc1b9aShshoexer 9059382ed8fShshoexer if (rule->auth == NULL) { 9069382ed8fShshoexer rule->auth = calloc(1, sizeof(struct 9079382ed8fShshoexer ipsec_auth)); 9089382ed8fShshoexer if (rule->auth == NULL) 909bd828a90Shshoexer err(1, "pfkey_parse: calloc"); 9109382ed8fShshoexer } 9119382ed8fShshoexer 912abe65127Shshoexer rule->auth->dstid = calloc(1, len); 913abe65127Shshoexer if (rule->auth->dstid == NULL) 914bd828a90Shshoexer err(1, "pfkey_parse: calloc"); 9151edc1b9aShshoexer 916abe65127Shshoexer strlcpy(rule->auth->dstid, (char *)(sident + 1), len); 9171edc1b9aShshoexer break; 9181edc1b9aShshoexer 9191edc1b9aShshoexer case SADB_X_EXT_PROTOCOL: 9209182219dSmarkus sproto = (struct sadb_protocol *)ext; 9219182219dSmarkus if (sproto->sadb_protocol_direction == 0) 9229182219dSmarkus rule->proto = sproto->sadb_protocol_proto; 9231edc1b9aShshoexer break; 9241edc1b9aShshoexer 9251edc1b9aShshoexer case SADB_X_EXT_FLOW_TYPE: 9261edc1b9aShshoexer sproto = (struct sadb_protocol *)ext; 9271edc1b9aShshoexer 9281edc1b9aShshoexer switch (sproto->sadb_protocol_direction) { 9291edc1b9aShshoexer case IPSP_DIRECTION_IN: 9301edc1b9aShshoexer rule->direction = IPSEC_IN; 9311edc1b9aShshoexer break; 9321edc1b9aShshoexer case IPSP_DIRECTION_OUT: 9331edc1b9aShshoexer rule->direction = IPSEC_OUT; 9341edc1b9aShshoexer break; 9351edc1b9aShshoexer default: 9361edc1b9aShshoexer return (1); 9371edc1b9aShshoexer } 9386122c05eShshoexer switch (sproto->sadb_protocol_proto) { 9396122c05eShshoexer case SADB_X_FLOW_TYPE_USE: 9401a3f035aShshoexer rule->flowtype = TYPE_USE; 9416122c05eShshoexer break; 9426122c05eShshoexer case SADB_X_FLOW_TYPE_ACQUIRE: 9431a3f035aShshoexer rule->flowtype = TYPE_ACQUIRE; 9446122c05eShshoexer break; 9456122c05eShshoexer case SADB_X_FLOW_TYPE_REQUIRE: 9461a3f035aShshoexer rule->flowtype = TYPE_REQUIRE; 9476122c05eShshoexer break; 9486122c05eShshoexer case SADB_X_FLOW_TYPE_DENY: 9491a3f035aShshoexer rule->flowtype = TYPE_DENY; 9506122c05eShshoexer break; 9516122c05eShshoexer case SADB_X_FLOW_TYPE_BYPASS: 9521a3f035aShshoexer rule->flowtype = TYPE_BYPASS; 9536122c05eShshoexer break; 9546122c05eShshoexer case SADB_X_FLOW_TYPE_DONTACQ: 9551a3f035aShshoexer rule->flowtype = TYPE_DONTACQ; 9566122c05eShshoexer break; 9576122c05eShshoexer default: 9581a3f035aShshoexer rule->flowtype = TYPE_UNKNOWN; 9596122c05eShshoexer break; 9606122c05eShshoexer } 9611edc1b9aShshoexer break; 9621edc1b9aShshoexer 9631edc1b9aShshoexer case SADB_X_EXT_SRC_FLOW: 9641edc1b9aShshoexer saddr = (struct sadb_address *)ext; 9651edc1b9aShshoexer sa = (struct sockaddr *)(saddr + 1); 9661edc1b9aShshoexer 9671edc1b9aShshoexer if (rule->src == NULL) { 9681edc1b9aShshoexer rule->src = calloc(1, 96991f765ddShshoexer sizeof(struct ipsec_addr_wrap)); 9701edc1b9aShshoexer if (rule->src == NULL) 971bd828a90Shshoexer err(1, "pfkey_parse: calloc"); 9721edc1b9aShshoexer } 9731edc1b9aShshoexer 9742099bcdfStodd rule->src->af = sa->sa_family; 9751edc1b9aShshoexer switch (sa->sa_family) { 9761edc1b9aShshoexer case AF_INET: 9771edc1b9aShshoexer bcopy(&((struct sockaddr_in *)sa)->sin_addr, 978712e78baShshoexer &rule->src->address.v4, 979712e78baShshoexer sizeof(struct in_addr)); 98057f58d0dSnaddy rule->sport = 98157f58d0dSnaddy ((struct sockaddr_in *)sa)->sin_port; 9822099bcdfStodd break; 9832099bcdfStodd case AF_INET6: 9842099bcdfStodd bcopy(&((struct sockaddr_in6 *)sa)->sin6_addr, 9852099bcdfStodd &rule->src->address.v6, 9862099bcdfStodd sizeof(struct in6_addr)); 98757f58d0dSnaddy rule->sport = 98857f58d0dSnaddy ((struct sockaddr_in6 *)sa)->sin6_port; 9891edc1b9aShshoexer break; 9901edc1b9aShshoexer default: 9911edc1b9aShshoexer return (1); 9921edc1b9aShshoexer } 9931edc1b9aShshoexer break; 9941edc1b9aShshoexer 9951edc1b9aShshoexer case SADB_X_EXT_DST_FLOW: 9961edc1b9aShshoexer saddr = (struct sadb_address *)ext; 9971edc1b9aShshoexer sa = (struct sockaddr *)(saddr + 1); 9981edc1b9aShshoexer 9991edc1b9aShshoexer if (rule->dst == NULL) { 10001edc1b9aShshoexer rule->dst = calloc(1, 100191f765ddShshoexer sizeof(struct ipsec_addr_wrap)); 10021edc1b9aShshoexer if (rule->dst == NULL) 1003bd828a90Shshoexer err(1, "pfkey_parse: calloc"); 10041edc1b9aShshoexer } 10051edc1b9aShshoexer 10062099bcdfStodd rule->dst->af = sa->sa_family; 10071edc1b9aShshoexer switch (sa->sa_family) { 10081edc1b9aShshoexer case AF_INET: 10091edc1b9aShshoexer bcopy(&((struct sockaddr_in *)sa)->sin_addr, 1010712e78baShshoexer &rule->dst->address.v4, 1011712e78baShshoexer sizeof(struct in_addr)); 101257f58d0dSnaddy rule->dport = 101357f58d0dSnaddy ((struct sockaddr_in *)sa)->sin_port; 10141edc1b9aShshoexer break; 10152099bcdfStodd case AF_INET6: 10162099bcdfStodd bcopy(&((struct sockaddr_in6 *)sa)->sin6_addr, 10172099bcdfStodd &rule->dst->address.v6, 10182099bcdfStodd sizeof(struct in6_addr)); 101957f58d0dSnaddy rule->dport = 102057f58d0dSnaddy ((struct sockaddr_in6 *)sa)->sin6_port; 10212099bcdfStodd break; 10221edc1b9aShshoexer default: 10231edc1b9aShshoexer return (1); 10241edc1b9aShshoexer } 10251edc1b9aShshoexer break; 10261edc1b9aShshoexer 10271edc1b9aShshoexer 10281edc1b9aShshoexer case SADB_X_EXT_SRC_MASK: 10291edc1b9aShshoexer saddr = (struct sadb_address *)ext; 10301edc1b9aShshoexer sa = (struct sockaddr *)(saddr + 1); 10311edc1b9aShshoexer 10321edc1b9aShshoexer if (rule->src == NULL) { 10331edc1b9aShshoexer rule->src = calloc(1, 103491f765ddShshoexer sizeof(struct ipsec_addr_wrap)); 10351edc1b9aShshoexer if (rule->src == NULL) 1036bd828a90Shshoexer err(1, "pfkey_parse: calloc"); 10371edc1b9aShshoexer } 10381edc1b9aShshoexer 10392099bcdfStodd rule->src->af = sa->sa_family; 10401edc1b9aShshoexer switch (sa->sa_family) { 10411edc1b9aShshoexer case AF_INET: 1042712e78baShshoexer sa_in = (struct sockaddr_in *)sa; 1043712e78baShshoexer bcopy(&sa_in->sin_addr, &rule->src->mask.v4, 10441edc1b9aShshoexer sizeof(struct in_addr)); 10452099bcdfStodd break; 10462099bcdfStodd case AF_INET6: 10472099bcdfStodd sa_in6 = (struct sockaddr_in6 *)sa; 10482099bcdfStodd bcopy(&sa_in6->sin6_addr, &rule->src->mask.v6, 10492099bcdfStodd sizeof(struct in6_addr)); 10501edc1b9aShshoexer break; 10511edc1b9aShshoexer 10521edc1b9aShshoexer default: 10531edc1b9aShshoexer return (1); 10541edc1b9aShshoexer } 10551edc1b9aShshoexer break; 10561edc1b9aShshoexer 10571edc1b9aShshoexer case SADB_X_EXT_DST_MASK: 10581edc1b9aShshoexer saddr = (struct sadb_address *)ext; 10591edc1b9aShshoexer sa = (struct sockaddr *)(saddr + 1); 10601edc1b9aShshoexer 10611edc1b9aShshoexer if (rule->dst == NULL) { 10621edc1b9aShshoexer rule->dst = calloc(1, 106391f765ddShshoexer sizeof(struct ipsec_addr_wrap)); 10641edc1b9aShshoexer if (rule->dst == NULL) 1065bd828a90Shshoexer err(1, "pfkey_parse: calloc"); 10661edc1b9aShshoexer } 10671edc1b9aShshoexer 10682099bcdfStodd rule->dst->af = sa->sa_family; 10691edc1b9aShshoexer switch (sa->sa_family) { 10701edc1b9aShshoexer case AF_INET: 1071712e78baShshoexer sa_in = (struct sockaddr_in *)sa; 1072712e78baShshoexer bcopy(&sa_in->sin_addr, &rule->dst->mask.v4, 10731edc1b9aShshoexer sizeof(struct in_addr)); 10741edc1b9aShshoexer break; 10752099bcdfStodd case AF_INET6: 10762099bcdfStodd sa_in6 = (struct sockaddr_in6 *)sa; 10772099bcdfStodd bcopy(&sa_in6->sin6_addr, &rule->dst->mask.v6, 10782099bcdfStodd sizeof(struct in6_addr)); 10792099bcdfStodd break; 10801edc1b9aShshoexer default: 10811edc1b9aShshoexer return (1); 10821edc1b9aShshoexer } 10831edc1b9aShshoexer break; 10841edc1b9aShshoexer 10851edc1b9aShshoexer default: 10861edc1b9aShshoexer return (1); 10871edc1b9aShshoexer } 10881edc1b9aShshoexer } 10891edc1b9aShshoexer 10901edc1b9aShshoexer return (0); 10911edc1b9aShshoexer } 10921edc1b9aShshoexer 10931edc1b9aShshoexer int 1094356121f6Shshoexer pfkey_ipsec_establish(int action, struct ipsec_rule *r) 1095f484f2cfShshoexer { 109622a29ad6Shshoexer int ret; 10978065703bShshoexer u_int8_t satype, satype2, direction; 1098f484f2cfShshoexer 1099f032086dShshoexer if (r->type == RULE_FLOW) { 11009182219dSmarkus switch (r->satype) { 1101f484f2cfShshoexer case IPSEC_ESP: 1102f484f2cfShshoexer satype = SADB_SATYPE_ESP; 1103f484f2cfShshoexer break; 1104f484f2cfShshoexer case IPSEC_AH: 1105f484f2cfShshoexer satype = SADB_SATYPE_AH; 1106f484f2cfShshoexer break; 110772e25333Shshoexer case IPSEC_IPCOMP: 110872e25333Shshoexer satype = SADB_X_SATYPE_IPCOMP; 110972e25333Shshoexer break; 111088a8cceeSmarkus case IPSEC_IPIP: 111188a8cceeSmarkus satype = SADB_X_SATYPE_IPIP; 111288a8cceeSmarkus break; 1113f484f2cfShshoexer default: 1114f484f2cfShshoexer return -1; 1115f484f2cfShshoexer } 1116f484f2cfShshoexer 1117f484f2cfShshoexer switch (r->direction) { 1118f484f2cfShshoexer case IPSEC_IN: 1119f484f2cfShshoexer direction = IPSP_DIRECTION_IN; 1120f484f2cfShshoexer break; 1121f484f2cfShshoexer case IPSEC_OUT: 1122f484f2cfShshoexer direction = IPSP_DIRECTION_OUT; 1123f484f2cfShshoexer break; 1124f484f2cfShshoexer default: 1125f484f2cfShshoexer return -1; 1126f484f2cfShshoexer } 1127f484f2cfShshoexer 112822a29ad6Shshoexer switch (action) { 112990bd57a7Shshoexer case ACTION_ADD: 1130f032086dShshoexer ret = pfkey_flow(fd, satype, SADB_X_ADDFLOW, direction, 113157f58d0dSnaddy r->proto, r->src, r->sport, r->dst, r->dport, 113257f58d0dSnaddy r->local, r->peer, r->auth, r->flowtype); 113322a29ad6Shshoexer break; 113490bd57a7Shshoexer case ACTION_DELETE: 113522a29ad6Shshoexer /* No peer for flow deletion. */ 1136f032086dShshoexer ret = pfkey_flow(fd, satype, SADB_X_DELFLOW, direction, 113757f58d0dSnaddy r->proto, r->src, r->sport, r->dst, r->dport, 113857f58d0dSnaddy NULL, NULL, NULL, r->flowtype); 113922a29ad6Shshoexer break; 114022a29ad6Shshoexer default: 114122a29ad6Shshoexer return -1; 114222a29ad6Shshoexer } 1143f032086dShshoexer } else if (r->type == RULE_SA) { 11449182219dSmarkus switch (r->satype) { 1145881e2068Shshoexer case IPSEC_AH: 1146881e2068Shshoexer satype = SADB_SATYPE_AH; 1147881e2068Shshoexer break; 1148881e2068Shshoexer case IPSEC_ESP: 1149881e2068Shshoexer satype = SADB_SATYPE_ESP; 1150881e2068Shshoexer break; 115172e25333Shshoexer case IPSEC_IPCOMP: 115272e25333Shshoexer satype = SADB_X_SATYPE_IPCOMP; 115372e25333Shshoexer break; 1154381a2422Shshoexer case IPSEC_TCPMD5: 1155f032086dShshoexer satype = SADB_X_SATYPE_TCPSIGNATURE; 1156381a2422Shshoexer break; 115788a8cceeSmarkus case IPSEC_IPIP: 115888a8cceeSmarkus satype = SADB_X_SATYPE_IPIP; 115988a8cceeSmarkus break; 1160381a2422Shshoexer default: 1161381a2422Shshoexer return -1; 1162381a2422Shshoexer } 1163f032086dShshoexer switch (action) { 116490bd57a7Shshoexer case ACTION_ADD: 1165f032086dShshoexer ret = pfkey_sa(fd, satype, SADB_ADD, r->spi, 1166a38d220fShshoexer r->src, r->dst, r->xfs, r->authkey, r->enckey, 1167a38d220fShshoexer r->tmode); 1168f032086dShshoexer break; 116990bd57a7Shshoexer case ACTION_DELETE: 1170f032086dShshoexer ret = pfkey_sa(fd, satype, SADB_DELETE, r->spi, 1171a38d220fShshoexer r->src, r->dst, r->xfs, NULL, NULL, r->tmode); 1172f032086dShshoexer break; 1173f032086dShshoexer default: 1174f032086dShshoexer return -1; 1175f032086dShshoexer } 11768f2109caShshoexer } else if (r->type == RULE_GROUP) { 11778f2109caShshoexer switch (r->satype) { 11788f2109caShshoexer case IPSEC_AH: 11798f2109caShshoexer satype = SADB_SATYPE_AH; 11808f2109caShshoexer break; 11818f2109caShshoexer case IPSEC_ESP: 11828f2109caShshoexer satype = SADB_SATYPE_ESP; 11838f2109caShshoexer break; 11848f2109caShshoexer case IPSEC_IPCOMP: 11858f2109caShshoexer satype = SADB_X_SATYPE_IPCOMP; 11868f2109caShshoexer break; 11878f2109caShshoexer case IPSEC_TCPMD5: 11888f2109caShshoexer satype = SADB_X_SATYPE_TCPSIGNATURE; 11898f2109caShshoexer break; 11908f2109caShshoexer case IPSEC_IPIP: 11918f2109caShshoexer satype = SADB_X_SATYPE_IPIP; 11928f2109caShshoexer break; 11938f2109caShshoexer default: 11948f2109caShshoexer return -1; 11958f2109caShshoexer } 11968065703bShshoexer switch (r->proto2) { 11978065703bShshoexer case IPSEC_AH: 11988065703bShshoexer satype2 = SADB_SATYPE_AH; 11998065703bShshoexer break; 12008065703bShshoexer case IPSEC_ESP: 12018065703bShshoexer satype2 = SADB_SATYPE_ESP; 12028065703bShshoexer break; 12038065703bShshoexer case IPSEC_IPCOMP: 12048065703bShshoexer satype2 = SADB_X_SATYPE_IPCOMP; 12058065703bShshoexer break; 12068065703bShshoexer case IPSEC_TCPMD5: 12078065703bShshoexer satype2 = SADB_X_SATYPE_TCPSIGNATURE; 12088065703bShshoexer break; 12098065703bShshoexer case IPSEC_IPIP: 12108065703bShshoexer satype2 = SADB_X_SATYPE_IPIP; 12118065703bShshoexer break; 12128065703bShshoexer default: 12138065703bShshoexer return -1; 12148065703bShshoexer } 12158f2109caShshoexer switch (action) { 12168f2109caShshoexer case ACTION_ADD: 12178065703bShshoexer ret = pfkey_sagroup(fd, satype, satype2, 12188065703bShshoexer SADB_X_GRPSPIS, r->dst, r->spi, r->dst2, r->spi2); 12198f2109caShshoexer break; 12208f2109caShshoexer case ACTION_DELETE: 12218f2109caShshoexer return 0; 12228f2109caShshoexer default: 12238f2109caShshoexer return -1; 12248f2109caShshoexer } 1225f032086dShshoexer } else 1226f032086dShshoexer return -1; 1227f032086dShshoexer 122822a29ad6Shshoexer if (ret < 0) 1229f484f2cfShshoexer return -1; 12308a87fca6Smsf if (pfkey_reply(fd, NULL, NULL) < 0) 1231f484f2cfShshoexer return -1; 1232f484f2cfShshoexer 1233f484f2cfShshoexer return 0; 1234f484f2cfShshoexer } 1235f484f2cfShshoexer 1236f484f2cfShshoexer int 1237f484f2cfShshoexer pfkey_ipsec_flush(void) 1238f484f2cfShshoexer { 1239f484f2cfShshoexer struct sadb_msg smsg; 1240f484f2cfShshoexer struct iovec iov[IOV_CNT]; 1241f484f2cfShshoexer ssize_t n; 1242f484f2cfShshoexer int iov_cnt, len; 1243f484f2cfShshoexer 1244f484f2cfShshoexer bzero(&smsg, sizeof(smsg)); 1245f484f2cfShshoexer smsg.sadb_msg_version = PF_KEY_V2; 1246f484f2cfShshoexer smsg.sadb_msg_seq = sadb_msg_seq++; 1247f484f2cfShshoexer smsg.sadb_msg_pid = getpid(); 1248f484f2cfShshoexer smsg.sadb_msg_len = sizeof(smsg) / 8; 1249f484f2cfShshoexer smsg.sadb_msg_type = SADB_FLUSH; 1250f484f2cfShshoexer smsg.sadb_msg_satype = SADB_SATYPE_UNSPEC; 1251f484f2cfShshoexer 1252f484f2cfShshoexer iov_cnt = 0; 1253f484f2cfShshoexer 1254f484f2cfShshoexer iov[iov_cnt].iov_base = &smsg; 1255f484f2cfShshoexer iov[iov_cnt].iov_len = sizeof(smsg); 1256f484f2cfShshoexer iov_cnt++; 1257f484f2cfShshoexer 1258f484f2cfShshoexer len = smsg.sadb_msg_len * 8; 1259f484f2cfShshoexer if ((n = writev(fd, iov, iov_cnt)) == -1) { 1260f484f2cfShshoexer warn("writev failed"); 1261f484f2cfShshoexer return -1; 1262f484f2cfShshoexer } 1263f484f2cfShshoexer if (n != len) { 1264f484f2cfShshoexer warnx("short write"); 1265f484f2cfShshoexer return -1; 1266f484f2cfShshoexer } 12678a87fca6Smsf if (pfkey_reply(fd, NULL, NULL) < 0) 1268f484f2cfShshoexer return -1; 1269f484f2cfShshoexer 1270f484f2cfShshoexer return 0; 1271f484f2cfShshoexer } 1272f484f2cfShshoexer 12738a87fca6Smsf static int 12748a87fca6Smsf pfkey_promisc(void) 12758a87fca6Smsf { 12768a87fca6Smsf struct sadb_msg msg; 12778a87fca6Smsf 12788a87fca6Smsf memset(&msg, 0, sizeof(msg)); 12798a87fca6Smsf msg.sadb_msg_version = PF_KEY_V2; 12808a87fca6Smsf msg.sadb_msg_seq = sadb_msg_seq++; 12818a87fca6Smsf msg.sadb_msg_pid = getpid(); 12828a87fca6Smsf msg.sadb_msg_len = sizeof(msg) / PFKEYV2_CHUNK; 12838a87fca6Smsf msg.sadb_msg_type = SADB_X_PROMISC; 12848a87fca6Smsf msg.sadb_msg_satype = 1; /* enable */ 12858a87fca6Smsf if (write(fd, &msg, sizeof(msg)) != sizeof(msg)) { 12868a87fca6Smsf warn("pfkey_promisc: write failed"); 12878a87fca6Smsf return -1; 12888a87fca6Smsf } 12898a87fca6Smsf if (pfkey_reply(fd, NULL, NULL) < 0) 12908a87fca6Smsf return -1; 12918a87fca6Smsf return 0; 12928a87fca6Smsf } 12938a87fca6Smsf 12948a87fca6Smsf int 12958a87fca6Smsf pfkey_monitor(int opts) 12968a87fca6Smsf { 12978a87fca6Smsf fd_set *rset; 12988a87fca6Smsf u_int8_t *data; 12998a87fca6Smsf struct sadb_msg *msg; 13008a87fca6Smsf ssize_t len, set_size; 13018a87fca6Smsf int n; 13028a87fca6Smsf 13038a87fca6Smsf if (pfkey_init() < 0) 13048a87fca6Smsf return -1; 13058a87fca6Smsf if (pfkey_promisc() < 0) 13068a87fca6Smsf return -1; 13078a87fca6Smsf 13088a87fca6Smsf set_size = howmany(fd + 1, NFDBITS) * sizeof(fd_mask); 13098a87fca6Smsf if ((rset = malloc(set_size)) == NULL) { 13108a87fca6Smsf warn("malloc"); 13118a87fca6Smsf return -1; 13128a87fca6Smsf } 13138a87fca6Smsf for (;;) { 13148a87fca6Smsf memset(rset, 0, set_size); 13158a87fca6Smsf FD_SET(fd, rset); 13168a87fca6Smsf if ((n = select(fd+1, rset, NULL, NULL, NULL)) < 0) 13178a87fca6Smsf err(2, "select"); 13188a87fca6Smsf if (n == 0) 13198a87fca6Smsf break; 13208a87fca6Smsf if (!FD_ISSET(fd, rset)) 13218a87fca6Smsf continue; 13228a87fca6Smsf if (pfkey_reply(fd, &data, &len) < 0) 13238a87fca6Smsf continue; 13248a87fca6Smsf msg = (struct sadb_msg *)data; 13258a87fca6Smsf if (msg->sadb_msg_type == SADB_X_PROMISC) { 13268a87fca6Smsf /* remove extra header from promisc messages */ 13278a87fca6Smsf if ((msg->sadb_msg_len * PFKEYV2_CHUNK) >= 13288a87fca6Smsf 2 * sizeof(struct sadb_msg)) { 13298a87fca6Smsf msg++; 13308a87fca6Smsf } 13318a87fca6Smsf } 13328a87fca6Smsf pfkey_monitor_sa(msg, opts); 13338a87fca6Smsf if (opts & IPSECCTL_OPT_VERBOSE) 13348a87fca6Smsf pfkey_print_raw(data, len); 13358a87fca6Smsf memset(data, 0, len); 13368a87fca6Smsf free(data); 13378a87fca6Smsf } 13388a87fca6Smsf close(fd); 13398a87fca6Smsf return 0; 13408a87fca6Smsf } 13418a87fca6Smsf 1342f484f2cfShshoexer int 1343f484f2cfShshoexer pfkey_init(void) 1344f484f2cfShshoexer { 1345f484f2cfShshoexer if ((fd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) == -1) 1346bd828a90Shshoexer err(1, "pfkey_init: failed to open PF_KEY socket"); 1347f484f2cfShshoexer 1348f484f2cfShshoexer return 0; 1349f484f2cfShshoexer } 1350