BGP: Support for MD5SIG together with remote range

When dynamic BGP with remote range is configured, MD5SIG needs to use
newer socket option (TCP_MD5SIG_EXT) to specify remote addres range for
listening socket.

Thanks to Adam Kułagowski for the suggestion.
This commit is contained in:
Ondrej Zajicek (work) 2020-02-27 16:16:48 +01:00
parent 22c3cf955d
commit 757cab18d6
6 changed files with 62 additions and 44 deletions

View file

@ -106,7 +106,7 @@ int sk_leave_group(sock *s, ip_addr maddr); /* Leave multicast group on sk iface
int sk_setup_broadcast(sock *s); int sk_setup_broadcast(sock *s);
int sk_set_ttl(sock *s, int ttl); /* Set transmit TTL for given socket */ int sk_set_ttl(sock *s, int ttl); /* Set transmit TTL for given socket */
int sk_set_min_ttl(sock *s, int ttl); /* Set minimal accepted TTL for given socket */ int sk_set_min_ttl(sock *s, int ttl); /* Set minimal accepted TTL for given socket */
int sk_set_md5_auth(sock *s, ip_addr local, ip_addr remote, struct iface *ifa, char *passwd, int setkey); int sk_set_md5_auth(sock *s, ip_addr local, ip_addr remote, int pxlen, struct iface *ifa, char *passwd, int setkey);
int sk_set_ipv6_checksum(sock *s, int offset); int sk_set_ipv6_checksum(sock *s, int offset);
int sk_set_icmp6_filter(sock *s, int p1, int p2); int sk_set_icmp6_filter(sock *s, int p1, int p2);
void sk_log_error(sock *s, const char *p); void sk_log_error(sock *s, const char *p);

View file

