nbns.c


1
/**
2
3
 * This file implements a simple NetBios Server for the HostName.
4
 * All other NetBios querys are ignored
5
6
 * by Oliver Schindler November 2008
7
8
 * uIP version Copyright (c) 2002-2003, Adam Dunkels.
9
 * All rights reserved.
10
 *
11
 * Redistribution and use in source and binary forms, with or without
12
 * modification, are permitted provided that the following conditions
13
 * are met:
14
 * 1. Redistributions of source code must retain the above copyright
15
 *    notice, this list of conditions and the following disclaimer.
16
 * 2. Redistributions in binary form must reproduce the above copyright
17
 *    notice, this list of conditions and the following disclaimer in the
18
 *    documentation and/or other materials provided with the distribution.
19
 * 3. The name of the author may not be used to endorse or promote
20
 *    products derived from this software without specific prior
21
 *    written permission.
22
 *
23
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
24
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
27
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
 *
35
 *
36
 * NBNS.C
37
 *
38
 * The NetbiosNameService waiting on UDP-Port 137 for a NBNS-Query.
39
 * If this Query matches with the HostName, a resond is send.
40
 * All other NetBios Telegramms are ignored. ( like Samba, PrinterServices , 
41
etc. )
42
 */
43
44
/*-----------------------------------------------------------------------------
45
 * RFC 1001 - Protocol Standard for a NetBIOS Service on a TCP/UDP Transport: 
46
Concepts and methods
47
 * RFC 1002 - Protocol standard for a NetBIOS service on a TCP/UDP transport: 
48
Detailed specifications
49
 *----------------------------------------------------------------------------*/
50
51
52
/*-----------------------------------------------------------------------------
53
 * Includes
54
 *----------------------------------------------------------------------------*/
55
56
#include "lwip/opt.h"
57
58
#if LWIP_NBNS /* don't build if not configured for use in lwipopts.h */
59
#if LWIP_UDP                        
60
61
#include "lwip/udp.h"
62
#include "lwip/mem.h"
63
#include "lwip/nbns.h"
64
65
66
#include <string.h>
67
#include <stdlib.h> 
68
#include <ctype.h>
69
70
71
/** NBNS server port address */
72
#ifndef NBNS_CLIENT_PORT
73
#define NBNS_CLIENT_PORT           137
74
#endif
75
76
#define NETBIOS_NAME_LEN                   32
77
78
#if (NBNS_USES_STATIC_BUF == 1)
79
static u8_t             pHostname[NETBIOS_NAME_LEN];
80
#endif /* (NBNS_USES_STATIC_BUF == 1) */
81
82
83
84
/** NBNS message header */
85
PACK_STRUCT_BEGIN
86
87
struct nbns_hdr {
88
  u16_t id;
89
  u16_t flags;
90
  u16_t numquestions;
91
  u16_t numanswers;
92
  u16_t numauthrr;
93
  u16_t numextrarr;
94
} PACK_STRUCT_STRUCT;
95
PACK_STRUCT_END
96
97
98
/** NBNS rdata field */
99
PACK_STRUCT_BEGIN
100
101
struct nbns_rdata {
102
  u16_t len;
103
  u16_t nbflags;
104
  struct ip_addr addr;
105
} PACK_STRUCT_STRUCT;
106
PACK_STRUCT_END
107
108
PACK_STRUCT_BEGIN
109
struct nbns_question {
110
  struct nbns_hdr hdr;
111
  u8_t name_len;
112
  char name[32];
113
  char zero;
114
  u16_t type;
115
  u16_t class;
116
} PACK_STRUCT_STRUCT;
117
PACK_STRUCT_END
118
119
PACK_STRUCT_BEGIN
120
struct node_name {
121
  char name[16];
122
  u16_t name_flags;  
123
} PACK_STRUCT_STRUCT;
124
PACK_STRUCT_END
125
126
PACK_STRUCT_BEGIN
127
struct nbns_statistics {
128
    char mac_adr[6];
129
    u8_t jumpers;
130
    u8_t test_result;
131
    u16_t dummy[19];  
132
} PACK_STRUCT_STRUCT;
133
PACK_STRUCT_END
134
135
PACK_STRUCT_BEGIN
136
struct nbstat_response {
137
  struct nbns_hdr hdr;
138
  u8_t name_len;
139
  char name[32];
140
  char zero;
141
  u16_t type;
142
  u16_t class;
143
  u32_t zero1;
144
  u16_t rdlength;
145
  u8_t numnames;
146
  struct node_name node_name[2];
147
  struct nbns_statistics stat;
148
} PACK_STRUCT_STRUCT;
149
PACK_STRUCT_END
150
151
/* forward declarations */
152
static void nbns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, struct 
153
ip_addr *addr, u16_t port);
154
155
/**
156
 * Initialize the resolver: set up the UDP pcb 
157
 */
