Browse Source

FIX #162 Unrecognized interface resolved as 0.0.0.0

If the interface named in environment.conf does not exist, the code
was supposed to fall into using hostname when resolving the '.' net
address. However due to a flaw in the logic it will actually use
0.0.0.0, and various components will fail to start as a result.

This patch splits the 'test' and 'retrieve' functionality into
separate functions to make them easier to follow, and adds the ability
to use a wildcard in the interface specification. When searching for
an interface ip, loopback interfaces are always searched AFTER
non-loopback ones.

With this fix in place, the most appropriate value for interface= in
environment.conf is *

Signed-off-by: Richard Chapman <rchapman@hpccsystems.com>
Richard Chapman 14 years ago
parent
commit
8e30227a0d
3 changed files with 64 additions and 20 deletions
  1. 1 0
      initfiles/etc/DIR_NAME/environment.conf.in
  2. 61 18
      system/jlib/jsocket.cpp
  3. 2 2
      system/jlib/jsocket.hpp

+ 1 - 0
initfiles/etc/DIR_NAME/environment.conf.in

@@ -13,3 +13,4 @@ home=${HOME_DIR}
 environment=${ENV_XML_FILE}
 sourcedir=${CONFIG_SOURCE_PATH}
 blockname=${DIR_NAME}
+interface=*

+ 61 - 18
system/jlib/jsocket.cpp

@@ -62,6 +62,7 @@
 #include "jqueue.tpp"
 #include "jtime.hpp"
 #include "jprop.hpp"
+#include "jregexp.hpp"
 #include "jdebug.hpp"
 #include "build-config.h"
 
@@ -2474,13 +2475,11 @@ ISocket* ISocket::attach(int s, bool tcpip)
     return sock;
 }
 
-bool lookupInterfaceIp(IpAddress &ip,const char *ifname,bool test)
+bool isInterfaceIp(const IpAddress &ip, const char *ifname)
 {
 #ifdef _WIN32
     return false;
 #else
-    if (!test)
-        ip.ipset(NULL);
     int fd = socket(AF_INET, SOCK_DGRAM, 0);  // IPV6 TBD
     if (fd<0)
         return false;
@@ -2493,25 +2492,66 @@ bool lookupInterfaceIp(IpAddress &ip,const char *ifname,bool test)
         return false;
     struct ifreq *ifr = ifc.ifc_req;
     unsigned n = ifc.ifc_len/sizeof(struct ifreq);
-    for(unsigned i=0; i<n; i++) {
+    bool match = false;
+    for(unsigned i=0; i<n; i++)
+    {
         struct ifreq *item = &ifr[i];
         if (ifname&&*ifname)
-            if (strcmp(item->ifr_name,ifname)!=0)
+            if (!WildMatch(item->ifr_name,ifname))
                 continue;
         IpAddress iptest((inet_ntoa(((struct sockaddr_in *)&item->ifr_addr)->sin_addr)));
-        if (test) {
-            if (ip.ipequals(iptest)) {
-                test = false;
-                break;
+        if (ip.ipequals(iptest))
+        {
+            match = true;
+            break;
+        }
+    }
+    close(fd);
+    return match;
+#endif
+}
+
+bool getInterfaceIp(IpAddress &ip,const char *ifname)
+{
+#ifdef _WIN32
+    return false;
+#else
+    ip.ipset(NULL);
+    int fd = socket(AF_INET, SOCK_DGRAM, 0);  // IPV6 TBD
+    if (fd<0)
+        return false;
+    MemoryAttr ma;
+    char *buf = (char *)ma.allocate(1024);
+    struct ifconf ifc;
+    ifc.ifc_len = 1024;
+    ifc.ifc_buf = buf;
+    if(ioctl(fd, SIOCGIFCONF, &ifc) < 0) // query interfaces
+        return false;
+    struct ifreq *ifr = ifc.ifc_req;
+    unsigned n = ifc.ifc_len/sizeof(struct ifreq);
+    for (int loopback = 0; loopback <= 1; loopback++)
+    {
+        for (int i=0; i<n; i++)
+        {
+            bool useLoopback = (loopback==1);
+            struct ifreq *item = &ifr[i];
+            if (ifname&&*ifname)
+                if (!WildMatch(item->ifr_name,ifname))
+                    continue;
+            IpAddress iptest((inet_ntoa(((struct sockaddr_in *)&item->ifr_addr)->sin_addr)));
+            if (iptest.isLoopBack() == useLoopback)
+            {
+                if (ip.isNull())
+                    ip.ipset(iptest);
+                else if (!PreferredSubnet.isNull()&&!PreferredSubnet.test(ip)&&PreferredSubnet.test(iptest))
+                    ip.ipset(iptest);
             }
         }
-        else if (ip.isNull())
-            ip.ipset(iptest);
-        else if (!PreferredSubnet.isNull()&&!PreferredSubnet.test(ip)&&PreferredSubnet.test(iptest))
-            ip.ipset(iptest);
+        if (!ip.isNull())
+            break;
     }
     close(fd);
-    return !test;
+    return !ip.isNull();
 #endif
 }
 
@@ -2533,11 +2573,14 @@ const char * GetCachedHostName()
         if (EnvConfPath.length() == 0)
             EnvConfPath.append(CONFIG_DIR).append(PATHSEPSTR).append("environment.conf");
         Owned<IProperties> conf = createProperties(EnvConfPath.str(), true);
-        if (conf->getProp("interface", ifs)&&ifs.length()) {
-            if (lookupInterfaceIp(ip,ifs.str(),false)) {
+        if (conf->getProp("interface", ifs) && ifs.length())
+        {
+            if (getInterfaceIp(ip, ifs.str()))
+            {
                 StringBuffer ips;
                 ip.getIpText(ips);
-                if (ips.length()) {
+                if (ips.length())
+                {
                     cachehostname.set(ips.str());
                     cachehostip.ipset(ip);
                     return cachehostname.get();
@@ -2629,7 +2672,7 @@ bool IpAddress::isLocal() const
     if (isLoopBack() || isHost())
         return true;
     IpAddress ip(*this);
-    return lookupInterfaceIp(ip,NULL,true); 
+    return isInterfaceIp(ip, NULL);
 }
 
 

+ 2 - 2
system/jlib/jsocket.hpp

@@ -600,8 +600,8 @@ extern jlib_decl bool setPreferredSubnet(const char *ip,const char *mask); // al
 
 extern jlib_decl StringBuffer lookupHostName(const IpAddress &ip,StringBuffer &ret);
 
-extern jlib_decl bool lookupInterfaceIp(IpAddress &ip,const char *ifname,bool test); // if test true returns true if ip matches interface 
-                                                                                     // if test false returns first ip for interface
+extern jlib_decl bool isInterfaceIp(const IpAddress &ip, const char *ifname);
+extern jlib_decl bool getInterfaceIp(IpAddress &ip, const char *ifname);
 
 #endif