usbmodeswitch: Updated to v.1.2.6 from shibby's branch.
[tomato.git] / release / src / router / zebra / bgpd / bgp_tcpsig.c
blobffd9999e412145688f957a1f2156c47c3f10c880
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
9 later version.
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
19 02111-1307, USA. */
21 #include <zebra.h>
23 #ifdef HAVE_OPENBSD_TCP_SIGNATURE
24 #include <net/pfkeyv2.h>
25 #endif /* HAVE_OPENBSD_TCP_SIGNATURE */
27 #include "log.h"
28 #include "memory.h"
29 #include "sockunion.h"
30 #include "vty.h"
31 #include "bgpd/bgpd.h"
32 #include "bgpd/bgp_network.h"
33 #include "bgpd/bgp_tcpsig.h"
35 #ifdef HAVE_OPENBSD_TCP_SIGNATURE
37 #define IOVEC_SIZE 20
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), \
53 (*iovp)++, \
54 (*iovsizep)--) : \
55 ((*iovsizep) = -1))
57 struct bgp_pfkey_sadb_msg {
58 struct sadb_msg header;
61 int
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;
84 int
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)
114 int paddedsslen;
116 memset(sp, 0, sizeof(*sp));
118 switch (su->sa.sa_family) {
119 case AF_INET:
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;
123 break;
124 case AF_INET6:
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;
128 break;
129 default:
130 return -1;
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)
153 int paddedkeylen;
155 if (keylen < 0 || keylen > MAX_KEY_LEN)
156 return -1;
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)
197 int i, len, rlen;
199 len = 0;
200 for (i = 0; i < iovcnt; i++)
201 len += iov[i].iov_len;
203 rlen = writev(fd, iov, iovcnt);
204 if (rlen == -1)
206 zlog_err("pfkey writev: %s", strerror(errno));
207 return -1;
209 else if (rlen != len)
211 zlog_err("pfkey writev: len=%d ret=%d", len, rlen);
212 return -1;
215 return 0;
219 bgp_pfkey_read(int fd, void **bufp, int *lenp)
221 struct sadb_msg smsg;
222 void *msgbuf;
223 int msglen, rlen;
225 rlen = recv(fd, &smsg, sizeof(smsg), MSG_PEEK);
226 if (rlen == -1)
228 zlog_err("pfkey recv: %s", strerror(errno));
229 return -1;
231 if (rlen != sizeof(smsg))
233 zlog_err("pfkey recv: len=%d ret=%d", sizeof(smsg), rlen);
234 return -1;
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 */
242 return -1;
245 msglen = smsg.sadb_msg_len * SADBALIGN;
246 msgbuf = XMALLOC(MTYPE_TMP, msglen);
248 rlen = read(fd, msgbuf, msglen);
249 if (rlen == -1)
251 zlog_err("pfkey read: %s", strerror(errno));
252 XFREE(MTYPE_TMP, msgbuf);
253 return -1;
255 if (rlen != msglen)
257 zlog_err("pfkey read: len=%d ret=%d", msglen, rlen);
258 XFREE(MTYPE_TMP, msgbuf);
259 return -1;
262 *bufp = msgbuf;
263 *lenp = msglen;
265 return 0;
269 bgp_pfkey_search_ext(void *buf, u_int16_t exttype, void **prevp)
271 struct sadb_msg *msg;
272 struct sadb_ext *p, *last;
273 u_int32_t len;
275 msg = buf;
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)
284 *prevp = p;
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;
298 int iovcnt, iovrest;
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;
302 int len;
303 void *buf;
304 int buflen;
305 struct sadb_sa *ext_sa;
307 if (bgp_pfkey_sd == -1)
309 bgp_pfkey_init();
310 if (bgp_pfkey_sd == -1)
311 return -1;
314 iov = iovbuf;
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;
323 iovcnt -= iovrest;
325 if (bgp_pfkey_write(bgp_pfkey_sd, iov, iovcnt) != 0)
327 zlog_err("pfkey getspi: fail to write request");
328 return -1;
331 if (bgp_pfkey_read(bgp_pfkey_sd, &buf, &buflen) != 0)
333 zlog_err("pfkey getspi: fail to read reply");
334 return -1;
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);
341 return -1;
344 *spip = ext_sa->sadb_sa_spi;
346 XFREE(MTYPE_TMP, buf);
347 return 0;
351 bgp_pfkey_update(u_int32_t spi, union sockunion *src, union sockunion *dst,
352 char *key)
354 struct iovec iovbuf[IOVEC_SIZE], *iov;
355 int iovcnt, iovrest;
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;
360 int len;
361 void *buf;
362 int buflen;
364 if (bgp_pfkey_sd == -1)
366 bgp_pfkey_init();
367 if (bgp_pfkey_sd == -1)
368 return -1;
371 iov = iovbuf;
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;
381 iovcnt -= iovrest;
383 if (bgp_pfkey_write(bgp_pfkey_sd, iov, iovcnt) != 0)
385 zlog_err("pfkey update: fail to write request");
386 return -1;
389 if (bgp_pfkey_read(bgp_pfkey_sd, &buf, &buflen) != 0)
391 zlog_err("pfkey update: fail to read reply");
392 return -1;
395 XFREE(MTYPE_TMP, buf);
397 return 0;
401 bgp_pfkey_delete(u_int32_t spi, union sockunion *src, union sockunion *dst)
403 struct iovec iovbuf[IOVEC_SIZE], *iov;
404 int iovcnt, iovrest;
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;
408 int len;
409 void *buf;
410 int buflen;
412 if (bgp_pfkey_sd == -1)
414 bgp_pfkey_init();
415 if (bgp_pfkey_sd == -1)
416 return -1;
419 iov = iovbuf;
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;
428 iovcnt -= iovrest;
430 if (bgp_pfkey_write(bgp_pfkey_sd, iov, iovcnt) != 0)
432 zlog_err("pfkey delete: fail to write request");
433 return -1;
436 if (bgp_pfkey_read(bgp_pfkey_sd, &buf, &buflen) != 0)
438 zlog_err("pfkey delete: fail to read reply");
439 return -1;
442 XFREE(MTYPE_TMP, buf);
444 return 0;
448 bgp_pfkey_init(void)
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));
454 return -1;
456 return 0;
459 /*----------------------------------------------------------------*/
462 bgp_tcpsig_pfkey_set(struct peer *p)
464 if (!p->update_source)
465 return -1;
467 if (p->spi_out == 0)
468 if (bgp_pfkey_getspi(p->update_source, &p->su, &p->spi_out) != 0)
469 return -1;
471 if (bgp_pfkey_update(p->spi_out,
472 p->update_source, &p->su, p->password) != 0)
473 return -1;
475 if (p->spi_in == 0)
476 if (bgp_pfkey_getspi(&p->su, p->update_source, &p->spi_in) != 0)
477 return -1;
479 if (bgp_pfkey_update(p->spi_in,
480 &p->su, p->update_source, p->password) != 0)
481 return -1;
483 return 0;
487 bgp_tcpsig_pfkey_unset(struct peer *p)
489 if (!p->update_source)
490 return -1;
492 if (p->spi_out != 0)
493 if (bgp_pfkey_delete(p->spi_out, p->update_source, &p->su) != 0)
494 return -1;
495 p->spi_out = 0;
497 if (p->spi_in != 0)
498 if (bgp_pfkey_delete(p->spi_in, &p->su, p->update_source) != 0)
499 return -1;
500 p->spi_in = 0;
502 return 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;
513 int ret;
515 if (sockunion_family (&peer->su) != AF_INET)
516 return 0; /* XXX */
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);
525 return ret;
527 #endif /* HAVE_LINUX_TCP_SIGNATURE */
529 #ifdef HAVE_OPENBSD_TCP_SIGNATURE
531 bgp_tcpsig_set (int sock, struct peer *peer)
533 int cmd = 1;
534 int ret = 0;
536 if (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);
542 return ret;
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;
551 int ret;
553 if (sockunion_family (&peer->su) != AF_INET)
554 return 0; /* XXX */
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);
563 return ret;
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 */