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