source: vendor/current/source4/nbt_server/interfaces.c

Last change on this file was 988, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.3

File size: 11.8 KB
Line 
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#include "lib/util/util_net.h"
33
34
35/*
36 receive an incoming request and dispatch it to the right place
37*/
38static void nbtd_request_handler(struct nbt_name_socket *nbtsock,
39 struct nbt_name_packet *packet,
40 struct socket_address *src)
41{
42 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
43 struct nbtd_interface);
44 struct nbtd_server *nbtsrv = iface->nbtsrv;
45
46 nbtsrv->stats.total_received++;
47
48 /* see if its from one of our own interfaces - if so, then ignore it */
49 if (nbtd_self_packet_and_bcast(nbtsock, packet, src)) {
50 DEBUG(10,("Ignoring bcast self packet from %s:%d\n", src->addr, src->port));
51 return;
52 }
53
54 switch (packet->operation & NBT_OPCODE) {
55 case NBT_OPCODE_QUERY:
56 nbtsrv->stats.query_count++;
57 nbtd_request_query(nbtsock, packet, src);
58 break;
59
60 case NBT_OPCODE_REGISTER:
61 case NBT_OPCODE_REFRESH:
62 case NBT_OPCODE_REFRESH2:
63 nbtsrv->stats.register_count++;
64 nbtd_request_defense(nbtsock, packet, src);
65 break;
66
67 case NBT_OPCODE_RELEASE:
68 case NBT_OPCODE_MULTI_HOME_REG:
69 nbtsrv->stats.release_count++;
70 nbtd_winsserver_request(nbtsock, packet, src);
71 break;
72
73 default:
74 nbtd_bad_packet(packet, src, "Unexpected opcode");
75 break;
76 }
77}
78
79static void nbtd_unexpected_handler(struct nbt_name_socket *nbtsock,
80 struct nbt_name_packet *packet,
81 struct socket_address *src)
82{
83 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
84 struct nbtd_interface);
85 struct nbtd_server *nbtsrv = iface->nbtsrv;
86 struct nbtd_interface *i;
87 struct nbt_name_request *req = NULL;
88
89 nbtsrv->stats.total_received++;
90
91 DEBUG(10,("unexpected from src[%s] on interface[%p] %s/%s\n",
92 src->addr, iface, iface->ip_address, iface->netmask));
93
94 /* try the broadcast interface */
95 if (nbtsrv->bcast_interface) {
96 i = nbtsrv->bcast_interface;
97 req = idr_find(i->nbtsock->idr, packet->name_trn_id);
98 }
99
100 /* try the wins server client interface */
101 if (!req && nbtsrv->wins_interface && nbtsrv->wins_interface->nbtsock) {
102 i = nbtsrv->wins_interface;
103 req = idr_find(i->nbtsock->idr, packet->name_trn_id);
104 }
105
106 /* try all other interfaces... */
107 if (!req) {
108 for (i = nbtsrv->interfaces; i; i = i->next) {
109 if (i == iface) {
110 continue;
111 }
112 req = idr_find(i->nbtsock->idr, packet->name_trn_id);
113 if (req) break;
114 }
115 }
116
117 if (!req) {
118 DEBUG(10,("unexpected from src[%s] unable to redirected\n", src->addr));
119 return;
120 }
121
122 DEBUG(10,("unexpected from src[%s] redirected to interface[%p] %s/%s\n",
123 src->addr, i, i->ip_address, i->netmask));
124
125 /*
126 * redirect the incoming response to the socket
127 * we sent the matching request
128 */
129 nbt_name_socket_handle_response_packet(req, packet, src);
130}
131
132/*
133 find a registered name on an interface
134*/
135struct nbtd_iface_name *nbtd_find_iname(struct nbtd_interface *iface,
136 struct nbt_name *name,
137 uint16_t nb_flags)
138{
139 struct nbtd_iface_name *iname;
140 for (iname=iface->names;iname;iname=iname->next) {
141 if (iname->name.type == name->type &&
142 strcmp(name->name, iname->name.name) == 0 &&
143 ((iname->nb_flags & nb_flags) == nb_flags)) {
144 return iname;
145 }
146 }
147 return NULL;
148}
149
150/*
151 start listening on the given address
152*/
153static NTSTATUS nbtd_add_socket(struct nbtd_server *nbtsrv,
154 struct loadparm_context *lp_ctx,
155 const char *bind_address,
156 const char *address,
157 const char *bcast,
158 const char *netmask)
159{
160 struct nbtd_interface *iface;
161 NTSTATUS status;
162 struct socket_address *bcast_address;
163 struct socket_address *unicast_address;
164
165 DEBUG(6,("nbtd_add_socket(%s, %s, %s, %s)\n", bind_address, address, bcast, netmask));
166
167 /*
168 we actually create two sockets. One listens on the broadcast address
169 for the interface, and the other listens on our specific address. This
170 allows us to run with "bind interfaces only" while still receiving
171 broadcast addresses, and also simplifies matching incoming requests
172 to interfaces
173 */
174
175 iface = talloc(nbtsrv, struct nbtd_interface);
176 NT_STATUS_HAVE_NO_MEMORY(iface);
177
178 iface->nbtsrv = nbtsrv;
179 iface->bcast_address = talloc_steal(iface, bcast);
180 iface->ip_address = talloc_steal(iface, address);
181 iface->netmask = talloc_steal(iface, netmask);
182 iface->names = NULL;
183 iface->wack_queue = NULL;
184
185 if (strcmp(netmask, "0.0.0.0") != 0) {
186 struct nbt_name_socket *bcast_nbtsock;
187
188 /* listen for broadcasts on port 137 */
189 bcast_nbtsock = nbt_name_socket_init(iface, nbtsrv->task->event_ctx);
190 if (!bcast_nbtsock) {
191 talloc_free(iface);
192 return NT_STATUS_NO_MEMORY;
193 }
194
195 bcast_address = socket_address_from_strings(bcast_nbtsock, bcast_nbtsock->sock->backend_name,
196 bcast, lpcfg_nbt_port(lp_ctx));
197 if (!bcast_address) {
198 talloc_free(iface);
199 return NT_STATUS_NO_MEMORY;
200 }
201
202 status = socket_listen(bcast_nbtsock->sock, bcast_address, 0, 0);
203 if (!NT_STATUS_IS_OK(status)) {
204 DEBUG(0,("Failed to bind to %s:%d - %s\n",
205 bcast, lpcfg_nbt_port(lp_ctx), nt_errstr(status)));
206 talloc_free(iface);
207 return status;
208 }
209 talloc_free(bcast_address);
210
211 nbt_set_incoming_handler(bcast_nbtsock, nbtd_request_handler, iface);
212 }
213
214 /* listen for unicasts on port 137 */
215 iface->nbtsock = nbt_name_socket_init(iface, nbtsrv->task->event_ctx);
216 if (!iface->nbtsock) {
217 talloc_free(iface);
218 return NT_STATUS_NO_MEMORY;
219 }
220
221 unicast_address = socket_address_from_strings(iface->nbtsock,
222 iface->nbtsock->sock->backend_name,
223 bind_address, lpcfg_nbt_port(lp_ctx));
224
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, lpcfg_nbt_port(lp_ctx), nt_errstr(status)));
229 talloc_free(iface);
230 return status;
231 }
232 talloc_free(unicast_address);
233
234 nbt_set_incoming_handler(iface->nbtsock, nbtd_request_handler, iface);
235 nbt_set_unexpected_handler(iface->nbtsock, nbtd_unexpected_handler, iface);
236
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;
244 }
245
246 if (strcmp(netmask, "0.0.0.0") == 0) {
247 DLIST_ADD(nbtsrv->bcast_interface, iface);
248 } else {
249 DLIST_ADD(nbtsrv->interfaces, iface);
250 }
251
252 return NT_STATUS_OK;
253}
254
255/*
256 setup a socket for talking to our WINS servers
257*/
258static NTSTATUS nbtd_add_wins_socket(struct nbtd_server *nbtsrv)
259{
260 struct nbtd_interface *iface;
261
262 iface = talloc_zero(nbtsrv, struct nbtd_interface);
263 NT_STATUS_HAVE_NO_MEMORY(iface);
264
265 iface->nbtsrv = nbtsrv;
266
267 DLIST_ADD(nbtsrv->wins_interface, iface);
268
269 return NT_STATUS_OK;
270}
271
272
273/*
274 setup our listening sockets on the configured network interfaces
275*/
276NTSTATUS nbtd_startup_interfaces(struct nbtd_server *nbtsrv, struct loadparm_context *lp_ctx,
277 struct interface *ifaces)
278{
279 int num_interfaces = iface_list_count(ifaces);
280 int i;
281 TALLOC_CTX *tmp_ctx = talloc_new(nbtsrv);
282 NTSTATUS status;
283
284 /* if we are allowing incoming packets from any address, then
285 we also need to bind to the wildcard address */
286 if (!lpcfg_bind_interfaces_only(lp_ctx)) {
287 const char *primary_address;
288
289 primary_address = iface_list_first_v4(ifaces);
290
291 /* the primary address is the address we will return
292 for non-WINS queries not made on a specific
293 interface */
294 if (primary_address == NULL) {
295 primary_address = inet_ntoa(interpret_addr2(
296 lpcfg_netbios_name(lp_ctx)));
297 }
298
299 primary_address = talloc_strdup(tmp_ctx, primary_address);
300 NT_STATUS_HAVE_NO_MEMORY(primary_address);
301
302 status = nbtd_add_socket(nbtsrv,
303 lp_ctx,
304 "0.0.0.0",
305 primary_address,
306 talloc_strdup(tmp_ctx, "255.255.255.255"),
307 talloc_strdup(tmp_ctx, "0.0.0.0"));
308 NT_STATUS_NOT_OK_RETURN(status);
309 }
310
311 for (i=0; i<num_interfaces; i++) {
312 const char *bcast;
313 const char *address, *netmask;
314
315 if (!iface_list_n_is_v4(ifaces, i)) {
316 /* v4 only for NBT protocol */
317 continue;
318 }
319
320 bcast = iface_list_n_bcast(ifaces, i);
321 /* we can't assume every interface is broadcast capable */
322 if (bcast == NULL) continue;
323
324 address = talloc_strdup(tmp_ctx, iface_list_n_ip(ifaces, i));
325 bcast = talloc_strdup(tmp_ctx, bcast);
326 netmask = talloc_strdup(tmp_ctx, iface_list_n_netmask(ifaces, i));
327
328 status = nbtd_add_socket(nbtsrv, lp_ctx,
329 address, address, bcast, netmask);
330 NT_STATUS_NOT_OK_RETURN(status);
331 }
332
333 if (lpcfg_wins_server_list(lp_ctx)) {
334 status = nbtd_add_wins_socket(nbtsrv);
335 NT_STATUS_NOT_OK_RETURN(status);
336 }
337
338 talloc_free(tmp_ctx);
339
340 return NT_STATUS_OK;
341}
342
343
344/*
345 form a list of addresses that we should use in name query replies
346 we always place the IP in the given interface first
347*/
348const char **nbtd_address_list(struct nbtd_interface *iface, TALLOC_CTX *mem_ctx)
349{
350 struct nbtd_server *nbtsrv = iface->nbtsrv;
351 const char **ret = NULL;
352 struct nbtd_interface *iface2;
353 bool is_loopback = false;
354
355 if (iface->ip_address) {
356 is_loopback = iface_list_same_net(iface->ip_address, "127.0.0.1", "255.0.0.0");
357 ret = str_list_add(ret, iface->ip_address);
358 }
359
360 for (iface2=nbtsrv->interfaces;iface2;iface2=iface2->next) {
361 if (iface2 == iface) continue;
362
363 if (!iface2->ip_address) continue;
364
365 if (!is_loopback) {
366 if (iface_list_same_net(iface2->ip_address, "127.0.0.1", "255.0.0.0")) {
367 continue;
368 }
369 }
370
371 ret = str_list_add(ret, iface2->ip_address);
372 }
373
374 talloc_steal(mem_ctx, ret);
375
376 return ret;
377}
378
379
380/*
381 find the interface to use for sending a outgoing request
382*/
383struct nbtd_interface *nbtd_find_request_iface(struct nbtd_server *nbtd_server,
384 const char *address, bool allow_bcast_iface)
385{
386 struct nbtd_interface *cur;
387
388 /* try to find a exact match */
389 for (cur=nbtd_server->interfaces;cur;cur=cur->next) {
390 if (iface_list_same_net(address, cur->ip_address, cur->netmask)) {
391 DEBUG(10,("find interface for dst[%s] ip: %s/%s (iface[%p])\n",
392 address, cur->ip_address, cur->netmask, cur));
393 return cur;
394 }
395 }
396
397 /* no exact match, if we have the broadcast interface, use that */
398 if (allow_bcast_iface && nbtd_server->bcast_interface) {
399 cur = nbtd_server->bcast_interface;
400 DEBUG(10,("find interface for dst[%s] ip: %s/%s (bcast iface[%p])\n",
401 address, cur->ip_address, cur->netmask, cur));
402 return cur;
403 }
404
405 /* fallback to first interface */
406 cur = nbtd_server->interfaces;
407 DEBUG(10,("find interface for dst[%s] ip: %s/%s (default iface[%p])\n",
408 address, cur->ip_address, cur->netmask, cur));
409 return cur;
410}
411
412/*
413 * find the interface to use for sending a outgoing reply
414 */
415struct nbtd_interface *nbtd_find_reply_iface(struct nbtd_interface *iface,
416 const char *address, bool allow_bcast_iface)
417{
418 struct nbtd_server *nbtd_server = iface->nbtsrv;
419
420 /* first try to use the given interfacel when it's not the broadcast one */
421 if (iface != nbtd_server->bcast_interface) {
422 return iface;
423 }
424
425 return nbtd_find_request_iface(nbtd_server, address, allow_bcast_iface);
426}
Note: See TracBrowser for help on using the repository browser.