]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
BGP: Support for MD5SIG together with remote range
authorOndrej Zajicek (work) <santiago@crfreenet.org>
Thu, 27 Feb 2020 15:16:48 +0000 (16:16 +0100)
committerOndrej Zajicek (work) <santiago@crfreenet.org>
Thu, 27 Feb 2020 16:29:17 +0000 (17:29 +0100)
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.

lib/socket.h
proto/bgp/bgp.c
sysdep/bsd/setkey.h
sysdep/bsd/sysio.h
sysdep/linux/sysio.h
sysdep/unix/io.c

index 03c15dcdf73cd0460aaaa9fe8ae0aed3b5bf6698..f2b0c0425c680cc29ddf2e208724652d3254df64 100644 (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_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);
index 83105a689f7ada323080d036b77c6cb6c22cbf44..b9ed6c7894ca5ba627f024006b7dfdc4666b7027 100644 (file)
@@ -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)
index 8a1bc9ad7ab085bcc7013e5bf43d45fe43a8de03..40564cf1337a23208b0e2d3e1f4b93aa5c8e347d 100644 (file)
@@ -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;
index a5d161ba0e99bac7ed2720c0e474b7797abc8187..929bfaf64aa6a76b1e9d2a4caa8725de34c0c8e0 100644 (file)
@@ -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
 
index b1cc25dce60bb1f5ca09ceb3692ba0e64cd42c74..8c3efd6ea28ee25cc70589bc6b2768842bd56f16 100644 (file)
@@ -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,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;
index 5e4d95734deb91ed1ad34722a12e01949b59219e..f4e45a5f59aedaaa10e0ac748d1484b5e45dfaab 100644 (file)
@@ -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)