LCOV - code coverage report
Current view: top level - source3/nmbd - nmbd_subnetdb.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 91 161 56.5 %
Date: 2024-02-28 12:06:22 Functions: 7 8 87.5 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             :    NBT netbios routines and daemon - version 2
       4             :    Copyright (C) Andrew Tridgell 1994-1998
       5             :    Copyright (C) Luke Kenneth Casson Leighton 1994-1998
       6             :    Copyright (C) Jeremy Allison 1994-1998
       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             :    Revision History:
      22             : 
      23             : */
      24             : 
      25             : #include "includes.h"
      26             : #include "nmbd/nmbd.h"
      27             : 
      28             : extern int global_nmb_port;
      29             : 
      30             : /* This is the broadcast subnets database. */
      31             : struct subnet_record *subnetlist = NULL;
      32             : 
      33             : /* Extra subnets - keep these separate so enumeration code doesn't
      34             :    run onto it by mistake. */
      35             : 
      36             : struct subnet_record *unicast_subnet = NULL;
      37             : struct subnet_record *remote_broadcast_subnet = NULL;
      38             : struct subnet_record *wins_server_subnet = NULL;
      39             : 
      40             : extern uint16_t samba_nb_type; /* Samba's NetBIOS name type. */
      41             : 
      42             : /****************************************************************************
      43             :   Add a subnet into the list.
      44             :   **************************************************************************/
      45             : 
      46          44 : static void add_subnet(struct subnet_record *subrec)
      47             : {
      48          44 :         DLIST_ADD(subnetlist, subrec);
      49          44 : }
      50             : 
      51             : /****************************************************************************
      52             : stop listening on a subnet
      53             : we don't free the record as we don't have proper reference counting for it
      54             : yet and it may be in use by a response record
      55             :   ****************************************************************************/
      56             : 
      57           0 : void close_subnet(struct subnet_record *subrec)
      58             : {
      59           0 :         if (subrec->nmb_sock != -1) {
      60           0 :                 close(subrec->nmb_sock);
      61           0 :                 subrec->nmb_sock = -1;
      62             :         }
      63           0 :         if (subrec->nmb_bcast != -1) {
      64           0 :                 close(subrec->nmb_bcast);
      65           0 :                 subrec->nmb_bcast = -1;
      66             :         }
      67           0 :         if (subrec->dgram_sock != -1) {
      68           0 :                 close(subrec->dgram_sock);
      69           0 :                 subrec->dgram_sock = -1;
      70             :         }
      71           0 :         if (subrec->dgram_bcast != -1) {
      72           0 :                 close(subrec->dgram_bcast);
      73           0 :                 subrec->dgram_bcast = -1;
      74             :         }
      75             : 
      76           0 :         DLIST_REMOVE(subnetlist, subrec);
      77           0 : }
      78             : 
      79             : /****************************************************************************
      80             :   Create a subnet entry.
      81             :   ****************************************************************************/
      82             : 
      83         132 : static struct subnet_record *make_subnet(const char *name, enum subnet_type type,
      84             :                                          struct in_addr myip, struct in_addr bcast_ip, 
      85             :                                          struct in_addr mask_ip)
      86             : {
      87         132 :         struct subnet_record *subrec = NULL;
      88         132 :         int nmb_sock = -1;
      89         132 :         int dgram_sock = -1;
      90         132 :         int nmb_bcast = -1;
      91         132 :         int dgram_bcast = -1;
      92         132 :         bool bind_bcast = lp_nmbd_bind_explicit_broadcast();
      93             : 
      94             :         /* Check if we are creating a non broadcast subnet - if so don't create
      95             :                 sockets.  */
      96             : 
      97         132 :         if (type == NORMAL_SUBNET) {
      98             :                 struct sockaddr_storage ss;
      99             :                 struct sockaddr_storage ss_bcast;
     100             : 
     101          44 :                 in_addr_to_sockaddr_storage(&ss, myip);
     102          44 :                 in_addr_to_sockaddr_storage(&ss_bcast, bcast_ip);
     103             : 
     104             :                 /*
     105             :                  * Attempt to open the sockets on port 137/138 for this interface
     106             :                  * and bind them.
     107             :                  * Fail the subnet creation if this fails.
     108             :                  */
     109             : 
     110          44 :                 nmb_sock = open_socket_in(
     111             :                         SOCK_DGRAM, &ss, global_nmb_port, true);
     112          44 :                 if (nmb_sock < 0) {
     113           0 :                         DBG_ERR("Failed to open nmb socket on interface %s "
     114             :                                 "for port %d: %s\n",
     115             :                                 inet_ntoa(myip),
     116             :                                 global_nmb_port,
     117             :                                 strerror(-nmb_sock));
     118           0 :                         goto failed;
     119             :                 }
     120          44 :                 set_socket_options(nmb_sock,"SO_BROADCAST");
     121          44 :                 set_blocking(nmb_sock, false);
     122             : 
     123          44 :                 if (bind_bcast) {
     124          44 :                         nmb_bcast = open_socket_in(
     125             :                                 SOCK_DGRAM, &ss_bcast, global_nmb_port, true);
     126          44 :                         if (nmb_bcast < 0) {
     127           0 :                                 DBG_ERR("Failed to open nmb bcast socket on "
     128             :                                         "interface %s for port %d: %s\n",
     129             :                                         inet_ntoa(myip),
     130             :                                         global_nmb_port,
     131             :                                         strerror(-nmb_bcast));
     132           0 :                                 goto failed;
     133             :                         }
     134          44 :                         set_socket_options(nmb_bcast, "SO_BROADCAST");
     135          44 :                         set_blocking(nmb_bcast, false);
     136             :                 }
     137             : 
     138          44 :                 dgram_sock = open_socket_in(SOCK_DGRAM, &ss, DGRAM_PORT, true);
     139          44 :                 if (dgram_sock < 0) {
     140           0 :                         DBG_ERR("Failed to open dgram socket on "
     141             :                                 "interface %s for port %d: %s\n",
     142             :                                 inet_ntoa(myip),
     143             :                                 DGRAM_PORT,
     144             :                                 strerror(-dgram_sock));
     145           0 :                         goto failed;
     146             :                 }
     147          44 :                 set_socket_options(dgram_sock, "SO_BROADCAST");
     148          44 :                 set_blocking(dgram_sock, false);
     149             : 
     150          44 :                 if (bind_bcast) {
     151          44 :                         dgram_bcast = open_socket_in(
     152             :                                 SOCK_DGRAM, &ss_bcast, DGRAM_PORT, true);
     153          44 :                         if (dgram_bcast < 0) {
     154           0 :                                 DBG_ERR("Failed to open dgram bcast socket on "
     155             :                                         "interface %s for port %d: %s\n",
     156             :                                         inet_ntoa(myip),
     157             :                                         DGRAM_PORT,
     158             :                                         strerror(-dgram_bcast));
     159           0 :                                 goto failed;
     160             :                         }
     161          44 :                         set_socket_options(dgram_bcast, "SO_BROADCAST");
     162          44 :                         set_blocking(dgram_bcast, false);
     163             :                 }
     164             :         }
     165             : 
     166         132 :         subrec = SMB_MALLOC_P(struct subnet_record);
     167         132 :         if (!subrec) {
     168           0 :                 DEBUG(0,("make_subnet: malloc fail !\n"));
     169           0 :                 goto failed;
     170             :         }
     171             :   
     172         132 :         ZERO_STRUCTP(subrec);
     173             : 
     174         132 :         if((subrec->subnet_name = SMB_STRDUP(name)) == NULL) {
     175           0 :                 DEBUG(0,("make_subnet: malloc fail for subnet name !\n"));
     176           0 :                 goto failed;
     177             :         }
     178             : 
     179         132 :         DEBUG(2, ("making subnet name:%s ", name ));
     180         132 :         DEBUG(2, ("Broadcast address:%s ", inet_ntoa(bcast_ip)));
     181         132 :         DEBUG(2, ("Subnet mask:%s\n", inet_ntoa(mask_ip)));
     182             :  
     183         132 :         subrec->namelist_changed = False;
     184         132 :         subrec->work_changed = False;
     185             :  
     186         132 :         subrec->bcast_ip = bcast_ip;
     187         132 :         subrec->mask_ip  = mask_ip;
     188         132 :         subrec->myip = myip;
     189         132 :         subrec->type = type;
     190         132 :         subrec->nmb_sock = nmb_sock;
     191         132 :         subrec->nmb_bcast = nmb_bcast;
     192         132 :         subrec->dgram_sock = dgram_sock;
     193         132 :         subrec->dgram_bcast = dgram_bcast;
     194             : 
     195         132 :         return subrec;
     196             : 
     197           0 : failed:
     198           0 :         SAFE_FREE(subrec);
     199           0 :         if (nmb_sock >= 0) {
     200           0 :                 close(nmb_sock);
     201             :         }
     202           0 :         if (nmb_bcast >= 0) {
     203           0 :                 close(nmb_bcast);
     204             :         }
     205           0 :         if (dgram_sock >= 0) {
     206           0 :                 close(dgram_sock);
     207             :         }
     208           0 :         if (dgram_bcast >= 0) {
     209           0 :                 close(dgram_bcast);
     210             :         }
     211           0 :         return NULL;
     212             : }
     213             : 
     214             : /****************************************************************************
     215             :   Create a normal subnet
     216             : **************************************************************************/
     217             : 
     218          44 : struct subnet_record *make_normal_subnet(const struct interface *iface)
     219             : {
     220             : 
     221             :         struct subnet_record *subrec;
     222          44 :         const struct in_addr *pip = &((const struct sockaddr_in *)&iface->ip)->sin_addr;
     223          44 :         const struct in_addr *pbcast = &((const struct sockaddr_in *)&iface->bcast)->sin_addr;
     224          44 :         const struct in_addr *pnmask = &((const struct sockaddr_in *)&iface->netmask)->sin_addr;
     225             : 
     226          44 :         subrec = make_subnet(inet_ntoa(*pip), NORMAL_SUBNET,
     227             :                              *pip, *pbcast, *pnmask);
     228          44 :         if (subrec) {
     229          44 :                 add_subnet(subrec);
     230             :         }
     231          44 :         return subrec;
     232             : }
     233             : 
     234             : /****************************************************************************
     235             :   Create subnet entries.
     236             : **************************************************************************/
     237             : 
     238          44 : bool create_subnets(void)
     239             : {
     240             :         /* We only count IPv4 interfaces whilst we're waiting. */
     241             :         int num_interfaces;
     242             :         int i;
     243             :         struct in_addr unicast_ip, ipzero;
     244             : 
     245          44 :   try_interfaces_again:
     246             : 
     247             :         /* Only count IPv4, non-loopback interfaces. */
     248          44 :         if (iface_count_v4_nl() == 0) {
     249           0 :                 daemon_status("nmbd",
     250             :                               "No local IPv4 non-loopback interfaces "
     251             :                               "available, waiting for interface ...");
     252           0 :                 DEBUG(0,("NOTE: NetBIOS name resolution is not supported for "
     253             :                          "Internet Protocol Version 6 (IPv6).\n"));
     254             :         }
     255             : 
     256             :         /* We only count IPv4, non-loopback interfaces here. */
     257          44 :         while (iface_count_v4_nl() == 0) {
     258             :                 void (*saved_handler)(int);
     259             : 
     260             :                 /*
     261             :                  * Whilst we're waiting for an interface, allow SIGTERM to
     262             :                  * cause us to exit.
     263             :                  */
     264             : 
     265           0 :                 saved_handler = CatchSignal(SIGTERM, SIG_DFL);
     266             : 
     267           0 :                 usleep(NMBD_WAIT_INTERFACES_TIME_USEC);
     268           0 :                 load_interfaces();
     269             : 
     270             :                 /*
     271             :                  * We got an interface, restore our normal term handler.
     272             :                  */
     273             : 
     274           0 :                 CatchSignal(SIGTERM, saved_handler);
     275             :         }
     276             : 
     277             :         /*
     278             :          * Here we count v4 and v6 - we know there's at least one
     279             :          * IPv4 interface and we filter on it below.
     280             :          */
     281          44 :         num_interfaces = iface_count();
     282             : 
     283             :         /*
     284             :          * Create subnets from all the local interfaces and thread them onto
     285             :          * the linked list.
     286             :          */
     287             : 
     288         132 :         for (i = 0 ; i < num_interfaces; i++) {
     289          88 :                 const struct interface *iface = get_interface(i);
     290             : 
     291          88 :                 if (!iface) {
     292           0 :                         DEBUG(2,("create_subnets: can't get interface %d.\n", i ));
     293           0 :                         continue;
     294             :                 }
     295             : 
     296             :                 /* Ensure we're only dealing with IPv4 here. */
     297          88 :                 if (iface->ip.ss_family != AF_INET) {
     298          44 :                         DEBUG(2,("create_subnets: "
     299             :                                 "ignoring non IPv4 interface.\n"));
     300          44 :                         continue;
     301             :                 }
     302             : 
     303             :                 /*
     304             :                  * We don't want to add a loopback interface, in case
     305             :                  * someone has added 127.0.0.1 for smbd, nmbd needs to
     306             :                  * ignore it here. JRA.
     307             :                  */
     308             : 
     309          44 :                 if (is_loopback_addr((const struct sockaddr *)&iface->ip)) {
     310           0 :                         DEBUG(2,("create_subnets: Ignoring loopback interface.\n" ));
     311           0 :                         continue;
     312             :                 }
     313             : 
     314          44 :                 if (!make_normal_subnet(iface))
     315           0 :                         return False;
     316             :         }
     317             : 
     318             :         /* We must have at least one subnet. */
     319          44 :         if (subnetlist == NULL) {
     320             :                 void (*saved_handler)(int);
     321             : 
     322           0 :                 DEBUG(0,("create_subnets: Unable to create any subnet from "
     323             :                                 "given interfaces. Is your interface line in "
     324             :                                 "smb.conf correct ?\n"));
     325             : 
     326           0 :                 saved_handler = CatchSignal(SIGTERM, SIG_DFL);
     327             : 
     328           0 :                 usleep(NMBD_WAIT_INTERFACES_TIME_USEC);
     329           0 :                 load_interfaces();
     330             : 
     331           0 :                 CatchSignal(SIGTERM, saved_handler);
     332           0 :                 goto try_interfaces_again;
     333             :         }
     334             : 
     335          44 :         if (lp_we_are_a_wins_server()) {
     336             :                 /* Pick the first interface IPv4 address as the WINS server
     337             :                  * ip. */
     338           0 :                 const struct in_addr *nip = first_ipv4_iface();
     339             : 
     340           0 :                 if (!nip) {
     341           0 :                         return False;
     342             :                 }
     343             : 
     344           0 :                 unicast_ip = *nip;
     345             :         } else {
     346             :                 /* note that we do not set the wins server IP here. We just
     347             :                         set it at zero and let the wins registration code cope
     348             :                         with getting the IPs right for each packet */
     349          44 :                 zero_ip_v4(&unicast_ip);
     350             :         }
     351             : 
     352             :         /*
     353             :          * Create the unicast and remote broadcast subnets.
     354             :          * Don't put these onto the linked list.
     355             :          * The ip address of the unicast subnet is set to be
     356             :          * the WINS server address, if it exists, or ipzero if not.
     357             :          */
     358             : 
     359          44 :         unicast_subnet = make_subnet( "UNICAST_SUBNET", UNICAST_SUBNET, 
     360             :                                 unicast_ip, unicast_ip, unicast_ip);
     361             : 
     362          44 :         zero_ip_v4(&ipzero);
     363             : 
     364          44 :         remote_broadcast_subnet = make_subnet( "REMOTE_BROADCAST_SUBNET",
     365             :                                 REMOTE_BROADCAST_SUBNET,
     366             :                                 ipzero, ipzero, ipzero);
     367             : 
     368          44 :         if((unicast_subnet == NULL) || (remote_broadcast_subnet == NULL))
     369           0 :                 return False;
     370             : 
     371             :         /* 
     372             :          * If we are WINS server, create the WINS_SERVER_SUBNET - don't put on
     373             :          * the linked list.
     374             :          */
     375             : 
     376          44 :         if (lp_we_are_a_wins_server()) {
     377           0 :                 if( (wins_server_subnet = make_subnet( "WINS_SERVER_SUBNET",
     378             :                                                 WINS_SERVER_SUBNET, 
     379             :                                                 ipzero, ipzero, ipzero )) == NULL )
     380           0 :                         return False;
     381             :         }
     382             : 
     383          44 :         return True;
     384             : }
     385             : 
     386             : /*******************************************************************
     387             : Function to tell us if we can use the unicast subnet.
     388             : ******************************************************************/
     389             : 
     390       89725 : bool we_are_a_wins_client(void)
     391             : {
     392       89725 :         if (wins_srv_count() > 0) {
     393           0 :                 return True;
     394             :         }
     395             : 
     396       89725 :         return False;
     397             : }
     398             : 
     399             : /*******************************************************************
     400             : Access function used by NEXT_SUBNET_INCLUDING_UNICAST
     401             : ******************************************************************/
     402             : 
     403       15727 : struct subnet_record *get_next_subnet_maybe_unicast(struct subnet_record *subrec)
     404             : {
     405       15727 :         if(subrec == unicast_subnet)
     406           0 :                 return NULL;
     407       15727 :         else if((subrec->next == NULL) && we_are_a_wins_client())
     408           0 :                 return unicast_subnet;
     409             :         else
     410       15727 :                 return subrec->next;
     411             : }
     412             : 
     413             : /*******************************************************************
     414             :  Access function used by retransmit_or_expire_response_records() in
     415             :  nmbd_packets.c. Patch from Andrey Alekseyev <fetch@muffin.arcadia.spb.ru>
     416             :  Needed when we need to enumerate all the broadcast, unicast and
     417             :  WINS subnets.
     418             : ******************************************************************/
     419             : 
     420       17498 : struct subnet_record *get_next_subnet_maybe_unicast_or_wins_server(struct subnet_record *subrec)
     421             : {
     422       17498 :         if(subrec == unicast_subnet) {
     423           0 :                 if(wins_server_subnet)
     424           0 :                         return wins_server_subnet;
     425             :                 else
     426           0 :                         return NULL;
     427             :         }
     428             : 
     429       17498 :         if(wins_server_subnet && subrec == wins_server_subnet)
     430           0 :                 return NULL;
     431             : 
     432       17498 :         if((subrec->next == NULL) && we_are_a_wins_client())
     433           0 :                 return unicast_subnet;
     434             :         else
     435       17498 :                 return subrec->next;
     436             : }

Generated by: LCOV version 1.14