lib: add support for extended TCP MD5 auth

MD5 auth on TCP is supported for prefixes in recent versions of Linux;
add complementary support for FRR.

This is a reworked version of Donald's commit to keep library
compatibility and obviate the need for changes in daemons that don't
need to support this themselves.

Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
This commit is contained in:
Quentin Young 2019-04-01 18:16:54 +00:00
parent 0697abef9d
commit b33e46666d
2 changed files with 79 additions and 5 deletions

View File

@ -587,10 +587,30 @@ int sockopt_tcp_rtt(int sock)
#endif
}
int sockopt_tcp_signature(int sock, union sockunion *su, const char *password)
int sockopt_tcp_signature_ext(int sock, union sockunion *su, uint16_t prefixlen,
const char *password)
{
#ifndef HAVE_DECL_TCP_MD5SIG
/*
* We have been asked to enable MD5 auth for an address, but our
* platform doesn't support that
*/
return -2;
#endif
#ifndef TCP_MD5SIG_EXT
/*
* We have been asked to enable MD5 auth for a prefix, but our platform
* doesn't support that
*/
if (prefixlen > 0)
return -2;
#endif
#if HAVE_DECL_TCP_MD5SIG
int ret;
int optname = TCP_MD5SIG;
#ifndef GNU_LINUX
/*
* XXX Need to do PF_KEY operation here to add/remove an SA entry,
@ -643,12 +663,29 @@ int sockopt_tcp_signature(int sock, union sockunion *su, const char *password)
memset(&md5sig, 0, sizeof(md5sig));
memcpy(&md5sig.tcpm_addr, su2, sizeof(*su2));
md5sig.tcpm_keylen = keylen;
if (keylen)
memcpy(md5sig.tcpm_key, password, keylen);
sockunion_free(susock);
/*
* Handle support for MD5 signatures on prefixes, if available and
* requested. Technically the #ifdef check below is not needed because
* if prefixlen > 0 and we don't have support for this feature we would
* have already returned by now, but leaving it there to be explicit.
*/
#ifdef TCP_MD5SIG_EXT
if (prefixlen > 0) {
md5sig.tcpm_prefixlen = prefixlen;
md5sig.tcpm_flags = TCP_MD5SIG_FLAG_PREFIX;
optname = TCP_MD5SIG_EXT;
}
#endif /* TCP_MD5SIG_EXT */
#endif /* GNU_LINUX */
if ((ret = setsockopt(sock, IPPROTO_TCP, TCP_MD5SIG, &md5sig,
if ((ret = setsockopt(sock, IPPROTO_TCP, optname, &md5sig,
sizeof md5sig))
< 0) {
/* ENOENT is harmless. It is returned when we clear a password
@ -663,7 +700,10 @@ int sockopt_tcp_signature(int sock, union sockunion *su, const char *password)
sock, safe_strerror(errno));
}
return ret;
#else /* HAVE_TCP_MD5SIG */
return -2;
#endif /* !HAVE_TCP_MD5SIG */
#endif /* HAVE_TCP_MD5SIG */
}
int sockopt_tcp_signature(int sock, union sockunion *su, const char *password)
{
return sockopt_tcp_signature_ext(sock, su, 0, password);
}

View File

@ -100,9 +100,43 @@ extern void sockopt_iphdrincl_swab_htosys(struct ip *iph);
extern void sockopt_iphdrincl_swab_systoh(struct ip *iph);
extern int sockopt_tcp_rtt(int);
/*
* TCP MD5 signature option. This option allows TCP MD5 to be enabled on
* addresses.
*
* sock
* Socket to enable option on.
*
* su
* Sockunion specifying address to enable option on.
*
* password
* MD5 auth password
*/
extern int sockopt_tcp_signature(int sock, union sockunion *su,
const char *password);
/*
* Extended TCP MD5 signature option. This option allows TCP MD5 to be enabled
* on prefixes.
*
* sock
* Socket to enable option on.
*
* su
* Sockunion specifying address (or prefix) to enable option on.
*
* prefixlen
* 0 - su is an address; fall back to non-extended mode
* Else - su is a prefix; prefixlen is the mask length
*
* password
* MD5 auth password
*/
extern int sockopt_tcp_signature_ext(int sock, union sockunion *su,
uint16_t prefixlen, const char *password);
#ifdef __cplusplus
}
#endif