Skip to content

Commit

Permalink
BGP: Support for MD5SIG together with remote range
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Ondrej Zajicek (work) committed Feb 27, 2020
1 parent 22c3cf9 commit 757cab1
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 42 deletions.
2 changes: 1 addition & 1 deletion lib/socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_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_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_icmp6_filter(sock *s, int p1, int p2);
void sk_log_error(sock *s, const char *p);
Expand Down
11 changes: 10 additions & 1 deletion proto/bgp/bgp.c
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,17 @@ bgp_setup_auth(struct bgp_proto *p, int enable)
{
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,
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);

if (rv < 0)
Expand Down
20 changes: 11 additions & 9 deletions sysdep/bsd/setkey.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ setkey_send(struct sadb_msg *msg, uint len)
* operations to implement replace.
*/
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;

Expand Down Expand Up @@ -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_exttype = SADB_EXT_ADDRESS_SRC;
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);
pos += len;

Expand All @@ -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_exttype = SADB_EXT_ADDRESS_DST;
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);
pos += len;

Expand All @@ -146,28 +146,30 @@ setkey_md5(sockaddr *src, sockaddr *dst, uint pxlen, char *passwd, uint type)
* Manipulation with the IPsec SA/SP database
*/
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_fill(&src, s->af, local, 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)
{
int len = strlen(passwd);
if (len > TCP_KEYLEN_MAX)
ERR_MSG("The password for TCP MD5 Signature is too long");

if ((setkey_md5(&src, &dst, pxlen, passwd, SADB_ADD) < 0) ||
(setkey_md5(&dst, &src, pxlen, passwd, SADB_ADD) < 0))
if ((setkey_md5(&src, slen, &dst, dlen, 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");
}
else
{
if ((setkey_md5(&src, &dst, pxlen, NULL, SADB_DELETE) < 0) ||
(setkey_md5(&dst, &src, pxlen, NULL, SADB_DELETE) < 0))
if ((setkey_md5(&src, slen, &dst, dlen, 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");
}
return 0;
Expand Down
4 changes: 2 additions & 2 deletions sysdep/bsd/sysio.h
Original file line number Diff line number Diff line change
Expand Up @@ -210,11 +210,11 @@ sk_prepare_ip_header(sock *s, void *hdr, int dlen)
#endif

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
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;
#endif

Expand Down
63 changes: 35 additions & 28 deletions sysdep/linux/sysio.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,28 @@
* 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
#define IPV6_MINHOPCOUNT 73
#endif

#ifndef TCP_MD5SIG_EXT
#define TCP_MD5SIG_EXT 32
#endif

#ifndef TCP_MD5SIG

#define TCP_MD5SIG 14
#define TCP_MD5SIG_MAXKEYLEN 80
#ifndef TCP_MD5SIG_FLAG_PREFIX
#define TCP_MD5SIG_FLAG_PREFIX 1
#endif

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) */
/* 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) */
};

#endif


/* Linux does not care if sa_len is larger than needed */
#define SA_LEN(x) sizeof(sockaddr)
Expand Down Expand Up @@ -169,9 +162,9 @@ sk_prepare_cmsgs4(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
*/

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));
sockaddr_fill((sockaddr *) &md5.tcpm_addr, s->af, remote, ifa, 0);
Expand All @@ -187,12 +180,26 @@ sk_set_md5_auth(sock *s, ip_addr local UNUSED, ip_addr remote, struct iface *ifa
memcpy(&md5.tcpm_key, passwd, len);
}

if (setsockopt(s->fd, SOL_TCP, TCP_MD5SIG, &md5, sizeof(md5)) < 0)
if (pxlen < 0)
{
if (errno == ENOPROTOOPT)
ERR_MSG("Kernel does not support TCP MD5 signatures");
else
ERR("TCP_MD5SIG");
if (setsockopt(s->fd, SOL_TCP, TCP_MD5SIG, &md5, sizeof(md5)) < 0)
if (errno == ENOPROTOOPT)
ERR_MSG("Kernel does not support TCP MD5 signatures");
else
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;
Expand Down
2 changes: 1 addition & 1 deletion sysdep/unix/io.c
Original file line number Diff line number Diff line change
Expand Up @@ -1442,7 +1442,7 @@ sk_open(sock *s)
}

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;

switch (s->type)
Expand Down

0 comments on commit 757cab1

Please sign in to comment.