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 2 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, write to the Free Software 20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 22 Revision History: 23 24*/ 25 26#include "includes.h" 27 28extern int ClientNMB; 29extern int ClientDGRAM; 30extern int global_nmb_port; 31 32/* This is the broadcast subnets database. */ 33struct subnet_record *subnetlist = NULL; 34 35/* Extra subnets - keep these separate so enumeration code doesn't 36 run onto it by mistake. */ 37 38struct subnet_record *unicast_subnet = NULL; 39struct subnet_record *remote_broadcast_subnet = NULL; 40struct subnet_record *wins_server_subnet = NULL; 41 42extern uint16 samba_nb_type; /* Samba's NetBIOS name type. */ 43 44/**************************************************************************** 45 Add a subnet into the list. 46 **************************************************************************/ 47 48static void add_subnet(struct subnet_record *subrec) 49{ 50 DLIST_ADD(subnetlist, subrec); 51} 52 53/* ************************************************************************** ** 54 * Comparison routine for ordering the splay-tree based namelists assoicated 55 * with each subnet record. 56 * 57 * Input: Item - Pointer to the comparison key. 58 * Node - Pointer to a node the splay tree. 59 * 60 * Output: The return value will be <0 , ==0, or >0 depending upon the 61 * ordinal relationship of the two keys. 62 * 63 * ************************************************************************** ** 64 */ 65static int namelist_entry_compare( ubi_trItemPtr Item, ubi_trNodePtr Node ) 66{ 67 struct name_record *NR = (struct name_record *)Node; 68 69 if( DEBUGLVL( 10 ) ) { 70 struct nmb_name *Iname = (struct nmb_name *)Item; 71 72 Debug1( "nmbd_subnetdb:namelist_entry_compare()\n" ); 73 Debug1( "%d == memcmp( \"%s\", \"%s\", %d )\n", 74 memcmp( Item, &(NR->name), sizeof(struct nmb_name) ), 75 nmb_namestr(Iname), nmb_namestr(&NR->name), (int)sizeof(struct nmb_name) ); 76 } 77 78 return( memcmp( Item, &(NR->name), sizeof(struct nmb_name) ) ); 79} 80 81/**************************************************************************** 82stop listening on a subnet 83we don't free the record as we don't have proper reference counting for it 84yet and it may be in use by a response record 85 ****************************************************************************/ 86 87void close_subnet(struct subnet_record *subrec) 88{ 89 DLIST_REMOVE(subnetlist, subrec); 90 91 if (subrec->dgram_sock != -1) { 92 close(subrec->dgram_sock); 93 subrec->dgram_sock = -1; 94 } 95 if (subrec->nmb_sock != -1) { 96 close(subrec->nmb_sock); 97 subrec->nmb_sock = -1; 98 } 99} 100 101/**************************************************************************** 102 Create a subnet entry. 103 ****************************************************************************/ 104 105static struct subnet_record *make_subnet(const char *name, enum subnet_type type, 106 struct in_addr myip, struct in_addr bcast_ip, 107 struct in_addr mask_ip) 108{ 109 struct subnet_record *subrec = NULL; 110 int nmb_sock, dgram_sock; 111 112 /* Check if we are creating a non broadcast subnet - if so don't create 113 sockets. */ 114 115 if(type != NORMAL_SUBNET) { 116 nmb_sock = -1; 117 dgram_sock = -1; 118 } else { 119 /* 120 * Attempt to open the sockets on port 137/138 for this interface 121 * and bind them. 122 * Fail the subnet creation if this fails. 123 */ 124 125 if((nmb_sock = open_socket_in(SOCK_DGRAM, global_nmb_port,0, myip.s_addr,True)) == -1) { 126 if( DEBUGLVL( 0 ) ) { 127 Debug1( "nmbd_subnetdb:make_subnet()\n" ); 128 Debug1( " Failed to open nmb socket on interface %s ", inet_ntoa(myip) ); 129 Debug1( "for port %d. ", global_nmb_port ); 130 Debug1( "Error was %s\n", strerror(errno) ); 131 } 132 return NULL; 133 } 134 135 if((dgram_sock = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3, myip.s_addr,True)) == -1) { 136 if( DEBUGLVL( 0 ) ) { 137 Debug1( "nmbd_subnetdb:make_subnet()\n" ); 138 Debug1( " Failed to open dgram socket on interface %s ", inet_ntoa(myip) ); 139 Debug1( "for port %d. ", DGRAM_PORT ); 140 Debug1( "Error was %s\n", strerror(errno) ); 141 } 142 return NULL; 143 } 144 145 /* Make sure we can broadcast from these sockets. */ 146 set_socket_options(nmb_sock,"SO_BROADCAST"); 147 set_socket_options(dgram_sock,"SO_BROADCAST"); 148 } 149 150 subrec = SMB_MALLOC_P(struct subnet_record); 151 if (!subrec) { 152 DEBUG(0,("make_subnet: malloc fail !\n")); 153 close(nmb_sock); 154 close(dgram_sock); 155 return(NULL); 156 } 157 158 memset( (char *)subrec, '\0', sizeof(*subrec) ); 159 (void)ubi_trInitTree( subrec->namelist, 160 namelist_entry_compare, 161 ubi_trOVERWRITE ); 162 163 if((subrec->subnet_name = SMB_STRDUP(name)) == NULL) { 164 DEBUG(0,("make_subnet: malloc fail for subnet name !\n")); 165 close(nmb_sock); 166 close(dgram_sock); 167 ZERO_STRUCTP(subrec); 168 SAFE_FREE(subrec); 169 return(NULL); 170 } 171 172 DEBUG(2, ("making subnet name:%s ", name )); 173 DEBUG(2, ("Broadcast address:%s ", inet_ntoa(bcast_ip))); 174 DEBUG(2, ("Subnet mask:%s\n", inet_ntoa(mask_ip))); 175 176 subrec->namelist_changed = False; 177 subrec->work_changed = False; 178 179 subrec->bcast_ip = bcast_ip; 180 subrec->mask_ip = mask_ip; 181 subrec->myip = myip; 182 subrec->type = type; 183 subrec->nmb_sock = nmb_sock; 184 subrec->dgram_sock = dgram_sock; 185 186 return subrec; 187} 188 189/**************************************************************************** 190 Create a normal subnet 191**************************************************************************/ 192 193struct subnet_record *make_normal_subnet(struct interface *iface) 194{ 195 struct subnet_record *subrec; 196 197 subrec = make_subnet(inet_ntoa(iface->ip), NORMAL_SUBNET, 198 iface->ip, iface->bcast, iface->nmask); 199 if (subrec) { 200 add_subnet(subrec); 201 } 202 return subrec; 203} 204 205/**************************************************************************** 206 Create subnet entries. 207**************************************************************************/ 208 209BOOL create_subnets(void) 210{ 211 int num_interfaces = iface_count(); 212 int i; 213 struct in_addr unicast_ip, ipzero; 214 extern struct in_addr loopback_ip; 215 216 if(num_interfaces == 0) { 217 DEBUG(0,("create_subnets: No local interfaces !\n")); 218 DEBUG(0,("create_subnets: Waiting for an interface to appear ...\n")); 219 while (iface_count() == 0) { 220 sleep(5); 221 load_interfaces(); 222 } 223 } 224 225 num_interfaces = iface_count(); 226 227 /* 228 * Create subnets from all the local interfaces and thread them onto 229 * the linked list. 230 */ 231 232 for (i = 0 ; i < num_interfaces; i++) { 233 struct interface *iface = get_interface(i); 234 235 /* 236 * We don't want to add a loopback interface, in case 237 * someone has added 127.0.0.1 for smbd, nmbd needs to 238 * ignore it here. JRA. 239 */ 240 241 if (ip_equal(iface->ip, loopback_ip)) { 242 DEBUG(2,("create_subnets: Ignoring loopback interface.\n" )); 243 continue; 244 } 245 246 if (!make_normal_subnet(iface)) 247 return False; 248 } 249 250 if (lp_we_are_a_wins_server()) { 251 /* Pick the first interface ip address as the WINS server ip. */ 252 unicast_ip = *iface_n_ip(0); 253 } else { 254 /* note that we do not set the wins server IP here. We just 255 set it at zero and let the wins registration code cope 256 with getting the IPs right for each packet */ 257 zero_ip(&unicast_ip); 258 } 259 260 /* 261 * Create the unicast and remote broadcast subnets. 262 * Don't put these onto the linked list. 263 * The ip address of the unicast subnet is set to be 264 * the WINS server address, if it exists, or ipzero if not. 265 */ 266 267 unicast_subnet = make_subnet( "UNICAST_SUBNET", UNICAST_SUBNET, 268 unicast_ip, unicast_ip, unicast_ip); 269 270 zero_ip(&ipzero); 271 272 remote_broadcast_subnet = make_subnet( "REMOTE_BROADCAST_SUBNET", 273 REMOTE_BROADCAST_SUBNET, 274 ipzero, ipzero, ipzero); 275 276 if((unicast_subnet == NULL) || (remote_broadcast_subnet == NULL)) 277 return False; 278 279 /* 280 * If we are WINS server, create the WINS_SERVER_SUBNET - don't put on 281 * the linked list. 282 */ 283 284 if (lp_we_are_a_wins_server()) { 285 if( (wins_server_subnet = make_subnet( "WINS_SERVER_SUBNET", 286 WINS_SERVER_SUBNET, 287 ipzero, ipzero, ipzero )) == NULL ) 288 return False; 289 } 290 291 return True; 292} 293 294/******************************************************************* 295Function to tell us if we can use the unicast subnet. 296******************************************************************/ 297 298BOOL we_are_a_wins_client(void) 299{ 300 if (wins_srv_count() > 0) { 301 return True; 302 } 303 304 return False; 305} 306 307/******************************************************************* 308Access function used by NEXT_SUBNET_INCLUDING_UNICAST 309******************************************************************/ 310 311struct subnet_record *get_next_subnet_maybe_unicast(struct subnet_record *subrec) 312{ 313 if(subrec == unicast_subnet) 314 return NULL; 315 else if((subrec->next == NULL) && we_are_a_wins_client()) 316 return unicast_subnet; 317 else 318 return subrec->next; 319} 320 321/******************************************************************* 322 Access function used by retransmit_or_expire_response_records() in 323 nmbd_packets.c. Patch from Andrey Alekseyev <fetch@muffin.arcadia.spb.ru> 324 Needed when we need to enumerate all the broadcast, unicast and 325 WINS subnets. 326******************************************************************/ 327 328struct subnet_record *get_next_subnet_maybe_unicast_or_wins_server(struct subnet_record *subrec) 329{ 330 if(subrec == unicast_subnet) { 331 if(wins_server_subnet) 332 return wins_server_subnet; 333 else 334 return NULL; 335 } 336 337 if(wins_server_subnet && subrec == wins_server_subnet) 338 return NULL; 339 340 if((subrec->next == NULL) && we_are_a_wins_client()) 341 return unicast_subnet; 342 else 343 return subrec->next; 344} 345