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