Browse Source

First attempt of mDNS interface selection (#2856)

fixes #2774
Sten Grüner 4 years ago
parent
commit
1de8b24ac0

+ 3 - 0
examples/discovery/server_multicast.c

@@ -251,6 +251,9 @@ int main(int argc, char **argv) {
 
     config->discovery.mdns.mdnsServerName = UA_String_fromChars("Sample Multicast Server");
 
+    //setting custom outbound interface
+    config->discovery.mdnsInterfaceIP = UA_String_fromChars("42.42.42.42"); //this line will produce an error and set the interface to 0.0.0.0
+
     // See http://www.opcfoundation.org/UA/schemas/1.03/ServerCapabilities.csv
     // For a LDS server, you should only indicate the LDS capability.
     // If this instance is an LDS and at the same time a normal OPC UA server, you also have to indicate

+ 1 - 0
include/open62541/server_config.h

@@ -76,6 +76,7 @@ typedef struct {
 
 #ifdef UA_ENABLE_DISCOVERY_MULTICAST
     UA_MdnsDiscoveryConfiguration mdns;
+    UA_String mdnsInterfaceIP;
 #endif
 
 } UA_ServerConfig_Discovery;

+ 1 - 0
plugins/ua_config_default.c

@@ -133,6 +133,7 @@ setDefaultConfig(UA_ServerConfig *conf) {
 
 #ifdef UA_ENABLE_DISCOVERY_MULTICAST
     UA_MdnsDiscoveryConfiguration_init(&conf->discovery.mdns);
+    conf->discovery.mdnsInterfaceIP = UA_STRING_NULL;
 #endif
 
     /* Custom DataTypes */

+ 41 - 3
src/server/ua_discovery_manager.c

@@ -4,7 +4,7 @@
  *
  *    Copyright 2014-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
  *    Copyright 2014, 2017 (c) Florian Palm
- *    Copyright 2015-2016 (c) Sten Grüner
+ *    Copyright 2015-2016, 2019 (c) Sten Grüner
  *    Copyright 2015 (c) Chris Iatrou
  *    Copyright 2015-2016 (c) Oleksiy Vasylyev
  *    Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH
@@ -17,9 +17,13 @@
 
 #ifdef UA_ENABLE_DISCOVERY_MULTICAST
 
+#ifndef IN_ZERONET
+#define IN_ZERONET(addr) ((addr & IN_CLASSA_NET) == 0)
+#endif
+
 /* Create multicast 224.0.0.251:5353 socket */
 static UA_SOCKET
-discovery_createMulticastSocket(void) {
+discovery_createMulticastSocket(UA_Server* server) {
     UA_SOCKET s;
     int flag = 1, ittl = 255;
     struct sockaddr_in in;
@@ -44,6 +48,40 @@ discovery_createMulticastSocket(void) {
         return UA_INVALID_SOCKET;
     }
 
+    /* Custom outbound multicast interface */
+    size_t length = server->config.discovery.mdnsInterfaceIP.length;
+    if(length > 0){
+        char* interfaceName = (char*)UA_malloc(length+1);
+        if (!interfaceName) {
+            UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_NETWORK, "Multicast DNS: cannot alloc memory for iface name");
+            return 0;
+        }
+        struct in_addr ina;
+        memset(&ina, 0, sizeof(ina));
+        memcpy(interfaceName, server->config.discovery.mdnsInterfaceIP.data, length);
+        interfaceName[length] = '\0';
+        inet_pton(AF_INET, interfaceName, &ina);
+        UA_free(interfaceName);
+        /* Set interface for outbound multicast */
+        if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, (char*)&ina, sizeof(ina)) < 0)
+            UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, "Multicast DNS: failed setting IP_MULTICAST_IF to %s: %s", inet_ntoa(ina), strerror(errno));
+    }
+
+    /* Check outbound multicast interface parameters */
+    struct in_addr interface_addr;
+    socklen_t addr_size = sizeof(struct in_addr);
+    if (getsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, (char*)&interface_addr, &addr_size) <  0) {
+        UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_NETWORK, "Multicast DNS: getsockopt(IP_MULTICAST_IF) failed");
+    }
+
+    if(IN_ZERONET(ntohl(interface_addr.s_addr))){
+        UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_NETWORK, "Multicast DNS: outbound interface 0.0.0.0, it means that the first OS interface is used (you can explicitly set the interface by using 'discovery.mdnsInterfaceIP' config parameter)");
+    }else{
+        char buf[16];
+        inet_ntop(AF_INET, &interface_addr, buf, 16);
+        UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_NETWORK, "Multicast DNS: outbound interface is %s", buf);
+    }
+
     mc.imr_multiaddr.s_addr = inet_addr("224.0.0.251");
     mc.imr_interface.s_addr = htonl(INADDR_ANY);
     UA_setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mc, sizeof(mc));
@@ -59,7 +97,7 @@ initMulticastDiscoveryServer(UA_DiscoveryManager *dm, UA_Server* server) {
     server->discoveryManager.mdnsDaemon = mdnsd_new(QCLASS_IN, 1000);
     UA_initialize_architecture_network();
 
-    if((server->discoveryManager.mdnsSocket = discovery_createMulticastSocket()) == UA_INVALID_SOCKET) {
+    if((server->discoveryManager.mdnsSocket = discovery_createMulticastSocket(server)) == UA_INVALID_SOCKET) {
         UA_LOG_SOCKET_ERRNO_WRAP(
                 UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER,
                      "Could not create multicast socket. Error: %s", errno_str));

+ 1 - 0
src/server/ua_server_config.c

@@ -17,6 +17,7 @@ UA_ServerConfig_clean(UA_ServerConfig *config) {
     UA_ApplicationDescription_deleteMembers(&config->applicationDescription);
 #ifdef UA_ENABLE_DISCOVERY_MULTICAST
     UA_MdnsDiscoveryConfiguration_clear(&config->discovery.mdns);
+    UA_String_clear(&config->discovery.mdnsInterfaceIP);
 #endif
 
     /* Custom DataTypes */