2 Unix SMB/CIFS implementation.
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 2 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, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "dlinklist.h"
25 #include "nbt_server/nbt_server.h"
26 #include "smbd/service_task.h"
30 receive an incoming request and dispatch it to the right place
32 static void nbtd_request_handler(struct nbt_name_socket *nbtsock,
33 struct nbt_name_packet *packet,
34 const char *src_address, int src_port)
36 /* if its a WINS query then direct to our WINS server if we
38 if ((packet->operation & NBT_FLAG_RECURSION_DESIRED) &&
39 !(packet->operation & NBT_FLAG_BROADCAST) &&
41 nbtd_query_wins(nbtsock, packet, src_address, src_port);
45 /* see if its from one of our own interfaces - if so, then ignore it */
46 if (nbtd_self_packet(nbtsock, packet, src_address, src_port)) {
47 DEBUG(10,("Ignoring self packet from %s:%d\n", src_address, src_port));
51 /* the request is to us in our role as a B node */
52 switch ((enum nbt_opcode)(packet->operation & NBT_OPCODE)) {
53 case NBT_OPCODE_QUERY:
54 nbtd_request_query(nbtsock, packet, src_address, src_port);
57 case NBT_OPCODE_REGISTER:
58 case NBT_OPCODE_REFRESH:
59 case NBT_OPCODE_REFRESH2:
60 nbtd_request_defense(nbtsock, packet, src_address, src_port);
64 nbtd_bad_packet(packet, src_address, "Unexpected opcode");
72 find a registered name on an interface
74 struct nbtd_iface_name *nbtd_find_iname(struct nbtd_interface *iface,
75 struct nbt_name *name,
78 struct nbtd_iface_name *iname;
79 for (iname=iface->names;iname;iname=iname->next) {
80 if (iname->name.type == name->type &&
81 StrCaseCmp(name->name, iname->name.name) == 0 &&
82 ((iname->nb_flags & nb_flags) == nb_flags)) {
90 start listening on the given address
92 static NTSTATUS nbtd_add_socket(struct nbtd_server *nbtsrv,
93 const char *bind_address,
98 struct nbtd_interface *iface;
100 struct nbt_name_socket *bcast_nbtsock;
103 we actually create two sockets. One listens on the broadcast address
104 for the interface, and the other listens on our specific address. This
105 allows us to run with "bind interfaces only" while still receiving
106 broadcast addresses, and also simplifies matching incoming requests
110 iface = talloc(nbtsrv, struct nbtd_interface);
111 NT_STATUS_HAVE_NO_MEMORY(iface);
113 iface->nbtsrv = nbtsrv;
114 iface->bcast_address = talloc_steal(iface, bcast);
115 iface->ip_address = talloc_steal(iface, address);
116 iface->netmask = talloc_steal(iface, netmask);
119 if (strcmp(netmask, "0.0.0.0") != 0) {
120 bcast_nbtsock = nbt_name_socket_init(iface, nbtsrv->task->event_ctx);
121 NT_STATUS_HAVE_NO_MEMORY(bcast_nbtsock);
123 status = socket_listen(bcast_nbtsock->sock, bcast, lp_nbt_port(), 0, 0);
124 if (!NT_STATUS_IS_OK(status)) {
125 DEBUG(0,("Failed to bind to %s:%d - %s\n",
126 bcast, lp_nbt_port(), nt_errstr(status)));
131 nbt_set_incoming_handler(bcast_nbtsock, nbtd_request_handler, iface);
134 iface->nbtsock = nbt_name_socket_init(iface, nbtsrv->task->event_ctx);
135 NT_STATUS_HAVE_NO_MEMORY(iface->ip_address);
137 status = socket_listen(iface->nbtsock->sock, bind_address, lp_nbt_port(), 0, 0);
138 if (!NT_STATUS_IS_OK(status)) {
139 DEBUG(0,("Failed to bind to %s:%d - %s\n",
140 address, lp_nbt_port(), nt_errstr(status)));
145 nbt_set_incoming_handler(iface->nbtsock, nbtd_request_handler, iface);
147 if (strcmp(netmask, "0.0.0.0") == 0) {
148 DLIST_ADD(nbtsrv->bcast_interface, iface);
150 DLIST_ADD(nbtsrv->interfaces, iface);
158 setup a socket for talking to our WINS servers
160 static NTSTATUS nbtd_add_wins_socket(struct nbtd_server *nbtsrv)
162 struct nbtd_interface *iface;
164 iface = talloc_zero(nbtsrv, struct nbtd_interface);
165 NT_STATUS_HAVE_NO_MEMORY(iface);
167 iface->nbtsrv = nbtsrv;
169 DLIST_ADD(nbtsrv->wins_interface, iface);
176 setup our listening sockets on the configured network interfaces
178 NTSTATUS nbtd_startup_interfaces(struct nbtd_server *nbtsrv)
180 int num_interfaces = iface_count();
182 TALLOC_CTX *tmp_ctx = talloc_new(nbtsrv);
185 /* if we are allowing incoming packets from any address, then
186 we also need to bind to the wildcard address */
187 if (!lp_bind_interfaces_only()) {
188 const char *primary_address;
190 /* the primary address is the address we will return
191 for non-WINS queries not made on a specific
193 if (num_interfaces > 0) {
194 primary_address = sys_inet_ntoa(*iface_n_ip(0));
196 primary_address = sys_inet_ntoa(interpret_addr2(
199 primary_address = talloc_strdup(tmp_ctx, primary_address);
200 NT_STATUS_HAVE_NO_MEMORY(primary_address);
202 status = nbtd_add_socket(nbtsrv,
205 talloc_strdup(tmp_ctx, "255.255.255.255"),
206 talloc_strdup(tmp_ctx, "0.0.0.0"));
207 NT_STATUS_NOT_OK_RETURN(status);
210 for (i=0; i<num_interfaces; i++) {
211 const char *address = talloc_strdup(tmp_ctx, sys_inet_ntoa(*iface_n_ip(i)));
212 const char *bcast = talloc_strdup(tmp_ctx, sys_inet_ntoa(*iface_n_bcast(i)));
213 const char *netmask = talloc_strdup(tmp_ctx, sys_inet_ntoa(*iface_n_netmask(i)));
215 status = nbtd_add_socket(nbtsrv, address, address, bcast, netmask);
216 NT_STATUS_NOT_OK_RETURN(status);
219 if (lp_wins_server_list()) {
220 status = nbtd_add_wins_socket(nbtsrv);
221 NT_STATUS_NOT_OK_RETURN(status);
224 talloc_free(tmp_ctx);
231 form a list of addresses that we should use in name query replies
232 we always place the IP in the given interface first
234 const char **nbtd_address_list(struct nbtd_interface *iface, TALLOC_CTX *mem_ctx)
236 struct nbtd_server *nbtsrv = iface->nbtsrv;
237 const char **ret = NULL;
238 struct nbtd_interface *iface2;
241 if (iface->ip_address) {
242 ret = talloc_array(mem_ctx, const char *, 2);
243 if (ret == NULL) goto failed;
245 ret[0] = talloc_strdup(ret, iface->ip_address);
246 if (ret[0] == NULL) goto failed;
252 for (iface2=nbtsrv->interfaces;iface2;iface2=iface2->next) {
255 if (iface->ip_address &&
256 strcmp(iface2->ip_address, iface->ip_address) == 0) {
260 ret2 = talloc_realloc(mem_ctx, ret, const char *, count+2);
261 if (ret2 == NULL) goto failed;
263 ret[count] = talloc_strdup(ret, iface2->ip_address);
264 if (ret[count] == NULL) goto failed;