158
void
159
nbns_init(struct netif *netif)
160
{
161
  static struct udp_pcb *nbns_pcb = NULL;
162
163
  LWIP_DEBUGF(NBNS_DEBUG, ("nbns_init: initializing\n"));
164
165
  LWIP_UNUSED_ARG(netif);
166
167
  /* if nbns client not yet initialized... */
168
  if (nbns_pcb == NULL) {
169
    nbns_pcb = udp_new();
170
171
    if (nbns_pcb != NULL) {
172
173
      /* initialize NBNS client */
174
      udp_bind(nbns_pcb, IP_ADDR_ANY, NBNS_CLIENT_PORT);
175
      udp_recv(nbns_pcb, nbns_recv, NULL);
176
    }
177
  }
178
}
179
180
static u8_t
181
nbns_compare_name(u8_t *query, u8_t *response,u8_t len)
182
{
183
  u8_t i;
184
185
  for (i=0;i<len;i++) {
186
    if (*response==0){
187
                return 1;
188
        }
189
        if (*query==0){
190
                return 1;
191
        }
192
        if (tolower(query[i])!=tolower(response[i])) {
193
                return 1;
194
        }
195
  } 
196
197
  return 0;
198
}
199
200
#define NBNS_TTL_POS sizeof(struct nbns_hdr)+1+NETBIOS_NAME_LEN+1+2+2   
201
#define NBNS_RDATA_POS NBNS_TTL_POS + 4         
202
203
#define NBNS_MSGLEN_QUERY_RESPONSE 70 // NBNS_RDATA_POS+sizeof(struct nbns_rdata)
204
205
206
/**
207
 * Receive input function for NBNS query packets arriving for the NameService 
208
UDP pcb.
209
 *
210
 * @params see udp.h
211
 */
