1*0813ab45Shshoexer /* $OpenBSD: pfkey.c,v 1.16 2005/07/09 21:31:24 hshoexer Exp $ */ 2f484f2cfShshoexer /* 3f484f2cfShshoexer * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 4f484f2cfShshoexer * Copyright (c) 2003, 2004 Markus Friedl <markus@openbsd.org> 5f484f2cfShshoexer * Copyright (c) 2004, 2005 Hans-Joerg Hoexer <hshoexer@openbsd.org> 6f484f2cfShshoexer * 7f484f2cfShshoexer * Permission to use, copy, modify, and distribute this software for any 8f484f2cfShshoexer * purpose with or without fee is hereby granted, provided that the above 9f484f2cfShshoexer * copyright notice and this permission notice appear in all copies. 10f484f2cfShshoexer * 11f484f2cfShshoexer * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12f484f2cfShshoexer * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13f484f2cfShshoexer * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14f484f2cfShshoexer * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15f484f2cfShshoexer * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16f484f2cfShshoexer * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17f484f2cfShshoexer * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18f484f2cfShshoexer */ 19f484f2cfShshoexer 20f484f2cfShshoexer #include <sys/types.h> 21f484f2cfShshoexer #include <sys/queue.h> 22f484f2cfShshoexer #include <sys/uio.h> 23f484f2cfShshoexer #include <sys/socket.h> 24f484f2cfShshoexer #include <netinet/in.h> 25f484f2cfShshoexer #include <netinet/ip_ipsp.h> 26f484f2cfShshoexer #include <net/pfkeyv2.h> 27f484f2cfShshoexer 28f484f2cfShshoexer #include <err.h> 29f484f2cfShshoexer #include <errno.h> 30f484f2cfShshoexer #include <stdio.h> 31f484f2cfShshoexer #include <string.h> 32f484f2cfShshoexer #include <stdlib.h> 33f484f2cfShshoexer #include <unistd.h> 34f484f2cfShshoexer 35f484f2cfShshoexer #include "ipsecctl.h" 361edc1b9aShshoexer #include "pfkey.h" 37f484f2cfShshoexer 38f484f2cfShshoexer #define ROUNDUP(x) (((x) + (PFKEYV2_CHUNK - 1)) & ~(PFKEYV2_CHUNK - 1)) 39f484f2cfShshoexer #define IOV_CNT 20 40f484f2cfShshoexer 41f484f2cfShshoexer static int fd; 42f484f2cfShshoexer static u_int32_t sadb_msg_seq = 1; 43f484f2cfShshoexer 44f032086dShshoexer static int pfkey_flow(int, u_int8_t, u_int8_t, u_int8_t, 45f484f2cfShshoexer struct ipsec_addr *, struct ipsec_addr *, 46f032086dShshoexer struct ipsec_addr *, struct ipsec_auth, u_int8_t); 47f032086dShshoexer static int pfkey_sa(int, u_int8_t, u_int8_t, u_int32_t, 48f032086dShshoexer struct ipsec_addr *, struct ipsec_addr *, 49f032086dShshoexer struct ipsec_key *); 50f484f2cfShshoexer static int pfkey_reply(int); 51e225c210Shshoexer int pfkey_parse(struct sadb_msg *, struct ipsec_rule *); 52f484f2cfShshoexer int pfkey_ipsec_flush(void); 53356121f6Shshoexer int pfkey_ipsec_establish(int, struct ipsec_rule *); 54f484f2cfShshoexer int pfkey_init(void); 55f484f2cfShshoexer 56f484f2cfShshoexer static int 57f484f2cfShshoexer pfkey_flow(int sd, u_int8_t satype, u_int8_t action, u_int8_t direction, 58f484f2cfShshoexer struct ipsec_addr *src, struct ipsec_addr *dst, struct ipsec_addr *peer, 59e1ffbfafShshoexer struct ipsec_auth auth, u_int8_t flowtype) 60f484f2cfShshoexer { 61f484f2cfShshoexer struct sadb_msg smsg; 62f484f2cfShshoexer struct sadb_address sa_src, sa_dst, sa_peer, sa_smask, sa_dmask; 63f484f2cfShshoexer struct sadb_protocol sa_flowtype, sa_protocol; 64f484f2cfShshoexer struct sadb_ident *sa_srcid, *sa_dstid; 65f484f2cfShshoexer struct sockaddr_storage ssrc, sdst, speer, smask, dmask; 66f484f2cfShshoexer struct iovec iov[IOV_CNT]; 67f484f2cfShshoexer ssize_t n; 68f484f2cfShshoexer int iov_cnt, len, ret = 0; 69f484f2cfShshoexer 70f484f2cfShshoexer sa_srcid = sa_dstid = NULL; 71f484f2cfShshoexer 72f484f2cfShshoexer bzero(&ssrc, sizeof(ssrc)); 73f484f2cfShshoexer bzero(&smask, sizeof(smask)); 74f484f2cfShshoexer switch (src->af) { 75f484f2cfShshoexer case AF_INET: 76f484f2cfShshoexer ((struct sockaddr_in *)&ssrc)->sin_addr = src->v4; 77f484f2cfShshoexer ssrc.ss_len = sizeof(struct sockaddr_in); 78f484f2cfShshoexer ssrc.ss_family = AF_INET; 79f484f2cfShshoexer ((struct sockaddr_in *)&smask)->sin_addr = src->v4mask.mask; 80f484f2cfShshoexer break; 81f484f2cfShshoexer case AF_INET6: 82f484f2cfShshoexer default: 83f484f2cfShshoexer warnx("unsupported address family %d", src->af); 84f484f2cfShshoexer return -1; 85f484f2cfShshoexer } 86f484f2cfShshoexer smask.ss_family = ssrc.ss_family; 87f484f2cfShshoexer smask.ss_len = ssrc.ss_len; 88f484f2cfShshoexer 89f484f2cfShshoexer bzero(&sdst, sizeof(sdst)); 90f484f2cfShshoexer bzero(&dmask, sizeof(dmask)); 91f484f2cfShshoexer switch (dst->af) { 92f484f2cfShshoexer case AF_INET: 93f484f2cfShshoexer ((struct sockaddr_in *)&sdst)->sin_addr = dst->v4; 94f484f2cfShshoexer sdst.ss_len = sizeof(struct sockaddr_in); 95f484f2cfShshoexer sdst.ss_family = AF_INET; 96f484f2cfShshoexer ((struct sockaddr_in *)&dmask)->sin_addr = dst->v4mask.mask; 97f484f2cfShshoexer break; 98f484f2cfShshoexer case AF_INET6: 99f484f2cfShshoexer default: 100f484f2cfShshoexer warnx("unsupported address family %d", dst->af); 101f484f2cfShshoexer return -1; 102f484f2cfShshoexer } 103f484f2cfShshoexer dmask.ss_family = sdst.ss_family; 104f484f2cfShshoexer dmask.ss_len = sdst.ss_len; 105f484f2cfShshoexer 106f484f2cfShshoexer bzero(&speer, sizeof(speer)); 10722a29ad6Shshoexer if (peer) { 108f484f2cfShshoexer switch (peer->af) { 109f484f2cfShshoexer case AF_INET: 110f484f2cfShshoexer ((struct sockaddr_in *)&speer)->sin_addr = peer->v4; 111f484f2cfShshoexer speer.ss_len = sizeof(struct sockaddr_in); 112f484f2cfShshoexer speer.ss_family = AF_INET; 113f484f2cfShshoexer break; 114f484f2cfShshoexer case AF_INET6: 115f484f2cfShshoexer default: 116f484f2cfShshoexer warnx("unsupported address family %d", peer->af); 117f484f2cfShshoexer return -1; 118f484f2cfShshoexer } 11922a29ad6Shshoexer } 120f484f2cfShshoexer 121f484f2cfShshoexer bzero(&smsg, sizeof(smsg)); 122f484f2cfShshoexer smsg.sadb_msg_version = PF_KEY_V2; 123f484f2cfShshoexer smsg.sadb_msg_seq = sadb_msg_seq++; 124f484f2cfShshoexer smsg.sadb_msg_pid = getpid(); 125f484f2cfShshoexer smsg.sadb_msg_len = sizeof(smsg) / 8; 126f484f2cfShshoexer smsg.sadb_msg_type = action; 127f484f2cfShshoexer smsg.sadb_msg_satype = satype; 128f484f2cfShshoexer 129f484f2cfShshoexer bzero(&sa_flowtype, sizeof(sa_flowtype)); 130f484f2cfShshoexer sa_flowtype.sadb_protocol_exttype = SADB_X_EXT_FLOW_TYPE; 131f484f2cfShshoexer sa_flowtype.sadb_protocol_len = sizeof(sa_flowtype) / 8; 132f484f2cfShshoexer sa_flowtype.sadb_protocol_direction = direction; 13326df514dShshoexer 134e1ffbfafShshoexer switch (flowtype) { 135e1ffbfafShshoexer case TYPE_USE: 13626df514dShshoexer sa_flowtype.sadb_protocol_proto = SADB_X_FLOW_TYPE_USE; 137e1ffbfafShshoexer break; 138e1ffbfafShshoexer case TYPE_REQUIRE: 139f484f2cfShshoexer sa_flowtype.sadb_protocol_proto = SADB_X_FLOW_TYPE_REQUIRE; 140e1ffbfafShshoexer break; 141e1ffbfafShshoexer default: 142e1ffbfafShshoexer warnx("unsupported flowtype %d", flowtype); 143e1ffbfafShshoexer return -1; 144e1ffbfafShshoexer } 145f484f2cfShshoexer 146f484f2cfShshoexer bzero(&sa_protocol, sizeof(sa_protocol)); 147f484f2cfShshoexer sa_protocol.sadb_protocol_exttype = SADB_X_EXT_PROTOCOL; 148f484f2cfShshoexer sa_protocol.sadb_protocol_len = sizeof(sa_protocol) / 8; 149f484f2cfShshoexer sa_protocol.sadb_protocol_direction = 0; 150f484f2cfShshoexer sa_protocol.sadb_protocol_proto = IPPROTO_IP; 151f484f2cfShshoexer 152f484f2cfShshoexer bzero(&sa_src, sizeof(sa_src)); 153f484f2cfShshoexer sa_src.sadb_address_exttype = SADB_X_EXT_SRC_FLOW; 154f484f2cfShshoexer sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(ssrc.ss_len)) / 8; 155f484f2cfShshoexer 156f484f2cfShshoexer bzero(&sa_smask, sizeof(sa_smask)); 157f484f2cfShshoexer sa_smask.sadb_address_exttype = SADB_X_EXT_SRC_MASK; 158f484f2cfShshoexer sa_smask.sadb_address_len = 159f484f2cfShshoexer (sizeof(sa_smask) + ROUNDUP(smask.ss_len)) / 8; 160f484f2cfShshoexer 161f484f2cfShshoexer bzero(&sa_dst, sizeof(sa_dst)); 162f484f2cfShshoexer sa_dst.sadb_address_exttype = SADB_X_EXT_DST_FLOW; 163f484f2cfShshoexer sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(sdst.ss_len)) / 8; 164f484f2cfShshoexer 165f484f2cfShshoexer bzero(&sa_dmask, sizeof(sa_dmask)); 166f484f2cfShshoexer sa_dmask.sadb_address_exttype = SADB_X_EXT_DST_MASK; 167f484f2cfShshoexer sa_dmask.sadb_address_len = 168f484f2cfShshoexer (sizeof(sa_dmask) + ROUNDUP(dmask.ss_len)) / 8; 169f484f2cfShshoexer 170f484f2cfShshoexer bzero(&sa_peer, sizeof(sa_peer)); 171f484f2cfShshoexer sa_peer.sadb_address_exttype = SADB_EXT_ADDRESS_DST; 172f484f2cfShshoexer sa_peer.sadb_address_len = 173f484f2cfShshoexer (sizeof(sa_peer) + ROUNDUP(speer.ss_len)) / 8; 174f484f2cfShshoexer 175f484f2cfShshoexer if (auth.srcid) { 176f484f2cfShshoexer len = ROUNDUP(strlen(auth.srcid) + 1) + sizeof(*sa_srcid); 177f484f2cfShshoexer 178f484f2cfShshoexer sa_srcid = calloc(len, sizeof(u_int8_t)); 179f484f2cfShshoexer if (sa_srcid == NULL) 180f484f2cfShshoexer err(1, "calloc"); 181f484f2cfShshoexer 182f484f2cfShshoexer sa_srcid->sadb_ident_type = auth.idtype; 183f484f2cfShshoexer sa_srcid->sadb_ident_len = len / 8; 184f484f2cfShshoexer sa_srcid->sadb_ident_exttype = SADB_EXT_IDENTITY_SRC; 185f484f2cfShshoexer 186f484f2cfShshoexer strlcpy((char *)(sa_srcid + 1), auth.srcid, 187f484f2cfShshoexer ROUNDUP(strlen(auth.srcid) + 1)); 188f484f2cfShshoexer } 189f484f2cfShshoexer if (auth.dstid) { 190f484f2cfShshoexer len = ROUNDUP(strlen(auth.dstid) + 1) + sizeof(*sa_dstid); 191f484f2cfShshoexer 192f484f2cfShshoexer sa_dstid = calloc(len, sizeof(u_int8_t)); 193f484f2cfShshoexer if (sa_dstid == NULL) 194f484f2cfShshoexer err(1, "calloc"); 195f484f2cfShshoexer 196f484f2cfShshoexer sa_dstid->sadb_ident_type = auth.idtype; 197f484f2cfShshoexer sa_dstid->sadb_ident_len = len / 8; 198f484f2cfShshoexer sa_dstid->sadb_ident_exttype = SADB_EXT_IDENTITY_DST; 199f484f2cfShshoexer 200f484f2cfShshoexer strlcpy((char *)(sa_dstid + 1), auth.dstid, 201f484f2cfShshoexer ROUNDUP(strlen(auth.dstid) + 1)); 202f484f2cfShshoexer } 203f484f2cfShshoexer 204f484f2cfShshoexer iov_cnt = 0; 205f484f2cfShshoexer 206f484f2cfShshoexer /* header */ 207f484f2cfShshoexer iov[iov_cnt].iov_base = &smsg; 208f484f2cfShshoexer iov[iov_cnt].iov_len = sizeof(smsg); 209f484f2cfShshoexer iov_cnt++; 210f484f2cfShshoexer 21189ad8c34Shshoexer /* add flow type */ 21289ad8c34Shshoexer iov[iov_cnt].iov_base = &sa_flowtype; 21389ad8c34Shshoexer iov[iov_cnt].iov_len = sizeof(sa_flowtype); 21489ad8c34Shshoexer smsg.sadb_msg_len += sa_flowtype.sadb_protocol_len; 21589ad8c34Shshoexer iov_cnt++; 21689ad8c34Shshoexer 217f484f2cfShshoexer /* remote peer */ 21822a29ad6Shshoexer if (peer) { 219f484f2cfShshoexer iov[iov_cnt].iov_base = &sa_peer; 220f484f2cfShshoexer iov[iov_cnt].iov_len = sizeof(sa_peer); 221f484f2cfShshoexer iov_cnt++; 222f484f2cfShshoexer iov[iov_cnt].iov_base = &speer; 223f484f2cfShshoexer iov[iov_cnt].iov_len = ROUNDUP(speer.ss_len); 224f484f2cfShshoexer smsg.sadb_msg_len += sa_peer.sadb_address_len; 225f484f2cfShshoexer iov_cnt++; 22622a29ad6Shshoexer } 227f484f2cfShshoexer 22889ad8c34Shshoexer /* src addr */ 22989ad8c34Shshoexer iov[iov_cnt].iov_base = &sa_src; 23089ad8c34Shshoexer iov[iov_cnt].iov_len = sizeof(sa_src); 23189ad8c34Shshoexer iov_cnt++; 23289ad8c34Shshoexer iov[iov_cnt].iov_base = &ssrc; 23389ad8c34Shshoexer iov[iov_cnt].iov_len = ROUNDUP(ssrc.ss_len); 23489ad8c34Shshoexer smsg.sadb_msg_len += sa_src.sadb_address_len; 235f484f2cfShshoexer iov_cnt++; 236f484f2cfShshoexer 23789ad8c34Shshoexer /* src mask */ 238f484f2cfShshoexer iov[iov_cnt].iov_base = &sa_smask; 239f484f2cfShshoexer iov[iov_cnt].iov_len = sizeof(sa_smask); 240f484f2cfShshoexer iov_cnt++; 241f484f2cfShshoexer iov[iov_cnt].iov_base = &smask; 242f484f2cfShshoexer iov[iov_cnt].iov_len = ROUNDUP(smask.ss_len); 243f484f2cfShshoexer smsg.sadb_msg_len += sa_smask.sadb_address_len; 244f484f2cfShshoexer iov_cnt++; 245f484f2cfShshoexer 246f484f2cfShshoexer /* dest addr */ 247f484f2cfShshoexer iov[iov_cnt].iov_base = &sa_dst; 248f484f2cfShshoexer iov[iov_cnt].iov_len = sizeof(sa_dst); 249f484f2cfShshoexer iov_cnt++; 250f484f2cfShshoexer iov[iov_cnt].iov_base = &sdst; 251f484f2cfShshoexer iov[iov_cnt].iov_len = ROUNDUP(sdst.ss_len); 252f484f2cfShshoexer smsg.sadb_msg_len += sa_dst.sadb_address_len; 253f484f2cfShshoexer iov_cnt++; 254f484f2cfShshoexer 25589ad8c34Shshoexer /* dst mask */ 25689ad8c34Shshoexer iov[iov_cnt].iov_base = &sa_dmask; 25789ad8c34Shshoexer iov[iov_cnt].iov_len = sizeof(sa_dmask); 258f484f2cfShshoexer iov_cnt++; 25989ad8c34Shshoexer iov[iov_cnt].iov_base = &dmask; 26089ad8c34Shshoexer iov[iov_cnt].iov_len = ROUNDUP(dmask.ss_len); 26189ad8c34Shshoexer smsg.sadb_msg_len += sa_dmask.sadb_address_len; 26289ad8c34Shshoexer iov_cnt++; 26389ad8c34Shshoexer 26489ad8c34Shshoexer /* add protocol */ 26589ad8c34Shshoexer iov[iov_cnt].iov_base = &sa_protocol; 26689ad8c34Shshoexer iov[iov_cnt].iov_len = sizeof(sa_protocol); 26789ad8c34Shshoexer smsg.sadb_msg_len += sa_protocol.sadb_protocol_len; 268f484f2cfShshoexer iov_cnt++; 269f484f2cfShshoexer 270f484f2cfShshoexer if (sa_srcid) { 271f484f2cfShshoexer /* src identity */ 272f484f2cfShshoexer iov[iov_cnt].iov_base = sa_srcid; 273f484f2cfShshoexer iov[iov_cnt].iov_len = sa_srcid->sadb_ident_len * 8; 274f484f2cfShshoexer smsg.sadb_msg_len += sa_srcid->sadb_ident_len; 275f484f2cfShshoexer iov_cnt++; 276f484f2cfShshoexer } 277f484f2cfShshoexer if (sa_dstid) { 278f484f2cfShshoexer /* dst identity */ 279f484f2cfShshoexer iov[iov_cnt].iov_base = sa_dstid; 280f484f2cfShshoexer iov[iov_cnt].iov_len = sa_dstid->sadb_ident_len * 8; 281f484f2cfShshoexer smsg.sadb_msg_len += sa_dstid->sadb_ident_len; 282f484f2cfShshoexer iov_cnt++; 283f484f2cfShshoexer } 284f484f2cfShshoexer len = smsg.sadb_msg_len * 8; 285f484f2cfShshoexer if ((n = writev(sd, iov, iov_cnt)) == -1) { 286f484f2cfShshoexer warn("writev failed"); 287f484f2cfShshoexer ret = -1; 288f484f2cfShshoexer goto out; 289f484f2cfShshoexer } 290f484f2cfShshoexer if (n != len) { 291f484f2cfShshoexer warnx("short write"); 292f484f2cfShshoexer ret = -1; 293f484f2cfShshoexer } 294f484f2cfShshoexer 295f484f2cfShshoexer out: 296f484f2cfShshoexer if (sa_srcid) 297f484f2cfShshoexer free(sa_srcid); 298f484f2cfShshoexer if (sa_dstid) 299f484f2cfShshoexer free(sa_dstid); 300f484f2cfShshoexer 301f484f2cfShshoexer return ret; 302f484f2cfShshoexer } 303f484f2cfShshoexer 304f484f2cfShshoexer static int 305f032086dShshoexer pfkey_sa(int sd, u_int8_t satype, u_int8_t action, u_int32_t spi, 306f032086dShshoexer struct ipsec_addr *src, struct ipsec_addr *dst, struct ipsec_key *key) 307f032086dShshoexer { 308f032086dShshoexer struct sadb_msg smsg; 309f032086dShshoexer struct sadb_sa sa; 310f032086dShshoexer struct sadb_address sa_src, sa_dst; 311f032086dShshoexer struct sadb_key sa_key; 312f032086dShshoexer struct sockaddr_storage ssrc, sdst; 313f032086dShshoexer struct iovec iov[IOV_CNT]; 314f032086dShshoexer ssize_t n; 315f032086dShshoexer int iov_cnt, len, ret = 0; 316f032086dShshoexer 317f032086dShshoexer bzero(&ssrc, sizeof(ssrc)); 318f032086dShshoexer switch (src->af) { 319f032086dShshoexer case AF_INET: 320f032086dShshoexer ((struct sockaddr_in *)&ssrc)->sin_addr = src->v4; 321f032086dShshoexer ssrc.ss_len = sizeof(struct sockaddr_in); 322f032086dShshoexer ssrc.ss_family = AF_INET; 323f032086dShshoexer break; 324f032086dShshoexer case AF_INET6: 325f032086dShshoexer default: 326f032086dShshoexer warnx("unsupported address family %d", src->af); 327f032086dShshoexer return -1; 328f032086dShshoexer } 329f032086dShshoexer 330f032086dShshoexer bzero(&sdst, sizeof(sdst)); 331f032086dShshoexer switch (dst->af) { 332f032086dShshoexer case AF_INET: 333f032086dShshoexer ((struct sockaddr_in *)&sdst)->sin_addr = dst->v4; 334f032086dShshoexer sdst.ss_len = sizeof(struct sockaddr_in); 335f032086dShshoexer sdst.ss_family = AF_INET; 336f032086dShshoexer break; 337f032086dShshoexer case AF_INET6: 338f032086dShshoexer default: 339f032086dShshoexer warnx("unsupported address family %d", dst->af); 340f032086dShshoexer return -1; 341f032086dShshoexer } 342f032086dShshoexer 343f032086dShshoexer bzero(&smsg, sizeof(smsg)); 344f032086dShshoexer smsg.sadb_msg_version = PF_KEY_V2; 345f032086dShshoexer smsg.sadb_msg_seq = sadb_msg_seq++; 346f032086dShshoexer smsg.sadb_msg_pid = getpid(); 347f032086dShshoexer smsg.sadb_msg_len = sizeof(smsg) / 8; 348f032086dShshoexer smsg.sadb_msg_type = action; 349f032086dShshoexer smsg.sadb_msg_satype = satype; 350f032086dShshoexer 351f032086dShshoexer bzero(&sa, sizeof(sa)); 352f032086dShshoexer sa.sadb_sa_len = sizeof(sa) / 8; 353f032086dShshoexer sa.sadb_sa_exttype = SADB_EXT_SA; 354f032086dShshoexer sa.sadb_sa_spi = htonl(spi); 355f032086dShshoexer sa.sadb_sa_state = SADB_SASTATE_MATURE; 356f032086dShshoexer 357f032086dShshoexer bzero(&sa_src, sizeof(sa_src)); 358f032086dShshoexer sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(ssrc.ss_len)) / 8; 359f032086dShshoexer sa_src.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; 360f032086dShshoexer 361f032086dShshoexer bzero(&sa_dst, sizeof(sa_dst)); 362f032086dShshoexer sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(sdst.ss_len)) / 8; 363f032086dShshoexer sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST; 364f032086dShshoexer 365f032086dShshoexer if (action == SADB_ADD) { 366*0813ab45Shshoexer if (!key) { 367*0813ab45Shshoexer warnx("no key specified"); 368*0813ab45Shshoexer return -1; 369*0813ab45Shshoexer } 370f032086dShshoexer bzero(&sa_key, sizeof(sa_key)); 371f032086dShshoexer sa_key.sadb_key_len = (sizeof(sa_key) + ((key->len + 7) / 8) 372f032086dShshoexer * 8) / 8; 373f032086dShshoexer sa_key.sadb_key_exttype = SADB_EXT_KEY_AUTH; 374f032086dShshoexer sa_key.sadb_key_bits = 8 * key->len; 375f032086dShshoexer } 376f032086dShshoexer 377f032086dShshoexer iov_cnt = 0; 378f032086dShshoexer 379f032086dShshoexer /* header */ 380f032086dShshoexer iov[iov_cnt].iov_base = &smsg; 381f032086dShshoexer iov[iov_cnt].iov_len = sizeof(smsg); 382f032086dShshoexer iov_cnt++; 383f032086dShshoexer 384f032086dShshoexer /* sa */ 385f032086dShshoexer iov[iov_cnt].iov_base = &sa; 386f032086dShshoexer iov[iov_cnt].iov_len = sizeof(sa); 387f032086dShshoexer smsg.sadb_msg_len += sa.sadb_sa_len; 388f032086dShshoexer iov_cnt++; 389f032086dShshoexer 390f032086dShshoexer /* src addr */ 391f032086dShshoexer iov[iov_cnt].iov_base = &sa_src; 392f032086dShshoexer iov[iov_cnt].iov_len = sizeof(sa_src); 393f032086dShshoexer iov_cnt++; 394f032086dShshoexer iov[iov_cnt].iov_base = &ssrc; 395f032086dShshoexer iov[iov_cnt].iov_len = ROUNDUP(ssrc.ss_len); 396f032086dShshoexer smsg.sadb_msg_len += sa_src.sadb_address_len; 397f032086dShshoexer iov_cnt++; 398f032086dShshoexer 399f032086dShshoexer /* dst addr */ 400f032086dShshoexer iov[iov_cnt].iov_base = &sa_dst; 401f032086dShshoexer iov[iov_cnt].iov_len = sizeof(sa_dst); 402f032086dShshoexer iov_cnt++; 403f032086dShshoexer iov[iov_cnt].iov_base = &sdst; 404f032086dShshoexer iov[iov_cnt].iov_len = ROUNDUP(sdst.ss_len); 405f032086dShshoexer smsg.sadb_msg_len += sa_dst.sadb_address_len; 406f032086dShshoexer iov_cnt++; 407f032086dShshoexer 408f032086dShshoexer if (action == SADB_ADD) { 409f032086dShshoexer /* key */ 410f032086dShshoexer iov[iov_cnt].iov_base = &sa_key; 411f032086dShshoexer iov[iov_cnt].iov_len = sizeof(sa_key); 412f032086dShshoexer iov_cnt++; 413f032086dShshoexer iov[iov_cnt].iov_base = key->data; 414f032086dShshoexer iov[iov_cnt].iov_len = ((key->len + 7) / 8) * 8; 415f032086dShshoexer smsg.sadb_msg_len += sa_key.sadb_key_len; 416f032086dShshoexer iov_cnt++; 417f032086dShshoexer } 418f032086dShshoexer 419f032086dShshoexer len = smsg.sadb_msg_len * 8; 420f032086dShshoexer if ((n = writev(sd, iov, iov_cnt)) == -1) { 421f032086dShshoexer warn("writev failed"); 422f032086dShshoexer ret = -1; 423f032086dShshoexer } else if (n != len) { 424f032086dShshoexer warnx("short write"); 425f032086dShshoexer ret = -1; 426f032086dShshoexer } 427f032086dShshoexer 428f032086dShshoexer return ret; 429f032086dShshoexer } 430f032086dShshoexer 431f032086dShshoexer static int 432f484f2cfShshoexer pfkey_reply(int sd) 433f484f2cfShshoexer { 434f484f2cfShshoexer struct sadb_msg hdr; 435f484f2cfShshoexer ssize_t len; 436f484f2cfShshoexer u_int8_t *data; 437f484f2cfShshoexer 438f484f2cfShshoexer if (recv(sd, &hdr, sizeof(hdr), MSG_PEEK) != sizeof(hdr)) { 439f484f2cfShshoexer warnx("short read"); 440f484f2cfShshoexer return -1; 441f484f2cfShshoexer } 442f484f2cfShshoexer if (hdr.sadb_msg_errno != 0) { 443f484f2cfShshoexer errno = hdr.sadb_msg_errno; 444*0813ab45Shshoexer warn("PF_KEY failed"); 445f484f2cfShshoexer return -1; 446f484f2cfShshoexer } 447f484f2cfShshoexer len = hdr.sadb_msg_len * PFKEYV2_CHUNK; 448f484f2cfShshoexer if ((data = malloc(len)) == NULL) 449f484f2cfShshoexer err(1, NULL); 450f484f2cfShshoexer if (read(sd, data, len) != len) { 451f484f2cfShshoexer warn("PF_KEY short read"); 452f484f2cfShshoexer bzero(data, len); 453f484f2cfShshoexer free(data); 454f484f2cfShshoexer return -1; 455f484f2cfShshoexer } 456f484f2cfShshoexer bzero(data, len); 457f484f2cfShshoexer free(data); 458f484f2cfShshoexer 459f484f2cfShshoexer return 0; 460f484f2cfShshoexer } 461f484f2cfShshoexer 462f484f2cfShshoexer int 4631edc1b9aShshoexer pfkey_parse(struct sadb_msg *msg, struct ipsec_rule *rule) 4641edc1b9aShshoexer { 4651edc1b9aShshoexer struct sadb_ext *ext; 4661edc1b9aShshoexer struct sadb_address *saddr; 4671edc1b9aShshoexer struct sadb_protocol *sproto; 4681edc1b9aShshoexer struct sadb_ident *sident; 4691edc1b9aShshoexer struct sockaddr *sa; 4701edc1b9aShshoexer int len; 4711edc1b9aShshoexer 4721edc1b9aShshoexer switch (msg->sadb_msg_satype) { 473b26a6cb5Shshoexer case SADB_SATYPE_ESP: 4741edc1b9aShshoexer rule->proto = IPSEC_ESP; 4751edc1b9aShshoexer break; 476b26a6cb5Shshoexer case SADB_SATYPE_AH: 4771edc1b9aShshoexer rule->proto = IPSEC_AH; 4781edc1b9aShshoexer break; 479b26a6cb5Shshoexer case SADB_X_SATYPE_IPCOMP: 4801edc1b9aShshoexer default: 4811edc1b9aShshoexer return (1); 4821edc1b9aShshoexer } 4831edc1b9aShshoexer 4841edc1b9aShshoexer for (ext = (struct sadb_ext *)(msg + 1); 4851edc1b9aShshoexer (size_t)((u_int8_t *)ext - (u_int8_t *)msg) < 486d5d1799eShshoexer msg->sadb_msg_len * PFKEYV2_CHUNK && ext->sadb_ext_len > 0; 4871edc1b9aShshoexer ext = (struct sadb_ext *)((u_int8_t *)ext + 4881edc1b9aShshoexer ext->sadb_ext_len * PFKEYV2_CHUNK)) { 4891edc1b9aShshoexer switch (ext->sadb_ext_type) { 4901edc1b9aShshoexer case SADB_EXT_ADDRESS_SRC: 491d5d1799eShshoexer #ifdef notyet 4921edc1b9aShshoexer saddr = (struct sadb_address *)ext; 4931edc1b9aShshoexer sa = (struct sockaddr *)(saddr + 1); 4941edc1b9aShshoexer 495d5d1799eShshoexer rule->local = calloc(1, sizeof(struct ipsec_addr)); 496d5d1799eShshoexer if (rule->local == NULL) 4971edc1b9aShshoexer err(1, "malloc"); 4981edc1b9aShshoexer 4991edc1b9aShshoexer switch (sa->sa_family) { 5001edc1b9aShshoexer case AF_INET: 5011edc1b9aShshoexer bcopy(&((struct sockaddr_in *)sa)->sin_addr, 502d5d1799eShshoexer &rule->local->v4, sizeof(struct in_addr)); 503d5d1799eShshoexer memset(&rule->local->v4mask, 0xff, 5041edc1b9aShshoexer sizeof(u_int32_t)); 505d5d1799eShshoexer rule->local->af = AF_INET; 5061edc1b9aShshoexer break; 5071edc1b9aShshoexer default: 5081edc1b9aShshoexer return (1); 5091edc1b9aShshoexer } 5101edc1b9aShshoexer #endif 5111edc1b9aShshoexer break; 5121edc1b9aShshoexer 5131edc1b9aShshoexer 5141edc1b9aShshoexer case SADB_EXT_ADDRESS_DST: 5151edc1b9aShshoexer saddr = (struct sadb_address *)ext; 5161edc1b9aShshoexer sa = (struct sockaddr *)(saddr + 1); 5171edc1b9aShshoexer 5181edc1b9aShshoexer rule->peer = calloc(1, sizeof(struct ipsec_addr)); 5191edc1b9aShshoexer if (rule->peer == NULL) 5201edc1b9aShshoexer err(1, "malloc"); 5211edc1b9aShshoexer 5221edc1b9aShshoexer switch (sa->sa_family) { 5231edc1b9aShshoexer case AF_INET: 5241edc1b9aShshoexer bcopy(&((struct sockaddr_in *)sa)->sin_addr, 5251edc1b9aShshoexer &rule->peer->v4, sizeof(struct in_addr)); 5261edc1b9aShshoexer memset(&rule->peer->v4mask, 0xff, 5271edc1b9aShshoexer sizeof(u_int32_t)); 5281edc1b9aShshoexer rule->peer->af = AF_INET; 5291edc1b9aShshoexer break; 5301edc1b9aShshoexer default: 5311edc1b9aShshoexer return (1); 5321edc1b9aShshoexer } 5331edc1b9aShshoexer break; 5341edc1b9aShshoexer 5351edc1b9aShshoexer case SADB_EXT_IDENTITY_SRC: 5361edc1b9aShshoexer sident = (struct sadb_ident *)ext; 5371edc1b9aShshoexer len = (sident->sadb_ident_len * sizeof(uint64_t)) - 5381edc1b9aShshoexer sizeof(struct sadb_ident); 5391edc1b9aShshoexer 5401edc1b9aShshoexer rule->auth.srcid = calloc(1, len); 5411edc1b9aShshoexer if (rule->auth.srcid == NULL) 5421edc1b9aShshoexer err(1, "calloc"); 5431edc1b9aShshoexer 5441edc1b9aShshoexer strlcpy(rule->auth.srcid, (char *)(sident + 1), len); 5451edc1b9aShshoexer break; 5461edc1b9aShshoexer 5471edc1b9aShshoexer case SADB_EXT_IDENTITY_DST: 5481edc1b9aShshoexer sident = (struct sadb_ident *)ext; 5491edc1b9aShshoexer len = (sident->sadb_ident_len * sizeof(uint64_t)) - 5501edc1b9aShshoexer sizeof(struct sadb_ident); 5511edc1b9aShshoexer 5521edc1b9aShshoexer rule->auth.dstid = calloc(1, len); 5531edc1b9aShshoexer if (rule->auth.dstid == NULL) 5541edc1b9aShshoexer err(1, "calloc"); 5551edc1b9aShshoexer 5561edc1b9aShshoexer strlcpy(rule->auth.dstid, (char *)(sident + 1), len); 5571edc1b9aShshoexer break; 5581edc1b9aShshoexer 5591edc1b9aShshoexer case SADB_X_EXT_PROTOCOL: 5601edc1b9aShshoexer /* XXX nothing yet? */ 5611edc1b9aShshoexer break; 5621edc1b9aShshoexer 5631edc1b9aShshoexer case SADB_X_EXT_FLOW_TYPE: 5641edc1b9aShshoexer sproto = (struct sadb_protocol *)ext; 5651edc1b9aShshoexer 5661edc1b9aShshoexer switch (sproto->sadb_protocol_direction) { 5671edc1b9aShshoexer case IPSP_DIRECTION_IN: 5681edc1b9aShshoexer rule->direction = IPSEC_IN; 5691edc1b9aShshoexer break; 5701edc1b9aShshoexer case IPSP_DIRECTION_OUT: 5711edc1b9aShshoexer rule->direction = IPSEC_OUT; 5721edc1b9aShshoexer break; 5731edc1b9aShshoexer default: 5741edc1b9aShshoexer return (1); 5751edc1b9aShshoexer } 5766122c05eShshoexer switch (sproto->sadb_protocol_proto) { 5776122c05eShshoexer case SADB_X_FLOW_TYPE_USE: 5781a3f035aShshoexer rule->flowtype = TYPE_USE; 5796122c05eShshoexer break; 5806122c05eShshoexer case SADB_X_FLOW_TYPE_ACQUIRE: 5811a3f035aShshoexer rule->flowtype = TYPE_ACQUIRE; 5826122c05eShshoexer break; 5836122c05eShshoexer case SADB_X_FLOW_TYPE_REQUIRE: 5841a3f035aShshoexer rule->flowtype = TYPE_REQUIRE; 5856122c05eShshoexer break; 5866122c05eShshoexer case SADB_X_FLOW_TYPE_DENY: 5871a3f035aShshoexer rule->flowtype = TYPE_DENY; 5886122c05eShshoexer break; 5896122c05eShshoexer case SADB_X_FLOW_TYPE_BYPASS: 5901a3f035aShshoexer rule->flowtype = TYPE_BYPASS; 5916122c05eShshoexer break; 5926122c05eShshoexer case SADB_X_FLOW_TYPE_DONTACQ: 5931a3f035aShshoexer rule->flowtype = TYPE_DONTACQ; 5946122c05eShshoexer break; 5956122c05eShshoexer default: 5961a3f035aShshoexer rule->flowtype = TYPE_UNKNOWN; 5976122c05eShshoexer break; 5986122c05eShshoexer } 5991edc1b9aShshoexer break; 6001edc1b9aShshoexer 6011edc1b9aShshoexer case SADB_X_EXT_SRC_FLOW: 6021edc1b9aShshoexer saddr = (struct sadb_address *)ext; 6031edc1b9aShshoexer sa = (struct sockaddr *)(saddr + 1); 6041edc1b9aShshoexer 6051edc1b9aShshoexer if (rule->src == NULL) { 6061edc1b9aShshoexer rule->src = calloc(1, 6071edc1b9aShshoexer sizeof(struct ipsec_addr)); 6081edc1b9aShshoexer if (rule->src == NULL) 6091edc1b9aShshoexer err(1, "calloc"); 6101edc1b9aShshoexer } 6111edc1b9aShshoexer 6121edc1b9aShshoexer switch (sa->sa_family) { 6131edc1b9aShshoexer case AF_INET: 6141edc1b9aShshoexer bcopy(&((struct sockaddr_in *)sa)->sin_addr, 6151edc1b9aShshoexer &rule->src->v4, sizeof(struct in_addr)); 6161edc1b9aShshoexer rule->src->af = AF_INET; 6171edc1b9aShshoexer break; 6181edc1b9aShshoexer default: 6191edc1b9aShshoexer return (1); 6201edc1b9aShshoexer } 6211edc1b9aShshoexer break; 6221edc1b9aShshoexer 6231edc1b9aShshoexer case SADB_X_EXT_DST_FLOW: 6241edc1b9aShshoexer saddr = (struct sadb_address *)ext; 6251edc1b9aShshoexer sa = (struct sockaddr *)(saddr + 1); 6261edc1b9aShshoexer 6271edc1b9aShshoexer if (rule->dst == NULL) { 6281edc1b9aShshoexer rule->dst = calloc(1, 6291edc1b9aShshoexer sizeof(struct ipsec_addr)); 6301edc1b9aShshoexer if (rule->dst == NULL) 6311edc1b9aShshoexer err(1, "calloc"); 6321edc1b9aShshoexer } 6331edc1b9aShshoexer 6341edc1b9aShshoexer switch (sa->sa_family) { 6351edc1b9aShshoexer case AF_INET: 6361edc1b9aShshoexer bcopy(&((struct sockaddr_in *)sa)->sin_addr, 6371edc1b9aShshoexer &rule->dst->v4, sizeof(struct in_addr)); 6381edc1b9aShshoexer rule->dst->af = AF_INET; 6391edc1b9aShshoexer break; 6401edc1b9aShshoexer 6411edc1b9aShshoexer default: 6421edc1b9aShshoexer return (1); 6431edc1b9aShshoexer } 6441edc1b9aShshoexer break; 6451edc1b9aShshoexer 6461edc1b9aShshoexer 6471edc1b9aShshoexer case SADB_X_EXT_SRC_MASK: 6481edc1b9aShshoexer saddr = (struct sadb_address *)ext; 6491edc1b9aShshoexer sa = (struct sockaddr *)(saddr + 1); 6501edc1b9aShshoexer 6511edc1b9aShshoexer if (rule->src == NULL) { 6521edc1b9aShshoexer rule->src = calloc(1, 6531edc1b9aShshoexer sizeof(struct ipsec_addr)); 6541edc1b9aShshoexer if (rule->src == NULL) 6551edc1b9aShshoexer err(1, "calloc"); 6561edc1b9aShshoexer } 6571edc1b9aShshoexer 6581edc1b9aShshoexer switch (sa->sa_family) { 6591edc1b9aShshoexer case AF_INET: 6601edc1b9aShshoexer bcopy(&((struct sockaddr_in *)sa)->sin_addr, 6611edc1b9aShshoexer &rule->src->v4mask.mask, 6621edc1b9aShshoexer sizeof(struct in_addr)); 6631edc1b9aShshoexer rule->src->af = AF_INET; 6641edc1b9aShshoexer break; 6651edc1b9aShshoexer 6661edc1b9aShshoexer default: 6671edc1b9aShshoexer return (1); 6681edc1b9aShshoexer } 6691edc1b9aShshoexer break; 6701edc1b9aShshoexer 6711edc1b9aShshoexer case SADB_X_EXT_DST_MASK: 6721edc1b9aShshoexer saddr = (struct sadb_address *)ext; 6731edc1b9aShshoexer sa = (struct sockaddr *)(saddr + 1); 6741edc1b9aShshoexer 6751edc1b9aShshoexer if (rule->dst == NULL) { 6761edc1b9aShshoexer rule->dst = calloc(1, 6771edc1b9aShshoexer sizeof(struct ipsec_addr)); 6781edc1b9aShshoexer if (rule->dst == NULL) 6791edc1b9aShshoexer err(1, "calloc"); 6801edc1b9aShshoexer } 6811edc1b9aShshoexer 6821edc1b9aShshoexer switch (sa->sa_family) { 6831edc1b9aShshoexer case AF_INET: 6841edc1b9aShshoexer bcopy(&((struct sockaddr_in *)sa)->sin_addr, 6851edc1b9aShshoexer &rule->dst->v4mask.mask, 6861edc1b9aShshoexer sizeof(struct in_addr)); 6871edc1b9aShshoexer rule->dst->af = AF_INET; 6881edc1b9aShshoexer break; 6891edc1b9aShshoexer 6901edc1b9aShshoexer default: 6911edc1b9aShshoexer return (1); 6921edc1b9aShshoexer } 6931edc1b9aShshoexer break; 6941edc1b9aShshoexer 6951edc1b9aShshoexer default: 6961edc1b9aShshoexer return (1); 6971edc1b9aShshoexer } 6981edc1b9aShshoexer } 6991edc1b9aShshoexer 7001edc1b9aShshoexer return (0); 7011edc1b9aShshoexer } 7021edc1b9aShshoexer 7031edc1b9aShshoexer int 704356121f6Shshoexer pfkey_ipsec_establish(int action, struct ipsec_rule *r) 705f484f2cfShshoexer { 70622a29ad6Shshoexer int ret; 70722a29ad6Shshoexer u_int8_t satype, direction; 708f484f2cfShshoexer 709f032086dShshoexer if (r->type == RULE_FLOW) { 710f484f2cfShshoexer switch (r->proto) { 711f484f2cfShshoexer case IPSEC_ESP: 712f484f2cfShshoexer satype = SADB_SATYPE_ESP; 713f484f2cfShshoexer break; 714f484f2cfShshoexer case IPSEC_AH: 715f484f2cfShshoexer satype = SADB_SATYPE_AH; 716f484f2cfShshoexer break; 717f484f2cfShshoexer case IPSEC_COMP: 718f484f2cfShshoexer default: 719f484f2cfShshoexer return -1; 720f484f2cfShshoexer } 721f484f2cfShshoexer 722f484f2cfShshoexer switch (r->direction) { 723f484f2cfShshoexer case IPSEC_IN: 724f484f2cfShshoexer direction = IPSP_DIRECTION_IN; 725f484f2cfShshoexer break; 726f484f2cfShshoexer case IPSEC_OUT: 727f484f2cfShshoexer direction = IPSP_DIRECTION_OUT; 728f484f2cfShshoexer break; 729f484f2cfShshoexer default: 730f484f2cfShshoexer return -1; 731f484f2cfShshoexer } 732f484f2cfShshoexer 73322a29ad6Shshoexer switch (action) { 73422a29ad6Shshoexer case PFK_ACTION_ADD: 735f032086dShshoexer ret = pfkey_flow(fd, satype, SADB_X_ADDFLOW, direction, 736f032086dShshoexer r->src, r->dst, r->peer, r->auth, r->flowtype); 73722a29ad6Shshoexer break; 73822a29ad6Shshoexer case PFK_ACTION_DELETE: 73922a29ad6Shshoexer /* No peer for flow deletion. */ 740f032086dShshoexer ret = pfkey_flow(fd, satype, SADB_X_DELFLOW, direction, 741f032086dShshoexer r->src, r->dst, NULL, r->auth, r->flowtype); 74222a29ad6Shshoexer break; 74322a29ad6Shshoexer default: 74422a29ad6Shshoexer return -1; 74522a29ad6Shshoexer } 746f032086dShshoexer } else if (r->type == RULE_SA) { 747f032086dShshoexer satype = SADB_X_SATYPE_TCPSIGNATURE; 748f032086dShshoexer switch (action) { 749f032086dShshoexer case PFK_ACTION_ADD: 750f032086dShshoexer ret = pfkey_sa(fd, satype, SADB_ADD, r->spi, 751f032086dShshoexer r->src, r->dst, r->key); 752f032086dShshoexer break; 753f032086dShshoexer case PFK_ACTION_DELETE: 754f032086dShshoexer ret = pfkey_sa(fd, satype, SADB_DELETE, r->spi, 755f032086dShshoexer r->src, r->dst, r->key); 756f032086dShshoexer break; 757f032086dShshoexer default: 758f032086dShshoexer return -1; 759f032086dShshoexer } 760f032086dShshoexer } else 761f032086dShshoexer return -1; 762f032086dShshoexer 76322a29ad6Shshoexer if (ret < 0) 764f484f2cfShshoexer return -1; 765f484f2cfShshoexer if (pfkey_reply(fd) < 0) 766f484f2cfShshoexer return -1; 767f484f2cfShshoexer 768f484f2cfShshoexer return 0; 769f484f2cfShshoexer } 770f484f2cfShshoexer 771f484f2cfShshoexer int 772f484f2cfShshoexer pfkey_ipsec_flush(void) 773f484f2cfShshoexer { 774f484f2cfShshoexer struct sadb_msg smsg; 775f484f2cfShshoexer struct iovec iov[IOV_CNT]; 776f484f2cfShshoexer ssize_t n; 777f484f2cfShshoexer int iov_cnt, len; 778f484f2cfShshoexer 779f484f2cfShshoexer bzero(&smsg, sizeof(smsg)); 780f484f2cfShshoexer smsg.sadb_msg_version = PF_KEY_V2; 781f484f2cfShshoexer smsg.sadb_msg_seq = sadb_msg_seq++; 782f484f2cfShshoexer smsg.sadb_msg_pid = getpid(); 783f484f2cfShshoexer smsg.sadb_msg_len = sizeof(smsg) / 8; 784f484f2cfShshoexer smsg.sadb_msg_type = SADB_FLUSH; 785f484f2cfShshoexer smsg.sadb_msg_satype = SADB_SATYPE_UNSPEC; 786f484f2cfShshoexer 787f484f2cfShshoexer iov_cnt = 0; 788f484f2cfShshoexer 789f484f2cfShshoexer iov[iov_cnt].iov_base = &smsg; 790f484f2cfShshoexer iov[iov_cnt].iov_len = sizeof(smsg); 791f484f2cfShshoexer iov_cnt++; 792f484f2cfShshoexer 793f484f2cfShshoexer len = smsg.sadb_msg_len * 8; 794f484f2cfShshoexer if ((n = writev(fd, iov, iov_cnt)) == -1) { 795f484f2cfShshoexer warn("writev failed"); 796f484f2cfShshoexer return -1; 797f484f2cfShshoexer } 798f484f2cfShshoexer if (n != len) { 799f484f2cfShshoexer warnx("short write"); 800f484f2cfShshoexer return -1; 801f484f2cfShshoexer } 802f484f2cfShshoexer if (pfkey_reply(fd) < 0) 803f484f2cfShshoexer return -1; 804f484f2cfShshoexer 805f484f2cfShshoexer return 0; 806f484f2cfShshoexer } 807f484f2cfShshoexer 808f484f2cfShshoexer int 809f484f2cfShshoexer pfkey_init(void) 810f484f2cfShshoexer { 811f484f2cfShshoexer if ((fd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) == -1) 812f484f2cfShshoexer err(1, "failed to open PF_KEY socket"); 813f484f2cfShshoexer 814f484f2cfShshoexer return 0; 815f484f2cfShshoexer } 816