40ae1db1b3580590cabc0a95ab8a2c573186f692
[samba.git] / source / nmbd / nmbd_subnetdb.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    NBT netbios routines and daemon - version 2
5    Copyright (C) Andrew Tridgell 1994-1998
6    Copyright (C) Luke Kenneth Casson Leighton 1994-1998
7    Copyright (C) Jeremy Allison 1994-1998
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22    
23    Revision History:
24
25 */
26
27 #include "includes.h"
28 #include "smb.h"
29
30 extern int ClientNMB;
31 extern int ClientDGRAM;
32 extern int global_nmb_port;
33
34 extern int DEBUGLEVEL;
35
36 extern fstring myworkgroup;
37 extern char **my_netbios_names;
38 extern struct in_addr ipzero;
39
40 /* This is the broadcast subnets database. */
41 struct subnet_record *subnetlist = NULL;
42
43 /* Extra subnets - keep these separate so enumeration code doesn't
44    run onto it by mistake. */
45
46 struct subnet_record *unicast_subnet = NULL;
47 struct subnet_record *remote_broadcast_subnet = NULL;
48 struct subnet_record *wins_server_subnet = NULL;
49
50 extern uint16 samba_nb_type; /* Samba's NetBIOS name type. */
51
52 /****************************************************************************
53   Add a subnet into the list.
54   **************************************************************************/
55
56 static void add_subnet(struct subnet_record *subrec)
57 {
58   struct subnet_record *subrec2;
59
60   if (!subnetlist)
61   {
62     subnetlist = subrec;
63     subrec->prev = NULL;
64     subrec->next = NULL;
65     return;
66   }
67
68   for (subrec2 = subnetlist; subrec2->next; subrec2 = subrec2->next)
69     ;
70
71   subrec2->next = subrec;
72   subrec->next = NULL;
73   subrec->prev = subrec2;
74 }
75
76 /* CRH!!! */
77 /* ************************************************************************** ** * This will go away when we move to a "real" database back-end.
78   Note that we cannot use memcmp here as we have no control
79   over how the struct nmb_name structures are packed in memory. JRA.
80  * ************************************************************************** ** */
81 int namelist_entry_compare( ubi_trItemPtr Item, ubi_trNodePtr Node )
82   {
83   struct name_record *NR = (struct name_record *)Node;
84   struct nmb_name *nmbname = (struct nmb_name *)Item;
85   int ret;
86
87   if(nmb_name_equal( &NR->name, nmbname))
88     return 0;
89
90   ret = strcmp( nmbname->name, NR->name.name);
91   if(ret)
92     return ret;
93
94   ret = strcmp( nmbname->scope, NR->name.scope);
95   if(ret)
96     return ret;
97
98   return nmbname->name_type - NR->name.name_type;
99   } /* namelist_entry_compare */
100 /* CRH!!! */   
101
102 /****************************************************************************
103   Create a subnet entry.
104   ****************************************************************************/
105
106 static struct subnet_record *make_subnet(char *name, enum subnet_type type,
107                                          struct in_addr myip, struct in_addr bcast_ip, 
108                                          struct in_addr mask_ip)
109 {
110   struct subnet_record *subrec = NULL;
111   int nmb_sock, dgram_sock;
112
113   /* Check if we are creating a non broadcast subnet - if so don't create
114      sockets.
115    */
116
117   if(type != NORMAL_SUBNET)
118   {
119     nmb_sock = -1;
120     dgram_sock = -1;
121   }
122   else
123   {
124     /*
125      * Attempt to open the sockets on port 137/138 for this interface
126      * and bind them.
127      * Fail the subnet creation if this fails.
128      */
129
130     if((nmb_sock = open_socket_in(SOCK_DGRAM, global_nmb_port,0, myip.s_addr)) == -1)
131     {
132       DEBUG(0,("make_subnet: Failed to open nmb socket on interface %s \
133 for port %d. Error was %s\n", inet_ntoa(myip), global_nmb_port, strerror(errno)));
134       return NULL;
135     }
136
137     if((dgram_sock = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3, myip.s_addr)) == -1)
138     {
139       DEBUG(0,("make_subnet: Failed to open dgram socket on interface %s \
140 for port %d. Error was %s\n", inet_ntoa(myip), DGRAM_PORT, strerror(errno)));
141       return NULL;
142     }
143
144     /* Make sure we can broadcast from these sockets. */
145     set_socket_options(nmb_sock,"SO_BROADCAST");
146     set_socket_options(dgram_sock,"SO_BROADCAST");
147
148   }
149
150   subrec = (struct subnet_record *)malloc(sizeof(*subrec));
151   
152   if (!subrec) 
153   {
154     DEBUG(0,("make_subnet: malloc fail !\n"));
155     close(nmb_sock);
156     close(dgram_sock);
157     return(NULL);
158   }
159   
160   bzero( (char *)subrec, sizeof(*subrec) );
161   (void)ubi_trInitTree( subrec->namelist,
162                         namelist_entry_compare,
163                         ubi_trOVERWRITE );
164
165   if((subrec->subnet_name = strdup(name)) == NULL)
166   {
167     DEBUG(0,("make_subnet: malloc fail for subnet name !\n"));
168     close(nmb_sock);
169     close(dgram_sock);
170     free((char *)subrec);
171     return(NULL);
172   }
173
174   DEBUG(2, ("making subnet name:%s ", name ));
175   DEBUG(2, ("Broadcast address:%s ", inet_ntoa(bcast_ip)));
176   DEBUG(2, ("Subnet mask:%s\n", inet_ntoa(mask_ip)));
177  
178   subrec->namelist_changed = False;
179   subrec->work_changed = False;
180  
181   subrec->bcast_ip = bcast_ip;
182   subrec->mask_ip  = mask_ip;
183   subrec->myip = myip;
184   subrec->type = type;
185   subrec->nmb_sock = nmb_sock;
186   subrec->dgram_sock = dgram_sock;
187   
188   return subrec;
189 }
190
191 /****************************************************************************
192   Create subnet entries.
193 **************************************************************************/
194
195 BOOL create_subnets(void)
196 {    
197   int num_interfaces = iface_count();
198   int i;
199   struct in_addr unicast_ip;
200
201   if(num_interfaces == 0)
202   {
203     DEBUG(0,("create_subnets: No local interfaces !\n"));
204     return False;
205   }
206
207   /* 
208    * Create subnets from all the local interfaces and thread them onto
209    * the linked list. 
210    */
211
212   for (i = 0 ; i < num_interfaces; i++)
213   {
214     struct subnet_record *subrec;
215     struct interface *iface = get_interface(i);
216
217     if((subrec = make_subnet(inet_ntoa(iface->ip), NORMAL_SUBNET,
218                  iface->ip, iface->bcast,iface->nmask)) == NULL)
219       return False;
220     add_subnet(subrec);
221   }
222
223   /* 
224    * If we have been configured to use a WINS server, then try and
225    * get the ip address of it here. If we are the WINS server then
226    * set the unicast subnet address to be the first of our own real
227    * addresses.
228    */
229
230   if(*lp_wins_server())
231   {
232     struct in_addr real_wins_ip;
233     real_wins_ip = *interpret_addr2(lp_wins_server());
234
235     if (!zero_ip(real_wins_ip))
236     {
237       unicast_ip = real_wins_ip;
238     }
239     else
240     {
241       /* The smb.conf's wins server parameter MUST be a host_name
242          or an ip_address. */
243       DEBUG(0,("invalid smb.conf parameter 'wins server'\n"));
244       return False;
245     }
246   } 
247   else if(lp_we_are_a_wins_server())
248   {
249     /* Pick the first interface ip address as the WINS server ip. */
250     unicast_ip = *iface_n_ip(0);
251   }
252   else
253   {
254     /* We should not be using a WINS server at all. Set the
255       ip address of the subnet to be zero. */
256     unicast_ip = ipzero;
257   }
258
259   /*
260    * Create the unicast and remote broadcast subnets.
261    * Don't put these onto the linked list.
262    * The ip address of the unicast subnet is set to be
263    * the WINS server address, if it exists, or ipzero if not.
264    */
265
266   unicast_subnet = make_subnet( "UNICAST_SUBNET", UNICAST_SUBNET, 
267                                  unicast_ip, unicast_ip, unicast_ip);
268
269   remote_broadcast_subnet = make_subnet( "REMOTE_BROADCAST_SUBNET",
270                                          REMOTE_BROADCAST_SUBNET,
271                                          ipzero, ipzero, ipzero);
272
273   if((unicast_subnet == NULL) || (remote_broadcast_subnet == NULL))
274     return False;
275
276   /* 
277    * If we are WINS server, create the WINS_SERVER_SUBNET - don't put on
278    * the linked list.
279    */
280
281   if (lp_we_are_a_wins_server())
282   {
283     if((wins_server_subnet = make_subnet("WINS_SERVER_SUBNET",
284                                        WINS_SERVER_SUBNET, 
285                                        ipzero, ipzero, ipzero)) == NULL)
286       return False;
287   }
288
289   return True;
290 }
291
292 /*******************************************************************
293 Function to tell us if we can use the unicast subnet.
294 ******************************************************************/
295
296 BOOL we_are_a_wins_client(void)
297 {
298   static int cache_we_are_a_wins_client = -1;
299
300   if(cache_we_are_a_wins_client == -1)
301     cache_we_are_a_wins_client = (ip_equal(ipzero, unicast_subnet->myip) ? 
302                                   False : True);
303
304   return cache_we_are_a_wins_client;
305 }
306
307 /*******************************************************************
308 Access function used by NEXT_SUBNET_INCLUDING_UNICAST
309 ******************************************************************/
310
311 struct subnet_record *get_next_subnet_maybe_unicast(struct subnet_record *subrec)
312 {
313   if(subrec == unicast_subnet)
314     return NULL;
315   else if((subrec->next == NULL) && we_are_a_wins_client())
316     return unicast_subnet;
317   else
318     return subrec->next;
319 }
320
321 /*******************************************************************
322  Access function used by retransmit_or_expire_response_records() in
323  nmbd_packets.c. Patch from Andrey Alekseyev <fetch@muffin.arcadia.spb.ru>
324  Needed when we need to enumerate all the broadcast, unicast and
325  WINS subnets.
326 ******************************************************************/
327
328 struct subnet_record *get_next_subnet_maybe_unicast_or_wins_server(struct subnet_record *subrec)
329 {
330   if(subrec == unicast_subnet)
331   {
332     if(wins_server_subnet)
333       return wins_server_subnet;
334     else
335       return NULL;
336   }
337
338   if(wins_server_subnet && subrec == wins_server_subnet)
339     return NULL;
340
341   if((subrec->next == NULL) && we_are_a_wins_client())
342     return unicast_subnet;
343   else
344     return subrec->next;
345 }