212
static void
213
nbns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)
214
{
215
  err_t err;
216
  u16_t unique_id,i;
217
  char c1,c2;
218
  struct nbns_hdr *hdr;
219
  struct nbns_question* question;
220
  struct nbns_rdata* rdata ;
221
  u16_t* ttl1,*ttl2;
222
  struct pbuf *prep;
223
  u16_t nquestions, nanswers,opcode,nm_flags,rcode;
224
  struct netif* netif;
225
#if (NBNS_USES_STATIC_BUF == 0)
226
  u8_t pHostname[NETBIOS_NAME_LEN];
227
#endif /* (NBNS_USES_STATIC_BUF == 0) */
228
#if (NBNS_USES_STATIC_BUF == 2)
229
  u8_t* pHostname;
230
#endif /* (NBNS_USES_STATIC_BUF == 2) */
231
232
  LWIP_UNUSED_ARG(arg);
233
  LWIP_UNUSED_ARG(pcb);
234
 
235
236
  /* is the nbns message too big ? */
237
  if (p->tot_len > NBNS_MSG_SIZE) {
238
    LWIP_DEBUGF(NBNS_DEBUG, ("nbns_recv: pbuf too big\n"));
239
    /* free pbuf and return */
240
    goto memerr1;
241
  }
242
243
  /* is the nbns message big enough ? */
244
  if (p->tot_len < (1+NETBIOS_NAME_LEN+1+2+2+sizeof(struct nbns_hdr))) {
245
    LWIP_DEBUGF(NBNS_DEBUG, ("nbns_recv: pbuf too small\n"));
246
    /* free pbuf and return */
247
    goto memerr1;
248
  }
249
250
#if (NBNS_USES_STATIC_BUF == 2)
251
  pHostname = mem_malloc(NETBIOS_NAME_LEN);
252
  if (pHostname == NULL) {
253
        LWIP_DEBUGF(NBNS_DEBUG, ("nbns_recv: mem_malloc error\n"));
254
        /* free pbuf and return */
255
        goto memerr2;
256
  }
257
258
#endif /* (NBNS_USES_STATIC_BUF == 2) */
259
260
  /* The content of the Telegramm is only decoded for information purpses.
261
     Later we use a copy of the orignal message */
262
 
263
   hdr = (struct nbns_hdr*)p->payload;
264
   unique_id = htons(hdr->id);                          /* this is a unique ID , which has to be sent back */
265
266
   /* We only care about the question(s) and the answers. The authrr
267
         and the extrarr are simply discarded. */
268
   nquestions = htons(hdr->numquestions);
269
   nanswers   = htons(hdr->numanswers);
270
271
   /* Decode what the client wants from us */
272
   opcode        =  htons(hdr->flags) & 0xf800;
273
   nm_flags      =  htons(hdr->flags) & 0x03f0;
274
   rcode                 =  htons(hdr->flags) & 0x000f;
275
276
   if (opcode & OPCODE_R ) { /* This is a response packet, so don't care about */
277
          /* deallocate memory and return */
278
          goto memerr2;
279
   }
280
281
   switch (opcode & OPCODE_MASK) {
282
     case OPCODE_QUERY:
283
          /* There is someone looking for a host with a certain name ... */
284
          break;
285
286
     case OPCODE_REGISTRATION:
287
     case OPCODE_RELEASE:     
288
     case OPCODE_WACK:        
289
     case OPCODE_REFRESH:
290
     default:
291
          /* Nothing of interest for us */
292
          /* deallocate memory and return */
293
          goto memerr2;
294
          break;        /* just for the compiler .... */
295
   }
296
297
  question = (struct nbns_question*)p->payload;
298
  if (question->name_len != NETBIOS_NAME_LEN)
299
  {
300
    goto memerr2;
301
  }
302
303
    memset (pHostname,0,NETBIOS_NAME_LEN);
304
    /* Decode the hostname */
305
    for (i=0;i<question->name_len;i+=2) {
306
          c1=(question->name[i]&0x3f)-1;
307
          c2=(question->name[i+1]&0x3f)-1;
308
       pHostname[i/2]=(c1<<4)+(c2);                                             
309
                         
310
    }
311
312
  netif = ip_route(addr);
313
314
  if (ntohs(question->type) == NB)
315
  {
316
     if (nbns_compare_name(pHostname,(u8_t*)netif->hostname,strlen(netif->hostname)) == 0)
317
     {
318
           /* Hey , this is ours .. we have to send a reply */
319
320
        LWIP_DEBUGF(NBNS_DEBUG, ("nbns_recv: Got a query for our hostname\n"));
321
322
        /* reallocate of pbuf isn't implemented to grow, so we have allocate a
323
         new buffer ,to have space for our IP-Adress */
324
325
        prep = pbuf_alloc(PBUF_TRANSPORT, NBNS_MSGLEN_QUERY_RESPONSE, PBUF_RAM);
326
327
        /* clone the original message, for the transport_id,hostname and flags*/
328
        pbuf_copy_partial(p, prep->payload, p->tot_len, 0);
329
330
            
331
        /* set pointers for the different parts in the message */
332
        hdr = (struct nbns_hdr*)prep->payload;
333
334
        /* ttl is 32-bit, but we can't guarantee that is aligned on a 32 bit boundary,
335
         so split it up into two halves */
336
        ttl1 = (u16_t*)(((u8_t*)prep->payload)+NBNS_TTL_POS);
337
        ttl2 = (u16_t*)(((u8_t*)prep->payload)+NBNS_TTL_POS+2);
338
339
        /* This is were our IP-Adress goes to */
340
        rdata = (struct nbns_rdata*) (((u8_t*)prep->payload)+NBNS_RDATA_POS);
341
342
        /* Set the response Flag, and the number of answers  */
343
344
        opcode=OPCODE_R+OPCODE_QUERY;
345
        nm_flags=NM_AA_BIT+NM_RD_BIT;
346
        rcode=RCODE_POS_RSP; /* Positive respones */
347
348
        hdr->flags =ntohs(opcode+nm_flags+rcode); 
349
        hdr->numquestions=ntohs(0);
350
        hdr->numanswers  =ntohs(1);
351
352
        *ttl1=ntohs(0);
353
        *ttl2=ntohs(0);       /* Infinite time to live */
354
        rdata->len=ntohs(2+sizeof(struct ip_addr)); 
355
        rdata->nbflags=ntohs(ONT_B);          /* Broadcast Node */
356
          
357
        memcpy((unsigned char*)&rdata->addr,(unsigned char*)&netif->ip_addr,sizeof(struct ip_addr));
358
359
        /* It's better to answer on the port , we got the query, maybe some strange
360
         port-translation is in between */
361
        err = udp_sendto_if(pcb, prep, addr, port, netif);
362
363
        /* cleaning up */
364
        pbuf_free(prep);
365
     }
366
  }
367
  else if(ntohs(question->type) == NBSTAT)
368
  {
369
     if ((strstr((char*)pHostname, "*") == (char*)pHostname))
370
     {
371
         struct nbstat_response* resp;
372
        prep = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct nbstat_response), PBUF_RAM);
373
374
        /* clone the original message, for the transport_id,hostname and flags*/
375
        pbuf_copy_partial(p, prep->payload, p->tot_len, 0);
376
377
            
378
        /* set pointers for the different parts in the message */
379
        resp = (struct nbstat_response*)prep->payload;
380
381
              resp->zero1 = 0;
382
383
        opcode=OPCODE_R+OPCODE_QUERY;
384
        nm_flags=NM_AA_BIT;
385
        rcode=RCODE_POS_RSP; /* Positive respones */
386
387
        resp->hdr.flags =ntohs(opcode+nm_flags+rcode); 
388
        resp->hdr.numquestions=ntohs(0);
389
        resp->hdr.numanswers  =ntohs(1);
390
        resp->rdlength = ntohs(2*sizeof(struct node_name) + sizeof(struct nbns_statistics));
391
        
392
        resp->numnames = 2;
393
        memset(resp->node_name[0].name, 0x20, sizeof(resp->node_name[0].name));
394
            memcpy(resp->node_name[0].name, netif->hostname, strlen((char*)netif->hostname));
395
            resp->node_name[0].name_flags = ntohs(0x6400);
396
            memset(resp->node_name[1].name, 0x20, sizeof(resp->node_name[1].name));
397
            memcpy(resp->node_name[1].name, netif->hostname, strlen((char*)netif->hostname));
398
              resp->node_name[1].name[15] = 0;
399
            resp->node_name[1].name_flags = ntohs(0x6400);
400
        
401
        resp->stat.jumpers = 0x00;
402
        resp->stat.test_result = 0x00;
403
        memset((char*)&resp->stat.dummy, 0, sizeof(resp->stat.dummy));
404
        memcpy((char*)&resp->stat.mac_adr, (char*)&netif->hwaddr, 6);
405
406
        /* It's better to answer on the port , we got the query, maybe some strange
407
         port-translation is in between */
408
        err = udp_sendto_if(pcb, prep, addr, port, netif);
409
410
        /* cleaning up */
411
        pbuf_free(prep);
412
    }
413
  }
414
415
  /* deallocate memory and return */
416
  //goto memerr2;
417
418
memerr2:
419
#if (NBNS_USES_STATIC_BUF == 2)
420
  /* free Hostname buffer */
421
 if(pHostname!=NULL){
422
  mem_free(pHostname);
423
 }
424
#endif /* (NBNS_USES_STATIC_BUF == 2) */
425
426
memerr1:
427
  /* free pbuf */
428
  pbuf_free(p);
429
  return;
430
}
431
432
#else
433
#error "UDP is needed !"
434
#endif
435
#endif /* LWIP_NBNS */