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