]> git.proxmox.com Git - mirror_frr.git/blame - ldpd/pfkey.c
Merge pull request #13649 from donaldsharp/unlock_the_node_or_else
[mirror_frr.git] / ldpd / pfkey.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: ISC
8429abe0
RW
2/* $OpenBSD$ */
3
4/*
5 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
6 * Copyright (c) 2003, 2004 Markus Friedl <markus@openbsd.org>
8429abe0
RW
7 */
8
b45ac5f5
DL
9#ifdef HAVE_CONFIG_H
10#include "config.h"
11#endif
12
eac6e3f0 13#ifdef __OpenBSD__
8429abe0 14#include <sys/types.h>
eac6e3f0 15#include <sys/socket.h>
8429abe0
RW
16#include <errno.h>
17#include <stdlib.h>
18#include <string.h>
19#include <unistd.h>
20
21#include "ldpd.h"
22#include "ldpe.h"
23#include "log.h"
24
25static int pfkey_send(int, uint8_t, uint8_t, uint8_t,
26 int, union ldpd_addr *, union ldpd_addr *,
27 uint32_t, uint8_t, int, char *, uint8_t, int, char *,
28 uint16_t, uint16_t);
29static int pfkey_reply(int, uint32_t *);
30static int pfkey_sa_add(int, union ldpd_addr *, union ldpd_addr *,
31 uint8_t, char *, uint32_t *);
32static int pfkey_sa_remove(int, union ldpd_addr *, union ldpd_addr *,
33 uint32_t *);
34static int pfkey_md5sig_establish(struct nbr *, struct nbr_params *nbrp);
35static int pfkey_md5sig_remove(struct nbr *);
36
37#define PFKEY2_CHUNK sizeof(uint64_t)
38#define ROUNDUP(x) (((x) + (PFKEY2_CHUNK - 1)) & ~(PFKEY2_CHUNK - 1))
39#define IOV_CNT 20
40
41static uint32_t sadb_msg_seq;
42static uint32_t pid; /* should pid_t but pfkey needs uint32_t */
43static int fd;
44
45static int
46pfkey_send(int sd, uint8_t satype, uint8_t mtype, uint8_t dir,
47 int af, union ldpd_addr *src, union ldpd_addr *dst, uint32_t spi,
48 uint8_t aalg, int alen, char *akey, uint8_t ealg, int elen, char *ekey,
49 uint16_t sport, uint16_t dport)
50{
51 struct sadb_msg smsg;
52 struct sadb_sa sa;
53 struct sadb_address sa_src, sa_dst;
54 struct sadb_key sa_akey, sa_ekey;
55 struct sadb_spirange sa_spirange;
56 struct iovec iov[IOV_CNT];
57 ssize_t n;
58 int len = 0;
59 int iov_cnt;
4149ef7c
A
60 struct sockaddr_storage smask, dmask;
61 union sockunion su_src, su_dst;
8429abe0
RW
62
63 if (!pid)
64 pid = getpid();
65
66 /* we need clean sockaddr... no ports set */
8429abe0 67 memset(&smask, 0, sizeof(smask));
4149ef7c
A
68
69 addr2sa(af, src, 0, &su_src);
70
8429abe0
RW
71 switch (af) {
72 case AF_INET:
73 memset(&((struct sockaddr_in *)&smask)->sin_addr, 0xff, 32/8);
74 break;
75 case AF_INET6:
76 memset(&((struct sockaddr_in6 *)&smask)->sin6_addr, 0xff,
77 128/8);
78 break;
79 default:
80 return (-1);
81 }
4149ef7c
A
82 smask.ss_family = su_src.sa.sa_family;
83 smask.ss_len = sockaddr_len(&su_src.sa);
8429abe0 84
8429abe0 85 memset(&dmask, 0, sizeof(dmask));
4149ef7c
A
86
87 addr2sa(af, dst, 0, &su_dst);
88
8429abe0
RW
89 switch (af) {
90 case AF_INET:
91 memset(&((struct sockaddr_in *)&dmask)->sin_addr, 0xff, 32/8);
92 break;
93 case AF_INET6:
94 memset(&((struct sockaddr_in6 *)&dmask)->sin6_addr, 0xff,
95 128/8);
96 break;
97 default:
98 return (-1);
99 }
4149ef7c
A
100 dmask.ss_family = su_dst.sa.sa_family;
101 dmask.ss_len = sockaddr_len(&su_dst.sa);
8429abe0
RW
102
103 memset(&smsg, 0, sizeof(smsg));
104 smsg.sadb_msg_version = PF_KEY_V2;
105 smsg.sadb_msg_seq = ++sadb_msg_seq;
106 smsg.sadb_msg_pid = pid;
107 smsg.sadb_msg_len = sizeof(smsg) / 8;
108 smsg.sadb_msg_type = mtype;
109 smsg.sadb_msg_satype = satype;
110
111 switch (mtype) {
112 case SADB_GETSPI:
113 memset(&sa_spirange, 0, sizeof(sa_spirange));
114 sa_spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE;
115 sa_spirange.sadb_spirange_len = sizeof(sa_spirange) / 8;
116 sa_spirange.sadb_spirange_min = 0x100;
117 sa_spirange.sadb_spirange_max = 0xffffffff;
118 sa_spirange.sadb_spirange_reserved = 0;
119 break;
120 case SADB_ADD:
121 case SADB_UPDATE:
122 case SADB_DELETE:
123 memset(&sa, 0, sizeof(sa));
124 sa.sadb_sa_exttype = SADB_EXT_SA;
125 sa.sadb_sa_len = sizeof(sa) / 8;
126 sa.sadb_sa_replay = 0;
ffdc293b 127 sa.sadb_sa_spi = htonl(spi);
8429abe0
RW
128 sa.sadb_sa_state = SADB_SASTATE_MATURE;
129 break;
130 }
131
132 memset(&sa_src, 0, sizeof(sa_src));
133 sa_src.sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
4149ef7c
A
134 sa_src.sadb_address_len =
135 (sizeof(sa_src) + ROUNDUP(sockaddr_len(&su_src.sa))) / 8;
8429abe0
RW
136
137 memset(&sa_dst, 0, sizeof(sa_dst));
138 sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST;
4149ef7c
A
139 sa_dst.sadb_address_len =
140 (sizeof(sa_dst) + ROUNDUP(sockaddr_len(&su_dst.sa))) / 8;
8429abe0
RW
141
142 sa.sadb_sa_auth = aalg;
143 sa.sadb_sa_encrypt = SADB_X_EALG_AES; /* XXX */
144
145 switch (mtype) {
146 case SADB_ADD:
147 case SADB_UPDATE:
148 memset(&sa_akey, 0, sizeof(sa_akey));
149 sa_akey.sadb_key_exttype = SADB_EXT_KEY_AUTH;
150 sa_akey.sadb_key_len = (sizeof(sa_akey) +
151 ((alen + 7) / 8) * 8) / 8;
152 sa_akey.sadb_key_bits = 8 * alen;
153
154 memset(&sa_ekey, 0, sizeof(sa_ekey));
155 sa_ekey.sadb_key_exttype = SADB_EXT_KEY_ENCRYPT;
156 sa_ekey.sadb_key_len = (sizeof(sa_ekey) +
157 ((elen + 7) / 8) * 8) / 8;
158 sa_ekey.sadb_key_bits = 8 * elen;
159
160 break;
161 }
162
163 iov_cnt = 0;
164
165 /* msghdr */
166 iov[iov_cnt].iov_base = &smsg;
167 iov[iov_cnt].iov_len = sizeof(smsg);
168 iov_cnt++;
169
170 switch (mtype) {
171 case SADB_ADD:
172 case SADB_UPDATE:
173 case SADB_DELETE:
174 /* SA hdr */
175 iov[iov_cnt].iov_base = &sa;
176 iov[iov_cnt].iov_len = sizeof(sa);
177 smsg.sadb_msg_len += sa.sadb_sa_len;
178 iov_cnt++;
179 break;
180 case SADB_GETSPI:
181 /* SPI range */
182 iov[iov_cnt].iov_base = &sa_spirange;
183 iov[iov_cnt].iov_len = sizeof(sa_spirange);
184 smsg.sadb_msg_len += sa_spirange.sadb_spirange_len;
185 iov_cnt++;
186 break;
187 }
188
189 /* dest addr */
190 iov[iov_cnt].iov_base = &sa_dst;
191 iov[iov_cnt].iov_len = sizeof(sa_dst);
192 iov_cnt++;
4149ef7c
A
193 iov[iov_cnt].iov_base = &su_dst;
194 iov[iov_cnt].iov_len = ROUNDUP(sockaddr_len(&su_dst.sa));
8429abe0
RW
195 smsg.sadb_msg_len += sa_dst.sadb_address_len;
196 iov_cnt++;
197
198 /* src addr */
199 iov[iov_cnt].iov_base = &sa_src;
200 iov[iov_cnt].iov_len = sizeof(sa_src);
201 iov_cnt++;
4149ef7c
A
202 iov[iov_cnt].iov_base = &su_src;
203 iov[iov_cnt].iov_len = ROUNDUP(sockaddr_len(&su_src.sa));
8429abe0
RW
204 smsg.sadb_msg_len += sa_src.sadb_address_len;
205 iov_cnt++;
206
207 switch (mtype) {
208 case SADB_ADD:
209 case SADB_UPDATE:
210 if (alen) {
211 /* auth key */
212 iov[iov_cnt].iov_base = &sa_akey;
213 iov[iov_cnt].iov_len = sizeof(sa_akey);
214 iov_cnt++;
215 iov[iov_cnt].iov_base = akey;
216 iov[iov_cnt].iov_len = ((alen + 7) / 8) * 8;
217 smsg.sadb_msg_len += sa_akey.sadb_key_len;
218 iov_cnt++;
219 }
220 if (elen) {
221 /* encryption key */
222 iov[iov_cnt].iov_base = &sa_ekey;
223 iov[iov_cnt].iov_len = sizeof(sa_ekey);
224 iov_cnt++;
225 iov[iov_cnt].iov_base = ekey;
226 iov[iov_cnt].iov_len = ((elen + 7) / 8) * 8;
227 smsg.sadb_msg_len += sa_ekey.sadb_key_len;
228 iov_cnt++;
229 }
230 break;
231 }
232
233 len = smsg.sadb_msg_len * 8;
234 do {
235 n = writev(sd, iov, iov_cnt);
236 } while (n == -1 && (errno == EAGAIN || errno == EINTR));
237
238 if (n == -1) {
239 log_warn("writev (%d/%d)", iov_cnt, len);
240 return (-1);
241 }
242
243 return (0);
244}
245
246int
247pfkey_read(int sd, struct sadb_msg *h)
248{
249 struct sadb_msg hdr;
250
251 if (recv(sd, &hdr, sizeof(hdr), MSG_PEEK) != sizeof(hdr)) {
252 if (errno == EAGAIN || errno == EINTR)
253 return (0);
254 log_warn("pfkey peek");
255 return (-1);
256 }
257
258 /* XXX: Only one message can be outstanding. */
259 if (hdr.sadb_msg_seq == sadb_msg_seq &&
260 hdr.sadb_msg_pid == pid) {
261 if (h)
262 *h = hdr;
263 return (0);
264 }
265
266 /* not ours, discard */
267 if (read(sd, &hdr, sizeof(hdr)) == -1) {
268 if (errno == EAGAIN || errno == EINTR)
269 return (0);
270 log_warn("pfkey read");
271 return (-1);
272 }
273
274 return (1);
275}
276
277static int
ffdc293b 278pfkey_reply(int sd, uint32_t *spi)
8429abe0
RW
279{
280 struct sadb_msg hdr, *msg;
281 struct sadb_ext *ext;
282 struct sadb_sa *sa;
283 uint8_t *data;
284 ssize_t len;
285 int rv;
286
287 do {
288 rv = pfkey_read(sd, &hdr);
289 if (rv == -1)
290 return (-1);
291 } while (rv);
292
293 if (hdr.sadb_msg_errno != 0) {
294 errno = hdr.sadb_msg_errno;
295 if (errno == ESRCH)
296 return (0);
297 else {
298 log_warn("pfkey");
299 return (-1);
300 }
301 }
302 if ((data = reallocarray(NULL, hdr.sadb_msg_len, PFKEY2_CHUNK)) == NULL) {
303 log_warn("pfkey malloc");
304 return (-1);
305 }
306 len = hdr.sadb_msg_len * PFKEY2_CHUNK;
307 if (read(sd, data, len) != len) {
308 log_warn("pfkey read");
309 explicit_bzero(data, len);
310 free(data);
311 return (-1);
312 }
313
314 if (hdr.sadb_msg_type == SADB_GETSPI) {
ffdc293b 315 if (spi == NULL) {
8429abe0
RW
316 explicit_bzero(data, len);
317 free(data);
318 return (0);
319 }
320
321 msg = (struct sadb_msg *)data;
322 for (ext = (struct sadb_ext *)(msg + 1);
323 (size_t)((uint8_t *)ext - (uint8_t *)msg) <
324 msg->sadb_msg_len * PFKEY2_CHUNK;
325 ext = (struct sadb_ext *)((uint8_t *)ext +
326 ext->sadb_ext_len * PFKEY2_CHUNK)) {
327 if (ext->sadb_ext_type == SADB_EXT_SA) {
328 sa = (struct sadb_sa *) ext;
ffdc293b 329 *spi = ntohl(sa->sadb_sa_spi);
8429abe0
RW
330 break;
331 }
332 }
333 }
334 explicit_bzero(data, len);
335 free(data);
336 return (0);
337}
338
339static int
340pfkey_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
356static int
357pfkey_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
369static int
370pfkey_md5sig_establish(struct nbr *nbr, struct nbr_params *nbrp)
371{
372 sleep(1);
373
374 if (!nbr->auth.spi_out)
375 if (pfkey_sa_add(nbr->af, &nbr->laddr, &nbr->raddr,
376 nbrp->auth.md5key_len, nbrp->auth.md5key,
377 &nbr->auth.spi_out) == -1)
378 return (-1);
379 if (!nbr->auth.spi_in)
380 if (pfkey_sa_add(nbr->af, &nbr->raddr, &nbr->laddr,
381 nbrp->auth.md5key_len, nbrp->auth.md5key,
382 &nbr->auth.spi_in) == -1)
383 return (-1);
384
385 nbr->auth.established = 1;
386 return (0);
387}
388
389static int
390pfkey_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 if (nbr->auth.spi_in)
397 if (pfkey_sa_remove(nbr->af, &nbr->raddr, &nbr->laddr,
398 &nbr->auth.spi_in) == -1)
399 return (-1);
400
401 nbr->auth.established = 0;
402 nbr->auth.spi_in = 0;
403 nbr->auth.spi_out = 0;
404 nbr->auth.method = AUTH_NONE;
405 memset(nbr->auth.md5key, 0, sizeof(nbr->auth.md5key));
406
407 return (0);
408}
409
410int
411pfkey_establish(struct nbr *nbr, struct nbr_params *nbrp)
412{
8429abe0
RW
413 switch (nbr->auth.method) {
414 case AUTH_MD5SIG:
415 strlcpy(nbr->auth.md5key, nbrp->auth.md5key,
416 sizeof(nbr->auth.md5key));
4a055ac2
DS
417 return pfkey_md5sig_establish(nbr, nbrp);
418 case AUTH_NONE:
419 return 0;
8429abe0
RW
420 }
421
4a055ac2 422 assert(!"Reached end of function where we are not expecting to");
8429abe0
RW
423}
424
425int
426pfkey_remove(struct nbr *nbr)
427{
4a055ac2
DS
428 if (!nbr->auth.established)
429 return 0;
8429abe0
RW
430
431 switch (nbr->auth.method) {
432 case AUTH_MD5SIG:
4a055ac2
DS
433 return pfkey_md5sig_remove(nbr);
434 case AUTH_NONE:
435 return 0;
8429abe0
RW
436 break;
437 }
438
4a055ac2 439 assert(!"Reached end of function where we are not expecting to");
8429abe0
RW
440}
441
442int
443pfkey_init(void)
444{
445 if ((fd = socket(PF_KEY, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
446 PF_KEY_V2)) == -1) {
447 if (errno == EPROTONOSUPPORT) {
448 log_warnx("PF_KEY not available");
449 sysdep.no_pfkey = 1;
450 return (-1);
451 } else
452 fatal("pfkey setup failed");
453 }
454 return (fd);
455}
eac6e3f0 456#endif /* __OpenBSD__ */