1*df69c215Sderaadt /* $OpenBSD: pfkey.c,v 1.61 2019/06/28 13:32:44 deraadt 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> 3356232324Sderaadt #include <poll.h> 34f484f2cfShshoexer #include <unistd.h> 35f484f2cfShshoexer 36f484f2cfShshoexer #include "ipsecctl.h" 371edc1b9aShshoexer #include "pfkey.h" 38f484f2cfShshoexer 39f484f2cfShshoexer #define ROUNDUP(x) (((x) + (PFKEYV2_CHUNK - 1)) & ~(PFKEYV2_CHUNK - 1)) 40f484f2cfShshoexer #define IOV_CNT 20 41f484f2cfShshoexer 42f484f2cfShshoexer static int fd; 43f484f2cfShshoexer static u_int32_t sadb_msg_seq = 1; 44f484f2cfShshoexer 459182219dSmarkus static int pfkey_flow(int, u_int8_t, u_int8_t, u_int8_t, u_int8_t, 4657f58d0dSnaddy struct ipsec_addr_wrap *, u_int16_t, 4757f58d0dSnaddy struct ipsec_addr_wrap *, u_int16_t, 48435bb41eSmarkus struct ipsec_addr_wrap *, struct ipsec_addr_wrap *, 49435bb41eSmarkus struct ipsec_auth *, u_int8_t); 50f032086dShshoexer static int pfkey_sa(int, u_int8_t, u_int8_t, u_int32_t, 5191f765ddShshoexer struct ipsec_addr_wrap *, struct ipsec_addr_wrap *, 52375db29dShshoexer struct ipsec_transforms *, struct ipsec_key *, 53a38d220fShshoexer struct ipsec_key *, u_int8_t); 54a6bcba92Sbluhm static int pfkey_sabundle(int, u_int8_t, u_int8_t, u_int8_t, 558065703bShshoexer struct ipsec_addr_wrap *, u_int32_t, 568065703bShshoexer struct ipsec_addr_wrap *, u_int32_t); 578a87fca6Smsf static int pfkey_reply(int, u_int8_t **, ssize_t *); 58e225c210Shshoexer int pfkey_parse(struct sadb_msg *, struct ipsec_rule *); 59f484f2cfShshoexer int pfkey_ipsec_flush(void); 60356121f6Shshoexer int pfkey_ipsec_establish(int, struct ipsec_rule *); 61f484f2cfShshoexer int pfkey_init(void); 62f484f2cfShshoexer 63f484f2cfShshoexer static int 64f484f2cfShshoexer pfkey_flow(int sd, u_int8_t satype, u_int8_t action, u_int8_t direction, 6557f58d0dSnaddy u_int8_t proto, struct ipsec_addr_wrap *src, u_int16_t sport, 6657f58d0dSnaddy struct ipsec_addr_wrap *dst, u_int16_t dport, 67435bb41eSmarkus struct ipsec_addr_wrap *local, struct ipsec_addr_wrap *peer, 68435bb41eSmarkus struct ipsec_auth *auth, u_int8_t flowtype) 69f484f2cfShshoexer { 70f484f2cfShshoexer struct sadb_msg smsg; 71435bb41eSmarkus struct sadb_address sa_src, sa_dst, sa_local, sa_peer, sa_smask, 72435bb41eSmarkus sa_dmask; 73f484f2cfShshoexer struct sadb_protocol sa_flowtype, sa_protocol; 74f484f2cfShshoexer struct sadb_ident *sa_srcid, *sa_dstid; 75435bb41eSmarkus struct sockaddr_storage ssrc, sdst, slocal, speer, smask, dmask; 76f484f2cfShshoexer struct iovec iov[IOV_CNT]; 77f484f2cfShshoexer ssize_t n; 78f484f2cfShshoexer int iov_cnt, len, ret = 0; 79f484f2cfShshoexer 80f484f2cfShshoexer sa_srcid = sa_dstid = NULL; 81f484f2cfShshoexer 82f484f2cfShshoexer bzero(&ssrc, sizeof(ssrc)); 83f484f2cfShshoexer bzero(&smask, sizeof(smask)); 842099bcdfStodd ssrc.ss_family = smask.ss_family = src->af; 85f484f2cfShshoexer switch (src->af) { 86f484f2cfShshoexer case AF_INET: 87712e78baShshoexer ((struct sockaddr_in *)&ssrc)->sin_addr = src->address.v4; 88f484f2cfShshoexer ssrc.ss_len = sizeof(struct sockaddr_in); 89712e78baShshoexer ((struct sockaddr_in *)&smask)->sin_addr = src->mask.v4; 9057f58d0dSnaddy if (sport) { 9157f58d0dSnaddy ((struct sockaddr_in *)&ssrc)->sin_port = sport; 9257f58d0dSnaddy ((struct sockaddr_in *)&smask)->sin_port = 0xffff; 9357f58d0dSnaddy } 94f484f2cfShshoexer break; 95f484f2cfShshoexer case AF_INET6: 962099bcdfStodd ((struct sockaddr_in6 *)&ssrc)->sin6_addr = src->address.v6; 972099bcdfStodd ssrc.ss_len = sizeof(struct sockaddr_in6); 982099bcdfStodd ((struct sockaddr_in6 *)&smask)->sin6_addr = src->mask.v6; 9957f58d0dSnaddy if (sport) { 10057f58d0dSnaddy ((struct sockaddr_in6 *)&ssrc)->sin6_port = sport; 10157f58d0dSnaddy ((struct sockaddr_in6 *)&smask)->sin6_port = 0xffff; 10257f58d0dSnaddy } 1032099bcdfStodd break; 104f484f2cfShshoexer default: 105f484f2cfShshoexer warnx("unsupported address family %d", src->af); 106f484f2cfShshoexer return -1; 107f484f2cfShshoexer } 108f484f2cfShshoexer smask.ss_len = ssrc.ss_len; 109f484f2cfShshoexer 110f484f2cfShshoexer bzero(&sdst, sizeof(sdst)); 111f484f2cfShshoexer bzero(&dmask, sizeof(dmask)); 1122099bcdfStodd sdst.ss_family = dmask.ss_family = dst->af; 113f484f2cfShshoexer switch (dst->af) { 114f484f2cfShshoexer case AF_INET: 115712e78baShshoexer ((struct sockaddr_in *)&sdst)->sin_addr = dst->address.v4; 116f484f2cfShshoexer sdst.ss_len = sizeof(struct sockaddr_in); 117712e78baShshoexer ((struct sockaddr_in *)&dmask)->sin_addr = dst->mask.v4; 11857f58d0dSnaddy if (dport) { 11957f58d0dSnaddy ((struct sockaddr_in *)&sdst)->sin_port = dport; 12057f58d0dSnaddy ((struct sockaddr_in *)&dmask)->sin_port = 0xffff; 12157f58d0dSnaddy } 122f484f2cfShshoexer break; 123f484f2cfShshoexer case AF_INET6: 1242099bcdfStodd ((struct sockaddr_in6 *)&sdst)->sin6_addr = dst->address.v6; 1252099bcdfStodd sdst.ss_len = sizeof(struct sockaddr_in6); 1262099bcdfStodd ((struct sockaddr_in6 *)&dmask)->sin6_addr = dst->mask.v6; 12757f58d0dSnaddy if (dport) { 12857f58d0dSnaddy ((struct sockaddr_in6 *)&sdst)->sin6_port = dport; 12957f58d0dSnaddy ((struct sockaddr_in6 *)&dmask)->sin6_port = 0xffff; 13057f58d0dSnaddy } 1312099bcdfStodd break; 132f484f2cfShshoexer default: 133f484f2cfShshoexer warnx("unsupported address family %d", dst->af); 134f484f2cfShshoexer return -1; 135f484f2cfShshoexer } 136f484f2cfShshoexer dmask.ss_len = sdst.ss_len; 137f484f2cfShshoexer 138435bb41eSmarkus bzero(&slocal, sizeof(slocal)); 139435bb41eSmarkus if (local) { 1402099bcdfStodd slocal.ss_family = local->af; 141435bb41eSmarkus switch (local->af) { 142435bb41eSmarkus case AF_INET: 143435bb41eSmarkus ((struct sockaddr_in *)&slocal)->sin_addr = 144435bb41eSmarkus local->address.v4; 145435bb41eSmarkus slocal.ss_len = sizeof(struct sockaddr_in); 146435bb41eSmarkus break; 147435bb41eSmarkus case AF_INET6: 1482099bcdfStodd ((struct sockaddr_in6 *)&slocal)->sin6_addr = 1492099bcdfStodd local->address.v6; 1502099bcdfStodd slocal.ss_len = sizeof(struct sockaddr_in6); 1512099bcdfStodd break; 152435bb41eSmarkus default: 153435bb41eSmarkus warnx("unsupported address family %d", local->af); 154435bb41eSmarkus return -1; 155435bb41eSmarkus } 156435bb41eSmarkus } 157435bb41eSmarkus 158f484f2cfShshoexer bzero(&speer, sizeof(speer)); 15922a29ad6Shshoexer if (peer) { 1602099bcdfStodd speer.ss_family = peer->af; 161f484f2cfShshoexer switch (peer->af) { 162f484f2cfShshoexer case AF_INET: 163712e78baShshoexer ((struct sockaddr_in *)&speer)->sin_addr = 164712e78baShshoexer peer->address.v4; 165f484f2cfShshoexer speer.ss_len = sizeof(struct sockaddr_in); 166f484f2cfShshoexer break; 167f484f2cfShshoexer case AF_INET6: 1682099bcdfStodd ((struct sockaddr_in6 *)&speer)->sin6_addr = 1692099bcdfStodd peer->address.v6; 1702099bcdfStodd speer.ss_len = sizeof(struct sockaddr_in6); 1712099bcdfStodd break; 172f484f2cfShshoexer default: 173f484f2cfShshoexer warnx("unsupported address family %d", peer->af); 174f484f2cfShshoexer return -1; 175f484f2cfShshoexer } 17622a29ad6Shshoexer } 177f484f2cfShshoexer 178f484f2cfShshoexer bzero(&smsg, sizeof(smsg)); 179f484f2cfShshoexer smsg.sadb_msg_version = PF_KEY_V2; 180f484f2cfShshoexer smsg.sadb_msg_seq = sadb_msg_seq++; 181f484f2cfShshoexer smsg.sadb_msg_pid = getpid(); 182f484f2cfShshoexer smsg.sadb_msg_len = sizeof(smsg) / 8; 183f484f2cfShshoexer smsg.sadb_msg_type = action; 184f484f2cfShshoexer smsg.sadb_msg_satype = satype; 185f484f2cfShshoexer 186f484f2cfShshoexer bzero(&sa_flowtype, sizeof(sa_flowtype)); 187f484f2cfShshoexer sa_flowtype.sadb_protocol_exttype = SADB_X_EXT_FLOW_TYPE; 188f484f2cfShshoexer sa_flowtype.sadb_protocol_len = sizeof(sa_flowtype) / 8; 189f484f2cfShshoexer sa_flowtype.sadb_protocol_direction = direction; 19026df514dShshoexer 191e1ffbfafShshoexer switch (flowtype) { 192e1ffbfafShshoexer case TYPE_USE: 19326df514dShshoexer sa_flowtype.sadb_protocol_proto = SADB_X_FLOW_TYPE_USE; 194e1ffbfafShshoexer break; 195b7a16601Shshoexer case TYPE_ACQUIRE: 196b7a16601Shshoexer sa_flowtype.sadb_protocol_proto = SADB_X_FLOW_TYPE_ACQUIRE; 197b7a16601Shshoexer break; 198e1ffbfafShshoexer case TYPE_REQUIRE: 199f484f2cfShshoexer sa_flowtype.sadb_protocol_proto = SADB_X_FLOW_TYPE_REQUIRE; 200e1ffbfafShshoexer break; 2017c7fb9e5Sreyk case TYPE_DENY: 2027c7fb9e5Sreyk sa_flowtype.sadb_protocol_proto = SADB_X_FLOW_TYPE_DENY; 2037c7fb9e5Sreyk break; 2047c7fb9e5Sreyk case TYPE_BYPASS: 2057c7fb9e5Sreyk sa_flowtype.sadb_protocol_proto = SADB_X_FLOW_TYPE_BYPASS; 2067c7fb9e5Sreyk break; 207b7a16601Shshoexer case TYPE_DONTACQ: 208b7a16601Shshoexer sa_flowtype.sadb_protocol_proto = SADB_X_FLOW_TYPE_DONTACQ; 209b7a16601Shshoexer break; 210e1ffbfafShshoexer default: 211e1ffbfafShshoexer warnx("unsupported flowtype %d", flowtype); 212e1ffbfafShshoexer return -1; 213e1ffbfafShshoexer } 214f484f2cfShshoexer 215f484f2cfShshoexer bzero(&sa_protocol, sizeof(sa_protocol)); 216f484f2cfShshoexer sa_protocol.sadb_protocol_exttype = SADB_X_EXT_PROTOCOL; 217f484f2cfShshoexer sa_protocol.sadb_protocol_len = sizeof(sa_protocol) / 8; 218f484f2cfShshoexer sa_protocol.sadb_protocol_direction = 0; 2199182219dSmarkus sa_protocol.sadb_protocol_proto = proto; 220f484f2cfShshoexer 221f484f2cfShshoexer bzero(&sa_src, sizeof(sa_src)); 222f484f2cfShshoexer sa_src.sadb_address_exttype = SADB_X_EXT_SRC_FLOW; 223f484f2cfShshoexer sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(ssrc.ss_len)) / 8; 224f484f2cfShshoexer 225f484f2cfShshoexer bzero(&sa_smask, sizeof(sa_smask)); 226f484f2cfShshoexer sa_smask.sadb_address_exttype = SADB_X_EXT_SRC_MASK; 227f484f2cfShshoexer sa_smask.sadb_address_len = 228f484f2cfShshoexer (sizeof(sa_smask) + ROUNDUP(smask.ss_len)) / 8; 229f484f2cfShshoexer 230f484f2cfShshoexer bzero(&sa_dst, sizeof(sa_dst)); 231f484f2cfShshoexer sa_dst.sadb_address_exttype = SADB_X_EXT_DST_FLOW; 232f484f2cfShshoexer sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(sdst.ss_len)) / 8; 233f484f2cfShshoexer 234f484f2cfShshoexer bzero(&sa_dmask, sizeof(sa_dmask)); 235f484f2cfShshoexer sa_dmask.sadb_address_exttype = SADB_X_EXT_DST_MASK; 236f484f2cfShshoexer sa_dmask.sadb_address_len = 237f484f2cfShshoexer (sizeof(sa_dmask) + ROUNDUP(dmask.ss_len)) / 8; 238f484f2cfShshoexer 239435bb41eSmarkus if (local) { 240435bb41eSmarkus bzero(&sa_local, sizeof(sa_local)); 241435bb41eSmarkus sa_local.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; 242435bb41eSmarkus sa_local.sadb_address_len = 243435bb41eSmarkus (sizeof(sa_local) + ROUNDUP(slocal.ss_len)) / 8; 244435bb41eSmarkus } 245435bb41eSmarkus if (peer) { 246f484f2cfShshoexer bzero(&sa_peer, sizeof(sa_peer)); 247f484f2cfShshoexer sa_peer.sadb_address_exttype = SADB_EXT_ADDRESS_DST; 248f484f2cfShshoexer sa_peer.sadb_address_len = 249f484f2cfShshoexer (sizeof(sa_peer) + ROUNDUP(speer.ss_len)) / 8; 250435bb41eSmarkus } 251f484f2cfShshoexer 252abe65127Shshoexer if (auth && auth->srcid) { 253abe65127Shshoexer len = ROUNDUP(strlen(auth->srcid) + 1) + sizeof(*sa_srcid); 254f484f2cfShshoexer 255f484f2cfShshoexer sa_srcid = calloc(len, sizeof(u_int8_t)); 256f484f2cfShshoexer if (sa_srcid == NULL) 257bd828a90Shshoexer err(1, "pfkey_flow: calloc"); 258f484f2cfShshoexer 2592281ca6dSmarkus sa_srcid->sadb_ident_type = auth->srcid_type; 260f484f2cfShshoexer sa_srcid->sadb_ident_len = len / 8; 261f484f2cfShshoexer sa_srcid->sadb_ident_exttype = SADB_EXT_IDENTITY_SRC; 262f484f2cfShshoexer 263abe65127Shshoexer strlcpy((char *)(sa_srcid + 1), auth->srcid, 264abe65127Shshoexer ROUNDUP(strlen(auth->srcid) + 1)); 265f484f2cfShshoexer } 266abe65127Shshoexer if (auth && auth->dstid) { 267abe65127Shshoexer len = ROUNDUP(strlen(auth->dstid) + 1) + sizeof(*sa_dstid); 268f484f2cfShshoexer 269f484f2cfShshoexer sa_dstid = calloc(len, sizeof(u_int8_t)); 270f484f2cfShshoexer if (sa_dstid == NULL) 271bd828a90Shshoexer err(1, "pfkey_flow: calloc"); 272f484f2cfShshoexer 2732281ca6dSmarkus sa_dstid->sadb_ident_type = auth->dstid_type; 274f484f2cfShshoexer sa_dstid->sadb_ident_len = len / 8; 275f484f2cfShshoexer sa_dstid->sadb_ident_exttype = SADB_EXT_IDENTITY_DST; 276f484f2cfShshoexer 277abe65127Shshoexer strlcpy((char *)(sa_dstid + 1), auth->dstid, 278abe65127Shshoexer ROUNDUP(strlen(auth->dstid) + 1)); 279f484f2cfShshoexer } 280f484f2cfShshoexer 281f484f2cfShshoexer iov_cnt = 0; 282f484f2cfShshoexer 283f484f2cfShshoexer /* header */ 284f484f2cfShshoexer iov[iov_cnt].iov_base = &smsg; 285f484f2cfShshoexer iov[iov_cnt].iov_len = sizeof(smsg); 286f484f2cfShshoexer iov_cnt++; 287f484f2cfShshoexer 28889ad8c34Shshoexer /* add flow type */ 28989ad8c34Shshoexer iov[iov_cnt].iov_base = &sa_flowtype; 29089ad8c34Shshoexer iov[iov_cnt].iov_len = sizeof(sa_flowtype); 29189ad8c34Shshoexer smsg.sadb_msg_len += sa_flowtype.sadb_protocol_len; 29289ad8c34Shshoexer iov_cnt++; 29389ad8c34Shshoexer 294435bb41eSmarkus /* local ip */ 295435bb41eSmarkus if (local) { 296435bb41eSmarkus iov[iov_cnt].iov_base = &sa_local; 297435bb41eSmarkus iov[iov_cnt].iov_len = sizeof(sa_local); 298435bb41eSmarkus iov_cnt++; 299435bb41eSmarkus iov[iov_cnt].iov_base = &slocal; 300435bb41eSmarkus iov[iov_cnt].iov_len = ROUNDUP(slocal.ss_len); 301435bb41eSmarkus smsg.sadb_msg_len += sa_local.sadb_address_len; 302435bb41eSmarkus iov_cnt++; 303435bb41eSmarkus } 304435bb41eSmarkus 305f484f2cfShshoexer /* remote peer */ 30622a29ad6Shshoexer if (peer) { 307f484f2cfShshoexer iov[iov_cnt].iov_base = &sa_peer; 308f484f2cfShshoexer iov[iov_cnt].iov_len = sizeof(sa_peer); 309f484f2cfShshoexer iov_cnt++; 310f484f2cfShshoexer iov[iov_cnt].iov_base = &speer; 311f484f2cfShshoexer iov[iov_cnt].iov_len = ROUNDUP(speer.ss_len); 312f484f2cfShshoexer smsg.sadb_msg_len += sa_peer.sadb_address_len; 313f484f2cfShshoexer iov_cnt++; 31422a29ad6Shshoexer } 315f484f2cfShshoexer 31689ad8c34Shshoexer /* src addr */ 31789ad8c34Shshoexer iov[iov_cnt].iov_base = &sa_src; 31889ad8c34Shshoexer iov[iov_cnt].iov_len = sizeof(sa_src); 31989ad8c34Shshoexer iov_cnt++; 32089ad8c34Shshoexer iov[iov_cnt].iov_base = &ssrc; 32189ad8c34Shshoexer iov[iov_cnt].iov_len = ROUNDUP(ssrc.ss_len); 32289ad8c34Shshoexer smsg.sadb_msg_len += sa_src.sadb_address_len; 323f484f2cfShshoexer iov_cnt++; 324f484f2cfShshoexer 32589ad8c34Shshoexer /* src mask */ 326f484f2cfShshoexer iov[iov_cnt].iov_base = &sa_smask; 327f484f2cfShshoexer iov[iov_cnt].iov_len = sizeof(sa_smask); 328f484f2cfShshoexer iov_cnt++; 329f484f2cfShshoexer iov[iov_cnt].iov_base = &smask; 330f484f2cfShshoexer iov[iov_cnt].iov_len = ROUNDUP(smask.ss_len); 331f484f2cfShshoexer smsg.sadb_msg_len += sa_smask.sadb_address_len; 332f484f2cfShshoexer iov_cnt++; 333f484f2cfShshoexer 334f484f2cfShshoexer /* dest addr */ 335f484f2cfShshoexer iov[iov_cnt].iov_base = &sa_dst; 336f484f2cfShshoexer iov[iov_cnt].iov_len = sizeof(sa_dst); 337f484f2cfShshoexer iov_cnt++; 338f484f2cfShshoexer iov[iov_cnt].iov_base = &sdst; 339f484f2cfShshoexer iov[iov_cnt].iov_len = ROUNDUP(sdst.ss_len); 340f484f2cfShshoexer smsg.sadb_msg_len += sa_dst.sadb_address_len; 341f484f2cfShshoexer iov_cnt++; 342f484f2cfShshoexer 34389ad8c34Shshoexer /* dst mask */ 34489ad8c34Shshoexer iov[iov_cnt].iov_base = &sa_dmask; 34589ad8c34Shshoexer iov[iov_cnt].iov_len = sizeof(sa_dmask); 346f484f2cfShshoexer iov_cnt++; 34789ad8c34Shshoexer iov[iov_cnt].iov_base = &dmask; 34889ad8c34Shshoexer iov[iov_cnt].iov_len = ROUNDUP(dmask.ss_len); 34989ad8c34Shshoexer smsg.sadb_msg_len += sa_dmask.sadb_address_len; 35089ad8c34Shshoexer iov_cnt++; 35189ad8c34Shshoexer 35289ad8c34Shshoexer /* add protocol */ 35389ad8c34Shshoexer iov[iov_cnt].iov_base = &sa_protocol; 35489ad8c34Shshoexer iov[iov_cnt].iov_len = sizeof(sa_protocol); 35589ad8c34Shshoexer smsg.sadb_msg_len += sa_protocol.sadb_protocol_len; 356f484f2cfShshoexer iov_cnt++; 357f484f2cfShshoexer 358f484f2cfShshoexer if (sa_srcid) { 359f484f2cfShshoexer /* src identity */ 360f484f2cfShshoexer iov[iov_cnt].iov_base = sa_srcid; 361f484f2cfShshoexer iov[iov_cnt].iov_len = sa_srcid->sadb_ident_len * 8; 362f484f2cfShshoexer smsg.sadb_msg_len += sa_srcid->sadb_ident_len; 363f484f2cfShshoexer iov_cnt++; 364f484f2cfShshoexer } 365f484f2cfShshoexer if (sa_dstid) { 366f484f2cfShshoexer /* dst identity */ 367f484f2cfShshoexer iov[iov_cnt].iov_base = sa_dstid; 368f484f2cfShshoexer iov[iov_cnt].iov_len = sa_dstid->sadb_ident_len * 8; 369f484f2cfShshoexer smsg.sadb_msg_len += sa_dstid->sadb_ident_len; 370f484f2cfShshoexer iov_cnt++; 371f484f2cfShshoexer } 372f484f2cfShshoexer len = smsg.sadb_msg_len * 8; 37389d271caShenning 37489d271caShenning do { 37589d271caShenning n = writev(sd, iov, iov_cnt); 37689d271caShenning } while (n == -1 && (errno == EAGAIN || errno == EINTR)); 37789d271caShenning if (n == -1) { 378f484f2cfShshoexer warn("writev failed"); 379f484f2cfShshoexer ret = -1; 380f484f2cfShshoexer } 381f484f2cfShshoexer 382f484f2cfShshoexer free(sa_srcid); 383f484f2cfShshoexer free(sa_dstid); 384f484f2cfShshoexer 385f484f2cfShshoexer return ret; 386f484f2cfShshoexer } 387f484f2cfShshoexer 388f484f2cfShshoexer static int 38991f765ddShshoexer pfkey_sa(int sd, u_int8_t satype, u_int8_t action, u_int32_t spi, 39091f765ddShshoexer struct ipsec_addr_wrap *src, struct ipsec_addr_wrap *dst, 39191f765ddShshoexer struct ipsec_transforms *xfs, struct ipsec_key *authkey, 392a38d220fShshoexer struct ipsec_key *enckey, u_int8_t tmode) 393f032086dShshoexer { 394f032086dShshoexer struct sadb_msg smsg; 395f032086dShshoexer struct sadb_sa sa; 396f032086dShshoexer struct sadb_address sa_src, sa_dst; 397881e2068Shshoexer struct sadb_key sa_authkey, sa_enckey; 398f032086dShshoexer struct sockaddr_storage ssrc, sdst; 399f032086dShshoexer struct iovec iov[IOV_CNT]; 400f032086dShshoexer ssize_t n; 401f032086dShshoexer int iov_cnt, len, ret = 0; 402f032086dShshoexer 403f032086dShshoexer bzero(&ssrc, sizeof(ssrc)); 4042099bcdfStodd ssrc.ss_family = src->af; 405f032086dShshoexer switch (src->af) { 406f032086dShshoexer case AF_INET: 407712e78baShshoexer ((struct sockaddr_in *)&ssrc)->sin_addr = src->address.v4; 408f032086dShshoexer ssrc.ss_len = sizeof(struct sockaddr_in); 409f032086dShshoexer break; 410f032086dShshoexer case AF_INET6: 4112099bcdfStodd ((struct sockaddr_in6 *)&ssrc)->sin6_addr = src->address.v6; 4122099bcdfStodd ssrc.ss_len = sizeof(struct sockaddr_in6); 4132099bcdfStodd break; 414f032086dShshoexer default: 415f032086dShshoexer warnx("unsupported address family %d", src->af); 416f032086dShshoexer return -1; 417f032086dShshoexer } 418f032086dShshoexer 419f032086dShshoexer bzero(&sdst, sizeof(sdst)); 4202099bcdfStodd sdst.ss_family = dst->af; 421f032086dShshoexer switch (dst->af) { 422f032086dShshoexer case AF_INET: 423712e78baShshoexer ((struct sockaddr_in *)&sdst)->sin_addr = dst->address.v4; 424f032086dShshoexer sdst.ss_len = sizeof(struct sockaddr_in); 425f032086dShshoexer break; 426f032086dShshoexer case AF_INET6: 4272099bcdfStodd ((struct sockaddr_in6 *)&sdst)->sin6_addr = dst->address.v6; 4282099bcdfStodd sdst.ss_len = sizeof(struct sockaddr_in6); 4292099bcdfStodd break; 430f032086dShshoexer default: 431f032086dShshoexer warnx("unsupported address family %d", dst->af); 432f032086dShshoexer return -1; 433f032086dShshoexer } 434f032086dShshoexer 435f032086dShshoexer bzero(&smsg, sizeof(smsg)); 436f032086dShshoexer smsg.sadb_msg_version = PF_KEY_V2; 437f032086dShshoexer smsg.sadb_msg_seq = sadb_msg_seq++; 438f032086dShshoexer smsg.sadb_msg_pid = getpid(); 439f032086dShshoexer smsg.sadb_msg_len = sizeof(smsg) / 8; 440f032086dShshoexer smsg.sadb_msg_type = action; 441f032086dShshoexer smsg.sadb_msg_satype = satype; 442f032086dShshoexer 443f032086dShshoexer bzero(&sa, sizeof(sa)); 444f032086dShshoexer sa.sadb_sa_len = sizeof(sa) / 8; 445f032086dShshoexer sa.sadb_sa_exttype = SADB_EXT_SA; 446f032086dShshoexer sa.sadb_sa_spi = htonl(spi); 447f032086dShshoexer sa.sadb_sa_state = SADB_SASTATE_MATURE; 448f032086dShshoexer 44988a8cceeSmarkus if (satype != SADB_X_SATYPE_IPIP && tmode == IPSEC_TUNNEL) 450a38d220fShshoexer sa.sadb_sa_flags |= SADB_X_SAFLAGS_TUNNEL; 451a38d220fShshoexer 452375db29dShshoexer if (xfs && xfs->authxf) { 453375db29dShshoexer switch (xfs->authxf->id) { 454881e2068Shshoexer case AUTHXF_NONE: 455881e2068Shshoexer break; 456881e2068Shshoexer case AUTHXF_HMAC_MD5: 457881e2068Shshoexer sa.sadb_sa_auth = SADB_AALG_MD5HMAC; 458881e2068Shshoexer break; 459881e2068Shshoexer case AUTHXF_HMAC_RIPEMD160: 460881e2068Shshoexer sa.sadb_sa_auth = SADB_X_AALG_RIPEMD160HMAC; 461881e2068Shshoexer break; 462881e2068Shshoexer case AUTHXF_HMAC_SHA1: 463881e2068Shshoexer sa.sadb_sa_auth = SADB_AALG_SHA1HMAC; 464881e2068Shshoexer break; 465881e2068Shshoexer case AUTHXF_HMAC_SHA2_256: 466881e2068Shshoexer sa.sadb_sa_auth = SADB_X_AALG_SHA2_256; 467881e2068Shshoexer break; 468881e2068Shshoexer case AUTHXF_HMAC_SHA2_384: 469881e2068Shshoexer sa.sadb_sa_auth = SADB_X_AALG_SHA2_384; 470881e2068Shshoexer break; 471881e2068Shshoexer case AUTHXF_HMAC_SHA2_512: 472881e2068Shshoexer sa.sadb_sa_auth = SADB_X_AALG_SHA2_512; 473881e2068Shshoexer break; 474881e2068Shshoexer default: 475881e2068Shshoexer warnx("unsupported authentication algorithm %d", 476375db29dShshoexer xfs->authxf->id); 477881e2068Shshoexer } 478881e2068Shshoexer } 479375db29dShshoexer if (xfs && xfs->encxf) { 480375db29dShshoexer switch (xfs->encxf->id) { 481881e2068Shshoexer case ENCXF_NONE: 482881e2068Shshoexer break; 483881e2068Shshoexer case ENCXF_3DES_CBC: 484881e2068Shshoexer sa.sadb_sa_encrypt = SADB_EALG_3DESCBC; 485881e2068Shshoexer break; 486881e2068Shshoexer case ENCXF_AES: 487783454c1Smikeb case ENCXF_AES_128: 488783454c1Smikeb case ENCXF_AES_192: 489783454c1Smikeb case ENCXF_AES_256: 490881e2068Shshoexer sa.sadb_sa_encrypt = SADB_X_EALG_AES; 491881e2068Shshoexer break; 492881e2068Shshoexer case ENCXF_AESCTR: 4935f649d51Snaddy case ENCXF_AES_128_CTR: 4945f649d51Snaddy case ENCXF_AES_192_CTR: 4955f649d51Snaddy case ENCXF_AES_256_CTR: 496881e2068Shshoexer sa.sadb_sa_encrypt = SADB_X_EALG_AESCTR; 497881e2068Shshoexer break; 498783454c1Smikeb case ENCXF_AES_128_GCM: 499783454c1Smikeb case ENCXF_AES_192_GCM: 500783454c1Smikeb case ENCXF_AES_256_GCM: 501783454c1Smikeb sa.sadb_sa_encrypt = SADB_X_EALG_AESGCM16; 502783454c1Smikeb break; 503783454c1Smikeb case ENCXF_AES_128_GMAC: 504783454c1Smikeb case ENCXF_AES_192_GMAC: 505783454c1Smikeb case ENCXF_AES_256_GMAC: 506783454c1Smikeb sa.sadb_sa_encrypt = SADB_X_EALG_AESGMAC; 507783454c1Smikeb break; 508881e2068Shshoexer case ENCXF_BLOWFISH: 509881e2068Shshoexer sa.sadb_sa_encrypt = SADB_X_EALG_BLF; 510881e2068Shshoexer break; 511881e2068Shshoexer case ENCXF_CAST128: 512881e2068Shshoexer sa.sadb_sa_encrypt = SADB_X_EALG_CAST; 513881e2068Shshoexer break; 514881e2068Shshoexer case ENCXF_NULL: 515881e2068Shshoexer sa.sadb_sa_encrypt = SADB_EALG_NULL; 516881e2068Shshoexer break; 517881e2068Shshoexer default: 518375db29dShshoexer warnx("unsupported encryption algorithm %d", 519375db29dShshoexer xfs->encxf->id); 520881e2068Shshoexer } 521881e2068Shshoexer } 52272e25333Shshoexer if (xfs && xfs->compxf) { 52372e25333Shshoexer switch (xfs->compxf->id) { 52472e25333Shshoexer case COMPXF_DEFLATE: 52572e25333Shshoexer sa.sadb_sa_encrypt = SADB_X_CALG_DEFLATE; 52672e25333Shshoexer break; 52772e25333Shshoexer case COMPXF_LZS: 52872e25333Shshoexer sa.sadb_sa_encrypt = SADB_X_CALG_LZS; 52972e25333Shshoexer break; 53072e25333Shshoexer default: 53172e25333Shshoexer warnx("unsupported compression algorithm %d", 53272e25333Shshoexer xfs->compxf->id); 53372e25333Shshoexer } 53472e25333Shshoexer } 535881e2068Shshoexer 536f032086dShshoexer bzero(&sa_src, sizeof(sa_src)); 537f032086dShshoexer sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(ssrc.ss_len)) / 8; 538f032086dShshoexer sa_src.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; 539f032086dShshoexer 540f032086dShshoexer bzero(&sa_dst, sizeof(sa_dst)); 541f032086dShshoexer sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(sdst.ss_len)) / 8; 542f032086dShshoexer sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST; 543f032086dShshoexer 54472e25333Shshoexer if (action == SADB_ADD && !authkey && !enckey && satype != 54588a8cceeSmarkus SADB_X_SATYPE_IPCOMP && satype != SADB_X_SATYPE_IPIP) { /* XXX ENCNULL */ 5460813ab45Shshoexer warnx("no key specified"); 5470813ab45Shshoexer return -1; 5480813ab45Shshoexer } 549881e2068Shshoexer if (authkey) { 550881e2068Shshoexer bzero(&sa_authkey, sizeof(sa_authkey)); 551881e2068Shshoexer sa_authkey.sadb_key_len = (sizeof(sa_authkey) + 552881e2068Shshoexer ((authkey->len + 7) / 8) * 8) / 8; 553881e2068Shshoexer sa_authkey.sadb_key_exttype = SADB_EXT_KEY_AUTH; 554881e2068Shshoexer sa_authkey.sadb_key_bits = 8 * authkey->len; 555881e2068Shshoexer } 556881e2068Shshoexer if (enckey) { 557881e2068Shshoexer bzero(&sa_enckey, sizeof(sa_enckey)); 558881e2068Shshoexer sa_enckey.sadb_key_len = (sizeof(sa_enckey) + 559881e2068Shshoexer ((enckey->len + 7) / 8) * 8) / 8; 560881e2068Shshoexer sa_enckey.sadb_key_exttype = SADB_EXT_KEY_ENCRYPT; 561881e2068Shshoexer sa_enckey.sadb_key_bits = 8 * enckey->len; 562f032086dShshoexer } 563f032086dShshoexer 564f032086dShshoexer iov_cnt = 0; 565f032086dShshoexer 566f032086dShshoexer /* header */ 567f032086dShshoexer iov[iov_cnt].iov_base = &smsg; 568f032086dShshoexer iov[iov_cnt].iov_len = sizeof(smsg); 569f032086dShshoexer iov_cnt++; 570f032086dShshoexer 571f032086dShshoexer /* sa */ 572f032086dShshoexer iov[iov_cnt].iov_base = &sa; 573f032086dShshoexer iov[iov_cnt].iov_len = sizeof(sa); 574f032086dShshoexer smsg.sadb_msg_len += sa.sadb_sa_len; 575f032086dShshoexer iov_cnt++; 576f032086dShshoexer 577f032086dShshoexer /* src addr */ 578f032086dShshoexer iov[iov_cnt].iov_base = &sa_src; 579f032086dShshoexer iov[iov_cnt].iov_len = sizeof(sa_src); 580f032086dShshoexer iov_cnt++; 581f032086dShshoexer iov[iov_cnt].iov_base = &ssrc; 582f032086dShshoexer iov[iov_cnt].iov_len = ROUNDUP(ssrc.ss_len); 583f032086dShshoexer smsg.sadb_msg_len += sa_src.sadb_address_len; 584f032086dShshoexer iov_cnt++; 585f032086dShshoexer 586f032086dShshoexer /* dst addr */ 587f032086dShshoexer iov[iov_cnt].iov_base = &sa_dst; 588f032086dShshoexer iov[iov_cnt].iov_len = sizeof(sa_dst); 589f032086dShshoexer iov_cnt++; 590f032086dShshoexer iov[iov_cnt].iov_base = &sdst; 591f032086dShshoexer iov[iov_cnt].iov_len = ROUNDUP(sdst.ss_len); 592f032086dShshoexer smsg.sadb_msg_len += sa_dst.sadb_address_len; 593f032086dShshoexer iov_cnt++; 594f032086dShshoexer 595881e2068Shshoexer if (authkey) { 596881e2068Shshoexer /* authentication key */ 597881e2068Shshoexer iov[iov_cnt].iov_base = &sa_authkey; 598881e2068Shshoexer iov[iov_cnt].iov_len = sizeof(sa_authkey); 599f032086dShshoexer iov_cnt++; 600881e2068Shshoexer iov[iov_cnt].iov_base = authkey->data; 601881e2068Shshoexer iov[iov_cnt].iov_len = ((authkey->len + 7) / 8) * 8; 602881e2068Shshoexer smsg.sadb_msg_len += sa_authkey.sadb_key_len; 603881e2068Shshoexer iov_cnt++; 604881e2068Shshoexer } 605881e2068Shshoexer if (enckey) { 606881e2068Shshoexer /* encryption key */ 607881e2068Shshoexer iov[iov_cnt].iov_base = &sa_enckey; 608881e2068Shshoexer iov[iov_cnt].iov_len = sizeof(sa_enckey); 609881e2068Shshoexer iov_cnt++; 610881e2068Shshoexer iov[iov_cnt].iov_base = enckey->data; 611881e2068Shshoexer iov[iov_cnt].iov_len = ((enckey->len + 7) / 8) * 8; 612881e2068Shshoexer smsg.sadb_msg_len += sa_enckey.sadb_key_len; 613f032086dShshoexer iov_cnt++; 614f032086dShshoexer } 615f032086dShshoexer 616f032086dShshoexer len = smsg.sadb_msg_len * 8; 617f032086dShshoexer if ((n = writev(sd, iov, iov_cnt)) == -1) { 618f032086dShshoexer warn("writev failed"); 619f032086dShshoexer ret = -1; 620f032086dShshoexer } else if (n != len) { 621f032086dShshoexer warnx("short write"); 622f032086dShshoexer ret = -1; 623f032086dShshoexer } 624f032086dShshoexer 625f032086dShshoexer return ret; 626f032086dShshoexer } 627f032086dShshoexer 628f032086dShshoexer static int 629a6bcba92Sbluhm pfkey_sabundle(int sd, u_int8_t satype, u_int8_t satype2, u_int8_t action, 6308065703bShshoexer struct ipsec_addr_wrap *dst, u_int32_t spi, struct ipsec_addr_wrap *dst2, 6318065703bShshoexer u_int32_t spi2) 6328f2109caShshoexer { 6338f2109caShshoexer struct sadb_msg smsg; 6348f2109caShshoexer struct sadb_sa sa1, sa2; 6358f2109caShshoexer struct sadb_address sa_dst, sa_dst2; 6368f2109caShshoexer struct sockaddr_storage sdst, sdst2; 6378f2109caShshoexer struct sadb_protocol sa_proto; 6388f2109caShshoexer struct iovec iov[IOV_CNT]; 6398f2109caShshoexer ssize_t n; 6408f2109caShshoexer int iov_cnt, len, ret = 0; 6418f2109caShshoexer 6428f2109caShshoexer bzero(&sdst, sizeof(sdst)); 6438f2109caShshoexer sdst.ss_family = dst->af; 6448f2109caShshoexer switch (dst->af) { 6458f2109caShshoexer case AF_INET: 6468f2109caShshoexer ((struct sockaddr_in *)&sdst)->sin_addr = dst->address.v4; 6478f2109caShshoexer sdst.ss_len = sizeof(struct sockaddr_in); 6488f2109caShshoexer break; 6498f2109caShshoexer case AF_INET6: 6508f2109caShshoexer ((struct sockaddr_in6 *)&sdst)->sin6_addr = dst->address.v6; 6518f2109caShshoexer sdst.ss_len = sizeof(struct sockaddr_in6); 6528f2109caShshoexer break; 6538f2109caShshoexer default: 6548f2109caShshoexer warnx("unsupported address family %d", dst->af); 6558f2109caShshoexer return -1; 6568f2109caShshoexer } 6578f2109caShshoexer 6588f2109caShshoexer bzero(&sdst2, sizeof(sdst2)); 6598f2109caShshoexer sdst2.ss_family = dst2->af; 6608f2109caShshoexer switch (dst2->af) { 6618f2109caShshoexer case AF_INET: 6628f2109caShshoexer ((struct sockaddr_in *)&sdst2)->sin_addr = dst2->address.v4; 6638f2109caShshoexer sdst2.ss_len = sizeof(struct sockaddr_in); 6648f2109caShshoexer break; 6658f2109caShshoexer case AF_INET6: 6668f2109caShshoexer ((struct sockaddr_in6 *)&sdst2)->sin6_addr = dst2->address.v6; 6678f2109caShshoexer sdst2.ss_len = sizeof(struct sockaddr_in6); 6688f2109caShshoexer break; 6698f2109caShshoexer default: 6708f2109caShshoexer warnx("unsupported address family %d", dst2->af); 6718f2109caShshoexer return -1; 6728f2109caShshoexer } 6738f2109caShshoexer 6748f2109caShshoexer bzero(&smsg, sizeof(smsg)); 6758f2109caShshoexer smsg.sadb_msg_version = PF_KEY_V2; 6768f2109caShshoexer smsg.sadb_msg_seq = sadb_msg_seq++; 6778f2109caShshoexer smsg.sadb_msg_pid = getpid(); 6788f2109caShshoexer smsg.sadb_msg_len = sizeof(smsg) / 8; 6798f2109caShshoexer smsg.sadb_msg_type = action; 6808f2109caShshoexer smsg.sadb_msg_satype = satype; 6818f2109caShshoexer 6828f2109caShshoexer bzero(&sa1, sizeof(sa1)); 6838f2109caShshoexer sa1.sadb_sa_len = sizeof(sa1) / 8; 6848f2109caShshoexer sa1.sadb_sa_exttype = SADB_EXT_SA; 6858f2109caShshoexer sa1.sadb_sa_spi = htonl(spi); 6868f2109caShshoexer sa1.sadb_sa_state = SADB_SASTATE_MATURE; 6878f2109caShshoexer 6888f2109caShshoexer bzero(&sa2, sizeof(sa2)); 6898f2109caShshoexer sa2.sadb_sa_len = sizeof(sa2) / 8; 6908f2109caShshoexer sa2.sadb_sa_exttype = SADB_X_EXT_SA2; 6918f2109caShshoexer sa2.sadb_sa_spi = htonl(spi2); 6928f2109caShshoexer sa2.sadb_sa_state = SADB_SASTATE_MATURE; 6938f2109caShshoexer iov_cnt = 0; 6948f2109caShshoexer 6958f2109caShshoexer bzero(&sa_dst, sizeof(sa_dst)); 6968f2109caShshoexer sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST; 6978f2109caShshoexer sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(sdst.ss_len)) / 8; 6988f2109caShshoexer 6998f2109caShshoexer bzero(&sa_dst2, sizeof(sa_dst2)); 7008f2109caShshoexer sa_dst2.sadb_address_exttype = SADB_X_EXT_DST2; 7018f2109caShshoexer sa_dst2.sadb_address_len = (sizeof(sa_dst2) + ROUNDUP(sdst2.ss_len)) / 8; 7028f2109caShshoexer 7038f2109caShshoexer bzero(&sa_proto, sizeof(sa_proto)); 704d44c51a1Sbluhm sa_proto.sadb_protocol_exttype = SADB_X_EXT_SATYPE2; 7058f2109caShshoexer sa_proto.sadb_protocol_len = sizeof(sa_proto) / 8; 7068f2109caShshoexer sa_proto.sadb_protocol_direction = 0; 7078065703bShshoexer sa_proto.sadb_protocol_proto = satype2; 7088f2109caShshoexer 7098f2109caShshoexer /* header */ 7108f2109caShshoexer iov[iov_cnt].iov_base = &smsg; 7118f2109caShshoexer iov[iov_cnt].iov_len = sizeof(smsg); 7128f2109caShshoexer iov_cnt++; 7138f2109caShshoexer 7148f2109caShshoexer /* sa */ 7158f2109caShshoexer iov[iov_cnt].iov_base = &sa1; 7168f2109caShshoexer iov[iov_cnt].iov_len = sizeof(sa1); 7178f2109caShshoexer smsg.sadb_msg_len += sa1.sadb_sa_len; 7188f2109caShshoexer iov_cnt++; 7198f2109caShshoexer 7208f2109caShshoexer /* dst addr */ 7218f2109caShshoexer iov[iov_cnt].iov_base = &sa_dst; 7228f2109caShshoexer iov[iov_cnt].iov_len = sizeof(sa_dst); 7238f2109caShshoexer iov_cnt++; 7248f2109caShshoexer iov[iov_cnt].iov_base = &sdst; 7258f2109caShshoexer iov[iov_cnt].iov_len = ROUNDUP(sdst.ss_len); 7268f2109caShshoexer smsg.sadb_msg_len += sa_dst.sadb_address_len; 7278f2109caShshoexer iov_cnt++; 7288f2109caShshoexer 7298f2109caShshoexer /* second sa */ 7308f2109caShshoexer iov[iov_cnt].iov_base = &sa2; 7318f2109caShshoexer iov[iov_cnt].iov_len = sizeof(sa2); 7328f2109caShshoexer smsg.sadb_msg_len += sa2.sadb_sa_len; 7338f2109caShshoexer iov_cnt++; 7348f2109caShshoexer 7358f2109caShshoexer /* second dst addr */ 7368f2109caShshoexer iov[iov_cnt].iov_base = &sa_dst2; 7378f2109caShshoexer iov[iov_cnt].iov_len = sizeof(sa_dst2); 7388f2109caShshoexer iov_cnt++; 7398f2109caShshoexer iov[iov_cnt].iov_base = &sdst2; 7408f2109caShshoexer iov[iov_cnt].iov_len = ROUNDUP(sdst2.ss_len); 7418f2109caShshoexer smsg.sadb_msg_len += sa_dst2.sadb_address_len; 7428f2109caShshoexer iov_cnt++; 7438f2109caShshoexer 7448f2109caShshoexer /* SA type */ 7458f2109caShshoexer iov[iov_cnt].iov_base = &sa_proto; 7468f2109caShshoexer iov[iov_cnt].iov_len = sizeof(sa_proto); 7478f2109caShshoexer smsg.sadb_msg_len += sa_proto.sadb_protocol_len; 7488f2109caShshoexer iov_cnt++; 7498f2109caShshoexer 7508f2109caShshoexer len = smsg.sadb_msg_len * 8; 7518f2109caShshoexer if ((n = writev(sd, iov, iov_cnt)) == -1) { 7528f2109caShshoexer warn("writev failed"); 7538f2109caShshoexer ret = -1; 7548f2109caShshoexer } else if (n != len) { 7558f2109caShshoexer warnx("short write"); 7568f2109caShshoexer ret = -1; 7578f2109caShshoexer } 7588f2109caShshoexer 7598f2109caShshoexer return (ret); 7608f2109caShshoexer } 7618f2109caShshoexer 7628f2109caShshoexer static int 7638a87fca6Smsf pfkey_reply(int sd, u_int8_t **datap, ssize_t *lenp) 764f484f2cfShshoexer { 765f484f2cfShshoexer struct sadb_msg hdr; 766f484f2cfShshoexer ssize_t len; 767f484f2cfShshoexer u_int8_t *data; 768f484f2cfShshoexer 769f484f2cfShshoexer if (recv(sd, &hdr, sizeof(hdr), MSG_PEEK) != sizeof(hdr)) { 770f484f2cfShshoexer warnx("short read"); 771f484f2cfShshoexer return -1; 772f484f2cfShshoexer } 773f484f2cfShshoexer len = hdr.sadb_msg_len * PFKEYV2_CHUNK; 774f484f2cfShshoexer if ((data = malloc(len)) == NULL) 775bd828a90Shshoexer err(1, "pfkey_reply: malloc"); 776f484f2cfShshoexer if (read(sd, data, len) != len) { 777f484f2cfShshoexer warn("PF_KEY short read"); 7781e82d711Sderaadt freezero(data, len); 779f484f2cfShshoexer return -1; 780f484f2cfShshoexer } 7818a87fca6Smsf if (datap) { 7828a87fca6Smsf *datap = data; 7838a87fca6Smsf if (lenp) 7848a87fca6Smsf *lenp = len; 7858a87fca6Smsf } else { 7861e82d711Sderaadt freezero(data, len); 7878a87fca6Smsf } 788011122f7Smarkus if (datap == NULL && hdr.sadb_msg_errno != 0) { 789011122f7Smarkus errno = hdr.sadb_msg_errno; 79092270c32Shshoexer if (errno != EEXIST) { 791011122f7Smarkus warn("PF_KEY failed"); 792011122f7Smarkus return -1; 793011122f7Smarkus } 79492270c32Shshoexer } 795f484f2cfShshoexer return 0; 796f484f2cfShshoexer } 797f484f2cfShshoexer 798f484f2cfShshoexer int 7991edc1b9aShshoexer pfkey_parse(struct sadb_msg *msg, struct ipsec_rule *rule) 8001edc1b9aShshoexer { 8011edc1b9aShshoexer struct sadb_ext *ext; 8021edc1b9aShshoexer struct sadb_address *saddr; 8031edc1b9aShshoexer struct sadb_protocol *sproto; 8041edc1b9aShshoexer struct sadb_ident *sident; 8051edc1b9aShshoexer struct sockaddr *sa; 806712e78baShshoexer struct sockaddr_in *sa_in; 8072099bcdfStodd struct sockaddr_in6 *sa_in6; 8081edc1b9aShshoexer int len; 8091edc1b9aShshoexer 8101edc1b9aShshoexer switch (msg->sadb_msg_satype) { 811b26a6cb5Shshoexer case SADB_SATYPE_ESP: 8129182219dSmarkus rule->satype = IPSEC_ESP; 8131edc1b9aShshoexer break; 814b26a6cb5Shshoexer case SADB_SATYPE_AH: 8159182219dSmarkus rule->satype = IPSEC_AH; 8161edc1b9aShshoexer break; 817b26a6cb5Shshoexer case SADB_X_SATYPE_IPCOMP: 8189182219dSmarkus rule->satype = IPSEC_IPCOMP; 819a29da9d0Shshoexer break; 82088a8cceeSmarkus case SADB_X_SATYPE_IPIP: 8219182219dSmarkus rule->satype = IPSEC_IPIP; 82288a8cceeSmarkus break; 8231edc1b9aShshoexer default: 8241edc1b9aShshoexer return (1); 8251edc1b9aShshoexer } 8261edc1b9aShshoexer 8271edc1b9aShshoexer for (ext = (struct sadb_ext *)(msg + 1); 8281edc1b9aShshoexer (size_t)((u_int8_t *)ext - (u_int8_t *)msg) < 829d5d1799eShshoexer msg->sadb_msg_len * PFKEYV2_CHUNK && ext->sadb_ext_len > 0; 8301edc1b9aShshoexer ext = (struct sadb_ext *)((u_int8_t *)ext + 8311edc1b9aShshoexer ext->sadb_ext_len * PFKEYV2_CHUNK)) { 8321edc1b9aShshoexer switch (ext->sadb_ext_type) { 8331edc1b9aShshoexer case SADB_EXT_ADDRESS_SRC: 8341edc1b9aShshoexer saddr = (struct sadb_address *)ext; 8351edc1b9aShshoexer sa = (struct sockaddr *)(saddr + 1); 8361edc1b9aShshoexer 83791f765ddShshoexer rule->local = calloc(1, sizeof(struct ipsec_addr_wrap)); 838d5d1799eShshoexer if (rule->local == NULL) 839a1059f6aStodd err(1, "pfkey_parse: calloc"); 8401edc1b9aShshoexer 8412099bcdfStodd rule->local->af = sa->sa_family; 8421edc1b9aShshoexer switch (sa->sa_family) { 8431edc1b9aShshoexer case AF_INET: 8441edc1b9aShshoexer bcopy(&((struct sockaddr_in *)sa)->sin_addr, 84591f765ddShshoexer &rule->local->address.v4, 846712e78baShshoexer sizeof(struct in_addr)); 8472099bcdfStodd set_ipmask(rule->local, 32); 8482099bcdfStodd break; 8492099bcdfStodd case AF_INET6: 8502099bcdfStodd bcopy(&((struct sockaddr_in6 *)sa)->sin6_addr, 8512099bcdfStodd &rule->local->address.v6, 8522099bcdfStodd sizeof(struct in6_addr)); 8532099bcdfStodd set_ipmask(rule->local, 128); 8541edc1b9aShshoexer break; 8551edc1b9aShshoexer default: 8561edc1b9aShshoexer return (1); 8571edc1b9aShshoexer } 8581edc1b9aShshoexer break; 8591edc1b9aShshoexer 8601edc1b9aShshoexer 8611edc1b9aShshoexer case SADB_EXT_ADDRESS_DST: 8621edc1b9aShshoexer saddr = (struct sadb_address *)ext; 8631edc1b9aShshoexer sa = (struct sockaddr *)(saddr + 1); 8641edc1b9aShshoexer 86591f765ddShshoexer rule->peer = calloc(1, sizeof(struct ipsec_addr_wrap)); 8661edc1b9aShshoexer if (rule->peer == NULL) 867a1059f6aStodd err(1, "pfkey_parse: calloc"); 8681edc1b9aShshoexer 8692099bcdfStodd rule->peer->af = sa->sa_family; 8701edc1b9aShshoexer switch (sa->sa_family) { 8711edc1b9aShshoexer case AF_INET: 8721edc1b9aShshoexer bcopy(&((struct sockaddr_in *)sa)->sin_addr, 873712e78baShshoexer &rule->peer->address.v4, 874712e78baShshoexer sizeof(struct in_addr)); 8752099bcdfStodd set_ipmask(rule->peer, 32); 8762099bcdfStodd break; 8772099bcdfStodd case AF_INET6: 8782099bcdfStodd bcopy(&((struct sockaddr_in6 *)sa)->sin6_addr, 8792099bcdfStodd &rule->peer->address.v6, 8802099bcdfStodd sizeof(struct in6_addr)); 8812099bcdfStodd set_ipmask(rule->peer, 128); 8821edc1b9aShshoexer break; 8831edc1b9aShshoexer default: 8841edc1b9aShshoexer return (1); 8851edc1b9aShshoexer } 8861edc1b9aShshoexer break; 8871edc1b9aShshoexer 8881edc1b9aShshoexer case SADB_EXT_IDENTITY_SRC: 8891edc1b9aShshoexer sident = (struct sadb_ident *)ext; 8901edc1b9aShshoexer len = (sident->sadb_ident_len * sizeof(uint64_t)) - 8911edc1b9aShshoexer sizeof(struct sadb_ident); 8921edc1b9aShshoexer 8939382ed8fShshoexer if (rule->auth == NULL) { 8949382ed8fShshoexer rule->auth = calloc(1, sizeof(struct 8959382ed8fShshoexer ipsec_auth)); 8969382ed8fShshoexer if (rule->auth == NULL) 897bd828a90Shshoexer err(1, "pfkey_parse: calloc"); 8989382ed8fShshoexer } 8999382ed8fShshoexer 900abe65127Shshoexer rule->auth->srcid = calloc(1, len); 901abe65127Shshoexer if (rule->auth->srcid == NULL) 902bd828a90Shshoexer err(1, "pfkey_parse: calloc"); 9031edc1b9aShshoexer 904abe65127Shshoexer strlcpy(rule->auth->srcid, (char *)(sident + 1), len); 9051edc1b9aShshoexer break; 9061edc1b9aShshoexer 9071edc1b9aShshoexer case SADB_EXT_IDENTITY_DST: 9081edc1b9aShshoexer sident = (struct sadb_ident *)ext; 9091edc1b9aShshoexer len = (sident->sadb_ident_len * sizeof(uint64_t)) - 9101edc1b9aShshoexer sizeof(struct sadb_ident); 9111edc1b9aShshoexer 9129382ed8fShshoexer if (rule->auth == NULL) { 9139382ed8fShshoexer rule->auth = calloc(1, sizeof(struct 9149382ed8fShshoexer ipsec_auth)); 9159382ed8fShshoexer if (rule->auth == NULL) 916bd828a90Shshoexer err(1, "pfkey_parse: calloc"); 9179382ed8fShshoexer } 9189382ed8fShshoexer 919abe65127Shshoexer rule->auth->dstid = calloc(1, len); 920abe65127Shshoexer if (rule->auth->dstid == NULL) 921bd828a90Shshoexer err(1, "pfkey_parse: calloc"); 9221edc1b9aShshoexer 923abe65127Shshoexer strlcpy(rule->auth->dstid, (char *)(sident + 1), len); 9241edc1b9aShshoexer break; 9251edc1b9aShshoexer 9261edc1b9aShshoexer case SADB_X_EXT_PROTOCOL: 9279182219dSmarkus sproto = (struct sadb_protocol *)ext; 9289182219dSmarkus if (sproto->sadb_protocol_direction == 0) 9299182219dSmarkus rule->proto = sproto->sadb_protocol_proto; 9301edc1b9aShshoexer break; 9311edc1b9aShshoexer 9321edc1b9aShshoexer case SADB_X_EXT_FLOW_TYPE: 9331edc1b9aShshoexer sproto = (struct sadb_protocol *)ext; 9341edc1b9aShshoexer 9351edc1b9aShshoexer switch (sproto->sadb_protocol_direction) { 9361edc1b9aShshoexer case IPSP_DIRECTION_IN: 9371edc1b9aShshoexer rule->direction = IPSEC_IN; 9381edc1b9aShshoexer break; 9391edc1b9aShshoexer case IPSP_DIRECTION_OUT: 9401edc1b9aShshoexer rule->direction = IPSEC_OUT; 9411edc1b9aShshoexer break; 9421edc1b9aShshoexer default: 9431edc1b9aShshoexer return (1); 9441edc1b9aShshoexer } 9456122c05eShshoexer switch (sproto->sadb_protocol_proto) { 9466122c05eShshoexer case SADB_X_FLOW_TYPE_USE: 9471a3f035aShshoexer rule->flowtype = TYPE_USE; 9486122c05eShshoexer break; 9496122c05eShshoexer case SADB_X_FLOW_TYPE_ACQUIRE: 9501a3f035aShshoexer rule->flowtype = TYPE_ACQUIRE; 9516122c05eShshoexer break; 9526122c05eShshoexer case SADB_X_FLOW_TYPE_REQUIRE: 9531a3f035aShshoexer rule->flowtype = TYPE_REQUIRE; 9546122c05eShshoexer break; 9556122c05eShshoexer case SADB_X_FLOW_TYPE_DENY: 9561a3f035aShshoexer rule->flowtype = TYPE_DENY; 9576122c05eShshoexer break; 9586122c05eShshoexer case SADB_X_FLOW_TYPE_BYPASS: 9591a3f035aShshoexer rule->flowtype = TYPE_BYPASS; 9606122c05eShshoexer break; 9616122c05eShshoexer case SADB_X_FLOW_TYPE_DONTACQ: 9621a3f035aShshoexer rule->flowtype = TYPE_DONTACQ; 9636122c05eShshoexer break; 9646122c05eShshoexer default: 9651a3f035aShshoexer rule->flowtype = TYPE_UNKNOWN; 9666122c05eShshoexer break; 9676122c05eShshoexer } 9681edc1b9aShshoexer break; 9691edc1b9aShshoexer 9701edc1b9aShshoexer case SADB_X_EXT_SRC_FLOW: 9711edc1b9aShshoexer saddr = (struct sadb_address *)ext; 9721edc1b9aShshoexer sa = (struct sockaddr *)(saddr + 1); 9731edc1b9aShshoexer 9741edc1b9aShshoexer if (rule->src == NULL) { 9751edc1b9aShshoexer rule->src = calloc(1, 97691f765ddShshoexer sizeof(struct ipsec_addr_wrap)); 9771edc1b9aShshoexer if (rule->src == NULL) 978bd828a90Shshoexer err(1, "pfkey_parse: calloc"); 9791edc1b9aShshoexer } 9801edc1b9aShshoexer 9812099bcdfStodd rule->src->af = sa->sa_family; 9821edc1b9aShshoexer switch (sa->sa_family) { 9831edc1b9aShshoexer case AF_INET: 9841edc1b9aShshoexer bcopy(&((struct sockaddr_in *)sa)->sin_addr, 985712e78baShshoexer &rule->src->address.v4, 986712e78baShshoexer sizeof(struct in_addr)); 98757f58d0dSnaddy rule->sport = 98857f58d0dSnaddy ((struct sockaddr_in *)sa)->sin_port; 9892099bcdfStodd break; 9902099bcdfStodd case AF_INET6: 9912099bcdfStodd bcopy(&((struct sockaddr_in6 *)sa)->sin6_addr, 9922099bcdfStodd &rule->src->address.v6, 9932099bcdfStodd sizeof(struct in6_addr)); 99457f58d0dSnaddy rule->sport = 99557f58d0dSnaddy ((struct sockaddr_in6 *)sa)->sin6_port; 9961edc1b9aShshoexer break; 9971edc1b9aShshoexer default: 9981edc1b9aShshoexer return (1); 9991edc1b9aShshoexer } 10001edc1b9aShshoexer break; 10011edc1b9aShshoexer 10021edc1b9aShshoexer case SADB_X_EXT_DST_FLOW: 10031edc1b9aShshoexer saddr = (struct sadb_address *)ext; 10041edc1b9aShshoexer sa = (struct sockaddr *)(saddr + 1); 10051edc1b9aShshoexer 10061edc1b9aShshoexer if (rule->dst == NULL) { 10071edc1b9aShshoexer rule->dst = calloc(1, 100891f765ddShshoexer sizeof(struct ipsec_addr_wrap)); 10091edc1b9aShshoexer if (rule->dst == NULL) 1010bd828a90Shshoexer err(1, "pfkey_parse: calloc"); 10111edc1b9aShshoexer } 10121edc1b9aShshoexer 10132099bcdfStodd rule->dst->af = sa->sa_family; 10141edc1b9aShshoexer switch (sa->sa_family) { 10151edc1b9aShshoexer case AF_INET: 10161edc1b9aShshoexer bcopy(&((struct sockaddr_in *)sa)->sin_addr, 1017712e78baShshoexer &rule->dst->address.v4, 1018712e78baShshoexer sizeof(struct in_addr)); 101957f58d0dSnaddy rule->dport = 102057f58d0dSnaddy ((struct sockaddr_in *)sa)->sin_port; 10211edc1b9aShshoexer break; 10222099bcdfStodd case AF_INET6: 10232099bcdfStodd bcopy(&((struct sockaddr_in6 *)sa)->sin6_addr, 10242099bcdfStodd &rule->dst->address.v6, 10252099bcdfStodd sizeof(struct in6_addr)); 102657f58d0dSnaddy rule->dport = 102757f58d0dSnaddy ((struct sockaddr_in6 *)sa)->sin6_port; 10282099bcdfStodd break; 10291edc1b9aShshoexer default: 10301edc1b9aShshoexer return (1); 10311edc1b9aShshoexer } 10321edc1b9aShshoexer break; 10331edc1b9aShshoexer 10341edc1b9aShshoexer 10351edc1b9aShshoexer case SADB_X_EXT_SRC_MASK: 10361edc1b9aShshoexer saddr = (struct sadb_address *)ext; 10371edc1b9aShshoexer sa = (struct sockaddr *)(saddr + 1); 10381edc1b9aShshoexer 10391edc1b9aShshoexer if (rule->src == NULL) { 10401edc1b9aShshoexer rule->src = calloc(1, 104191f765ddShshoexer sizeof(struct ipsec_addr_wrap)); 10421edc1b9aShshoexer if (rule->src == NULL) 1043bd828a90Shshoexer err(1, "pfkey_parse: calloc"); 10441edc1b9aShshoexer } 10451edc1b9aShshoexer 10462099bcdfStodd rule->src->af = sa->sa_family; 10471edc1b9aShshoexer switch (sa->sa_family) { 10481edc1b9aShshoexer case AF_INET: 1049712e78baShshoexer sa_in = (struct sockaddr_in *)sa; 1050712e78baShshoexer bcopy(&sa_in->sin_addr, &rule->src->mask.v4, 10511edc1b9aShshoexer sizeof(struct in_addr)); 10522099bcdfStodd break; 10532099bcdfStodd case AF_INET6: 10542099bcdfStodd sa_in6 = (struct sockaddr_in6 *)sa; 10552099bcdfStodd bcopy(&sa_in6->sin6_addr, &rule->src->mask.v6, 10562099bcdfStodd sizeof(struct in6_addr)); 10571edc1b9aShshoexer break; 10581edc1b9aShshoexer 10591edc1b9aShshoexer default: 10601edc1b9aShshoexer return (1); 10611edc1b9aShshoexer } 10621edc1b9aShshoexer break; 10631edc1b9aShshoexer 10641edc1b9aShshoexer case SADB_X_EXT_DST_MASK: 10651edc1b9aShshoexer saddr = (struct sadb_address *)ext; 10661edc1b9aShshoexer sa = (struct sockaddr *)(saddr + 1); 10671edc1b9aShshoexer 10681edc1b9aShshoexer if (rule->dst == NULL) { 10691edc1b9aShshoexer rule->dst = calloc(1, 107091f765ddShshoexer sizeof(struct ipsec_addr_wrap)); 10711edc1b9aShshoexer if (rule->dst == NULL) 1072bd828a90Shshoexer err(1, "pfkey_parse: calloc"); 10731edc1b9aShshoexer } 10741edc1b9aShshoexer 10752099bcdfStodd rule->dst->af = sa->sa_family; 10761edc1b9aShshoexer switch (sa->sa_family) { 10771edc1b9aShshoexer case AF_INET: 1078712e78baShshoexer sa_in = (struct sockaddr_in *)sa; 1079712e78baShshoexer bcopy(&sa_in->sin_addr, &rule->dst->mask.v4, 10801edc1b9aShshoexer sizeof(struct in_addr)); 10811edc1b9aShshoexer break; 10822099bcdfStodd case AF_INET6: 10832099bcdfStodd sa_in6 = (struct sockaddr_in6 *)sa; 10842099bcdfStodd bcopy(&sa_in6->sin6_addr, &rule->dst->mask.v6, 10852099bcdfStodd sizeof(struct in6_addr)); 10862099bcdfStodd break; 10871edc1b9aShshoexer default: 10881edc1b9aShshoexer return (1); 10891edc1b9aShshoexer } 10901edc1b9aShshoexer break; 10911edc1b9aShshoexer 10921edc1b9aShshoexer default: 10931edc1b9aShshoexer return (1); 10941edc1b9aShshoexer } 10951edc1b9aShshoexer } 10961edc1b9aShshoexer 10971edc1b9aShshoexer return (0); 10981edc1b9aShshoexer } 10991edc1b9aShshoexer 11001edc1b9aShshoexer int 1101356121f6Shshoexer pfkey_ipsec_establish(int action, struct ipsec_rule *r) 1102f484f2cfShshoexer { 110322a29ad6Shshoexer int ret; 11048065703bShshoexer u_int8_t satype, satype2, direction; 1105f484f2cfShshoexer 1106f032086dShshoexer if (r->type == RULE_FLOW) { 11079182219dSmarkus switch (r->satype) { 1108f484f2cfShshoexer case IPSEC_ESP: 1109f484f2cfShshoexer satype = SADB_SATYPE_ESP; 1110f484f2cfShshoexer break; 1111f484f2cfShshoexer case IPSEC_AH: 1112f484f2cfShshoexer satype = SADB_SATYPE_AH; 1113f484f2cfShshoexer break; 111472e25333Shshoexer case IPSEC_IPCOMP: 111572e25333Shshoexer satype = SADB_X_SATYPE_IPCOMP; 111672e25333Shshoexer break; 111788a8cceeSmarkus case IPSEC_IPIP: 111888a8cceeSmarkus satype = SADB_X_SATYPE_IPIP; 111988a8cceeSmarkus break; 1120f484f2cfShshoexer default: 1121f484f2cfShshoexer return -1; 1122f484f2cfShshoexer } 1123f484f2cfShshoexer 1124f484f2cfShshoexer switch (r->direction) { 1125f484f2cfShshoexer case IPSEC_IN: 1126f484f2cfShshoexer direction = IPSP_DIRECTION_IN; 1127f484f2cfShshoexer break; 1128f484f2cfShshoexer case IPSEC_OUT: 1129f484f2cfShshoexer direction = IPSP_DIRECTION_OUT; 1130f484f2cfShshoexer break; 1131f484f2cfShshoexer default: 1132f484f2cfShshoexer return -1; 1133f484f2cfShshoexer } 1134f484f2cfShshoexer 113522a29ad6Shshoexer switch (action) { 113690bd57a7Shshoexer case ACTION_ADD: 1137f032086dShshoexer ret = pfkey_flow(fd, satype, SADB_X_ADDFLOW, direction, 113857f58d0dSnaddy r->proto, r->src, r->sport, r->dst, r->dport, 113957f58d0dSnaddy r->local, r->peer, r->auth, r->flowtype); 114022a29ad6Shshoexer break; 114190bd57a7Shshoexer case ACTION_DELETE: 114222a29ad6Shshoexer /* No peer for flow deletion. */ 1143f032086dShshoexer ret = pfkey_flow(fd, satype, SADB_X_DELFLOW, direction, 114457f58d0dSnaddy r->proto, r->src, r->sport, r->dst, r->dport, 114557f58d0dSnaddy NULL, NULL, NULL, r->flowtype); 114622a29ad6Shshoexer break; 114722a29ad6Shshoexer default: 114822a29ad6Shshoexer return -1; 114922a29ad6Shshoexer } 1150f032086dShshoexer } else if (r->type == RULE_SA) { 11519182219dSmarkus switch (r->satype) { 1152881e2068Shshoexer case IPSEC_AH: 1153881e2068Shshoexer satype = SADB_SATYPE_AH; 1154881e2068Shshoexer break; 1155881e2068Shshoexer case IPSEC_ESP: 1156881e2068Shshoexer satype = SADB_SATYPE_ESP; 1157881e2068Shshoexer break; 115872e25333Shshoexer case IPSEC_IPCOMP: 115972e25333Shshoexer satype = SADB_X_SATYPE_IPCOMP; 116072e25333Shshoexer break; 1161381a2422Shshoexer case IPSEC_TCPMD5: 1162f032086dShshoexer satype = SADB_X_SATYPE_TCPSIGNATURE; 1163381a2422Shshoexer break; 116488a8cceeSmarkus case IPSEC_IPIP: 116588a8cceeSmarkus satype = SADB_X_SATYPE_IPIP; 116688a8cceeSmarkus break; 1167381a2422Shshoexer default: 1168381a2422Shshoexer return -1; 1169381a2422Shshoexer } 1170f032086dShshoexer switch (action) { 117190bd57a7Shshoexer case ACTION_ADD: 1172f032086dShshoexer ret = pfkey_sa(fd, satype, SADB_ADD, r->spi, 1173a38d220fShshoexer r->src, r->dst, r->xfs, r->authkey, r->enckey, 1174a38d220fShshoexer r->tmode); 1175f032086dShshoexer break; 117690bd57a7Shshoexer case ACTION_DELETE: 1177f032086dShshoexer ret = pfkey_sa(fd, satype, SADB_DELETE, r->spi, 1178a38d220fShshoexer r->src, r->dst, r->xfs, NULL, NULL, r->tmode); 1179f032086dShshoexer break; 1180f032086dShshoexer default: 1181f032086dShshoexer return -1; 1182f032086dShshoexer } 1183a6bcba92Sbluhm } else if (r->type == RULE_BUNDLE) { 11848f2109caShshoexer switch (r->satype) { 11858f2109caShshoexer case IPSEC_AH: 11868f2109caShshoexer satype = SADB_SATYPE_AH; 11878f2109caShshoexer break; 11888f2109caShshoexer case IPSEC_ESP: 11898f2109caShshoexer satype = SADB_SATYPE_ESP; 11908f2109caShshoexer break; 11918f2109caShshoexer case IPSEC_IPCOMP: 11928f2109caShshoexer satype = SADB_X_SATYPE_IPCOMP; 11938f2109caShshoexer break; 11948f2109caShshoexer case IPSEC_TCPMD5: 11958f2109caShshoexer satype = SADB_X_SATYPE_TCPSIGNATURE; 11968f2109caShshoexer break; 11978f2109caShshoexer case IPSEC_IPIP: 11988f2109caShshoexer satype = SADB_X_SATYPE_IPIP; 11998f2109caShshoexer break; 12008f2109caShshoexer default: 12018f2109caShshoexer return -1; 12028f2109caShshoexer } 12038065703bShshoexer switch (r->proto2) { 12048065703bShshoexer case IPSEC_AH: 12058065703bShshoexer satype2 = SADB_SATYPE_AH; 12068065703bShshoexer break; 12078065703bShshoexer case IPSEC_ESP: 12088065703bShshoexer satype2 = SADB_SATYPE_ESP; 12098065703bShshoexer break; 12108065703bShshoexer case IPSEC_IPCOMP: 12118065703bShshoexer satype2 = SADB_X_SATYPE_IPCOMP; 12128065703bShshoexer break; 12138065703bShshoexer case IPSEC_TCPMD5: 12148065703bShshoexer satype2 = SADB_X_SATYPE_TCPSIGNATURE; 12158065703bShshoexer break; 12168065703bShshoexer case IPSEC_IPIP: 12178065703bShshoexer satype2 = SADB_X_SATYPE_IPIP; 12188065703bShshoexer break; 12198065703bShshoexer default: 12208065703bShshoexer return -1; 12218065703bShshoexer } 12228f2109caShshoexer switch (action) { 12238f2109caShshoexer case ACTION_ADD: 1224a6bcba92Sbluhm ret = pfkey_sabundle(fd, satype, satype2, 12258065703bShshoexer SADB_X_GRPSPIS, r->dst, r->spi, r->dst2, r->spi2); 12268f2109caShshoexer break; 12278f2109caShshoexer case ACTION_DELETE: 12288f2109caShshoexer return 0; 12298f2109caShshoexer default: 12308f2109caShshoexer return -1; 12318f2109caShshoexer } 1232f032086dShshoexer } else 1233f032086dShshoexer return -1; 1234f032086dShshoexer 123522a29ad6Shshoexer if (ret < 0) 1236f484f2cfShshoexer return -1; 12378a87fca6Smsf if (pfkey_reply(fd, NULL, NULL) < 0) 1238f484f2cfShshoexer return -1; 1239f484f2cfShshoexer 1240f484f2cfShshoexer return 0; 1241f484f2cfShshoexer } 1242f484f2cfShshoexer 1243f484f2cfShshoexer int 1244f484f2cfShshoexer pfkey_ipsec_flush(void) 1245f484f2cfShshoexer { 1246f484f2cfShshoexer struct sadb_msg smsg; 1247f484f2cfShshoexer struct iovec iov[IOV_CNT]; 1248f484f2cfShshoexer ssize_t n; 1249f484f2cfShshoexer int iov_cnt, len; 1250f484f2cfShshoexer 1251f484f2cfShshoexer bzero(&smsg, sizeof(smsg)); 1252f484f2cfShshoexer smsg.sadb_msg_version = PF_KEY_V2; 1253f484f2cfShshoexer smsg.sadb_msg_seq = sadb_msg_seq++; 1254f484f2cfShshoexer smsg.sadb_msg_pid = getpid(); 1255f484f2cfShshoexer smsg.sadb_msg_len = sizeof(smsg) / 8; 1256f484f2cfShshoexer smsg.sadb_msg_type = SADB_FLUSH; 1257f484f2cfShshoexer smsg.sadb_msg_satype = SADB_SATYPE_UNSPEC; 1258f484f2cfShshoexer 1259f484f2cfShshoexer iov_cnt = 0; 1260f484f2cfShshoexer 1261f484f2cfShshoexer iov[iov_cnt].iov_base = &smsg; 1262f484f2cfShshoexer iov[iov_cnt].iov_len = sizeof(smsg); 1263f484f2cfShshoexer iov_cnt++; 1264f484f2cfShshoexer 1265f484f2cfShshoexer len = smsg.sadb_msg_len * 8; 1266f484f2cfShshoexer if ((n = writev(fd, iov, iov_cnt)) == -1) { 1267f484f2cfShshoexer warn("writev failed"); 1268f484f2cfShshoexer return -1; 1269f484f2cfShshoexer } 1270f484f2cfShshoexer if (n != len) { 1271f484f2cfShshoexer warnx("short write"); 1272f484f2cfShshoexer return -1; 1273f484f2cfShshoexer } 12748a87fca6Smsf if (pfkey_reply(fd, NULL, NULL) < 0) 1275f484f2cfShshoexer return -1; 1276f484f2cfShshoexer 1277f484f2cfShshoexer return 0; 1278f484f2cfShshoexer } 1279f484f2cfShshoexer 12808a87fca6Smsf static int 12818a87fca6Smsf pfkey_promisc(void) 12828a87fca6Smsf { 12838a87fca6Smsf struct sadb_msg msg; 12848a87fca6Smsf 12858a87fca6Smsf memset(&msg, 0, sizeof(msg)); 12868a87fca6Smsf msg.sadb_msg_version = PF_KEY_V2; 12878a87fca6Smsf msg.sadb_msg_seq = sadb_msg_seq++; 12888a87fca6Smsf msg.sadb_msg_pid = getpid(); 12898a87fca6Smsf msg.sadb_msg_len = sizeof(msg) / PFKEYV2_CHUNK; 12908a87fca6Smsf msg.sadb_msg_type = SADB_X_PROMISC; 12918a87fca6Smsf msg.sadb_msg_satype = 1; /* enable */ 12928a87fca6Smsf if (write(fd, &msg, sizeof(msg)) != sizeof(msg)) { 12938a87fca6Smsf warn("pfkey_promisc: write failed"); 12948a87fca6Smsf return -1; 12958a87fca6Smsf } 12968a87fca6Smsf if (pfkey_reply(fd, NULL, NULL) < 0) 12978a87fca6Smsf return -1; 12988a87fca6Smsf return 0; 12998a87fca6Smsf } 13008a87fca6Smsf 13018a87fca6Smsf int 13028a87fca6Smsf pfkey_monitor(int opts) 13038a87fca6Smsf { 130456232324Sderaadt struct pollfd pfd[1]; 13058a87fca6Smsf struct sadb_msg *msg; 130656232324Sderaadt u_int8_t *data; 130756232324Sderaadt ssize_t len; 13088a87fca6Smsf int n; 13098a87fca6Smsf 13108a87fca6Smsf if (pfkey_init() < 0) 13118a87fca6Smsf return -1; 13128a87fca6Smsf if (pfkey_promisc() < 0) 13138a87fca6Smsf return -1; 13148a87fca6Smsf 131556232324Sderaadt pfd[0].fd = fd; 131656232324Sderaadt pfd[0].events = POLLIN; 13178a87fca6Smsf for (;;) { 1318*df69c215Sderaadt if ((n = poll(pfd, 1, -1)) == -1) 131956232324Sderaadt err(2, "poll"); 13208a87fca6Smsf if (n == 0) 13218a87fca6Smsf break; 132256232324Sderaadt if ((pfd[0].revents & POLLIN) == 0) 13238a87fca6Smsf continue; 13248a87fca6Smsf if (pfkey_reply(fd, &data, &len) < 0) 13258a87fca6Smsf continue; 13268a87fca6Smsf msg = (struct sadb_msg *)data; 13278a87fca6Smsf if (msg->sadb_msg_type == SADB_X_PROMISC) { 13288a87fca6Smsf /* remove extra header from promisc messages */ 13298a87fca6Smsf if ((msg->sadb_msg_len * PFKEYV2_CHUNK) >= 13308a87fca6Smsf 2 * sizeof(struct sadb_msg)) { 13318a87fca6Smsf msg++; 13328a87fca6Smsf } 13338a87fca6Smsf } 13348a87fca6Smsf pfkey_monitor_sa(msg, opts); 13358a87fca6Smsf if (opts & IPSECCTL_OPT_VERBOSE) 13368a87fca6Smsf pfkey_print_raw(data, len); 13371e82d711Sderaadt freezero(data, len); 13388a87fca6Smsf } 13398a87fca6Smsf close(fd); 13408a87fca6Smsf return 0; 13418a87fca6Smsf } 13428a87fca6Smsf 1343f484f2cfShshoexer int 1344f484f2cfShshoexer pfkey_init(void) 1345f484f2cfShshoexer { 1346f484f2cfShshoexer if ((fd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) == -1) 1347bd828a90Shshoexer err(1, "pfkey_init: failed to open PF_KEY socket"); 1348f484f2cfShshoexer 1349f484f2cfShshoexer return 0; 1350f484f2cfShshoexer } 1351