nbt_server: fix crash bug, the wins client interface may not have a nbtsock
[Samba/gbeck.git] / source4 / nbt_server / interfaces.c
blob0a9196a74753dc535456e35c0c4f56d8ef5de4dc
1 /*
2 Unix SMB/CIFS implementation.
4 NBT interface handling
6 Copyright (C) Andrew Tridgell 2005
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.
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.
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/>.
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"
35 receive an incoming request and dispatch it to the right place
37 static void nbtd_request_handler(struct nbt_name_socket *nbtsock,
38 struct nbt_name_packet *packet,
39 struct socket_address *src)
41 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
42 struct nbtd_interface);
43 struct nbtd_server *nbtsrv = iface->nbtsrv;
45 nbtsrv->stats.total_received++;
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;
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;
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;
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;
72 default:
73 nbtd_bad_packet(packet, src, "Unexpected opcode");
74 break;
78 static void nbtd_unexpected_handler(struct nbt_name_socket *nbtsock,
79 struct nbt_name_packet *packet,
80 struct socket_address *src)
82 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
83 struct nbtd_interface);
84 struct nbtd_server *nbtsrv = iface->nbtsrv;
85 struct nbtd_interface *i;
86 struct nbt_name_request *req = NULL;
88 nbtsrv->stats.total_received++;
90 DEBUG(10,("unexpected from src[%s] on interface[%p] %s/%s\n",
91 src->addr, iface, iface->ip_address, iface->netmask));
93 /* try the broadcast interface */
94 if (nbtsrv->bcast_interface) {
95 i = nbtsrv->bcast_interface;
96 req = idr_find(i->nbtsock->idr, packet->name_trn_id);
99 /* try the wins server client interface */
100 if (!req && nbtsrv->wins_interface && nbtsrv->wins_interface->nbtsock) {
101 i = nbtsrv->wins_interface;
102 req = idr_find(i->nbtsock->idr, packet->name_trn_id);
105 /* try all other interfaces... */
106 if (!req) {
107 for (i = nbtsrv->interfaces; i; i = i->next) {
108 if (i == iface) {
109 continue;
111 req = idr_find(i->nbtsock->idr, packet->name_trn_id);
112 if (req) break;
116 if (!req) {
117 DEBUG(10,("unexpected from src[%s] unable to redirected\n", src->addr));
118 return;
121 DEBUG(10,("unexpected from src[%s] redirected to interface[%p] %s/%s\n",
122 src->addr, i, i->ip_address, i->netmask));
125 * redirect the incoming response to the socket
126 * we sent the matching request
128 nbt_name_socket_handle_response_packet(req, packet, src);
132 find a registered name on an interface
134 struct nbtd_iface_name *nbtd_find_iname(struct nbtd_interface *iface,
135 struct nbt_name *name,
136 uint16_t nb_flags)
138 struct nbtd_iface_name *iname;
139 for (iname=iface->names;iname;iname=iname->next) {
140 if (iname->name.type == name->type &&
141 strcmp(name->name, iname->name.name) == 0 &&
142 ((iname->nb_flags & nb_flags) == nb_flags)) {
143 return iname;
146 return NULL;
150 start listening on the given address
152 static NTSTATUS nbtd_add_socket(struct nbtd_server *nbtsrv,
153 struct loadparm_context *lp_ctx,
154 const char *bind_address,
155 const char *address,
156 const char *bcast,
157 const char *netmask)
159 struct nbtd_interface *iface;
160 NTSTATUS status;
161 struct socket_address *bcast_address;
162 struct socket_address *unicast_address;
164 DEBUG(6,("nbtd_add_socket(%s, %s, %s, %s)\n", bind_address, address, bcast, netmask));
167 we actually create two sockets. One listens on the broadcast address
168 for the interface, and the other listens on our specific address. This
169 allows us to run with "bind interfaces only" while still receiving
170 broadcast addresses, and also simplifies matching incoming requests
171 to interfaces
174 iface = talloc(nbtsrv, struct nbtd_interface);
175 NT_STATUS_HAVE_NO_MEMORY(iface);
177 iface->nbtsrv = nbtsrv;
178 iface->bcast_address = talloc_steal(iface, bcast);
179 iface->ip_address = talloc_steal(iface, address);
180 iface->netmask = talloc_steal(iface, netmask);
181 iface->names = NULL;
182 iface->wack_queue = NULL;
184 if (strcmp(netmask, "0.0.0.0") != 0) {
185 struct nbt_name_socket *bcast_nbtsock;
187 /* listen for broadcasts on port 137 */
188 bcast_nbtsock = nbt_name_socket_init(iface, nbtsrv->task->event_ctx, lp_iconv_convenience(nbtsrv->task->lp_ctx));
189 if (!bcast_nbtsock) {
190 talloc_free(iface);
191 return NT_STATUS_NO_MEMORY;
194 bcast_address = socket_address_from_strings(bcast_nbtsock, bcast_nbtsock->sock->backend_name,
195 bcast, lp_nbt_port(lp_ctx));
196 if (!bcast_address) {
197 talloc_free(iface);
198 return NT_STATUS_NO_MEMORY;
201 status = socket_listen(bcast_nbtsock->sock, bcast_address, 0, 0);
202 if (!NT_STATUS_IS_OK(status)) {
203 DEBUG(0,("Failed to bind to %s:%d - %s\n",
204 bcast, lp_nbt_port(lp_ctx), nt_errstr(status)));
205 talloc_free(iface);
206 return status;
208 talloc_free(bcast_address);
210 nbt_set_incoming_handler(bcast_nbtsock, nbtd_request_handler, iface);
213 /* listen for unicasts on port 137 */
214 iface->nbtsock = nbt_name_socket_init(iface, nbtsrv->task->event_ctx,
215 lp_iconv_convenience(nbtsrv->task->lp_ctx));
216 if (!iface->nbtsock) {
217 talloc_free(iface);
218 return NT_STATUS_NO_MEMORY;
221 unicast_address = socket_address_from_strings(iface->nbtsock,
222 iface->nbtsock->sock->backend_name,
223 bind_address, lp_nbt_port(lp_ctx));
225 status = socket_listen(iface->nbtsock->sock, unicast_address, 0, 0);
226 if (!NT_STATUS_IS_OK(status)) {
227 DEBUG(0,("Failed to bind to %s:%d - %s\n",
228 bind_address, lp_nbt_port(lp_ctx), nt_errstr(status)));
229 talloc_free(iface);
230 return status;
232 talloc_free(unicast_address);
234 nbt_set_incoming_handler(iface->nbtsock, nbtd_request_handler, iface);
235 nbt_set_unexpected_handler(iface->nbtsock, nbtd_unexpected_handler, iface);
237 /* also setup the datagram listeners */
238 status = nbtd_dgram_setup(iface, bind_address);
239 if (!NT_STATUS_IS_OK(status)) {
240 DEBUG(0,("Failed to setup dgram listen on %s - %s\n",
241 bind_address, nt_errstr(status)));
242 talloc_free(iface);
243 return status;
246 if (strcmp(netmask, "0.0.0.0") == 0) {
247 DLIST_ADD(nbtsrv->bcast_interface, iface);
248 } else {
249 DLIST_ADD(nbtsrv->interfaces, iface);
252 return NT_STATUS_OK;
256 setup a socket for talking to our WINS servers
258 static NTSTATUS nbtd_add_wins_socket(struct nbtd_server *nbtsrv)
260 struct nbtd_interface *iface;
262 iface = talloc_zero(nbtsrv, struct nbtd_interface);
263 NT_STATUS_HAVE_NO_MEMORY(iface);
265 iface->nbtsrv = nbtsrv;
267 DLIST_ADD(nbtsrv->wins_interface, iface);
269 return NT_STATUS_OK;
274 setup our listening sockets on the configured network interfaces
276 NTSTATUS nbtd_startup_interfaces(struct nbtd_server *nbtsrv, struct loadparm_context *lp_ctx,
277 struct interface *ifaces)
279 int num_interfaces = iface_count(ifaces);
280 int i;
281 TALLOC_CTX *tmp_ctx = talloc_new(nbtsrv);
282 NTSTATUS status;
284 /* if we are allowing incoming packets from any address, then
285 we also need to bind to the wildcard address */
286 if (!lp_bind_interfaces_only(lp_ctx)) {
287 const char *primary_address;
289 /* the primary address is the address we will return
290 for non-WINS queries not made on a specific
291 interface */
292 if (num_interfaces > 0) {
293 primary_address = iface_n_ip(ifaces, 0);
294 } else {
295 primary_address = inet_ntoa(interpret_addr2(
296 lp_netbios_name(lp_ctx)));
298 primary_address = talloc_strdup(tmp_ctx, primary_address);
299 NT_STATUS_HAVE_NO_MEMORY(primary_address);
301 status = nbtd_add_socket(nbtsrv,
302 lp_ctx,
303 "0.0.0.0",
304 primary_address,
305 talloc_strdup(tmp_ctx, "255.255.255.255"),
306 talloc_strdup(tmp_ctx, "0.0.0.0"));
307 NT_STATUS_NOT_OK_RETURN(status);
310 for (i=0; i<num_interfaces; i++) {
311 const char *bcast = iface_n_bcast(ifaces, i);
312 const char *address, *netmask;
314 /* we can't assume every interface is broadcast capable */
315 if (bcast == NULL) continue;
317 address = talloc_strdup(tmp_ctx, iface_n_ip(ifaces, i));
318 bcast = talloc_strdup(tmp_ctx, bcast);
319 netmask = talloc_strdup(tmp_ctx, iface_n_netmask(ifaces, i));
321 status = nbtd_add_socket(nbtsrv, lp_ctx,
322 address, address, bcast, netmask);
323 NT_STATUS_NOT_OK_RETURN(status);
326 if (lp_wins_server_list(lp_ctx)) {
327 status = nbtd_add_wins_socket(nbtsrv);
328 NT_STATUS_NOT_OK_RETURN(status);
331 talloc_free(tmp_ctx);
333 return NT_STATUS_OK;
338 form a list of addresses that we should use in name query replies
339 we always place the IP in the given interface first
341 const char **nbtd_address_list(struct nbtd_interface *iface, TALLOC_CTX *mem_ctx)
343 struct nbtd_server *nbtsrv = iface->nbtsrv;
344 const char **ret = NULL;
345 struct nbtd_interface *iface2;
346 bool is_loopback = false;
348 if (iface->ip_address) {
349 is_loopback = iface_same_net(iface->ip_address, "127.0.0.1", "255.0.0.0");
350 ret = str_list_add(ret, iface->ip_address);
353 for (iface2=nbtsrv->interfaces;iface2;iface2=iface2->next) {
354 if (iface2 == iface) continue;
356 if (!iface2->ip_address) continue;
358 if (!is_loopback) {
359 if (iface_same_net(iface2->ip_address, "127.0.0.1", "255.0.0.0")) {
360 continue;
364 ret = str_list_add(ret, iface2->ip_address);
367 talloc_steal(mem_ctx, ret);
369 return ret;
374 find the interface to use for sending a outgoing request
376 struct nbtd_interface *nbtd_find_request_iface(struct nbtd_server *nbtd_server,
377 const char *address, bool allow_bcast_iface)
379 struct nbtd_interface *cur;
381 /* try to find a exact match */
382 for (cur=nbtd_server->interfaces;cur;cur=cur->next) {
383 if (iface_same_net(address, cur->ip_address, cur->netmask)) {
384 DEBUG(10,("find interface for dst[%s] ip: %s/%s (iface[%p])\n",
385 address, cur->ip_address, cur->netmask, cur));
386 return cur;
390 /* no exact match, if we have the broadcast interface, use that */
391 if (allow_bcast_iface && nbtd_server->bcast_interface) {
392 cur = nbtd_server->bcast_interface;
393 DEBUG(10,("find interface for dst[%s] ip: %s/%s (bcast iface[%p])\n",
394 address, cur->ip_address, cur->netmask, cur));
395 return cur;
398 /* fallback to first interface */
399 cur = nbtd_server->interfaces;
400 DEBUG(10,("find interface for dst[%s] ip: %s/%s (default iface[%p])\n",
401 address, cur->ip_address, cur->netmask, cur));
402 return cur;
406 * find the interface to use for sending a outgoing reply
408 struct nbtd_interface *nbtd_find_reply_iface(struct nbtd_interface *iface,
409 const char *address, bool allow_bcast_iface)
411 struct nbtd_server *nbtd_server = iface->nbtsrv;
413 /* first try to use the given interfacel when it's not the broadcast one */
414 if (iface != nbtd_server->bcast_interface) {
415 return iface;
418 return nbtd_find_request_iface(nbtd_server, address, allow_bcast_iface);