xref: /openbsd/sbin/ipsecctl/pfkey.c (revision 57f58d0d)
1*57f58d0dSnaddy /*	$OpenBSD: pfkey.c,v 1.43 2006/06/01 17:32:20 naddy Exp $	*/
2f484f2cfShshoexer /*
3f484f2cfShshoexer  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
4f484f2cfShshoexer  * Copyright (c) 2003, 2004 Markus Friedl <markus@openbsd.org>
5f484f2cfShshoexer  * Copyright (c) 2004, 2005 Hans-Joerg Hoexer <hshoexer@openbsd.org>
6f484f2cfShshoexer  *
7f484f2cfShshoexer  * Permission to use, copy, modify, and distribute this software for any
8f484f2cfShshoexer  * purpose with or without fee is hereby granted, provided that the above
9f484f2cfShshoexer  * copyright notice and this permission notice appear in all copies.
10f484f2cfShshoexer  *
11f484f2cfShshoexer  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12f484f2cfShshoexer  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13f484f2cfShshoexer  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14f484f2cfShshoexer  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15f484f2cfShshoexer  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16f484f2cfShshoexer  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17f484f2cfShshoexer  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18f484f2cfShshoexer  */
19f484f2cfShshoexer 
20f484f2cfShshoexer #include <sys/types.h>
21f484f2cfShshoexer #include <sys/queue.h>
22f484f2cfShshoexer #include <sys/uio.h>
23f484f2cfShshoexer #include <sys/socket.h>
24f484f2cfShshoexer #include <netinet/in.h>
25f484f2cfShshoexer #include <netinet/ip_ipsp.h>
26f484f2cfShshoexer #include <net/pfkeyv2.h>
27f484f2cfShshoexer 
28f484f2cfShshoexer #include <err.h>
29f484f2cfShshoexer #include <errno.h>
30f484f2cfShshoexer #include <stdio.h>
31f484f2cfShshoexer #include <string.h>
32f484f2cfShshoexer #include <stdlib.h>
33f484f2cfShshoexer #include <unistd.h>
34f484f2cfShshoexer 
35f484f2cfShshoexer #include "ipsecctl.h"
361edc1b9aShshoexer #include "pfkey.h"
37f484f2cfShshoexer 
38f484f2cfShshoexer #define ROUNDUP(x) (((x) + (PFKEYV2_CHUNK - 1)) & ~(PFKEYV2_CHUNK - 1))
39f484f2cfShshoexer #define IOV_CNT 20
40f484f2cfShshoexer 
41f484f2cfShshoexer static int	fd;
42f484f2cfShshoexer static u_int32_t sadb_msg_seq = 1;
43f484f2cfShshoexer 
449182219dSmarkus static int	pfkey_flow(int, u_int8_t, u_int8_t, u_int8_t, u_int8_t,
45*57f58d0dSnaddy 		    struct ipsec_addr_wrap *, u_int16_t,
46*57f58d0dSnaddy 		    struct ipsec_addr_wrap *, u_int16_t,
47435bb41eSmarkus 		    struct ipsec_addr_wrap *, struct ipsec_addr_wrap *,
48435bb41eSmarkus 		    struct ipsec_auth *, u_int8_t);
49f032086dShshoexer static int	pfkey_sa(int, u_int8_t, u_int8_t, u_int32_t,
5091f765ddShshoexer 		    struct ipsec_addr_wrap *, struct ipsec_addr_wrap *,
51375db29dShshoexer 		    struct ipsec_transforms *, struct ipsec_key *,
52a38d220fShshoexer 		    struct ipsec_key *, u_int8_t);
538a87fca6Smsf static int	pfkey_reply(int, u_int8_t **, ssize_t *);
54e225c210Shshoexer int		pfkey_parse(struct sadb_msg *, struct ipsec_rule *);
55f484f2cfShshoexer int		pfkey_ipsec_flush(void);
56356121f6Shshoexer int		pfkey_ipsec_establish(int, struct ipsec_rule *);
57f484f2cfShshoexer int		pfkey_init(void);
58f484f2cfShshoexer 
59f484f2cfShshoexer static int
60f484f2cfShshoexer pfkey_flow(int sd, u_int8_t satype, u_int8_t action, u_int8_t direction,
61*57f58d0dSnaddy     u_int8_t proto, struct ipsec_addr_wrap *src, u_int16_t sport,
62*57f58d0dSnaddy     struct ipsec_addr_wrap *dst, u_int16_t dport,
63435bb41eSmarkus     struct ipsec_addr_wrap *local, struct ipsec_addr_wrap *peer,
64435bb41eSmarkus     struct ipsec_auth *auth, u_int8_t flowtype)
65f484f2cfShshoexer {
66f484f2cfShshoexer 	struct sadb_msg		 smsg;
67435bb41eSmarkus 	struct sadb_address	 sa_src, sa_dst, sa_local, sa_peer, sa_smask,
68435bb41eSmarkus 				 sa_dmask;
69f484f2cfShshoexer 	struct sadb_protocol	 sa_flowtype, sa_protocol;
70f484f2cfShshoexer 	struct sadb_ident	*sa_srcid, *sa_dstid;
71435bb41eSmarkus 	struct sockaddr_storage	 ssrc, sdst, slocal, speer, smask, dmask;
72f484f2cfShshoexer 	struct iovec		 iov[IOV_CNT];
73f484f2cfShshoexer 	ssize_t			 n;
74f484f2cfShshoexer 	int			 iov_cnt, len, ret = 0;
75f484f2cfShshoexer 
76f484f2cfShshoexer 	sa_srcid = sa_dstid = NULL;
77f484f2cfShshoexer 
78f484f2cfShshoexer 	bzero(&ssrc, sizeof(ssrc));
79f484f2cfShshoexer 	bzero(&smask, sizeof(smask));
802099bcdfStodd 	ssrc.ss_family = smask.ss_family = src->af;
81f484f2cfShshoexer 	switch (src->af) {
82f484f2cfShshoexer 	case AF_INET:
83712e78baShshoexer 		((struct sockaddr_in *)&ssrc)->sin_addr = src->address.v4;
84f484f2cfShshoexer 		ssrc.ss_len = sizeof(struct sockaddr_in);
85712e78baShshoexer 		((struct sockaddr_in *)&smask)->sin_addr = src->mask.v4;
86*57f58d0dSnaddy 		if (sport) {
87*57f58d0dSnaddy 			((struct sockaddr_in *)&ssrc)->sin_port = sport;
88*57f58d0dSnaddy 			((struct sockaddr_in *)&smask)->sin_port = 0xffff;
89*57f58d0dSnaddy 		}
90f484f2cfShshoexer 		break;
91f484f2cfShshoexer 	case AF_INET6:
922099bcdfStodd 		((struct sockaddr_in6 *)&ssrc)->sin6_addr = src->address.v6;
932099bcdfStodd 		ssrc.ss_len = sizeof(struct sockaddr_in6);
942099bcdfStodd 		((struct sockaddr_in6 *)&smask)->sin6_addr = src->mask.v6;
95*57f58d0dSnaddy 		if (sport) {
96*57f58d0dSnaddy 			((struct sockaddr_in6 *)&ssrc)->sin6_port = sport;
97*57f58d0dSnaddy 			((struct sockaddr_in6 *)&smask)->sin6_port = 0xffff;
98*57f58d0dSnaddy 		}
992099bcdfStodd 		break;
100f484f2cfShshoexer 	default:
101f484f2cfShshoexer 		warnx("unsupported address family %d", src->af);
102f484f2cfShshoexer 		return -1;
103f484f2cfShshoexer 	}
104f484f2cfShshoexer 	smask.ss_len = ssrc.ss_len;
105f484f2cfShshoexer 
106f484f2cfShshoexer 	bzero(&sdst, sizeof(sdst));
107f484f2cfShshoexer 	bzero(&dmask, sizeof(dmask));
1082099bcdfStodd 	sdst.ss_family = dmask.ss_family = dst->af;
109f484f2cfShshoexer 	switch (dst->af) {
110f484f2cfShshoexer 	case AF_INET:
111712e78baShshoexer 		((struct sockaddr_in *)&sdst)->sin_addr = dst->address.v4;
112f484f2cfShshoexer 		sdst.ss_len = sizeof(struct sockaddr_in);
113712e78baShshoexer 		((struct sockaddr_in *)&dmask)->sin_addr = dst->mask.v4;
114*57f58d0dSnaddy 		if (dport) {
115*57f58d0dSnaddy 			((struct sockaddr_in *)&sdst)->sin_port = dport;
116*57f58d0dSnaddy 			((struct sockaddr_in *)&dmask)->sin_port = 0xffff;
117*57f58d0dSnaddy 		}
118f484f2cfShshoexer 		break;
119f484f2cfShshoexer 	case AF_INET6:
1202099bcdfStodd 		((struct sockaddr_in6 *)&sdst)->sin6_addr = dst->address.v6;
1212099bcdfStodd 		sdst.ss_len = sizeof(struct sockaddr_in6);
1222099bcdfStodd 		((struct sockaddr_in6 *)&dmask)->sin6_addr = dst->mask.v6;
123*57f58d0dSnaddy 		if (dport) {
124*57f58d0dSnaddy 			((struct sockaddr_in6 *)&sdst)->sin6_port = dport;
125*57f58d0dSnaddy 			((struct sockaddr_in6 *)&dmask)->sin6_port = 0xffff;
126*57f58d0dSnaddy 		}
1272099bcdfStodd 		break;
128f484f2cfShshoexer 	default:
129f484f2cfShshoexer 		warnx("unsupported address family %d", dst->af);
130f484f2cfShshoexer 		return -1;
131f484f2cfShshoexer 	}
132f484f2cfShshoexer 	dmask.ss_len = sdst.ss_len;
133f484f2cfShshoexer 
134435bb41eSmarkus 	bzero(&slocal, sizeof(slocal));
135435bb41eSmarkus 	if (local) {
1362099bcdfStodd 		slocal.ss_family = local->af;
137435bb41eSmarkus 		switch (local->af) {
138435bb41eSmarkus 		case AF_INET:
139435bb41eSmarkus 			((struct sockaddr_in *)&slocal)->sin_addr =
140435bb41eSmarkus 			    local->address.v4;
141435bb41eSmarkus 			slocal.ss_len = sizeof(struct sockaddr_in);
142435bb41eSmarkus 			break;
143435bb41eSmarkus 		case AF_INET6:
1442099bcdfStodd 			((struct sockaddr_in6 *)&slocal)->sin6_addr =
1452099bcdfStodd 			    local->address.v6;
1462099bcdfStodd 			slocal.ss_len = sizeof(struct sockaddr_in6);
1472099bcdfStodd 			break;
148435bb41eSmarkus 		default:
149435bb41eSmarkus 			warnx("unsupported address family %d", local->af);
150435bb41eSmarkus 			return -1;
151435bb41eSmarkus 		}
152435bb41eSmarkus 	}
153435bb41eSmarkus 
154f484f2cfShshoexer 	bzero(&speer, sizeof(speer));
15522a29ad6Shshoexer 	if (peer) {
1562099bcdfStodd 		speer.ss_family = peer->af;
157f484f2cfShshoexer 		switch (peer->af) {
158f484f2cfShshoexer 		case AF_INET:
159712e78baShshoexer 			((struct sockaddr_in *)&speer)->sin_addr =
160712e78baShshoexer 			    peer->address.v4;
161f484f2cfShshoexer 			speer.ss_len = sizeof(struct sockaddr_in);
162f484f2cfShshoexer 			break;
163f484f2cfShshoexer 		case AF_INET6:
1642099bcdfStodd 			((struct sockaddr_in6 *)&speer)->sin6_addr =
1652099bcdfStodd 			    peer->address.v6;
1662099bcdfStodd 			speer.ss_len = sizeof(struct sockaddr_in6);
1672099bcdfStodd 			break;
168f484f2cfShshoexer 		default:
169f484f2cfShshoexer 			warnx("unsupported address family %d", peer->af);
170f484f2cfShshoexer 			return -1;
171f484f2cfShshoexer 		}
17222a29ad6Shshoexer 	}
173f484f2cfShshoexer 
174f484f2cfShshoexer 	bzero(&smsg, sizeof(smsg));
175f484f2cfShshoexer 	smsg.sadb_msg_version = PF_KEY_V2;
176f484f2cfShshoexer 	smsg.sadb_msg_seq = sadb_msg_seq++;
177f484f2cfShshoexer 	smsg.sadb_msg_pid = getpid();
178f484f2cfShshoexer 	smsg.sadb_msg_len = sizeof(smsg) / 8;
179f484f2cfShshoexer 	smsg.sadb_msg_type = action;
180f484f2cfShshoexer 	smsg.sadb_msg_satype = satype;
181f484f2cfShshoexer 
182f484f2cfShshoexer 	bzero(&sa_flowtype, sizeof(sa_flowtype));
183f484f2cfShshoexer 	sa_flowtype.sadb_protocol_exttype = SADB_X_EXT_FLOW_TYPE;
184f484f2cfShshoexer 	sa_flowtype.sadb_protocol_len = sizeof(sa_flowtype) / 8;
185f484f2cfShshoexer 	sa_flowtype.sadb_protocol_direction = direction;
18626df514dShshoexer 
187e1ffbfafShshoexer 	switch (flowtype) {
188e1ffbfafShshoexer 	case TYPE_USE:
18926df514dShshoexer 		sa_flowtype.sadb_protocol_proto = SADB_X_FLOW_TYPE_USE;
190e1ffbfafShshoexer 		break;
191b7a16601Shshoexer 	case TYPE_ACQUIRE:
192b7a16601Shshoexer 		sa_flowtype.sadb_protocol_proto = SADB_X_FLOW_TYPE_ACQUIRE;
193b7a16601Shshoexer 		break;
194e1ffbfafShshoexer 	case TYPE_REQUIRE:
195f484f2cfShshoexer 		sa_flowtype.sadb_protocol_proto = SADB_X_FLOW_TYPE_REQUIRE;
196e1ffbfafShshoexer 		break;
1977c7fb9e5Sreyk 	case TYPE_DENY:
1987c7fb9e5Sreyk 		sa_flowtype.sadb_protocol_proto = SADB_X_FLOW_TYPE_DENY;
1997c7fb9e5Sreyk 		break;
2007c7fb9e5Sreyk 	case TYPE_BYPASS:
2017c7fb9e5Sreyk 		sa_flowtype.sadb_protocol_proto = SADB_X_FLOW_TYPE_BYPASS;
2027c7fb9e5Sreyk 		break;
203b7a16601Shshoexer 	case TYPE_DONTACQ:
204b7a16601Shshoexer 		sa_flowtype.sadb_protocol_proto = SADB_X_FLOW_TYPE_DONTACQ;
205b7a16601Shshoexer 		break;
206e1ffbfafShshoexer 	default:
207e1ffbfafShshoexer 		warnx("unsupported flowtype %d", flowtype);
208e1ffbfafShshoexer 		return -1;
209e1ffbfafShshoexer 	}
210f484f2cfShshoexer 
211f484f2cfShshoexer 	bzero(&sa_protocol, sizeof(sa_protocol));
212f484f2cfShshoexer 	sa_protocol.sadb_protocol_exttype = SADB_X_EXT_PROTOCOL;
213f484f2cfShshoexer 	sa_protocol.sadb_protocol_len = sizeof(sa_protocol) / 8;
214f484f2cfShshoexer 	sa_protocol.sadb_protocol_direction = 0;
2159182219dSmarkus 	sa_protocol.sadb_protocol_proto = proto;
216f484f2cfShshoexer 
217f484f2cfShshoexer 	bzero(&sa_src, sizeof(sa_src));
218f484f2cfShshoexer 	sa_src.sadb_address_exttype = SADB_X_EXT_SRC_FLOW;
219f484f2cfShshoexer 	sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(ssrc.ss_len)) / 8;
220f484f2cfShshoexer 
221f484f2cfShshoexer 	bzero(&sa_smask, sizeof(sa_smask));
222f484f2cfShshoexer 	sa_smask.sadb_address_exttype = SADB_X_EXT_SRC_MASK;
223f484f2cfShshoexer 	sa_smask.sadb_address_len =
224f484f2cfShshoexer 	    (sizeof(sa_smask) + ROUNDUP(smask.ss_len)) / 8;
225f484f2cfShshoexer 
226f484f2cfShshoexer 	bzero(&sa_dst, sizeof(sa_dst));
227f484f2cfShshoexer 	sa_dst.sadb_address_exttype = SADB_X_EXT_DST_FLOW;
228f484f2cfShshoexer 	sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(sdst.ss_len)) / 8;
229f484f2cfShshoexer 
230f484f2cfShshoexer 	bzero(&sa_dmask, sizeof(sa_dmask));
231f484f2cfShshoexer 	sa_dmask.sadb_address_exttype = SADB_X_EXT_DST_MASK;
232f484f2cfShshoexer 	sa_dmask.sadb_address_len =
233f484f2cfShshoexer 	    (sizeof(sa_dmask) + ROUNDUP(dmask.ss_len)) / 8;
234f484f2cfShshoexer 
235435bb41eSmarkus 	if (local) {
236435bb41eSmarkus 		bzero(&sa_local, sizeof(sa_local));
237435bb41eSmarkus 		sa_local.sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
238435bb41eSmarkus 		sa_local.sadb_address_len =
239435bb41eSmarkus 		    (sizeof(sa_local) + ROUNDUP(slocal.ss_len)) / 8;
240435bb41eSmarkus 	}
241435bb41eSmarkus 	if (peer) {
242f484f2cfShshoexer 		bzero(&sa_peer, sizeof(sa_peer));
243f484f2cfShshoexer 		sa_peer.sadb_address_exttype = SADB_EXT_ADDRESS_DST;
244f484f2cfShshoexer 		sa_peer.sadb_address_len =
245f484f2cfShshoexer 		    (sizeof(sa_peer) + ROUNDUP(speer.ss_len)) / 8;
246435bb41eSmarkus 	}
247f484f2cfShshoexer 
248abe65127Shshoexer 	if (auth && auth->srcid) {
249abe65127Shshoexer 		len = ROUNDUP(strlen(auth->srcid) + 1) + sizeof(*sa_srcid);
250f484f2cfShshoexer 
251f484f2cfShshoexer 		sa_srcid = calloc(len, sizeof(u_int8_t));
252f484f2cfShshoexer 		if (sa_srcid == NULL)
253bd828a90Shshoexer 			err(1, "pfkey_flow: calloc");
254f484f2cfShshoexer 
255abe65127Shshoexer 		sa_srcid->sadb_ident_type = auth->idtype;
256f484f2cfShshoexer 		sa_srcid->sadb_ident_len = len / 8;
257f484f2cfShshoexer 		sa_srcid->sadb_ident_exttype = SADB_EXT_IDENTITY_SRC;
258f484f2cfShshoexer 
259abe65127Shshoexer 		strlcpy((char *)(sa_srcid + 1), auth->srcid,
260abe65127Shshoexer 		    ROUNDUP(strlen(auth->srcid) + 1));
261f484f2cfShshoexer 	}
262abe65127Shshoexer 	if (auth && auth->dstid) {
263abe65127Shshoexer 		len = ROUNDUP(strlen(auth->dstid) + 1) + sizeof(*sa_dstid);
264f484f2cfShshoexer 
265f484f2cfShshoexer 		sa_dstid = calloc(len, sizeof(u_int8_t));
266f484f2cfShshoexer 		if (sa_dstid == NULL)
267bd828a90Shshoexer 			err(1, "pfkey_flow: calloc");
268f484f2cfShshoexer 
269abe65127Shshoexer 		sa_dstid->sadb_ident_type = auth->idtype;
270f484f2cfShshoexer 		sa_dstid->sadb_ident_len = len / 8;
271f484f2cfShshoexer 		sa_dstid->sadb_ident_exttype = SADB_EXT_IDENTITY_DST;
272f484f2cfShshoexer 
273abe65127Shshoexer 		strlcpy((char *)(sa_dstid + 1), auth->dstid,
274abe65127Shshoexer 		    ROUNDUP(strlen(auth->dstid) + 1));
275f484f2cfShshoexer 	}
276f484f2cfShshoexer 
277f484f2cfShshoexer 	iov_cnt = 0;
278f484f2cfShshoexer 
279f484f2cfShshoexer 	/* header */
280f484f2cfShshoexer 	iov[iov_cnt].iov_base = &smsg;
281f484f2cfShshoexer 	iov[iov_cnt].iov_len = sizeof(smsg);
282f484f2cfShshoexer 	iov_cnt++;
283f484f2cfShshoexer 
28489ad8c34Shshoexer 	/* add flow type */
28589ad8c34Shshoexer 	iov[iov_cnt].iov_base = &sa_flowtype;
28689ad8c34Shshoexer 	iov[iov_cnt].iov_len = sizeof(sa_flowtype);
28789ad8c34Shshoexer 	smsg.sadb_msg_len += sa_flowtype.sadb_protocol_len;
28889ad8c34Shshoexer 	iov_cnt++;
28989ad8c34Shshoexer 
290435bb41eSmarkus 	/* local ip */
291435bb41eSmarkus 	if (local) {
292435bb41eSmarkus 		iov[iov_cnt].iov_base = &sa_local;
293435bb41eSmarkus 		iov[iov_cnt].iov_len = sizeof(sa_local);
294435bb41eSmarkus 		iov_cnt++;
295435bb41eSmarkus 		iov[iov_cnt].iov_base = &slocal;
296435bb41eSmarkus 		iov[iov_cnt].iov_len = ROUNDUP(slocal.ss_len);
297435bb41eSmarkus 		smsg.sadb_msg_len += sa_local.sadb_address_len;
298435bb41eSmarkus 		iov_cnt++;
299435bb41eSmarkus 	}
300435bb41eSmarkus 
301f484f2cfShshoexer 	/* remote peer */
30222a29ad6Shshoexer 	if (peer) {
303f484f2cfShshoexer 		iov[iov_cnt].iov_base = &sa_peer;
304f484f2cfShshoexer 		iov[iov_cnt].iov_len = sizeof(sa_peer);
305f484f2cfShshoexer 		iov_cnt++;
306f484f2cfShshoexer 		iov[iov_cnt].iov_base = &speer;
307f484f2cfShshoexer 		iov[iov_cnt].iov_len = ROUNDUP(speer.ss_len);
308f484f2cfShshoexer 		smsg.sadb_msg_len += sa_peer.sadb_address_len;
309f484f2cfShshoexer 		iov_cnt++;
31022a29ad6Shshoexer 	}
311f484f2cfShshoexer 
31289ad8c34Shshoexer 	/* src addr */
31389ad8c34Shshoexer 	iov[iov_cnt].iov_base = &sa_src;
31489ad8c34Shshoexer 	iov[iov_cnt].iov_len = sizeof(sa_src);
31589ad8c34Shshoexer 	iov_cnt++;
31689ad8c34Shshoexer 	iov[iov_cnt].iov_base = &ssrc;
31789ad8c34Shshoexer 	iov[iov_cnt].iov_len = ROUNDUP(ssrc.ss_len);
31889ad8c34Shshoexer 	smsg.sadb_msg_len += sa_src.sadb_address_len;
319f484f2cfShshoexer 	iov_cnt++;
320f484f2cfShshoexer 
32189ad8c34Shshoexer 	/* src mask */
322f484f2cfShshoexer 	iov[iov_cnt].iov_base = &sa_smask;
323f484f2cfShshoexer 	iov[iov_cnt].iov_len = sizeof(sa_smask);
324f484f2cfShshoexer 	iov_cnt++;
325f484f2cfShshoexer 	iov[iov_cnt].iov_base = &smask;
326f484f2cfShshoexer 	iov[iov_cnt].iov_len = ROUNDUP(smask.ss_len);
327f484f2cfShshoexer 	smsg.sadb_msg_len += sa_smask.sadb_address_len;
328f484f2cfShshoexer 	iov_cnt++;
329f484f2cfShshoexer 
330f484f2cfShshoexer 	/* dest addr */
331f484f2cfShshoexer 	iov[iov_cnt].iov_base = &sa_dst;
332f484f2cfShshoexer 	iov[iov_cnt].iov_len = sizeof(sa_dst);
333f484f2cfShshoexer 	iov_cnt++;
334f484f2cfShshoexer 	iov[iov_cnt].iov_base = &sdst;
335f484f2cfShshoexer 	iov[iov_cnt].iov_len = ROUNDUP(sdst.ss_len);
336f484f2cfShshoexer 	smsg.sadb_msg_len += sa_dst.sadb_address_len;
337f484f2cfShshoexer 	iov_cnt++;
338f484f2cfShshoexer 
33989ad8c34Shshoexer 	/* dst mask */
34089ad8c34Shshoexer 	iov[iov_cnt].iov_base = &sa_dmask;
34189ad8c34Shshoexer 	iov[iov_cnt].iov_len = sizeof(sa_dmask);
342f484f2cfShshoexer 	iov_cnt++;
34389ad8c34Shshoexer 	iov[iov_cnt].iov_base = &dmask;
34489ad8c34Shshoexer 	iov[iov_cnt].iov_len = ROUNDUP(dmask.ss_len);
34589ad8c34Shshoexer 	smsg.sadb_msg_len += sa_dmask.sadb_address_len;
34689ad8c34Shshoexer 	iov_cnt++;
34789ad8c34Shshoexer 
34889ad8c34Shshoexer 	/* add protocol */
34989ad8c34Shshoexer 	iov[iov_cnt].iov_base = &sa_protocol;
35089ad8c34Shshoexer 	iov[iov_cnt].iov_len = sizeof(sa_protocol);
35189ad8c34Shshoexer 	smsg.sadb_msg_len += sa_protocol.sadb_protocol_len;
352f484f2cfShshoexer 	iov_cnt++;
353f484f2cfShshoexer 
354f484f2cfShshoexer 	if (sa_srcid) {
355f484f2cfShshoexer 		/* src identity */
356f484f2cfShshoexer 		iov[iov_cnt].iov_base = sa_srcid;
357f484f2cfShshoexer 		iov[iov_cnt].iov_len = sa_srcid->sadb_ident_len * 8;
358f484f2cfShshoexer 		smsg.sadb_msg_len += sa_srcid->sadb_ident_len;
359f484f2cfShshoexer 		iov_cnt++;
360f484f2cfShshoexer 	}
361f484f2cfShshoexer 	if (sa_dstid) {
362f484f2cfShshoexer 		/* dst identity */
363f484f2cfShshoexer 		iov[iov_cnt].iov_base = sa_dstid;
364f484f2cfShshoexer 		iov[iov_cnt].iov_len = sa_dstid->sadb_ident_len * 8;
365f484f2cfShshoexer 		smsg.sadb_msg_len += sa_dstid->sadb_ident_len;
366f484f2cfShshoexer 		iov_cnt++;
367f484f2cfShshoexer 	}
368f484f2cfShshoexer 	len = smsg.sadb_msg_len * 8;
369f484f2cfShshoexer 	if ((n = writev(sd, iov, iov_cnt)) == -1) {
370f484f2cfShshoexer 		warn("writev failed");
371f484f2cfShshoexer 		ret = -1;
372f484f2cfShshoexer 		goto out;
373f484f2cfShshoexer 	}
374f484f2cfShshoexer 	if (n != len) {
375f484f2cfShshoexer 		warnx("short write");
376f484f2cfShshoexer 		ret = -1;
377f484f2cfShshoexer 	}
378f484f2cfShshoexer 
379f484f2cfShshoexer out:
380f484f2cfShshoexer 	if (sa_srcid)
381f484f2cfShshoexer 		free(sa_srcid);
382f484f2cfShshoexer 	if (sa_dstid)
383f484f2cfShshoexer 		free(sa_dstid);
384f484f2cfShshoexer 
385f484f2cfShshoexer 	return ret;
386f484f2cfShshoexer }
387f484f2cfShshoexer 
388f484f2cfShshoexer static int
38991f765ddShshoexer pfkey_sa(int sd, u_int8_t satype, u_int8_t action, u_int32_t spi,
39091f765ddShshoexer     struct ipsec_addr_wrap *src, struct ipsec_addr_wrap *dst,
39191f765ddShshoexer     struct ipsec_transforms *xfs, struct ipsec_key *authkey,
392a38d220fShshoexer     struct ipsec_key *enckey, u_int8_t tmode)
393f032086dShshoexer {
394f032086dShshoexer 	struct sadb_msg		smsg;
395f032086dShshoexer 	struct sadb_sa		sa;
396f032086dShshoexer 	struct sadb_address	sa_src, sa_dst;
397881e2068Shshoexer 	struct sadb_key		sa_authkey, sa_enckey;
398f032086dShshoexer 	struct sockaddr_storage	ssrc, sdst;
399f032086dShshoexer 	struct iovec		iov[IOV_CNT];
400f032086dShshoexer 	ssize_t			n;
401f032086dShshoexer 	int			iov_cnt, len, ret = 0;
402f032086dShshoexer 
403f032086dShshoexer 	bzero(&ssrc, sizeof(ssrc));
4042099bcdfStodd 	ssrc.ss_family = src->af;
405f032086dShshoexer 	switch (src->af) {
406f032086dShshoexer 	case AF_INET:
407712e78baShshoexer 		((struct sockaddr_in *)&ssrc)->sin_addr = src->address.v4;
408f032086dShshoexer 		ssrc.ss_len = sizeof(struct sockaddr_in);
409f032086dShshoexer 		break;
410f032086dShshoexer 	case AF_INET6:
4112099bcdfStodd 		((struct sockaddr_in6 *)&ssrc)->sin6_addr = src->address.v6;
4122099bcdfStodd 		ssrc.ss_len = sizeof(struct sockaddr_in6);
4132099bcdfStodd 		break;
414f032086dShshoexer 	default:
415f032086dShshoexer 		warnx("unsupported address family %d", src->af);
416f032086dShshoexer 		return -1;
417f032086dShshoexer 	}
418f032086dShshoexer 
419f032086dShshoexer 	bzero(&sdst, sizeof(sdst));
4202099bcdfStodd 	sdst.ss_family = dst->af;
421f032086dShshoexer 	switch (dst->af) {
422f032086dShshoexer 	case AF_INET:
423712e78baShshoexer 		((struct sockaddr_in *)&sdst)->sin_addr = dst->address.v4;
424f032086dShshoexer 		sdst.ss_len = sizeof(struct sockaddr_in);
425f032086dShshoexer 		break;
426f032086dShshoexer 	case AF_INET6:
4272099bcdfStodd 		((struct sockaddr_in6 *)&sdst)->sin6_addr = dst->address.v6;
4282099bcdfStodd 		sdst.ss_len = sizeof(struct sockaddr_in6);
4292099bcdfStodd 		break;
430f032086dShshoexer 	default:
431f032086dShshoexer 		warnx("unsupported address family %d", dst->af);
432f032086dShshoexer 		return -1;
433f032086dShshoexer 	}
434f032086dShshoexer 
435f032086dShshoexer 	bzero(&smsg, sizeof(smsg));
436f032086dShshoexer 	smsg.sadb_msg_version = PF_KEY_V2;
437f032086dShshoexer 	smsg.sadb_msg_seq = sadb_msg_seq++;
438f032086dShshoexer 	smsg.sadb_msg_pid = getpid();
439f032086dShshoexer 	smsg.sadb_msg_len = sizeof(smsg) / 8;
440f032086dShshoexer 	smsg.sadb_msg_type = action;
441f032086dShshoexer 	smsg.sadb_msg_satype = satype;
442f032086dShshoexer 
443f032086dShshoexer 	bzero(&sa, sizeof(sa));
444f032086dShshoexer 	sa.sadb_sa_len = sizeof(sa) / 8;
445f032086dShshoexer 	sa.sadb_sa_exttype = SADB_EXT_SA;
446f032086dShshoexer 	sa.sadb_sa_spi = htonl(spi);
447f032086dShshoexer 	sa.sadb_sa_state = SADB_SASTATE_MATURE;
448f032086dShshoexer 
44988a8cceeSmarkus 	if (satype != SADB_X_SATYPE_IPIP && tmode == IPSEC_TUNNEL)
450a38d220fShshoexer 		sa.sadb_sa_flags |= SADB_X_SAFLAGS_TUNNEL;
451a38d220fShshoexer 
452375db29dShshoexer 	if (xfs && xfs->authxf) {
453375db29dShshoexer 		switch (xfs->authxf->id) {
454881e2068Shshoexer 		case AUTHXF_NONE:
455881e2068Shshoexer 			break;
456881e2068Shshoexer 		case AUTHXF_HMAC_MD5:
457881e2068Shshoexer 			sa.sadb_sa_auth = SADB_AALG_MD5HMAC;
458881e2068Shshoexer 			break;
459881e2068Shshoexer 		case AUTHXF_HMAC_RIPEMD160:
460881e2068Shshoexer 			sa.sadb_sa_auth = SADB_X_AALG_RIPEMD160HMAC;
461881e2068Shshoexer 			break;
462881e2068Shshoexer 		case AUTHXF_HMAC_SHA1:
463881e2068Shshoexer 			sa.sadb_sa_auth = SADB_AALG_SHA1HMAC;
464881e2068Shshoexer 			break;
465881e2068Shshoexer 		case AUTHXF_HMAC_SHA2_256:
466881e2068Shshoexer 			sa.sadb_sa_auth = SADB_X_AALG_SHA2_256;
467881e2068Shshoexer 			break;
468881e2068Shshoexer 		case AUTHXF_HMAC_SHA2_384:
469881e2068Shshoexer 			sa.sadb_sa_auth = SADB_X_AALG_SHA2_384;
470881e2068Shshoexer 			break;
471881e2068Shshoexer 		case AUTHXF_HMAC_SHA2_512:
472881e2068Shshoexer 			sa.sadb_sa_auth = SADB_X_AALG_SHA2_512;
473881e2068Shshoexer 			break;
474881e2068Shshoexer 		default:
475881e2068Shshoexer 			warnx("unsupported authentication algorithm %d",
476375db29dShshoexer 			    xfs->authxf->id);
477881e2068Shshoexer 		}
478881e2068Shshoexer 	}
479375db29dShshoexer 	if (xfs && xfs->encxf) {
480375db29dShshoexer 		switch (xfs->encxf->id) {
481881e2068Shshoexer 		case ENCXF_NONE:
482881e2068Shshoexer 			break;
483881e2068Shshoexer 		case ENCXF_3DES_CBC:
484881e2068Shshoexer 			sa.sadb_sa_encrypt = SADB_EALG_3DESCBC;
485881e2068Shshoexer 			break;
486881e2068Shshoexer 		case ENCXF_DES_CBC:
487881e2068Shshoexer 			sa.sadb_sa_encrypt = SADB_EALG_DESCBC;
488881e2068Shshoexer 			break;
489881e2068Shshoexer 		case ENCXF_AES:
490881e2068Shshoexer 			sa.sadb_sa_encrypt = SADB_X_EALG_AES;
491881e2068Shshoexer 			break;
492881e2068Shshoexer 		case ENCXF_AESCTR:
493881e2068Shshoexer 			sa.sadb_sa_encrypt = SADB_X_EALG_AESCTR;
494881e2068Shshoexer 			break;
495881e2068Shshoexer 		case ENCXF_BLOWFISH:
496881e2068Shshoexer 			sa.sadb_sa_encrypt = SADB_X_EALG_BLF;
497881e2068Shshoexer 			break;
498881e2068Shshoexer 		case ENCXF_CAST128:
499881e2068Shshoexer 			sa.sadb_sa_encrypt = SADB_X_EALG_CAST;
500881e2068Shshoexer 			break;
501881e2068Shshoexer 		case ENCXF_NULL:
502881e2068Shshoexer 			sa.sadb_sa_encrypt = SADB_EALG_NULL;
503881e2068Shshoexer 			break;
504881e2068Shshoexer 		case ENCXF_SKIPJACK:
505881e2068Shshoexer 			sa.sadb_sa_encrypt = SADB_X_EALG_SKIPJACK;
506881e2068Shshoexer 			break;
507881e2068Shshoexer 		default:
508375db29dShshoexer 			warnx("unsupported encryption algorithm %d",
509375db29dShshoexer 			    xfs->encxf->id);
510881e2068Shshoexer 		}
511881e2068Shshoexer 	}
51272e25333Shshoexer 	if (xfs && xfs->compxf) {
51372e25333Shshoexer 		switch (xfs->compxf->id) {
51472e25333Shshoexer 		case COMPXF_DEFLATE:
51572e25333Shshoexer 			sa.sadb_sa_encrypt = SADB_X_CALG_DEFLATE;
51672e25333Shshoexer 			break;
51772e25333Shshoexer 		case COMPXF_LZS:
51872e25333Shshoexer 			sa.sadb_sa_encrypt = SADB_X_CALG_LZS;
51972e25333Shshoexer 			break;
52072e25333Shshoexer 		default:
52172e25333Shshoexer 			warnx("unsupported compression algorithm %d",
52272e25333Shshoexer 			    xfs->compxf->id);
52372e25333Shshoexer 		}
52472e25333Shshoexer 	}
525881e2068Shshoexer 
526f032086dShshoexer 	bzero(&sa_src, sizeof(sa_src));
527f032086dShshoexer 	sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(ssrc.ss_len)) / 8;
528f032086dShshoexer 	sa_src.sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
529f032086dShshoexer 
530f032086dShshoexer 	bzero(&sa_dst, sizeof(sa_dst));
531f032086dShshoexer 	sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(sdst.ss_len)) / 8;
532f032086dShshoexer 	sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST;
533f032086dShshoexer 
53472e25333Shshoexer 	if (action == SADB_ADD && !authkey && !enckey && satype !=
53588a8cceeSmarkus 	    SADB_X_SATYPE_IPCOMP && satype != SADB_X_SATYPE_IPIP) { /* XXX ENCNULL */
5360813ab45Shshoexer 		warnx("no key specified");
5370813ab45Shshoexer 		return -1;
5380813ab45Shshoexer 	}
539881e2068Shshoexer 	if (authkey) {
540881e2068Shshoexer 		bzero(&sa_authkey, sizeof(sa_authkey));
541881e2068Shshoexer 		sa_authkey.sadb_key_len = (sizeof(sa_authkey) +
542881e2068Shshoexer 		    ((authkey->len + 7) / 8) * 8) / 8;
543881e2068Shshoexer 		sa_authkey.sadb_key_exttype = SADB_EXT_KEY_AUTH;
544881e2068Shshoexer 		sa_authkey.sadb_key_bits = 8 * authkey->len;
545881e2068Shshoexer 	}
546881e2068Shshoexer 	if (enckey) {
547881e2068Shshoexer 		bzero(&sa_enckey, sizeof(sa_enckey));
548881e2068Shshoexer 		sa_enckey.sadb_key_len = (sizeof(sa_enckey) +
549881e2068Shshoexer 		    ((enckey->len + 7) / 8) * 8) / 8;
550881e2068Shshoexer 		sa_enckey.sadb_key_exttype = SADB_EXT_KEY_ENCRYPT;
551881e2068Shshoexer 		sa_enckey.sadb_key_bits = 8 * enckey->len;
552f032086dShshoexer 	}
553f032086dShshoexer 
554f032086dShshoexer 	iov_cnt = 0;
555f032086dShshoexer 
556f032086dShshoexer 	/* header */
557f032086dShshoexer 	iov[iov_cnt].iov_base = &smsg;
558f032086dShshoexer 	iov[iov_cnt].iov_len = sizeof(smsg);
559f032086dShshoexer 	iov_cnt++;
560f032086dShshoexer 
561f032086dShshoexer 	/* sa */
562f032086dShshoexer 	iov[iov_cnt].iov_base = &sa;
563f032086dShshoexer 	iov[iov_cnt].iov_len = sizeof(sa);
564f032086dShshoexer 	smsg.sadb_msg_len += sa.sadb_sa_len;
565f032086dShshoexer 	iov_cnt++;
566f032086dShshoexer 
567f032086dShshoexer 	/* src addr */
568f032086dShshoexer 	iov[iov_cnt].iov_base = &sa_src;
569f032086dShshoexer 	iov[iov_cnt].iov_len = sizeof(sa_src);
570f032086dShshoexer 	iov_cnt++;
571f032086dShshoexer 	iov[iov_cnt].iov_base = &ssrc;
572f032086dShshoexer 	iov[iov_cnt].iov_len = ROUNDUP(ssrc.ss_len);
573f032086dShshoexer 	smsg.sadb_msg_len += sa_src.sadb_address_len;
574f032086dShshoexer 	iov_cnt++;
575f032086dShshoexer 
576f032086dShshoexer 	/* dst addr */
577f032086dShshoexer 	iov[iov_cnt].iov_base = &sa_dst;
578f032086dShshoexer 	iov[iov_cnt].iov_len = sizeof(sa_dst);
579f032086dShshoexer 	iov_cnt++;
580f032086dShshoexer 	iov[iov_cnt].iov_base = &sdst;
581f032086dShshoexer 	iov[iov_cnt].iov_len = ROUNDUP(sdst.ss_len);
582f032086dShshoexer 	smsg.sadb_msg_len += sa_dst.sadb_address_len;
583f032086dShshoexer 	iov_cnt++;
584f032086dShshoexer 
585881e2068Shshoexer 	if (authkey) {
586881e2068Shshoexer 		/* authentication key */
587881e2068Shshoexer 		iov[iov_cnt].iov_base = &sa_authkey;
588881e2068Shshoexer 		iov[iov_cnt].iov_len = sizeof(sa_authkey);
589f032086dShshoexer 		iov_cnt++;
590881e2068Shshoexer 		iov[iov_cnt].iov_base = authkey->data;
591881e2068Shshoexer 		iov[iov_cnt].iov_len = ((authkey->len + 7) / 8) * 8;
592881e2068Shshoexer 		smsg.sadb_msg_len += sa_authkey.sadb_key_len;
593881e2068Shshoexer 		iov_cnt++;
594881e2068Shshoexer 	}
595881e2068Shshoexer 	if (enckey) {
596881e2068Shshoexer 		/* encryption key */
597881e2068Shshoexer 		iov[iov_cnt].iov_base = &sa_enckey;
598881e2068Shshoexer 		iov[iov_cnt].iov_len = sizeof(sa_enckey);
599881e2068Shshoexer 		iov_cnt++;
600881e2068Shshoexer 		iov[iov_cnt].iov_base = enckey->data;
601881e2068Shshoexer 		iov[iov_cnt].iov_len = ((enckey->len + 7) / 8) * 8;
602881e2068Shshoexer 		smsg.sadb_msg_len += sa_enckey.sadb_key_len;
603f032086dShshoexer 		iov_cnt++;
604f032086dShshoexer 	}
605f032086dShshoexer 
606f032086dShshoexer 	len = smsg.sadb_msg_len * 8;
607f032086dShshoexer 	if ((n = writev(sd, iov, iov_cnt)) == -1) {
608f032086dShshoexer 		warn("writev failed");
609f032086dShshoexer 		ret = -1;
610f032086dShshoexer 	} else if (n != len) {
611f032086dShshoexer 		warnx("short write");
612f032086dShshoexer 		ret = -1;
613f032086dShshoexer 	}
614f032086dShshoexer 
615f032086dShshoexer 	return ret;
616f032086dShshoexer }
617f032086dShshoexer 
618f032086dShshoexer static int
6198a87fca6Smsf pfkey_reply(int sd, u_int8_t **datap, ssize_t *lenp)
620f484f2cfShshoexer {
621f484f2cfShshoexer 	struct sadb_msg	 hdr;
622f484f2cfShshoexer 	ssize_t		 len;
623f484f2cfShshoexer 	u_int8_t	*data;
624f484f2cfShshoexer 
625f484f2cfShshoexer 	if (recv(sd, &hdr, sizeof(hdr), MSG_PEEK) != sizeof(hdr)) {
626f484f2cfShshoexer 		warnx("short read");
627f484f2cfShshoexer 		return -1;
628f484f2cfShshoexer 	}
629f484f2cfShshoexer 	len = hdr.sadb_msg_len * PFKEYV2_CHUNK;
630f484f2cfShshoexer 	if ((data = malloc(len)) == NULL)
631bd828a90Shshoexer 		err(1, "pfkey_reply: malloc");
632f484f2cfShshoexer 	if (read(sd, data, len) != len) {
633f484f2cfShshoexer 		warn("PF_KEY short read");
634f484f2cfShshoexer 		bzero(data, len);
635f484f2cfShshoexer 		free(data);
636f484f2cfShshoexer 		return -1;
637f484f2cfShshoexer 	}
6388a87fca6Smsf 	if (datap) {
6398a87fca6Smsf 		*datap = data;
6408a87fca6Smsf 		if (lenp)
6418a87fca6Smsf 			*lenp = len;
6428a87fca6Smsf 	} else {
643f484f2cfShshoexer 		bzero(data, len);
644f484f2cfShshoexer 		free(data);
6458a87fca6Smsf 	}
646011122f7Smarkus 	if (datap == NULL && hdr.sadb_msg_errno != 0) {
647011122f7Smarkus 		errno = hdr.sadb_msg_errno;
648011122f7Smarkus 		warn("PF_KEY failed");
649011122f7Smarkus 		return -1;
650011122f7Smarkus 	}
651f484f2cfShshoexer 	return 0;
652f484f2cfShshoexer }
653f484f2cfShshoexer 
654f484f2cfShshoexer int
6551edc1b9aShshoexer pfkey_parse(struct sadb_msg *msg, struct ipsec_rule *rule)
6561edc1b9aShshoexer {
6571edc1b9aShshoexer 	struct sadb_ext		*ext;
6581edc1b9aShshoexer 	struct sadb_address	*saddr;
6591edc1b9aShshoexer 	struct sadb_protocol	*sproto;
6601edc1b9aShshoexer 	struct sadb_ident	*sident;
6611edc1b9aShshoexer 	struct sockaddr		*sa;
662712e78baShshoexer 	struct sockaddr_in	*sa_in;
6632099bcdfStodd 	struct sockaddr_in6	*sa_in6;
6641edc1b9aShshoexer 	int			 len;
6651edc1b9aShshoexer 
6661edc1b9aShshoexer 	switch (msg->sadb_msg_satype) {
667b26a6cb5Shshoexer 	case SADB_SATYPE_ESP:
6689182219dSmarkus 		rule->satype = IPSEC_ESP;
6691edc1b9aShshoexer 		break;
670b26a6cb5Shshoexer 	case SADB_SATYPE_AH:
6719182219dSmarkus 		rule->satype = IPSEC_AH;
6721edc1b9aShshoexer 		break;
673b26a6cb5Shshoexer 	case SADB_X_SATYPE_IPCOMP:
6749182219dSmarkus 		rule->satype = IPSEC_IPCOMP;
675a29da9d0Shshoexer 		break;
67688a8cceeSmarkus 	case SADB_X_SATYPE_IPIP:
6779182219dSmarkus 		rule->satype = IPSEC_IPIP;
67888a8cceeSmarkus 		break;
6791edc1b9aShshoexer 	default:
6801edc1b9aShshoexer 		return (1);
6811edc1b9aShshoexer 	}
6821edc1b9aShshoexer 
6831edc1b9aShshoexer 	for (ext = (struct sadb_ext *)(msg + 1);
6841edc1b9aShshoexer 	    (size_t)((u_int8_t *)ext - (u_int8_t *)msg) <
685d5d1799eShshoexer 	    msg->sadb_msg_len * PFKEYV2_CHUNK && ext->sadb_ext_len > 0;
6861edc1b9aShshoexer 	    ext = (struct sadb_ext *)((u_int8_t *)ext +
6871edc1b9aShshoexer 	    ext->sadb_ext_len * PFKEYV2_CHUNK)) {
6881edc1b9aShshoexer 		switch (ext->sadb_ext_type) {
6891edc1b9aShshoexer 		case SADB_EXT_ADDRESS_SRC:
6901edc1b9aShshoexer 			saddr = (struct sadb_address *)ext;
6911edc1b9aShshoexer 			sa = (struct sockaddr *)(saddr + 1);
6921edc1b9aShshoexer 
69391f765ddShshoexer 			rule->local = calloc(1, sizeof(struct ipsec_addr_wrap));
694d5d1799eShshoexer 			if (rule->local == NULL)
695a1059f6aStodd 				err(1, "pfkey_parse: calloc");
6961edc1b9aShshoexer 
6972099bcdfStodd 			rule->local->af = sa->sa_family;
6981edc1b9aShshoexer 			switch (sa->sa_family) {
6991edc1b9aShshoexer 			case AF_INET:
7001edc1b9aShshoexer 				bcopy(&((struct sockaddr_in *)sa)->sin_addr,
70191f765ddShshoexer 				    &rule->local->address.v4,
702712e78baShshoexer 				    sizeof(struct in_addr));
7032099bcdfStodd 				set_ipmask(rule->local, 32);
7042099bcdfStodd 				break;
7052099bcdfStodd 			case AF_INET6:
7062099bcdfStodd 				bcopy(&((struct sockaddr_in6 *)sa)->sin6_addr,
7072099bcdfStodd 				    &rule->local->address.v6,
7082099bcdfStodd 				    sizeof(struct in6_addr));
7092099bcdfStodd 				set_ipmask(rule->local, 128);
7101edc1b9aShshoexer 				break;
7111edc1b9aShshoexer 			default:
7121edc1b9aShshoexer 				return (1);
7131edc1b9aShshoexer 			}
7141edc1b9aShshoexer 			break;
7151edc1b9aShshoexer 
7161edc1b9aShshoexer 
7171edc1b9aShshoexer 		case SADB_EXT_ADDRESS_DST:
7181edc1b9aShshoexer 			saddr = (struct sadb_address *)ext;
7191edc1b9aShshoexer 			sa = (struct sockaddr *)(saddr + 1);
7201edc1b9aShshoexer 
72191f765ddShshoexer 			rule->peer = calloc(1, sizeof(struct ipsec_addr_wrap));
7221edc1b9aShshoexer 			if (rule->peer == NULL)
723a1059f6aStodd 				err(1, "pfkey_parse: calloc");
7241edc1b9aShshoexer 
7252099bcdfStodd 			rule->peer->af = sa->sa_family;
7261edc1b9aShshoexer 			switch (sa->sa_family) {
7271edc1b9aShshoexer 			case AF_INET:
7281edc1b9aShshoexer 				bcopy(&((struct sockaddr_in *)sa)->sin_addr,
729712e78baShshoexer 				    &rule->peer->address.v4,
730712e78baShshoexer 				    sizeof(struct in_addr));
7312099bcdfStodd 				set_ipmask(rule->peer, 32);
7322099bcdfStodd 				break;
7332099bcdfStodd 			case AF_INET6:
7342099bcdfStodd 				bcopy(&((struct sockaddr_in6 *)sa)->sin6_addr,
7352099bcdfStodd 				    &rule->peer->address.v6,
7362099bcdfStodd 				    sizeof(struct in6_addr));
7372099bcdfStodd 				set_ipmask(rule->peer, 128);
7381edc1b9aShshoexer 				break;
7391edc1b9aShshoexer 			default:
7401edc1b9aShshoexer 				return (1);
7411edc1b9aShshoexer 			}
7421edc1b9aShshoexer 			break;
7431edc1b9aShshoexer 
7441edc1b9aShshoexer 		case SADB_EXT_IDENTITY_SRC:
7451edc1b9aShshoexer 			sident = (struct sadb_ident *)ext;
7461edc1b9aShshoexer 			len = (sident->sadb_ident_len * sizeof(uint64_t)) -
7471edc1b9aShshoexer 			    sizeof(struct sadb_ident);
7481edc1b9aShshoexer 
7499382ed8fShshoexer 			if (rule->auth == NULL) {
7509382ed8fShshoexer 				rule->auth = calloc(1, sizeof(struct
7519382ed8fShshoexer 				    ipsec_auth));
7529382ed8fShshoexer 				if (rule->auth == NULL)
753bd828a90Shshoexer 					err(1, "pfkey_parse: calloc");
7549382ed8fShshoexer 			}
7559382ed8fShshoexer 
756abe65127Shshoexer 			rule->auth->srcid = calloc(1, len);
757abe65127Shshoexer 			if (rule->auth->srcid == NULL)
758bd828a90Shshoexer 				err(1, "pfkey_parse: calloc");
7591edc1b9aShshoexer 
760abe65127Shshoexer 			strlcpy(rule->auth->srcid, (char *)(sident + 1), len);
7611edc1b9aShshoexer 			break;
7621edc1b9aShshoexer 
7631edc1b9aShshoexer 		case SADB_EXT_IDENTITY_DST:
7641edc1b9aShshoexer 			sident = (struct sadb_ident *)ext;
7651edc1b9aShshoexer 			len = (sident->sadb_ident_len * sizeof(uint64_t)) -
7661edc1b9aShshoexer 			    sizeof(struct sadb_ident);
7671edc1b9aShshoexer 
7689382ed8fShshoexer 			if (rule->auth == NULL) {
7699382ed8fShshoexer 				rule->auth = calloc(1, sizeof(struct
7709382ed8fShshoexer 				    ipsec_auth));
7719382ed8fShshoexer 				if (rule->auth == NULL)
772bd828a90Shshoexer 					err(1, "pfkey_parse: calloc");
7739382ed8fShshoexer 			}
7749382ed8fShshoexer 
775abe65127Shshoexer 			rule->auth->dstid = calloc(1, len);
776abe65127Shshoexer 			if (rule->auth->dstid == NULL)
777bd828a90Shshoexer 				err(1, "pfkey_parse: calloc");
7781edc1b9aShshoexer 
779abe65127Shshoexer 			strlcpy(rule->auth->dstid, (char *)(sident + 1), len);
7801edc1b9aShshoexer 			break;
7811edc1b9aShshoexer 
7821edc1b9aShshoexer 		case SADB_X_EXT_PROTOCOL:
7839182219dSmarkus 			sproto = (struct sadb_protocol *)ext;
7849182219dSmarkus 			if (sproto->sadb_protocol_direction == 0)
7859182219dSmarkus 				rule->proto = sproto->sadb_protocol_proto;
7861edc1b9aShshoexer 			break;
7871edc1b9aShshoexer 
7881edc1b9aShshoexer 		case SADB_X_EXT_FLOW_TYPE:
7891edc1b9aShshoexer 			sproto = (struct sadb_protocol *)ext;
7901edc1b9aShshoexer 
7911edc1b9aShshoexer 			switch (sproto->sadb_protocol_direction) {
7921edc1b9aShshoexer 			case IPSP_DIRECTION_IN:
7931edc1b9aShshoexer 				rule->direction = IPSEC_IN;
7941edc1b9aShshoexer 				break;
7951edc1b9aShshoexer 			case IPSP_DIRECTION_OUT:
7961edc1b9aShshoexer 				rule->direction = IPSEC_OUT;
7971edc1b9aShshoexer 				break;
7981edc1b9aShshoexer 			default:
7991edc1b9aShshoexer 				return (1);
8001edc1b9aShshoexer 			}
8016122c05eShshoexer 			switch (sproto->sadb_protocol_proto) {
8026122c05eShshoexer 			case SADB_X_FLOW_TYPE_USE:
8031a3f035aShshoexer 				rule->flowtype = TYPE_USE;
8046122c05eShshoexer 				break;
8056122c05eShshoexer 			case SADB_X_FLOW_TYPE_ACQUIRE:
8061a3f035aShshoexer 				rule->flowtype = TYPE_ACQUIRE;
8076122c05eShshoexer 				break;
8086122c05eShshoexer 			case SADB_X_FLOW_TYPE_REQUIRE:
8091a3f035aShshoexer 				rule->flowtype = TYPE_REQUIRE;
8106122c05eShshoexer 				break;
8116122c05eShshoexer 			case SADB_X_FLOW_TYPE_DENY:
8121a3f035aShshoexer 				rule->flowtype = TYPE_DENY;
8136122c05eShshoexer 				break;
8146122c05eShshoexer 			case SADB_X_FLOW_TYPE_BYPASS:
8151a3f035aShshoexer 				rule->flowtype = TYPE_BYPASS;
8166122c05eShshoexer 				break;
8176122c05eShshoexer 			case SADB_X_FLOW_TYPE_DONTACQ:
8181a3f035aShshoexer 				rule->flowtype = TYPE_DONTACQ;
8196122c05eShshoexer 				break;
8206122c05eShshoexer 			default:
8211a3f035aShshoexer 				rule->flowtype = TYPE_UNKNOWN;
8226122c05eShshoexer 				break;
8236122c05eShshoexer 			}
8241edc1b9aShshoexer 			break;
8251edc1b9aShshoexer 
8261edc1b9aShshoexer 		case SADB_X_EXT_SRC_FLOW:
8271edc1b9aShshoexer 			saddr = (struct sadb_address *)ext;
8281edc1b9aShshoexer 			sa = (struct sockaddr *)(saddr + 1);
8291edc1b9aShshoexer 
8301edc1b9aShshoexer 			if (rule->src == NULL) {
8311edc1b9aShshoexer 				rule->src = calloc(1,
83291f765ddShshoexer 				    sizeof(struct ipsec_addr_wrap));
8331edc1b9aShshoexer 				if (rule->src == NULL)
834bd828a90Shshoexer 					err(1, "pfkey_parse: calloc");
8351edc1b9aShshoexer 			}
8361edc1b9aShshoexer 
8372099bcdfStodd 			rule->src->af = sa->sa_family;
8381edc1b9aShshoexer 			switch (sa->sa_family) {
8391edc1b9aShshoexer 			case AF_INET:
8401edc1b9aShshoexer 				bcopy(&((struct sockaddr_in *)sa)->sin_addr,
841712e78baShshoexer 				    &rule->src->address.v4,
842712e78baShshoexer 				    sizeof(struct in_addr));
843*57f58d0dSnaddy 				rule->sport =
844*57f58d0dSnaddy 				    ((struct sockaddr_in *)sa)->sin_port;
8452099bcdfStodd 				break;
8462099bcdfStodd 			case AF_INET6:
8472099bcdfStodd 				bcopy(&((struct sockaddr_in6 *)sa)->sin6_addr,
8482099bcdfStodd 				    &rule->src->address.v6,
8492099bcdfStodd 				    sizeof(struct in6_addr));
850*57f58d0dSnaddy 				rule->sport =
851*57f58d0dSnaddy 				    ((struct sockaddr_in6 *)sa)->sin6_port;
8521edc1b9aShshoexer 				break;
8531edc1b9aShshoexer 			default:
8541edc1b9aShshoexer 				return (1);
8551edc1b9aShshoexer 			}
8561edc1b9aShshoexer 			break;
8571edc1b9aShshoexer 
8581edc1b9aShshoexer 		case SADB_X_EXT_DST_FLOW:
8591edc1b9aShshoexer 			saddr = (struct sadb_address *)ext;
8601edc1b9aShshoexer 			sa = (struct sockaddr *)(saddr + 1);
8611edc1b9aShshoexer 
8621edc1b9aShshoexer 			if (rule->dst == NULL) {
8631edc1b9aShshoexer 				rule->dst = calloc(1,
86491f765ddShshoexer 				    sizeof(struct ipsec_addr_wrap));
8651edc1b9aShshoexer 				if (rule->dst == NULL)
866bd828a90Shshoexer 					err(1, "pfkey_parse: calloc");
8671edc1b9aShshoexer 			}
8681edc1b9aShshoexer 
8692099bcdfStodd 			rule->dst->af = sa->sa_family;
8701edc1b9aShshoexer 			switch (sa->sa_family) {
8711edc1b9aShshoexer 			case AF_INET:
8721edc1b9aShshoexer 				bcopy(&((struct sockaddr_in *)sa)->sin_addr,
873712e78baShshoexer 				    &rule->dst->address.v4,
874712e78baShshoexer 				    sizeof(struct in_addr));
875*57f58d0dSnaddy 				rule->dport =
876*57f58d0dSnaddy 				    ((struct sockaddr_in *)sa)->sin_port;
8771edc1b9aShshoexer 				break;
8782099bcdfStodd 			case AF_INET6:
8792099bcdfStodd 				bcopy(&((struct sockaddr_in6 *)sa)->sin6_addr,
8802099bcdfStodd 				    &rule->dst->address.v6,
8812099bcdfStodd 				    sizeof(struct in6_addr));
882*57f58d0dSnaddy 				rule->dport =
883*57f58d0dSnaddy 				    ((struct sockaddr_in6 *)sa)->sin6_port;
8842099bcdfStodd 				break;
8851edc1b9aShshoexer 			default:
8861edc1b9aShshoexer 				return (1);
8871edc1b9aShshoexer 			}
8881edc1b9aShshoexer 			break;
8891edc1b9aShshoexer 
8901edc1b9aShshoexer 
8911edc1b9aShshoexer 		case SADB_X_EXT_SRC_MASK:
8921edc1b9aShshoexer 			saddr = (struct sadb_address *)ext;
8931edc1b9aShshoexer 			sa = (struct sockaddr *)(saddr + 1);
8941edc1b9aShshoexer 
8951edc1b9aShshoexer 			if (rule->src == NULL) {
8961edc1b9aShshoexer 				rule->src = calloc(1,
89791f765ddShshoexer 				    sizeof(struct ipsec_addr_wrap));
8981edc1b9aShshoexer 				if (rule->src == NULL)
899bd828a90Shshoexer 					err(1, "pfkey_parse: calloc");
9001edc1b9aShshoexer 			}
9011edc1b9aShshoexer 
9022099bcdfStodd 			rule->src->af = sa->sa_family;
9031edc1b9aShshoexer 			switch (sa->sa_family) {
9041edc1b9aShshoexer 			case AF_INET:
905712e78baShshoexer 				sa_in = (struct sockaddr_in *)sa;
906712e78baShshoexer 				bcopy(&sa_in->sin_addr, &rule->src->mask.v4,
9071edc1b9aShshoexer 				    sizeof(struct in_addr));
9082099bcdfStodd 				break;
9092099bcdfStodd 			case AF_INET6:
9102099bcdfStodd 				sa_in6 = (struct sockaddr_in6 *)sa;
9112099bcdfStodd 				bcopy(&sa_in6->sin6_addr, &rule->src->mask.v6,
9122099bcdfStodd 				    sizeof(struct in6_addr));
9131edc1b9aShshoexer 				break;
9141edc1b9aShshoexer 
9151edc1b9aShshoexer 			default:
9161edc1b9aShshoexer 				return (1);
9171edc1b9aShshoexer 			}
9181edc1b9aShshoexer 			break;
9191edc1b9aShshoexer 
9201edc1b9aShshoexer 		case SADB_X_EXT_DST_MASK:
9211edc1b9aShshoexer 			saddr = (struct sadb_address *)ext;
9221edc1b9aShshoexer 			sa = (struct sockaddr *)(saddr + 1);
9231edc1b9aShshoexer 
9241edc1b9aShshoexer 			if (rule->dst == NULL) {
9251edc1b9aShshoexer 				rule->dst = calloc(1,
92691f765ddShshoexer 				    sizeof(struct ipsec_addr_wrap));
9271edc1b9aShshoexer 				if (rule->dst == NULL)
928bd828a90Shshoexer 					err(1, "pfkey_parse: calloc");
9291edc1b9aShshoexer 			}
9301edc1b9aShshoexer 
9312099bcdfStodd 			rule->dst->af = sa->sa_family;
9321edc1b9aShshoexer 			switch (sa->sa_family) {
9331edc1b9aShshoexer 			case AF_INET:
934712e78baShshoexer 				sa_in = (struct sockaddr_in *)sa;
935712e78baShshoexer 				bcopy(&sa_in->sin_addr, &rule->dst->mask.v4,
9361edc1b9aShshoexer 				    sizeof(struct in_addr));
9371edc1b9aShshoexer 				break;
9382099bcdfStodd 			case AF_INET6:
9392099bcdfStodd 				sa_in6 = (struct sockaddr_in6 *)sa;
9402099bcdfStodd 				bcopy(&sa_in6->sin6_addr, &rule->dst->mask.v6,
9412099bcdfStodd 				    sizeof(struct in6_addr));
9422099bcdfStodd 				break;
9431edc1b9aShshoexer 			default:
9441edc1b9aShshoexer 				return (1);
9451edc1b9aShshoexer 			}
9461edc1b9aShshoexer 			break;
9471edc1b9aShshoexer 
9481edc1b9aShshoexer 		default:
9491edc1b9aShshoexer 			return (1);
9501edc1b9aShshoexer 		}
9511edc1b9aShshoexer 	}
9521edc1b9aShshoexer 
9531edc1b9aShshoexer 	return (0);
9541edc1b9aShshoexer }
9551edc1b9aShshoexer 
9561edc1b9aShshoexer int
957356121f6Shshoexer pfkey_ipsec_establish(int action, struct ipsec_rule *r)
958f484f2cfShshoexer {
95922a29ad6Shshoexer 	int		ret;
96022a29ad6Shshoexer 	u_int8_t	satype, direction;
961f484f2cfShshoexer 
962f032086dShshoexer 	if (r->type == RULE_FLOW) {
9639182219dSmarkus 		switch (r->satype) {
964f484f2cfShshoexer 		case IPSEC_ESP:
965f484f2cfShshoexer 			satype = SADB_SATYPE_ESP;
966f484f2cfShshoexer 			break;
967f484f2cfShshoexer 		case IPSEC_AH:
968f484f2cfShshoexer 			satype = SADB_SATYPE_AH;
969f484f2cfShshoexer 			break;
97072e25333Shshoexer 		case IPSEC_IPCOMP:
97172e25333Shshoexer 			satype = SADB_X_SATYPE_IPCOMP;
97272e25333Shshoexer 			break;
97388a8cceeSmarkus 		case IPSEC_IPIP:
97488a8cceeSmarkus 			satype = SADB_X_SATYPE_IPIP;
97588a8cceeSmarkus 			break;
976f484f2cfShshoexer 		default:
977f484f2cfShshoexer 			return -1;
978f484f2cfShshoexer 		}
979f484f2cfShshoexer 
980f484f2cfShshoexer 		switch (r->direction) {
981f484f2cfShshoexer 		case IPSEC_IN:
982f484f2cfShshoexer 			direction = IPSP_DIRECTION_IN;
983f484f2cfShshoexer 			break;
984f484f2cfShshoexer 		case IPSEC_OUT:
985f484f2cfShshoexer 			direction = IPSP_DIRECTION_OUT;
986f484f2cfShshoexer 			break;
987f484f2cfShshoexer 		default:
988f484f2cfShshoexer 			return -1;
989f484f2cfShshoexer 		}
990f484f2cfShshoexer 
99122a29ad6Shshoexer 		switch (action) {
99290bd57a7Shshoexer 		case ACTION_ADD:
993f032086dShshoexer 			ret = pfkey_flow(fd, satype, SADB_X_ADDFLOW, direction,
994*57f58d0dSnaddy 			    r->proto, r->src, r->sport, r->dst, r->dport,
995*57f58d0dSnaddy 			    r->local, r->peer, r->auth, r->flowtype);
99622a29ad6Shshoexer 			break;
99790bd57a7Shshoexer 		case ACTION_DELETE:
99822a29ad6Shshoexer 			/* No peer for flow deletion. */
999f032086dShshoexer 			ret = pfkey_flow(fd, satype, SADB_X_DELFLOW, direction,
1000*57f58d0dSnaddy 			    r->proto, r->src, r->sport, r->dst, r->dport,
1001*57f58d0dSnaddy 			    NULL, NULL, NULL, r->flowtype);
100222a29ad6Shshoexer 			break;
100322a29ad6Shshoexer 		default:
100422a29ad6Shshoexer 			return -1;
100522a29ad6Shshoexer 		}
1006f032086dShshoexer 	} else if (r->type == RULE_SA) {
10079182219dSmarkus 		switch (r->satype) {
1008881e2068Shshoexer 		case IPSEC_AH:
1009881e2068Shshoexer 			satype = SADB_SATYPE_AH;
1010881e2068Shshoexer 			break;
1011881e2068Shshoexer 		case IPSEC_ESP:
1012881e2068Shshoexer 			satype = SADB_SATYPE_ESP;
1013881e2068Shshoexer 			break;
101472e25333Shshoexer 		case IPSEC_IPCOMP:
101572e25333Shshoexer 			satype = SADB_X_SATYPE_IPCOMP;
101672e25333Shshoexer 			break;
1017381a2422Shshoexer 		case IPSEC_TCPMD5:
1018f032086dShshoexer 			satype = SADB_X_SATYPE_TCPSIGNATURE;
1019381a2422Shshoexer 			break;
102088a8cceeSmarkus 		case IPSEC_IPIP:
102188a8cceeSmarkus 			satype = SADB_X_SATYPE_IPIP;
102288a8cceeSmarkus 			break;
1023381a2422Shshoexer 		default:
1024381a2422Shshoexer 			return -1;
1025381a2422Shshoexer 		}
1026f032086dShshoexer 		switch (action) {
102790bd57a7Shshoexer 		case ACTION_ADD:
1028f032086dShshoexer 			ret = pfkey_sa(fd, satype, SADB_ADD, r->spi,
1029a38d220fShshoexer 			    r->src, r->dst, r->xfs, r->authkey, r->enckey,
1030a38d220fShshoexer 			    r->tmode);
1031f032086dShshoexer 			break;
103290bd57a7Shshoexer 		case ACTION_DELETE:
1033f032086dShshoexer 			ret = pfkey_sa(fd, satype, SADB_DELETE, r->spi,
1034a38d220fShshoexer 			    r->src, r->dst, r->xfs, NULL, NULL, r->tmode);
1035f032086dShshoexer 			break;
1036f032086dShshoexer 		default:
1037f032086dShshoexer 			return -1;
1038f032086dShshoexer 		}
1039f032086dShshoexer 	} else
1040f032086dShshoexer 		return -1;
1041f032086dShshoexer 
104222a29ad6Shshoexer 	if (ret < 0)
1043f484f2cfShshoexer 		return -1;
10448a87fca6Smsf 	if (pfkey_reply(fd, NULL, NULL) < 0)
1045f484f2cfShshoexer 		return -1;
1046f484f2cfShshoexer 
1047f484f2cfShshoexer 	return 0;
1048f484f2cfShshoexer }
1049f484f2cfShshoexer 
1050f484f2cfShshoexer int
1051f484f2cfShshoexer pfkey_ipsec_flush(void)
1052f484f2cfShshoexer {
1053f484f2cfShshoexer 	struct sadb_msg smsg;
1054f484f2cfShshoexer 	struct iovec	iov[IOV_CNT];
1055f484f2cfShshoexer 	ssize_t		n;
1056f484f2cfShshoexer 	int		iov_cnt, len;
1057f484f2cfShshoexer 
1058f484f2cfShshoexer 	bzero(&smsg, sizeof(smsg));
1059f484f2cfShshoexer 	smsg.sadb_msg_version = PF_KEY_V2;
1060f484f2cfShshoexer 	smsg.sadb_msg_seq = sadb_msg_seq++;
1061f484f2cfShshoexer 	smsg.sadb_msg_pid = getpid();
1062f484f2cfShshoexer 	smsg.sadb_msg_len = sizeof(smsg) / 8;
1063f484f2cfShshoexer 	smsg.sadb_msg_type = SADB_FLUSH;
1064f484f2cfShshoexer 	smsg.sadb_msg_satype = SADB_SATYPE_UNSPEC;
1065f484f2cfShshoexer 
1066f484f2cfShshoexer 	iov_cnt = 0;
1067f484f2cfShshoexer 
1068f484f2cfShshoexer 	iov[iov_cnt].iov_base = &smsg;
1069f484f2cfShshoexer 	iov[iov_cnt].iov_len = sizeof(smsg);
1070f484f2cfShshoexer 	iov_cnt++;
1071f484f2cfShshoexer 
1072f484f2cfShshoexer 	len = smsg.sadb_msg_len * 8;
1073f484f2cfShshoexer 	if ((n = writev(fd, iov, iov_cnt)) == -1) {
1074f484f2cfShshoexer 		warn("writev failed");
1075f484f2cfShshoexer 		return -1;
1076f484f2cfShshoexer 	}
1077f484f2cfShshoexer 	if (n != len) {
1078f484f2cfShshoexer 		warnx("short write");
1079f484f2cfShshoexer 		return -1;
1080f484f2cfShshoexer 	}
10818a87fca6Smsf 	if (pfkey_reply(fd, NULL, NULL) < 0)
1082f484f2cfShshoexer 		return -1;
1083f484f2cfShshoexer 
1084f484f2cfShshoexer 	return 0;
1085f484f2cfShshoexer }
1086f484f2cfShshoexer 
10878a87fca6Smsf static int
10888a87fca6Smsf pfkey_promisc(void)
10898a87fca6Smsf {
10908a87fca6Smsf 	struct sadb_msg msg;
10918a87fca6Smsf 
10928a87fca6Smsf 	memset(&msg, 0, sizeof(msg));
10938a87fca6Smsf 	msg.sadb_msg_version = PF_KEY_V2;
10948a87fca6Smsf 	msg.sadb_msg_seq = sadb_msg_seq++;
10958a87fca6Smsf 	msg.sadb_msg_pid = getpid();
10968a87fca6Smsf 	msg.sadb_msg_len = sizeof(msg) / PFKEYV2_CHUNK;
10978a87fca6Smsf 	msg.sadb_msg_type = SADB_X_PROMISC;
10988a87fca6Smsf 	msg.sadb_msg_satype = 1;	/* enable */
10998a87fca6Smsf 	if (write(fd, &msg, sizeof(msg)) != sizeof(msg)) {
11008a87fca6Smsf 		warn("pfkey_promisc: write failed");
11018a87fca6Smsf 		return -1;
11028a87fca6Smsf 	}
11038a87fca6Smsf 	if (pfkey_reply(fd, NULL, NULL) < 0)
11048a87fca6Smsf 		return -1;
11058a87fca6Smsf 	return 0;
11068a87fca6Smsf }
11078a87fca6Smsf 
11088a87fca6Smsf int
11098a87fca6Smsf pfkey_monitor(int opts)
11108a87fca6Smsf {
11118a87fca6Smsf 	fd_set *rset;
11128a87fca6Smsf 	u_int8_t *data;
11138a87fca6Smsf 	struct sadb_msg *msg;
11148a87fca6Smsf 	ssize_t len, set_size;
11158a87fca6Smsf 	int n;
11168a87fca6Smsf 
11178a87fca6Smsf 	if (pfkey_init() < 0)
11188a87fca6Smsf 		return -1;
11198a87fca6Smsf 	if (pfkey_promisc() < 0)
11208a87fca6Smsf 		return -1;
11218a87fca6Smsf 
11228a87fca6Smsf 	set_size = howmany(fd + 1, NFDBITS) * sizeof(fd_mask);
11238a87fca6Smsf 	if ((rset = malloc(set_size)) == NULL) {
11248a87fca6Smsf 		warn("malloc");
11258a87fca6Smsf 		return -1;
11268a87fca6Smsf 	}
11278a87fca6Smsf 	for (;;) {
11288a87fca6Smsf 		memset(rset, 0, set_size);
11298a87fca6Smsf 		FD_SET(fd, rset);
11308a87fca6Smsf 		if ((n = select(fd+1, rset, NULL, NULL, NULL)) < 0)
11318a87fca6Smsf 			err(2, "select");
11328a87fca6Smsf 		if (n == 0)
11338a87fca6Smsf 			break;
11348a87fca6Smsf 		if (!FD_ISSET(fd, rset))
11358a87fca6Smsf 			continue;
11368a87fca6Smsf 		if (pfkey_reply(fd, &data, &len) < 0)
11378a87fca6Smsf 			continue;
11388a87fca6Smsf 		msg = (struct sadb_msg *)data;
11398a87fca6Smsf 		if (msg->sadb_msg_type == SADB_X_PROMISC) {
11408a87fca6Smsf 			/* remove extra header from promisc messages */
11418a87fca6Smsf 			if ((msg->sadb_msg_len * PFKEYV2_CHUNK) >=
11428a87fca6Smsf 			     2 * sizeof(struct sadb_msg)) {
11438a87fca6Smsf 				msg++;
11448a87fca6Smsf 			}
11458a87fca6Smsf 		}
11468a87fca6Smsf 		pfkey_monitor_sa(msg, opts);
11478a87fca6Smsf 		if (opts & IPSECCTL_OPT_VERBOSE)
11488a87fca6Smsf 			pfkey_print_raw(data, len);
11498a87fca6Smsf 		memset(data, 0, len);
11508a87fca6Smsf 		free(data);
11518a87fca6Smsf 	}
11528a87fca6Smsf 	close(fd);
11538a87fca6Smsf 	return 0;
11548a87fca6Smsf }
11558a87fca6Smsf 
1156f484f2cfShshoexer int
1157f484f2cfShshoexer pfkey_init(void)
1158f484f2cfShshoexer {
1159f484f2cfShshoexer 	if ((fd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) == -1)
1160bd828a90Shshoexer 		err(1, "pfkey_init: failed to open PF_KEY socket");
1161f484f2cfShshoexer 
1162f484f2cfShshoexer 	return 0;
1163f484f2cfShshoexer }
1164