vrrp: fix source address on advertisements 25/33625/2
authorMatthew Smith <mgsmith@netgate.com>
Wed, 25 Aug 2021 22:09:34 +0000 (17:09 -0500)
committerDamjan Marion <dmarion@me.com>
Wed, 8 Sep 2021 14:40:23 +0000 (14:40 +0000)
Type: fix

Advertisements are dropped by anti spoofing check in some situations.

When a VR has "accept mode" enabled, we must add the virtual IP addresses
to the interface when the VR transitions to master state. When this
happens, fib_sas4_get() starts selecting the newly added virtual IP
address as the source address for packets sent on the interface, so
advertisements are sent with that source address.

When the virtual IP address is being used as a NAT pool address on a peer
in the backup state, the peer sees the address as a local address and
drops incoming advertisements with that source address.

RFC 5798 section 5.1.1.1 says advertisements should use the primary
IPv4 address of the interface they are being sent on as the source
IP address. Since the virtual IP address is only temporarily added
while the VR is in the master state, the virtual IP address should
probably not be considered the primary address of the interface. The
definition of Primary IP Address in section 1.6 says that selecting
the first address is a valid selection algorithm. Do that instead of
calling fib_sas4_get().

Change-Id: Id92f0e3237c7fd491dd8d695bb27307d494f8573
Signed-off-by: Matthew Smith <mgsmith@netgate.com>
src/plugins/vrrp/vrrp_packet.c

index b470dde..84bd370 100644 (file)
@@ -102,13 +102,20 @@ vrrp_adv_l3_build (vrrp_vr_t * vr, vlib_buffer_t * b,
   if (!vrrp_vr_is_ipv6 (vr))   /* IPv4 */
     {
       ip4_header_t *ip4 = vlib_buffer_get_current (b);
+      ip4_address_t *src4;
 
       clib_memset (ip4, 0, sizeof (*ip4));
       ip4->ip_version_and_header_length = 0x45;
       ip4->ttl = 255;
       ip4->protocol = IP_PROTOCOL_VRRP;
       clib_memcpy (&ip4->dst_address, &dst->ip4, sizeof (dst->ip4));
-      fib_sas4_get (vr->config.sw_if_index, NULL, &ip4->src_address);
+
+      /* RFC 5798 Section 5.1.1.1 - Source Address "is the primary IPv4
+       * address of the interface the packet is being sent from". Assume
+       * this is the first address on the interface.
+       */
+      src4 = ip_interface_get_first_ip (vr->config.sw_if_index, 1);
+      ip4->src_address.as_u32 = src4->as_u32;
       ip4->length = clib_host_to_net_u16 (sizeof (*ip4) +
                                          vrrp_adv_payload_len (vr));
       ip4->checksum = ip4_header_checksum (ip4);
@@ -536,10 +543,14 @@ vrrp_igmp_pkt_build (vrrp_vr_t * vr, vlib_buffer_t * b)
   u8 *ip4_options;
   igmp_membership_report_v3_t *report;
   igmp_membership_group_v3_t *group;
+  ip4_address_t *src4;
 
   ip4 = vlib_buffer_get_current (b);
   clib_memcpy (ip4, &igmp_ip4_mcast, sizeof (*ip4));
-  fib_sas4_get (vr->config.sw_if_index, NULL, &ip4->src_address);
+
+  /* Use the source address advertisements will use to join mcast group */
+  src4 = ip_interface_get_first_ip (vr->config.sw_if_index, 1);
+  ip4->src_address.as_u32 = src4->as_u32;
 
   vlib_buffer_chain_increase_length (b, b, sizeof (*ip4));
   vlib_buffer_advance (b, sizeof (*ip4));