📄 bgp_tcpsig.c
字号:
/* BGP TCP signature related functions Copyright (C) 2004 Hiroki Nakano; Thanks to Okabe lab. (Kyoto University)This file is part of GNU Zebra.GNU Zebra is free software; you can redistribute it and/or modify itunder the terms of the GNU General Public License as published by theFree Software Foundation; either version 2, or (at your option) anylater version.GNU Zebra is distributed in the hope that it will be useful, butWITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNUGeneral Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU Zebra; see the file COPYING. If not, write to the FreeSoftware Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA02111-1307, USA. */#include <zebra.h>#ifdef HAVE_OPENBSD_TCP_SIGNATURE#include <net/pfkeyv2.h>#endif /* HAVE_OPENBSD_TCP_SIGNATURE */#include "log.h"#include "memory.h"#include "sockunion.h"#include "vty.h"#include "bgpd/bgpd.h"#include "bgpd/bgp_network.h"#include "bgpd/bgp_tcpsig.h"#ifdef HAVE_OPENBSD_TCP_SIGNATURE#define IOVEC_SIZE 20#define MAX_KEY_LEN 80#define SADBALIGN sizeof(u_int64_t)#define LENUNIT(x) ((x) / SADBALIGN)#define EXTLEN(x) (((struct sadb_ext *)(x))->sadb_ext_len * SADBALIGN)#define PADUP(x) (((x) + (SADBALIGN - 1)) & ~(SADBALIGN - 1))static u_int32_t bgp_pfkey_sadb_msg_seq = 1;static int bgp_pfkey_sd = -1;int bgp_pfkey_init(void);#define PUSH_IOVEC(base,len) ((*iovsizep) > 0 ? \ ((*iovp)->iov_base = (base), \ (*iovp)->iov_len = (len), \ (*iovp)++, \ (*iovsizep)--) : \ ((*iovsizep) = -1))struct bgp_pfkey_sadb_msg { struct sadb_msg header;};intbgp_pfkey_build_sadb_msg(u_int8_t mtype, struct bgp_pfkey_sadb_msg *sp, struct iovec **iovp, int *iovsizep){ memset(sp, 0, sizeof(*sp)); sp->header.sadb_msg_version = PF_KEY_V2; sp->header.sadb_msg_type = mtype; sp->header.sadb_msg_satype = SADB_X_SATYPE_TCPSIGNATURE; sp->header.sadb_msg_len = LENUNIT(sizeof(sp->header)); sp->header.sadb_msg_seq = bgp_pfkey_sadb_msg_seq++; sp->header.sadb_msg_pid = getpid(); PUSH_IOVEC(&sp->header, sizeof(sp->header)); return sp->header.sadb_msg_len;}struct bgp_pfkey_sadb_sa { struct sadb_sa header;};intbgp_pfkey_build_sadb_sa(u_int32_t spi, struct bgp_pfkey_sadb_sa *sp, struct iovec **iovp, int *iovsizep){ memset(sp, 0, sizeof(*sp)); sp->header.sadb_sa_len = LENUNIT(sizeof(sp->header)); sp->header.sadb_sa_exttype = SADB_EXT_SA; sp->header.sadb_sa_spi = spi; sp->header.sadb_sa_replay = 0; sp->header.sadb_sa_state = SADB_SASTATE_MATURE; sp->header.sadb_sa_auth = 0; sp->header.sadb_sa_encrypt = 0; PUSH_IOVEC(&sp->header, sizeof(sp->header)); return sp->header.sadb_sa_len;}struct bgp_pfkey_sadb_address { struct sadb_address header; struct sockaddr_storage ss;};intbgp_pfkey_build_sadb_address(union sockunion *su, struct bgp_pfkey_sadb_address *sp, struct iovec **iovp, int *iovsizep){ int paddedsslen; memset(sp, 0, sizeof(*sp)); switch (su->sa.sa_family) { case AF_INET: ((struct sockaddr_in *)&sp->ss)->sin_family = AF_INET; ((struct sockaddr_in *)&sp->ss)->sin_len = sizeof(struct sockaddr_in); ((struct sockaddr_in *)&sp->ss)->sin_addr = su->sin.sin_addr; break; case AF_INET6: ((struct sockaddr_in6 *)&sp->ss)->sin6_family = AF_INET6; ((struct sockaddr_in6 *)&sp->ss)->sin6_len = sizeof(struct sockaddr_in6); ((struct sockaddr_in6 *)&sp->ss)->sin6_addr = su->sin6.sin6_addr; break; default: return -1; } paddedsslen = PADUP(((struct sockaddr *)&sp->ss)->sa_len); sp->header.sadb_address_len = LENUNIT(sizeof(sp->header) + paddedsslen); sp->header.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; PUSH_IOVEC(&sp->header, sizeof(sp->header)); PUSH_IOVEC(&sp->ss, paddedsslen); return sp->header.sadb_address_len;}struct bgp_pfkey_sadb_key { struct sadb_key header; char keybuf[PADUP(MAX_KEY_LEN)];};intbgp_pfkey_build_sadb_key(char *key, int keylen, struct bgp_pfkey_sadb_key *sp, struct iovec **iovp, int *iovsizep){ int paddedkeylen; if (keylen < 0 || keylen > MAX_KEY_LEN) return -1; memset(sp, 0, sizeof(*sp)); memcpy(sp->keybuf, key, keylen); paddedkeylen = PADUP(keylen); sp->header.sadb_key_len = LENUNIT(sizeof(sp->header) + paddedkeylen); sp->header.sadb_key_exttype = SADB_EXT_KEY_AUTH; sp->header.sadb_key_bits = 8 * keylen; PUSH_IOVEC(&sp->header, sizeof(sp->header)); PUSH_IOVEC(sp->keybuf, paddedkeylen); return sp->header.sadb_key_len;}struct bgp_pfkey_sadb_spirange { struct sadb_spirange header;};intbgp_pfkey_build_sadb_spirange(struct bgp_pfkey_sadb_spirange *sp, struct iovec **iovp, int *iovsizep){ memset(sp, 0, sizeof(*sp)); sp->header.sadb_spirange_len = LENUNIT(sizeof(sp->header)); sp->header.sadb_spirange_exttype = SADB_EXT_SPIRANGE; sp->header.sadb_spirange_min = 0x100; sp->header.sadb_spirange_max = 0xffffffff; PUSH_IOVEC(&sp->header, sizeof(sp->header)); return sp->header.sadb_spirange_len;}intbgp_pfkey_write(int fd, struct iovec *iov, int iovcnt){ int i, len, rlen; len = 0; for (i = 0; i < iovcnt; i++) len += iov[i].iov_len; rlen = writev(fd, iov, iovcnt); if (rlen == -1) { zlog_err("pfkey writev: %s", strerror(errno)); return -1; } else if (rlen != len) { zlog_err("pfkey writev: len=%d ret=%d", len, rlen); return -1; } return 0;}intbgp_pfkey_read(int fd, void **bufp, int *lenp){ struct sadb_msg smsg; void *msgbuf; int msglen, rlen; rlen = recv(fd, &smsg, sizeof(smsg), MSG_PEEK); if (rlen == -1) { zlog_err("pfkey recv: %s", strerror(errno)); return -1; } if (rlen != sizeof(smsg)) { zlog_err("pfkey recv: len=%d ret=%d", sizeof(smsg), rlen); return -1; } if (smsg.sadb_msg_errno != 0 || smsg.sadb_msg_errno != ESRCH) { zlog_err("pfkey read msg: %s", strerror(smsg.sadb_msg_errno)); read(fd, &smsg, sizeof(smsg)); /* get rid of error message */ return -1; } msglen = smsg.sadb_msg_len * SADBALIGN; msgbuf = XMALLOC(MTYPE_TMP, msglen); rlen = read(fd, msgbuf, msglen); if (rlen == -1) { zlog_err("pfkey read: %s", strerror(errno)); XFREE(MTYPE_TMP, msgbuf); return -1; } if (rlen != msglen) { zlog_err("pfkey read: len=%d ret=%d", msglen, rlen); XFREE(MTYPE_TMP, msgbuf); return -1; } *bufp = msgbuf; *lenp = msglen; return 0;}intbgp_pfkey_search_ext(void *buf, u_int16_t exttype, void **prevp){ struct sadb_msg *msg; struct sadb_ext *p, *last; u_int32_t len; msg = buf; len = msg->sadb_msg_len * SADBALIGN; last = (struct sadb_ext *)(((u_int8_t *)msg) + len); p = *prevp ? *prevp : (struct sadb_ext *)(msg + 1); while ((u_int8_t *)p < (u_int8_t *)last) { if (p->sadb_ext_type == exttype) { *prevp = p; return 0; /* found */ } p = (struct sadb_ext *)(((u_int8_t *)p) + EXTLEN(p)); } return -1; /* not found */}intbgp_pfkey_getspi(union sockunion *src, union sockunion *dst, u_int32_t *spip){ struct iovec iovbuf[IOVEC_SIZE], *iov; int iovcnt, iovrest; struct bgp_pfkey_sadb_msg s_msg; struct bgp_pfkey_sadb_spirange s_spirange; struct bgp_pfkey_sadb_address s_srcaddr, s_dstaddr; int len; void *buf; int buflen; struct sadb_sa *ext_sa; if (bgp_pfkey_sd == -1) { bgp_pfkey_init(); if (bgp_pfkey_sd == -1) return -1; } iov = iovbuf; iovcnt = iovrest = sizeof(iov) / sizeof(iov[0]); len = bgp_pfkey_build_sadb_msg(SADB_GETSPI, &s_msg, &iov, &iovrest); len += bgp_pfkey_build_sadb_spirange(&s_spirange, &iov, &iovrest); len += bgp_pfkey_build_sadb_address(dst, &s_dstaddr, &iov, &iovrest); len += bgp_pfkey_build_sadb_address(src, &s_srcaddr, &iov, &iovrest); s_msg.header.sadb_msg_len = len; iovcnt -= iovrest; if (bgp_pfkey_write(bgp_pfkey_sd, iov, iovcnt) != 0) { zlog_err("pfkey getspi: fail to write request"); return -1; } if (bgp_pfkey_read(bgp_pfkey_sd, &buf, &buflen) != 0) { zlog_err("pfkey getspi: fail to read reply"); return -1; } if (bgp_pfkey_search_ext(buf, SADB_EXT_SA, (void **)&ext_sa) != 0) { zlog_err("pfkey getspi: no SA extention"); XFREE(MTYPE_TMP, buf); return -1; } *spip = ext_sa->sadb_sa_spi; XFREE(MTYPE_TMP, buf); return 0;}intbgp_pfkey_update(u_int32_t spi, union sockunion *src, union sockunion *dst, char *key){ struct iovec iovbuf[IOVEC_SIZE], *iov; int iovcnt, iovrest; struct bgp_pfkey_sadb_msg s_msg; struct bgp_pfkey_sadb_sa s_sa; struct bgp_pfkey_sadb_address s_srcaddr, s_dstaddr; struct bgp_pfkey_sadb_key s_key; int len; void *buf; int buflen; if (bgp_pfkey_sd == -1) { bgp_pfkey_init(); if (bgp_pfkey_sd == -1) return -1; } iov = iovbuf; iovcnt = iovrest = sizeof(iov) / sizeof(iov[0]); len = bgp_pfkey_build_sadb_msg(SADB_UPDATE, &s_msg, &iov, &iovrest); len += bgp_pfkey_build_sadb_sa(spi, &s_sa, &iov, &iovrest); len += bgp_pfkey_build_sadb_address(dst, &s_dstaddr, &iov, &iovrest); len += bgp_pfkey_build_sadb_address(src, &s_srcaddr, &iov, &iovrest); len += bgp_pfkey_build_sadb_key(key, strlen(key), &s_key, &iov, &iovrest); s_msg.header.sadb_msg_len = len; iovcnt -= iovrest; if (bgp_pfkey_write(bgp_pfkey_sd, iov, iovcnt) != 0) { zlog_err("pfkey update: fail to write request"); return -1; } if (bgp_pfkey_read(bgp_pfkey_sd, &buf, &buflen) != 0) { zlog_err("pfkey update: fail to read reply"); return -1; } XFREE(MTYPE_TMP, buf); return 0;}intbgp_pfkey_delete(u_int32_t spi, union sockunion *src, union sockunion *dst){ struct iovec iovbuf[IOVEC_SIZE], *iov; int iovcnt, iovrest; struct bgp_pfkey_sadb_msg s_msg; struct bgp_pfkey_sadb_sa s_sa; struct bgp_pfkey_sadb_address s_srcaddr, s_dstaddr; int len; void *buf; int buflen; if (bgp_pfkey_sd == -1) { bgp_pfkey_init(); if (bgp_pfkey_sd == -1) return -1; } iov = iovbuf; iovcnt = iovrest = sizeof(iov) / sizeof(iov[0]); len = bgp_pfkey_build_sadb_msg(SADB_DELETE, &s_msg, &iov, &iovrest); len += bgp_pfkey_build_sadb_sa(spi, &s_sa, &iov, &iovrest); len += bgp_pfkey_build_sadb_address(dst, &s_dstaddr, &iov, &iovrest); len += bgp_pfkey_build_sadb_address(src, &s_srcaddr, &iov, &iovrest); s_msg.header.sadb_msg_len = len; iovcnt -= iovrest; if (bgp_pfkey_write(bgp_pfkey_sd, iov, iovcnt) != 0) { zlog_err("pfkey delete: fail to write request"); return -1; } if (bgp_pfkey_read(bgp_pfkey_sd, &buf, &buflen) != 0) { zlog_err("pfkey delete: fail to read reply"); return -1; } XFREE(MTYPE_TMP, buf); return 0;}intbgp_pfkey_init(void){ bgp_pfkey_sd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2); if (bgp_pfkey_sd == -1) { zlog_warn("pfkey socket: %s", strerror(errno)); return -1; } return 0;}/*----------------------------------------------------------------*/intbgp_tcpsig_pfkey_set(struct peer *p){ if (!p->update_source) return -1; if (p->spi_out == 0) if (bgp_pfkey_getspi(p->update_source, &p->su, &p->spi_out) != 0) return -1; if (bgp_pfkey_update(p->spi_out, p->update_source, &p->su, p->password) != 0) return -1; if (p->spi_in == 0) if (bgp_pfkey_getspi(&p->su, p->update_source, &p->spi_in) != 0) return -1; if (bgp_pfkey_update(p->spi_in, &p->su, p->update_source, p->password) != 0) return -1; return 0;}intbgp_tcpsig_pfkey_unset(struct peer *p){ if (!p->update_source) return -1; if (p->spi_out != 0) if (bgp_pfkey_delete(p->spi_out, p->update_source, &p->su) != 0) return -1; p->spi_out = 0; if (p->spi_in != 0) if (bgp_pfkey_delete(p->spi_in, &p->su, p->update_source) != 0) return -1; p->spi_in = 0; return 0;}#endif /* HAVE_OPENBSD_TCP_SIGNATURE *//*----------------------------------------------------------------*/#ifdef HAVE_LINUX_TCP_SIGNATUREintbgp_tcpsig_set (int sock, struct peer *peer){ struct tcp_rfc2385_cmd cmd; int ret; if (sockunion_family (&peer->su) != AF_INET) return 0; /* XXX */ cmd.command = TCP_MD5_AUTH_ADD; cmd.address = peer->su.sin.sin_addr.s_addr; cmd.keylen = strlen (peer->password); cmd.key = peer->password; ret = setsockopt (sock, IPPROTO_TCP, TCP_MD5_AUTH, &cmd, sizeof cmd); return ret;}#endif /* HAVE_LINUX_TCP_SIGNATURE */#ifdef HAVE_OPENBSD_TCP_SIGNATUREintbgp_tcpsig_set (int sock, struct peer *peer){ int cmd = 1; int ret = 0; if (peer) ret = bgp_tcpsig_pfkey_set(peer); if (ret == 0 && sock != -1) ret = setsockopt (sock, IPPROTO_TCP, TCP_MD5SIG, &cmd, sizeof cmd); return ret;}#endif /* HAVE_OPENBSD_TCP_SIGNATURE */#ifdef HAVE_LINUX_TCP_SIGNATUREintbgp_tcpsig_unset (int sock, struct peer *peer){ struct tcp_rfc2385_cmd cmd; int ret; if (sockunion_family (&peer->su) != AF_INET) return 0; /* XXX */ cmd.command = TCP_MD5_AUTH_DEL; cmd.address = peer->su.sin.sin_addr.s_addr; cmd.keylen = strlen (peer->password); cmd.key = peer->password; ret = setsockopt (sock, IPPROTO_TCP, TCP_MD5_AUTH, &cmd, sizeof cmd); return ret;}#endif /* HAVE_LINUX_TCP_SIGNATURE */#ifdef HAVE_OPENBSD_TCP_SIGNATUREintbgp_tcpsig_unset (int sock, struct peer *peer){ return bgp_tcpsig_pfkey_unset(peer);}#endif /* HAVE_OPENBSD_TCP_SIGNATURE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -