heimdal_build: Use consistent name for heimbase.
[Samba.git] / source3 / nmbd / nmbd_subnetdb.c
blob3a60038dcdcec3933b8da843e7e8bc857053fe9e
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
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.
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.
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/>.
21 Revision History:
25 #include "includes.h"
26 #include "nmbd/nmbd.h"
28 extern int global_nmb_port;
30 /* This is the broadcast subnets database. */
31 struct subnet_record *subnetlist = NULL;
33 /* Extra subnets - keep these separate so enumeration code doesn't
34 run onto it by mistake. */
36 struct subnet_record *unicast_subnet = NULL;
37 struct subnet_record *remote_broadcast_subnet = NULL;
38 struct subnet_record *wins_server_subnet = NULL;
40 extern uint16 samba_nb_type; /* Samba's NetBIOS name type. */
42 /****************************************************************************
43 Add a subnet into the list.
44 **************************************************************************/
46 static void add_subnet(struct subnet_record *subrec)
48 DLIST_ADD(subnetlist, subrec);
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 ****************************************************************************/
57 void close_subnet(struct subnet_record *subrec)
59 if (subrec->dgram_sock != -1) {
60 close(subrec->dgram_sock);
61 subrec->dgram_sock = -1;
63 if (subrec->nmb_sock != -1) {
64 close(subrec->nmb_sock);
65 subrec->nmb_sock = -1;
68 DLIST_REMOVE(subnetlist, subrec);
71 /****************************************************************************
72 Create a subnet entry.
73 ****************************************************************************/
75 static struct subnet_record *make_subnet(const char *name, enum subnet_type type,
76 struct in_addr myip, struct in_addr bcast_ip,
77 struct in_addr mask_ip)
79 struct subnet_record *subrec = NULL;
80 int nmb_sock = -1;
81 int dgram_sock = -1;
82 int nmb_bcast = -1;
83 int dgram_bcast = -1;
84 bool bind_bcast = lp_nmbd_bind_explicit_broadcast();
86 /* Check if we are creating a non broadcast subnet - if so don't create
87 sockets. */
89 if (type == NORMAL_SUBNET) {
90 struct sockaddr_storage ss;
91 struct sockaddr_storage ss_bcast;
93 in_addr_to_sockaddr_storage(&ss, myip);
94 in_addr_to_sockaddr_storage(&ss_bcast, bcast_ip);
97 * Attempt to open the sockets on port 137/138 for this interface
98 * and bind them.
99 * Fail the subnet creation if this fails.
102 nmb_sock = open_socket_in(SOCK_DGRAM, global_nmb_port,
103 0, &ss, true);
104 if (nmb_sock == -1) {
105 DEBUG(0, ("nmbd_subnetdb:make_subnet()\n"));
106 DEBUGADD(0,(" Failed to open nmb socket on interface %s ",
107 inet_ntoa(myip)));
108 DEBUGADD(0,("for port %d. ", global_nmb_port));
109 DEBUGADD(0,("Error was %s\n", strerror(errno)));
110 goto failed;
112 set_socket_options(nmb_sock,"SO_BROADCAST");
113 set_blocking(nmb_sock, false);
115 if (bind_bcast) {
116 nmb_bcast = open_socket_in(SOCK_DGRAM, global_nmb_port,
117 0, &ss_bcast, true);
118 if (nmb_bcast == -1) {
119 DEBUG(0, ("nmbd_subnetdb:make_subnet()\n"));
120 DEBUGADD(0,(" Failed to open nmb bcast socket on interface %s ",
121 inet_ntoa(bcast_ip)));
122 DEBUGADD(0,("for port %d. ", global_nmb_port));
123 DEBUGADD(0,("Error was %s\n", strerror(errno)));
124 goto failed;
126 set_socket_options(nmb_bcast, "SO_BROADCAST");
127 set_blocking(nmb_bcast, false);
130 dgram_sock = open_socket_in(SOCK_DGRAM, DGRAM_PORT,
131 3, &ss, true);
132 if (dgram_sock == -1) {
133 DEBUG(0, ("nmbd_subnetdb:make_subnet()\n"));
134 DEBUGADD(0,(" Failed to open dgram socket on interface %s ",
135 inet_ntoa(myip)));
136 DEBUGADD(0,("for port %d. ", DGRAM_PORT));
137 DEBUGADD(0,("Error was %s\n", strerror(errno)));
138 goto failed;
140 set_socket_options(dgram_sock, "SO_BROADCAST");
141 set_blocking(dgram_sock, false);
143 if (bind_bcast) {
144 dgram_bcast = open_socket_in(SOCK_DGRAM, DGRAM_PORT,
145 3, &ss_bcast, true);
146 if (dgram_bcast == -1) {
147 DEBUG(0, ("nmbd_subnetdb:make_subnet()\n"));
148 DEBUGADD(0,(" Failed to open dgram bcast socket on interface %s ",
149 inet_ntoa(bcast_ip)));
150 DEBUGADD(0,("for port %d. ", DGRAM_PORT));
151 DEBUGADD(0,("Error was %s\n", strerror(errno)));
152 goto failed;
154 set_socket_options(dgram_bcast, "SO_BROADCAST");
155 set_blocking(dgram_bcast, false);
159 subrec = SMB_MALLOC_P(struct subnet_record);
160 if (!subrec) {
161 DEBUG(0,("make_subnet: malloc fail !\n"));
162 goto failed;
165 ZERO_STRUCTP(subrec);
167 if((subrec->subnet_name = SMB_STRDUP(name)) == NULL) {
168 DEBUG(0,("make_subnet: malloc fail for subnet name !\n"));
169 goto failed;
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)));
176 subrec->namelist_changed = False;
177 subrec->work_changed = False;
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->nmb_bcast = nmb_bcast;
185 subrec->dgram_sock = dgram_sock;
186 subrec->dgram_bcast = dgram_bcast;
188 return subrec;
190 failed:
191 SAFE_FREE(subrec);
192 if (nmb_sock != -1) {
193 close(nmb_sock);
195 if (nmb_bcast != -1) {
196 close(nmb_bcast);
198 if (dgram_sock != -1) {
199 close(dgram_sock);
201 if (dgram_bcast != -1) {
202 close(dgram_bcast);
204 return NULL;
207 /****************************************************************************
208 Create a normal subnet
209 **************************************************************************/
211 struct subnet_record *make_normal_subnet(const struct interface *iface)
214 struct subnet_record *subrec;
215 const struct in_addr *pip = &((const struct sockaddr_in *)&iface->ip)->sin_addr;
216 const struct in_addr *pbcast = &((const struct sockaddr_in *)&iface->bcast)->sin_addr;
217 const struct in_addr *pnmask = &((const struct sockaddr_in *)&iface->netmask)->sin_addr;
219 subrec = make_subnet(inet_ntoa(*pip), NORMAL_SUBNET,
220 *pip, *pbcast, *pnmask);
221 if (subrec) {
222 add_subnet(subrec);
224 return subrec;
227 /****************************************************************************
228 Create subnet entries.
229 **************************************************************************/
231 bool create_subnets(void)
233 /* We only count IPv4 interfaces whilst we're waiting. */
234 int num_interfaces;
235 int i;
236 struct in_addr unicast_ip, ipzero;
238 try_interfaces_again:
240 /* Only count IPv4, non-loopback interfaces. */
241 if (iface_count_v4_nl() == 0) {
242 DEBUG(0,("create_subnets: No local IPv4 non-loopback interfaces !\n"));
243 DEBUG(0,("create_subnets: Waiting for an interface to appear ...\n"));
246 /* We only count IPv4, non-loopback interfaces here. */
247 while (iface_count_v4_nl() == 0) {
248 void (*saved_handler)(int);
251 * Whilst we're waiting for an interface, allow SIGTERM to
252 * cause us to exit.
255 saved_handler = CatchSignal(SIGTERM, SIG_DFL);
257 sleep(5);
258 load_interfaces();
261 * We got an interface, restore our normal term handler.
264 CatchSignal(SIGTERM, saved_handler);
268 * Here we count v4 and v6 - we know there's at least one
269 * IPv4 interface and we filter on it below.
271 num_interfaces = iface_count();
274 * Create subnets from all the local interfaces and thread them onto
275 * the linked list.
278 for (i = 0 ; i < num_interfaces; i++) {
279 const struct interface *iface = get_interface(i);
281 if (!iface) {
282 DEBUG(2,("create_subnets: can't get interface %d.\n", i ));
283 continue;
286 /* Ensure we're only dealing with IPv4 here. */
287 if (iface->ip.ss_family != AF_INET) {
288 DEBUG(2,("create_subnets: "
289 "ignoring non IPv4 interface.\n"));
290 continue;
294 * We don't want to add a loopback interface, in case
295 * someone has added 127.0.0.1 for smbd, nmbd needs to
296 * ignore it here. JRA.
299 if (is_loopback_addr((struct sockaddr *)&iface->ip)) {
300 DEBUG(2,("create_subnets: Ignoring loopback interface.\n" ));
301 continue;
304 if (!make_normal_subnet(iface))
305 return False;
308 /* We must have at least one subnet. */
309 if (subnetlist == NULL) {
310 void (*saved_handler)(int);
312 DEBUG(0,("create_subnets: Unable to create any subnet from "
313 "given interfaces. Is your interface line in "
314 "smb.conf correct ?\n"));
316 saved_handler = CatchSignal(SIGTERM, SIG_DFL);
318 sleep(5);
319 load_interfaces();
321 CatchSignal(SIGTERM, saved_handler);
322 goto try_interfaces_again;
325 if (lp_we_are_a_wins_server()) {
326 /* Pick the first interface IPv4 address as the WINS server
327 * ip. */
328 const struct in_addr *nip = first_ipv4_iface();
330 if (!nip) {
331 return False;
334 unicast_ip = *nip;
335 } else {
336 /* note that we do not set the wins server IP here. We just
337 set it at zero and let the wins registration code cope
338 with getting the IPs right for each packet */
339 zero_ip_v4(&unicast_ip);
343 * Create the unicast and remote broadcast subnets.
344 * Don't put these onto the linked list.
345 * The ip address of the unicast subnet is set to be
346 * the WINS server address, if it exists, or ipzero if not.
349 unicast_subnet = make_subnet( "UNICAST_SUBNET", UNICAST_SUBNET,
350 unicast_ip, unicast_ip, unicast_ip);
352 zero_ip_v4(&ipzero);
354 remote_broadcast_subnet = make_subnet( "REMOTE_BROADCAST_SUBNET",
355 REMOTE_BROADCAST_SUBNET,
356 ipzero, ipzero, ipzero);
358 if((unicast_subnet == NULL) || (remote_broadcast_subnet == NULL))
359 return False;
362 * If we are WINS server, create the WINS_SERVER_SUBNET - don't put on
363 * the linked list.
366 if (lp_we_are_a_wins_server()) {
367 if( (wins_server_subnet = make_subnet( "WINS_SERVER_SUBNET",
368 WINS_SERVER_SUBNET,
369 ipzero, ipzero, ipzero )) == NULL )
370 return False;
373 return True;
376 /*******************************************************************
377 Function to tell us if we can use the unicast subnet.
378 ******************************************************************/
380 bool we_are_a_wins_client(void)
382 if (wins_srv_count() > 0) {
383 return True;
386 return False;
389 /*******************************************************************
390 Access function used by NEXT_SUBNET_INCLUDING_UNICAST
391 ******************************************************************/
393 struct subnet_record *get_next_subnet_maybe_unicast(struct subnet_record *subrec)
395 if(subrec == unicast_subnet)
396 return NULL;
397 else if((subrec->next == NULL) && we_are_a_wins_client())
398 return unicast_subnet;
399 else
400 return subrec->next;
403 /*******************************************************************
404 Access function used by retransmit_or_expire_response_records() in
405 nmbd_packets.c. Patch from Andrey Alekseyev <fetch@muffin.arcadia.spb.ru>
406 Needed when we need to enumerate all the broadcast, unicast and
407 WINS subnets.
408 ******************************************************************/
410 struct subnet_record *get_next_subnet_maybe_unicast_or_wins_server(struct subnet_record *subrec)
412 if(subrec == unicast_subnet) {
413 if(wins_server_subnet)
414 return wins_server_subnet;
415 else
416 return NULL;
419 if(wins_server_subnet && subrec == wins_server_subnet)
420 return NULL;
422 if((subrec->next == NULL) && we_are_a_wins_client())
423 return unicast_subnet;
424 else
425 return subrec->next;