xref: /openbsd/sbin/ipsecctl/pfkey.c (revision 0813ab45)
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