r25546: Convert to standard bool type.
[garming/samba-autobuild/.git] / source4 / nbt_server / interfaces.c
index a75275dec7b60e40b0314ebfeb3ebeaa53542c92..f2a875142a8ae5fc2f8214c8ac4a839d429dbb9d 100644 (file)
@@ -7,7 +7,7 @@
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
-#include "dlinklist.h"
+#include "lib/util/dlinklist.h"
 #include "nbt_server/nbt_server.h"
 #include "smbd/service_task.h"
+#include "lib/socket/socket.h"
+#include "nbt_server/wins/winsserver.h"
+#include "nbt_server/dgram/proto.h"
+#include "system/network.h"
+#include "lib/socket/netif.h"
+#include "param/param.h"
 
 
 /*
 */
 static void nbtd_request_handler(struct nbt_name_socket *nbtsock, 
                                 struct nbt_name_packet *packet, 
-                                const char *src_address, int src_port)
+                                struct socket_address *src)
 {
-       /* if its a WINS query then direct to our WINS server if we
-          are running one */
-       if ((packet->operation & NBT_FLAG_RECURSION_DESIRED) &&
-           !(packet->operation & NBT_FLAG_BROADCAST) &&
-           lp_wins_support()) {
-               nbtd_query_wins(nbtsock, packet, src_address, src_port);
-               return;
-       }
+       struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, 
+                                                      struct nbtd_interface);
+       struct nbtd_server *nbtsrv = iface->nbtsrv;
+
+       nbtsrv->stats.total_received++;
 
        /* see if its from one of our own interfaces - if so, then ignore it */
-       if (nbtd_self_packet(nbtsock, packet, src_address, src_port)) {
-               DEBUG(10,("Ignoring self packet from %s:%d\n", src_address, src_port));
+       if (nbtd_self_packet_and_bcast(nbtsock, packet, src)) {
+               DEBUG(10,("Ignoring bcast self packet from %s:%d\n", src->addr, src->port));
                return;
        }
 
-       /* the request is to us in our role as a B node */
        switch (packet->operation & NBT_OPCODE) {
        case NBT_OPCODE_QUERY:
-               nbtd_request_query(nbtsock, packet, src_address, src_port);
+               nbtsrv->stats.query_count++;
+               nbtd_request_query(nbtsock, packet, src);
                break;
 
        case NBT_OPCODE_REGISTER:
        case NBT_OPCODE_REFRESH:
-               nbtd_request_defense(nbtsock, packet, src_address, src_port);
+       case NBT_OPCODE_REFRESH2:
+               nbtsrv->stats.register_count++;
+               nbtd_request_defense(nbtsock, packet, src);
+               break;
+
+       case NBT_OPCODE_RELEASE:
+       case NBT_OPCODE_MULTI_HOME_REG:
+               nbtsrv->stats.release_count++;
+               nbtd_winsserver_request(nbtsock, packet, src);
                break;
 
        default:
-               nbtd_bad_packet(packet, src_address, "Unexpected opcode");
+               nbtd_bad_packet(packet, src, "Unexpected opcode");
                break;
        }
 }
 
 
-
 /*
   find a registered name on an interface
 */
