1*783454c1Smikeb /* $OpenBSD: pfkey.c,v 1.50 2010/09/22 14:04:09 mikeb 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: 491*783454c1Smikeb case ENCXF_AES_128: 492*783454c1Smikeb case ENCXF_AES_192: 493*783454c1Smikeb case ENCXF_AES_256: 494881e2068Shshoexer sa.sadb_sa_encrypt = SADB_X_EALG_AES; 495881e2068Shshoexer break; 496881e2068Shshoexer case ENCXF_AESCTR: 497881e2068Shshoexer sa.sadb_sa_encrypt = SADB_X_EALG_AESCTR; 498881e2068Shshoexer break; 499*783454c1Smikeb case ENCXF_AES_128_GCM: 500*783454c1Smikeb case ENCXF_AES_192_GCM: 501*783454c1Smikeb case ENCXF_AES_256_GCM: 502*783454c1Smikeb sa.sadb_sa_encrypt = SADB_X_EALG_AESGCM16; 503*783454c1Smikeb break; 504*783454c1Smikeb case ENCXF_AES_128_GMAC: 505*783454c1Smikeb case ENCXF_AES_192_GMAC: 506*783454c1Smikeb case ENCXF_AES_256_GMAC: 507*783454c1Smikeb sa.sadb_sa_encrypt = SADB_X_EALG_AESGMAC; 508*783454c1Smikeb break; 509881e2068Shshoexer case ENCXF_BLOWFISH: 510881e2068Shshoexer sa.sadb_sa_encrypt = SADB_X_EALG_BLF; 511881e2068Shshoexer break; 512881e2068Shshoexer case ENCXF_CAST128: 513881e2068Shshoexer sa.sadb_sa_encrypt = SADB_X_EALG_CAST; 514881e2068Shshoexer break; 515881e2068Shshoexer case ENCXF_NULL: 516881e2068Shshoexer sa.sadb_sa_encrypt = SADB_EALG_NULL; 517881e2068Shshoexer break; 518881e2068Shshoexer case ENCXF_SKIPJACK: 519881e2068Shshoexer sa.sadb_sa_encrypt = SADB_X_EALG_SKIPJACK; 520881e2068Shshoexer break; 521881e2068Shshoexer default: 522375db29dShshoexer warnx("unsupported encryption algorithm %d", 523375db29dShshoexer xfs->encxf->id); 524881e2068Shshoexer } 525881e2068Shshoexer } 52672e25333Shshoexer if (xfs && xfs->compxf) { 52772e25333Shshoexer switch (xfs->compxf->id) { 52872e25333Shshoexer case COMPXF_DEFLATE: 52972e25333Shshoexer sa.sadb_sa_encrypt = SADB_X_CALG_DEFLATE; 53072e25333Shshoexer break; 53172e25333Shshoexer case COMPXF_LZS: 53272e25333Shshoexer sa.sadb_sa_encrypt = SADB_X_CALG_LZS; 53372e25333Shshoexer break; 53472e25333Shshoexer default: 53572e25333Shshoexer warnx("unsupported compression algorithm %d", 53672e25333Shshoexer xfs->compxf->id); 53772e25333Shshoexer } 53872e25333Shshoexer } 539881e2068Shshoexer 540f032086dShshoexer bzero(&sa_src, sizeof(sa_src)); 541f032086dShshoexer sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(ssrc.ss_len)) / 8; 542f032086dShshoexer sa_src.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; 543f032086dShshoexer 544f032086dShshoexer bzero(&sa_dst, sizeof(sa_dst)); 545f032086dShshoexer sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(sdst.ss_len)) / 8; 546f032086dShshoexer sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST; 547f032086dShshoexer 54872e25333Shshoexer if (action == SADB_ADD && !authkey && !enckey && satype != 54988a8cceeSmarkus SADB_X_SATYPE_IPCOMP && satype != SADB_X_SATYPE_IPIP) { /* XXX ENCNULL */ 5500813ab45Shshoexer warnx("no key specified"); 5510813ab45Shshoexer return -1; 5520813ab45Shshoexer } 553881e2068Shshoexer if (authkey) { 554881e2068Shshoexer bzero(&sa_authkey, sizeof(sa_authkey)); 555881e2068Shshoexer sa_authkey.sadb_key_len = (sizeof(sa_authkey) + 556881e2068Shshoexer ((authkey->len + 7) / 8) * 8) / 8; 557881e2068Shshoexer sa_authkey.sadb_key_exttype = SADB_EXT_KEY_AUTH; 558881e2068Shshoexer sa_authkey.sadb_key_bits = 8 * authkey->len; 559881e2068Shshoexer } 560881e2068Shshoexer if (enckey) { 561881e2068Shshoexer bzero(&sa_enckey, sizeof(sa_enckey)); 562881e2068Shshoexer sa_enckey.sadb_key_len = (sizeof(sa_enckey) + 563881e2068Shshoexer ((enckey->len + 7) / 8) * 8) / 8; 564881e2068Shshoexer sa_enckey.sadb_key_exttype = SADB_EXT_KEY_ENCRYPT; 565881e2068Shshoexer sa_enckey.sadb_key_bits = 8 * enckey->len; 566f032086dShshoexer } 567f032086dShshoexer 568f032086dShshoexer iov_cnt = 0; 569f032086dShshoexer 570f032086dShshoexer /* header */ 571f032086dShshoexer iov[iov_cnt].iov_base = &smsg; 572f032086dShshoexer iov[iov_cnt].iov_len = sizeof(smsg); 573f032086dShshoexer iov_cnt++; 574f032086dShshoexer 575f032086dShshoexer /* sa */ 576f032086dShshoexer iov[iov_cnt].iov_base = &sa; 577f032086dShshoexer iov[iov_cnt].iov_len = sizeof(sa); 578f032086dShshoexer smsg.sadb_msg_len += sa.sadb_sa_len; 579f032086dShshoexer iov_cnt++; 580f032086dShshoexer 581f032086dShshoexer /* src addr */ 582f032086dShshoexer iov[iov_cnt].iov_base = &sa_src; 583f032086dShshoexer iov[iov_cnt].iov_len = sizeof(sa_src); 584f032086dShshoexer iov_cnt++; 585f032086dShshoexer iov[iov_cnt].iov_base = &ssrc; 586f032086dShshoexer iov[iov_cnt].iov_len = ROUNDUP(ssrc.ss_len); 587f032086dShshoexer smsg.sadb_msg_len += sa_src.sadb_address_len; 588f032086dShshoexer iov_cnt++; 589f032086dShshoexer 590f032086dShshoexer /* dst addr */ 591f032086dShshoexer iov[iov_cnt].iov_base = &sa_dst; 592f032086dShshoexer iov[iov_cnt].iov_len = sizeof(sa_dst); 593f032086dShshoexer iov_cnt++; 594f032086dShshoexer iov[iov_cnt].iov_base = &sdst; 595f032086dShshoexer iov[iov_cnt].iov_len = ROUNDUP(sdst.ss_len); 596f032086dShshoexer smsg.sadb_msg_len += sa_dst.sadb_address_len; 597f032086dShshoexer iov_cnt++; 598f032086dShshoexer 599881e2068Shshoexer if (authkey) { 600881e2068Shshoexer /* authentication key */ 601881e2068Shshoexer iov[iov_cnt].iov_base = &sa_authkey; 602881e2068Shshoexer iov[iov_cnt].iov_len = sizeof(sa_authkey); 603f032086dShshoexer iov_cnt++; 604881e2068Shshoexer iov[iov_cnt].iov_base = authkey->data; 605881e2068Shshoexer iov[iov_cnt].iov_len = ((authkey->len + 7) / 8) * 8; 606881e2068Shshoexer smsg.sadb_msg_len += sa_authkey.sadb_key_len; 607881e2068Shshoexer iov_cnt++; 608881e2068Shshoexer } 609881e2068Shshoexer if (enckey) { 610881e2068Shshoexer /* encryption key */ 611881e2068Shshoexer iov[iov_cnt].iov_base = &sa_enckey; 612881e2068Shshoexer iov[iov_cnt].iov_len = sizeof(sa_enckey); 613881e2068Shshoexer iov_cnt++; 614881e2068Shshoexer iov[iov_cnt].iov_base = enckey->data; 615881e2068Shshoexer iov[iov_cnt].iov_len = ((enckey->len + 7) / 8) * 8; 616881e2068Shshoexer smsg.sadb_msg_len += sa_enckey.sadb_key_len; 617f032086dShshoexer iov_cnt++; 618f032086dShshoexer } 619f032086dShshoexer 620f032086dShshoexer len = smsg.sadb_msg_len * 8; 621f032086dShshoexer if ((n = writev(sd, iov, iov_cnt)) == -1) { 622f032086dShshoexer warn("writev failed"); 623f032086dShshoexer ret = -1; 624f032086dShshoexer } else if (n != len) { 625f032086dShshoexer warnx("short write"); 626f032086dShshoexer ret = -1; 627f032086dShshoexer } 628f032086dShshoexer 629f032086dShshoexer return ret; 630f032086dShshoexer } 631f032086dShshoexer 632f032086dShshoexer static int 6338065703bShshoexer pfkey_sagroup(int sd, u_int8_t satype, u_int8_t satype2, u_int8_t action, 6348065703bShshoexer struct ipsec_addr_wrap *dst, u_int32_t spi, struct ipsec_addr_wrap *dst2, 6358065703bShshoexer u_int32_t spi2) 6368f2109caShshoexer { 6378f2109caShshoexer struct sadb_msg smsg; 6388f2109caShshoexer struct sadb_sa sa1, sa2; 6398f2109caShshoexer struct sadb_address sa_dst, sa_dst2; 6408f2109caShshoexer struct sockaddr_storage sdst, sdst2; 6418f2109caShshoexer struct sadb_protocol sa_proto; 6428f2109caShshoexer struct iovec iov[IOV_CNT]; 6438f2109caShshoexer ssize_t n; 6448f2109caShshoexer int iov_cnt, len, ret = 0; 6458f2109caShshoexer 6468f2109caShshoexer bzero(&sdst, sizeof(sdst)); 6478f2109caShshoexer sdst.ss_family = dst->af; 6488f2109caShshoexer switch (dst->af) { 6498f2109caShshoexer case AF_INET: 6508f2109caShshoexer ((struct sockaddr_in *)&sdst)->sin_addr = dst->address.v4; 6518f2109caShshoexer sdst.ss_len = sizeof(struct sockaddr_in); 6528f2109caShshoexer break; 6538f2109caShshoexer case AF_INET6: 6548f2109caShshoexer ((struct sockaddr_in6 *)&sdst)->sin6_addr = dst->address.v6; 6558f2109caShshoexer sdst.ss_len = sizeof(struct sockaddr_in6); 6568f2109caShshoexer break; 6578f2109caShshoexer default: 6588f2109caShshoexer warnx("unsupported address family %d", dst->af); 6598f2109caShshoexer return -1; 6608f2109caShshoexer } 6618f2109caShshoexer 6628f2109caShshoexer bzero(&sdst2, sizeof(sdst2)); 6638f2109caShshoexer sdst2.ss_family = dst2->af; 6648f2109caShshoexer switch (dst2->af) { 6658f2109caShshoexer case AF_INET: 6668f2109caShshoexer ((struct sockaddr_in *)&sdst2)->sin_addr = dst2->address.v4; 6678f2109caShshoexer sdst2.ss_len = sizeof(struct sockaddr_in); 6688f2109caShshoexer break; 6698f2109caShshoexer case AF_INET6: 6708f2109caShshoexer ((struct sockaddr_in6 *)&sdst2)->sin6_addr = dst2->address.v6; 6718f2109caShshoexer sdst2.ss_len = sizeof(struct sockaddr_in6); 6728f2109caShshoexer break; 6738f2109caShshoexer default: 6748f2109caShshoexer warnx("unsupported address family %d", dst2->af); 6758f2109caShshoexer return -1; 6768f2109caShshoexer } 6778f2109caShshoexer 6788f2109caShshoexer bzero(&smsg, sizeof(smsg)); 6798f2109caShshoexer smsg.sadb_msg_version = PF_KEY_V2; 6808f2109caShshoexer smsg.sadb_msg_seq = sadb_msg_seq++; 6818f2109caShshoexer smsg.sadb_msg_pid = getpid(); 6828f2109caShshoexer smsg.sadb_msg_len = sizeof(smsg) / 8; 6838f2109caShshoexer smsg.sadb_msg_type = action; 6848f2109caShshoexer smsg.sadb_msg_satype = satype; 6858f2109caShshoexer 6868f2109caShshoexer bzero(&sa1, sizeof(sa1)); 6878f2109caShshoexer sa1.sadb_sa_len = sizeof(sa1) / 8; 6888f2109caShshoexer sa1.sadb_sa_exttype = SADB_EXT_SA; 6898f2109caShshoexer sa1.sadb_sa_spi = htonl(spi); 6908f2109caShshoexer sa1.sadb_sa_state = SADB_SASTATE_MATURE; 6918f2109caShshoexer 6928f2109caShshoexer bzero(&sa2, sizeof(sa2)); 6938f2109caShshoexer sa2.sadb_sa_len = sizeof(sa2) / 8; 6948f2109caShshoexer sa2.sadb_sa_exttype = SADB_X_EXT_SA2; 6958f2109caShshoexer sa2.sadb_sa_spi = htonl(spi2); 6968f2109caShshoexer sa2.sadb_sa_state = SADB_SASTATE_MATURE; 6978f2109caShshoexer iov_cnt = 0; 6988f2109caShshoexer 6998f2109caShshoexer bzero(&sa_dst, sizeof(sa_dst)); 7008f2109caShshoexer sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST; 7018f2109caShshoexer sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(sdst.ss_len)) / 8; 7028f2109caShshoexer 7038f2109caShshoexer bzero(&sa_dst2, sizeof(sa_dst2)); 7048f2109caShshoexer sa_dst2.sadb_address_exttype = SADB_X_EXT_DST2; 7058f2109caShshoexer sa_dst2.sadb_address_len = (sizeof(sa_dst2) + ROUNDUP(sdst2.ss_len)) / 8; 7068f2109caShshoexer 7078f2109caShshoexer bzero(&sa_proto, sizeof(sa_proto)); 7088f2109caShshoexer sa_proto.sadb_protocol_exttype = SADB_X_EXT_PROTOCOL; 7098f2109caShshoexer sa_proto.sadb_protocol_len = sizeof(sa_proto) / 8; 7108f2109caShshoexer sa_proto.sadb_protocol_direction = 0; 7118065703bShshoexer sa_proto.sadb_protocol_proto = satype2; 7128f2109caShshoexer 7138f2109caShshoexer /* header */ 7148f2109caShshoexer iov[iov_cnt].iov_base = &smsg; 7158f2109caShshoexer iov[iov_cnt].iov_len = sizeof(smsg); 7168f2109caShshoexer iov_cnt++; 7178f2109caShshoexer 7188f2109caShshoexer /* sa */ 7198f2109caShshoexer iov[iov_cnt].iov_base = &sa1; 7208f2109caShshoexer iov[iov_cnt].iov_len = sizeof(sa1); 7218f2109caShshoexer smsg.sadb_msg_len += sa1.sadb_sa_len; 7228f2109caShshoexer iov_cnt++; 7238f2109caShshoexer 7248f2109caShshoexer /* dst addr */ 7258f2109caShshoexer iov[iov_cnt].iov_base = &sa_dst; 7268f2109caShshoexer iov[iov_cnt].iov_len = sizeof(sa_dst); 7278f2109caShshoexer iov_cnt++; 7288f2109caShshoexer iov[iov_cnt].iov_base = &sdst; 7298f2109caShshoexer iov[iov_cnt].iov_len = ROUNDUP(sdst.ss_len); 7308f2109caShshoexer smsg.sadb_msg_len += sa_dst.sadb_address_len; 7318f2109caShshoexer iov_cnt++; 7328f2109caShshoexer 7338f2109caShshoexer /* second sa */ 7348f2109caShshoexer iov[iov_cnt].iov_base = &sa2; 7358f2109caShshoexer iov[iov_cnt].iov_len = sizeof(sa2); 7368f2109caShshoexer smsg.sadb_msg_len += sa2.sadb_sa_len; 7378f2109caShshoexer iov_cnt++; 7388f2109caShshoexer 7398f2109caShshoexer /* second dst addr */ 7408f2109caShshoexer iov[iov_cnt].iov_base = &sa_dst2; 7418f2109caShshoexer iov[iov_cnt].iov_len = sizeof(sa_dst2); 7428f2109caShshoexer iov_cnt++; 7438f2109caShshoexer iov[iov_cnt].iov_base = &sdst2; 7448f2109caShshoexer iov[iov_cnt].iov_len = ROUNDUP(sdst2.ss_len); 7458f2109caShshoexer smsg.sadb_msg_len += sa_dst2.sadb_address_len; 7468f2109caShshoexer iov_cnt++; 7478f2109caShshoexer 7488f2109caShshoexer /* SA type */ 7498f2109caShshoexer iov[iov_cnt].iov_base = &sa_proto; 7508f2109caShshoexer iov[iov_cnt].iov_len = sizeof(sa_proto); 7518f2109caShshoexer smsg.sadb_msg_len += sa_proto.sadb_protocol_len; 7528f2109caShshoexer iov_cnt++; 7538f2109caShshoexer 7548f2109caShshoexer len = smsg.sadb_msg_len * 8; 7558f2109caShshoexer if ((n = writev(sd, iov, iov_cnt)) == -1) { 7568f2109caShshoexer warn("writev failed"); 7578f2109caShshoexer ret = -1; 7588f2109caShshoexer } else if (n != len) { 7598f2109caShshoexer warnx("short write"); 7608f2109caShshoexer ret = -1; 7618f2109caShshoexer } 7628f2109caShshoexer 7638f2109caShshoexer return (ret); 7648f2109caShshoexer } 7658f2109caShshoexer 7668f2109caShshoexer static int 7678a87fca6Smsf pfkey_reply(int sd, u_int8_t **datap, ssize_t *lenp) 768f484f2cfShshoexer { 769f484f2cfShshoexer struct sadb_msg hdr; 770f484f2cfShshoexer ssize_t len; 771f484f2cfShshoexer u_int8_t *data; 772f484f2cfShshoexer 773f484f2cfShshoexer if (recv(sd, &hdr, sizeof(hdr), MSG_PEEK) != sizeof(hdr)) { 774f484f2cfShshoexer warnx("short read"); 775f484f2cfShshoexer return -1; 776f484f2cfShshoexer } 777f484f2cfShshoexer len = hdr.sadb_msg_len * PFKEYV2_CHUNK; 778f484f2cfShshoexer if ((data = malloc(len)) == NULL) 779bd828a90Shshoexer err(1, "pfkey_reply: malloc"); 780f484f2cfShshoexer if (read(sd, data, len) != len) { 781f484f2cfShshoexer warn("PF_KEY short read"); 782f484f2cfShshoexer bzero(data, len); 783f484f2cfShshoexer free(data); 784f484f2cfShshoexer return -1; 785f484f2cfShshoexer } 7868a87fca6Smsf if (datap) { 7878a87fca6Smsf *datap = data; 7888a87fca6Smsf if (lenp) 7898a87fca6Smsf *lenp = len; 7908a87fca6Smsf } else { 791f484f2cfShshoexer bzero(data, len); 792f484f2cfShshoexer free(data); 7938a87fca6Smsf } 794011122f7Smarkus if (datap == NULL && hdr.sadb_msg_errno != 0) { 795011122f7Smarkus errno = hdr.sadb_msg_errno; 79692270c32Shshoexer if (errno != EEXIST) { 797011122f7Smarkus warn("PF_KEY failed"); 798011122f7Smarkus return -1; 799011122f7Smarkus } 80092270c32Shshoexer } 801f484f2cfShshoexer return 0; 802f484f2cfShshoexer } 803f484f2cfShshoexer 804f484f2cfShshoexer int 8051edc1b9aShshoexer pfkey_parse(struct sadb_msg *msg, struct ipsec_rule *rule) 8061edc1b9aShshoexer { 8071edc1b9aShshoexer struct sadb_ext *ext; 8081edc1b9aShshoexer struct sadb_address *saddr; 8091edc1b9aShshoexer struct sadb_protocol *sproto; 8101edc1b9aShshoexer struct sadb_ident *sident; 8111edc1b9aShshoexer struct sockaddr *sa; 812712e78baShshoexer struct sockaddr_in *sa_in; 8132099bcdfStodd struct sockaddr_in6 *sa_in6; 8141edc1b9aShshoexer int len; 8151edc1b9aShshoexer 8161edc1b9aShshoexer switch (msg->sadb_msg_satype) { 817b26a6cb5Shshoexer case SADB_SATYPE_ESP: 8189182219dSmarkus rule->satype = IPSEC_ESP; 8191edc1b9aShshoexer break; 820b26a6cb5Shshoexer case SADB_SATYPE_AH: 8219182219dSmarkus rule->satype = IPSEC_AH; 8221edc1b9aShshoexer break; 823b26a6cb5Shshoexer case SADB_X_SATYPE_IPCOMP: 8249182219dSmarkus rule->satype = IPSEC_IPCOMP; 825a29da9d0Shshoexer break; 82688a8cceeSmarkus case SADB_X_SATYPE_IPIP: 8279182219dSmarkus rule->satype = IPSEC_IPIP; 82888a8cceeSmarkus break; 8291edc1b9aShshoexer default: 8301edc1b9aShshoexer return (1); 8311edc1b9aShshoexer } 8321edc1b9aShshoexer 8331edc1b9aShshoexer for (ext = (struct sadb_ext *)(msg + 1); 8341edc1b9aShshoexer (size_t)((u_int8_t *)ext - (u_int8_t *)msg) < 835d5d1799eShshoexer msg->sadb_msg_len * PFKEYV2_CHUNK && ext->sadb_ext_len > 0; 8361edc1b9aShshoexer ext = (struct sadb_ext *)((u_int8_t *)ext + 8371edc1b9aShshoexer ext->sadb_ext_len * PFKEYV2_CHUNK)) { 8381edc1b9aShshoexer switch (ext->sadb_ext_type) { 8391edc1b9aShshoexer case SADB_EXT_ADDRESS_SRC: 8401edc1b9aShshoexer saddr = (struct sadb_address *)ext; 8411edc1b9aShshoexer sa = (struct sockaddr *)(saddr + 1); 8421edc1b9aShshoexer 84391f765ddShshoexer rule->local = calloc(1, sizeof(struct ipsec_addr_wrap)); 844d5d1799eShshoexer if (rule->local == NULL) 845a1059f6aStodd err(1, "pfkey_parse: calloc"); 8461edc1b9aShshoexer 8472099bcdfStodd rule->local->af = sa->sa_family; 8481edc1b9aShshoexer switch (sa->sa_family) { 8491edc1b9aShshoexer case AF_INET: 8501edc1b9aShshoexer bcopy(&((struct sockaddr_in *)sa)->sin_addr, 85191f765ddShshoexer &rule->local->address.v4, 852712e78baShshoexer sizeof(struct in_addr)); 8532099bcdfStodd set_ipmask(rule->local, 32); 8542099bcdfStodd break; 8552099bcdfStodd case AF_INET6: 8562099bcdfStodd bcopy(&((struct sockaddr_in6 *)sa)->sin6_addr, 8572099bcdfStodd &rule->local->address.v6, 8582099bcdfStodd sizeof(struct in6_addr)); 8592099bcdfStodd set_ipmask(rule->local, 128); 8601edc1b9aShshoexer break; 8611edc1b9aShshoexer default: 8621edc1b9aShshoexer return (1); 8631edc1b9aShshoexer } 8641edc1b9aShshoexer break; 8651edc1b9aShshoexer 8661edc1b9aShshoexer 8671edc1b9aShshoexer case SADB_EXT_ADDRESS_DST: 8681edc1b9aShshoexer saddr = (struct sadb_address *)ext; 8691edc1b9aShshoexer sa = (struct sockaddr *)(saddr + 1); 8701edc1b9aShshoexer 87191f765ddShshoexer rule->peer = calloc(1, sizeof(struct ipsec_addr_wrap)); 8721edc1b9aShshoexer if (rule->peer == NULL) 873a1059f6aStodd err(1, "pfkey_parse: calloc"); 8741edc1b9aShshoexer 8752099bcdfStodd rule->peer->af = sa->sa_family; 8761edc1b9aShshoexer switch (sa->sa_family) { 8771edc1b9aShshoexer case AF_INET: 8781edc1b9aShshoexer bcopy(&((struct sockaddr_in *)sa)->sin_addr, 879712e78baShshoexer &rule->peer->address.v4, 880712e78baShshoexer sizeof(struct in_addr)); 8812099bcdfStodd set_ipmask(rule->peer, 32); 8822099bcdfStodd break; 8832099bcdfStodd case AF_INET6: 8842099bcdfStodd bcopy(&((struct sockaddr_in6 *)sa)->sin6_addr, 8852099bcdfStodd &rule->peer->address.v6, 8862099bcdfStodd sizeof(struct in6_addr)); 8872099bcdfStodd set_ipmask(rule->peer, 128); 8881edc1b9aShshoexer break; 8891edc1b9aShshoexer default: 8901edc1b9aShshoexer return (1); 8911edc1b9aShshoexer } 8921edc1b9aShshoexer break; 8931edc1b9aShshoexer 8941edc1b9aShshoexer case SADB_EXT_IDENTITY_SRC: 8951edc1b9aShshoexer sident = (struct sadb_ident *)ext; 8961edc1b9aShshoexer len = (sident->sadb_ident_len * sizeof(uint64_t)) - 8971edc1b9aShshoexer sizeof(struct sadb_ident); 8981edc1b9aShshoexer 8999382ed8fShshoexer if (rule->auth == NULL) { 9009382ed8fShshoexer rule->auth = calloc(1, sizeof(struct 9019382ed8fShshoexer ipsec_auth)); 9029382ed8fShshoexer if (rule->auth == NULL) 903bd828a90Shshoexer err(1, "pfkey_parse: calloc"); 9049382ed8fShshoexer } 9059382ed8fShshoexer 906abe65127Shshoexer rule->auth->srcid = calloc(1, len); 907abe65127Shshoexer if (rule->auth->srcid == NULL) 908bd828a90Shshoexer err(1, "pfkey_parse: calloc"); 9091edc1b9aShshoexer 910abe65127Shshoexer strlcpy(rule->auth->srcid, (char *)(sident + 1), len); 9111edc1b9aShshoexer break; 9121edc1b9aShshoexer 9131edc1b9aShshoexer case SADB_EXT_IDENTITY_DST: 9141edc1b9aShshoexer sident = (struct sadb_ident *)ext; 9151edc1b9aShshoexer len = (sident->sadb_ident_len * sizeof(uint64_t)) - 9161edc1b9aShshoexer sizeof(struct sadb_ident); 9171edc1b9aShshoexer 9189382ed8fShshoexer if (rule->auth == NULL) { 9199382ed8fShshoexer rule->auth = calloc(1, sizeof(struct 9209382ed8fShshoexer ipsec_auth)); 9219382ed8fShshoexer if (rule->auth == NULL) 922bd828a90Shshoexer err(1, "pfkey_parse: calloc"); 9239382ed8fShshoexer } 9249382ed8fShshoexer 925abe65127Shshoexer rule->auth->dstid = calloc(1, len); 926abe65127Shshoexer if (rule->auth->dstid == NULL) 927bd828a90Shshoexer err(1, "pfkey_parse: calloc"); 9281edc1b9aShshoexer 929abe65127Shshoexer strlcpy(rule->auth->dstid, (char *)(sident + 1), len); 9301edc1b9aShshoexer break; 9311edc1b9aShshoexer 9321edc1b9aShshoexer case SADB_X_EXT_PROTOCOL: 9339182219dSmarkus sproto = (struct sadb_protocol *)ext; 9349182219dSmarkus if (sproto->sadb_protocol_direction == 0) 9359182219dSmarkus rule->proto = sproto->sadb_protocol_proto; 9361edc1b9aShshoexer break; 9371edc1b9aShshoexer 9381edc1b9aShshoexer case SADB_X_EXT_FLOW_TYPE: 9391edc1b9aShshoexer sproto = (struct sadb_protocol *)ext; 9401edc1b9aShshoexer 9411edc1b9aShshoexer switch (sproto->sadb_protocol_direction) { 9421edc1b9aShshoexer case IPSP_DIRECTION_IN: 9431edc1b9aShshoexer rule->direction = IPSEC_IN; 9441edc1b9aShshoexer break; 9451edc1b9aShshoexer case IPSP_DIRECTION_OUT: 9461edc1b9aShshoexer rule->direction = IPSEC_OUT; 9471edc1b9aShshoexer break; 9481edc1b9aShshoexer default: 9491edc1b9aShshoexer return (1); 9501edc1b9aShshoexer } 9516122c05eShshoexer switch (sproto->sadb_protocol_proto) { 9526122c05eShshoexer case SADB_X_FLOW_TYPE_USE: 9531a3f035aShshoexer rule->flowtype = TYPE_USE; 9546122c05eShshoexer break; 9556122c05eShshoexer case SADB_X_FLOW_TYPE_ACQUIRE: 9561a3f035aShshoexer rule->flowtype = TYPE_ACQUIRE; 9576122c05eShshoexer break; 9586122c05eShshoexer case SADB_X_FLOW_TYPE_REQUIRE: 9591a3f035aShshoexer rule->flowtype = TYPE_REQUIRE; 9606122c05eShshoexer break; 9616122c05eShshoexer case SADB_X_FLOW_TYPE_DENY: 9621a3f035aShshoexer rule->flowtype = TYPE_DENY; 9636122c05eShshoexer break; 9646122c05eShshoexer case SADB_X_FLOW_TYPE_BYPASS: 9651a3f035aShshoexer rule->flowtype = TYPE_BYPASS; 9666122c05eShshoexer break; 9676122c05eShshoexer case SADB_X_FLOW_TYPE_DONTACQ: 9681a3f035aShshoexer rule->flowtype = TYPE_DONTACQ; 9696122c05eShshoexer break; 9706122c05eShshoexer default: 9711a3f035aShshoexer rule->flowtype = TYPE_UNKNOWN; 9726122c05eShshoexer break; 9736122c05eShshoexer } 9741edc1b9aShshoexer break; 9751edc1b9aShshoexer 9761edc1b9aShshoexer case SADB_X_EXT_SRC_FLOW: 9771edc1b9aShshoexer saddr = (struct sadb_address *)ext; 9781edc1b9aShshoexer sa = (struct sockaddr *)(saddr + 1); 9791edc1b9aShshoexer 9801edc1b9aShshoexer if (rule->src == NULL) { 9811edc1b9aShshoexer rule->src = calloc(1, 98291f765ddShshoexer sizeof(struct ipsec_addr_wrap)); 9831edc1b9aShshoexer if (rule->src == NULL) 984bd828a90Shshoexer err(1, "pfkey_parse: calloc"); 9851edc1b9aShshoexer } 9861edc1b9aShshoexer 9872099bcdfStodd rule->src->af = sa->sa_family; 9881edc1b9aShshoexer switch (sa->sa_family) { 9891edc1b9aShshoexer case AF_INET: 9901edc1b9aShshoexer bcopy(&((struct sockaddr_in *)sa)->sin_addr, 991712e78baShshoexer &rule->src->address.v4, 992712e78baShshoexer sizeof(struct in_addr)); 99357f58d0dSnaddy rule->sport = 99457f58d0dSnaddy ((struct sockaddr_in *)sa)->sin_port; 9952099bcdfStodd break; 9962099bcdfStodd case AF_INET6: 9972099bcdfStodd bcopy(&((struct sockaddr_in6 *)sa)->sin6_addr, 9982099bcdfStodd &rule->src->address.v6, 9992099bcdfStodd sizeof(struct in6_addr)); 100057f58d0dSnaddy rule->sport = 100157f58d0dSnaddy ((struct sockaddr_in6 *)sa)->sin6_port; 10021edc1b9aShshoexer break; 10031edc1b9aShshoexer default: 10041edc1b9aShshoexer return (1); 10051edc1b9aShshoexer } 10061edc1b9aShshoexer break; 10071edc1b9aShshoexer 10081edc1b9aShshoexer case SADB_X_EXT_DST_FLOW: 10091edc1b9aShshoexer saddr = (struct sadb_address *)ext; 10101edc1b9aShshoexer sa = (struct sockaddr *)(saddr + 1); 10111edc1b9aShshoexer 10121edc1b9aShshoexer if (rule->dst == NULL) { 10131edc1b9aShshoexer rule->dst = calloc(1, 101491f765ddShshoexer sizeof(struct ipsec_addr_wrap)); 10151edc1b9aShshoexer if (rule->dst == NULL) 1016bd828a90Shshoexer err(1, "pfkey_parse: calloc"); 10171edc1b9aShshoexer } 10181edc1b9aShshoexer 10192099bcdfStodd rule->dst->af = sa->sa_family; 10201edc1b9aShshoexer switch (sa->sa_family) { 10211edc1b9aShshoexer case AF_INET: 10221edc1b9aShshoexer bcopy(&((struct sockaddr_in *)sa)->sin_addr, 1023712e78baShshoexer &rule->dst->address.v4, 1024712e78baShshoexer sizeof(struct in_addr)); 102557f58d0dSnaddy rule->dport = 102657f58d0dSnaddy ((struct sockaddr_in *)sa)->sin_port; 10271edc1b9aShshoexer break; 10282099bcdfStodd case AF_INET6: 10292099bcdfStodd bcopy(&((struct sockaddr_in6 *)sa)->sin6_addr, 10302099bcdfStodd &rule->dst->address.v6, 10312099bcdfStodd sizeof(struct in6_addr)); 103257f58d0dSnaddy rule->dport = 103357f58d0dSnaddy ((struct sockaddr_in6 *)sa)->sin6_port; 10342099bcdfStodd break; 10351edc1b9aShshoexer default: 10361edc1b9aShshoexer return (1); 10371edc1b9aShshoexer } 10381edc1b9aShshoexer break; 10391edc1b9aShshoexer 10401edc1b9aShshoexer 10411edc1b9aShshoexer case SADB_X_EXT_SRC_MASK: 10421edc1b9aShshoexer saddr = (struct sadb_address *)ext; 10431edc1b9aShshoexer sa = (struct sockaddr *)(saddr + 1); 10441edc1b9aShshoexer 10451edc1b9aShshoexer if (rule->src == NULL) { 10461edc1b9aShshoexer rule->src = calloc(1, 104791f765ddShshoexer sizeof(struct ipsec_addr_wrap)); 10481edc1b9aShshoexer if (rule->src == NULL) 1049bd828a90Shshoexer err(1, "pfkey_parse: calloc"); 10501edc1b9aShshoexer } 10511edc1b9aShshoexer 10522099bcdfStodd rule->src->af = sa->sa_family; 10531edc1b9aShshoexer switch (sa->sa_family) { 10541edc1b9aShshoexer case AF_INET: 1055712e78baShshoexer sa_in = (struct sockaddr_in *)sa; 1056712e78baShshoexer bcopy(&sa_in->sin_addr, &rule->src->mask.v4, 10571edc1b9aShshoexer sizeof(struct in_addr)); 10582099bcdfStodd break; 10592099bcdfStodd case AF_INET6: 10602099bcdfStodd sa_in6 = (struct sockaddr_in6 *)sa; 10612099bcdfStodd bcopy(&sa_in6->sin6_addr, &rule->src->mask.v6, 10622099bcdfStodd sizeof(struct in6_addr)); 10631edc1b9aShshoexer break; 10641edc1b9aShshoexer 10651edc1b9aShshoexer default: 10661edc1b9aShshoexer return (1); 10671edc1b9aShshoexer } 10681edc1b9aShshoexer break; 10691edc1b9aShshoexer 10701edc1b9aShshoexer case SADB_X_EXT_DST_MASK: 10711edc1b9aShshoexer saddr = (struct sadb_address *)ext; 10721edc1b9aShshoexer sa = (struct sockaddr *)(saddr + 1); 10731edc1b9aShshoexer 10741edc1b9aShshoexer if (rule->dst == NULL) { 10751edc1b9aShshoexer rule->dst = calloc(1, 107691f765ddShshoexer sizeof(struct ipsec_addr_wrap)); 10771edc1b9aShshoexer if (rule->dst == NULL) 1078bd828a90Shshoexer err(1, "pfkey_parse: calloc"); 10791edc1b9aShshoexer } 10801edc1b9aShshoexer 10812099bcdfStodd rule->dst->af = sa->sa_family; 10821edc1b9aShshoexer switch (sa->sa_family) { 10831edc1b9aShshoexer case AF_INET: 1084712e78baShshoexer sa_in = (struct sockaddr_in *)sa; 1085712e78baShshoexer bcopy(&sa_in->sin_addr, &rule->dst->mask.v4, 10861edc1b9aShshoexer sizeof(struct in_addr)); 10871edc1b9aShshoexer break; 10882099bcdfStodd case AF_INET6: 10892099bcdfStodd sa_in6 = (struct sockaddr_in6 *)sa; 10902099bcdfStodd bcopy(&sa_in6->sin6_addr, &rule->dst->mask.v6, 10912099bcdfStodd sizeof(struct in6_addr)); 10922099bcdfStodd break; 10931edc1b9aShshoexer default: 10941edc1b9aShshoexer return (1); 10951edc1b9aShshoexer } 10961edc1b9aShshoexer break; 10971edc1b9aShshoexer 10981edc1b9aShshoexer default: 10991edc1b9aShshoexer return (1); 11001edc1b9aShshoexer } 11011edc1b9aShshoexer } 11021edc1b9aShshoexer 11031edc1b9aShshoexer return (0); 11041edc1b9aShshoexer } 11051edc1b9aShshoexer 11061edc1b9aShshoexer int 1107356121f6Shshoexer pfkey_ipsec_establish(int action, struct ipsec_rule *r) 1108f484f2cfShshoexer { 110922a29ad6Shshoexer int ret; 11108065703bShshoexer u_int8_t satype, satype2, direction; 1111f484f2cfShshoexer 1112f032086dShshoexer if (r->type == RULE_FLOW) { 11139182219dSmarkus switch (r->satype) { 1114f484f2cfShshoexer case IPSEC_ESP: 1115f484f2cfShshoexer satype = SADB_SATYPE_ESP; 1116f484f2cfShshoexer break; 1117f484f2cfShshoexer case IPSEC_AH: 1118f484f2cfShshoexer satype = SADB_SATYPE_AH; 1119f484f2cfShshoexer break; 112072e25333Shshoexer case IPSEC_IPCOMP: 112172e25333Shshoexer satype = SADB_X_SATYPE_IPCOMP; 112272e25333Shshoexer break; 112388a8cceeSmarkus case IPSEC_IPIP: 112488a8cceeSmarkus satype = SADB_X_SATYPE_IPIP; 112588a8cceeSmarkus break; 1126f484f2cfShshoexer default: 1127f484f2cfShshoexer return -1; 1128f484f2cfShshoexer } 1129f484f2cfShshoexer 1130f484f2cfShshoexer switch (r->direction) { 1131f484f2cfShshoexer case IPSEC_IN: 1132f484f2cfShshoexer direction = IPSP_DIRECTION_IN; 1133f484f2cfShshoexer break; 1134f484f2cfShshoexer case IPSEC_OUT: 1135f484f2cfShshoexer direction = IPSP_DIRECTION_OUT; 1136f484f2cfShshoexer break; 1137f484f2cfShshoexer default: 1138f484f2cfShshoexer return -1; 1139f484f2cfShshoexer } 1140f484f2cfShshoexer 114122a29ad6Shshoexer switch (action) { 114290bd57a7Shshoexer case ACTION_ADD: 1143f032086dShshoexer ret = pfkey_flow(fd, satype, SADB_X_ADDFLOW, direction, 114457f58d0dSnaddy r->proto, r->src, r->sport, r->dst, r->dport, 114557f58d0dSnaddy r->local, r->peer, r->auth, r->flowtype); 114622a29ad6Shshoexer break; 114790bd57a7Shshoexer case ACTION_DELETE: 114822a29ad6Shshoexer /* No peer for flow deletion. */ 1149f032086dShshoexer ret = pfkey_flow(fd, satype, SADB_X_DELFLOW, direction, 115057f58d0dSnaddy r->proto, r->src, r->sport, r->dst, r->dport, 115157f58d0dSnaddy NULL, NULL, NULL, r->flowtype); 115222a29ad6Shshoexer break; 115322a29ad6Shshoexer default: 115422a29ad6Shshoexer return -1; 115522a29ad6Shshoexer } 1156f032086dShshoexer } else if (r->type == RULE_SA) { 11579182219dSmarkus switch (r->satype) { 1158881e2068Shshoexer case IPSEC_AH: 1159881e2068Shshoexer satype = SADB_SATYPE_AH; 1160881e2068Shshoexer break; 1161881e2068Shshoexer case IPSEC_ESP: 1162881e2068Shshoexer satype = SADB_SATYPE_ESP; 1163881e2068Shshoexer break; 116472e25333Shshoexer case IPSEC_IPCOMP: 116572e25333Shshoexer satype = SADB_X_SATYPE_IPCOMP; 116672e25333Shshoexer break; 1167381a2422Shshoexer case IPSEC_TCPMD5: 1168f032086dShshoexer satype = SADB_X_SATYPE_TCPSIGNATURE; 1169381a2422Shshoexer break; 117088a8cceeSmarkus case IPSEC_IPIP: 117188a8cceeSmarkus satype = SADB_X_SATYPE_IPIP; 117288a8cceeSmarkus break; 1173381a2422Shshoexer default: 1174381a2422Shshoexer return -1; 1175381a2422Shshoexer } 1176f032086dShshoexer switch (action) { 117790bd57a7Shshoexer case ACTION_ADD: 1178f032086dShshoexer ret = pfkey_sa(fd, satype, SADB_ADD, r->spi, 1179a38d220fShshoexer r->src, r->dst, r->xfs, r->authkey, r->enckey, 1180a38d220fShshoexer r->tmode); 1181f032086dShshoexer break; 118290bd57a7Shshoexer case ACTION_DELETE: 1183f032086dShshoexer ret = pfkey_sa(fd, satype, SADB_DELETE, r->spi, 1184a38d220fShshoexer r->src, r->dst, r->xfs, NULL, NULL, r->tmode); 1185f032086dShshoexer break; 1186f032086dShshoexer default: 1187f032086dShshoexer return -1; 1188f032086dShshoexer } 11898f2109caShshoexer } else if (r->type == RULE_GROUP) { 11908f2109caShshoexer switch (r->satype) { 11918f2109caShshoexer case IPSEC_AH: 11928f2109caShshoexer satype = SADB_SATYPE_AH; 11938f2109caShshoexer break; 11948f2109caShshoexer case IPSEC_ESP: 11958f2109caShshoexer satype = SADB_SATYPE_ESP; 11968f2109caShshoexer break; 11978f2109caShshoexer case IPSEC_IPCOMP: 11988f2109caShshoexer satype = SADB_X_SATYPE_IPCOMP; 11998f2109caShshoexer break; 12008f2109caShshoexer case IPSEC_TCPMD5: 12018f2109caShshoexer satype = SADB_X_SATYPE_TCPSIGNATURE; 12028f2109caShshoexer break; 12038f2109caShshoexer case IPSEC_IPIP: 12048f2109caShshoexer satype = SADB_X_SATYPE_IPIP; 12058f2109caShshoexer break; 12068f2109caShshoexer default: 12078f2109caShshoexer return -1; 12088f2109caShshoexer } 12098065703bShshoexer switch (r->proto2) { 12108065703bShshoexer case IPSEC_AH: 12118065703bShshoexer satype2 = SADB_SATYPE_AH; 12128065703bShshoexer break; 12138065703bShshoexer case IPSEC_ESP: 12148065703bShshoexer satype2 = SADB_SATYPE_ESP; 12158065703bShshoexer break; 12168065703bShshoexer case IPSEC_IPCOMP: 12178065703bShshoexer satype2 = SADB_X_SATYPE_IPCOMP; 12188065703bShshoexer break; 12198065703bShshoexer case IPSEC_TCPMD5: 12208065703bShshoexer satype2 = SADB_X_SATYPE_TCPSIGNATURE; 12218065703bShshoexer break; 12228065703bShshoexer case IPSEC_IPIP: 12238065703bShshoexer satype2 = SADB_X_SATYPE_IPIP; 12248065703bShshoexer break; 12258065703bShshoexer default: 12268065703bShshoexer return -1; 12278065703bShshoexer } 12288f2109caShshoexer switch (action) { 12298f2109caShshoexer case ACTION_ADD: 12308065703bShshoexer ret = pfkey_sagroup(fd, satype, satype2, 12318065703bShshoexer SADB_X_GRPSPIS, r->dst, r->spi, r->dst2, r->spi2); 12328f2109caShshoexer break; 12338f2109caShshoexer case ACTION_DELETE: 12348f2109caShshoexer return 0; 12358f2109caShshoexer default: 12368f2109caShshoexer return -1; 12378f2109caShshoexer } 1238f032086dShshoexer } else 1239f032086dShshoexer return -1; 1240f032086dShshoexer 124122a29ad6Shshoexer if (ret < 0) 1242f484f2cfShshoexer return -1; 12438a87fca6Smsf if (pfkey_reply(fd, NULL, NULL) < 0) 1244f484f2cfShshoexer return -1; 1245f484f2cfShshoexer 1246f484f2cfShshoexer return 0; 1247f484f2cfShshoexer } 1248f484f2cfShshoexer 1249f484f2cfShshoexer int 1250f484f2cfShshoexer pfkey_ipsec_flush(void) 1251f484f2cfShshoexer { 1252f484f2cfShshoexer struct sadb_msg smsg; 1253f484f2cfShshoexer struct iovec iov[IOV_CNT]; 1254f484f2cfShshoexer ssize_t n; 1255f484f2cfShshoexer int iov_cnt, len; 1256f484f2cfShshoexer 1257f484f2cfShshoexer bzero(&smsg, sizeof(smsg)); 1258f484f2cfShshoexer smsg.sadb_msg_version = PF_KEY_V2; 1259f484f2cfShshoexer smsg.sadb_msg_seq = sadb_msg_seq++; 1260f484f2cfShshoexer smsg.sadb_msg_pid = getpid(); 1261f484f2cfShshoexer smsg.sadb_msg_len = sizeof(smsg) / 8; 1262f484f2cfShshoexer smsg.sadb_msg_type = SADB_FLUSH; 1263f484f2cfShshoexer smsg.sadb_msg_satype = SADB_SATYPE_UNSPEC; 1264f484f2cfShshoexer 1265f484f2cfShshoexer iov_cnt = 0; 1266f484f2cfShshoexer 1267f484f2cfShshoexer iov[iov_cnt].iov_base = &smsg; 1268f484f2cfShshoexer iov[iov_cnt].iov_len = sizeof(smsg); 1269f484f2cfShshoexer iov_cnt++; 1270f484f2cfShshoexer 1271f484f2cfShshoexer len = smsg.sadb_msg_len * 8; 1272f484f2cfShshoexer if ((n = writev(fd, iov, iov_cnt)) == -1) { 1273f484f2cfShshoexer warn("writev failed"); 1274f484f2cfShshoexer return -1; 1275f484f2cfShshoexer } 1276f484f2cfShshoexer if (n != len) { 1277f484f2cfShshoexer warnx("short write"); 1278f484f2cfShshoexer return -1; 1279f484f2cfShshoexer } 12808a87fca6Smsf if (pfkey_reply(fd, NULL, NULL) < 0) 1281f484f2cfShshoexer return -1; 1282f484f2cfShshoexer 1283f484f2cfShshoexer return 0; 1284f484f2cfShshoexer } 1285f484f2cfShshoexer 12868a87fca6Smsf static int 12878a87fca6Smsf pfkey_promisc(void) 12888a87fca6Smsf { 12898a87fca6Smsf struct sadb_msg msg; 12908a87fca6Smsf 12918a87fca6Smsf memset(&msg, 0, sizeof(msg)); 12928a87fca6Smsf msg.sadb_msg_version = PF_KEY_V2; 12938a87fca6Smsf msg.sadb_msg_seq = sadb_msg_seq++; 12948a87fca6Smsf msg.sadb_msg_pid = getpid(); 12958a87fca6Smsf msg.sadb_msg_len = sizeof(msg) / PFKEYV2_CHUNK; 12968a87fca6Smsf msg.sadb_msg_type = SADB_X_PROMISC; 12978a87fca6Smsf msg.sadb_msg_satype = 1; /* enable */ 12988a87fca6Smsf if (write(fd, &msg, sizeof(msg)) != sizeof(msg)) { 12998a87fca6Smsf warn("pfkey_promisc: write failed"); 13008a87fca6Smsf return -1; 13018a87fca6Smsf } 13028a87fca6Smsf if (pfkey_reply(fd, NULL, NULL) < 0) 13038a87fca6Smsf return -1; 13048a87fca6Smsf return 0; 13058a87fca6Smsf } 13068a87fca6Smsf 13078a87fca6Smsf int 13088a87fca6Smsf pfkey_monitor(int opts) 13098a87fca6Smsf { 13108a87fca6Smsf fd_set *rset; 13118a87fca6Smsf u_int8_t *data; 13128a87fca6Smsf struct sadb_msg *msg; 13138a87fca6Smsf ssize_t len, set_size; 13148a87fca6Smsf int n; 13158a87fca6Smsf 13168a87fca6Smsf if (pfkey_init() < 0) 13178a87fca6Smsf return -1; 13188a87fca6Smsf if (pfkey_promisc() < 0) 13198a87fca6Smsf return -1; 13208a87fca6Smsf 13218a87fca6Smsf set_size = howmany(fd + 1, NFDBITS) * sizeof(fd_mask); 13228a87fca6Smsf if ((rset = malloc(set_size)) == NULL) { 13238a87fca6Smsf warn("malloc"); 13248a87fca6Smsf return -1; 13258a87fca6Smsf } 13268a87fca6Smsf for (;;) { 13278a87fca6Smsf memset(rset, 0, set_size); 13288a87fca6Smsf FD_SET(fd, rset); 13298a87fca6Smsf if ((n = select(fd+1, rset, NULL, NULL, NULL)) < 0) 13308a87fca6Smsf err(2, "select"); 13318a87fca6Smsf if (n == 0) 13328a87fca6Smsf break; 13338a87fca6Smsf if (!FD_ISSET(fd, rset)) 13348a87fca6Smsf continue; 13358a87fca6Smsf if (pfkey_reply(fd, &data, &len) < 0) 13368a87fca6Smsf continue; 13378a87fca6Smsf msg = (struct sadb_msg *)data; 13388a87fca6Smsf if (msg->sadb_msg_type == SADB_X_PROMISC) { 13398a87fca6Smsf /* remove extra header from promisc messages */ 13408a87fca6Smsf if ((msg->sadb_msg_len * PFKEYV2_CHUNK) >= 13418a87fca6Smsf 2 * sizeof(struct sadb_msg)) { 13428a87fca6Smsf msg++; 13438a87fca6Smsf } 13448a87fca6Smsf } 13458a87fca6Smsf pfkey_monitor_sa(msg, opts); 13468a87fca6Smsf if (opts & IPSECCTL_OPT_VERBOSE) 13478a87fca6Smsf pfkey_print_raw(data, len); 13488a87fca6Smsf memset(data, 0, len); 13498a87fca6Smsf free(data); 13508a87fca6Smsf } 13518a87fca6Smsf close(fd); 13528a87fca6Smsf return 0; 13538a87fca6Smsf } 13548a87fca6Smsf 1355f484f2cfShshoexer int 1356f484f2cfShshoexer pfkey_init(void) 1357f484f2cfShshoexer { 1358f484f2cfShshoexer if ((fd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) == -1) 1359bd828a90Shshoexer err(1, "pfkey_init: failed to open PF_KEY socket"); 1360f484f2cfShshoexer 1361f484f2cfShshoexer return 0; 1362f484f2cfShshoexer } 1363