r21316: if we got an unexpected nbt packet that most times mean
[bbaumbach/samba-autobuild/.git] / source4 / libcli / nbt / nbtsocket.c
index 38b356338cdeca1351b082e5521b6d5495b91105..c1e30fc2457c38f4424ae7a9d20b13c918b215bf 100644 (file)
 
 #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);
        }
@@ -72,8 +71,8 @@ static void nbt_name_socket_send(struct nbt_name_socket *nbtsock)
                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)) {
@@ -82,10 +81,10 @@ static void nbt_name_socket_send(struct nbt_name_socket *nbtsock)
                }
 
                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++;
                }
@@ -122,7 +121,11 @@ static void nbt_name_socket_timeout(struct event_context *ev, struct timed_event
                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;
        }
@@ -149,27 +152,30 @@ static void nbt_name_socket_recv(struct nbt_name_socket *nbtsock)
 {
        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) {
@@ -189,7 +195,7 @@ static void nbt_name_socket_recv(struct nbt_name_socket *nbtsock)
 
        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);
        }
 
@@ -197,7 +203,7 @@ static void nbt_name_socket_recv(struct nbt_name_socket *nbtsock)
           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;
@@ -206,8 +212,12 @@ static void nbt_name_socket_recv(struct nbt_name_socket *nbtsock)
        /* 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;
        }
@@ -226,14 +236,12 @@ static void nbt_name_socket_recv(struct nbt_name_socket *nbtsock)
                   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;
        }
@@ -247,9 +255,10 @@ static void nbt_name_socket_recv(struct nbt_name_socket *nbtsock)
                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 */
@@ -280,7 +289,8 @@ static void nbt_name_socket_handler(struct event_context *ev, struct fd_event *f
                                                          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);
        }
 }
@@ -290,7 +300,7 @@ static void nbt_name_socket_handler(struct event_context *ev, struct fd_event *f
   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;
@@ -319,6 +329,7 @@ struct nbt_name_socket *nbt_name_socket_init(TALLOC_CTX *mem_ctx,
        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,
@@ -335,7 +346,7 @@ failed:
   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)
@@ -348,33 +359,24 @@ struct nbt_name_request *nbt_name_request_send(struct nbt_name_socket *nbtsock,
        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;
 
@@ -392,7 +394,7 @@ struct nbt_name_request *nbt_name_request_send(struct nbt_name_socket *nbtsock,
 
        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);
        }
 
@@ -410,7 +412,7 @@ failed:
   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;
@@ -420,9 +422,8 @@ NTSTATUS nbt_name_reply_send(struct nbt_name_socket *nbtsock,
        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;
 
@@ -475,7 +476,7 @@ NTSTATUS nbt_name_request_recv(struct nbt_name_request *req)
 */
 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;
@@ -501,7 +502,7 @@ NTSTATUS nbt_rcode_to_ntstatus(uint8_t rcode)
                { 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) {