@@ -77,7 +86,7 @@ struct nbtd_iface_name *nbtd_find_iname(struct nbtd_interface *iface,
        struct nbtd_iface_name *iname;
        for (iname=iface->names;iname;iname=iname->next) {
                if (iname->name.type == name->type &&
-                   StrCaseCmp(name->name, iname->name.name) == 0 &&
+                   strcmp(name->name, iname->name.name) == 0 &&
                    ((iname->nb_flags & nb_flags) == nb_flags)) {
                        return iname;
                }
@@ -96,7 +105,8 @@ static NTSTATUS nbtd_add_socket(struct nbtd_server *nbtsrv,
 {
        struct nbtd_interface *iface;
        NTSTATUS status;
-       struct nbt_name_socket *bcast_nbtsock;
+       struct socket_address *bcast_address;
+       struct socket_address *unicast_address;
 
        /*
          we actually create two sockets. One listens on the broadcast address
@@ -116,36 +126,65 @@ static NTSTATUS nbtd_add_socket(struct nbtd_server *nbtsrv,
        iface->names         = NULL;
 
        if (strcmp(netmask, "0.0.0.0") != 0) {
+               struct nbt_name_socket *bcast_nbtsock;
+
+               /* listen for broadcasts on port 137 */
                bcast_nbtsock = nbt_name_socket_init(iface, nbtsrv->task->event_ctx);
-               NT_STATUS_HAVE_NO_MEMORY(bcast_nbtsock);
+               if (!bcast_nbtsock) {
+                       talloc_free(iface);
+                       return NT_STATUS_NO_MEMORY;
+               }
+
+               bcast_address = socket_address_from_strings(bcast_nbtsock, bcast_nbtsock->sock->backend_name, 
+                                                           bcast, lp_nbt_port(global_loadparm));
+               if (!bcast_address) {
+                       talloc_free(iface);
+                       return NT_STATUS_NO_MEMORY;
+               }
 
-               status = socket_listen(bcast_nbtsock->sock, bcast, lp_nbt_port(), 0, 0);
+               status = socket_listen(bcast_nbtsock->sock, bcast_address, 0, 0);
                if (!NT_STATUS_IS_OK(status)) {
                        DEBUG(0,("Failed to bind to %s:%d - %s\n", 
-                                bcast, lp_nbt_port(), nt_errstr(status)));
+                                bcast, lp_nbt_port(global_loadparm), nt_errstr(status)));
                        talloc_free(iface);
                        return status;
                }
+               talloc_free(bcast_address);
 
                nbt_set_incoming_handler(bcast_nbtsock, nbtd_request_handler, iface);
        }
 
+       /* listen for unicasts on port 137 */
        iface->nbtsock = nbt_name_socket_init(iface, nbtsrv->task->event_ctx);
-       NT_STATUS_HAVE_NO_MEMORY(iface->ip_address);
+       if (!iface->nbtsock) {
+               talloc_free(iface);
+               return NT_STATUS_NO_MEMORY;
+       }
 
-       status = socket_listen(iface->nbtsock->sock, bind_address, lp_nbt_port(), 0, 0);
+       unicast_address = socket_address_from_strings(iface->nbtsock, 
+                                                     iface->nbtsock->sock->backend_name, 
+                                                     bind_address, lp_nbt_port(global_loadparm));
+
+       status = socket_listen(iface->nbtsock->sock, unicast_address, 0, 0);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(0,("Failed to bind to %s:%d - %s\n", 
-                        address, lp_nbt_port(), nt_errstr(status)));
+                        bind_address, lp_nbt_port(global_loadparm), nt_errstr(status)));
                talloc_free(iface);
                return status;
        }
-
-       /* we need to be able to send broadcasts out */
-       socket_set_option(iface->nbtsock->sock, "SO_BROADCAST", "1");
+       talloc_free(unicast_address);
 
        nbt_set_incoming_handler(iface->nbtsock, nbtd_request_handler, iface);
 
+       /* also setup the datagram listeners */
+       status = nbtd_dgram_setup(iface, bind_address);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0,("Failed to setup dgram listen on %s - %s\n", 
+                        bind_address, nt_errstr(status)));
+               talloc_free(iface);
+               return status;
+       }
+       
        if (strcmp(netmask, "0.0.0.0") == 0) {
                DLIST_ADD(nbtsrv->bcast_interface, iface);
        } else {
@@ -155,7 +194,6 @@ static NTSTATUS nbtd_add_socket(struct nbtd_server *nbtsrv,
        return NT_STATUS_OK;
 }
 
-
 /*
   setup a socket for talking to our WINS servers
 */
@@ -168,9 +206,6 @@ static NTSTATUS nbtd_add_wins_socket(struct nbtd_server *nbtsrv)
 
        iface->nbtsrv        = nbtsrv;
 
-       iface->nbtsock = nbt_name_socket_init(iface, nbtsrv->task->event_ctx);
-       NT_STATUS_HAVE_NO_MEMORY(iface->nbtsock);
-
        DLIST_ADD(nbtsrv->wins_interface, iface);
 
        return NT_STATUS_OK;
@@ -189,17 +224,17 @@ NTSTATUS nbtd_startup_interfaces(struct nbtd_server *nbtsrv)
 
        /* if we are allowing incoming packets from any address, then
           we also need to bind to the wildcard address */
-       if (!lp_bind_interfaces_only()) {
+       if (!lp_bind_interfaces_only(global_loadparm)) {
                const char *primary_address;
 
                /* the primary address is the address we will return
                   for non-WINS queries not made on a specific
                   interface */
                if (num_interfaces > 0) {
-                       primary_address = sys_inet_ntoa(*iface_n_ip(0));
+                       primary_address = iface_n_ip(0);
                } else {
                        primary_address = sys_inet_ntoa(interpret_addr2(
-                                                               lp_netbios_name()));
+                                                       lp_netbios_name(global_loadparm)));
                }
                primary_address = talloc_strdup(tmp_ctx, primary_address);
                NT_STATUS_HAVE_NO_MEMORY(primary_address);
@@ -213,15 +248,21 @@ NTSTATUS nbtd_startup_interfaces(struct nbtd_server *nbtsrv)
        }
 
        for (i=0; i<num_interfaces; i++) {
-               const char *address = talloc_strdup(tmp_ctx, sys_inet_ntoa(*iface_n_ip(i)));
-               const char *bcast   = talloc_strdup(tmp_ctx, sys_inet_ntoa(*iface_n_bcast(i)));
-               const char *netmask = talloc_strdup(tmp_ctx, sys_inet_ntoa(*iface_n_netmask(i)));
+               const char *bcast = iface_n_bcast(i);
+               const char *address, *netmask;
+
+               /* we can't assume every interface is broadcast capable */
+               if (bcast == NULL) continue;
+
+               address = talloc_strdup(tmp_ctx, iface_n_ip(i));
+               bcast   = talloc_strdup(tmp_ctx, bcast);
+               netmask = talloc_strdup(tmp_ctx, iface_n_netmask(i));
 
                status = nbtd_add_socket(nbtsrv, address, address, bcast, netmask);
                NT_STATUS_NOT_OK_RETURN(status);
        }
 
