Commit 757cab18 authored by Ondrej Zajicek (work)'s avatar Ondrej Zajicek (work)
Browse files

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.
parent 22c3cf95
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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);
+10 −1
Original line number Diff line number Diff line
@@ -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)
+11 −9
Original line number Diff line number Diff line
@@ -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;

@@ -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;

@@ -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;

@@ -146,13 +146,15 @@ 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)
  {
@@ -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)
      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;
+2 −2
Original line number Diff line number Diff line
@@ -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

+35 −28
Original line number Diff line number Diff line
@@ -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)
@@ -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);
@@ -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);
  }

  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)
	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;
}
Loading