@ -247,8 +247,17 @@ bgp_setup_auth(struct bgp_proto *p, int enable)
{ {
if (p->cf->password) if (p->cf->password)
{ {
ip_addr prefix = p->cf->remote_ip;
int pxlen = -1;
if (p->cf->remote_range)
{
prefix = net_prefix(p->cf->remote_range);
pxlen = net_pxlen(p->cf->remote_range);
}
int rv = sk_set_md5_auth(p->sock->sk, int rv = sk_set_md5_auth(p->sock->sk,
p->cf->local_ip, p->cf->remote_ip, p->cf->iface, p->cf->local_ip, prefix, pxlen, p->cf->iface,
enable ? p->cf->password : NULL, p->cf->setkey); enable ? p->cf->password : NULL, p->cf->setkey);
if (rv < 0) if (rv < 0)

View file

@ -63,7 +63,7 @@ setkey_send(struct sadb_msg *msg, uint len)
* operations to implement replace. * operations to implement replace.
*/ */
static int static int
setkey_md5(sockaddr *src, sockaddr *dst, uint pxlen, char *passwd, uint type) setkey_md5(sockaddr *src, uint slen, sockaddr *dst, uint dlen, char *passwd, uint type)
{ {
uint passwd_len = passwd ? strlen(passwd) : 0; uint passwd_len = passwd ? strlen(passwd) : 0;
@ -122,7 +122,7 @@ setkey_md5(sockaddr *src, sockaddr *dst, uint pxlen, char *passwd, uint type)
saddr->sadb_address_len = PFKEY_UNIT64(len); saddr->sadb_address_len = PFKEY_UNIT64(len);
saddr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; saddr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
saddr->sadb_address_proto = IPSEC_ULPROTO_ANY; saddr->sadb_address_proto = IPSEC_ULPROTO_ANY;
saddr->sadb_address_prefixlen = pxlen; saddr->sadb_address_prefixlen = slen;
memcpy(pos + sizeof(struct sadb_address), &src->sa, src->sa.sa_len); memcpy(pos + sizeof(struct sadb_address), &src->sa, src->sa.sa_len);
pos += len; pos += len;
@ -132,7 +132,7 @@ setkey_md5(sockaddr *src, sockaddr *dst, uint pxlen, char *passwd, uint type)
daddr->sadb_address_len = PFKEY_UNIT64(len); daddr->sadb_address_len = PFKEY_UNIT64(len);
daddr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; daddr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
daddr->sadb_address_proto = IPSEC_ULPROTO_ANY; daddr->sadb_address_proto = IPSEC_ULPROTO_ANY;
daddr->sadb_address_prefixlen = pxlen; daddr->sadb_address_prefixlen = dlen;
memcpy(pos + sizeof(struct sadb_address), &dst->sa, dst->sa.sa_len); memcpy(pos + sizeof(struct sadb_address), &dst->sa, dst->sa.sa_len);
pos += len; pos += len;
@ -146,13 +146,15 @@ setkey_md5(sockaddr *src, sockaddr *dst, uint pxlen, char *passwd, uint type)
* Manipulation with the IPsec SA/SP database * Manipulation with the IPsec SA/SP database
*/ */
static int static int
sk_set_md5_in_sasp_db(sock *s, ip_addr local, ip_addr remote, struct iface *ifa, char *passwd) sk_set_md5_in_sasp_db(sock *s, ip_addr local, ip_addr remote, int pxlen, struct iface *ifa, char *passwd)
{ {
sockaddr src, dst; sockaddr src, dst;
sockaddr_fill(&src, s->af, local, ifa, 0); sockaddr_fill(&src, s->af, local, ifa, 0);
sockaddr_fill(&dst, s->af, remote, ifa, 0); sockaddr_fill(&dst, s->af, remote, ifa, 0);
uint pxlen = (s->af == AF_INET) ? IP4_MAX_PREFIX_LENGTH : IP6_MAX_PREFIX_LENGTH; uint maxlen = (s->af == AF_INET) ? IP4_MAX_PREFIX_LENGTH : IP6_MAX_PREFIX_LENGTH;
uint slen = maxlen;
uint dlen = (pxlen < 0) ? maxlen : pxlen;
if (passwd && *passwd) if (passwd && *passwd)
{ {
@ -160,14 +162,14 @@ sk_set_md5_in_sasp_db(sock *s, ip_addr local, ip_addr remote, struct iface *ifa,
if (len > TCP_KEYLEN_MAX) if (len > TCP_KEYLEN_MAX)
ERR_MSG("The password for TCP MD5 Signature is too long"); ERR_MSG("The password for TCP MD5 Signature is too long");
if ((setkey_md5(&src, &dst, pxlen, passwd, SADB_ADD) < 0) || if ((setkey_md5(&src, slen, &dst, dlen, passwd, SADB_ADD) < 0) ||
(setkey_md5(&dst, &src, pxlen, passwd, SADB_ADD) < 0)) (setkey_md5(&dst, dlen, &src, slen, passwd, SADB_ADD) < 0))
ERR_MSG("Cannot add TCP-MD5 password into the IPsec SA/SP database"); ERR_MSG("Cannot add TCP-MD5 password into the IPsec SA/SP database");
} }
else else
{ {
if ((setkey_md5(&src, &dst, pxlen, NULL, SADB_DELETE) < 0) || if ((setkey_md5(&src, slen, &dst, dlen, NULL, SADB_DELETE) < 0) ||
(setkey_md5(&dst, &src, pxlen, NULL, SADB_DELETE) < 0)) (setkey_md5(&dst, dlen, &src, slen, NULL, SADB_DELETE) < 0))
ERR_MSG("Cannot delete TCP-MD5 password from the IPsec SA/SP database"); ERR_MSG("Cannot delete TCP-MD5 password from the IPsec SA/SP database");
} }
return 0; return 0;

View file

@ -210,11 +210,11 @@ sk_prepare_ip_header(sock *s, void *hdr, int dlen)
#endif #endif
int int
sk_set_md5_auth(sock *s, ip_addr local UNUSED, ip_addr remote UNUSED, struct iface *ifa UNUSED, char *passwd, int setkey UNUSED) sk_set_md5_auth(sock *s, ip_addr local UNUSED, ip_addr remote UNUSED, int pxlen UNUSED, struct iface *ifa UNUSED, char *passwd, int setkey UNUSED)
{ {
#ifdef USE_MD5SIG_SETKEY #ifdef USE_MD5SIG_SETKEY
if (setkey) if (setkey)
if (sk_set_md5_in_sasp_db(s, local, remote, ifa, passwd) < 0) if (sk_set_md5_in_sasp_db(s, local, remote, pxlen, ifa, passwd) < 0)
return -1; return -1;
#endif #endif

View file

@ -6,35 +6,28 @@
* Can be freely distributed and used under the terms of the GNU GPL. * Can be freely distributed and used under the terms of the GNU GPL.
*/ */
#ifndef IP_MINTTL
#define IP_MINTTL 21
#endif
#ifndef IPV6_TCLASS
#define IPV6_TCLASS 67
#endif
#ifndef IPV6_MINHOPCOUNT #ifndef IPV6_MINHOPCOUNT
#define IPV6_MINHOPCOUNT 73 #define IPV6_MINHOPCOUNT 73
#endif #endif
#ifndef TCP_MD5SIG_EXT
#ifndef TCP_MD5SIG #define TCP_MD5SIG_EXT 32
#define TCP_MD5SIG 14
#define TCP_MD5SIG_MAXKEYLEN 80
struct tcp_md5sig {
struct sockaddr_storage tcpm_addr; /* address associated */
u16 __tcpm_pad1; /* zero */
u16 tcpm_keylen; /* key length */
u32 __tcpm_pad2; /* zero */
u8 tcpm_key[TCP_MD5SIG_MAXKEYLEN]; /* key (binary) */
};
#endif #endif
#ifndef TCP_MD5SIG_FLAG_PREFIX
#define TCP_MD5SIG_FLAG_PREFIX 1
#endif
/* We redefine the tcp_md5sig structure with different name to avoid collision with older headers */
struct tcp_md5sig_ext {
struct sockaddr_storage tcpm_addr; /* Address associated */
u8 tcpm_flags; /* Extension flags */
u8 tcpm_prefixlen; /* Address prefix */
u16 tcpm_keylen; /* Key length */
u32 __tcpm_pad2; /* Zero */
u8 tcpm_key[TCP_MD5SIG_MAXKEYLEN]; /* Key (binary) */
};
/* Linux does not care if sa_len is larger than needed */ /* Linux does not care if sa_len is larger than needed */
#define SA_LEN(x) sizeof(sockaddr) #define SA_LEN(x) sizeof(sockaddr)
@ -169,9 +162,9 @@ sk_prepare_cmsgs4(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
*/ */
int int
sk_set_md5_auth(sock *s, ip_addr local UNUSED, ip_addr remote, struct iface *ifa, char *passwd, int setkey UNUSED) sk_set_md5_auth(sock *s, ip_addr local UNUSED, ip_addr remote, int pxlen, struct iface *ifa, char *passwd, int setkey UNUSED)
{ {
struct tcp_md5sig md5; struct tcp_md5sig_ext md5;
memset(&md5, 0, sizeof(md5)); memset(&md5, 0, sizeof(md5));
sockaddr_fill((sockaddr *) &md5.tcpm_addr, s->af, remote, ifa, 0); sockaddr_fill((sockaddr *) &md5.tcpm_addr, s->af, remote, ifa, 0);
@ -187,13 +180,27 @@ sk_set_md5_auth(sock *s, ip_addr local UNUSED, ip_addr remote, struct iface *ifa
memcpy(&md5.tcpm_key, passwd, len); memcpy(&md5.tcpm_key, passwd, len);
} }
if (setsockopt(s->fd, SOL_TCP, TCP_MD5SIG, &md5, sizeof(md5)) < 0) if (pxlen < 0)
{ {
if (setsockopt(s->fd, SOL_TCP, TCP_MD5SIG, &md5, sizeof(md5)) < 0)
if (errno == ENOPROTOOPT) if (errno == ENOPROTOOPT)
ERR_MSG("Kernel does not support TCP MD5 signatures"); ERR_MSG("Kernel does not support TCP MD5 signatures");
else else
ERR("TCP_MD5SIG"); ERR("TCP_MD5SIG");
} }
else
{
md5.tcpm_flags = TCP_MD5SIG_FLAG_PREFIX;
md5.tcpm_prefixlen = pxlen;
if (setsockopt(s->fd, SOL_TCP, TCP_MD5SIG_EXT, &md5, sizeof(md5)) < 0)
{
if (errno == ENOPROTOOPT)
ERR_MSG("Kernel does not support extended TCP MD5 signatures");
else
ERR("TCP_MD5SIG_EXT");
}
}
return 0; return 0;
} }

View file

@ -1442,7 +1442,7 @@ sk_open(sock *s)
} }
if (s->password) if (s->password)
if (sk_set_md5_auth(s, s->saddr, s->daddr, s->iface, s->password, 0) < 0) if (sk_set_md5_auth(s, s->saddr, s->daddr, -1, s->iface, s->password, 0) < 0)
goto err; goto err;
switch (s->type) switch (s->type)