#include "includes.h"
#include "lib/events/events.h"
-#include "dlinklist.h"
+#include "lib/util/dlinklist.h"
#include "libcli/nbt/libnbt.h"
+#include "lib/socket/socket.h"
+#include "librpc/gen_ndr/ndr_nbt.h"
-#define NBT_MAX_PACKET_SIZE 2048
#define NBT_MAX_REPLIES 1000
/*
destroy a pending request
*/
-static int nbt_name_request_destructor(void *ptr)
-{
- struct nbt_name_request *req = talloc_get_type(ptr, struct nbt_name_request);
-
+static int nbt_name_request_destructor(struct nbt_name_request *req)
+{
if (req->state == NBT_REQUEST_SEND) {
DLIST_REMOVE(req->nbtsock->send_queue, req);
}
size_t len;
len = req->encoded.length;
- status = socket_sendto(nbtsock->sock, &req->encoded, &len, 0,
- req->dest_addr, req->dest_port);
+ status = socket_sendto(nbtsock->sock, &req->encoded, &len,
+ req->dest);
if (NT_STATUS_IS_ERR(status)) goto failed;
if (!NT_STATUS_IS_OK(status)) {
}
DLIST_REMOVE(nbtsock->send_queue, req);
+ req->state = NBT_REQUEST_WAIT;
if (req->is_reply) {
talloc_free(req);
} else {
- req->state = NBT_REQUEST_WAIT;
EVENT_FD_READABLE(nbtsock->fde);
nbtsock->num_pending++;
}
req->te = event_add_timed(req->nbtsock->event_ctx, req,
timeval_add(&t, req->timeout, 0),
nbt_name_socket_timeout, req);
- DLIST_ADD_END(req->nbtsock->send_queue, req, struct nbt_name_request *);
+ if (req->state != NBT_REQUEST_SEND) {
+ req->state = NBT_REQUEST_SEND;
+ DLIST_ADD_END(req->nbtsock->send_queue, req,
+ struct nbt_name_request *);
+ }
EVENT_FD_WRITEABLE(req->nbtsock->fde);
return;
}
{
TALLOC_CTX *tmp_ctx = talloc_new(nbtsock);
NTSTATUS status;
- const char *src_addr;
- int src_port;
+ struct socket_address *src;
DATA_BLOB blob;
- size_t nread;
+ size_t nread, dsize;
struct nbt_name_packet *packet;
struct nbt_name_request *req;
- blob = data_blob_talloc(tmp_ctx, NULL, NBT_MAX_PACKET_SIZE);
+ status = socket_pending(nbtsock->sock, &dsize);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(tmp_ctx);
+ return;
+ }
+
+ blob = data_blob_talloc(tmp_ctx, NULL, dsize);
if (blob.data == NULL) {
talloc_free(tmp_ctx);
return;
}
- status = socket_recvfrom(nbtsock->sock, blob.data, blob.length, &nread, 0,
- &src_addr, &src_port);
+ status = socket_recvfrom(nbtsock->sock, blob.data, blob.length, &nread,
+ tmp_ctx, &src);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(tmp_ctx);
return;
}
- talloc_steal(tmp_ctx, src_addr);
- blob.length = nread;
packet = talloc(tmp_ctx, struct nbt_name_packet);
if (packet == NULL) {
if (DEBUGLVL(10)) {
DEBUG(10,("Received nbt packet of length %d from %s:%d\n",
- blob.length, src_addr, src_port));
+ (int)blob.length, src->addr, src->port));
NDR_PRINT_DEBUG(nbt_name_packet, packet);
}
handler, if any */
if (!(packet->operation & NBT_FLAG_REPLY)) {
if (nbtsock->incoming.handler) {
- nbtsock->incoming.handler(nbtsock, packet, src_addr, src_port);
+ nbtsock->incoming.handler(nbtsock, packet, src);
}
talloc_free(tmp_ctx);
return;
/* find the matching request */
req = idr_find(nbtsock->idr, packet->name_trn_id);
if (req == NULL) {
- DEBUG(2,("Failed to match request for incoming name packet id 0x%04x\n",
- packet->name_trn_id));
+ if (nbtsock->unexpected.handler) {
+ nbtsock->unexpected.handler(nbtsock, packet, src);
+ } else {
+ DEBUG(10,("Failed to match request for incoming name packet id 0x%04x on %p\n",
+ packet->name_trn_id, nbtsock));
+ }
talloc_free(tmp_ctx);
return;
}
has received our request */
req->num_retries = 0;
req->received_wack = True;
- if (packet->answers[0].ttl != 0) {
- req->timeout = MIN(packet->answers[0].ttl, 20);
- }
- req->te = event_add_timed(req->nbtsock->event_ctx, req,
- timeval_current_ofs(req->timeout, 0),
- nbt_name_socket_timeout, req);
- DLIST_ADD_END(req->nbtsock->send_queue, req, struct nbt_name_request *);
- EVENT_FD_WRITEABLE(req->nbtsock->fde);
+ /* although there can be a timeout in the packet, w2k3 screws it up,
+ so better to set it ourselves */
+ req->timeout = lp_parm_int(-1, "nbt", "wack_timeout", 30);
+ req->te = event_add_timed(req->nbtsock->event_ctx, req,
+ timeval_current_ofs(req->timeout, 0),
+ nbt_name_socket_timeout, req);
talloc_free(tmp_ctx);
return;
}
goto done;
}
- req->replies[req->num_replies].reply_addr = talloc_steal(req, src_addr);
- req->replies[req->num_replies].reply_port = src_port;
- req->replies[req->num_replies].packet = talloc_steal(req, packet);
+ talloc_steal(req, src);
+ req->replies[req->num_replies].dest = src;
+ talloc_steal(req, packet);
+ req->replies[req->num_replies].packet = packet;
req->num_replies++;
/* if we don't want multiple replies then we are done */
struct nbt_name_socket);
if (flags & EVENT_FD_WRITE) {
nbt_name_socket_send(nbtsock);
- } else if (flags & EVENT_FD_READ) {
+ }
+ if (flags & EVENT_FD_READ) {
nbt_name_socket_recv(nbtsock);
}
}
initialise a nbt_name_socket. The event_ctx is optional, if provided
then operations will use that event context
*/
-struct nbt_name_socket *nbt_name_socket_init(TALLOC_CTX *mem_ctx,
+_PUBLIC_ struct nbt_name_socket *nbt_name_socket_init(TALLOC_CTX *mem_ctx,
struct event_context *event_ctx)
{
struct nbt_name_socket *nbtsock;
nbtsock->send_queue = NULL;
nbtsock->num_pending = 0;
nbtsock->incoming.handler = NULL;
+ nbtsock->unexpected.handler = NULL;
nbtsock->fde = event_add_fd(nbtsock->event_ctx, nbtsock,
socket_get_fd(nbtsock->sock), 0,
send off a nbt name request
*/
struct nbt_name_request *nbt_name_request_send(struct nbt_name_socket *nbtsock,
- const char *dest_addr, int dest_port,
+ struct socket_address *dest,
struct nbt_name_packet *request,
int timeout, int retries,
BOOL allow_multiple_replies)
if (req == NULL) goto failed;
req->nbtsock = nbtsock;
- req->dest_port = dest_port;
req->allow_multiple_replies = allow_multiple_replies;
req->state = NBT_REQUEST_SEND;
req->is_reply = False;
req->timeout = timeout;
req->num_retries = retries;
- req->dest_addr = talloc_strdup(req, dest_addr);
- if (req->dest_addr == NULL) goto failed;
+ req->dest = dest;
+ if (talloc_reference(req, dest) == NULL) goto failed;
/* we select a random transaction id unless the user supplied one */
if (request->name_trn_id == 0) {
- request->name_trn_id = generate_random() % UINT16_MAX;
- }
-
- /* choose the next available transaction id >= the one asked for.
- The strange 2nd call is to try to make the ids less guessable
- and less likely to collide. It's not possible to make NBT secure
- to ID guessing, but this at least makes accidential collisions
- less likely */
- id = idr_get_new_above(req->nbtsock->idr, req,
- request->name_trn_id, UINT16_MAX);
- if (id == -1) {
- id = idr_get_new_above(req->nbtsock->idr, req,
- 1+(generate_random()%(UINT16_MAX/2)),
+ id = idr_get_new_random(req->nbtsock->idr, req, UINT16_MAX);
+ } else {
+ if (idr_find(req->nbtsock->idr, request->name_trn_id)) goto failed;
+ id = idr_get_new_above(req->nbtsock->idr, req, request->name_trn_id,
UINT16_MAX);
}
if (id == -1) goto failed;
+
request->name_trn_id = id;
req->name_trn_id = id;
if (DEBUGLVL(10)) {
DEBUG(10,("Queueing nbt packet to %s:%d\n",
- req->dest_addr, req->dest_port));
+ req->dest->addr, req->dest->port));
NDR_PRINT_DEBUG(nbt_name_packet, request);
}
send off a nbt name reply
*/
NTSTATUS nbt_name_reply_send(struct nbt_name_socket *nbtsock,
- const char *dest_addr, int dest_port,
+ struct socket_address *dest,
struct nbt_name_packet *request)
{
struct nbt_name_request *req;
NT_STATUS_HAVE_NO_MEMORY(req);
req->nbtsock = nbtsock;
- req->dest_addr = talloc_strdup(req, dest_addr);
- if (req->dest_addr == NULL) goto failed;
- req->dest_port = dest_port;
+ req->dest = dest;
+ if (talloc_reference(req, dest) == NULL) goto failed;
req->state = NBT_REQUEST_SEND;
req->is_reply = True;
*/
NTSTATUS nbt_set_incoming_handler(struct nbt_name_socket *nbtsock,
void (*handler)(struct nbt_name_socket *, struct nbt_name_packet *,
- const char *, int ),
+ struct socket_address *),
void *private)
{
nbtsock->incoming.handler = handler;
{ NBT_RCODE_IMP, NT_STATUS_NOT_SUPPORTED },
{ NBT_RCODE_RFS, NT_STATUS_ACCESS_DENIED },
{ NBT_RCODE_ACT, NT_STATUS_ADDRESS_ALREADY_EXISTS },
- { NBT_RCODE_ACT, NT_STATUS_CONFLICTING_ADDRESSES }
+ { NBT_RCODE_CFT, NT_STATUS_CONFLICTING_ADDRESSES }
};
for (i=0;i<ARRAY_SIZE(map);i++) {
if (map[i].rcode == rcode) {