/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- add_subnet
- close_subnet
- make_subnet
- make_normal_subnet
- create_subnets
- we_are_a_wins_client
- get_next_subnet_maybe_unicast
- 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 }