~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/nbt_server/interfaces.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 3 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, see <http://www.gnu.org/licenses/>.
 
20
*/
 
21
 
 
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"
 
32
 
 
33
 
 
34
/*
 
35
  receive an incoming request and dispatch it to the right place
 
36
*/
 
37
static void nbtd_request_handler(struct nbt_name_socket *nbtsock, 
 
38
                                 struct nbt_name_packet *packet, 
 
39
                                 struct socket_address *src)
 
40
{
 
41
        struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
 
42
                                                       struct nbtd_interface);
 
43
        struct nbtd_server *nbtsrv = iface->nbtsrv;
 
44
 
 
45
        nbtsrv->stats.total_received++;
 
46
 
 
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;
 
51
        }
 
52
 
 
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;
 
58
 
 
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;
 
65
 
 
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;
 
71
 
 
72
        default:
 
73
                nbtd_bad_packet(packet, src, "Unexpected opcode");
 
74
                break;
 
75
        }
 
76
}
 
77
 
 
78
static void nbtd_unexpected_handler(struct nbt_name_socket *nbtsock,
 
79
                                    struct nbt_name_packet *packet,
 
80
                                    struct socket_address *src)
 
81
{
 
82
        struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
 
83
                                                       struct nbtd_interface);
 
84
        struct nbtd_server *nbtsrv = iface->nbtsrv;
 
85
        struct nbtd_interface *i;
 
86
        struct nbt_name_request *req = NULL;
 
87
 
 
88
        nbtsrv->stats.total_received++;
 
89
 
 
90
        DEBUG(10,("unexpected from src[%s] on interface[%p] %s/%s\n",
 
91
                src->addr, iface, iface->ip_address, iface->netmask));
 
92
 
 
93
        /* try the broadcast interface */
 
94
        if (nbtsrv->bcast_interface) {
 
95
                i = nbtsrv->bcast_interface;
 
96
                req = idr_find(i->nbtsock->idr, packet->name_trn_id);
 
97
        }
 
98
 
 
99
        /* try the wins server client interface */
 
100
        if (!req && nbtsrv->wins_interface && nbtsrv->wins_interface->nbtsock) {
 
101
                i = nbtsrv->wins_interface;
 
102
                req = idr_find(i->nbtsock->idr, packet->name_trn_id);
 
103
        }
 
104
 
 
105
        /* try all other interfaces... */
 
106
        if (!req) {
 
107
                for (i = nbtsrv->interfaces; i; i = i->next) {
 
108
                        if (i == iface) {
 
109
                                continue;
 
110
                        }
 
111
                        req = idr_find(i->nbtsock->idr, packet->name_trn_id);
 
112
                        if (req) break;
 
113
                }
 
114
        }
 
115
 
 
116
        if (!req) {
 
117
                DEBUG(10,("unexpected from src[%s] unable to redirected\n", src->addr));
 
118
                return;
 
119
        }
 
120
 
 
121
        DEBUG(10,("unexpected from src[%s] redirected to interface[%p] %s/%s\n",
 
122
                src->addr, i, i->ip_address, i->netmask));
 
123
 
 
124
        /*
 
125
         * redirect the incoming response to the socket
 
126
         * we sent the matching request
 
127
         */
 
128
        nbt_name_socket_handle_response_packet(req, packet, src);
 
129
}
 
130
 
 
131
/*
 
132
  find a registered name on an interface
 
133
*/
 
134
struct nbtd_iface_name *nbtd_find_iname(struct nbtd_interface *iface, 
 
135
                                        struct nbt_name *name, 
 
136
                                        uint16_t nb_flags)
 
137
{
 
138
        struct nbtd_iface_name *iname;
 
139
        for (iname=iface->names;iname;iname=iname->next) {
 
140
                if (iname->name.type == name->type &&
 
141
                    strcmp(name->name, iname->name.name) == 0 &&
 
142
                    ((iname->nb_flags & nb_flags) == nb_flags)) {
 
143
                        return iname;
 
144
                }
 
145
        }
 
146
        return NULL;
 
147
}
 
148
 
 
149
/*
 
150
  start listening on the given address
 
151
*/
 
