1 /* BGP TCP signature related functions
2 Copyright (C) 2004 Hiroki Nakano; Thanks to Okabe lab. (Kyoto University)
4 This file is part of GNU Zebra.
6 GNU Zebra is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 GNU Zebra is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Zebra; see the file COPYING. If not, write to the Free
18 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
23 #ifdef HAVE_OPENBSD_TCP_SIGNATURE
24 #include <net/pfkeyv2.h>
25 #endif /* HAVE_OPENBSD_TCP_SIGNATURE */
29 #include "sockunion.h"
31 #include "bgpd/bgpd.h"
32 #include "bgpd/bgp_network.h"
33 #include "bgpd/bgp_tcpsig.h"
35 #ifdef HAVE_OPENBSD_TCP_SIGNATURE
38 #define MAX_KEY_LEN 80
40 #define SADBALIGN sizeof(u_int64_t)
41 #define LENUNIT(x) ((x) / SADBALIGN)
42 #define EXTLEN(x) (((struct sadb_ext *)(x))->sadb_ext_len * SADBALIGN)
43 #define PADUP(x) (((x) + (SADBALIGN - 1)) & ~(SADBALIGN - 1))
45 static u_int32_t bgp_pfkey_sadb_msg_seq
= 1;
46 static int bgp_pfkey_sd
= -1;
48 int bgp_pfkey_init(void);
50 #define PUSH_IOVEC(base,len) ((*iovsizep) > 0 ? \
51 ((*iovp)->iov_base = (base), \
52 (*iovp)->iov_len = (len), \
57 struct bgp_pfkey_sadb_msg
{
58 struct sadb_msg header
;
62 bgp_pfkey_build_sadb_msg(u_int8_t mtype
,
63 struct bgp_pfkey_sadb_msg
*sp
,
64 struct iovec
**iovp
, int *iovsizep
)
66 memset(sp
, 0, sizeof(*sp
));
68 sp
->header
.sadb_msg_version
= PF_KEY_V2
;
69 sp
->header
.sadb_msg_type
= mtype
;
70 sp
->header
.sadb_msg_satype
= SADB_X_SATYPE_TCPSIGNATURE
;
71 sp
->header
.sadb_msg_len
= LENUNIT(sizeof(sp
->header
));
72 sp
->header
.sadb_msg_seq
= bgp_pfkey_sadb_msg_seq
++;
73 sp
->header
.sadb_msg_pid
= getpid();
75 PUSH_IOVEC(&sp
->header
, sizeof(sp
->header
));
77 return sp
->header
.sadb_msg_len
;
80 struct bgp_pfkey_sadb_sa
{
81 struct sadb_sa header
;
85 bgp_pfkey_build_sadb_sa(u_int32_t spi
,
86 struct bgp_pfkey_sadb_sa
*sp
,
87 struct iovec
**iovp
, int *iovsizep
)
89 memset(sp
, 0, sizeof(*sp
));
91 sp
->header
.sadb_sa_len
= LENUNIT(sizeof(sp
->header
));
92 sp
->header
.sadb_sa_exttype
= SADB_EXT_SA
;
93 sp
->header
.sadb_sa_spi
= spi
;
94 sp
->header
.sadb_sa_replay
= 0;
95 sp
->header
.sadb_sa_state
= SADB_SASTATE_MATURE
;
96 sp
->header
.sadb_sa_auth
= 0;
97 sp
->header
.sadb_sa_encrypt
= 0;
99 PUSH_IOVEC(&sp
->header
, sizeof(sp
->header
));
101 return sp
->header
.sadb_sa_len
;
104 struct bgp_pfkey_sadb_address
{
105 struct sadb_address header
;
106 struct sockaddr_storage ss
;
110 bgp_pfkey_build_sadb_address(union sockunion
*su
,
111 struct bgp_pfkey_sadb_address
*sp
,
112 struct iovec
**iovp
, int *iovsizep
)
116 memset(sp
, 0, sizeof(*sp
));
118 switch (su
->sa
.sa_family
) {
120 ((struct sockaddr_in
*)&sp
->ss
)->sin_family
= AF_INET
;
121 ((struct sockaddr_in
*)&sp
->ss
)->sin_len
= sizeof(struct sockaddr_in
);
122 ((struct sockaddr_in
*)&sp
->ss
)->sin_addr
= su
->sin
.sin_addr
;
125 ((struct sockaddr_in6
*)&sp
->ss
)->sin6_family
= AF_INET6
;
126 ((struct sockaddr_in6
*)&sp
->ss
)->sin6_len
= sizeof(struct sockaddr_in6
);
127 ((struct sockaddr_in6
*)&sp
->ss
)->sin6_addr
= su
->sin6
.sin6_addr
;
132 paddedsslen
= PADUP(((struct sockaddr
*)&sp
->ss
)->sa_len
);
134 sp
->header
.sadb_address_len
= LENUNIT(sizeof(sp
->header
) + paddedsslen
);
135 sp
->header
.sadb_address_exttype
= SADB_EXT_ADDRESS_SRC
;
137 PUSH_IOVEC(&sp
->header
, sizeof(sp
->header
));
138 PUSH_IOVEC(&sp
->ss
, paddedsslen
);
140 return sp
->header
.sadb_address_len
;
143 struct bgp_pfkey_sadb_key
{
144 struct sadb_key header
;
145 char keybuf
[PADUP(MAX_KEY_LEN
)];
149 bgp_pfkey_build_sadb_key(char *key
, int keylen
,
150 struct bgp_pfkey_sadb_key
*sp
,
151 struct iovec
**iovp
, int *iovsizep
)
155 if (keylen
< 0 || keylen
> MAX_KEY_LEN
)
158 memset(sp
, 0, sizeof(*sp
));
160 memcpy(sp
->keybuf
, key
, keylen
);
161 paddedkeylen
= PADUP(keylen
);
163 sp
->header
.sadb_key_len
= LENUNIT(sizeof(sp
->header
) + paddedkeylen
);
164 sp
->header
.sadb_key_exttype
= SADB_EXT_KEY_AUTH
;
165 sp
->header
.sadb_key_bits
= 8 * keylen
;
167 PUSH_IOVEC(&sp
->header
, sizeof(sp
->header
));
168 PUSH_IOVEC(sp
->keybuf
, paddedkeylen
);
170 return sp
->header
.sadb_key_len
;
173 struct bgp_pfkey_sadb_spirange
{
174 struct sadb_spirange header
;
178 bgp_pfkey_build_sadb_spirange(struct bgp_pfkey_sadb_spirange
*sp
,
179 struct iovec
**iovp
, int *iovsizep
)
181 memset(sp
, 0, sizeof(*sp
));
183 sp
->header
.sadb_spirange_len
= LENUNIT(sizeof(sp
->header
));
184 sp
->header
.sadb_spirange_exttype
= SADB_EXT_SPIRANGE
;
185 sp
->header
.sadb_spirange_min
= 0x100;
186 sp
->header
.sadb_spirange_max
= 0xffffffff;
188 PUSH_IOVEC(&sp
->header
, sizeof(sp
->header
));
190 return sp
->header
.sadb_spirange_len
;
195 bgp_pfkey_write(int fd
, struct iovec
*iov
, int iovcnt
)
200 for (i
= 0; i
< iovcnt
; i
++)
201 len
+= iov
[i
].iov_len
;
203 rlen
= writev(fd
, iov
, iovcnt
);
206 zlog_err("pfkey writev: %s", strerror(errno
));
209 else if (rlen
!= len
)
211 zlog_err("pfkey writev: len=%d ret=%d", len
, rlen
);
219 bgp_pfkey_read(int fd
, void **bufp
, int *lenp
)
221 struct sadb_msg smsg
;
225 rlen
= recv(fd
, &smsg
, sizeof(smsg
), MSG_PEEK
);
228 zlog_err("pfkey recv: %s", strerror(errno
));
231 if (rlen
!= sizeof(smsg
))
233 zlog_err("pfkey recv: len=%d ret=%d", sizeof(smsg
), rlen
);
237 if (smsg
.sadb_msg_errno
!= 0 ||
238 smsg
.sadb_msg_errno
!= ESRCH
)
240 zlog_err("pfkey read msg: %s", strerror(smsg
.sadb_msg_errno
));
241 read(fd
, &smsg
, sizeof(smsg
)); /* get rid of error message */
245 msglen
= smsg
.sadb_msg_len
* SADBALIGN
;
246 msgbuf
= XMALLOC(MTYPE_TMP
, msglen
);
248 rlen
= read(fd
, msgbuf
, msglen
);
251 zlog_err("pfkey read: %s", strerror(errno
));
252 XFREE(MTYPE_TMP
, msgbuf
);
257 zlog_err("pfkey read: len=%d ret=%d", msglen
, rlen
);
258 XFREE(MTYPE_TMP
, msgbuf
);
269 bgp_pfkey_search_ext(void *buf
, u_int16_t exttype
, void **prevp
)
271 struct sadb_msg
*msg
;
272 struct sadb_ext
*p
, *last
;
276 len
= msg
->sadb_msg_len
* SADBALIGN
;
277 last
= (struct sadb_ext
*)(((u_int8_t
*)msg
) + len
);
279 p
= *prevp
? *prevp
: (struct sadb_ext
*)(msg
+ 1);
280 while ((u_int8_t
*)p
< (u_int8_t
*)last
)
282 if (p
->sadb_ext_type
== exttype
)
285 return 0; /* found */
288 p
= (struct sadb_ext
*)(((u_int8_t
*)p
) + EXTLEN(p
));
291 return -1; /* not found */
295 bgp_pfkey_getspi(union sockunion
*src
, union sockunion
*dst
, u_int32_t
*spip
)
297 struct iovec iovbuf
[IOVEC_SIZE
], *iov
;
299 struct bgp_pfkey_sadb_msg s_msg
;
300 struct bgp_pfkey_sadb_spirange s_spirange
;
301 struct bgp_pfkey_sadb_address s_srcaddr
, s_dstaddr
;
305 struct sadb_sa
*ext_sa
;
307 if (bgp_pfkey_sd
== -1)
310 if (bgp_pfkey_sd
== -1)
315 iovcnt
= iovrest
= sizeof(iov
) / sizeof(iov
[0]);
317 len
= bgp_pfkey_build_sadb_msg(SADB_GETSPI
, &s_msg
, &iov
, &iovrest
);
318 len
+= bgp_pfkey_build_sadb_spirange(&s_spirange
, &iov
, &iovrest
);
319 len
+= bgp_pfkey_build_sadb_address(dst
, &s_dstaddr
, &iov
, &iovrest
);
320 len
+= bgp_pfkey_build_sadb_address(src
, &s_srcaddr
, &iov
, &iovrest
);
322 s_msg
.header
.sadb_msg_len
= len
;
325 if (bgp_pfkey_write(bgp_pfkey_sd
, iov
, iovcnt
) != 0)
327 zlog_err("pfkey getspi: fail to write request");
331 if (bgp_pfkey_read(bgp_pfkey_sd
, &buf
, &buflen
) != 0)
333 zlog_err("pfkey getspi: fail to read reply");
337 if (bgp_pfkey_search_ext(buf
, SADB_EXT_SA
, (void **)&ext_sa
) != 0)
339 zlog_err("pfkey getspi: no SA extention");
340 XFREE(MTYPE_TMP
, buf
);
344 *spip
= ext_sa
->sadb_sa_spi
;
346 XFREE(MTYPE_TMP
, buf
);
351 bgp_pfkey_update(u_int32_t spi
, union sockunion
*src
, union sockunion
*dst
,
354 struct iovec iovbuf
[IOVEC_SIZE
], *iov
;
356 struct bgp_pfkey_sadb_msg s_msg
;
357 struct bgp_pfkey_sadb_sa s_sa
;
358 struct bgp_pfkey_sadb_address s_srcaddr
, s_dstaddr
;
359 struct bgp_pfkey_sadb_key s_key
;
364 if (bgp_pfkey_sd
== -1)
367 if (bgp_pfkey_sd
== -1)
372 iovcnt
= iovrest
= sizeof(iov
) / sizeof(iov
[0]);
374 len
= bgp_pfkey_build_sadb_msg(SADB_UPDATE
, &s_msg
, &iov
, &iovrest
);
375 len
+= bgp_pfkey_build_sadb_sa(spi
, &s_sa
, &iov
, &iovrest
);
376 len
+= bgp_pfkey_build_sadb_address(dst
, &s_dstaddr
, &iov
, &iovrest
);
377 len
+= bgp_pfkey_build_sadb_address(src
, &s_srcaddr
, &iov
, &iovrest
);
378 len
+= bgp_pfkey_build_sadb_key(key
, strlen(key
), &s_key
, &iov
, &iovrest
);
380 s_msg
.header
.sadb_msg_len
= len
;
383 if (bgp_pfkey_write(bgp_pfkey_sd
, iov
, iovcnt
) != 0)
385 zlog_err("pfkey update: fail to write request");
389 if (bgp_pfkey_read(bgp_pfkey_sd
, &buf
, &buflen
) != 0)
391 zlog_err("pfkey update: fail to read reply");
395 XFREE(MTYPE_TMP
, buf
);
401 bgp_pfkey_delete(u_int32_t spi
, union sockunion
*src
, union sockunion
*dst
)
403 struct iovec iovbuf
[IOVEC_SIZE
], *iov
;
405 struct bgp_pfkey_sadb_msg s_msg
;
406 struct bgp_pfkey_sadb_sa s_sa
;
407 struct bgp_pfkey_sadb_address s_srcaddr
, s_dstaddr
;
412 if (bgp_pfkey_sd
== -1)
415 if (bgp_pfkey_sd
== -1)
420 iovcnt
= iovrest
= sizeof(iov
) / sizeof(iov
[0]);
422 len
= bgp_pfkey_build_sadb_msg(SADB_DELETE
, &s_msg
, &iov
, &iovrest
);
423 len
+= bgp_pfkey_build_sadb_sa(spi
, &s_sa
, &iov
, &iovrest
);
424 len
+= bgp_pfkey_build_sadb_address(dst
, &s_dstaddr
, &iov
, &iovrest
);
425 len
+= bgp_pfkey_build_sadb_address(src
, &s_srcaddr
, &iov
, &iovrest
);
427 s_msg
.header
.sadb_msg_len
= len
;
430 if (bgp_pfkey_write(bgp_pfkey_sd
, iov
, iovcnt
) != 0)
432 zlog_err("pfkey delete: fail to write request");
436 if (bgp_pfkey_read(bgp_pfkey_sd
, &buf
, &buflen
) != 0)
438 zlog_err("pfkey delete: fail to read reply");
442 XFREE(MTYPE_TMP
, buf
);
450 bgp_pfkey_sd
= socket(PF_KEY
, SOCK_RAW
, PF_KEY_V2
);
451 if (bgp_pfkey_sd
== -1)
453 zlog_warn("pfkey socket: %s", strerror(errno
));
459 /*----------------------------------------------------------------*/
462 bgp_tcpsig_pfkey_set(struct peer
*p
)
464 if (!p
->update_source
)
468 if (bgp_pfkey_getspi(p
->update_source
, &p
->su
, &p
->spi_out
) != 0)
471 if (bgp_pfkey_update(p
->spi_out
,
472 p
->update_source
, &p
->su
, p
->password
) != 0)
476 if (bgp_pfkey_getspi(&p
->su
, p
->update_source
, &p
->spi_in
) != 0)
479 if (bgp_pfkey_update(p
->spi_in
,
480 &p
->su
, p
->update_source
, p
->password
) != 0)
487 bgp_tcpsig_pfkey_unset(struct peer
*p
)
489 if (!p
->update_source
)
493 if (bgp_pfkey_delete(p
->spi_out
, p
->update_source
, &p
->su
) != 0)
498 if (bgp_pfkey_delete(p
->spi_in
, &p
->su
, p
->update_source
) != 0)
505 #endif /* HAVE_OPENBSD_TCP_SIGNATURE */
507 /*----------------------------------------------------------------*/
508 #ifdef HAVE_LINUX_TCP_SIGNATURE
510 bgp_tcpsig_set (int sock
, struct peer
*peer
)
512 struct tcp_rfc2385_cmd cmd
;
515 if (sockunion_family (&peer
->su
) != AF_INET
)
518 cmd
.command
= TCP_MD5_AUTH_ADD
;
519 cmd
.address
= peer
->su
.sin
.sin_addr
.s_addr
;
520 cmd
.keylen
= strlen (peer
->password
);
521 cmd
.key
= peer
->password
;
523 ret
= setsockopt (sock
, IPPROTO_TCP
, TCP_MD5_AUTH
, &cmd
, sizeof cmd
);
527 #endif /* HAVE_LINUX_TCP_SIGNATURE */
529 #ifdef HAVE_OPENBSD_TCP_SIGNATURE
531 bgp_tcpsig_set (int sock
, struct peer
*peer
)
537 ret
= bgp_tcpsig_pfkey_set(peer
);
539 if (ret
== 0 && sock
!= -1)
540 ret
= setsockopt (sock
, IPPROTO_TCP
, TCP_MD5SIG
, &cmd
, sizeof cmd
);
544 #endif /* HAVE_OPENBSD_TCP_SIGNATURE */
546 #ifdef HAVE_LINUX_TCP_SIGNATURE
548 bgp_tcpsig_unset (int sock
, struct peer
*peer
)
550 struct tcp_rfc2385_cmd cmd
;
553 if (sockunion_family (&peer
->su
) != AF_INET
)
556 cmd
.command
= TCP_MD5_AUTH_DEL
;
557 cmd
.address
= peer
->su
.sin
.sin_addr
.s_addr
;
558 cmd
.keylen
= strlen (peer
->password
);
559 cmd
.key
= peer
->password
;
561 ret
= setsockopt (sock
, IPPROTO_TCP
, TCP_MD5_AUTH
, &cmd
, sizeof cmd
);
565 #endif /* HAVE_LINUX_TCP_SIGNATURE */
567 #ifdef HAVE_OPENBSD_TCP_SIGNATURE
569 bgp_tcpsig_unset (int sock
, struct peer
*peer
)
571 return bgp_tcpsig_pfkey_unset(peer
);
573 #endif /* HAVE_OPENBSD_TCP_SIGNATURE */