LCOV - code coverage report
Current view: top level - source4/nbt_server - interfaces.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 160 197 81.2 %
Date: 2024-05-31 13:13:24 Functions: 9 9 100.0 %

          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             : #include "../source3/include/fstring.h"
      35             : #include "../source3/libsmb/nmblib.h"
      36             : #include "../source3/libsmb/unexpected.h"
      37             : 
      38             : /*
      39             :   receive an incoming request and dispatch it to the right place
      40             : */
      41       12803 : static void nbtd_request_handler(struct nbt_name_socket *nbtsock, 
      42             :                                  struct nbt_name_packet *packet, 
      43             :                                  struct socket_address *src)
      44             : {
      45       12803 :         struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
      46             :                                                        struct nbtd_interface);
      47       12803 :         struct nbtd_server *nbtsrv = iface->nbtsrv;
      48             : 
      49       12803 :         nbtsrv->stats.total_received++;
      50             : 
      51             :         /* see if it's from one of our own interfaces - if so, then ignore it */
      52       12803 :         if (nbtd_self_packet_and_bcast(nbtsock, packet, src)) {
      53           0 :                 DEBUG(10,("Ignoring bcast self packet from %s:%d\n", src->addr, src->port));
      54           0 :                 return;
      55             :         }
      56             : 
      57       12803 :         switch (packet->operation & NBT_OPCODE) {
      58        7025 :         case NBT_OPCODE_QUERY:
      59        7025 :                 nbtsrv->stats.query_count++;
      60        7025 :                 nbtd_request_query(nbtsock, packet, src);
      61        7025 :                 break;
      62             : 
      63        5480 :         case NBT_OPCODE_REGISTER:
      64             :         case NBT_OPCODE_REFRESH:
      65             :         case NBT_OPCODE_REFRESH2:
      66        5480 :                 nbtsrv->stats.register_count++;
      67        5480 :                 nbtd_request_defense(nbtsock, packet, src);
      68        5480 :                 break;
      69             : 
      70         298 :         case NBT_OPCODE_RELEASE:
      71             :         case NBT_OPCODE_MULTI_HOME_REG:
      72         298 :                 nbtsrv->stats.release_count++;
      73         298 :                 nbtd_winsserver_request(nbtsock, packet, src);
      74         298 :                 break;
      75             : 
      76           0 :         default:
      77           0 :                 nbtd_bad_packet(packet, src, "Unexpected opcode");
      78           0 :                 break;
      79             :         }
      80             : }
      81             : 
      82           1 : static void nbtd_unexpected_handler(struct nbt_name_socket *nbtsock,
      83             :                                     struct nbt_name_packet *packet,
      84             :                                     struct socket_address *src)
      85             : {
      86           1 :         struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
      87             :                                                        struct nbtd_interface);
      88           1 :         struct nbtd_server *nbtsrv = iface->nbtsrv;
      89           0 :         struct nbtd_interface *i;
      90           1 :         struct nbt_name_request *req = NULL;
      91             : 
      92           1 :         nbtsrv->stats.total_received++;
      93             : 
      94           1 :         DEBUG(10,("unexpected from src[%s] on interface[%p] %s/%s\n",
      95             :                 src->addr, iface, iface->ip_address, iface->netmask));
      96             : 
      97             :         /* try the broadcast interface */
      98           1 :         if (nbtsrv->bcast_interface) {
      99           1 :                 i = nbtsrv->bcast_interface;
     100           1 :                 req = idr_find(i->nbtsock->idr, packet->name_trn_id);
     101             :         }
     102             : 
     103             :         /* try the wins server client interface */
     104           1 :         if (!req && nbtsrv->wins_interface && nbtsrv->wins_interface->nbtsock) {
     105           0 :                 i = nbtsrv->wins_interface;
     106           0 :                 req = idr_find(i->nbtsock->idr, packet->name_trn_id);
     107             :         }
     108             : 
     109             :         /* try all other interfaces... */
     110           1 :         if (!req) {
     111           2 :                 for (i = nbtsrv->interfaces; i; i = i->next) {
     112           1 :                         if (i == iface) {
     113           1 :                                 continue;
     114             :                         }
     115           0 :                         req = idr_find(i->nbtsock->idr, packet->name_trn_id);
     116           0 :                         if (req) break;
     117             :                 }
     118             :         }
     119             : 
     120           1 :         if (!req) {
     121           1 :                 struct packet_struct *pstruct = NULL;
     122           1 :                 DATA_BLOB blob = { .length = 0, };
     123           0 :                 enum ndr_err_code ndr_err;
     124             : 
     125             :                 /*
     126             :                  * Here we have NBT_FLAG_REPLY
     127             :                  */
     128           1 :                 DEBUG(10,("unexpected from src[%s] unable to redirected\n", src->addr));
     129             : 
     130           1 :                 ndr_err = ndr_push_struct_blob(&blob, packet, packet,
     131             :                                 (ndr_push_flags_fn_t)ndr_push_nbt_name_packet);
     132           1 :                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     133           0 :                         DBG_ERR("ndr_push_nbt_name_packet - %s\n",
     134             :                                 ndr_errstr(ndr_err));
     135           0 :                         return;
     136             :                 }
     137             : 
     138           2 :                 pstruct = parse_packet((char *)blob.data,
     139           1 :                                        blob.length,
     140             :                                        NMB_PACKET,
     141           1 :                                        interpret_addr2(src->addr),
     142             :                                        src->port);
     143           1 :                 if (pstruct != NULL) {
     144           1 :                         nb_packet_dispatch(nbtsrv->unexpected_server, pstruct);
     145           1 :                         free_packet(pstruct);
     146             :                 }
     147             : 
     148           1 :                 return;
     149             :         }
     150             : 
     151           0 :         DEBUG(10,("unexpected from src[%s] redirected to interface[%p] %s/%s\n",
     152             :                 src->addr, i, i->ip_address, i->netmask));
     153             : 
     154             :         /*
     155             :          * redirect the incoming response to the socket
     156             :          * we sent the matching request
     157             :          */
     158           0 :         nbt_name_socket_handle_response_packet(req, packet, src);
     159             : }
     160             : 
     161             : /*
     162             :   find a registered name on an interface
     163             : */
     164       11049 : struct nbtd_iface_name *nbtd_find_iname(struct nbtd_interface *iface, 
     165             :                                         struct nbt_name *name, 
     166             :                                         uint16_t nb_flags)
     167             : {
     168          61 :         struct nbtd_iface_name *iname;
     169       99351 :         for (iname=iface->names;iname;iname=iname->next) {
     170       89872 :                 if (iname->name.type == name->type &&
     171       19144 :                     strcmp(name->name, iname->name.name) == 0 &&
     172        1570 :                     ((iname->nb_flags & nb_flags) == nb_flags)) {
     173        1570 :                         return iname;
     174             :                 }
     175             :         }
     176        9457 :         return NULL;
     177             : }
     178             : 
     179             : /*
     180             :   start listening on the given address
     181             : */
     182         130 : static NTSTATUS nbtd_add_socket(struct nbtd_server *nbtsrv, 
     183             :                                 struct loadparm_context *lp_ctx,
     184             :                                 const char *bind_address, 
     185             :                                 const char *address, 
     186             :                                 const char *bcast, 
     187             :                                 const char *netmask)
     188             : {
     189           4 :         struct nbtd_interface *iface;
     190           4 :         NTSTATUS status;
     191           4 :         struct socket_address *bcast_address;
     192           4 :         struct socket_address *unicast_address;
     193             : 
     194         130 :         DEBUG(6,("nbtd_add_socket(%s, %s, %s, %s)\n", bind_address, address, bcast, netmask));
     195             : 
     196             :         /*
     197             :           we actually create two sockets. One listens on the broadcast address
     198             :           for the interface, and the other listens on our specific address. This
     199             :           allows us to run with "bind interfaces only" while still receiving 
     200             :           broadcast addresses, and also simplifies matching incoming requests 
     201             :           to interfaces
     202             :         */
     203             : 
     204         130 :         iface = talloc(nbtsrv, struct nbtd_interface);
     205         130 :         NT_STATUS_HAVE_NO_MEMORY(iface);
     206             : 
     207         130 :         iface->nbtsrv        = nbtsrv;
     208         130 :         iface->bcast_address = talloc_steal(iface, bcast);
     209         130 :         iface->ip_address    = talloc_steal(iface, address);
     210         130 :         iface->netmask       = talloc_steal(iface, netmask);
     211         130 :         iface->names         = NULL;
     212         130 :         iface->wack_queue    = NULL;
     213             : 
     214         130 :         if (strcmp(netmask, "0.0.0.0") != 0) {
     215           2 :                 struct nbt_name_socket *bcast_nbtsock;
     216             : 
     217             :                 /* listen for broadcasts on port 137 */
     218          65 :                 bcast_nbtsock = nbt_name_socket_init(iface, nbtsrv->task->event_ctx);
     219          65 :                 if (!bcast_nbtsock) {
     220           0 :                         talloc_free(iface);
     221           0 :                         return NT_STATUS_NO_MEMORY;
     222             :                 }
     223             : 
     224          65 :                 bcast_address = socket_address_from_strings(bcast_nbtsock, bcast_nbtsock->sock->backend_name, 
     225             :                                                             bcast, lpcfg_nbt_port(lp_ctx));
     226          65 :                 if (!bcast_address) {
     227           0 :                         talloc_free(iface);
     228           0 :                         return NT_STATUS_NO_MEMORY;
     229             :                 }
     230             : 
     231          65 :                 status = socket_listen(bcast_nbtsock->sock, bcast_address, 0, 0);
     232          65 :                 if (!NT_STATUS_IS_OK(status)) {
     233           0 :                         DEBUG(0,("Failed to bind to %s:%d - %s\n", 
     234             :                                  bcast, lpcfg_nbt_port(lp_ctx), nt_errstr(status)));
     235           0 :                         talloc_free(iface);
     236           0 :                         return status;
     237             :                 }
     238          65 :                 talloc_free(bcast_address);
     239             : 
     240          65 :                 nbt_set_incoming_handler(bcast_nbtsock, nbtd_request_handler, iface);
     241             :         }
     242             : 
     243             :         /* listen for unicasts on port 137 */
     244         130 :         iface->nbtsock = nbt_name_socket_init(iface, nbtsrv->task->event_ctx);
     245         130 :         if (!iface->nbtsock) {
     246           0 :                 talloc_free(iface);
     247           0 :                 return NT_STATUS_NO_MEMORY;
     248             :         }
     249             : 
     250         130 :         unicast_address = socket_address_from_strings(iface->nbtsock, 
     251         130 :                                                       iface->nbtsock->sock->backend_name, 
     252             :                                                       bind_address, lpcfg_nbt_port(lp_ctx));
     253             : 
     254         130 :         status = socket_listen(iface->nbtsock->sock, unicast_address, 0, 0);
     255         130 :         if (!NT_STATUS_IS_OK(status)) {
     256           0 :                 DEBUG(0,("Failed to bind to %s:%d - %s\n", 
     257             :                          bind_address, lpcfg_nbt_port(lp_ctx), nt_errstr(status)));
     258           0 :                 talloc_free(iface);
     259           0 :                 return status;
     260             :         }
     261         130 :         talloc_free(unicast_address);
     262             : 
     263         130 :         nbt_set_incoming_handler(iface->nbtsock, nbtd_request_handler, iface);
     264         130 :         nbt_set_unexpected_handler(iface->nbtsock, nbtd_unexpected_handler, iface);
     265             : 
     266             :         /* also setup the datagram listeners */
     267         130 :         status = nbtd_dgram_setup(iface, bind_address);
     268         130 :         if (!NT_STATUS_IS_OK(status)) {
     269           0 :                 DEBUG(0,("Failed to setup dgram listen on %s - %s\n", 
     270             :                          bind_address, nt_errstr(status)));
     271           0 :                 talloc_free(iface);
     272           0 :                 return status;
     273             :         }
     274             :         
     275         130 :         if (strcmp(netmask, "0.0.0.0") == 0) {
     276          65 :                 DLIST_ADD(nbtsrv->bcast_interface, iface);
     277             :         } else {
     278          65 :                 DLIST_ADD(nbtsrv->interfaces, iface);
     279             :         }
     280             : 
     281         130 :         return NT_STATUS_OK;
     282             : }
     283             : 
     284             : /*
     285             :   setup a socket for talking to our WINS servers
     286             : */
     287          65 : static NTSTATUS nbtd_add_wins_socket(struct nbtd_server *nbtsrv)
     288             : {
     289           2 :         struct nbtd_interface *iface;
     290             : 
     291          65 :         iface = talloc_zero(nbtsrv, struct nbtd_interface);
     292          65 :         NT_STATUS_HAVE_NO_MEMORY(iface);
     293             : 
     294          65 :         iface->nbtsrv        = nbtsrv;
     295             : 
     296          65 :         DLIST_ADD(nbtsrv->wins_interface, iface);
     297             : 
     298          65 :         return NT_STATUS_OK;
     299             : }
     300             : 
     301             : 
     302             : /*
     303             :   setup our listening sockets on the configured network interfaces
     304             : */
     305          65 : NTSTATUS nbtd_startup_interfaces(struct nbtd_server *nbtsrv, struct loadparm_context *lp_ctx,
     306             :                                  struct interface *ifaces)
     307             : {
     308          65 :         int num_interfaces = iface_list_count(ifaces);
     309           2 :         int i;
     310          65 :         TALLOC_CTX *tmp_ctx = talloc_new(nbtsrv);
     311           2 :         NTSTATUS status;
     312             : 
     313             :         /* if we are allowing incoming packets from any address, then
     314             :            we also need to bind to the wildcard address */
     315          65 :         if (!lpcfg_bind_interfaces_only(lp_ctx)) {
     316           2 :                 const char *primary_address;
     317             : 
     318          65 :                 primary_address = iface_list_first_v4(ifaces);
     319             : 
     320             :                 /* the primary address is the address we will return
     321             :                    for non-WINS queries not made on a specific
     322             :                    interface */
     323          65 :                 if (primary_address == NULL) {
     324           0 :                         primary_address = inet_ntoa(interpret_addr2(
     325             :                                                             lpcfg_netbios_name(lp_ctx)));
     326             :                 }
     327             : 
     328          65 :                 primary_address = talloc_strdup(tmp_ctx, primary_address);
     329          65 :                 NT_STATUS_HAVE_NO_MEMORY(primary_address);
     330             : 
     331          65 :                 status = nbtd_add_socket(nbtsrv, 
     332             :                                          lp_ctx,
     333             :                                          "0.0.0.0",
     334             :                                          primary_address,
     335          65 :                                          talloc_strdup(tmp_ctx, "255.255.255.255"),
     336          65 :                                          talloc_strdup(tmp_ctx, "0.0.0.0"));
     337          65 :                 NT_STATUS_NOT_OK_RETURN(status);
     338             :         }
     339             : 
     340         195 :         for (i=0; i<num_interfaces; i++) {
     341           4 :                 const char *bcast;
     342           4 :                 const char *address, *netmask;
     343             : 
     344         130 :                 if (!iface_list_n_is_v4(ifaces, i)) {
     345             :                         /* v4 only for NBT protocol */
     346          65 :                         continue;
     347             :                 }
     348             : 
     349          65 :                 bcast = iface_list_n_bcast(ifaces, i);
     350             :                 /* we can't assume every interface is broadcast capable */
     351          65 :                 if (bcast == NULL) continue;
     352             : 
     353          65 :                 address = talloc_strdup(tmp_ctx, iface_list_n_ip(ifaces, i));
     354          65 :                 bcast   = talloc_strdup(tmp_ctx, bcast);
     355          65 :                 netmask = talloc_strdup(tmp_ctx, iface_list_n_netmask(ifaces, i));
     356             : 
     357          65 :                 status = nbtd_add_socket(nbtsrv, lp_ctx,
     358             :                                          address, address, bcast, netmask);
     359          67 :                 NT_STATUS_NOT_OK_RETURN(status);
     360             :         }
     361             : 
     362          65 :         if (lpcfg_wins_server_list(lp_ctx)) {
     363          65 :                 status = nbtd_add_wins_socket(nbtsrv);
     364          65 :                 NT_STATUS_NOT_OK_RETURN(status);
     365             :         }
     366             : 
     367          65 :         talloc_free(tmp_ctx);
     368             : 
     369          65 :         return NT_STATUS_OK;
     370             : }
     371             : 
     372             : 
     373             : /*
     374             :   form a list of addresses that we should use in name query replies
     375             :   we always place the IP in the given interface first
     376             : */
     377        1447 : const char **nbtd_address_list(struct nbtd_interface *iface, TALLOC_CTX *mem_ctx)
     378             : {
     379        1447 :         struct nbtd_server *nbtsrv = iface->nbtsrv;
     380        1447 :         const char **ret = NULL;
     381          36 :         struct nbtd_interface *iface2;
     382        1447 :         bool is_loopback = false;
     383             : 
     384        1447 :         if (iface->ip_address) {
     385        1058 :                 is_loopback = iface_list_same_net(iface->ip_address, "127.0.0.1", "255.0.0.0");
     386        1058 :                 ret = str_list_add(ret, iface->ip_address);
     387             :         }
     388             : 
     389        2894 :         for (iface2=nbtsrv->interfaces;iface2;iface2=iface2->next) {
     390        1447 :                 if (iface2 == iface) continue;
     391             : 
     392         389 :                 if (!iface2->ip_address) continue;
     393             : 
     394         389 :                 if (!is_loopback) {
     395         389 :                         if (iface_list_same_net(iface2->ip_address, "127.0.0.1", "255.0.0.0")) {
     396           0 :                                 continue;
     397             :                         }
     398             :                 }
     399             : 
     400         389 :                 ret = str_list_add(ret, iface2->ip_address);
     401             :         }
     402             : 
     403        1447 :         talloc_steal(mem_ctx, ret);
     404             : 
     405        1447 :         return ret;
     406             : }
     407             : 
     408             : 
     409             : /*
     410             :   find the interface to use for sending a outgoing request
     411             : */
     412          64 : struct nbtd_interface *nbtd_find_request_iface(struct nbtd_server *nbtd_server,
     413             :                                                const char *address, bool allow_bcast_iface)
     414             : {
     415           0 :         struct nbtd_interface *cur;
     416             : 
     417             :         /* try to find a exact match */
     418          74 :         for (cur=nbtd_server->interfaces;cur;cur=cur->next) {
     419          64 :                 if (iface_list_same_net(address, cur->ip_address, cur->netmask)) {
     420          54 :                         DEBUG(10,("find interface for dst[%s] ip: %s/%s (iface[%p])\n",
     421             :                                   address, cur->ip_address, cur->netmask, cur));
     422          54 :                         return cur;
     423             :                 }
     424             :         }
     425             : 
     426             :         /* no exact match, if we have the broadcast interface, use that */
     427          10 :         if (allow_bcast_iface && nbtd_server->bcast_interface) {
     428          10 :                 cur = nbtd_server->bcast_interface;
     429          10 :                 DEBUG(10,("find interface for dst[%s] ip: %s/%s (bcast iface[%p])\n",
     430             :                         address, cur->ip_address, cur->netmask, cur));
     431          10 :                 return cur;
     432             :         }
     433             : 
     434             :         /* fallback to first interface */
     435           0 :         cur = nbtd_server->interfaces;
     436           0 :         DEBUG(10,("find interface for dst[%s] ip: %s/%s (default iface[%p])\n",
     437             :                 address, cur->ip_address, cur->netmask, cur));
     438           0 :         return cur;
     439             : }
     440             : 
     441             : /*
     442             :  * find the interface to use for sending a outgoing reply
     443             :  */
     444          45 : struct nbtd_interface *nbtd_find_reply_iface(struct nbtd_interface *iface,
     445             :                                              const char *address, bool allow_bcast_iface)
     446             : {
     447          45 :         struct nbtd_server *nbtd_server = iface->nbtsrv;
     448             : 
     449             :         /* first try to use the given interfacel when it's not the broadcast one */
     450          45 :         if (iface != nbtd_server->bcast_interface) {
     451          45 :                 return iface;
     452             :         }
     453             : 
     454           0 :         return nbtd_find_request_iface(nbtd_server, address, allow_bcast_iface);
     455             : }

Generated by: LCOV version 1.14