36a65b18593acd6f82c56f08b7160ee1ebcfa768
[kai/samba.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 *bcast = iface_n_bcast(i);
249                 const char *address, *netmask;
250
251                 /* we can't assume every interface is broadcast capable */
252                 if (bcast == NULL) continue;
253
254                 address = talloc_strdup(tmp_ctx, iface_n_ip(i));
255                 bcast   = talloc_strdup(tmp_ctx, bcast);
256                 netmask = talloc_strdup(tmp_ctx, iface_n_netmask(i));
257
258                 status = nbtd_add_socket(nbtsrv, address, address, bcast, netmask);
259                 NT_STATUS_NOT_OK_RETURN(status);
260         }
261
262         if (lp_wins_server_list()) {
263                 status = nbtd_add_wins_socket(nbtsrv);
264                 NT_STATUS_NOT_OK_RETURN(status);
265         }
266
267         talloc_free(tmp_ctx);
268
269         return NT_STATUS_OK;
270 }
271
272
273 /*
274   form a list of addresses that we should use in name query replies
275   we always place the IP in the given interface first
276 */
277 const char **nbtd_address_list(struct nbtd_interface *iface, TALLOC_CTX *mem_ctx)
278 {
279         struct nbtd_server *nbtsrv = iface->nbtsrv;
280         const char **ret = NULL;
281         struct nbtd_interface *iface2;
282         BOOL is_loopback = False;
283
284         if (iface->ip_address) {
285                 is_loopback = iface_same_net(iface->ip_address, "127.0.0.1", "255.0.0.0");
286                 ret = str_list_add(ret, iface->ip_address);
287         }
288
289         for (iface2=nbtsrv->interfaces;iface2;iface2=iface2->next) {
290                 if (iface2 == iface) continue;
291
292                 if (!iface2->ip_address) continue;
293
294                 if (!is_loopback) {
295                         if (iface_same_net(iface2->ip_address, "127.0.0.1", "255.0.0.0")) {
296                                 continue;
297                         }
298                 }
299
300                 ret = str_list_add(ret, iface2->ip_address);
301         }
302
303         talloc_steal(mem_ctx, ret);
304
305         return ret;
306 }
307
308
309 /*
310   find the interface to use for sending a outgoing request
311 */
312 struct nbtd_interface *nbtd_find_interface(struct nbtd_server *nbtd_server,
313                                            const char *address)
314 {
315         struct nbtd_interface *iface;
316         /* try to find a exact match */
317         for (iface=nbtd_server->interfaces;iface;iface=iface->next) {
318                 if (iface_same_net(address, iface->ip_address, iface->netmask)) {
319                         return iface;
320                 }
321         }
322
323         /* no exact match, if we have the broadcast interface, use that */
324         if (nbtd_server->bcast_interface) {
325                 return nbtd_server->bcast_interface;
326         }
327
328         /* fallback to first interface */
329         return nbtd_server->interfaces;
330 }