r6246: stop waiting when we get a reply
[samba.git] / source / nbt_server / interfaces.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    NBT interface handling
5
6    Copyright (C) Andrew Tridgell        2005
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
23 #include "includes.h"
24 #include "dlinklist.h"
25 #include "nbt_server/nbt_server.h"
26 #include "smbd/service_task.h"
27 #include "lib/socket/socket.h"
28
29
30 /*
31   receive an incoming request and dispatch it to the right place
32 */
33 static void nbtd_request_handler(struct nbt_name_socket *nbtsock, 
34                                  struct nbt_name_packet *packet, 
35                                  const char *src_address, int src_port)
36 {
37         /* see if its from one of our own interfaces - if so, then ignore it */
38         if (nbtd_self_packet(nbtsock, packet, src_address, src_port)) {
39                 DEBUG(10,("Ignoring self packet from %s:%d\n", src_address, src_port));
40                 return;
41         }
42
43         switch (packet->operation & NBT_OPCODE) {
44         case NBT_OPCODE_QUERY:
45                 nbtd_request_query(nbtsock, packet, src_address, src_port);
46                 break;
47
48         case NBT_OPCODE_REGISTER:
49         case NBT_OPCODE_REFRESH:
50         case NBT_OPCODE_REFRESH2:
51                 nbtd_request_defense(nbtsock, packet, src_address, src_port);
52                 break;
53
54         case NBT_OPCODE_RELEASE:
55         case NBT_OPCODE_MULTI_HOME_REG:
56                 nbtd_winsserver_request(nbtsock, packet, src_address, src_port);
57                 break;
58
59         default:
60                 nbtd_bad_packet(packet, src_address, "Unexpected opcode");
61                 break;
62         }
63 }
64
65
66 /*
67   receive an incoming dgram request
68 */
69 static void dgram_request_handler(struct nbt_dgram_socket *dgmsock, 
70                                   struct nbt_dgram_packet *packet, 
71                                   const char *src_address, int src_port)
72 {
73 }
74
75
76
77 /*
78   find a registered name on an interface
79 */
80 struct nbtd_iface_name *nbtd_find_iname(struct nbtd_interface *iface, 
81                                         struct nbt_name *name, 
82                                         uint16_t nb_flags)
83 {
84         struct nbtd_iface_name *iname;
85         for (iname=iface->names;iname;iname=iname->next) {
86                 if (iname->name.type == name->type &&
87                     strcmp(name->name, iname->name.name) == 0 &&
88                     ((iname->nb_flags & nb_flags) == nb_flags)) {
89                         return iname;
90                 }
91         }
92         return NULL;
93 }
94
95 /*
96   start listening on the given address
97 */
98 static NTSTATUS nbtd_add_socket(struct nbtd_server *nbtsrv, 
99                                 const char *bind_address, 
100                                 const char *address, 
101                                 const char *bcast, 
102                                 const char *netmask)
103 {
104         struct nbtd_interface *iface;
105         NTSTATUS status;
106
107         /*
108           we actually create two sockets. One listens on the broadcast address
109           for the interface, and the other listens on our specific address. This
110           allows us to run with "bind interfaces only" while still receiving 
111           broadcast addresses, and also simplifies matching incoming requests 
112           to interfaces
113         */
114
115         iface = talloc(nbtsrv, struct nbtd_interface);
116         NT_STATUS_HAVE_NO_MEMORY(iface);
117
118         iface->nbtsrv        = nbtsrv;
119         iface->bcast_address = talloc_steal(iface, bcast);
120         iface->ip_address    = talloc_steal(iface, address);
121         iface->netmask       = talloc_steal(iface, netmask);
122         iface->names         = NULL;
123
124         if (strcmp(netmask, "0.0.0.0") != 0) {
125                 struct nbt_name_socket *bcast_nbtsock;
126                 struct nbt_dgram_socket *bcast_dgmsock;
127
128                 /* listen for broadcasts on port 137 */
129                 bcast_nbtsock = nbt_name_socket_init(iface, nbtsrv->task->event_ctx);
130                 NT_STATUS_HAVE_NO_MEMORY(bcast_nbtsock);
131
132                 status = socket_listen(bcast_nbtsock->sock, bcast, lp_nbt_port(), 0, 0);
133                 if (!NT_STATUS_IS_OK(status)) {
134                         DEBUG(0,("Failed to bind to %s:%d - %s\n", 
135                                  bcast, lp_nbt_port(), nt_errstr(status)));
136                         talloc_free(iface);
137                         return status;
138                 }
139
140                 nbt_set_incoming_handler(bcast_nbtsock, nbtd_request_handler, iface);
141
142
143                 /* listen for broadcasts on port 138 */
144                 bcast_dgmsock = nbt_dgram_socket_init(iface, nbtsrv->task->event_ctx);
145                 NT_STATUS_HAVE_NO_MEMORY(bcast_dgmsock);
146
147                 status = socket_listen(bcast_dgmsock->sock, bcast, lp_dgram_port(), 0, 0);
148                 if (!NT_STATUS_IS_OK(status)) {
149                         DEBUG(0,("Failed to bind to %s:%d - %s\n", 
150                                  bcast, lp_dgram_port(), nt_errstr(status)));
151                         talloc_free(iface);
152                         return status;
153                 }
154
155                 dgram_set_incoming_handler(bcast_dgmsock, dgram_request_handler, iface);
156         }
157
158         /* listen for unicasts on port 137 */
159         iface->nbtsock = nbt_name_socket_init(iface, nbtsrv->task->event_ctx);
160         NT_STATUS_HAVE_NO_MEMORY(iface->nbtsock);
161
162         status = socket_listen(iface->nbtsock->sock, bind_address, lp_nbt_port(), 0, 0);
163         if (!NT_STATUS_IS_OK(status)) {
164                 DEBUG(0,("Failed to bind to %s:%d - %s\n", 
165                          address, lp_nbt_port(), nt_errstr(status)));
166                 talloc_free(iface);
167                 return status;
168         }
169         nbt_set_incoming_handler(iface->nbtsock, nbtd_request_handler, iface);
170
171
172         /* listen for unicasts on port 138 */
173         iface->dgmsock = nbt_dgram_socket_init(iface, nbtsrv->task->event_ctx);
174         NT_STATUS_HAVE_NO_MEMORY(iface->dgmsock);
175
176         status = socket_listen(iface->dgmsock->sock, bind_address, lp_dgram_port(), 0, 0);
177         if (!NT_STATUS_IS_OK(status)) {
178                 DEBUG(0,("Failed to bind to %s:%d - %s\n", 
179                          address, lp_dgram_port(), nt_errstr(status)));
180                 talloc_free(iface);
181                 return status;
182         }
183         dgram_set_incoming_handler(iface->dgmsock, dgram_request_handler, iface);
184
185         if (strcmp(netmask, "0.0.0.0") == 0) {
186                 DLIST_ADD(nbtsrv->bcast_interface, iface);
187         } else {
188                 DLIST_ADD(nbtsrv->interfaces, iface);
189         }
190
191         return NT_STATUS_OK;
192 }
193
194
195 /*
196   setup a socket for talking to our WINS servers
197 */
198 static NTSTATUS nbtd_add_wins_socket(struct nbtd_server *nbtsrv)
199 {
200         struct nbtd_interface *iface;
201
202         iface = talloc_zero(nbtsrv, struct nbtd_interface);
203         NT_STATUS_HAVE_NO_MEMORY(iface);
204
205         iface->nbtsrv        = nbtsrv;
206
207         DLIST_ADD(nbtsrv->wins_interface, iface);
208
209         return NT_STATUS_OK;
210 }
211
212
213 /*
214   setup our listening sockets on the configured network interfaces
215 */
216 NTSTATUS nbtd_startup_interfaces(struct nbtd_server *nbtsrv)
217 {
218         int num_interfaces = iface_count();
219         int i;
220         TALLOC_CTX *tmp_ctx = talloc_new(nbtsrv);
221         NTSTATUS status;
222
223         /* if we are allowing incoming packets from any address, then
224            we also need to bind to the wildcard address */
225         if (!lp_bind_interfaces_only()) {
226                 const char *primary_address;
227
228                 /* the primary address is the address we will return
229                    for non-WINS queries not made on a specific
230                    interface */
231                 if (num_interfaces > 0) {
232                         primary_address = iface_n_ip(0);
233                 } else {
234                         primary_address = sys_inet_ntoa(interpret_addr2(
235                                                                 lp_netbios_name()));
236                 }
237                 primary_address = talloc_strdup(tmp_ctx, primary_address);
238                 NT_STATUS_HAVE_NO_MEMORY(primary_address);
239
240                 status = nbtd_add_socket(nbtsrv, 
241                                          "0.0.0.0",
242                                          primary_address,
243                                          talloc_strdup(tmp_ctx, "255.255.255.255"),
244                                          talloc_strdup(tmp_ctx, "0.0.0.0"));
245                 NT_STATUS_NOT_OK_RETURN(status);
246         }
247
248         for (i=0; i<num_interfaces; i++) {
249                 const char *address = talloc_strdup(tmp_ctx, iface_n_ip(i));
250                 const char *bcast   = talloc_strdup(tmp_ctx, iface_n_bcast(i));
251                 const char *netmask = talloc_strdup(tmp_ctx, iface_n_netmask(i));
252
253                 status = nbtd_add_socket(nbtsrv, address, address, bcast, netmask);
254                 NT_STATUS_NOT_OK_RETURN(status);
255         }
256
257         if (lp_wins_server_list()) {
258                 status = nbtd_add_wins_socket(nbtsrv);
259                 NT_STATUS_NOT_OK_RETURN(status);
260         }
261
262         talloc_free(tmp_ctx);
263
264         return NT_STATUS_OK;
265 }
266
267
268 /*
269   form a list of addresses that we should use in name query replies
270   we always place the IP in the given interface first
271 */
272 const char **nbtd_address_list(struct nbtd_interface *iface, TALLOC_CTX *mem_ctx)
273 {
274         struct nbtd_server *nbtsrv = iface->nbtsrv;
275         const char **ret = NULL;
276         struct nbtd_interface *iface2;
277         int count = 0;
278
279         if (iface->ip_address) {
280                 ret = talloc_array(mem_ctx, const char *, 2);
281                 if (ret == NULL) goto failed;
282
283                 ret[0] = talloc_strdup(ret, iface->ip_address);
284                 if (ret[0] == NULL) goto failed;
285                 ret[1] = NULL;
286
287                 count = 1;
288         }
289
290         for (iface2=nbtsrv->interfaces;iface2;iface2=iface2->next) {
291                 const char **ret2;
292
293                 if (iface->ip_address &&
294                     strcmp(iface2->ip_address, iface->ip_address) == 0) {
295                         continue;
296                 }
297
298                 ret2 = talloc_realloc(mem_ctx, ret, const char *, count+2);
299                 if (ret2 == NULL) goto failed;
300                 ret = ret2;
301                 ret[count] = talloc_strdup(ret, iface2->ip_address);
302                 if (ret[count] == NULL) goto failed;
303                 count++;
304         }
305         ret[count] = NULL;
306         return ret;
307
308 failed:
309         talloc_free(ret);
310         return NULL;
311 }