jitsi/jitsi-videobridge

FreeBSD: failure binding on a NAT-ed loopback interface.

karolyi opened this issue · 5 comments

Hey guys,

yes I read the issue template, and this seems to be a genuine bug. For details, see https://community.jitsi.org/t/videobridge-problems/67691.

Because of this bug, I am unable to run Jitsi on FreeBSD now.

Hey, thanks for the report.

Most probably the failure is because ice4j refuses to bind on a loopback interface, and there are no other interfaces available. You can run the following to confirm (save as Test.java and run javac Test.java && java Test):


import java.lang.reflect.*;
import java.net.*;
import java.util.*;

class Test
{
   public static void main(String[] args)
   {
       getAllAllowedAddresses();
   }

   public static List<InetAddress> getAllAllowedAddresses()
   {
       List<InetAddress> addresses = new LinkedList<>();
       try
       {
           for (NetworkInterface iface
                   : Collections.list(NetworkInterface.getNetworkInterfaces()))
           {
               System.err.println("Interface: " + iface);
               System.err.println("  isLoopback:" + isInterfaceLoopback(iface));
               System.err.println("  isUp:" + isInterfaceUp(iface));
               if (isInterfaceLoopback(iface) || !isInterfaceUp(iface))
               {
                   continue;
               }

               Enumeration<InetAddress> ifaceAddresses = iface.getInetAddresses();
               while (ifaceAddresses.hasMoreElements())
               {
                   InetAddress address = ifaceAddresses.nextElement();
                   System.err.println("  Address"+address + " isIvp6="+(address instanceof Inet6Address));

                   if (address instanceof Inet6Address)
                       continue;

                   addresses.add(address);
               }
           }
       }
       catch (SocketException se)
       {
           System.err.println("Failed to get network interfaces: " + se);
       }

       return addresses;
   }

   public static boolean isInterfaceLoopback(NetworkInterface iface)
   {
       try
       {
           Method method = iface.getClass().getMethod("isLoopback");

           return (Boolean) method.invoke(iface);
       }
       catch(Throwable t)
       {
           //apparently we are not running in a JVM that supports the
           //is Loopback method. we'll try another approach.
       }
       Enumeration<InetAddress> addresses = iface.getInetAddresses();

       return addresses.hasMoreElements()
               && addresses.nextElement().isLoopbackAddress();
   }

   public static boolean isInterfaceUp(NetworkInterface iface)
   {
       try
       {
           Method method = iface.getClass().getMethod("isUp");

           return (Boolean) method.invoke(iface);
       }
       catch(Throwable t)
       {
           //apparently we are not running in a JVM that supports the
           //isUp method. returning default value.
       }

       return true;
   }
}

Assuming that this is the case. Do you know if it is normal for FreeBSD and/or jails to run with only loopback interfaces? We can accept a patch to make this ice4j behavior configurable.

Hey, thanks for the super quick reply.

Yes, in the case of FreeBSD, it is pretty usual that jails (the same as docker for linux but more powerful) get such interfaces, with NAT-ed internal IP addresses. As you can see on the linked forum topic, many people struggle with it, just like me.

I've got a bridge0, the videobridge can bind on it, but that is only a public ipv6 address in my case which is not sufficient. We need to bind all to all interfaces, be it loopback or not.

As for a patch, unfortunately I'm not a Java coder so I can't help you out here.

Hoping for a quick resolution.

Cheers!

Executing the test code, the output displayed the lo0 interface, but not its IPv4 address:

Interface: name:bridge0 (bridge0)
  isLoopback:false
  isUp:true
  Address/2aff::3e isIvp6=true
Interface: name:lo0 (lo0)
  isLoopback:true
  isUp:true

it's got an IPv4 address though:

lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> metric 0 mtu 16384
        options=680003<RXCSUM,TXCSUM,LINKSTATE,RXCSUM_IPV6,TXCSUM_IPV6>
        inet 127.0.0.35 netmask 0xffffffff
        groups: lo
        nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>

Edit: alright, my bad, I saw the code exited on the interface being loopback. Commenting that part out displayed its IP address.

Thanks, this confirms that the reason the interface is not used by ice4j is because it's loopback.

Hey @bgrozev, see the submitted patch. Disclaimer: I'm still not a java coder, although I already built a small application in Kotlin a couple years ago.

This whole new configuration option I added has the caveat of making the other two configuration option for the allowed/blockes interfaces unclear.

I'd rather just use the two options already in place (but properly evaluated), and skip loopback address checking in isAddressAllowed().

On second thought, I might just added an error there, in the case of IPv6 link local addresses, I think.

It's your call.