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