Merge branch 'selftest' of git://git.samba.org/jelmer/samba
[kai/samba.git] / source4 / 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 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
22 #include "includes.h"
23 #include "../lib/util/dlinklist.h"
24 #include "nbt_server/nbt_server.h"
25 #include "smbd/service_task.h"
26 #include "lib/socket/socket.h"
27 #include "nbt_server/wins/winsserver.h"
28 #include "nbt_server/dgram/proto.h"
29 #include "system/network.h"
30 #include "lib/socket/netif.h"
31 #include "param/param.h"
32
33
34 /*
35   receive an incoming request and dispatch it to the right place
36 */
37 static void nbtd_request_handler(struct nbt_name_socket *nbtsock, 
38                                  struct nbt_name_packet *packet, 
39                                  struct socket_address *src)
40 {
41         struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
42                                                        struct nbtd_interface);
43         struct nbtd_server *nbtsrv = iface->nbtsrv;
44
45         nbtsrv->stats.total_received++;
46
47         /* see if its from one of our own interfaces - if so, then ignore it */
48         if (nbtd_self_packet_and_bcast(nbtsock, packet, src)) {
49                 DEBUG(10,("Ignoring bcast self packet from %s:%d\n", src->addr, src->port));
50                 return;
51         }
52
53         switch (packet->operation & NBT_OPCODE) {
54         case NBT_OPCODE_QUERY:
55                 nbtsrv->stats.query_count++;
56                 nbtd_request_query(nbtsock, packet, src);
57                 break;
58
59         case NBT_OPCODE_REGISTER:
60         case NBT_OPCODE_REFRESH:
61         case NBT_OPCODE_REFRESH2:
62                 nbtsrv->stats.register_count++;
63                 nbtd_request_defense(nbtsock, packet, src);
64                 break;
65
66         case NBT_OPCODE_RELEASE:
67         case NBT_OPCODE_MULTI_HOME_REG:
68                 nbtsrv->stats.release_count++;
69                 nbtd_winsserver_request(nbtsock, packet, src);
70                 break;
71
72         default:
73                 nbtd_bad_packet(packet, src, "Unexpected opcode");
74                 break;
75         }
76 }
77
78
79 /*
80   find a registered name on an interface
81 */
82 struct nbtd_iface_name *nbtd_find_iname(struct nbtd_interface *iface, 
83                                         struct nbt_name *name, 
84                                         uint16_t nb_flags)
85 {
86         struct nbtd_iface_name *iname;
87         for (iname=iface->names;iname;iname=iname->next) {
88                 if (iname->name.type == name->type &&
89                     strcmp(name->name, iname->name.name) == 0 &&
90                     ((iname->nb_flags & nb_flags) == nb_flags)) {
91                         return iname;
92                 }
93         }
94         return NULL;
95 }
96
97 /*
98   start listening on the given address
99 */
100 static NTSTATUS nbtd_add_socket(struct nbtd_server *nbtsrv, 
101                                 struct loadparm_context *lp_ctx,
102                                 const char *bind_address, 
103                                 const char *address, 
104                                 const char *bcast, 
105                                 const char *netmask)
106 {
107         struct nbtd_interface *iface;
108         NTSTATUS status;
109         struct socket_address *bcast_address;
110         struct socket_address *unicast_address;
111
112         /*
113           we actually create two sockets. One listens on the broadcast address
114           for the interface, and the other listens on our specific address. This
115           allows us to run with "bind interfaces only" while still receiving 
116           broadcast addresses, and also simplifies matching incoming requests 
117           to interfaces
118         */
119
120         iface = talloc(nbtsrv, struct nbtd_interface);
121         NT_STATUS_HAVE_NO_MEMORY(iface);
122
123         iface->nbtsrv        = nbtsrv;
124         iface->bcast_address = talloc_steal(iface, bcast);
125         iface->ip_address    = talloc_steal(iface, address);
126         iface->netmask       = talloc_steal(iface, netmask);
127         iface->names         = NULL;
128
129         if (strcmp(netmask, "0.0.0.0") != 0) {
130                 struct nbt_name_socket *bcast_nbtsock;
131
132                 /* listen for broadcasts on port 137 */
133                 bcast_nbtsock = nbt_name_socket_init(iface, nbtsrv->task->event_ctx, lp_iconv_convenience(nbtsrv->task->lp_ctx));
134                 if (!bcast_nbtsock) {
135                         talloc_free(iface);
136                         return NT_STATUS_NO_MEMORY;
137                 }
138
139                 bcast_address = socket_address_from_strings(bcast_nbtsock, bcast_nbtsock->sock->backend_name, 
140                                                             bcast, lp_nbt_port(lp_ctx));
141                 if (!bcast_address) {
142                         talloc_free(iface);
143                         return NT_STATUS_NO_MEMORY;
144                 }
145
146                 status = socket_listen(bcast_nbtsock->sock, bcast_address, 0, 0);
147                 if (!NT_STATUS_IS_OK(status)) {
148                         DEBUG(0,("Failed to bind to %s:%d - %s\n", 
149                                  bcast, lp_nbt_port(lp_ctx), nt_errstr(status)));
150                         talloc_free(iface);
151                         return status;
152                 }
153                 talloc_free(bcast_address);
154
155                 nbt_set_incoming_handler(bcast_nbtsock, nbtd_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                                               lp_iconv_convenience(nbtsrv->task->lp_ctx));
161         if (!iface->nbtsock) {
162                 talloc_free(iface);
163                 return NT_STATUS_NO_MEMORY;
164         }
165
166         unicast_address = socket_address_from_strings(iface->nbtsock, 
167                                                       iface->nbtsock->sock->backend_name, 
168                                                       bind_address, lp_nbt_port(lp_ctx));
169
170         status = socket_listen(iface->nbtsock->sock, unicast_address, 0, 0);
171         if (!NT_STATUS_IS_OK(status)) {
172                 DEBUG(0,("Failed to bind to %s:%d - %s\n", 
173                          bind_address, lp_nbt_port(lp_ctx), nt_errstr(status)));
174                 talloc_free(iface);
175                 return status;
176         }
177         talloc_free(unicast_address);
178
179         nbt_set_incoming_handler(iface->nbtsock, nbtd_request_handler, iface);
180
181         /* also setup the datagram listeners */
182         status = nbtd_dgram_setup(iface, bind_address);
183         if (!NT_STATUS_IS_OK(status)) {
184                 DEBUG(0,("Failed to setup dgram listen on %s - %s\n", 
185                          bind_address, nt_errstr(status)));
186                 talloc_free(iface);
187                 return status;
188         }
189         
190         if (strcmp(netmask, "0.0.0.0") == 0) {
191                 DLIST_ADD(nbtsrv->bcast_interface, iface);
192         } else {
193                 DLIST_ADD(nbtsrv->interfaces, iface);
194         }
195
196         return NT_STATUS_OK;
197 }
198
199 /*
200   setup a socket for talking to our WINS servers
201 */
202 static NTSTATUS nbtd_add_wins_socket(struct nbtd_server *nbtsrv)
203 {
204         struct nbtd_interface *iface;
205
206         iface = talloc_zero(nbtsrv, struct nbtd_interface);
207         NT_STATUS_HAVE_NO_MEMORY(iface);
208
209         iface->nbtsrv        = nbtsrv;
210
211         DLIST_ADD(nbtsrv->wins_interface, iface);
212
213         return NT_STATUS_OK;
214 }
215
216
217 /*
218   setup our listening sockets on the configured network interfaces
219 */
220 NTSTATUS nbtd_startup_interfaces(struct nbtd_server *nbtsrv, struct loadparm_context *lp_ctx,
221                                  struct interface *ifaces)
222 {
223         int num_interfaces = iface_count(ifaces);
224         int i;
225         TALLOC_CTX *tmp_ctx = talloc_new(nbtsrv);
226         NTSTATUS status;
227
228         /* if we are allowing incoming packets from any address, then
229            we also need to bind to the wildcard address */
230         if (!lp_bind_interfaces_only(lp_ctx)) {
231                 const char *primary_address;
232
233                 /* the primary address is the address we will return
234                    for non-WINS queries not made on a specific
235                    interface */
236                 if (num_interfaces > 0) {
237                         primary_address = iface_n_ip(ifaces, 0);
238                 } else {
239                         primary_address = inet_ntoa(interpret_addr2(
240                                                         lp_netbios_name(lp_ctx)));
241                 }
242                 primary_address = talloc_strdup(tmp_ctx, primary_address);
243                 NT_STATUS_HAVE_NO_MEMORY(primary_address);
244
245                 status = nbtd_add_socket(nbtsrv, 
246                                          lp_ctx,
247                                          "0.0.0.0",
248                                          primary_address,
249                                          talloc_strdup(tmp_ctx, "255.255.255.255"),
250                                          talloc_strdup(tmp_ctx, "0.0.0.0"));
251                 NT_STATUS_NOT_OK_RETURN(status);
252         }
253
254         for (i=0; i<num_interfaces; i++) {
255                 const char *bcast = iface_n_bcast(ifaces, i);
256                 const char *address, *netmask;
257
258                 /* we can't assume every interface is broadcast capable */
259                 if (bcast == NULL) continue;
260
261                 address = talloc_strdup(tmp_ctx, iface_n_ip(ifaces, i));
262                 bcast   = talloc_strdup(tmp_ctx, bcast);
263                 netmask = talloc_strdup(tmp_ctx, iface_n_netmask(ifaces, i));
264
265                 status = nbtd_add_socket(nbtsrv, lp_ctx, 
266                                          address, address, bcast, netmask);
267                 NT_STATUS_NOT_OK_RETURN(status);
268         }
269
270         if (lp_wins_server_list(lp_ctx)) {
271                 status = nbtd_add_wins_socket(nbtsrv);
272                 NT_STATUS_NOT_OK_RETURN(status);
273         }
274
275         talloc_free(tmp_ctx);
276
277         return NT_STATUS_OK;
278 }
279
280
281 /*
282   form a list of addresses that we should use in name query replies
283   we always place the IP in the given interface first
284 */
285 const char **nbtd_address_list(struct nbtd_interface *iface, TALLOC_CTX *mem_ctx)
286 {
287         struct nbtd_server *nbtsrv = iface->nbtsrv;
288         const char **ret = NULL;
289         struct nbtd_interface *iface2;
290         bool is_loopback = false;
291
292         if (iface->ip_address) {
293                 is_loopback = iface_same_net(iface->ip_address, "127.0.0.1", "255.0.0.0");
294                 ret = str_list_add(ret, iface->ip_address);
295         }
296
297         for (iface2=nbtsrv->interfaces;iface2;iface2=iface2->next) {
298                 if (iface2 == iface) continue;
299
300                 if (!iface2->ip_address) continue;
301
302                 if (!is_loopback) {
303                         if (iface_same_net(iface2->ip_address, "127.0.0.1", "255.0.0.0")) {
304                                 continue;
305                         }
306                 }
307
308                 ret = str_list_add(ret, iface2->ip_address);
309         }
310
311         talloc_steal(mem_ctx, ret);
312
313         return ret;
314 }
315
316
317 /*
318   find the interface to use for sending a outgoing request
319 */
320 struct nbtd_interface *nbtd_find_request_iface(struct nbtd_server *nbtd_server,
321                                                const char *address, bool allow_bcast_iface)
322 {
323         struct nbtd_interface *cur;
324
325         /* try to find a exact match */
326         for (cur=nbtd_server->interfaces;cur;cur=cur->next) {
327                 if (iface_same_net(address, cur->ip_address, cur->netmask)) {
328                         return cur;
329                 }
330         }
331
332         /* no exact match, if we have the broadcast interface, use that */
333         if (allow_bcast_iface && nbtd_server->bcast_interface) {
334                 return nbtd_server->bcast_interface;
335         }
336
337         /* fallback to first interface */
338         return nbtd_server->interfaces;
339 }
340
341 /*
342  * find the interface to use for sending a outgoing reply
343  */
344 struct nbtd_interface *nbtd_find_reply_iface(struct nbtd_interface *iface,
345                                              const char *address, bool allow_bcast_iface)
346 {
347         struct nbtd_server *nbtd_server = iface->nbtsrv;
348
349         /* first try to use the given interfacel when it's not the broadcast one */
350         if (iface != nbtd_server->bcast_interface) {
351                 return iface;
352         }
353
354         return nbtd_find_request_iface(nbtd_server, address, allow_bcast_iface);
355 }