More simple const fixes.
[samba.git] / source3 / nmbd / nmbd_subnetdb.c
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 samba_nb_type; /* Samba's NetBIOS name type. */
41
42 /****************************************************************************
43   Add a subnet into the list.
44   **************************************************************************/
45
46 static void add_subnet(struct subnet_record *subrec)
47 {
48         DLIST_ADD(subnetlist, subrec);
49 }
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 void close_subnet(struct subnet_record *subrec)
58 {
59         if (subrec->dgram_sock != -1) {
60                 close(subrec->dgram_sock);
61                 subrec->dgram_sock = -1;
62         }
63         if (subrec->nmb_sock != -1) {
64                 close(subrec->nmb_sock);
65                 subrec->nmb_sock = -1;
66         }
67
68         DLIST_REMOVE(subnetlist, subrec);
69 }
70
71 /****************************************************************************
72   Create a subnet entry.
73   ****************************************************************************/
74
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)
78 {
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();
85
86         /* Check if we are creating a non broadcast subnet - if so don't create
87                 sockets.  */
88
89         if (type == NORMAL_SUBNET) {
90                 struct sockaddr_storage ss;
91                 struct sockaddr_storage ss_bcast;
92
93                 in_addr_to_sockaddr_storage(&ss, myip);
94                 in_addr_to_sockaddr_storage(&ss_bcast, bcast_ip);
95
96                 /*
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.
100                  */
101
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;
111                 }
112                 set_socket_options(nmb_sock,"SO_BROADCAST");
113                 set_blocking(nmb_sock, false);
114
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;
125                         }
126                         set_socket_options(nmb_bcast, "SO_BROADCAST");
127                         set_blocking(nmb_bcast, false);
128                 }
129
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;
139                 }
140                 set_socket_options(dgram_sock, "SO_BROADCAST");
141                 set_blocking(dgram_sock, false);
142
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;
153                         }
154                         set_socket_options(dgram_bcast, "SO_BROADCAST");
155                         set_blocking(dgram_bcast, false);
156                 }
157         }
158
159         subrec = SMB_MALLOC_P(struct subnet_record);
160         if (!subrec) {
161                 DEBUG(0,("make_subnet: malloc fail !\n"));
162                 goto failed;
163         }
164   
165         ZERO_STRUCTP(subrec);
166
167         if((subrec->subnet_name = SMB_STRDUP(name)) == NULL) {
168                 DEBUG(0,("make_subnet: malloc fail for subnet name !\n"));
169                 goto failed;
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->nmb_bcast = nmb_bcast;
185         subrec->dgram_sock = dgram_sock;
186         subrec->dgram_bcast = dgram_bcast;
187
188         return subrec;
189
190 failed:
191         SAFE_FREE(subrec);
192         if (nmb_sock != -1) {
193                 close(nmb_sock);
194         }
195         if (nmb_bcast != -1) {
196                 close(nmb_bcast);
197         }
198         if (dgram_sock != -1) {
199                 close(dgram_sock);
200         }
201         if (dgram_bcast != -1) {
202                 close(dgram_bcast);
203         }
204         return NULL;
205 }
206
207 /****************************************************************************
208   Create a normal subnet
209 **************************************************************************/
210
211 struct subnet_record *make_normal_subnet(const struct interface *iface)
212 {
213
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;
218
219         subrec = make_subnet(inet_ntoa(*pip), NORMAL_SUBNET,
220                              *pip, *pbcast, *pnmask);
221         if (subrec) {
222                 add_subnet(subrec);
223         }
224         return subrec;
225 }
226
227 /****************************************************************************
228   Create subnet entries.
229 **************************************************************************/
230
231 bool create_subnets(void)
232 {
233         /* We only count IPv4 interfaces whilst we're waiting. */
234         int num_interfaces;
235         int i;
236         struct in_addr unicast_ip, ipzero;
237
238   try_interfaces_again:
239
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"));
244         }
245
246         /* We only count IPv4, non-loopback interfaces here. */
247         while (iface_count_v4_nl() == 0) {
248                 void (*saved_handler)(int);
249
250                 /*
251                  * Whilst we're waiting for an interface, allow SIGTERM to
252                  * cause us to exit.
253                  */
254
255                 saved_handler = CatchSignal(SIGTERM, SIG_DFL);
256
257                 sleep(5);
258                 load_interfaces();
259
260                 /*
261                  * We got an interface, restore our normal term handler.
262                  */
263
264                 CatchSignal(SIGTERM, saved_handler);
265         }
266
267         /*
268          * Here we count v4 and v6 - we know there's at least one
269          * IPv4 interface and we filter on it below.
270          */
271         num_interfaces = iface_count();
272
273         /*
274          * Create subnets from all the local interfaces and thread them onto
275          * the linked list.
276          */
277
278         for (i = 0 ; i < num_interfaces; i++) {
279                 const struct interface *iface = get_interface(i);
280
281                 if (!iface) {
282                         DEBUG(2,("create_subnets: can't get interface %d.\n", i ));
283                         continue;
284                 }
285
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;
291                 }
292
293                 /*
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.
297                  */
298
299                 if (is_loopback_addr((const struct sockaddr *)&iface->ip)) {
300                         DEBUG(2,("create_subnets: Ignoring loopback interface.\n" ));
301                         continue;
302                 }
303
304                 if (!make_normal_subnet(iface))
305                         return False;
306         }
307
308         /* We must have at least one subnet. */
309         if (subnetlist == NULL) {
310                 void (*saved_handler)(int);
311
312                 DEBUG(0,("create_subnets: Unable to create any subnet from "
313                                 "given interfaces. Is your interface line in "
314                                 "smb.conf correct ?\n"));
315
316                 saved_handler = CatchSignal(SIGTERM, SIG_DFL);
317
318                 sleep(5);
319                 load_interfaces();
320
321                 CatchSignal(SIGTERM, saved_handler);
322                 goto try_interfaces_again;
323         }
324
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();
329
330                 if (!nip) {
331                         return False;
332                 }
333
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);
340         }
341
342         /*
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.
347          */
348
349         unicast_subnet = make_subnet( "UNICAST_SUBNET", UNICAST_SUBNET, 
350                                 unicast_ip, unicast_ip, unicast_ip);
351
352         zero_ip_v4(&ipzero);
353
354         remote_broadcast_subnet = make_subnet( "REMOTE_BROADCAST_SUBNET",
355                                 REMOTE_BROADCAST_SUBNET,
356                                 ipzero, ipzero, ipzero);
357
358         if((unicast_subnet == NULL) || (remote_broadcast_subnet == NULL))
359                 return False;
360
361         /* 
362          * If we are WINS server, create the WINS_SERVER_SUBNET - don't put on
363          * the linked list.
364          */
365
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;
371         }
372
373         return True;
374 }
375
376 /*******************************************************************
377 Function to tell us if we can use the unicast subnet.
378 ******************************************************************/
379
380 bool we_are_a_wins_client(void)
381 {
382         if (wins_srv_count() > 0) {
383                 return True;
384         }
385
386         return False;
387 }
388
389 /*******************************************************************
390 Access function used by NEXT_SUBNET_INCLUDING_UNICAST
391 ******************************************************************/
392
393 struct subnet_record *get_next_subnet_maybe_unicast(struct subnet_record *subrec)
394 {
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;
401 }
402
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 ******************************************************************/
409
410 struct subnet_record *get_next_subnet_maybe_unicast_or_wins_server(struct subnet_record *subrec)
411 {
412         if(subrec == unicast_subnet) {
413                 if(wins_server_subnet)
414                         return wins_server_subnet;
415                 else
416                         return NULL;
417         }
418
419         if(wins_server_subnet && subrec == wins_server_subnet)
420                 return NULL;
421
422         if((subrec->next == NULL) && we_are_a_wins_client())
423                 return unicast_subnet;
424         else
425                 return subrec->next;
426 }