152
static NTSTATUS nbtd_add_socket(struct nbtd_server *nbtsrv, 
 
153
                                struct loadparm_context *lp_ctx,
 
154
                                const char *bind_address, 
 
155
                                const char *address, 
 
156
                                const char *bcast, 
 
157
                                const char *netmask)
 
158
{
 
159
        struct nbtd_interface *iface;
 
160
        NTSTATUS status;
 
161
        struct socket_address *bcast_address;
 
162
        struct socket_address *unicast_address;
 
163
 
 
164
        DEBUG(6,("nbtd_add_socket(%s, %s, %s, %s)\n", bind_address, address, bcast, netmask));
 
165
 
 
166
        /*
 
167
          we actually create two sockets. One listens on the broadcast address
 
168
          for the interface, and the other listens on our specific address. This
 
169
          allows us to run with "bind interfaces only" while still receiving 
 
170
          broadcast addresses, and also simplifies matching incoming requests 
 
171
          to interfaces
 
172
        */
 
173
 
 
174
        iface = talloc(nbtsrv, struct nbtd_interface);
 
175
        NT_STATUS_HAVE_NO_MEMORY(iface);
 
176
 
 
177
        iface->nbtsrv        = nbtsrv;
 
178
        iface->bcast_address = talloc_steal(iface, bcast);
 
179
        iface->ip_address    = talloc_steal(iface, address);
 
180
        iface->netmask       = talloc_steal(iface, netmask);
 
181
        iface->names         = NULL;
 
182
        iface->wack_queue    = NULL;
 
183
 
 
184
        if (strcmp(netmask, "0.0.0.0") != 0) {
 
185
                struct nbt_name_socket *bcast_nbtsock;
 
186
 
 
187
                /* listen for broadcasts on port 137 */
 
188
                bcast_nbtsock = nbt_name_socket_init(iface, nbtsrv->task->event_ctx, lp_iconv_convenience(nbtsrv->task->lp_ctx));
 
189
                if (!bcast_nbtsock) {
 
190
                        talloc_free(iface);
 
191
                        return NT_STATUS_NO_MEMORY;
 
192
                }
 
193
 
 
194
                bcast_address = socket_address_from_strings(bcast_nbtsock, bcast_nbtsock->sock->backend_name, 
 
195
                                                            bcast, lp_nbt_port(lp_ctx));
 
196
                if (!bcast_address) {
 
197
                        talloc_free(iface);
 
198
                        return NT_STATUS_NO_MEMORY;
 
199
                }
 
200
 
 
201
                status = socket_listen(bcast_nbtsock->sock, bcast_address, 0, 0);
 
202
                if (!NT_STATUS_IS_OK(status)) {
 
203
                        DEBUG(0,("Failed to bind to %s:%d - %s\n", 
 
204
                                 bcast, lp_nbt_port(lp_ctx), nt_errstr(status)));
 
205
                        talloc_free(iface);
 
206
                        return status;
 
207
                }
 
208
                talloc_free(bcast_address);
 
209
 
 
210
                nbt_set_incoming_handler(bcast_nbtsock, nbtd_request_handler, iface);
 
211
        }
 
212
 
 
213
        /* listen for unicasts on port 137 */
 
214
        iface->nbtsock = nbt_name_socket_init(iface, nbtsrv->task->event_ctx, 
 
215
                                              lp_iconv_convenience(nbtsrv->task->lp_ctx));
 
216
        if (!iface->nbtsock) {
 
217
                talloc_free(iface);
 
218
                return NT_STATUS_NO_MEMORY;
 
219
        }
 
220
 
 
221
        unicast_address = socket_address_from_strings(iface->nbtsock, 
 
222
                                                      iface->nbtsock->sock->backend_name, 
 
223
                                                      bind_address, lp_nbt_port(lp_ctx));
 
224
 
 
225
        status = socket_listen(iface->nbtsock->sock, unicast_address, 0, 0);
 
226
        if (!NT_STATUS_IS_OK(status)) {
 
227
                DEBUG(0,("Failed to bind to %s:%d - %s\n", 
 
228
                         bind_address, lp_nbt_port(lp_ctx), nt_errstr(status)));
 
229
                talloc_free(iface);
 
230
                return status;
 
231
        }
 
232
        talloc_free(unicast_address);
 
233
 
 
234
        nbt_set_incoming_handler(iface->nbtsock, nbtd_request_handler, iface);
 
235
        nbt_set_unexpected_handler(iface->nbtsock, nbtd_unexpected_handler, iface);
 
236
 
 
237
        /* also setup the datagram listeners */
 
238
        status = nbtd_dgram_setup(iface, bind_address);
 
239
        if (!NT_STATUS_IS_OK(status)) {
 
240
                DEBUG(0,("Failed to setup dgram listen on %s - %s\n", 
 
241
                         bind_address, nt_errstr(status)));
 
242
                talloc_free(iface);
 
243
                return status;
 
244
        }
 
245
        
 
246
        if (strcmp(netmask, "0.0.0.0") == 0) {
 
247
                DLIST_ADD(nbtsrv->bcast_interface, iface);
 
248
        } else {
 
249
                DLIST_ADD(nbtsrv->interfaces, iface);
 
250
        }
 
251
 
 
252
        return NT_STATUS_OK;
 
253
}
 
