r23784: use the GPLv3 boilerplate as recommended by the FSF and the license text
[samba.git] / source / 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
27 extern struct in_addr loopback_ip;
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, dgram_sock;
81
82         /* Check if we are creating a non broadcast subnet - if so don't create
83                 sockets.  */
84
85         if(type != NORMAL_SUBNET) {
86                 nmb_sock = -1;
87                 dgram_sock = -1;
88         } else {
89                 /*
90                  * Attempt to open the sockets on port 137/138 for this interface
91                  * and bind them.
92                  * Fail the subnet creation if this fails.
93                  */
94
95                 if((nmb_sock = open_socket_in(SOCK_DGRAM, global_nmb_port,0, myip.s_addr,True)) == -1) {
96                         if( DEBUGLVL( 0 ) ) {
97                                 Debug1( "nmbd_subnetdb:make_subnet()\n" );
98                                 Debug1( "  Failed to open nmb socket on interface %s ", inet_ntoa(myip) );
99                                 Debug1( "for port %d.  ", global_nmb_port );
100                                 Debug1( "Error was %s\n", strerror(errno) );
101                         }
102                         return NULL;
103                 }
104
105                 if((dgram_sock = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3, myip.s_addr,True)) == -1) {
106                         if( DEBUGLVL( 0 ) ) {
107                                 Debug1( "nmbd_subnetdb:make_subnet()\n" );
108                                 Debug1( "  Failed to open dgram socket on interface %s ", inet_ntoa(myip) );
109                                 Debug1( "for port %d.  ", DGRAM_PORT );
110                                 Debug1( "Error was %s\n", strerror(errno) );
111                         }
112                         return NULL;
113                 }
114
115                 /* Make sure we can broadcast from these sockets. */
116                 set_socket_options(nmb_sock,"SO_BROADCAST");
117                 set_socket_options(dgram_sock,"SO_BROADCAST");
118
119                 /* Set them non-blocking. */
120                 set_blocking(nmb_sock, False);
121                 set_blocking(dgram_sock, False);
122         }
123
124         subrec = SMB_MALLOC_P(struct subnet_record);
125         if (!subrec) {
126                 DEBUG(0,("make_subnet: malloc fail !\n"));
127                 close(nmb_sock);
128                 close(dgram_sock);
129                 return(NULL);
130         }
131   
132         ZERO_STRUCTP(subrec);
133
134         if((subrec->subnet_name = SMB_STRDUP(name)) == NULL) {
135                 DEBUG(0,("make_subnet: malloc fail for subnet name !\n"));
136                 close(nmb_sock);
137                 close(dgram_sock);
138                 ZERO_STRUCTP(subrec);
139                 SAFE_FREE(subrec);
140                 return(NULL);
141         }
142
143         DEBUG(2, ("making subnet name:%s ", name ));
144         DEBUG(2, ("Broadcast address:%s ", inet_ntoa(bcast_ip)));
145         DEBUG(2, ("Subnet mask:%s\n", inet_ntoa(mask_ip)));
146  
147         subrec->namelist_changed = False;
148         subrec->work_changed = False;
149  
150         subrec->bcast_ip = bcast_ip;
151         subrec->mask_ip  = mask_ip;
152         subrec->myip = myip;
153         subrec->type = type;
154         subrec->nmb_sock = nmb_sock;
155         subrec->dgram_sock = dgram_sock;
156   
157         return subrec;
158 }
159
160 /****************************************************************************
161   Create a normal subnet
162 **************************************************************************/
163
164 struct subnet_record *make_normal_subnet(struct interface *iface)
165 {
166         struct subnet_record *subrec;
167
168         subrec = make_subnet(inet_ntoa(iface->ip), NORMAL_SUBNET,
169                              iface->ip, iface->bcast, iface->nmask);
170         if (subrec) {
171                 add_subnet(subrec);
172         }
173         return subrec;
174 }
175
176 /****************************************************************************
177   Create subnet entries.
178 **************************************************************************/
179
180 BOOL create_subnets(void)
181 {    
182         int num_interfaces = iface_count();
183         int i;
184         struct in_addr unicast_ip, ipzero;
185
186         if(num_interfaces == 0) {
187                 void (*saved_handler)(int);
188
189                 DEBUG(0,("create_subnets: No local interfaces !\n"));
190                 DEBUG(0,("create_subnets: Waiting for an interface to appear ...\n"));
191
192                 /* 
193                  * Whilst we're waiting for an interface, allow SIGTERM to
194                  * cause us to exit.
195                  */
196
197                 saved_handler = CatchSignal( SIGTERM, SIGNAL_CAST SIG_DFL );
198
199                 while (iface_count() == 0) {
200                         sleep(5);
201                         load_interfaces();
202                 }
203
204                 /* 
205                  * We got an interface, restore our normal term handler.
206                  */
207
208                 CatchSignal( SIGTERM, SIGNAL_CAST saved_handler );
209         }
210
211         num_interfaces = iface_count();
212
213         /* 
214          * Create subnets from all the local interfaces and thread them onto
215          * the linked list. 
216          */
217
218         for (i = 0 ; i < num_interfaces; i++) {
219                 struct interface *iface = get_interface(i);
220
221                 if (!iface) {
222                         DEBUG(2,("create_subnets: can't get interface %d.\n", i ));
223                         continue;
224                 }
225
226                 /*
227                  * We don't want to add a loopback interface, in case
228                  * someone has added 127.0.0.1 for smbd, nmbd needs to
229                  * ignore it here. JRA.
230                  */
231
232                 if (ip_equal(iface->ip, loopback_ip)) {
233                         DEBUG(2,("create_subnets: Ignoring loopback interface.\n" ));
234                         continue;
235                 }
236
237                 if (!make_normal_subnet(iface))
238                         return False;
239         }
240
241         /* We must have at least one subnet. */
242         if (subnetlist == NULL) {
243                 DEBUG(0,("create_subnets: unable to create any subnet from "
244                                 "given interfaces. nmbd is terminating\n"));
245                 return False;
246         }
247
248         if (lp_we_are_a_wins_server()) {
249                 /* Pick the first interface ip address as the WINS server ip. */
250                 struct in_addr *nip = iface_n_ip(0);
251
252                 if (!nip) {
253                         return False;
254                 }
255
256                 unicast_ip = *nip;
257         } else {
258                 /* note that we do not set the wins server IP here. We just
259                         set it at zero and let the wins registration code cope
260                         with getting the IPs right for each packet */
261                 zero_ip(&unicast_ip);
262         }
263
264         /*
265          * Create the unicast and remote broadcast subnets.
266          * Don't put these onto the linked list.
267          * The ip address of the unicast subnet is set to be
268          * the WINS server address, if it exists, or ipzero if not.
269          */
270
271         unicast_subnet = make_subnet( "UNICAST_SUBNET", UNICAST_SUBNET, 
272                                 unicast_ip, unicast_ip, unicast_ip);
273
274         zero_ip(&ipzero);
275
276         remote_broadcast_subnet = make_subnet( "REMOTE_BROADCAST_SUBNET",
277                                 REMOTE_BROADCAST_SUBNET,
278                                 ipzero, ipzero, ipzero);
279
280         if((unicast_subnet == NULL) || (remote_broadcast_subnet == NULL))
281                 return False;
282
283         /* 
284          * If we are WINS server, create the WINS_SERVER_SUBNET - don't put on
285          * the linked list.
286          */
287
288         if (lp_we_are_a_wins_server()) {
289                 if( (wins_server_subnet = make_subnet( "WINS_SERVER_SUBNET",
290                                                 WINS_SERVER_SUBNET, 
291                                                 ipzero, ipzero, ipzero )) == NULL )
292                         return False;
293         }
294
295         return True;
296 }
297
298 /*******************************************************************
299 Function to tell us if we can use the unicast subnet.
300 ******************************************************************/
301
302 BOOL we_are_a_wins_client(void)
303 {
304         if (wins_srv_count() > 0) {
305                 return True;
306         }
307
308         return False;
309 }
310
311 /*******************************************************************
312 Access function used by NEXT_SUBNET_INCLUDING_UNICAST
313 ******************************************************************/
314
315 struct subnet_record *get_next_subnet_maybe_unicast(struct subnet_record *subrec)
316 {
317         if(subrec == unicast_subnet)
318                 return NULL;
319         else if((subrec->next == NULL) && we_are_a_wins_client())
320                 return unicast_subnet;
321         else
322                 return subrec->next;
323 }
324
325 /*******************************************************************
326  Access function used by retransmit_or_expire_response_records() in
327  nmbd_packets.c. Patch from Andrey Alekseyev <fetch@muffin.arcadia.spb.ru>
328  Needed when we need to enumerate all the broadcast, unicast and
329  WINS subnets.
330 ******************************************************************/
331
332 struct subnet_record *get_next_subnet_maybe_unicast_or_wins_server(struct subnet_record *subrec)
333 {
334         if(subrec == unicast_subnet) {
335                 if(wins_server_subnet)
336                         return wins_server_subnet;
337                 else
338                         return NULL;
339         }
340
341         if(wins_server_subnet && subrec == wins_server_subnet)
342                 return NULL;
343
344         if((subrec->next == NULL) && we_are_a_wins_client())
345                 return unicast_subnet;
346         else
347                 return subrec->next;
348 }