updated the 3.0 branch from the head branch - ready for alpha18
[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 2 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, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21    
22    Revision History:
23
24 */
25
26 #include "includes.h"
27 #include "smb.h"
28
29 extern int ClientNMB;
30 extern int ClientDGRAM;
31 extern int global_nmb_port;
32
33 extern fstring myworkgroup;
34 extern char **my_netbios_names;
35
36 /* This is the broadcast subnets database. */
37 struct subnet_record *subnetlist = NULL;
38
39 /* Extra subnets - keep these separate so enumeration code doesn't
40    run onto it by mistake. */
41
42 struct subnet_record *unicast_subnet = NULL;
43 struct subnet_record *remote_broadcast_subnet = NULL;
44 struct subnet_record *wins_server_subnet = NULL;
45
46 extern uint16 samba_nb_type; /* Samba's NetBIOS name type. */
47
48 /****************************************************************************
49   Add a subnet into the list.
50   **************************************************************************/
51
52 static void add_subnet(struct subnet_record *subrec)
53 {
54         DLIST_ADD(subnetlist, subrec);
55 }
56
57 /* ************************************************************************** **
58  * Comparison routine for ordering the splay-tree based namelists assoicated
59  * with each subnet record.
60  *
61  *  Input:  Item  - Pointer to the comparison key.
62  *          Node  - Pointer to a node the splay tree.
63  *
64  *  Output: The return value will be <0 , ==0, or >0 depending upon the
65  *          ordinal relationship of the two keys.
66  *
67  * ************************************************************************** **
68  */
69 static int namelist_entry_compare( ubi_trItemPtr Item, ubi_trNodePtr Node )
70   {
71   struct name_record *NR = (struct name_record *)Node;
72
73   if( DEBUGLVL( 10 ) )
74     {
75     struct nmb_name *Iname = (struct nmb_name *)Item;
76
77     Debug1( "nmbd_subnetdb:namelist_entry_compare()\n" );
78     Debug1( "%d == memcmp( \"%s\", \"%s\", %d )\n",
79             memcmp( Item, &(NR->name), sizeof(struct nmb_name) ),
80             nmb_namestr(Iname), nmb_namestr(&NR->name), (int)sizeof(struct nmb_name) );
81     }
82
83   return( memcmp( Item, &(NR->name), sizeof(struct nmb_name) ) ); 
84   } /* namelist_entry_compare */
85
86
87 /****************************************************************************
88 stop listening on a subnet
89 we don't free the record as we don't have proper reference counting for it
90 yet and it may be in use by a response record
91   ****************************************************************************/
92 void close_subnet(struct subnet_record *subrec)
93 {
94         DLIST_REMOVE(subnetlist, subrec);
95
96         if (subrec->dgram_sock != -1) {
97                 close(subrec->dgram_sock);
98                 subrec->dgram_sock = -1;
99         }
100         if (subrec->nmb_sock != -1) {
101                 close(subrec->nmb_sock);
102                 subrec->nmb_sock = -1;
103         }
104 }
105
106
107
108 /****************************************************************************
109   Create a subnet entry.
110   ****************************************************************************/
111
112 static struct subnet_record *make_subnet(char *name, enum subnet_type type,
113                                          struct in_addr myip, struct in_addr bcast_ip, 
114                                          struct in_addr mask_ip)
115 {
116   struct subnet_record *subrec = NULL;
117   int nmb_sock, dgram_sock;
118
119   /* Check if we are creating a non broadcast subnet - if so don't create
120      sockets.
121    */
122
123   if(type != NORMAL_SUBNET)
124   {
125     nmb_sock = -1;
126     dgram_sock = -1;
127   }
128   else
129   {
130     /*
131      * Attempt to open the sockets on port 137/138 for this interface
132      * and bind them.
133      * Fail the subnet creation if this fails.
134      */
135
136     if((nmb_sock = open_socket_in(SOCK_DGRAM, global_nmb_port,0, myip.s_addr,True)) == -1)
137     {
138       if( DEBUGLVL( 0 ) )
139       {
140         Debug1( "nmbd_subnetdb:make_subnet()\n" );
141         Debug1( "  Failed to open nmb socket on interface %s ", inet_ntoa(myip) );
142         Debug1( "for port %d.  ", global_nmb_port );
143         Debug1( "Error was %s\n", strerror(errno) );
144       }
145       return NULL;
146     }
147
148     if((dgram_sock = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3, myip.s_addr,True)) == -1)
149     {
150       if( DEBUGLVL( 0 ) )
151       {
152         Debug1( "nmbd_subnetdb:make_subnet()\n" );
153         Debug1( "  Failed to open dgram socket on interface %s ", inet_ntoa(myip) );
154         Debug1( "for port %d.  ", DGRAM_PORT );
155         Debug1( "Error was %s\n", strerror(errno) );
156       }
157       return NULL;
158     }
159
160     /* Make sure we can broadcast from these sockets. */
161     set_socket_options(nmb_sock,"SO_BROADCAST");
162     set_socket_options(dgram_sock,"SO_BROADCAST");
163
164   }
165
166   subrec = (struct subnet_record *)malloc(sizeof(*subrec));
167   
168   if (!subrec) 
169   {
170     DEBUG(0,("make_subnet: malloc fail !\n"));
171     close(nmb_sock);
172     close(dgram_sock);
173     return(NULL);
174   }
175   
176   memset( (char *)subrec, '\0', sizeof(*subrec) );
177   (void)ubi_trInitTree( subrec->namelist,
178                         namelist_entry_compare,
179                         ubi_trOVERWRITE );
180
181   if((subrec->subnet_name = strdup(name)) == NULL)
182   {
183     DEBUG(0,("make_subnet: malloc fail for subnet name !\n"));
184     close(nmb_sock);
185     close(dgram_sock);
186     ZERO_STRUCTP(subrec);
187     SAFE_FREE(subrec);
188     return(NULL);
189   }
190
191   DEBUG(2, ("making subnet name:%s ", name ));
192   DEBUG(2, ("Broadcast address:%s ", inet_ntoa(bcast_ip)));
193   DEBUG(2, ("Subnet mask:%s\n", inet_ntoa(mask_ip)));
194  
195   subrec->namelist_changed = False;
196   subrec->work_changed = False;
197  
198   subrec->bcast_ip = bcast_ip;
199   subrec->mask_ip  = mask_ip;
200   subrec->myip = myip;
201   subrec->type = type;
202   subrec->nmb_sock = nmb_sock;
203   subrec->dgram_sock = dgram_sock;
204   
205   return subrec;
206 }
207
208
209 /****************************************************************************
210   Create a normal subnet
211 **************************************************************************/
212 struct subnet_record *make_normal_subnet(struct interface *iface)
213 {
214         struct subnet_record *subrec;
215
216         subrec = make_subnet(inet_ntoa(iface->ip), NORMAL_SUBNET,
217                              iface->ip, iface->bcast, iface->nmask);
218         if (subrec) {
219                 add_subnet(subrec);
220         }
221         return subrec;
222 }
223
224
225 /****************************************************************************
226   Create subnet entries.
227 **************************************************************************/
228
229 BOOL create_subnets(void)
230 {    
231   int num_interfaces = iface_count();
232   int i;
233   struct in_addr unicast_ip, ipzero;
234   extern struct in_addr loopback_ip;
235
236   if(num_interfaces == 0) {
237           DEBUG(0,("create_subnets: No local interfaces !\n"));
238           DEBUG(0,("create_subnets: Waiting for an interface to appear ...\n"));
239           while (iface_count() == 0) {
240                   sleep(5);
241                   load_interfaces();
242           }
243   }
244
245   num_interfaces = iface_count();
246
247   /* 
248    * Create subnets from all the local interfaces and thread them onto
249    * the linked list. 
250    */
251
252   for (i = 0 ; i < num_interfaces; i++)
253   {
254     struct interface *iface = get_interface(i);
255
256     /*
257      * We don't want to add a loopback interface, in case
258      * someone has added 127.0.0.1 for smbd, nmbd needs to
259      * ignore it here. JRA.
260      */
261
262     if (ip_equal(iface->ip, loopback_ip)) {
263       DEBUG(2,("create_subnets: Ignoring loopback interface.\n" ));
264       continue;
265     }
266
267     if (!make_normal_subnet(iface)) return False;
268   }
269
270   if (lp_we_are_a_wins_server()) {
271           /* Pick the first interface ip address as the WINS server ip. */
272           unicast_ip = *iface_n_ip(0);
273   } else {
274           /* note that we do not set the wins server IP here. We just
275              set it at zero and let the wins registration code cope
276              with getting the IPs right for each packet */
277           zero_ip(&unicast_ip);
278   }
279
280   /*
281    * Create the unicast and remote broadcast subnets.
282    * Don't put these onto the linked list.
283    * The ip address of the unicast subnet is set to be
284    * the WINS server address, if it exists, or ipzero if not.
285    */
286
287   unicast_subnet = make_subnet( "UNICAST_SUBNET", UNICAST_SUBNET, 
288                                  unicast_ip, unicast_ip, unicast_ip);
289
290   zero_ip(&ipzero);
291
292   remote_broadcast_subnet = make_subnet( "REMOTE_BROADCAST_SUBNET",
293                                          REMOTE_BROADCAST_SUBNET,
294                                          ipzero, ipzero, ipzero);
295
296   if((unicast_subnet == NULL) || (remote_broadcast_subnet == NULL))
297     return False;
298
299   /* 
300    * If we are WINS server, create the WINS_SERVER_SUBNET - don't put on
301    * the linked list.
302    */
303
304   if (lp_we_are_a_wins_server())
305   {
306     if( (wins_server_subnet = make_subnet( "WINS_SERVER_SUBNET",
307                                            WINS_SERVER_SUBNET, 
308                                            ipzero, ipzero, ipzero )) == NULL )
309       return False;
310   }
311
312   return True;
313 }
314
315 /*******************************************************************
316 Function to tell us if we can use the unicast subnet.
317 ******************************************************************/
318 BOOL we_are_a_wins_client(void)
319 {
320         if (wins_srv_count() > 0) {
321                 return True;
322         }
323
324         return False;
325 }
326
327 /*******************************************************************
328 Access function used by NEXT_SUBNET_INCLUDING_UNICAST
329 ******************************************************************/
330
331 struct subnet_record *get_next_subnet_maybe_unicast(struct subnet_record *subrec)
332 {
333   if(subrec == unicast_subnet)
334     return NULL;
335   else if((subrec->next == NULL) && we_are_a_wins_client())
336     return unicast_subnet;
337   else
338     return subrec->next;
339 }
340
341 /*******************************************************************
342  Access function used by retransmit_or_expire_response_records() in
343  nmbd_packets.c. Patch from Andrey Alekseyev <fetch@muffin.arcadia.spb.ru>
344  Needed when we need to enumerate all the broadcast, unicast and
345  WINS subnets.
346 ******************************************************************/
347
348 struct subnet_record *get_next_subnet_maybe_unicast_or_wins_server(struct subnet_record *subrec)
349 {
350   if(subrec == unicast_subnet)
351   {
352     if(wins_server_subnet)
353       return wins_server_subnet;
354     else
355       return NULL;
356   }
357
358   if(wins_server_subnet && subrec == wins_server_subnet)
359     return NULL;
360
361   if((subrec->next == NULL) && we_are_a_wins_client())
362     return unicast_subnet;
363   else
364     return subrec->next;
365 }