254
 
 
255
/*
 
256
  setup a socket for talking to our WINS servers
 
257
*/
 
258
static NTSTATUS nbtd_add_wins_socket(struct nbtd_server *nbtsrv)
 
259
{
 
260
        struct nbtd_interface *iface;
 
261
 
 
262
        iface = talloc_zero(nbtsrv, struct nbtd_interface);
 
263
        NT_STATUS_HAVE_NO_MEMORY(iface);
 
264
 
 
265
        iface->nbtsrv        = nbtsrv;
 
266
 
 
267
        DLIST_ADD(nbtsrv->wins_interface, iface);
 
268
 
 
269
        return NT_STATUS_OK;
 
270
}
 
271
 
 
272
 
 
273
/*
 
274
  setup our listening sockets on the configured network interfaces
 
275
*/
 
276
NTSTATUS nbtd_startup_interfaces(struct nbtd_server *nbtsrv, struct loadparm_context *lp_ctx,
 
277
                                 struct interface *ifaces)
 
278
{
 
279
        int num_interfaces = iface_count(ifaces);
 
280
        int i;
 
281
        TALLOC_CTX *tmp_ctx = talloc_new(nbtsrv);
 
282
        NTSTATUS status;
 
283
 
 
284
        /* if we are allowing incoming packets from any address, then
 
285
           we also need to bind to the wildcard address */
 
286
        if (!lp_bind_interfaces_only(lp_ctx)) {
 
287
                const char *primary_address;
 
288
 
 
289
                /* the primary address is the address we will return
 
290
                   for non-WINS queries not made on a specific
 
291
                   interface */
 
292
                if (num_interfaces > 0) {
 
293
                        primary_address = iface_n_ip(ifaces, 0);
 
294
                } else {
 
295
                        primary_address = inet_ntoa(interpret_addr2(
 
296
                                                        lp_netbios_name(lp_ctx)));
 
297
                }
 
298
                primary_address = talloc_strdup(tmp_ctx, primary_address);
 
299
                NT_STATUS_HAVE_NO_MEMORY(primary_address);
 
300
 
 
301
                status = nbtd_add_socket(nbtsrv, 
 
302
                                         lp_ctx,
 
303
                                         "0.0.0.0",
 
304
                                         primary_address,
 
305
                                         talloc_strdup(tmp_ctx, "255.255.255.255"),
 
306
                                         talloc_strdup(tmp_ctx, "0.0.0.0"));
 
307
                NT_STATUS_NOT_OK_RETURN(status);
 
308
        }
 
309
 
 
310
        for (i=0; i<num_interfaces; i++) {
 
311
                const char *bcast = iface_n_bcast(ifaces, i);
 
312
                const char *address, *netmask;
 
313
 
 
314
                /* we can't assume every interface is broadcast capable */
 
315
                if (bcast == NULL) continue;
 
316
 
 
317
                address = talloc_strdup(tmp_ctx, iface_n_ip(ifaces, i));
 
318
                bcast   = talloc_strdup(tmp_ctx, bcast);
 
319
                netmask = talloc_strdup(tmp_ctx, iface_n_netmask(ifaces, i));
 
320
 
 
321
                status = nbtd_add_socket(nbtsrv, lp_ctx, 
 
322
                                         address, address, bcast, netmask);
 
323
                NT_STATUS_NOT_OK_RETURN(status);
 
324
        }
 
325
 
 
326
        if (lp_wins_server_list(lp_ctx)) {
 
327
                status = nbtd_add_wins_socket(nbtsrv);
 
328
                NT_STATUS_NOT_OK_RETURN(status);
 
329
        }
 
330
 
 
331
        talloc_free(tmp_ctx);
 
332
 
 
333
        return NT_STATUS_OK;
 
334
}
 
