1*6122c05eShshoexer /* $OpenBSD: pfkey.c,v 1.8 2005/05/27 19:55:21 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 44f484f2cfShshoexer static int pfkey_flow(int, u_int8_t, u_int8_t, u_int8_t, struct ipsec_addr *, 45f484f2cfShshoexer struct ipsec_addr *, struct ipsec_addr *, 46f484f2cfShshoexer struct ipsec_auth); 47f484f2cfShshoexer static int pfkey_reply(int); 48f484f2cfShshoexer int pfkey_ipsec_flush(void); 49f484f2cfShshoexer int pfkey_ipsec_establish(struct ipsec_rule *); 50f484f2cfShshoexer int pfkey_init(void); 51f484f2cfShshoexer 52f484f2cfShshoexer static int 53f484f2cfShshoexer pfkey_flow(int sd, u_int8_t satype, u_int8_t action, u_int8_t direction, 54f484f2cfShshoexer struct ipsec_addr *src, struct ipsec_addr *dst, struct ipsec_addr *peer, 55f484f2cfShshoexer struct ipsec_auth auth) 56f484f2cfShshoexer { 57f484f2cfShshoexer struct sadb_msg smsg; 58f484f2cfShshoexer struct sadb_address sa_src, sa_dst, sa_peer, sa_smask, sa_dmask; 59f484f2cfShshoexer struct sadb_protocol sa_flowtype, sa_protocol; 60f484f2cfShshoexer struct sadb_ident *sa_srcid, *sa_dstid; 61f484f2cfShshoexer struct sockaddr_storage ssrc, sdst, speer, smask, dmask; 62f484f2cfShshoexer struct iovec iov[IOV_CNT]; 63f484f2cfShshoexer ssize_t n; 64f484f2cfShshoexer int iov_cnt, len, ret = 0; 65f484f2cfShshoexer 66f484f2cfShshoexer sa_srcid = sa_dstid = NULL; 67f484f2cfShshoexer 68f484f2cfShshoexer bzero(&ssrc, sizeof(ssrc)); 69f484f2cfShshoexer bzero(&smask, sizeof(smask)); 70f484f2cfShshoexer switch (src->af) { 71f484f2cfShshoexer case AF_INET: 72f484f2cfShshoexer ((struct sockaddr_in *)&ssrc)->sin_addr = src->v4; 73f484f2cfShshoexer ssrc.ss_len = sizeof(struct sockaddr_in); 74f484f2cfShshoexer ssrc.ss_family = AF_INET; 75f484f2cfShshoexer ((struct sockaddr_in *)&smask)->sin_addr = src->v4mask.mask; 76f484f2cfShshoexer break; 77f484f2cfShshoexer case AF_INET6: 78f484f2cfShshoexer default: 79f484f2cfShshoexer warnx("unsupported address family %d", src->af); 80f484f2cfShshoexer return -1; 81f484f2cfShshoexer } 82f484f2cfShshoexer smask.ss_family = ssrc.ss_family; 83f484f2cfShshoexer smask.ss_len = ssrc.ss_len; 84f484f2cfShshoexer 85f484f2cfShshoexer bzero(&sdst, sizeof(sdst)); 86f484f2cfShshoexer bzero(&dmask, sizeof(dmask)); 87f484f2cfShshoexer switch (dst->af) { 88f484f2cfShshoexer case AF_INET: 89f484f2cfShshoexer ((struct sockaddr_in *)&sdst)->sin_addr = dst->v4; 90f484f2cfShshoexer sdst.ss_len = sizeof(struct sockaddr_in); 91f484f2cfShshoexer sdst.ss_family = AF_INET; 92f484f2cfShshoexer ((struct sockaddr_in *)&dmask)->sin_addr = dst->v4mask.mask; 93f484f2cfShshoexer break; 94f484f2cfShshoexer case AF_INET6: 95f484f2cfShshoexer default: 96f484f2cfShshoexer warnx("unsupported address family %d", dst->af); 97f484f2cfShshoexer return -1; 98f484f2cfShshoexer } 99f484f2cfShshoexer dmask.ss_family = sdst.ss_family; 100f484f2cfShshoexer dmask.ss_len = sdst.ss_len; 101f484f2cfShshoexer 102f484f2cfShshoexer bzero(&speer, sizeof(speer)); 103f484f2cfShshoexer switch (peer->af) { 104f484f2cfShshoexer case AF_INET: 105f484f2cfShshoexer ((struct sockaddr_in *)&speer)->sin_addr = peer->v4; 106f484f2cfShshoexer speer.ss_len = sizeof(struct sockaddr_in); 107f484f2cfShshoexer speer.ss_family = AF_INET; 108f484f2cfShshoexer break; 109f484f2cfShshoexer case AF_INET6: 110f484f2cfShshoexer default: 111f484f2cfShshoexer warnx("unsupported address family %d", peer->af); 112f484f2cfShshoexer return -1; 113f484f2cfShshoexer } 114f484f2cfShshoexer 115f484f2cfShshoexer bzero(&smsg, sizeof(smsg)); 116f484f2cfShshoexer smsg.sadb_msg_version = PF_KEY_V2; 117f484f2cfShshoexer smsg.sadb_msg_seq = sadb_msg_seq++; 118f484f2cfShshoexer smsg.sadb_msg_pid = getpid(); 119f484f2cfShshoexer smsg.sadb_msg_len = sizeof(smsg) / 8; 120f484f2cfShshoexer smsg.sadb_msg_type = action; 121f484f2cfShshoexer smsg.sadb_msg_satype = satype; 122f484f2cfShshoexer 123f484f2cfShshoexer bzero(&sa_flowtype, sizeof(sa_flowtype)); 124f484f2cfShshoexer sa_flowtype.sadb_protocol_exttype = SADB_X_EXT_FLOW_TYPE; 125f484f2cfShshoexer sa_flowtype.sadb_protocol_len = sizeof(sa_flowtype) / 8; 126f484f2cfShshoexer sa_flowtype.sadb_protocol_direction = direction; 12726df514dShshoexer 12826df514dShshoexer if (direction == IPSP_DIRECTION_IN) 12926df514dShshoexer sa_flowtype.sadb_protocol_proto = SADB_X_FLOW_TYPE_USE; 13026df514dShshoexer else 131f484f2cfShshoexer sa_flowtype.sadb_protocol_proto = SADB_X_FLOW_TYPE_REQUIRE; 132f484f2cfShshoexer 133f484f2cfShshoexer bzero(&sa_protocol, sizeof(sa_protocol)); 134f484f2cfShshoexer sa_protocol.sadb_protocol_exttype = SADB_X_EXT_PROTOCOL; 135f484f2cfShshoexer sa_protocol.sadb_protocol_len = sizeof(sa_protocol) / 8; 136f484f2cfShshoexer sa_protocol.sadb_protocol_direction = 0; 137f484f2cfShshoexer sa_protocol.sadb_protocol_proto = IPPROTO_IP; 138f484f2cfShshoexer 139f484f2cfShshoexer bzero(&sa_src, sizeof(sa_src)); 140f484f2cfShshoexer sa_src.sadb_address_exttype = SADB_X_EXT_SRC_FLOW; 141f484f2cfShshoexer sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(ssrc.ss_len)) / 8; 142f484f2cfShshoexer 143f484f2cfShshoexer bzero(&sa_smask, sizeof(sa_smask)); 144f484f2cfShshoexer sa_smask.sadb_address_exttype = SADB_X_EXT_SRC_MASK; 145f484f2cfShshoexer sa_smask.sadb_address_len = 146f484f2cfShshoexer (sizeof(sa_smask) + ROUNDUP(smask.ss_len)) / 8; 147f484f2cfShshoexer 148f484f2cfShshoexer bzero(&sa_dst, sizeof(sa_dst)); 149f484f2cfShshoexer sa_dst.sadb_address_exttype = SADB_X_EXT_DST_FLOW; 150f484f2cfShshoexer sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(sdst.ss_len)) / 8; 151f484f2cfShshoexer 152f484f2cfShshoexer bzero(&sa_dmask, sizeof(sa_dmask)); 153f484f2cfShshoexer sa_dmask.sadb_address_exttype = SADB_X_EXT_DST_MASK; 154f484f2cfShshoexer sa_dmask.sadb_address_len = 155f484f2cfShshoexer (sizeof(sa_dmask) + ROUNDUP(dmask.ss_len)) / 8; 156f484f2cfShshoexer 157f484f2cfShshoexer bzero(&sa_peer, sizeof(sa_peer)); 158f484f2cfShshoexer sa_peer.sadb_address_exttype = SADB_EXT_ADDRESS_DST; 159f484f2cfShshoexer sa_peer.sadb_address_len = 160f484f2cfShshoexer (sizeof(sa_peer) + ROUNDUP(speer.ss_len)) / 8; 161f484f2cfShshoexer 162f484f2cfShshoexer if (auth.srcid) { 163f484f2cfShshoexer len = ROUNDUP(strlen(auth.srcid) + 1) + sizeof(*sa_srcid); 164f484f2cfShshoexer 165f484f2cfShshoexer sa_srcid = calloc(len, sizeof(u_int8_t)); 166f484f2cfShshoexer if (sa_srcid == NULL) 167f484f2cfShshoexer err(1, "calloc"); 168f484f2cfShshoexer 169f484f2cfShshoexer sa_srcid->sadb_ident_type = auth.idtype; 170f484f2cfShshoexer sa_srcid->sadb_ident_len = len / 8; 171f484f2cfShshoexer sa_srcid->sadb_ident_exttype = SADB_EXT_IDENTITY_SRC; 172f484f2cfShshoexer 173f484f2cfShshoexer strlcpy((char *)(sa_srcid + 1), auth.srcid, 174f484f2cfShshoexer ROUNDUP(strlen(auth.srcid) + 1)); 175f484f2cfShshoexer } 176f484f2cfShshoexer if (auth.dstid) { 177f484f2cfShshoexer len = ROUNDUP(strlen(auth.dstid) + 1) + sizeof(*sa_dstid); 178f484f2cfShshoexer 179f484f2cfShshoexer sa_dstid = calloc(len, sizeof(u_int8_t)); 180f484f2cfShshoexer if (sa_dstid == NULL) 181f484f2cfShshoexer err(1, "calloc"); 182f484f2cfShshoexer 183f484f2cfShshoexer sa_dstid->sadb_ident_type = auth.idtype; 184f484f2cfShshoexer sa_dstid->sadb_ident_len = len / 8; 185f484f2cfShshoexer sa_dstid->sadb_ident_exttype = SADB_EXT_IDENTITY_DST; 186f484f2cfShshoexer 187f484f2cfShshoexer strlcpy((char *)(sa_dstid + 1), auth.dstid, 188f484f2cfShshoexer ROUNDUP(strlen(auth.dstid) + 1)); 189f484f2cfShshoexer } 190f484f2cfShshoexer 191f484f2cfShshoexer iov_cnt = 0; 192f484f2cfShshoexer 193f484f2cfShshoexer /* header */ 194f484f2cfShshoexer iov[iov_cnt].iov_base = &smsg; 195f484f2cfShshoexer iov[iov_cnt].iov_len = sizeof(smsg); 196f484f2cfShshoexer iov_cnt++; 197f484f2cfShshoexer 19889ad8c34Shshoexer /* add flow type */ 19989ad8c34Shshoexer iov[iov_cnt].iov_base = &sa_flowtype; 20089ad8c34Shshoexer iov[iov_cnt].iov_len = sizeof(sa_flowtype); 20189ad8c34Shshoexer smsg.sadb_msg_len += sa_flowtype.sadb_protocol_len; 20289ad8c34Shshoexer iov_cnt++; 20389ad8c34Shshoexer 204f484f2cfShshoexer /* remote peer */ 205f484f2cfShshoexer iov[iov_cnt].iov_base = &sa_peer; 206f484f2cfShshoexer iov[iov_cnt].iov_len = sizeof(sa_peer); 207f484f2cfShshoexer iov_cnt++; 208f484f2cfShshoexer iov[iov_cnt].iov_base = &speer; 209f484f2cfShshoexer iov[iov_cnt].iov_len = ROUNDUP(speer.ss_len); 210f484f2cfShshoexer smsg.sadb_msg_len += sa_peer.sadb_address_len; 211f484f2cfShshoexer iov_cnt++; 212f484f2cfShshoexer 21389ad8c34Shshoexer /* src addr */ 21489ad8c34Shshoexer iov[iov_cnt].iov_base = &sa_src; 21589ad8c34Shshoexer iov[iov_cnt].iov_len = sizeof(sa_src); 21689ad8c34Shshoexer iov_cnt++; 21789ad8c34Shshoexer iov[iov_cnt].iov_base = &ssrc; 21889ad8c34Shshoexer iov[iov_cnt].iov_len = ROUNDUP(ssrc.ss_len); 21989ad8c34Shshoexer smsg.sadb_msg_len += sa_src.sadb_address_len; 220f484f2cfShshoexer iov_cnt++; 221f484f2cfShshoexer 22289ad8c34Shshoexer /* src mask */ 223f484f2cfShshoexer iov[iov_cnt].iov_base = &sa_smask; 224f484f2cfShshoexer iov[iov_cnt].iov_len = sizeof(sa_smask); 225f484f2cfShshoexer iov_cnt++; 226f484f2cfShshoexer iov[iov_cnt].iov_base = &smask; 227f484f2cfShshoexer iov[iov_cnt].iov_len = ROUNDUP(smask.ss_len); 228f484f2cfShshoexer smsg.sadb_msg_len += sa_smask.sadb_address_len; 229f484f2cfShshoexer iov_cnt++; 230f484f2cfShshoexer 231f484f2cfShshoexer /* dest addr */ 232f484f2cfShshoexer iov[iov_cnt].iov_base = &sa_dst; 233f484f2cfShshoexer iov[iov_cnt].iov_len = sizeof(sa_dst); 234f484f2cfShshoexer iov_cnt++; 235f484f2cfShshoexer iov[iov_cnt].iov_base = &sdst; 236f484f2cfShshoexer iov[iov_cnt].iov_len = ROUNDUP(sdst.ss_len); 237f484f2cfShshoexer smsg.sadb_msg_len += sa_dst.sadb_address_len; 238f484f2cfShshoexer iov_cnt++; 239f484f2cfShshoexer 24089ad8c34Shshoexer /* dst mask */ 24189ad8c34Shshoexer iov[iov_cnt].iov_base = &sa_dmask; 24289ad8c34Shshoexer iov[iov_cnt].iov_len = sizeof(sa_dmask); 243f484f2cfShshoexer iov_cnt++; 24489ad8c34Shshoexer iov[iov_cnt].iov_base = &dmask; 24589ad8c34Shshoexer iov[iov_cnt].iov_len = ROUNDUP(dmask.ss_len); 24689ad8c34Shshoexer smsg.sadb_msg_len += sa_dmask.sadb_address_len; 24789ad8c34Shshoexer iov_cnt++; 24889ad8c34Shshoexer 24989ad8c34Shshoexer /* add protocol */ 25089ad8c34Shshoexer iov[iov_cnt].iov_base = &sa_protocol; 25189ad8c34Shshoexer iov[iov_cnt].iov_len = sizeof(sa_protocol); 25289ad8c34Shshoexer smsg.sadb_msg_len += sa_protocol.sadb_protocol_len; 253f484f2cfShshoexer iov_cnt++; 254f484f2cfShshoexer 255f484f2cfShshoexer if (sa_srcid) { 256f484f2cfShshoexer /* src identity */ 257f484f2cfShshoexer iov[iov_cnt].iov_base = sa_srcid; 258f484f2cfShshoexer iov[iov_cnt].iov_len = sa_srcid->sadb_ident_len * 8; 259f484f2cfShshoexer smsg.sadb_msg_len += sa_srcid->sadb_ident_len; 260f484f2cfShshoexer iov_cnt++; 261f484f2cfShshoexer } 262f484f2cfShshoexer if (sa_dstid) { 263f484f2cfShshoexer /* dst identity */ 264f484f2cfShshoexer iov[iov_cnt].iov_base = sa_dstid; 265f484f2cfShshoexer iov[iov_cnt].iov_len = sa_dstid->sadb_ident_len * 8; 266f484f2cfShshoexer smsg.sadb_msg_len += sa_dstid->sadb_ident_len; 267f484f2cfShshoexer iov_cnt++; 268f484f2cfShshoexer } 269f484f2cfShshoexer len = smsg.sadb_msg_len * 8; 270f484f2cfShshoexer if ((n = writev(sd, iov, iov_cnt)) == -1) { 271f484f2cfShshoexer warn("writev failed"); 272f484f2cfShshoexer ret = -1; 273f484f2cfShshoexer goto out; 274f484f2cfShshoexer } 275f484f2cfShshoexer if (n != len) { 276f484f2cfShshoexer warnx("short write"); 277f484f2cfShshoexer ret = -1; 278f484f2cfShshoexer } 279f484f2cfShshoexer 280f484f2cfShshoexer out: 281f484f2cfShshoexer if (sa_srcid) 282f484f2cfShshoexer free(sa_srcid); 283f484f2cfShshoexer if (sa_dstid) 284f484f2cfShshoexer free(sa_dstid); 285f484f2cfShshoexer 286f484f2cfShshoexer return ret; 287f484f2cfShshoexer } 288f484f2cfShshoexer 289f484f2cfShshoexer static int 290f484f2cfShshoexer pfkey_reply(int sd) 291f484f2cfShshoexer { 292f484f2cfShshoexer struct sadb_msg hdr; 293f484f2cfShshoexer ssize_t len; 294f484f2cfShshoexer u_int8_t *data; 295f484f2cfShshoexer 296f484f2cfShshoexer if (recv(sd, &hdr, sizeof(hdr), MSG_PEEK) != sizeof(hdr)) { 297f484f2cfShshoexer warnx("short read"); 298f484f2cfShshoexer return -1; 299f484f2cfShshoexer } 300f484f2cfShshoexer if (hdr.sadb_msg_errno != 0) { 301f484f2cfShshoexer errno = hdr.sadb_msg_errno; 302f484f2cfShshoexer if (errno == ESRCH) 303f484f2cfShshoexer return 0; 304f484f2cfShshoexer else { 305f484f2cfShshoexer warn("PF_KEY returned error"); 306f484f2cfShshoexer return -1; 307f484f2cfShshoexer } 308f484f2cfShshoexer } 309f484f2cfShshoexer len = hdr.sadb_msg_len * PFKEYV2_CHUNK; 310f484f2cfShshoexer if ((data = malloc(len)) == NULL) 311f484f2cfShshoexer err(1, NULL); 312f484f2cfShshoexer if (read(sd, data, len) != len) { 313f484f2cfShshoexer warn("PF_KEY short read"); 314f484f2cfShshoexer bzero(data, len); 315f484f2cfShshoexer free(data); 316f484f2cfShshoexer return -1; 317f484f2cfShshoexer } 318f484f2cfShshoexer bzero(data, len); 319f484f2cfShshoexer free(data); 320f484f2cfShshoexer 321f484f2cfShshoexer return 0; 322f484f2cfShshoexer } 323f484f2cfShshoexer 324f484f2cfShshoexer int 3251edc1b9aShshoexer pfkey_parse(struct sadb_msg *msg, struct ipsec_rule *rule) 3261edc1b9aShshoexer { 3271edc1b9aShshoexer struct sadb_ext *ext; 3281edc1b9aShshoexer struct sadb_address *saddr; 3291edc1b9aShshoexer struct sadb_protocol *sproto; 3301edc1b9aShshoexer struct sadb_ident *sident; 3311edc1b9aShshoexer struct sockaddr *sa; 3321edc1b9aShshoexer int len; 3331edc1b9aShshoexer 3341edc1b9aShshoexer switch (msg->sadb_msg_satype) { 335b26a6cb5Shshoexer case SADB_SATYPE_ESP: 3361edc1b9aShshoexer rule->proto = IPSEC_ESP; 3371edc1b9aShshoexer break; 338b26a6cb5Shshoexer case SADB_SATYPE_AH: 3391edc1b9aShshoexer rule->proto = IPSEC_AH; 3401edc1b9aShshoexer break; 341b26a6cb5Shshoexer case SADB_X_SATYPE_IPCOMP: 3421edc1b9aShshoexer default: 3431edc1b9aShshoexer return (1); 3441edc1b9aShshoexer } 3451edc1b9aShshoexer 3461edc1b9aShshoexer for (ext = (struct sadb_ext *)(msg + 1); 3471edc1b9aShshoexer (size_t)((u_int8_t *)ext - (u_int8_t *)msg) < 348d5d1799eShshoexer msg->sadb_msg_len * PFKEYV2_CHUNK && ext->sadb_ext_len > 0; 3491edc1b9aShshoexer ext = (struct sadb_ext *)((u_int8_t *)ext + 3501edc1b9aShshoexer ext->sadb_ext_len * PFKEYV2_CHUNK)) { 3511edc1b9aShshoexer switch (ext->sadb_ext_type) { 3521edc1b9aShshoexer case SADB_EXT_ADDRESS_SRC: 353d5d1799eShshoexer #ifdef notyet 3541edc1b9aShshoexer saddr = (struct sadb_address *)ext; 3551edc1b9aShshoexer sa = (struct sockaddr *)(saddr + 1); 3561edc1b9aShshoexer 357d5d1799eShshoexer rule->local = calloc(1, sizeof(struct ipsec_addr)); 358d5d1799eShshoexer if (rule->local == NULL) 3591edc1b9aShshoexer err(1, "malloc"); 3601edc1b9aShshoexer 3611edc1b9aShshoexer switch (sa->sa_family) { 3621edc1b9aShshoexer case AF_INET: 3631edc1b9aShshoexer bcopy(&((struct sockaddr_in *)sa)->sin_addr, 364d5d1799eShshoexer &rule->local->v4, sizeof(struct in_addr)); 365d5d1799eShshoexer memset(&rule->local->v4mask, 0xff, 3661edc1b9aShshoexer sizeof(u_int32_t)); 367d5d1799eShshoexer rule->local->af = AF_INET; 3681edc1b9aShshoexer break; 3691edc1b9aShshoexer default: 3701edc1b9aShshoexer return (1); 3711edc1b9aShshoexer } 3721edc1b9aShshoexer #endif 3731edc1b9aShshoexer break; 3741edc1b9aShshoexer 3751edc1b9aShshoexer 3761edc1b9aShshoexer case SADB_EXT_ADDRESS_DST: 3771edc1b9aShshoexer saddr = (struct sadb_address *)ext; 3781edc1b9aShshoexer sa = (struct sockaddr *)(saddr + 1); 3791edc1b9aShshoexer 3801edc1b9aShshoexer rule->peer = calloc(1, sizeof(struct ipsec_addr)); 3811edc1b9aShshoexer if (rule->peer == NULL) 3821edc1b9aShshoexer err(1, "malloc"); 3831edc1b9aShshoexer 3841edc1b9aShshoexer switch (sa->sa_family) { 3851edc1b9aShshoexer case AF_INET: 3861edc1b9aShshoexer bcopy(&((struct sockaddr_in *)sa)->sin_addr, 3871edc1b9aShshoexer &rule->peer->v4, sizeof(struct in_addr)); 3881edc1b9aShshoexer memset(&rule->peer->v4mask, 0xff, 3891edc1b9aShshoexer sizeof(u_int32_t)); 3901edc1b9aShshoexer rule->peer->af = AF_INET; 3911edc1b9aShshoexer break; 3921edc1b9aShshoexer default: 3931edc1b9aShshoexer return (1); 3941edc1b9aShshoexer } 3951edc1b9aShshoexer break; 3961edc1b9aShshoexer 3971edc1b9aShshoexer case SADB_EXT_IDENTITY_SRC: 3981edc1b9aShshoexer sident = (struct sadb_ident *)ext; 3991edc1b9aShshoexer len = (sident->sadb_ident_len * sizeof(uint64_t)) - 4001edc1b9aShshoexer sizeof(struct sadb_ident); 4011edc1b9aShshoexer 4021edc1b9aShshoexer rule->auth.srcid = calloc(1, len); 4031edc1b9aShshoexer if (rule->auth.srcid == NULL) 4041edc1b9aShshoexer err(1, "calloc"); 4051edc1b9aShshoexer 4061edc1b9aShshoexer strlcpy(rule->auth.srcid, (char *)(sident + 1), len); 4071edc1b9aShshoexer break; 4081edc1b9aShshoexer 4091edc1b9aShshoexer case SADB_EXT_IDENTITY_DST: 4101edc1b9aShshoexer sident = (struct sadb_ident *)ext; 4111edc1b9aShshoexer len = (sident->sadb_ident_len * sizeof(uint64_t)) - 4121edc1b9aShshoexer sizeof(struct sadb_ident); 4131edc1b9aShshoexer 4141edc1b9aShshoexer rule->auth.dstid = calloc(1, len); 4151edc1b9aShshoexer if (rule->auth.dstid == NULL) 4161edc1b9aShshoexer err(1, "calloc"); 4171edc1b9aShshoexer 4181edc1b9aShshoexer strlcpy(rule->auth.dstid, (char *)(sident + 1), len); 4191edc1b9aShshoexer break; 4201edc1b9aShshoexer 4211edc1b9aShshoexer case SADB_X_EXT_PROTOCOL: 4221edc1b9aShshoexer /* XXX nothing yet? */ 4231edc1b9aShshoexer break; 4241edc1b9aShshoexer 4251edc1b9aShshoexer case SADB_X_EXT_FLOW_TYPE: 4261edc1b9aShshoexer sproto = (struct sadb_protocol *)ext; 4271edc1b9aShshoexer 4281edc1b9aShshoexer switch (sproto->sadb_protocol_direction) { 4291edc1b9aShshoexer case IPSP_DIRECTION_IN: 4301edc1b9aShshoexer rule->direction = IPSEC_IN; 4311edc1b9aShshoexer break; 4321edc1b9aShshoexer case IPSP_DIRECTION_OUT: 4331edc1b9aShshoexer rule->direction = IPSEC_OUT; 4341edc1b9aShshoexer break; 4351edc1b9aShshoexer default: 4361edc1b9aShshoexer return (1); 4371edc1b9aShshoexer } 438*6122c05eShshoexer switch (sproto->sadb_protocol_proto) { 439*6122c05eShshoexer case SADB_X_FLOW_TYPE_USE: 440*6122c05eShshoexer rule->type = TYPE_USE; 441*6122c05eShshoexer break; 442*6122c05eShshoexer case SADB_X_FLOW_TYPE_ACQUIRE: 443*6122c05eShshoexer rule->type = TYPE_ACQUIRE; 444*6122c05eShshoexer break; 445*6122c05eShshoexer case SADB_X_FLOW_TYPE_REQUIRE: 446*6122c05eShshoexer rule->type = TYPE_REQUIRE; 447*6122c05eShshoexer break; 448*6122c05eShshoexer case SADB_X_FLOW_TYPE_DENY: 449*6122c05eShshoexer rule->type = TYPE_DENY; 450*6122c05eShshoexer break; 451*6122c05eShshoexer case SADB_X_FLOW_TYPE_BYPASS: 452*6122c05eShshoexer rule->type = TYPE_BYPASS; 453*6122c05eShshoexer break; 454*6122c05eShshoexer case SADB_X_FLOW_TYPE_DONTACQ: 455*6122c05eShshoexer rule->type = TYPE_DONTACQ; 456*6122c05eShshoexer break; 457*6122c05eShshoexer default: 458*6122c05eShshoexer rule->type = TYPE_UNKNOWN; 459*6122c05eShshoexer break; 460*6122c05eShshoexer } 4611edc1b9aShshoexer break; 4621edc1b9aShshoexer 4631edc1b9aShshoexer case SADB_X_EXT_SRC_FLOW: 4641edc1b9aShshoexer saddr = (struct sadb_address *)ext; 4651edc1b9aShshoexer sa = (struct sockaddr *)(saddr + 1); 4661edc1b9aShshoexer 4671edc1b9aShshoexer if (rule->src == NULL) { 4681edc1b9aShshoexer rule->src = calloc(1, 4691edc1b9aShshoexer sizeof(struct ipsec_addr)); 4701edc1b9aShshoexer if (rule->src == NULL) 4711edc1b9aShshoexer err(1, "calloc"); 4721edc1b9aShshoexer } 4731edc1b9aShshoexer 4741edc1b9aShshoexer switch (sa->sa_family) { 4751edc1b9aShshoexer case AF_INET: 4761edc1b9aShshoexer bcopy(&((struct sockaddr_in *)sa)->sin_addr, 4771edc1b9aShshoexer &rule->src->v4, sizeof(struct in_addr)); 4781edc1b9aShshoexer rule->src->af = AF_INET; 4791edc1b9aShshoexer break; 4801edc1b9aShshoexer default: 4811edc1b9aShshoexer return (1); 4821edc1b9aShshoexer } 4831edc1b9aShshoexer break; 4841edc1b9aShshoexer 4851edc1b9aShshoexer case SADB_X_EXT_DST_FLOW: 4861edc1b9aShshoexer saddr = (struct sadb_address *)ext; 4871edc1b9aShshoexer sa = (struct sockaddr *)(saddr + 1); 4881edc1b9aShshoexer 4891edc1b9aShshoexer if (rule->dst == NULL) { 4901edc1b9aShshoexer rule->dst = calloc(1, 4911edc1b9aShshoexer sizeof(struct ipsec_addr)); 4921edc1b9aShshoexer if (rule->dst == NULL) 4931edc1b9aShshoexer err(1, "calloc"); 4941edc1b9aShshoexer } 4951edc1b9aShshoexer 4961edc1b9aShshoexer switch (sa->sa_family) { 4971edc1b9aShshoexer case AF_INET: 4981edc1b9aShshoexer bcopy(&((struct sockaddr_in *)sa)->sin_addr, 4991edc1b9aShshoexer &rule->dst->v4, sizeof(struct in_addr)); 5001edc1b9aShshoexer rule->dst->af = AF_INET; 5011edc1b9aShshoexer break; 5021edc1b9aShshoexer 5031edc1b9aShshoexer default: 5041edc1b9aShshoexer return (1); 5051edc1b9aShshoexer } 5061edc1b9aShshoexer break; 5071edc1b9aShshoexer 5081edc1b9aShshoexer 5091edc1b9aShshoexer case SADB_X_EXT_SRC_MASK: 5101edc1b9aShshoexer saddr = (struct sadb_address *)ext; 5111edc1b9aShshoexer sa = (struct sockaddr *)(saddr + 1); 5121edc1b9aShshoexer 5131edc1b9aShshoexer if (rule->src == NULL) { 5141edc1b9aShshoexer rule->src = calloc(1, 5151edc1b9aShshoexer sizeof(struct ipsec_addr)); 5161edc1b9aShshoexer if (rule->src == NULL) 5171edc1b9aShshoexer err(1, "calloc"); 5181edc1b9aShshoexer } 5191edc1b9aShshoexer 5201edc1b9aShshoexer switch (sa->sa_family) { 5211edc1b9aShshoexer case AF_INET: 5221edc1b9aShshoexer bcopy(&((struct sockaddr_in *)sa)->sin_addr, 5231edc1b9aShshoexer &rule->src->v4mask.mask, 5241edc1b9aShshoexer sizeof(struct in_addr)); 5251edc1b9aShshoexer rule->src->af = AF_INET; 5261edc1b9aShshoexer break; 5271edc1b9aShshoexer 5281edc1b9aShshoexer default: 5291edc1b9aShshoexer return (1); 5301edc1b9aShshoexer } 5311edc1b9aShshoexer break; 5321edc1b9aShshoexer 5331edc1b9aShshoexer case SADB_X_EXT_DST_MASK: 5341edc1b9aShshoexer saddr = (struct sadb_address *)ext; 5351edc1b9aShshoexer sa = (struct sockaddr *)(saddr + 1); 5361edc1b9aShshoexer 5371edc1b9aShshoexer if (rule->dst == NULL) { 5381edc1b9aShshoexer rule->dst = calloc(1, 5391edc1b9aShshoexer sizeof(struct ipsec_addr)); 5401edc1b9aShshoexer if (rule->dst == NULL) 5411edc1b9aShshoexer err(1, "calloc"); 5421edc1b9aShshoexer } 5431edc1b9aShshoexer 5441edc1b9aShshoexer switch (sa->sa_family) { 5451edc1b9aShshoexer case AF_INET: 5461edc1b9aShshoexer bcopy(&((struct sockaddr_in *)sa)->sin_addr, 5471edc1b9aShshoexer &rule->dst->v4mask.mask, 5481edc1b9aShshoexer sizeof(struct in_addr)); 5491edc1b9aShshoexer rule->dst->af = AF_INET; 5501edc1b9aShshoexer break; 5511edc1b9aShshoexer 5521edc1b9aShshoexer default: 5531edc1b9aShshoexer return (1); 5541edc1b9aShshoexer } 5551edc1b9aShshoexer break; 5561edc1b9aShshoexer 5571edc1b9aShshoexer default: 5581edc1b9aShshoexer return (1); 5591edc1b9aShshoexer } 5601edc1b9aShshoexer } 5611edc1b9aShshoexer 5621edc1b9aShshoexer return (0); 5631edc1b9aShshoexer } 5641edc1b9aShshoexer 5651edc1b9aShshoexer int 566f484f2cfShshoexer pfkey_ipsec_establish(struct ipsec_rule *r) 567f484f2cfShshoexer { 568f484f2cfShshoexer u_int8_t satype; 569f484f2cfShshoexer u_int8_t direction; 570f484f2cfShshoexer 571f484f2cfShshoexer switch (r->proto) { 572f484f2cfShshoexer case IPSEC_ESP: 573f484f2cfShshoexer satype = SADB_SATYPE_ESP; 574f484f2cfShshoexer break; 575f484f2cfShshoexer case IPSEC_AH: 576f484f2cfShshoexer satype = SADB_SATYPE_AH; 577f484f2cfShshoexer break; 578f484f2cfShshoexer case IPSEC_COMP: 579f484f2cfShshoexer default: 580f484f2cfShshoexer return -1; 581f484f2cfShshoexer } 582f484f2cfShshoexer 583f484f2cfShshoexer switch (r->direction) { 584f484f2cfShshoexer case IPSEC_IN: 585f484f2cfShshoexer direction = IPSP_DIRECTION_IN; 586f484f2cfShshoexer break; 587f484f2cfShshoexer case IPSEC_OUT: 588f484f2cfShshoexer direction = IPSP_DIRECTION_OUT; 589f484f2cfShshoexer break; 590f484f2cfShshoexer default: 591f484f2cfShshoexer return -1; 592f484f2cfShshoexer } 593f484f2cfShshoexer 594f484f2cfShshoexer if (pfkey_flow(fd, satype, SADB_X_ADDFLOW, direction, r->src, r->dst, 595f484f2cfShshoexer r->peer, r->auth) < 0) 596f484f2cfShshoexer return -1; 597f484f2cfShshoexer if (pfkey_reply(fd) < 0) 598f484f2cfShshoexer return -1; 599f484f2cfShshoexer 600f484f2cfShshoexer return 0; 601f484f2cfShshoexer } 602f484f2cfShshoexer 603f484f2cfShshoexer int 604f484f2cfShshoexer pfkey_ipsec_flush(void) 605f484f2cfShshoexer { 606f484f2cfShshoexer struct sadb_msg smsg; 607f484f2cfShshoexer struct iovec iov[IOV_CNT]; 608f484f2cfShshoexer ssize_t n; 609f484f2cfShshoexer int iov_cnt, len; 610f484f2cfShshoexer 611f484f2cfShshoexer bzero(&smsg, sizeof(smsg)); 612f484f2cfShshoexer smsg.sadb_msg_version = PF_KEY_V2; 613f484f2cfShshoexer smsg.sadb_msg_seq = sadb_msg_seq++; 614f484f2cfShshoexer smsg.sadb_msg_pid = getpid(); 615f484f2cfShshoexer smsg.sadb_msg_len = sizeof(smsg) / 8; 616f484f2cfShshoexer smsg.sadb_msg_type = SADB_FLUSH; 617f484f2cfShshoexer smsg.sadb_msg_satype = SADB_SATYPE_UNSPEC; 618f484f2cfShshoexer 619f484f2cfShshoexer iov_cnt = 0; 620f484f2cfShshoexer 621f484f2cfShshoexer iov[iov_cnt].iov_base = &smsg; 622f484f2cfShshoexer iov[iov_cnt].iov_len = sizeof(smsg); 623f484f2cfShshoexer iov_cnt++; 624f484f2cfShshoexer 625f484f2cfShshoexer len = smsg.sadb_msg_len * 8; 626f484f2cfShshoexer if ((n = writev(fd, iov, iov_cnt)) == -1) { 627f484f2cfShshoexer warn("writev failed"); 628f484f2cfShshoexer return -1; 629f484f2cfShshoexer } 630f484f2cfShshoexer if (n != len) { 631f484f2cfShshoexer warnx("short write"); 632f484f2cfShshoexer return -1; 633f484f2cfShshoexer } 634f484f2cfShshoexer if (pfkey_reply(fd) < 0) 635f484f2cfShshoexer return -1; 636f484f2cfShshoexer 637f484f2cfShshoexer return 0; 638f484f2cfShshoexer } 639f484f2cfShshoexer 640f484f2cfShshoexer int 641f484f2cfShshoexer pfkey_init(void) 642f484f2cfShshoexer { 643f484f2cfShshoexer if ((fd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) == -1) 644f484f2cfShshoexer err(1, "failed to open PF_KEY socket"); 645f484f2cfShshoexer 646f484f2cfShshoexer return 0; 647f484f2cfShshoexer } 648