diff --git a/CMakeLists.txt b/CMakeLists.txt
index f7e2f1cdd8b5f20dc399027d0d0018254341fbf7..559659b763452036d1a2e90387637f016defc73f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -6,8 +6,9 @@ tdaq_add_library(asyncmsg
   src/Session.cxx
   src/NameService.cxx
   src/UDPSession.cxx
+  src/Interface.cxx
   OPTIONS -O3
-  LINK_LIBRARIES transport is Boost::system)
+  LINK_LIBRARIES is Boost::system)
 
 tdaq_add_executable(test_namesvc NOINSTALL
   test/test_namesvc.cxx
diff --git a/cmt/requirements b/cmt/requirements
deleted file mode 100644
index 3c7e12f4794471375f80ebe31c05ce36064fc906..0000000000000000000000000000000000000000
--- a/cmt/requirements
+++ /dev/null
@@ -1,46 +0,0 @@
-package asyncmsg
-
-author  Tommaso.Colombo@cern.ch
-manager Tommaso.Colombo@cern.ch
-
-use TDAQPolicy
-
-use Boost * TDAQCExternal
-
-use is
-use transport
-
-private
-
-library asyncmsg "Error.cxx Server.cxx Session.cxx NameService.cxx UDPSession.cxx"
-macro asyncmsg_cppflags "-O3"
-macro asyncmsg_shlibflags "-lboost_system-${boost_libsuffix} -lis -ltransport"
-apply_pattern install_headers src_dir="../asyncmsg/detail" files="*.h" target_dir="detail"
-apply_pattern install_libs files="libasyncmsg.so"
-
-apply_pattern   install_data name=isschema              files="../schema/MsgInfo_is.schema.xml"\
-                                                        target_dir="schema"
-macro sw.repository.is-info-file.share/data/asyncmsg/schema/MsgInfo_is.schema.xml:name "MsgInfo IS xml description"
-
-
-# Test programs for name service
-#
-# This only requires a minimal partition with
-# one ipc_server and one IS server called 'DF'
-#
-
-application test_namesvc ../test/test_namesvc.cxx
-macro_append test_namesvclinkopts "-lasyncmsg"
-macro_append test_namesvc_dependencies "asyncmsg"
-
-application test_udpsession ../test/test_udpsession.cxx
-macro_append test_udpsessionlinkopts "-lasyncmsg"
-macro_append test_udpsession_dependencies "asyncmsg"
-
-#
-# This is usually just needed for a special test inside a partition.
-#
-
-# application test_lookup ../test/test_lookup.cxx
-# macro_append test_lookuplinkopts "-lasyncmsg -lItemCtrl -lcmdline"
-# macro_append test_lookup_dependencies "asyncmsg"
diff --git a/src/Interface.cxx b/src/Interface.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..edc64b15c7bb3eb55ee2aeda22afcb827ffcc42b
--- /dev/null
+++ b/src/Interface.cxx
@@ -0,0 +1,257 @@
+
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <netinet/ether.h>
+#include <ifaddrs.h>
+#include <netdb.h>
+#include "Interface.h"
+
+#include <iostream>
+
+namespace daq {
+
+    namespace asyncmsg {
+
+        class Cleanup {
+        public:
+            ~Cleanup();
+        };
+
+        // static
+        std::vector<const Interface *> Interface::s_interfaces;
+        struct ifaddrs *Interface::s_addresses = 0;
+
+        Cleanup s_cleanup;
+
+        // Interface::Cleanup s_cleanup;
+
+        /**
+         * Information about a network interface.
+         *
+         * This basically encapsulates the information returned
+         * by various ioctls() in a 'struct ifreq'.
+         *
+         * Only the IPv4 address family is supported at
+         * the moment and only Ethernet HW addresses are known.
+         */
+
+        /** The interface name, e.g. eth0 */
+        const std::string Interface::name() const
+        {
+            return m_addr->ifa_name;
+        }
+
+        // Return the address family.
+        int Interface::family() const
+        {
+            return m_addr->ifa_addr->sa_family;
+        }
+
+        /** The internal interface index (usually starting at 1) */
+        int Interface::index() const
+        {
+            return if_nametoindex(m_addr->ifa_name);
+        }
+
+        /** The various flags in net/if.h for interfaces */
+        int Interface::flags() const
+        {
+            return m_addr->ifa_flags;
+        }
+
+        /** Return true if the corresponding flag from net/if.h is set */
+        bool Interface::has_flag(int flag) const
+        {
+            return m_addr->ifa_flags & flag;
+        }
+
+        /** The IP address of this interface or 0 */
+        in_addr_t Interface::address() const
+        {
+            if(m_addr->ifa_addr->sa_family == AF_INET) {
+                return ((sockaddr_in *)m_addr->ifa_addr)->sin_addr.s_addr;
+            } else {
+                return 0;
+            }
+        }
+
+        /** The IP address of this interface or 0 */
+        in6_addr Interface::address_v6() const
+        {
+            if(m_addr->ifa_addr->sa_family == AF_INET6 ) {
+                return ((sockaddr_in6 *)m_addr->ifa_addr)->sin6_addr;
+            } else {
+                return in6addr_any;
+            }
+        }
+
+        /** The IP address of this interface as a string or "" */
+        std::string Interface::address_string() const
+        {
+            char buf[INET6_ADDRSTRLEN+1]= { 0 };
+            getnameinfo(m_addr->ifa_addr, sizeof(sockaddr_storage), buf, sizeof(buf), 0, 0, NI_NUMERICHOST);
+            return buf;
+        }
+
+        /** The broadcast IP address of this interface or 0 */
+        in_addr_t Interface::broadcast() const
+        {
+            if(m_addr->ifa_addr->sa_family == AF_INET) {
+                return ((sockaddr_in *)m_addr->ifa_broadaddr)->sin_addr.s_addr;
+            } else {
+                return 0;
+            }
+        }
+
+        /** The broadcast IP address as a string or "" */
+        std::string Interface::broadcast_string() const
+        {
+            char buf[INET_ADDRSTRLEN] = { 0 };
+            if(m_addr->ifa_addr->sa_family == AF_INET && m_addr->ifa_broadaddr) {
+                getnameinfo(m_addr->ifa_broadaddr, sizeof(sockaddr_in), buf, sizeof(buf), 0, 0, NI_NUMERICHOST);
+            }
+            return buf;
+        }
+
+
+        /** The netmask for this interface or 0 */
+        in_addr_t Interface::netmask() const
+        {
+            return ((sockaddr_in *)m_addr->ifa_netmask)->sin_addr.s_addr;
+        }
+
+        /** The IP v6 netmask for this interface  */
+        in6_addr Interface::netmask_v6() const
+        {
+            return ((sockaddr_in6 *)m_addr->ifa_netmask)->sin6_addr;
+        }
+
+        /** The netmask for this interface or 0 */
+        std::string Interface::netmask_string() const
+        {
+            char buf[INET6_ADDRSTRLEN+1]= { 0 };
+            getnameinfo(m_addr->ifa_netmask, sizeof(sockaddr_storage), buf, sizeof(buf), 0, 0, NI_NUMERICHOST);
+            return buf;
+        }
+
+        /** Network: address masked with netmask */
+        in_addr_t Interface::network() const
+        {
+            return  ((sockaddr_in *)m_addr->ifa_addr)->sin_addr.s_addr & ((sockaddr_in *)m_addr->ifa_netmask)->sin_addr.s_addr;
+        }
+
+        /** Network: address masked with netmask, IPV6*/
+        in6_addr Interface::network_v6() const
+        {
+            in6_addr result = ((sockaddr_in6 *)m_addr->ifa_addr)->sin6_addr;
+            for(int i = 0; i < 4; i++) {
+                result.s6_addr32[i] &= ((sockaddr_in6 *)m_addr->ifa_netmask)->sin6_addr.s6_addr32[i];
+            }
+            return result;
+        }
+
+
+#if 0
+        /** The Ethernet hw address of the interface */
+        ether_addr Interface::hw_address() const
+        {
+            ether_addr addr;
+            memcpy(&addr, m_addr->ifa_addr->sa_data, sizeof(ether_addr));
+            return addr;
+        }
+
+        std::string Interface::hw_address_string() const
+        {
+            char buffer[20];
+            return ether_ntoa_r((const ether_addr *)m_addr->ifa_addr->sa_data, buffer);
+        }
+#endif 
+
+        /** Find interface by index.*/ 
+        const Interface *Interface::find(int index, int af)
+        {
+            const InterfaceList& if_list = interfaces();
+            for(InterfaceList::const_iterator it = if_list.begin();
+                it != if_list.end();
+                ++it) {
+                if((*it)->index() == index && (*it)->family() == af) return *it;
+            }
+            return 0;
+        }
+
+        /// Find interface by name.
+        const Interface *Interface::find(const std::string& name, int af)
+        {
+            const InterfaceList& if_list = interfaces();
+            for(InterfaceList::const_iterator it = if_list.begin();
+                it != if_list.end();
+                ++it) {
+                if((*it)->name() == name && (*it)->family() == af) return *it;
+            }
+            return 0;
+        }
+
+        /// Return list of all interfaces.
+        const Interface::InterfaceList& Interface::interfaces()
+        {
+            if(s_interfaces.size() == 0) {
+                
+                getifaddrs(&s_addresses);
+                struct ifaddrs *ptr = s_addresses;
+
+                while(ptr) {
+                    if(ptr->ifa_addr->sa_family == AF_INET || ptr->ifa_addr->sa_family == AF_INET6) {
+                        s_interfaces.push_back(new Interface(ptr));
+                    }
+                    ptr = ptr->ifa_next;
+                }
+            }
+
+            return s_interfaces;
+        }
+
+        Interface::Interface(ifaddrs *addr)
+            : m_addr(addr)
+        {
+        }
+    
+        Interface::~Interface()
+        {
+        }
+
+        Cleanup::~Cleanup()
+        {
+            for(Interface::InterfaceList::const_iterator it = Interface::s_interfaces.begin();
+                it != Interface::s_interfaces.end();
+                ++it) {
+                delete *it;
+            }
+            freeifaddrs(Interface::s_addresses);
+        }
+
+        std::ostream& operator<<(std::ostream& os, const Interface& intf)
+        {
+            switch (intf.family()) {
+            case AF_INET:
+            case AF_INET6:
+                os << intf.address_string() << '/' << intf.netmask_string();
+                break;
+            default:
+                os << intf.name() << ": " << "Unkwown interface type: " << intf.family() ;
+                break;
+            }
+
+            return os;
+        }
+
+        bool operator==(const in6_addr& a, const in6_addr& b)
+        {
+            return memcmp(&a,&b, sizeof(in6_addr)) == 0;
+        }
+        
+    }
+}
+
diff --git a/src/Interface.h b/src/Interface.h
new file mode 100644
index 0000000000000000000000000000000000000000..4290d75e8125d2c66e0fc371fc30710f18beb0fb
--- /dev/null
+++ b/src/Interface.h
@@ -0,0 +1,118 @@
+// this is -*- c++ -*-
+#ifndef TRANSPORT_INTERFACE_H_
+#define TRANSPORT_INTERFACE_H_
+
+#include <string>
+#include <vector>
+#include <iosfwd>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <net/ethernet.h>
+
+// fwd declaration
+struct ifaddrs;
+
+namespace daq {
+    namespace asyncmsg {
+
+        // Internal helper class
+        class Cleanup;
+
+        /**
+         * Information about a network interface.
+         *
+         * This basically encapsulates the information returned
+         * by getifaddrs().
+         *
+         * Both IP V4 and V6 are supported. 
+         */
+        class Interface {
+        public:
+
+            /** The interface name, e.g. eth0 */
+            const std::string name() const;
+
+            /** The address family for this Interface 
+             *  One of AF_INET, AF_INET6, AF_PACKET
+             */
+            int family() const;
+
+            /** The internal interface index (usually starting at 1) */
+            int index() const;
+
+            /** The various flags in net/if.h for interfaces */
+            int flags() const;
+
+            /** Return true if the corresponding flag from net/if.h is set */
+            bool has_flag(int flag) const;
+
+            /** The IP address of this interface or 0 */
+            in_addr_t address() const;
+
+            /** The IP V6 address of this interface */
+            in6_addr  address_v6() const;
+
+            /** The IP address of this interface as a string or "" */
+            std::string address_string() const;
+
+            /** The broadcast IP address of this interface or 0 */
+            in_addr_t broadcast() const;
+
+            /** The broadcast IP address as a string or "" */
+            std::string broadcast_string() const;
+
+            /** The netmask for this interface or 0 */
+            in_addr_t netmask() const;
+
+            /** The IP V6 netmask of this interface */
+            in6_addr  netmask_v6() const;
+
+            /** Network: address masked with netmask */
+            in_addr_t network() const;
+
+            /** Network: address masked with netmask, IPV6*/
+            in6_addr network_v6() const;
+
+            /** The netmask for this interface or 0 */
+            std::string netmask_string() const;
+
+#if 0
+            /** The Ethernet hw address of the interface */
+            ether_addr hw_address() const;
+
+            std::string hw_address_string() const;
+#endif
+        public:
+            /** Find interface by index.*/ 
+            static const Interface *find(int index, int af = AF_INET); 
+
+            /// Find interface by name.
+            static const Interface *find(const std::string& name, int af = AF_INET);
+
+            typedef std::vector<const Interface *> InterfaceList;
+
+            /// Return list of all interfaces.
+            static const InterfaceList& interfaces();
+
+        private:
+            Interface(struct ifaddrs *addr);
+            ~Interface();
+
+            // Representation
+            struct ifaddrs *m_addr;
+
+            friend class Cleanup;
+        
+            /// Global list of all interfaces
+            static InterfaceList  s_interfaces;
+            static struct ifaddrs *s_addresses;
+        };
+
+        std::ostream& operator<<(std::ostream& os, const Interface& );
+
+        bool operator==(const in6_addr& , const in6_addr& );
+    }
+}
+
+#endif // TRANSPORT_INTERFACE_H_
diff --git a/src/NameService.cxx b/src/NameService.cxx
index 0b9ce4c699cea2a9a346e77918688e7d43d41375..9e67dd3a9435192e46928d588977dca96a5263c4 100644
--- a/src/NameService.cxx
+++ b/src/NameService.cxx
@@ -1,7 +1,7 @@
 
 
 #include "asyncmsg/NameService.h"
-#include "transport/Interface.h"
+#include "Interface.h"
 
 #include "MsgInfo.h"
 #include "MultiCastGroup.h"
@@ -73,7 +73,7 @@ namespace daq {
             info.Hostname = host;
             info.Port     = port;
 
-            const daq::transport::Interface::InterfaceList& interfaces = daq::transport::Interface::interfaces();
+            const daq::asyncmsg::Interface::InterfaceList& interfaces = daq::asyncmsg::Interface::interfaces();
 
             for(auto intf : interfaces) {
 
@@ -176,7 +176,7 @@ namespace daq {
 
         bool NameService::matches(const boost::asio::ip::address& addr, const boost::asio::ip::address& mask) const
         {
-            for(const auto intf : daq::transport::Interface::interfaces()) {
+            for(const auto intf : daq::asyncmsg::Interface::interfaces()) {
 
                 // ignore these
                 if(!intf->has_flag(IFF_UP) || intf->has_flag(IFF_LOOPBACK) || intf->address() == 0) {
@@ -351,7 +351,7 @@ namespace daq {
             auto addr = boost::asio::ip::address::from_string(local_mask).to_v4();
 	    auto mask = boost::asio::ip::address::from_string(mc_mask).to_v4();
 
-            auto interfaces = daq::transport::Interface::interfaces();
+            auto interfaces = daq::asyncmsg::Interface::interfaces();
             for(auto intf : interfaces) {
                 if(!intf->has_flag(IFF_UP) || intf->has_flag(IFF_LOOPBACK)) {
                     continue;