335
 
 
336
 
 
337
/*
 
338
  form a list of addresses that we should use in name query replies
 
339
  we always place the IP in the given interface first
 
340
*/
 
341
const char **nbtd_address_list(struct nbtd_interface *iface, TALLOC_CTX *mem_ctx)
 
342
{
 
343
        struct nbtd_server *nbtsrv = iface->nbtsrv;
 
344
        const char **ret = NULL;
 
345
        struct nbtd_interface *iface2;
 
346
        bool is_loopback = false;
 
347
 
 
348
        if (iface->ip_address) {
 
349
                is_loopback = iface_same_net(iface->ip_address, "127.0.0.1", "255.0.0.0");
 
350
                ret = str_list_add(ret, iface->ip_address);
 
351
        }
 
352
 
 
353
        for (iface2=nbtsrv->interfaces;iface2;iface2=iface2->next) {
 
354
                if (iface2 == iface) continue;
 
355
 
 
356
                if (!iface2->ip_address) continue;
 
357
 
 
358
                if (!is_loopback) {
 
359
                        if (iface_same_net(iface2->ip_address, "127.0.0.1", "255.0.0.0")) {
 
360
                                continue;
 
361
                        }
 
362
                }
 
363
 
 
364
                ret = str_list_add(ret, iface2->ip_address);
 
365
        }
 
366
 
 
367
        talloc_steal(mem_ctx, ret);
 
368
 
 
369
        return ret;
 
370
}
 
371
 
 
372
 
 
373
/*
 
374
  find the interface to use for sending a outgoing request
 
375
*/
 
376
struct nbtd_interface *nbtd_find_request_iface(struct nbtd_server *nbtd_server,
 
377
                                               const char *address, bool allow_bcast_iface)
 
378
{
 
379
        struct nbtd_interface *cur;
 
380
 
 
381
        /* try to find a exact match */
 
382
        for (cur=nbtd_server->interfaces;cur;cur=cur->next) {
 
383
                if (iface_same_net(address, cur->ip_address, cur->netmask)) {
 
384
                        DEBUG(10,("find interface for dst[%s] ip: %s/%s (iface[%p])\n",
 
385
                                  address, cur->ip_address, cur->netmask, cur));
 
386
                        return cur;
 
387
                }
 
388
        }
 
389
 
 
390
        /* no exact match, if we have the broadcast interface, use that */
 
391
        if (allow_bcast_iface && nbtd_server->bcast_interface) {
 
392
                cur = nbtd_server->bcast_interface;
 
393
                DEBUG(10,("find interface for dst[%s] ip: %s/%s (bcast iface[%p])\n",
 
394
                        address, cur->ip_address, cur->netmask, cur));
 
395
                return cur;
 
396
        }
 
397
 
 
398
        /* fallback to first interface */
 
399
        cur = nbtd_server->interfaces;
 
400
        DEBUG(10,("find interface for dst[%s] ip: %s/%s (default iface[%p])\n",
 
401
                address, cur->ip_address, cur->netmask, cur));
 
402
        return cur;
 
403
}
 
404
 
 
405
/*
 
406
 * find the interface to use for sending a outgoing reply
 
407
 */
 
408
struct nbtd_interface *nbtd_find_reply_iface(struct nbtd_interface *iface,
 
409
                                             const char *address, bool allow_bcast_iface)
 
410
{
 
411
        struct nbtd_server *nbtd_server = iface->nbtsrv;
 
412
 
 
413
        /* first try to use the given interfacel when it's not the broadcast one */
 
414
        if (iface != nbtd_server->bcast_interface) {
 
415
                return iface;
 
416
        }
 
417
 
 
418
        return nbtd_find_request_iface(nbtd_server, address, allow_bcast_iface);
 
419
}