mirror of
https://github.com/samba-team/samba.git
synced 2024-12-25 23:21:54 +03:00
998c856d90
- when registering with a WINS server, initially use multi-homed
registration, then switch to name refresh requests. Send refresh
requests only to the WINS server that responded to our
registration. If that server goes away, then start the registration
from scratch. This makes registration more robust to WINS server
failure.
- send WINS registration requests out on our first interface rather
than an unbound interface, to avoid the problem of WACK replies
being sent to the wrong port (w2k3 WINS server does this)
(This used to be commit f7712ac746
)
231 lines
6.7 KiB
C
231 lines
6.7 KiB
C
/*
|
|
Unix SMB/CIFS implementation.
|
|
|
|
wins client name registration and refresh
|
|
|
|
Copyright (C) Andrew Tridgell 2005
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
#include "includes.h"
|
|
#include "nbt_server/nbt_server.h"
|
|
#include "libcli/raw/libcliraw.h"
|
|
#include "libcli/composite/composite.h"
|
|
#include "lib/events/events.h"
|
|
#include "smbd/service_task.h"
|
|
|
|
|
|
/* we send WINS client requests using our primary network interface
|
|
*/
|
|
static struct nbt_name_socket *wins_socket(struct nbtd_interface *iface)
|
|
{
|
|
struct nbtd_server *nbtsrv = iface->nbtsrv;
|
|
return nbtsrv->interfaces->nbtsock;
|
|
}
|
|
|
|
|
|
static void nbtd_wins_refresh(struct event_context *ev, struct timed_event *te,
|
|
struct timeval t, void *private);
|
|
|
|
/*
|
|
retry a WINS name registration
|
|
*/
|
|
static void nbtd_wins_register_retry(struct event_context *ev, struct timed_event *te,
|
|
struct timeval t, void *private)
|
|
{
|
|
struct nbtd_iface_name *iname = talloc_get_type(private, struct nbtd_iface_name);
|
|
nbtd_winsclient_register(iname);
|
|
}
|
|
|
|
|
|
/*
|
|
called when a wins name refresh has completed
|
|
*/
|
|
static void nbtd_wins_refresh_handler(struct composite_context *c)
|
|
{
|
|
NTSTATUS status;
|
|
struct nbt_name_refresh_wins io;
|
|
struct nbtd_iface_name *iname = talloc_get_type(c->async.private,
|
|
struct nbtd_iface_name);
|
|
TALLOC_CTX *tmp_ctx = talloc_new(iname);
|
|
|
|
status = nbt_name_refresh_wins_recv(c, tmp_ctx, &io);
|
|
if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
|
|
/* our WINS server is dead - start registration over
|
|
from scratch */
|
|
DEBUG(2,("Failed to refresh %s<%02x> with WINS server %s\n",
|
|
iname->name.name, iname->name.type, iname->wins_server));
|
|
nbtd_winsclient_register(iname);
|
|
return;
|
|
}
|
|
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
DEBUG(1,("Name refresh failure with WINS for %s<%02x> - %s\n",
|
|
iname->name.name, iname->name.type, nt_errstr(status)));
|
|
talloc_free(tmp_ctx);
|
|
return;
|
|
}
|
|
|
|
if (io.out.rcode != 0) {
|
|
DEBUG(1,("WINS server %s rejected name refresh of %s<%02x> - %s\n",
|
|
io.out.wins_server, iname->name.name, iname->name.type,
|
|
nt_errstr(nbt_rcode_to_ntstatus(io.out.rcode))));
|
|
iname->nb_flags |= NBT_NM_CONFLICT;
|
|
talloc_free(tmp_ctx);
|
|
return;
|
|
}
|
|
|
|
DEBUG(4,("Refreshed name %s<%02x> with WINS server %s\n",
|
|
iname->name.name, iname->name.type, iname->wins_server));
|
|
/* success - start a periodic name refresh */
|
|
iname->nb_flags |= NBT_NM_ACTIVE;
|
|
if (iname->wins_server) {
|
|
talloc_free(iname->wins_server);
|
|
}
|
|
iname->wins_server = talloc_steal(iname, io.out.wins_server);
|
|
|
|
iname->registration_time = timeval_current();
|
|
event_add_timed(iname->iface->nbtsrv->task->event_ctx,
|
|
iname,
|
|
timeval_add(&iname->registration_time, iname->ttl/2, 0),
|
|
nbtd_wins_refresh,
|
|
iname);
|
|
|
|
talloc_free(tmp_ctx);
|
|
}
|
|
|
|
|
|
/*
|
|
refresh a WINS name registration
|
|
*/
|
|
static void nbtd_wins_refresh(struct event_context *ev, struct timed_event *te,
|
|
struct timeval t, void *private)
|
|
{
|
|
struct nbtd_iface_name *iname = talloc_get_type(private, struct nbtd_iface_name);
|
|
struct nbtd_interface *iface = iname->iface;
|
|
struct nbt_name_refresh_wins io;
|
|
struct composite_context *c;
|
|
TALLOC_CTX *tmp_ctx = talloc_new(iname);
|
|
|
|
/* setup a wins name refresh request */
|
|
io.in.name = iname->name;
|
|
io.in.wins_servers = str_list_make(tmp_ctx, iname->wins_server, NULL);
|
|
io.in.addresses = nbtd_address_list(iface, tmp_ctx);
|
|
io.in.nb_flags = iname->nb_flags;
|
|
io.in.ttl = iname->ttl;
|
|
|
|
c = nbt_name_refresh_wins_send(wins_socket(iface), &io);
|
|
if (c == NULL) {
|
|
talloc_free(tmp_ctx);
|
|
return;
|
|
}
|
|
talloc_steal(c, io.in.addresses);
|
|
|
|
c->async.fn = nbtd_wins_refresh_handler;
|
|
c->async.private = iname;
|
|
|
|
talloc_free(tmp_ctx);
|
|
}
|
|
|
|
|
|
/*
|
|
called when a wins name register has completed
|
|
*/
|
|
static void nbtd_wins_register_handler(struct composite_context *c)
|
|
{
|
|
NTSTATUS status;
|
|
struct nbt_name_register_wins io;
|
|
struct nbtd_iface_name *iname = talloc_get_type(c->async.private,
|
|
struct nbtd_iface_name);
|
|
TALLOC_CTX *tmp_ctx = talloc_new(iname);
|
|
|
|
status = nbt_name_register_wins_recv(c, tmp_ctx, &io);
|
|
if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
|
|
/* none of the WINS servers responded - try again
|
|
periodically */
|
|
int wins_retry_time = lp_parm_int(-1, "nbtd", "wins_retry", 300);
|
|
event_add_timed(iname->iface->nbtsrv->task->event_ctx,
|
|
iname,
|
|
timeval_current_ofs(wins_retry_time, 0),
|
|
nbtd_wins_register_retry,
|
|
iname);
|
|
talloc_free(tmp_ctx);
|
|
return;
|
|
}
|
|
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
DEBUG(1,("Name register failure with WINS for %s<%02x> - %s\n",
|
|
iname->name.name, iname->name.type, nt_errstr(status)));
|
|
talloc_free(tmp_ctx);
|
|
return;
|
|
}
|
|
|
|
if (io.out.rcode != 0) {
|
|
DEBUG(1,("WINS server %s rejected name register of %s<%02x> - %s\n",
|
|
io.out.wins_server, iname->name.name, iname->name.type,
|
|
nt_errstr(nbt_rcode_to_ntstatus(io.out.rcode))));
|
|
iname->nb_flags |= NBT_NM_CONFLICT;
|
|
talloc_free(tmp_ctx);
|
|
return;
|
|
}
|
|
|
|
/* success - start a periodic name refresh */
|
|
iname->nb_flags |= NBT_NM_ACTIVE;
|
|
if (iname->wins_server) {
|
|
talloc_free(iname->wins_server);
|
|
}
|
|
iname->wins_server = talloc_steal(iname, io.out.wins_server);
|
|
|
|
iname->registration_time = timeval_current();
|
|
event_add_timed(iname->iface->nbtsrv->task->event_ctx,
|
|
iname,
|
|
timeval_add(&iname->registration_time, iname->ttl/2, 0),
|
|
nbtd_wins_refresh,
|
|
iname);
|
|
|
|
DEBUG(3,("Registered %s<%02x> with WINS server %s\n",
|
|
iname->name.name, iname->name.type, iname->wins_server));
|
|
|
|
talloc_free(tmp_ctx);
|
|
}
|
|
|
|
/*
|
|
register a name with our WINS servers
|
|
*/
|
|
void nbtd_winsclient_register(struct nbtd_iface_name *iname)
|
|
{
|
|
struct nbtd_interface *iface = iname->iface;
|
|
struct nbt_name_register_wins io;
|
|
struct composite_context *c;
|
|
|
|
/* setup a wins name register request */
|
|
io.in.name = iname->name;
|
|
io.in.wins_servers = lp_wins_server_list();
|
|
io.in.addresses = nbtd_address_list(iface, iname);
|
|
io.in.nb_flags = iname->nb_flags;
|
|
io.in.ttl = iname->ttl;
|
|
|
|
c = nbt_name_register_wins_send(wins_socket(iface), &io);
|
|
if (c == NULL) {
|
|
talloc_free(io.in.addresses);
|
|
return;
|
|
}
|
|
talloc_steal(c, io.in.addresses);
|
|
|
|
c->async.fn = nbtd_wins_register_handler;
|
|
c->async.private = iname;
|
|
}
|