1 /* $OpenBSD: pfkey.c,v 1.13 2022/11/07 22:39:13 mbuhl Exp $ */
2
3 /*
4 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
5 * Copyright (c) 2003, 2004 Markus Friedl <markus@openbsd.org>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 #include <sys/types.h>
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25
26 #include "ldpd.h"
27 #include "ldpe.h"
28 #include "log.h"
29
30 static int pfkey_send(int, uint8_t, uint8_t, uint8_t,
31 int, union ldpd_addr *, union ldpd_addr *,
32 uint32_t, uint8_t, int, char *, uint8_t, int, char *,
33 uint16_t, uint16_t);
34 static int pfkey_reply(int, uint32_t *);
35 static int pfkey_sa_add(int, union ldpd_addr *, union ldpd_addr *,
36 uint8_t, char *, uint32_t *);
37 static int pfkey_sa_remove(int, union ldpd_addr *, union ldpd_addr *,
38 uint32_t *);
39 static int pfkey_md5sig_establish(struct nbr *, struct ldp_auth *);
40 static int pfkey_md5sig_remove(struct nbr *);
41
42 #define PFKEY2_CHUNK sizeof(uint64_t)
43 #define ROUNDUP(x) (((x) + (PFKEY2_CHUNK - 1)) & ~(PFKEY2_CHUNK - 1))
44 #define IOV_CNT 20
45
46 static uint32_t sadb_msg_seq;
47 static uint32_t pid; /* should pid_t but pfkey needs uint32_t */
48 static int fd;
49
50 static int
pfkey_send(int sd,uint8_t satype,uint8_t mtype,uint8_t dir,int af,union ldpd_addr * src,union ldpd_addr * dst,uint32_t spi,uint8_t aalg,int alen,char * akey,uint8_t ealg,int elen,char * ekey,uint16_t sport,uint16_t dport)51 pfkey_send(int sd, uint8_t satype, uint8_t mtype, uint8_t dir,
52 int af, union ldpd_addr *src, union ldpd_addr *dst, uint32_t spi,
53 uint8_t aalg, int alen, char *akey, uint8_t ealg, int elen, char *ekey,
54 uint16_t sport, uint16_t dport)
55 {
56 struct sadb_msg smsg;
57 struct sadb_sa sa;
58 struct sadb_address sa_src, sa_dst;
59 struct sadb_key sa_akey, sa_ekey;
60 struct sadb_spirange sa_spirange;
61 struct iovec iov[IOV_CNT];
62 ssize_t n;
63 int len = 0;
64 int iov_cnt;
65 struct sockaddr_storage ssrc, sdst, smask, dmask;
66 struct sockaddr *saptr;
67
68 if (!pid)
69 pid = getpid();
70
71 /* we need clean sockaddr... no ports set */
72 memset(&ssrc, 0, sizeof(ssrc));
73 memset(&smask, 0, sizeof(smask));
74 if ((saptr = addr2sa(af, src, 0)))
75 memcpy(&ssrc, saptr, sizeof(ssrc));
76 switch (af) {
77 case AF_INET:
78 memset(&((struct sockaddr_in *)&smask)->sin_addr, 0xff, 32/8);
79 break;
80 case AF_INET6:
81 memset(&((struct sockaddr_in6 *)&smask)->sin6_addr, 0xff,
82 128/8);
83 break;
84 default:
85 return (-1);
86 }
87 smask.ss_family = ssrc.ss_family;
88 smask.ss_len = ssrc.ss_len;
89
90 memset(&sdst, 0, sizeof(sdst));
91 memset(&dmask, 0, sizeof(dmask));
92 if ((saptr = addr2sa(af, dst, 0)))
93 memcpy(&sdst, saptr, sizeof(sdst));
94 switch (af) {
95 case AF_INET:
96 memset(&((struct sockaddr_in *)&dmask)->sin_addr, 0xff, 32/8);
97 break;
98 case AF_INET6:
99 memset(&((struct sockaddr_in6 *)&dmask)->sin6_addr, 0xff,
100 128/8);
101 break;
102 default:
103 return (-1);
104 }
105 dmask.ss_family = sdst.ss_family;
106 dmask.ss_len = sdst.ss_len;
107
108 memset(&smsg, 0, sizeof(smsg));
109 smsg.sadb_msg_version = PF_KEY_V2;
110 smsg.sadb_msg_seq = ++sadb_msg_seq;
111 smsg.sadb_msg_pid = pid;
112 smsg.sadb_msg_len = sizeof(smsg) / 8;
113 smsg.sadb_msg_type = mtype;
114 smsg.sadb_msg_satype = satype;
115
116 switch (mtype) {
117 case SADB_GETSPI:
118 memset(&sa_spirange, 0, sizeof(sa_spirange));
119 sa_spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE;
120 sa_spirange.sadb_spirange_len = sizeof(sa_spirange) / 8;
121 sa_spirange.sadb_spirange_min = 0x100;
122 sa_spirange.sadb_spirange_max = 0xffffffff;
123 sa_spirange.sadb_spirange_reserved = 0;
124 break;
125 case SADB_ADD:
126 case SADB_UPDATE:
127 case SADB_DELETE:
128 memset(&sa, 0, sizeof(sa));
129 sa.sadb_sa_exttype = SADB_EXT_SA;
130 sa.sadb_sa_len = sizeof(sa) / 8;
131 sa.sadb_sa_replay = 0;
132 sa.sadb_sa_spi = spi;
133 sa.sadb_sa_state = SADB_SASTATE_MATURE;
134 break;
135 }
136
137 memset(&sa_src, 0, sizeof(sa_src));
138 sa_src.sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
139 sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(ssrc.ss_len)) / 8;
140
141 memset(&sa_dst, 0, sizeof(sa_dst));
142 sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST;
143 sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(sdst.ss_len)) / 8;
144
145 sa.sadb_sa_auth = aalg;
146 sa.sadb_sa_encrypt = SADB_X_EALG_AES; /* XXX */
147
148 switch (mtype) {
149 case SADB_ADD:
150 case SADB_UPDATE:
151 memset(&sa_akey, 0, sizeof(sa_akey));
152 sa_akey.sadb_key_exttype = SADB_EXT_KEY_AUTH;
153 sa_akey.sadb_key_len = (sizeof(sa_akey) +
154 ((alen + 7) / 8) * 8) / 8;
155 sa_akey.sadb_key_bits = 8 * alen;
156
157 memset(&sa_ekey, 0, sizeof(sa_ekey));
158 sa_ekey.sadb_key_exttype = SADB_EXT_KEY_ENCRYPT;
159 sa_ekey.sadb_key_len = (sizeof(sa_ekey) +
160 ((elen + 7) / 8) * 8) / 8;
161 sa_ekey.sadb_key_bits = 8 * elen;
162
163 break;
164 }
165
166 iov_cnt = 0;
167
168 /* msghdr */
169 iov[iov_cnt].iov_base = &smsg;
170 iov[iov_cnt].iov_len = sizeof(smsg);
171 iov_cnt++;
172
173 switch (mtype) {
174 case SADB_ADD:
175 case SADB_UPDATE:
176 case SADB_DELETE:
177 /* SA hdr */
178 iov[iov_cnt].iov_base = &sa;
179 iov[iov_cnt].iov_len = sizeof(sa);
180 smsg.sadb_msg_len += sa.sadb_sa_len;
181 iov_cnt++;
182 break;
183 case SADB_GETSPI:
184 /* SPI range */
185 iov[iov_cnt].iov_base = &sa_spirange;
186 iov[iov_cnt].iov_len = sizeof(sa_spirange);
187 smsg.sadb_msg_len += sa_spirange.sadb_spirange_len;
188 iov_cnt++;
189 break;
190 }
191
192 /* dest addr */
193 iov[iov_cnt].iov_base = &sa_dst;
194 iov[iov_cnt].iov_len = sizeof(sa_dst);
195 iov_cnt++;
196 iov[iov_cnt].iov_base = &sdst;
197 iov[iov_cnt].iov_len = ROUNDUP(sdst.ss_len);
198 smsg.sadb_msg_len += sa_dst.sadb_address_len;
199 iov_cnt++;
200
201 /* src addr */
202 iov[iov_cnt].iov_base = &sa_src;
203 iov[iov_cnt].iov_len = sizeof(sa_src);
204 iov_cnt++;
205 iov[iov_cnt].iov_base = &ssrc;
206 iov[iov_cnt].iov_len = ROUNDUP(ssrc.ss_len);
207 smsg.sadb_msg_len += sa_src.sadb_address_len;
208 iov_cnt++;
209
210 switch (mtype) {
211 case SADB_ADD:
212 case SADB_UPDATE:
213 if (alen) {
214 /* auth key */
215 iov[iov_cnt].iov_base = &sa_akey;
216 iov[iov_cnt].iov_len = sizeof(sa_akey);
217 iov_cnt++;
218 iov[iov_cnt].iov_base = akey;
219 iov[iov_cnt].iov_len = ((alen + 7) / 8) * 8;
220 smsg.sadb_msg_len += sa_akey.sadb_key_len;
221 iov_cnt++;
222 }
223 if (elen) {
224 /* encryption key */
225 iov[iov_cnt].iov_base = &sa_ekey;
226 iov[iov_cnt].iov_len = sizeof(sa_ekey);
227 iov_cnt++;
228 iov[iov_cnt].iov_base = ekey;
229 iov[iov_cnt].iov_len = ((elen + 7) / 8) * 8;
230 smsg.sadb_msg_len += sa_ekey.sadb_key_len;
231 iov_cnt++;
232 }
233 break;
234 }
235
236 len = smsg.sadb_msg_len * 8;
237 do {
238 n = writev(sd, iov, iov_cnt);
239 } while (n == -1 && (errno == EAGAIN || errno == EINTR));
240
241 if (n == -1) {
242 log_warn("writev (%d/%d)", iov_cnt, len);
243 return (-1);
244 }
245
246 return (0);
247 }
248
249 int
pfkey_read(int sd,struct sadb_msg * h)250 pfkey_read(int sd, struct sadb_msg *h)
251 {
252 struct sadb_msg hdr;
253
254 if (recv(sd, &hdr, sizeof(hdr), MSG_PEEK) != sizeof(hdr)) {
255 if (errno == EAGAIN || errno == EINTR)
256 return (1);
257 log_warn("pfkey peek");
258 return (-1);
259 }
260
261 /* XXX: Only one message can be outstanding. */
262 if (hdr.sadb_msg_seq == sadb_msg_seq &&
263 hdr.sadb_msg_pid == pid) {
264 if (h)
265 *h = hdr;
266 return (0);
267 }
268
269 /* not ours, discard */
270 if (read(sd, &hdr, sizeof(hdr)) == -1) {
271 if (errno == EAGAIN || errno == EINTR)
272 return (1);
273 log_warn("pfkey read");
274 return (-1);
275 }
276
277 return (1);
278 }
279
280 static int
pfkey_reply(int sd,uint32_t * spip)281 pfkey_reply(int sd, uint32_t *spip)
282 {
283 struct sadb_msg hdr, *msg;
284 struct sadb_ext *ext;
285 struct sadb_sa *sa;
286 uint8_t *data;
287 ssize_t len;
288 int rv;
289
290 do {
291 rv = pfkey_read(sd, &hdr);
292 if (rv == -1)
293 return (-1);
294 } while (rv);
295
296 if (hdr.sadb_msg_errno != 0) {
297 errno = hdr.sadb_msg_errno;
298 if (errno == ESRCH)
299 return (0);
300 else {
301 log_warn("pfkey");
302 return (-1);
303 }
304 }
305 if ((data = reallocarray(NULL, hdr.sadb_msg_len, PFKEY2_CHUNK)) == NULL) {
306 log_warn("pfkey malloc");
307 return (-1);
308 }
309 len = hdr.sadb_msg_len * PFKEY2_CHUNK;
310 if (read(sd, data, len) != len) {
311 log_warn("pfkey read");
312 freezero(data, len);
313 return (-1);
314 }
315
316 if (hdr.sadb_msg_type == SADB_GETSPI) {
317 if (spip == NULL) {
318 freezero(data, len);
319 return (0);
320 }
321
322 msg = (struct sadb_msg *)data;
323 for (ext = (struct sadb_ext *)(msg + 1);
324 (size_t)((uint8_t *)ext - (uint8_t *)msg) <
325 msg->sadb_msg_len * PFKEY2_CHUNK;
326 ext = (struct sadb_ext *)((uint8_t *)ext +
327 ext->sadb_ext_len * PFKEY2_CHUNK)) {
328 if (ext->sadb_ext_type == SADB_EXT_SA) {
329 sa = (struct sadb_sa *) ext;
330 *spip = sa->sadb_sa_spi;
331 break;
332 }
333 }
334 }
335 freezero(data, len);
336 return (0);
337 }
338
339 static int
pfkey_sa_add(int af,union ldpd_addr * src,union ldpd_addr * dst,uint8_t keylen,char * key,uint32_t * spi)340 pfkey_sa_add(int af, union ldpd_addr *src, union ldpd_addr *dst, uint8_t keylen,
341 char *key, uint32_t *spi)
342 {
343 if (pfkey_send(fd, SADB_X_SATYPE_TCPSIGNATURE, SADB_GETSPI, 0,
344 af, src, dst, 0, 0, 0, NULL, 0, 0, NULL, 0, 0) < 0)
345 return (-1);
346 if (pfkey_reply(fd, spi) < 0)
347 return (-1);
348 if (pfkey_send(fd, SADB_X_SATYPE_TCPSIGNATURE, SADB_UPDATE, 0,
349 af, src, dst, *spi, 0, keylen, key, 0, 0, NULL, 0, 0) < 0)
350 return (-1);
351 if (pfkey_reply(fd, NULL) < 0)
352 return (-1);
353 return (0);
354 }
355
356 static int
pfkey_sa_remove(int af,union ldpd_addr * src,union ldpd_addr * dst,uint32_t * spi)357 pfkey_sa_remove(int af, union ldpd_addr *src, union ldpd_addr *dst,
358 uint32_t *spi)
359 {
360 if (pfkey_send(fd, SADB_X_SATYPE_TCPSIGNATURE, SADB_DELETE, 0,
361 af, src, dst, *spi, 0, 0, NULL, 0, 0, NULL, 0, 0) < 0)
362 return (-1);
363 if (pfkey_reply(fd, NULL) < 0)
364 return (-1);
365 *spi = 0;
366 return (0);
367 }
368
369 static int
pfkey_md5sig_establish(struct nbr * nbr,struct ldp_auth * auth)370 pfkey_md5sig_establish(struct nbr *nbr, struct ldp_auth *auth)
371 {
372 sleep(1);
373
374 pfkey_md5sig_remove(nbr);
375
376 if (pfkey_sa_add(nbr->af, &nbr->laddr, &nbr->raddr,
377 auth->md5key_len, auth->md5key, &nbr->auth_spi_out) == -1)
378 return (-1);
379
380 if (pfkey_sa_add(nbr->af, &nbr->raddr, &nbr->laddr,
381 auth->md5key_len, auth->md5key, &nbr->auth_spi_in) == -1)
382 return (-1);
383
384 nbr->auth_established = 1;
385
386 return (0);
387 }
388
389 static int
pfkey_md5sig_remove(struct nbr * nbr)390 pfkey_md5sig_remove(struct nbr *nbr)
391 {
392 if (nbr->auth_spi_out) {
393 if (pfkey_sa_remove(nbr->af, &nbr->laddr, &nbr->raddr,
394 &nbr->auth_spi_out) == -1)
395 return (-1);
396 }
397 if (nbr->auth_spi_in) {
398 if (pfkey_sa_remove(nbr->af, &nbr->raddr, &nbr->laddr,
399 &nbr->auth_spi_in) == -1)
400 return (-1);
401 }
402
403 nbr->auth_established = 0;
404 nbr->auth_spi_in = 0;
405 nbr->auth_spi_out = 0;
406
407 return (0);
408 }
409
410 static struct ldp_auth *
pfkey_find_auth(struct ldpd_conf * conf,struct nbr * nbr)411 pfkey_find_auth(struct ldpd_conf *conf, struct nbr *nbr)
412 {
413 struct ldp_auth *auth, *match = NULL;
414
415 LIST_FOREACH(auth, &conf->auth_list, entry) {
416 in_addr_t mask = prefixlen2mask(auth->idlen);
417 if ((auth->id.s_addr & mask) != (nbr->id.s_addr & mask))
418 continue;
419
420 if (match == NULL ||
421 match->idlen < auth->idlen)
422 match = auth;
423 }
424
425 return (match);
426 }
427
428 int
pfkey_establish(struct ldpd_conf * conf,struct nbr * nbr)429 pfkey_establish(struct ldpd_conf *conf, struct nbr *nbr)
430 {
431 struct ldp_auth *auth = NULL;
432
433 auth = pfkey_find_auth(conf, nbr);
434 if (auth == NULL || /* no policy */
435 auth->md5key_len == 0) /* "no tcpmd5 sig" */
436 return (0);
437
438 return (pfkey_md5sig_establish(nbr, auth));
439 }
440
441 int
pfkey_remove(struct nbr * nbr)442 pfkey_remove(struct nbr *nbr)
443 {
444 return (pfkey_md5sig_remove(nbr));
445 }
446
447 int
pfkey_init(void)448 pfkey_init(void)
449 {
450 if ((fd = socket(PF_KEY, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
451 PF_KEY_V2)) == -1) {
452 if (errno == EPROTONOSUPPORT) {
453 log_warnx("PF_KEY not available");
454 sysdep.no_pfkey = 1;
455 return (-1);
456 } else
457 fatal("pfkey setup failed");
458 }
459 return (fd);
460 }
461