Hi,

Using OpenVPN to build a WAN, I noticed a disturbing thing: After
failing over to secondary OpenVPN server it takes a long time until a
ping to a client side IP works again. I think I know what's happening:

An OpenVPN server learns client-side MAC addresses based on the source
MAC addresses of received packets, just like an ethernet switch. When an
ethernet packet has to be sent to a client, the OpenVPN server selects
the client based on previously learnt MAC addresses. When a packet has
an unknown destination MAC address it's dropped - this is very unlike a
switch which broadcasts a packet to all interfaces. There's only one
exception for OpenVPN: when the destination MAC address is a broadcast /
multicast address the packet is sent to all clients.

The above makes clear why ICMP (or other IP) packets normaly arrive.
It's because they're preceeded by an ARP request..... which is a
broadcast. The ARP request is delivered to all clients, including the
right one. The ARP reply that's sent back to the server contains a
source MAC address which is learnt by the server, after which the ICMP
packets are delivered properly.

The attached patch makes OpenVPN do the switch-like thing: broadcast a
packet with an unknow destination to all clients instead of dropping it.

It helps me a lot, so it may help others as well.

Cheers,

Rolf

--- openvpn-2.0.2/multi.c.orig	2005-10-02 14:58:58.000000000 +0200
+++ openvpn-2.0.2/multi.c	2005-10-02 15:04:20.000000000 +0200
@@ -1756,9 +1756,17 @@
 	    }
 	  else
 	    {
-	      multi_set_pending (m, multi_get_instance_by_virtual_addr (m, &dest, dev_type == DEV_TYPE_TUN));
+              struct multi_instance *mi;

-	      if (m->pending)
+	      mi = multi_get_instance_by_virtual_addr (m, &dest, dev_type == DEV_TYPE_TUN);
+	      multi_set_pending (m, mi);
+
+	      if (!mi)
+                {
+	          /* No known instance? Do like a switch: broadcast */
+	          if (dev_type == DEV_TYPE_TAP) multi_bcast (m, &m->top.c2.buf, NULL);
+                }
+              else
 		{
 		  /* get instance context */
 		  c = &m->pending->context;

Reply via email to