1 // SPDX-License-Identifier: ISC
5 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
6 * Copyright (c) 2003, 2004 Markus Friedl <markus@openbsd.org>
14 #include <sys/types.h>
15 #include <sys/socket.h>
25 static 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 *,
29 static int pfkey_reply(int, uint32_t *);
30 static int pfkey_sa_add(int, union ldpd_addr
*, union ldpd_addr
*,
31 uint8_t, char *, uint32_t *);
32 static int pfkey_sa_remove(int, union ldpd_addr
*, union ldpd_addr
*,
34 static int pfkey_md5sig_establish(struct nbr
*, struct nbr_params
*nbrp
);
35 static int pfkey_md5sig_remove(struct nbr
*);
37 #define PFKEY2_CHUNK sizeof(uint64_t)
38 #define ROUNDUP(x) (((x) + (PFKEY2_CHUNK - 1)) & ~(PFKEY2_CHUNK - 1))
41 static uint32_t sadb_msg_seq
;
42 static uint32_t pid
; /* should pid_t but pfkey needs uint32_t */
46 pfkey_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
)
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
];
60 struct sockaddr_storage smask
, dmask
;
61 union sockunion su_src
, su_dst
;
66 /* we need clean sockaddr... no ports set */
67 memset(&smask
, 0, sizeof(smask
));
69 addr2sa(af
, src
, 0, &su_src
);
73 memset(&((struct sockaddr_in
*)&smask
)->sin_addr
, 0xff, 32/8);
76 memset(&((struct sockaddr_in6
*)&smask
)->sin6_addr
, 0xff,
82 smask
.ss_family
= su_src
.sa
.sa_family
;
83 smask
.ss_len
= sockaddr_len(&su_src
.sa
);
85 memset(&dmask
, 0, sizeof(dmask
));
87 addr2sa(af
, dst
, 0, &su_dst
);
91 memset(&((struct sockaddr_in
*)&dmask
)->sin_addr
, 0xff, 32/8);
94 memset(&((struct sockaddr_in6
*)&dmask
)->sin6_addr
, 0xff,
100 dmask
.ss_family
= su_dst
.sa
.sa_family
;
101 dmask
.ss_len
= sockaddr_len(&su_dst
.sa
);
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
;
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;
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;
127 sa
.sadb_sa_spi
= htonl(spi
);
128 sa
.sadb_sa_state
= SADB_SASTATE_MATURE
;
132 memset(&sa_src
, 0, sizeof(sa_src
));
133 sa_src
.sadb_address_exttype
= SADB_EXT_ADDRESS_SRC
;
134 sa_src
.sadb_address_len
=
135 (sizeof(sa_src
) + ROUNDUP(sockaddr_len(&su_src
.sa
))) / 8;
137 memset(&sa_dst
, 0, sizeof(sa_dst
));
138 sa_dst
.sadb_address_exttype
= SADB_EXT_ADDRESS_DST
;
139 sa_dst
.sadb_address_len
=
140 (sizeof(sa_dst
) + ROUNDUP(sockaddr_len(&su_dst
.sa
))) / 8;
142 sa
.sadb_sa_auth
= aalg
;
143 sa
.sadb_sa_encrypt
= SADB_X_EALG_AES
; /* XXX */
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
;
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
;
166 iov
[iov_cnt
].iov_base
= &smsg
;
167 iov
[iov_cnt
].iov_len
= sizeof(smsg
);
175 iov
[iov_cnt
].iov_base
= &sa
;
176 iov
[iov_cnt
].iov_len
= sizeof(sa
);
177 smsg
.sadb_msg_len
+= sa
.sadb_sa_len
;
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
;
190 iov
[iov_cnt
].iov_base
= &sa_dst
;
191 iov
[iov_cnt
].iov_len
= sizeof(sa_dst
);
193 iov
[iov_cnt
].iov_base
= &su_dst
;
194 iov
[iov_cnt
].iov_len
= ROUNDUP(sockaddr_len(&su_dst
.sa
));
195 smsg
.sadb_msg_len
+= sa_dst
.sadb_address_len
;
199 iov
[iov_cnt
].iov_base
= &sa_src
;
200 iov
[iov_cnt
].iov_len
= sizeof(sa_src
);
202 iov
[iov_cnt
].iov_base
= &su_src
;
203 iov
[iov_cnt
].iov_len
= ROUNDUP(sockaddr_len(&su_src
.sa
));
204 smsg
.sadb_msg_len
+= sa_src
.sadb_address_len
;
212 iov
[iov_cnt
].iov_base
= &sa_akey
;
213 iov
[iov_cnt
].iov_len
= sizeof(sa_akey
);
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
;
222 iov
[iov_cnt
].iov_base
= &sa_ekey
;
223 iov
[iov_cnt
].iov_len
= sizeof(sa_ekey
);
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
;
233 len
= smsg
.sadb_msg_len
* 8;
235 n
= writev(sd
, iov
, iov_cnt
);
236 } while (n
== -1 && (errno
== EAGAIN
|| errno
== EINTR
));
239 log_warn("writev (%d/%d)", iov_cnt
, len
);
247 pfkey_read(int sd
, struct sadb_msg
*h
)
251 if (recv(sd
, &hdr
, sizeof(hdr
), MSG_PEEK
) != sizeof(hdr
)) {
252 if (errno
== EAGAIN
|| errno
== EINTR
)
254 log_warn("pfkey peek");
258 /* XXX: Only one message can be outstanding. */
259 if (hdr
.sadb_msg_seq
== sadb_msg_seq
&&
260 hdr
.sadb_msg_pid
== pid
) {
266 /* not ours, discard */
267 if (read(sd
, &hdr
, sizeof(hdr
)) == -1) {
268 if (errno
== EAGAIN
|| errno
== EINTR
)
270 log_warn("pfkey read");
278 pfkey_reply(int sd
, uint32_t *spi
)
280 struct sadb_msg hdr
, *msg
;
281 struct sadb_ext
*ext
;
288 rv
= pfkey_read(sd
, &hdr
);
293 if (hdr
.sadb_msg_errno
!= 0) {
294 errno
= hdr
.sadb_msg_errno
;
302 if ((data
= reallocarray(NULL
, hdr
.sadb_msg_len
, PFKEY2_CHUNK
)) == NULL
) {
303 log_warn("pfkey malloc");
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
);
314 if (hdr
.sadb_msg_type
== SADB_GETSPI
) {
316 explicit_bzero(data
, len
);
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
;
329 *spi
= ntohl(sa
->sadb_sa_spi
);
334 explicit_bzero(data
, len
);
340 pfkey_sa_add(int af
, union ldpd_addr
*src
, union ldpd_addr
*dst
, uint8_t keylen
,
341 char *key
, uint32_t *spi
)
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)
346 if (pfkey_reply(fd
, spi
) < 0)
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)
351 if (pfkey_reply(fd
, NULL
) < 0)
357 pfkey_sa_remove(int af
, union ldpd_addr
*src
, union ldpd_addr
*dst
,
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)
363 if (pfkey_reply(fd
, NULL
) < 0)
370 pfkey_md5sig_establish(struct nbr
*nbr
, struct nbr_params
*nbrp
)
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)
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)
385 nbr
->auth
.established
= 1;
390 pfkey_md5sig_remove(struct nbr
*nbr
)
392 if (nbr
->auth
.spi_out
)
393 if (pfkey_sa_remove(nbr
->af
, &nbr
->laddr
, &nbr
->raddr
,
394 &nbr
->auth
.spi_out
) == -1)
396 if (nbr
->auth
.spi_in
)
397 if (pfkey_sa_remove(nbr
->af
, &nbr
->raddr
, &nbr
->laddr
,
398 &nbr
->auth
.spi_in
) == -1)
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
));
411 pfkey_establish(struct nbr
*nbr
, struct nbr_params
*nbrp
)
413 switch (nbr
->auth
.method
) {
415 strlcpy(nbr
->auth
.md5key
, nbrp
->auth
.md5key
,
416 sizeof(nbr
->auth
.md5key
));
417 return pfkey_md5sig_establish(nbr
, nbrp
);
422 assert(!"Reached end of function where we are not expecting to");
426 pfkey_remove(struct nbr
*nbr
)
428 if (!nbr
->auth
.established
)
431 switch (nbr
->auth
.method
) {
433 return pfkey_md5sig_remove(nbr
);
439 assert(!"Reached end of function where we are not expecting to");
445 if ((fd
= socket(PF_KEY
, SOCK_RAW
| SOCK_CLOEXEC
| SOCK_NONBLOCK
,
447 if (errno
== EPROTONOSUPPORT
) {
448 log_warnx("PF_KEY not available");
452 fatal("pfkey setup failed");
456 #endif /* __OpenBSD__ */