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