summaryrefslogtreecommitdiffstats
path: root/source4/nbt_server
diff options
context:
space:
mode:
Diffstat (limited to 'source4/nbt_server')
-rw-r--r--source4/nbt_server/interfaces.c1
-rw-r--r--source4/nbt_server/nbt_server.h2
-rw-r--r--source4/nbt_server/wins/winsserver.c63
3 files changed, 59 insertions, 7 deletions
diff --git a/source4/nbt_server/interfaces.c b/source4/nbt_server/interfaces.c
index 49406440cf7..d466db514d0 100644
--- a/source4/nbt_server/interfaces.c
+++ b/source4/nbt_server/interfaces.c
@@ -125,6 +125,7 @@ static NTSTATUS nbtd_add_socket(struct nbtd_server *nbtsrv,
iface->ip_address = talloc_steal(iface, address);
iface->netmask = talloc_steal(iface, netmask);
iface->names = NULL;
+ iface->wack_queue = NULL;
if (strcmp(netmask, "0.0.0.0") != 0) {
struct nbt_name_socket *bcast_nbtsock;
diff --git a/source4/nbt_server/nbt_server.h b/source4/nbt_server/nbt_server.h
index 00d8f31b2b7..c80e5bfca07 100644
--- a/source4/nbt_server/nbt_server.h
+++ b/source4/nbt_server/nbt_server.h
@@ -41,6 +41,7 @@ struct nbtd_iface_name {
const char *wins_server;
};
+struct nbtd_wins_wack_state;
/* a list of network interfaces we are listening on */
struct nbtd_interface {
@@ -52,6 +53,7 @@ struct nbtd_interface {
struct nbt_name_socket *nbtsock;
struct nbt_dgram_socket *dgmsock;
struct nbtd_iface_name *names;
+ struct nbtd_wins_wack_state *wack_queue;
};
diff --git a/source4/nbt_server/wins/winsserver.c b/source4/nbt_server/wins/winsserver.c
index 399530b4cf7..c9d19936ed2 100644
--- a/source4/nbt_server/wins/winsserver.c
+++ b/source4/nbt_server/wins/winsserver.c
@@ -21,6 +21,7 @@
*/
#include "includes.h"
+#include "dlinklist.h"
#include "nbt_server/nbt_server.h"
#include "nbt_server/wins/winsdb.h"
#include "nbt_server/wins/winsserver.h"
@@ -180,9 +181,11 @@ static uint8_t wins_sgroup_merge(struct nbt_name_socket *nbtsock,
return winsdb_modify(winssrv->wins_db, rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
}
-struct wack_state {
+struct nbtd_wins_wack_state {
+ struct nbtd_wins_wack_state *prev, *next;
struct wins_server *winssrv;
struct nbt_name_socket *nbtsock;
+ struct nbtd_interface *iface;
struct nbt_name_packet *request_packet;
struct winsdb_record *rec;
struct socket_address *src;
@@ -192,10 +195,42 @@ struct wack_state {
NTSTATUS status;
};
+static int nbtd_wins_wack_state_destructor(struct nbtd_wins_wack_state *s)
+{
+ DLIST_REMOVE(s->iface->wack_queue, s);
+ return 0;
+}
+
+static bool wins_check_wack_queue(struct nbtd_interface *iface,
+ struct nbt_name_packet *packet,
+ struct socket_address *src)
+{
+ struct nbtd_wins_wack_state *s;
+
+ for (s= iface->wack_queue; s; s = s->next) {
+ if (packet->name_trn_id != s->request_packet->name_trn_id) {
+ continue;
+ }
+ if (packet->operation != s->request_packet->operation) {
+ continue;
+ }
+ if (src->port != s->src->port) {
+ continue;
+ }
+ if (strcmp(src->addr, s->src->addr) != 0) {
+ continue;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
/*
deny a registration request
*/
-static void wins_wack_deny(struct wack_state *s)
+static void wins_wack_deny(struct nbtd_wins_wack_state *s)
{
nbtd_name_registration_reply(s->nbtsock, s->request_packet,
s->src, NBT_RCODE_ACT);
@@ -207,7 +242,7 @@ static void wins_wack_deny(struct wack_state *s)
/*
allow a registration request
*/
-static void wins_wack_allow(struct wack_state *s)
+static void wins_wack_allow(struct nbtd_wins_wack_state *s)
{
NTSTATUS status;
uint32_t ttl = wins_server_ttl(s->winssrv, s->request_packet->additional[0].ttl);
@@ -301,8 +336,8 @@ failed:
*/
static void wack_wins_challenge_handler(struct composite_context *c_req)
{
- struct wack_state *s = talloc_get_type(c_req->async.private_data,
- struct wack_state);
+ struct nbtd_wins_wack_state *s = talloc_get_type(c_req->async.private_data,
+ struct nbtd_wins_wack_state);
bool found;
uint32_t i;
@@ -360,16 +395,17 @@ static void wins_register_wack(struct nbt_name_socket *nbtsock,
struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
struct nbtd_interface);
struct wins_server *winssrv = iface->nbtsrv->winssrv;
- struct wack_state *s;
+ struct nbtd_wins_wack_state *s;
struct composite_context *c_req;
uint32_t ttl;
- s = talloc_zero(nbtsock, struct wack_state);
+ s = talloc_zero(nbtsock, struct nbtd_wins_wack_state);
if (s == NULL) goto failed;
/* package up the state variables for this wack request */
s->winssrv = winssrv;
s->nbtsock = nbtsock;
+ s->iface = iface;
s->request_packet = talloc_steal(s, packet);
s->rec = talloc_steal(s, rec);
s->reg_address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
@@ -385,6 +421,10 @@ static void wins_register_wack(struct nbt_name_socket *nbtsock,
s->io.in.addresses = winsdb_addr_string_list(s, rec->addresses);
if (s->io.in.addresses == NULL) goto failed;
+ DLIST_ADD_END(iface->wack_queue, s, struct nbtd_wins_wack_state *);
+
+ talloc_set_destructor(s, nbtd_wins_wack_state_destructor);
+
/*
* send a WACK to the client, specifying the maximum time it could
* take to check with the owner, plus some slack
@@ -426,6 +466,7 @@ static void nbtd_winsserver_register(struct nbt_name_socket *nbtsock,
bool mhomed = ((packet->operation & NBT_OPCODE) == NBT_OPCODE_MULTI_HOME_REG);
enum wrepl_name_type new_type = wrepl_type(nb_flags, name, mhomed);
struct winsdb_addr *winsdb_addr = NULL;
+ bool duplicate_packet;
/*
* as a special case, the local master browser name is always accepted
@@ -455,6 +496,14 @@ static void nbtd_winsserver_register(struct nbt_name_socket *nbtsock,
goto done;
}
+ duplicate_packet = wins_check_wack_queue(iface, packet, src);
+ if (duplicate_packet) {
+ /* just ignore the packet */
+ DEBUG(5,("Ignoring duplicate packet while WACK is pending from %s:%d\n",
+ src->addr, src->port));
+ return;
+ }
+
status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND, status)) {
rcode = wins_register_new(nbtsock, packet, src, new_type);