source: trunk/server/source4/nbt_server/interfaces.c

Last change on this file was 745, checked in by Silvan Scherrer, 13 years ago

Samba Server: updated trunk to 3.6.0

File size: 12.0 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_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 /* 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 lpcfg_netbios_name(lp_ctx)));
297 }
298 primary_address = talloc_strdup(tmp_ctx, primary_address);
299 NT_STATUS_HAVE_NO_MEMORY(primary_address);
300
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);
308 }
309
310 for (i=0; i<num_interfaces; i++) {
311 const char *bcast = iface_n_bcast(ifaces, i);
312 const char *address, *netmask;
313
314 /* we can't assume every interface is broadcast capable */
315 if (bcast == NULL) continue;
316
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));
320
321 status = nbtd_add_socket(nbtsrv, lp_ctx,
322 address, address, bcast, netmask);
323 NT_STATUS_NOT_OK_RETURN(status);
324 }
325
326 if (lpcfg_wins_server_list(lp_ctx)) {
327 status = nbtd_add_wins_socket(nbtsrv);
328 NT_STATUS_NOT_OK_RETURN(status);
329 }
330
331 talloc_free(tmp_ctx);
332
333 return NT_STATUS_OK;
334}
335
336
337/*
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
340*/
341const char **nbtd_address_list(struct nbtd_interface *iface, TALLOC_CTX *mem_ctx)
342{
343 struct nbtd_server *nbtsrv = iface->nbtsrv;
344 const char **ret = NULL;
345 struct nbtd_interface *iface2;
346 bool is_loopback = false;
347
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);
351 }
352
353 for (iface2=nbtsrv->interfaces;iface2;iface2=iface2->next) {
354 if (iface2 == iface) continue;
355
356 if (!iface2->ip_address) continue;
357
358 if (!is_loopback) {
359 if (iface_same_net(iface2->ip_address, "127.0.0.1", "255.0.0.0")) {
360 continue;
361 }
362 }
363
364 ret = str_list_add(ret, iface2->ip_address);
365 }
366
367 talloc_steal(mem_ctx, ret);
368
369 return ret;
370}
371
372
373/*
374 find the interface to use for sending a outgoing request
375*/
376struct nbtd_interface *nbtd_find_request_iface(struct nbtd_server *nbtd_server,
377 const char *address, bool allow_bcast_iface)
378{
379 struct nbtd_interface *cur;
380
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;
387 }
388 }
389
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;
396 }
397
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;
403}
404
405/*
406 * find the interface to use for sending a outgoing reply
407 */
408struct nbtd_interface *nbtd_find_reply_iface(struct nbtd_interface *iface,
409 const char *address, bool allow_bcast_iface)
410{
411 struct nbtd_server *nbtd_server = iface->nbtsrv;
412
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;
416 }
417
418 return nbtd_find_request_iface(nbtd_server, address, allow_bcast_iface);
419}
Note: See TracBrowser for help on using the repository browser.