s3:modules: call rpcgen only if vfs_nfs4acl_xattr is enabled
[Samba.git] / source4 / nbt_server / interfaces.c
blobb946a1dedf40827236410dd698a834d7d6dccc39
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 "samba/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 #include "lib/util/idtree.h"
36 receive an incoming request and dispatch it to the right place
38 static void nbtd_request_handler(struct nbt_name_socket *nbtsock,
39 struct nbt_name_packet *packet,
40 struct socket_address *src)
42 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
43 struct nbtd_interface);
44 struct nbtd_server *nbtsrv = iface->nbtsrv;
46 nbtsrv->stats.total_received++;
48 /* see if it's 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;
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;
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;
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;
73 default:
74 nbtd_bad_packet(packet, src, "Unexpected opcode");
75 break;
79 static void nbtd_unexpected_handler(struct nbt_name_socket *nbtsock,
80 struct nbt_name_packet *packet,
81 struct socket_address *src)
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;
89 nbtsrv->stats.total_received++;
91 DEBUG(10,("unexpected from src[%s] on interface[%p] %s/%s\n",
92 src->addr, iface, iface->ip_address, iface->netmask));
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);
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);
106 /* try all other interfaces... */
107 if (!req) {
108 for (i = nbtsrv->interfaces; i; i = i->next) {
109 if (i == iface) {
110 continue;
112 req = idr_find(i->nbtsock->idr, packet->name_trn_id);
113 if (req) break;
117 if (!req) {
118 DEBUG(10,("unexpected from src[%s] unable to redirected\n", src->addr));
119 return;
122 DEBUG(10,("unexpected from src[%s] redirected to interface[%p] %s/%s\n",
123 src->addr, i, i->ip_address, i->netmask));
126 * redirect the incoming response to the socket
127 * we sent the matching request
129 nbt_name_socket_handle_response_packet(req, packet, src);
133 find a registered name on an interface
135 struct nbtd_iface_name *nbtd_find_iname(struct nbtd_interface *iface,
136 struct nbt_name *name,
137 uint16_t nb_flags)
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;
147 return NULL;
151 start listening on the given address
153 static 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)
160 struct nbtd_interface *iface;
161 NTSTATUS status;
162 struct socket_address *bcast_address;
163 struct socket_address *unicast_address;
165 DEBUG(6,("nbtd_add_socket(%s, %s, %s, %s)\n", bind_address, address, bcast, netmask));
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
175 iface = talloc(nbtsrv, struct nbtd_interface);
176 NT_STATUS_HAVE_NO_MEMORY(iface);
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;
185 if (strcmp(netmask, "0.0.0.0") != 0) {
186 struct nbt_name_socket *bcast_nbtsock;
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;
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;
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;
209 talloc_free(bcast_address);
211 nbt_set_incoming_handler(bcast_nbtsock, nbtd_request_handler, iface);
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;
221 unicast_address = socket_address_from_strings(iface->nbtsock,
222 iface->nbtsock->sock->backend_name,
223 bind_address, lpcfg_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, lpcfg_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_list_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 (!lpcfg_bind_interfaces_only(lp_ctx)) {
287 const char *primary_address;
289 primary_address = iface_list_first_v4(ifaces);
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)));
299 primary_address = talloc_strdup(tmp_ctx, primary_address);
300 NT_STATUS_HAVE_NO_MEMORY(primary_address);
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);
311 for (i=0; i<num_interfaces; i++) {
312 const char *bcast;
313 const char *address, *netmask;
315 if (!iface_list_n_is_v4(ifaces, i)) {
316 /* v4 only for NBT protocol */
317 continue;
320 bcast = iface_list_n_bcast(ifaces, i);
321 /* we can't assume every interface is broadcast capable */
322 if (bcast == NULL) continue;
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));
328 status = nbtd_add_socket(nbtsrv, lp_ctx,
329 address, address, bcast, netmask);
330 NT_STATUS_NOT_OK_RETURN(status);
333 if (lpcfg_wins_server_list(lp_ctx)) {
334 status = nbtd_add_wins_socket(nbtsrv);
335 NT_STATUS_NOT_OK_RETURN(status);
338 talloc_free(tmp_ctx);
340 return NT_STATUS_OK;
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
348 const char **nbtd_address_list(struct nbtd_interface *iface, TALLOC_CTX *mem_ctx)
350 struct nbtd_server *nbtsrv = iface->nbtsrv;
351 const char **ret = NULL;
352 struct nbtd_interface *iface2;
353 bool is_loopback = false;
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);
360 for (iface2=nbtsrv->interfaces;iface2;iface2=iface2->next) {
361 if (iface2 == iface) continue;
363 if (!iface2->ip_address) continue;
365 if (!is_loopback) {
366 if (iface_list_same_net(iface2->ip_address, "127.0.0.1", "255.0.0.0")) {
367 continue;
371 ret = str_list_add(ret, iface2->ip_address);
374 talloc_steal(mem_ctx, ret);
376 return ret;
381 find the interface to use for sending a outgoing request
383 struct nbtd_interface *nbtd_find_request_iface(struct nbtd_server *nbtd_server,
384 const char *address, bool allow_bcast_iface)
386 struct nbtd_interface *cur;
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;
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;
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;
413 * find the interface to use for sending a outgoing reply
415 struct nbtd_interface *nbtd_find_reply_iface(struct nbtd_interface *iface,
416 const char *address, bool allow_bcast_iface)
418 struct nbtd_server *nbtd_server = iface->nbtsrv;
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;
425 return nbtd_find_request_iface(nbtd_server, address, allow_bcast_iface);