File: | src/usr.sbin/ldpd/pfkey.c |
Warning: | line 296, column 25 The left operand of '!=' is a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: pfkey.c,v 1.12 2019/01/23 02:02:04 dlg 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(*__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_CHUNKsizeof(uint64_t) sizeof(uint64_t) | |||
43 | #define ROUNDUP(x)(((x) + (sizeof(uint64_t) - 1)) & ~(sizeof(uint64_t) - 1) ) (((x) + (PFKEY2_CHUNKsizeof(uint64_t) - 1)) & ~(PFKEY2_CHUNKsizeof(uint64_t) - 1)) | |||
44 | #define IOV_CNT20 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 | |||
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_CNT20]; | |||
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_INET2: | |||
78 | memset(&((struct sockaddr_in *)&smask)->sin_addr, 0xff, 32/8); | |||
79 | break; | |||
80 | case AF_INET624: | |||
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_INET2: | |||
96 | memset(&((struct sockaddr_in *)&dmask)->sin_addr, 0xff, 32/8); | |||
97 | break; | |||
98 | case AF_INET624: | |||
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_V22; | |||
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_GETSPI1: | |||
118 | memset(&sa_spirange, 0, sizeof(sa_spirange)); | |||
119 | sa_spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE16; | |||
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_ADD3: | |||
126 | case SADB_UPDATE2: | |||
127 | case SADB_DELETE4: | |||
128 | memset(&sa, 0, sizeof(sa)); | |||
129 | sa.sadb_sa_exttype = SADB_EXT_SA1; | |||
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_MATURE1; | |||
134 | break; | |||
135 | } | |||
136 | ||||
137 | memset(&sa_src, 0, sizeof(sa_src)); | |||
138 | sa_src.sadb_address_exttype = SADB_EXT_ADDRESS_SRC5; | |||
139 | sa_src.sadb_address_len = (sizeof(sa_src) + ROUNDUP(ssrc.ss_len)(((ssrc.ss_len) + (sizeof(uint64_t) - 1)) & ~(sizeof(uint64_t ) - 1))) / 8; | |||
140 | ||||
141 | memset(&sa_dst, 0, sizeof(sa_dst)); | |||
142 | sa_dst.sadb_address_exttype = SADB_EXT_ADDRESS_DST6; | |||
143 | sa_dst.sadb_address_len = (sizeof(sa_dst) + ROUNDUP(sdst.ss_len)(((sdst.ss_len) + (sizeof(uint64_t) - 1)) & ~(sizeof(uint64_t ) - 1))) / 8; | |||
144 | ||||
145 | sa.sadb_sa_auth = aalg; | |||
146 | sa.sadb_sa_encrypt = SADB_X_EALG_AES12; /* XXX */ | |||
147 | ||||
148 | switch (mtype) { | |||
149 | case SADB_ADD3: | |||
150 | case SADB_UPDATE2: | |||
151 | memset(&sa_akey, 0, sizeof(sa_akey)); | |||
152 | sa_akey.sadb_key_exttype = SADB_EXT_KEY_AUTH8; | |||
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_ENCRYPT9; | |||
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_ADD3: | |||
175 | case SADB_UPDATE2: | |||
176 | case SADB_DELETE4: | |||
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_GETSPI1: | |||
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)(((sdst.ss_len) + (sizeof(uint64_t) - 1)) & ~(sizeof(uint64_t ) - 1)); | |||
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)(((ssrc.ss_len) + (sizeof(uint64_t) - 1)) & ~(sizeof(uint64_t ) - 1)); | |||
207 | smsg.sadb_msg_len += sa_src.sadb_address_len; | |||
208 | iov_cnt++; | |||
209 | ||||
210 | switch (mtype) { | |||
211 | case SADB_ADD3: | |||
212 | case SADB_UPDATE2: | |||
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(*__errno()) == EAGAIN35 || errno(*__errno()) == EINTR4)); | |||
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 | |||
250 | pfkey_read(int sd, struct sadb_msg *h) | |||
251 | { | |||
252 | struct sadb_msg hdr; | |||
253 | ||||
254 | if (recv(sd, &hdr, sizeof(hdr), MSG_PEEK0x2) != sizeof(hdr)) { | |||
255 | if (errno(*__errno()) == EAGAIN35 || errno(*__errno()) == EINTR4) | |||
256 | return (0); | |||
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(*__errno()) == EAGAIN35 || errno(*__errno()) == EINTR4) | |||
272 | return (0); | |||
273 | log_warn("pfkey read"); | |||
274 | return (-1); | |||
275 | } | |||
276 | ||||
277 | return (1); | |||
278 | } | |||
279 | ||||
280 | static int | |||
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(*__errno()) = hdr.sadb_msg_errno; | |||
298 | if (errno(*__errno()) == ESRCH3) | |||
299 | return (0); | |||
300 | else { | |||
301 | log_warn("pfkey"); | |||
302 | return (-1); | |||
303 | } | |||
304 | } | |||
305 | if ((data = reallocarray(NULL((void *)0), hdr.sadb_msg_len, PFKEY2_CHUNKsizeof(uint64_t))) == NULL((void *)0)) { | |||
306 | log_warn("pfkey malloc"); | |||
307 | return (-1); | |||
308 | } | |||
309 | len = hdr.sadb_msg_len * PFKEY2_CHUNKsizeof(uint64_t); | |||
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_GETSPI1) { | |||
317 | if (spip == NULL((void *)0)) { | |||
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_CHUNKsizeof(uint64_t); | |||
326 | ext = (struct sadb_ext *)((uint8_t *)ext + | |||
327 | ext->sadb_ext_len * PFKEY2_CHUNKsizeof(uint64_t))) { | |||
328 | if (ext->sadb_ext_type == SADB_EXT_SA1) { | |||
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 | |||
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_TCPSIGNATURE8, SADB_GETSPI1, 0, | |||
344 | af, src, dst, 0, 0, 0, NULL((void *)0), 0, 0, NULL((void *)0), 0, 0) < 0) | |||
345 | return (-1); | |||
346 | if (pfkey_reply(fd, spi) < 0) | |||
347 | return (-1); | |||
348 | if (pfkey_send(fd, SADB_X_SATYPE_TCPSIGNATURE8, SADB_UPDATE2, 0, | |||
349 | af, src, dst, *spi, 0, keylen, key, 0, 0, NULL((void *)0), 0, 0) < 0) | |||
350 | return (-1); | |||
351 | if (pfkey_reply(fd, NULL((void *)0)) < 0) | |||
352 | return (-1); | |||
353 | return (0); | |||
354 | } | |||
355 | ||||
356 | static int | |||
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_TCPSIGNATURE8, SADB_DELETE4, 0, | |||
361 | af, src, dst, *spi, 0, 0, NULL((void *)0), 0, 0, NULL((void *)0), 0, 0) < 0) | |||
362 | return (-1); | |||
363 | if (pfkey_reply(fd, NULL((void *)0)) < 0) | |||
364 | return (-1); | |||
365 | *spi = 0; | |||
366 | return (0); | |||
367 | } | |||
368 | ||||
369 | static int | |||
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 | |||
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 * | |||
411 | pfkey_find_auth(struct ldpd_conf *conf, struct nbr *nbr) | |||
412 | { | |||
413 | struct ldp_auth *auth, *match = NULL((void *)0); | |||
414 | ||||
415 | LIST_FOREACH(auth, &conf->auth_list, entry)for((auth) = ((&conf->auth_list)->lh_first); (auth) != ((void *)0); (auth) = ((auth)->entry.le_next)) { | |||
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((void *)0) || | |||
421 | match->idlen < auth->idlen) | |||
422 | match = auth; | |||
423 | } | |||
424 | ||||
425 | return (match); | |||
426 | } | |||
427 | ||||
428 | int | |||
429 | pfkey_establish(struct ldpd_conf *conf, struct nbr *nbr) | |||
430 | { | |||
431 | struct ldp_auth *auth = NULL((void *)0); | |||
432 | ||||
433 | auth = pfkey_find_auth(conf, nbr); | |||
434 | if (auth == NULL((void *)0) || /* 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 | |||
442 | pfkey_remove(struct nbr *nbr) | |||
443 | { | |||
444 | return (pfkey_md5sig_remove(nbr)); | |||
| ||||
445 | } | |||
446 | ||||
447 | int | |||
448 | pfkey_init(void) | |||
449 | { | |||
450 | if ((fd = socket(PF_KEY30, SOCK_RAW3 | SOCK_CLOEXEC0x8000 | SOCK_NONBLOCK0x4000, | |||
451 | PF_KEY_V22)) == -1) { | |||
452 | if (errno(*__errno()) == EPROTONOSUPPORT43) { | |||
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 | } |