root/source3/nmbd/nmbd_subnetdb.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. add_subnet
  2. close_subnet
  3. make_subnet
  4. make_normal_subnet
  5. create_subnets
  6. we_are_a_wins_client
  7. get_next_subnet_maybe_unicast
  8. get_next_subnet_maybe_unicast_or_wins_server

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

/* [<][>][^][v][top][bottom][index][help] */