s4-nbt: use private_data instead of private.
[Samba/gbeck.git] / source4 / nbt_server / interfaces.c
blob76bc145903a97e5802ed34449a84d1c3d21a00ed
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;
80 find a registered name on an interface
82 struct nbtd_iface_name *nbtd_find_iname(struct nbtd_interface *iface,
83 struct nbt_name *name,
84 uint16_t nb_flags)
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;
94 return NULL;
98 start listening on the given address
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)
107 struct nbtd_interface *iface;
108 NTSTATUS status;
109 struct socket_address *bcast_address;
110 struct socket_address *unicast_address;
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
120 iface = talloc(nbtsrv, struct nbtd_interface);
121 NT_STATUS_HAVE_NO_MEMORY(iface);
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;
129 if (strcmp(netmask, "0.0.0.0") != 0) {
130 struct nbt_name_socket *bcast_nbtsock;
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;
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;
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;
153 talloc_free(bcast_address);
155 nbt_set_incoming_handler(bcast_nbtsock, nbtd_request_handler, iface);
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;
166 unicast_address = socket_address_from_strings(iface->nbtsock,
167 iface->nbtsock->sock->backend_name,
168 bind_address, lp_nbt_port(lp_ctx));
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;
177 talloc_free(unicast_address);
179 nbt_set_incoming_handler(iface->nbtsock, nbtd_request_handler, iface);
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;
190 if (strcmp(netmask, "0.0.0.0") == 0) {
191 DLIST_ADD(nbtsrv->bcast_interface, iface);
192 } else {
193 DLIST_ADD(nbtsrv->interfaces, iface);
196 return NT_STATUS_OK;
200 setup a socket for talking to our WINS servers
202 static NTSTATUS nbtd_add_wins_socket(struct nbtd_server *nbtsrv)
204 struct nbtd_interface *iface;
206 iface = talloc_zero(nbtsrv, struct nbtd_interface);
207 NT_STATUS_HAVE_NO_MEMORY(iface);
209 iface->nbtsrv = nbtsrv;
211 DLIST_ADD(nbtsrv->wins_interface, iface);
213 return NT_STATUS_OK;
218 setup our listening sockets on the configured network interfaces
220 NTSTATUS nbtd_startup_interfaces(struct nbtd_server *nbtsrv, struct loadparm_context *lp_ctx,
221 struct interface *ifaces)
223 int num_interfaces = iface_count(ifaces);
224 int i;
225 TALLOC_CTX *tmp_ctx = talloc_new(nbtsrv);
226 NTSTATUS status;
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;
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)));
242 primary_address = talloc_strdup(tmp_ctx, primary_address);
243 NT_STATUS_HAVE_NO_MEMORY(primary_address);
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);
254 for (i=0; i<num_interfaces; i++) {
255 const char *bcast = iface_n_bcast(ifaces, i);
256 const char *address, *netmask;
258 /* we can't assume every interface is broadcast capable */
259 if (bcast == NULL) continue;
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));
265 status = nbtd_add_socket(nbtsrv, lp_ctx,
266 address, address, bcast, netmask);
267 NT_STATUS_NOT_OK_RETURN(status);
270 if (lp_wins_server_list(lp_ctx)) {
271 status = nbtd_add_wins_socket(nbtsrv);
272 NT_STATUS_NOT_OK_RETURN(status);
275 talloc_free(tmp_ctx);
277 return NT_STATUS_OK;
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
285 const char **nbtd_address_list(struct nbtd_interface *iface, TALLOC_CTX *mem_ctx)
287 struct nbtd_server *nbtsrv = iface->nbtsrv;
288 const char **ret = NULL;
289 struct nbtd_interface *iface2;
290 bool is_loopback = false;
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);
297 for (iface2=nbtsrv->interfaces;iface2;iface2=iface2->next) {
298 if (iface2 == iface) continue;
300 if (!iface2->ip_address) continue;
302 if (!is_loopback) {
303 if (iface_same_net(iface2->ip_address, "127.0.0.1", "255.0.0.0")) {
304 continue;
308 ret = str_list_add(ret, iface2->ip_address);
311 talloc_steal(mem_ctx, ret);
313 return ret;
318 find the interface to use for sending a outgoing request
320 struct nbtd_interface *nbtd_find_request_iface(struct nbtd_server *nbtd_server,
321 const char *address, bool allow_bcast_iface)
323 struct nbtd_interface *cur;
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;
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;
337 /* fallback to first interface */
338 return nbtd_server->interfaces;
342 * find the interface to use for sending a outgoing reply
344 struct nbtd_interface *nbtd_find_reply_iface(struct nbtd_interface *iface,
345 const char *address, bool allow_bcast_iface)
347 struct nbtd_server *nbtd_server = iface->nbtsrv;
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;
354 return nbtd_find_request_iface(nbtd_server, address, allow_bcast_iface);