r13115: call the wins hook script on modifications of the wins.ldb
[kai/samba-autobuild/.git] / source4 / nbt_server / interfaces.c
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 2 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, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "dlinklist.h"
25 #include "nbt_server/nbt_server.h"
26 #include "smbd/service_task.h"
27 #include "lib/socket/socket.h"
28 #include "nbt_server/wins/winsserver.h"
29
30
31 /*
32   receive an incoming request and dispatch it to the right place
33 */
34 static void nbtd_request_handler(struct nbt_name_socket *nbtsock, 
35                                  struct nbt_name_packet *packet, 
36                                  struct socket_address *src)
37 {
38         struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, 
39                                                        struct nbtd_interface);
40         struct nbtd_server *nbtsrv = iface->nbtsrv;
41
42         nbtsrv->stats.total_received++;
43
44         /* see if its from one of our own interfaces - if so, then ignore it */
45         if (nbtd_self_packet_and_bcast(nbtsock, packet, src)) {
46                 DEBUG(10,("Ignoring bcast self packet from %s:%d\n", src->addr, src->port));
47                 return;
48         }
49
50         switch (packet->operation & NBT_OPCODE) {
51         case NBT_OPCODE_QUERY:
52                 nbtsrv->stats.query_count++;
53                 nbtd_request_query(nbtsock, packet, src);
54                 break;
55
56         case NBT_OPCODE_REGISTER:
57         case NBT_OPCODE_REFRESH:
58         case NBT_OPCODE_REFRESH2:
59                 nbtsrv->stats.register_count++;
60                 nbtd_request_defense(nbtsock, packet, src);
61                 break;
62
63         case NBT_OPCODE_RELEASE:
64         case NBT_OPCODE_MULTI_HOME_REG:
65                 nbtsrv->stats.release_count++;
66                 nbtd_winsserver_request(nbtsock, packet, src);
67                 break;
68
69         default:
70                 nbtd_bad_packet(packet, src, "Unexpected opcode");
71                 break;
72         }
73 }
74
75
76 /*
77   find a registered name on an interface
78 */
79 struct nbtd_iface_name *nbtd_find_iname(struct nbtd_interface *iface, 
80                                         struct nbt_name *name, 
81                                         uint16_t nb_flags)
82 {
83         struct nbtd_iface_name *iname;
84         for (iname=iface->names;iname;iname=iname->next) {
85                 if (iname->name.type == name->type &&
86                     strcmp(name->name, iname->name.name) == 0 &&
87                     ((iname->nb_flags & nb_flags) == nb_flags)) {
88                         return iname;
89                 }
90         }
91         return NULL;
92 }
93
94 /*
95   start listening on the given address
96 */
97 static NTSTATUS nbtd_add_socket(struct nbtd_server *nbtsrv, 
98                                 const char *bind_address, 
99                                 const char *address, 
100                                 const char *bcast, 
101                                 const char *netmask)
102 {
103         struct nbtd_interface *iface;
104         NTSTATUS status;
105         struct socket_address *bcast_address;
106         struct socket_address *unicast_address;
107
108         /*
109           we actually create two sockets. One listens on the broadcast address
110           for the interface, and the other listens on our specific address. This
111           allows us to run with "bind interfaces only" while still receiving 
112           broadcast addresses, and also simplifies matching incoming requests 
113           to interfaces
114         */
115
116         iface = talloc(nbtsrv, struct nbtd_interface);
117         NT_STATUS_HAVE_NO_MEMORY(iface);
118
119         iface->nbtsrv        = nbtsrv;
120         iface->bcast_address = talloc_steal(iface, bcast);
121         iface->ip_address    = talloc_steal(iface, address);
122         iface->netmask       = talloc_steal(iface, netmask);
123         iface->names         = NULL;
124
125         if (strcmp(netmask, "0.0.0.0") != 0) {
126                 struct nbt_name_socket *bcast_nbtsock;
127
128                 /* listen for broadcasts on port 137 */
129                 bcast_nbtsock = nbt_name_socket_init(iface, nbtsrv->task->event_ctx);
130                 if (!bcast_nbtsock) {
131                         talloc_free(iface);
132                         return NT_STATUS_NO_MEMORY;
133                 }
134
135                 bcast_address = socket_address_from_strings(bcast_nbtsock, bcast_nbtsock->sock->backend_name, 
136                                                             bcast, lp_nbt_port());
137                 if (!bcast_address) {
138                         talloc_free(iface);
139                         return NT_STATUS_NO_MEMORY;
140                 }
141
142                 status = socket_listen(bcast_nbtsock->sock, bcast_address, 0, 0);
143                 if (!NT_STATUS_IS_OK(status)) {
144                         DEBUG(0,("Failed to bind to %s:%d - %s\n", 
145                                  bcast, lp_nbt_port(), nt_errstr(status)));
146                         talloc_free(iface);
147                         return status;
148                 }
149                 talloc_free(bcast_address);
150
151                 nbt_set_incoming_handler(bcast_nbtsock, nbtd_request_handler, iface);
152         }
153
154         /* listen for unicasts on port 137 */
155         iface->nbtsock = nbt_name_socket_init(iface, nbtsrv->task->event_ctx);
156         if (!iface->nbtsock) {
157                 talloc_free(iface);
158                 return NT_STATUS_NO_MEMORY;
159         }
160
161         unicast_address = socket_address_from_strings(iface->nbtsock, iface->nbtsock->sock->backend_name, 
162                                                       bind_address, lp_nbt_port());
163
164         status = socket_listen(iface->nbtsock->sock, unicast_address, 0, 0);
165         if (!NT_STATUS_IS_OK(status)) {
166                 DEBUG(0,("Failed to bind to %s:%d - %s\n", 
167                          bind_address, lp_nbt_port(), nt_errstr(status)));
168                 talloc_free(iface);
169                 return status;
170         }
171         talloc_free(unicast_address);
172
173         nbt_set_incoming_handler(iface->nbtsock, nbtd_request_handler, iface);
174
175         /* also setup the datagram listeners */
176         status = nbtd_dgram_setup(iface, bind_address);
177         if (!NT_STATUS_IS_OK(status)) {
178                 DEBUG(0,("Failed to setup dgram listen on %s - %s\n", 
179                          bind_address, nt_errstr(status)));
180                 talloc_free(iface);
181                 return status;
182         }
183         
184         if (strcmp(netmask, "0.0.0.0") == 0) {
185                 DLIST_ADD(nbtsrv->bcast_interface, iface);
186         } else {
187                 DLIST_ADD(nbtsrv->interfaces, iface);
188         }
189
190         return NT_STATUS_OK;
191 }
192
193
194 /*
195   setup a socket for talking to our WINS servers
196 */
197 static NTSTATUS nbtd_add_wins_socket(struct nbtd_server *nbtsrv)
198 {
199         struct nbtd_interface *iface;
200
201         iface = talloc_zero(nbtsrv, struct nbtd_interface);
202         NT_STATUS_HAVE_NO_MEMORY(iface);
203
204         iface->nbtsrv        = nbtsrv;
205
206         DLIST_ADD(nbtsrv->wins_interface, iface);
207
208         return NT_STATUS_OK;
209 }
210
211
212 /*
213   setup our listening sockets on the configured network interfaces
214 */
215 NTSTATUS nbtd_startup_interfaces(struct nbtd_server *nbtsrv)
216 {
217         int num_interfaces = iface_count();
218         int i;
219         TALLOC_CTX *tmp_ctx = talloc_new(nbtsrv);
220         NTSTATUS status;
221
222         /* if we are allowing incoming packets from any address, then
223            we also need to bind to the wildcard address */
224         if (!lp_bind_interfaces_only()) {
225                 const char *primary_address;
226
227                 /* the primary address is the address we will return
228                    for non-WINS queries not made on a specific
229                    interface */
230                 if (num_interfaces > 0) {
231                         primary_address = iface_n_ip(0);
232                 } else {
233                         primary_address = sys_inet_ntoa(interpret_addr2(
234                                                                 lp_netbios_name()));
235                 }
236                 primary_address = talloc_strdup(tmp_ctx, primary_address);
237                 NT_STATUS_HAVE_NO_MEMORY(primary_address);
238
239                 status = nbtd_add_socket(nbtsrv, 
240                                          "0.0.0.0",
241                                          primary_address,
242                                          talloc_strdup(tmp_ctx, "255.255.255.255"),
243                                          talloc_strdup(tmp_ctx, "0.0.0.0"));
244                 NT_STATUS_NOT_OK_RETURN(status);
245         }
246
247         for (i=0; i<num_interfaces; i++) {
248                 const char *address = talloc_strdup(tmp_ctx, iface_n_ip(i));
249                 const char *bcast   = talloc_strdup(tmp_ctx, iface_n_bcast(i));
250                 const char *netmask = talloc_strdup(tmp_ctx, iface_n_netmask(i));
251
252                 status = nbtd_add_socket(nbtsrv, address, address, bcast, netmask);
253                 NT_STATUS_NOT_OK_RETURN(status);
254         }
255
256         if (lp_wins_server_list()) {
257                 status = nbtd_add_wins_socket(nbtsrv);
258                 NT_STATUS_NOT_OK_RETURN(status);
259         }
260
261         talloc_free(tmp_ctx);
262
263         return NT_STATUS_OK;
264 }
265
266
267 /*
268   form a list of addresses that we should use in name query replies
269   we always place the IP in the given interface first
270 */
271 const char **nbtd_address_list(struct nbtd_interface *iface, TALLOC_CTX *mem_ctx)
272 {
273         struct nbtd_server *nbtsrv = iface->nbtsrv;
274         const char **ret = NULL;
275         struct nbtd_interface *iface2;
276         BOOL is_loopback = False;
277
278         if (iface->ip_address) {
279                 is_loopback = iface_same_net(iface->ip_address, "127.0.0.1", "255.0.0.0");
280                 ret = str_list_add(ret, iface->ip_address);
281         }
282
283         for (iface2=nbtsrv->interfaces;iface2;iface2=iface2->next) {
284                 if (iface2 == iface) continue;
285
286                 if (!iface2->ip_address) continue;
287
288                 if (!is_loopback) {
289                         if (iface_same_net(iface2->ip_address, "127.0.0.1", "255.0.0.0")) {
290                                 continue;
291                         }
292                 }
293
294                 ret = str_list_add(ret, iface2->ip_address);
295         }
296
297         talloc_steal(mem_ctx, ret);
298
299         return ret;
300 }
301
302
303 /*
304   find the interface to use for sending a outgoing request
305 */
306 struct nbtd_interface *nbtd_find_interface(struct nbtd_server *nbtd_server,
307                                            const char *address)
308 {
309         struct nbtd_interface *iface;
310         /* try to find a exact match */
311         for (iface=nbtd_server->interfaces;iface;iface=iface->next) {
312                 if (iface_same_net(address, iface->ip_address, iface->netmask)) {
313                         return iface;
314                 }
315         }
316
317         /* no exact match, if we have the broadcast interface, use that */
318         if (nbtd_server->bcast_interface) {
319                 return nbtd_server->bcast_interface;
320         }
321
322         /* fallback to first interface */
323         return nbtd_server->interfaces;
324 }