LCOV - code coverage report
Current view: top level - source4/nbt_server - interfaces.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 133 184 72.3 %
Date: 2024-02-28 12:06:22 Functions: 8 9 88.9 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    NBT interface handling
       5             : 
       6             :    Copyright (C) Andrew Tridgell        2005
       7             :    
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             :    
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             :    
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "includes.h"
      23             : #include "../lib/util/dlinklist.h"
      24             : #include "nbt_server/nbt_server.h"
      25             : #include "samba/service_task.h"
      26             : #include "lib/socket/socket.h"
      27             : #include "nbt_server/wins/winsserver.h"
      28             : #include "nbt_server/dgram/proto.h"
      29             : #include "system/network.h"
      30             : #include "lib/socket/netif.h"
      31             : #include "param/param.h"
      32             : #include "lib/util/util_net.h"
      33             : #include "lib/util/idtree.h"
      34             : 
      35             : /*
      36             :   receive an incoming request and dispatch it to the right place
      37             : */
      38       11713 : static void nbtd_request_handler(struct nbt_name_socket *nbtsock, 
      39             :                                  struct nbt_name_packet *packet, 
      40             :                                  struct socket_address *src)
      41             : {
      42       11713 :         struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
      43             :                                                        struct nbtd_interface);
      44       11713 :         struct nbtd_server *nbtsrv = iface->nbtsrv;
      45             : 
      46       11713 :         nbtsrv->stats.total_received++;
      47             : 
      48             :         /* see if it's from one of our own interfaces - if so, then ignore it */
      49       11713 :         if (nbtd_self_packet_and_bcast(nbtsock, packet, src)) {
      50           0 :                 DEBUG(10,("Ignoring bcast self packet from %s:%d\n", src->addr, src->port));
      51           0 :                 return;
      52             :         }
      53             : 
      54       11713 :         switch (packet->operation & NBT_OPCODE) {
      55        5908 :         case NBT_OPCODE_QUERY:
      56        5908 :                 nbtsrv->stats.query_count++;
      57        5908 :                 nbtd_request_query(nbtsock, packet, src);
      58        5908 :                 break;
      59             : 
      60        5507 :         case NBT_OPCODE_REGISTER:
      61             :         case NBT_OPCODE_REFRESH:
      62             :         case NBT_OPCODE_REFRESH2:
      63        5507 :                 nbtsrv->stats.register_count++;
      64        5507 :                 nbtd_request_defense(nbtsock, packet, src);
      65        5507 :                 break;
      66             : 
      67         298 :         case NBT_OPCODE_RELEASE:
      68             :         case NBT_OPCODE_MULTI_HOME_REG:
      69         298 :                 nbtsrv->stats.release_count++;
      70         298 :                 nbtd_winsserver_request(nbtsock, packet, src);
      71         298 :                 break;
      72             : 
      73           0 :         default:
      74           0 :                 nbtd_bad_packet(packet, src, "Unexpected opcode");
      75           0 :                 break;
      76             :         }
      77             : }
      78             : 
      79           0 : static void nbtd_unexpected_handler(struct nbt_name_socket *nbtsock,
      80             :                                     struct nbt_name_packet *packet,
      81             :                                     struct socket_address *src)
      82             : {
      83           0 :         struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
      84             :                                                        struct nbtd_interface);
      85           0 :         struct nbtd_server *nbtsrv = iface->nbtsrv;
      86           0 :         struct nbtd_interface *i;
      87           0 :         struct nbt_name_request *req = NULL;
      88             : 
      89           0 :         nbtsrv->stats.total_received++;
      90             : 
      91           0 :         DEBUG(10,("unexpected from src[%s] on interface[%p] %s/%s\n",
      92             :                 src->addr, iface, iface->ip_address, iface->netmask));
      93             : 
      94             :         /* try the broadcast interface */
      95           0 :         if (nbtsrv->bcast_interface) {
      96           0 :                 i = nbtsrv->bcast_interface;
      97           0 :                 req = idr_find(i->nbtsock->idr, packet->name_trn_id);
      98             :         }
      99             : 
     100             :         /* try the wins server client interface */
     101           0 :         if (!req && nbtsrv->wins_interface && nbtsrv->wins_interface->nbtsock) {
     102           0 :                 i = nbtsrv->wins_interface;
     103           0 :                 req = idr_find(i->nbtsock->idr, packet->name_trn_id);
     104             :         }
     105             : 
     106             :         /* try all other interfaces... */
     107           0 :         if (!req) {
     108           0 :                 for (i = nbtsrv->interfaces; i; i = i->next) {
     109           0 :                         if (i == iface) {
     110           0 :                                 continue;
     111             :                         }
     112           0 :                         req = idr_find(i->nbtsock->idr, packet->name_trn_id);
     113           0 :                         if (req) break;
     114             :                 }
     115             :         }
     116             : 
     117           0 :         if (!req) {
     118           0 :                 DEBUG(10,("unexpected from src[%s] unable to redirected\n", src->addr));
     119           0 :                 return;
     120             :         }
     121             : 
     122           0 :         DEBUG(10,("unexpected from src[%s] redirected to interface[%p] %s/%s\n",
     123             :                 src->addr, i, i->ip_address, i->netmask));
     124             : 
     125             :         /*
     126             :          * redirect the incoming response to the socket
     127             :          * we sent the matching request
     128             :          */
     129           0 :         nbt_name_socket_handle_response_packet(req, packet, src);
     130             : }
     131             : 
     132             : /*
     133             :   find a registered name on an interface
     134             : */
     135        9936 : struct nbtd_iface_name *nbtd_find_iname(struct nbtd_interface *iface, 
     136             :                                         struct nbt_name *name, 
     137             :                                         uint16_t nb_flags)
     138             : {
     139          61 :         struct nbtd_iface_name *iname;
     140       88261 :         for (iname=iface->names;iname;iname=iname->next) {
     141       79897 :                 if (iname->name.type == name->type &&
     142       18065 :                     strcmp(name->name, iname->name.name) == 0 &&
     143        1572 :                     ((iname->nb_flags & nb_flags) == nb_flags)) {
     144        1572 :                         return iname;
     145             :                 }
     146             :         }
     147        8342 :         return NULL;
     148             : }
     149             : 
     150             : /*
     151             :   start listening on the given address
     152             : */
     153         130 : static NTSTATUS nbtd_add_socket(struct nbtd_server *nbtsrv, 
     154             :                                 struct loadparm_context *lp_ctx,
     155             :                                 const char *bind_address, 
     156             :                                 const char *address, 
     157             :                                 const char *bcast, 
     158             :                                 const char *netmask)
     159             : {
     160           4 :         struct nbtd_interface *iface;
     161           4 :         NTSTATUS status;
     162           4 :         struct socket_address *bcast_address;
     163           4 :         struct socket_address *unicast_address;
     164             : 
     165         130 :         DEBUG(6,("nbtd_add_socket(%s, %s, %s, %s)\n", bind_address, address, bcast, netmask));
     166             : 
     167             :         /*
     168             :           we actually create two sockets. One listens on the broadcast address
     169             :           for the interface, and the other listens on our specific address. This
     170             :           allows us to run with "bind interfaces only" while still receiving 
     171             :           broadcast addresses, and also simplifies matching incoming requests 
     172             :           to interfaces
     173             :         */
     174             : 
     175         130 :         iface = talloc(nbtsrv, struct nbtd_interface);
     176         130 :         NT_STATUS_HAVE_NO_MEMORY(iface);
     177             : 
     178         130 :         iface->nbtsrv        = nbtsrv;
     179         130 :         iface->bcast_address = talloc_steal(iface, bcast);
     180         130 :         iface->ip_address    = talloc_steal(iface, address);
     181         130 :         iface->netmask       = talloc_steal(iface, netmask);
     182         130 :         iface->names         = NULL;
     183         130 :         iface->wack_queue    = NULL;
     184             : 
     185         130 :         if (strcmp(netmask, "0.0.0.0") != 0) {
     186           2 :                 struct nbt_name_socket *bcast_nbtsock;
     187             : 
     188             :                 /* listen for broadcasts on port 137 */
     189          65 :                 bcast_nbtsock = nbt_name_socket_init(iface, nbtsrv->task->event_ctx);
     190          65 :                 if (!bcast_nbtsock) {
     191           0 :                         talloc_free(iface);
     192           0 :                         return NT_STATUS_NO_MEMORY;
     193             :                 }
     194             : 
     195          65 :                 bcast_address = socket_address_from_strings(bcast_nbtsock, bcast_nbtsock->sock->backend_name, 
     196             :                                                             bcast, lpcfg_nbt_port(lp_ctx));
     197          65 :                 if (!bcast_address) {
     198           0 :                         talloc_free(iface);
     199           0 :                         return NT_STATUS_NO_MEMORY;
     200             :                 }
     201             : 
     202          65 :                 status = socket_listen(bcast_nbtsock->sock, bcast_address, 0, 0);
     203          65 :                 if (!NT_STATUS_IS_OK(status)) {
     204           0 :                         DEBUG(0,("Failed to bind to %s:%d - %s\n", 
     205             :                                  bcast, lpcfg_nbt_port(lp_ctx), nt_errstr(status)));
     206           0 :                         talloc_free(iface);
     207           0 :                         return status;
     208             :                 }
     209          65 :                 talloc_free(bcast_address);
     210             : 
     211          65 :                 nbt_set_incoming_handler(bcast_nbtsock, nbtd_request_handler, iface);
     212             :         }
     213             : 
     214             :         /* listen for unicasts on port 137 */
     215         130 :         iface->nbtsock = nbt_name_socket_init(iface, nbtsrv->task->event_ctx);
     216         130 :         if (!iface->nbtsock) {
     217           0 :                 talloc_free(iface);
     218           0 :                 return NT_STATUS_NO_MEMORY;
     219             :         }
     220             : 
     221         130 :         unicast_address = socket_address_from_strings(iface->nbtsock, 
     222         130 :                                                       iface->nbtsock->sock->backend_name, 
     223             :                                                       bind_address, lpcfg_nbt_port(lp_ctx));
     224             : 
     225         130 :         status = socket_listen(iface->nbtsock->sock, unicast_address, 0, 0);
     226         130 :         if (!NT_STATUS_IS_OK(status)) {
     227           0 :                 DEBUG(0,("Failed to bind to %s:%d - %s\n", 
     228             :                          bind_address, lpcfg_nbt_port(lp_ctx), nt_errstr(status)));
     229           0 :                 talloc_free(iface);
     230           0 :                 return status;
     231             :         }
     232         130 :         talloc_free(unicast_address);
     233             : 
     234         130 :         nbt_set_incoming_handler(iface->nbtsock, nbtd_request_handler, iface);
     235         130 :         nbt_set_unexpected_handler(iface->nbtsock, nbtd_unexpected_handler, iface);
     236             : 
     237             :         /* also setup the datagram listeners */
     238         130 :         status = nbtd_dgram_setup(iface, bind_address);
     239         130 :         if (!NT_STATUS_IS_OK(status)) {
     240           0 :                 DEBUG(0,("Failed to setup dgram listen on %s - %s\n", 
     241             :                          bind_address, nt_errstr(status)));
     242           0 :                 talloc_free(iface);
     243           0 :                 return status;
     244             :         }
     245             :         
     246         130 :         if (strcmp(netmask, "0.0.0.0") == 0) {
     247          65 :                 DLIST_ADD(nbtsrv->bcast_interface, iface);
     248             :         } else {
     249          65 :                 DLIST_ADD(nbtsrv->interfaces, iface);
     250             :         }
     251             : 
     252         130 :         return NT_STATUS_OK;
     253             : }
     254             : 
     255             : /*
     256             :   setup a socket for talking to our WINS servers
     257             : */
     258          65 : static NTSTATUS nbtd_add_wins_socket(struct nbtd_server *nbtsrv)
     259             : {
     260           2 :         struct nbtd_interface *iface;
     261             : 
     262          65 :         iface = talloc_zero(nbtsrv, struct nbtd_interface);
     263          65 :         NT_STATUS_HAVE_NO_MEMORY(iface);
     264             : 
     265          65 :         iface->nbtsrv        = nbtsrv;
     266             : 
     267          65 :         DLIST_ADD(nbtsrv->wins_interface, iface);
     268             : 
     269          65 :         return NT_STATUS_OK;
     270             : }
     271             : 
     272             : 
     273             : /*
     274             :   setup our listening sockets on the configured network interfaces
     275             : */
     276          65 : NTSTATUS nbtd_startup_interfaces(struct nbtd_server *nbtsrv, struct loadparm_context *lp_ctx,
     277             :                                  struct interface *ifaces)
     278             : {
     279          65 :         int num_interfaces = iface_list_count(ifaces);
     280           2 :         int i;
     281          65 :         TALLOC_CTX *tmp_ctx = talloc_new(nbtsrv);
     282           2 :         NTSTATUS status;
     283             : 
     284             :         /* if we are allowing incoming packets from any address, then
     285             :            we also need to bind to the wildcard address */
     286          65 :         if (!lpcfg_bind_interfaces_only(lp_ctx)) {
     287           2 :                 const char *primary_address;
     288             : 
     289          65 :                 primary_address = iface_list_first_v4(ifaces);
     290             : 
     291             :                 /* the primary address is the address we will return
     292             :                    for non-WINS queries not made on a specific
     293             :                    interface */
     294          65 :                 if (primary_address == NULL) {
     295           0 :                         primary_address = inet_ntoa(interpret_addr2(
     296             :                                                             lpcfg_netbios_name(lp_ctx)));
     297             :                 }
     298             : 
     299          65 :                 primary_address = talloc_strdup(tmp_ctx, primary_address);
     300          65 :                 NT_STATUS_HAVE_NO_MEMORY(primary_address);
     301             : 
     302          65 :                 status = nbtd_add_socket(nbtsrv, 
     303             :                                          lp_ctx,
     304             :                                          "0.0.0.0",
     305             :                                          primary_address,
     306          65 :                                          talloc_strdup(tmp_ctx, "255.255.255.255"),
     307          65 :                                          talloc_strdup(tmp_ctx, "0.0.0.0"));
     308          65 :                 NT_STATUS_NOT_OK_RETURN(status);
     309             :         }
     310             : 
     311         195 :         for (i=0; i<num_interfaces; i++) {
     312           4 :                 const char *bcast;
     313           4 :                 const char *address, *netmask;
     314             : 
     315         130 :                 if (!iface_list_n_is_v4(ifaces, i)) {
     316             :                         /* v4 only for NBT protocol */
     317          65 :                         continue;
     318             :                 }
     319             : 
     320          65 :                 bcast = iface_list_n_bcast(ifaces, i);
     321             :                 /* we can't assume every interface is broadcast capable */
     322          65 :                 if (bcast == NULL) continue;
     323             : 
     324          65 :                 address = talloc_strdup(tmp_ctx, iface_list_n_ip(ifaces, i));
     325          65 :                 bcast   = talloc_strdup(tmp_ctx, bcast);
     326          65 :                 netmask = talloc_strdup(tmp_ctx, iface_list_n_netmask(ifaces, i));
     327             : 
     328          65 :                 status = nbtd_add_socket(nbtsrv, lp_ctx,
     329             :                                          address, address, bcast, netmask);
     330          67 :                 NT_STATUS_NOT_OK_RETURN(status);
     331             :         }
     332             : 
     333          65 :         if (lpcfg_wins_server_list(lp_ctx)) {
     334          65 :                 status = nbtd_add_wins_socket(nbtsrv);
     335          65 :                 NT_STATUS_NOT_OK_RETURN(status);
     336             :         }
     337             : 
     338          65 :         talloc_free(tmp_ctx);
     339             : 
     340          65 :         return NT_STATUS_OK;
     341             : }
     342             : 
     343             : 
     344             : /*
     345             :   form a list of addresses that we should use in name query replies
     346             :   we always place the IP in the given interface first
     347             : */
     348        1447 : const char **nbtd_address_list(struct nbtd_interface *iface, TALLOC_CTX *mem_ctx)
     349             : {
     350        1447 :         struct nbtd_server *nbtsrv = iface->nbtsrv;
     351        1447 :         const char **ret = NULL;
     352          36 :         struct nbtd_interface *iface2;
     353        1447 :         bool is_loopback = false;
     354             : 
     355        1447 :         if (iface->ip_address) {
     356        1058 :                 is_loopback = iface_list_same_net(iface->ip_address, "127.0.0.1", "255.0.0.0");
     357        1058 :                 ret = str_list_add(ret, iface->ip_address);
     358             :         }
     359             : 
     360        2894 :         for (iface2=nbtsrv->interfaces;iface2;iface2=iface2->next) {
     361        1447 :                 if (iface2 == iface) continue;
     362             : 
     363         389 :                 if (!iface2->ip_address) continue;
     364             : 
     365         389 :                 if (!is_loopback) {
     366         389 :                         if (iface_list_same_net(iface2->ip_address, "127.0.0.1", "255.0.0.0")) {
     367           0 :                                 continue;
     368             :                         }
     369             :                 }
     370             : 
     371         389 :                 ret = str_list_add(ret, iface2->ip_address);
     372             :         }
     373             : 
     374        1447 :         talloc_steal(mem_ctx, ret);
     375             : 
     376        1447 :         return ret;
     377             : }
     378             : 
     379             : 
     380             : /*
     381             :   find the interface to use for sending a outgoing request
     382             : */
     383          49 : struct nbtd_interface *nbtd_find_request_iface(struct nbtd_server *nbtd_server,
     384             :                                                const char *address, bool allow_bcast_iface)
     385             : {
     386           0 :         struct nbtd_interface *cur;
     387             : 
     388             :         /* try to find a exact match */
     389          59 :         for (cur=nbtd_server->interfaces;cur;cur=cur->next) {
     390          49 :                 if (iface_list_same_net(address, cur->ip_address, cur->netmask)) {
     391          39 :                         DEBUG(10,("find interface for dst[%s] ip: %s/%s (iface[%p])\n",
     392             :                                   address, cur->ip_address, cur->netmask, cur));
     393          39 :                         return cur;
     394             :                 }
     395             :         }
     396             : 
     397             :         /* no exact match, if we have the broadcast interface, use that */
     398          10 :         if (allow_bcast_iface && nbtd_server->bcast_interface) {
     399          10 :                 cur = nbtd_server->bcast_interface;
     400          10 :                 DEBUG(10,("find interface for dst[%s] ip: %s/%s (bcast iface[%p])\n",
     401             :                         address, cur->ip_address, cur->netmask, cur));
     402          10 :                 return cur;
     403             :         }
     404             : 
     405             :         /* fallback to first interface */
     406           0 :         cur = nbtd_server->interfaces;
     407           0 :         DEBUG(10,("find interface for dst[%s] ip: %s/%s (default iface[%p])\n",
     408             :                 address, cur->ip_address, cur->netmask, cur));
     409           0 :         return cur;
     410             : }
     411             : 
     412             : /*
     413             :  * find the interface to use for sending a outgoing reply
     414             :  */
     415          28 : struct nbtd_interface *nbtd_find_reply_iface(struct nbtd_interface *iface,
     416             :                                              const char *address, bool allow_bcast_iface)
     417             : {
     418          28 :         struct nbtd_server *nbtd_server = iface->nbtsrv;
     419             : 
     420             :         /* first try to use the given interfacel when it's not the broadcast one */
     421          28 :         if (iface != nbtd_server->bcast_interface) {
     422          28 :                 return iface;
     423             :         }
     424             : 
     425           0 :         return nbtd_find_request_iface(nbtd_server, address, allow_bcast_iface);
     426             : }

Generated by: LCOV version 1.14