-       if (lp_wins_server_list()) {
+       if (lp_wins_server_list(global_loadparm)) {
                status = nbtd_add_wins_socket(nbtsrv);
                NT_STATUS_NOT_OK_RETURN(status);
        }
@@ -241,35 +282,69 @@ const char **nbtd_address_list(struct nbtd_interface *iface, TALLOC_CTX *mem_ctx
        struct nbtd_server *nbtsrv = iface->nbtsrv;
        const char **ret = NULL;
        struct nbtd_interface *iface2;
-       int count;
+       bool is_loopback = false;
 
-       ret = talloc_array(mem_ctx, const char *, 2);
-       if (ret == NULL) goto failed;
-
-       ret[0] = talloc_strdup(ret, iface->ip_address);
-       if (ret[0] == NULL) goto failed;
-       ret[1] = NULL;
-
-       count = 1;
+       if (iface->ip_address) {
+               is_loopback = iface_same_net(iface->ip_address, "127.0.0.1", "255.0.0.0");
+               ret = str_list_add(ret, iface->ip_address);
+       }
 
        for (iface2=nbtsrv->interfaces;iface2;iface2=iface2->next) {
-               const char **ret2;
+               if (iface2 == iface) continue;
+
+               if (!iface2->ip_address) continue;
 
-               if (strcmp(iface2->ip_address, iface->ip_address) == 0) {
-                       continue;
+               if (!is_loopback) {
+                       if (iface_same_net(iface2->ip_address, "127.0.0.1", "255.0.0.0")) {
+                               continue;
+                       }
                }
 
-               ret2 = talloc_realloc(mem_ctx, ret, const char *, count+2);
-               if (ret2 == NULL) goto failed;
-               ret = ret2;
-               ret[count] = talloc_strdup(ret, iface2->ip_address);
-               if (ret[count] == NULL) goto failed;
-               count++;
+               ret = str_list_add(ret, iface2->ip_address);
        }
-       ret[count] = NULL;
+
+       talloc_steal(mem_ctx, ret);
+
        return ret;
+}
 
-failed:
-       talloc_free(ret);
-       return NULL;
+
+/*
+  find the interface to use for sending a outgoing request
+*/
+struct nbtd_interface *nbtd_find_request_iface(struct nbtd_server *nbtd_server,
+                                              const char *address, bool allow_bcast_iface)
+{
+       struct nbtd_interface *cur;
+
+       /* try to find a exact match */
+       for (cur=nbtd_server->interfaces;cur;cur=cur->next) {
+               if (iface_same_net(address, cur->ip_address, cur->netmask)) {
+                       return cur;
+               }
+       }
+
+       /* no exact match, if we have the broadcast interface, use that */
+       if (allow_bcast_iface && nbtd_server->bcast_interface) {
+               return nbtd_server->bcast_interface;
+       }
+
+       /* fallback to first interface */
+       return nbtd_server->interfaces;
+}
+
+/*
+ * find the interface to use for sending a outgoing reply
+ */
+struct nbtd_interface *nbtd_find_reply_iface(struct nbtd_interface *iface,
+                                            const char *address, bool allow_bcast_iface)
+{
+       struct nbtd_server *nbtd_server = iface->nbtsrv;
+
+       /* first try to use the given interfacel when it's not the broadcast one */
+       if (iface != nbtd_server->bcast_interface) {
+               return iface;
+       }
+
+       return nbtd_find_request_iface(nbtd_server, address, allow_bcast_iface);
 }