xref: /nrf52832-nimble/rt-thread/components/net/lwip-2.1.0/src/apps/netbiosns/netbiosns.c (revision 104654410c56c573564690304ae786df310c91fc)
1   /**
2  * @file
3  * NetBIOS name service responder
4  */
5 
6 /**
7  * @defgroup netbiosns NETBIOS responder
8  * @ingroup apps
9  *
10  * This is an example implementation of a NetBIOS name server.
11  * It responds to name queries for a configurable name.
12  * Name resolving is not supported.
13  *
14  * Note that the device doesn't broadcast it's own name so can't
15  * detect duplicate names!
16  */
17 
18 /*
19  * Redistribution and use in source and binary forms, with or without modification,
20  * are permitted provided that the following conditions are met:
21  *
22  * 1. Redistributions of source code must retain the above copyright notice,
23  *    this list of conditions and the following disclaimer.
24  * 2. Redistributions in binary form must reproduce the above copyright notice,
25  *    this list of conditions and the following disclaimer in the documentation
26  *    and/or other materials provided with the distribution.
27  * 3. The name of the author may not be used to endorse or promote products
28  *    derived from this software without specific prior written permission.
29  *
30  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
31  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
32  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
33  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
34  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
35  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
37  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
38  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
39  * OF SUCH DAMAGE.
40  *
41  * This file is part of the lwIP TCP/IP stack.
42  *
43  * Modifications by Ray Abram to respond to NetBIOS name requests when Incoming name = *
44  * - based on code from "https://github.com/esp8266/Arduino/commit/1f7989b31d26d7df9776a08f36d685eae7ac8f99"
45  * - with permission to relicense to BSD from original author:
46  *   http://www.xpablo.cz/?p=751#more-751
47  */
48 
49 #include "lwip/apps/netbiosns.h"
50 
51 #if LWIP_IPV4 && LWIP_UDP  /* don't build if not configured for use in lwipopts.h */
52 
53 #include "lwip/def.h"
54 #include "lwip/udp.h"
55 #include "lwip/ip.h"
56 #include "lwip/netif.h"
57 #include "lwip/prot/iana.h"
58 
59 #include <string.h>
60 
61 /** size of a NetBIOS name */
62 #define NETBIOS_NAME_LEN 16
63 
64 /** The Time-To-Live for NetBIOS name responds (in seconds)
65  * Default is 300000 seconds (3 days, 11 hours, 20 minutes) */
66 #define NETBIOS_NAME_TTL 300000u
67 
68 /** NetBIOS header flags */
69 #define NETB_HFLAG_RESPONSE           0x8000U
70 #define NETB_HFLAG_OPCODE             0x7800U
71 #define NETB_HFLAG_OPCODE_NAME_QUERY  0x0000U
72 #define NETB_HFLAG_AUTHORATIVE        0x0400U
73 #define NETB_HFLAG_TRUNCATED          0x0200U
74 #define NETB_HFLAG_RECURS_DESIRED     0x0100U
75 #define NETB_HFLAG_RECURS_AVAILABLE   0x0080U
76 #define NETB_HFLAG_BROADCAST          0x0010U
77 #define NETB_HFLAG_REPLYCODE          0x0008U
78 #define NETB_HFLAG_REPLYCODE_NOERROR  0x0000U
79 
80 /* NetBIOS question types */
81 #define NETB_QTYPE_NB                 0x0020U
82 #define NETB_QTYPE_NBSTAT             0x0021U
83 
84 /** NetBIOS name flags */
85 #define NETB_NFLAG_UNIQUE             0x8000U
86 #define NETB_NFLAG_NODETYPE           0x6000U
87 #define NETB_NFLAG_NODETYPE_HNODE     0x6000U
88 #define NETB_NFLAG_NODETYPE_MNODE     0x4000U
89 #define NETB_NFLAG_NODETYPE_PNODE     0x2000U
90 #define NETB_NFLAG_NODETYPE_BNODE     0x0000U
91 
92 #define NETB_NFLAG_NAME_IN_CONFLICT   0x0800U /* 1=Yes, 0=No */
93 #define NETB_NFLAG_NAME_IS_ACTIVE     0x0400U /* 1=Yes, 0=No */
94 #define NETB_NFLAG_NAME_IS_PERMANENT  0x0200U /* 1=Yes (Name is Permanent Node Name), 0=No */
95 
96 /** NetBIOS message header */
97 #ifdef PACK_STRUCT_USE_INCLUDES
98 #  include "arch/bpstruct.h"
99 #endif
100 PACK_STRUCT_BEGIN
101 struct netbios_hdr {
102   PACK_STRUCT_FIELD(u16_t trans_id);
103   PACK_STRUCT_FIELD(u16_t flags);
104   PACK_STRUCT_FIELD(u16_t questions);
105   PACK_STRUCT_FIELD(u16_t answerRRs);
106   PACK_STRUCT_FIELD(u16_t authorityRRs);
107   PACK_STRUCT_FIELD(u16_t additionalRRs);
108 } PACK_STRUCT_STRUCT;
109 PACK_STRUCT_END
110 #ifdef PACK_STRUCT_USE_INCLUDES
111 #  include "arch/epstruct.h"
112 #endif
113 
114 /** NetBIOS message name part */
115 #ifdef PACK_STRUCT_USE_INCLUDES
116 #  include "arch/bpstruct.h"
117 #endif
118 PACK_STRUCT_BEGIN
119 struct netbios_name_hdr {
120   PACK_STRUCT_FLD_8(u8_t  nametype);
121   PACK_STRUCT_FLD_8(u8_t  encname[(NETBIOS_NAME_LEN * 2) + 1]);
122   PACK_STRUCT_FIELD(u16_t type);
123   PACK_STRUCT_FIELD(u16_t cls);
124   PACK_STRUCT_FIELD(u32_t ttl);
125   PACK_STRUCT_FIELD(u16_t datalen);
126   PACK_STRUCT_FIELD(u16_t flags);
127   PACK_STRUCT_FLD_S(ip4_addr_p_t addr);
128 } PACK_STRUCT_STRUCT;
129 PACK_STRUCT_END
130 #ifdef PACK_STRUCT_USE_INCLUDES
131 #  include "arch/epstruct.h"
132 #endif
133 
134 /** NetBIOS message */
135 #ifdef PACK_STRUCT_USE_INCLUDES
136 #  include "arch/bpstruct.h"
137 #endif
138 PACK_STRUCT_BEGIN
139 struct netbios_resp {
140   struct netbios_hdr      resp_hdr;
141   struct netbios_name_hdr resp_name;
142 } PACK_STRUCT_STRUCT;
143 PACK_STRUCT_END
144 #ifdef PACK_STRUCT_USE_INCLUDES
145 #  include "arch/epstruct.h"
146 #endif
147 
148 /** The NBNS Structure Responds to a Name Query */
149 #ifdef PACK_STRUCT_USE_INCLUDES
150 #  include "arch/bpstruct.h"
151 #endif
152 PACK_STRUCT_BEGIN
153 struct netbios_answer {
154   struct netbios_hdr      answer_hdr;
155   /** the length of the next string */
156   PACK_STRUCT_FIELD(u8_t  name_size);
157   /** WARNING!!! this item may be of a different length (we use this struct for transmission) */
158   PACK_STRUCT_FLD_8(u8_t  query_name[(NETBIOS_NAME_LEN * 2) + 1]);
159   PACK_STRUCT_FIELD(u16_t packet_type);
160   PACK_STRUCT_FIELD(u16_t cls);
161   PACK_STRUCT_FIELD(u32_t ttl);
162   PACK_STRUCT_FIELD(u16_t data_length);
163 #define OFFSETOF_STRUCT_NETBIOS_ANSWER_NUMBER_OF_NAMES 56
164   /** number of names */
165   PACK_STRUCT_FLD_8(u8_t  number_of_names);
166   /** node name */
167   PACK_STRUCT_FLD_8(u8_t  answer_name[NETBIOS_NAME_LEN]);
168   /** node flags */
169   PACK_STRUCT_FIELD(u16_t answer_name_flags);
170   /** Unit ID */
171   PACK_STRUCT_FLD_8(u8_t  unit_id[6]);
172   /** Jumpers */
173   PACK_STRUCT_FLD_8(u8_t  jumpers);
174   /** Test result */
175   PACK_STRUCT_FLD_8(u8_t  test_result);
176   /** Version number */
177   PACK_STRUCT_FIELD(u16_t version_number);
178   /** Period of statistics */
179   PACK_STRUCT_FIELD(u16_t period_of_statistics);
180   /** Statistics */
181   PACK_STRUCT_FIELD(u16_t number_of_crcs);
182   /** Statistics */
183   PACK_STRUCT_FIELD(u16_t number_of_alignment_errors);
184   /** Statistics */
185   PACK_STRUCT_FIELD(u16_t number_of_collisions);
186   /** Statistics */
187   PACK_STRUCT_FIELD(u16_t number_of_send_aborts);
188   /** Statistics */
189   PACK_STRUCT_FIELD(u32_t number_of_good_sends);
190   /** Statistics */
191   PACK_STRUCT_FIELD(u32_t number_of_good_receives);
192   /** Statistics */
193   PACK_STRUCT_FIELD(u16_t number_of_retransmits);
194   /** Statistics */
195   PACK_STRUCT_FIELD(u16_t number_of_no_resource_condition);
196   /** Statistics */
197   PACK_STRUCT_FIELD(u16_t number_of_free_command_blocks);
198   /** Statistics */
199   PACK_STRUCT_FIELD(u16_t total_number_of_command_blocks);
200   /** Statistics */
201   PACK_STRUCT_FIELD(u16_t max_total_number_of_command_blocks);
202   /** Statistics */
203   PACK_STRUCT_FIELD(u16_t number_of_pending_sessions);
204   /** Statistics */
205   PACK_STRUCT_FIELD(u16_t max_number_of_pending_sessions);
206   /** Statistics */
207   PACK_STRUCT_FIELD(u16_t max_total_sessions_possible);
208   /** Statistics */
209   PACK_STRUCT_FIELD(u16_t session_data_packet_size);
210 } PACK_STRUCT_STRUCT;
211 PACK_STRUCT_END
212 #ifdef PACK_STRUCT_USE_INCLUDES
213 #  include "arch/epstruct.h"
214 #endif
215 
216 #ifdef NETBIOS_LWIP_NAME
217 #define NETBIOS_LOCAL_NAME NETBIOS_LWIP_NAME
218 #else
219 static char netbiosns_local_name[NETBIOS_NAME_LEN];
220 #define NETBIOS_LOCAL_NAME netbiosns_local_name
221 #endif
222 
223 static struct udp_pcb *netbiosns_pcb;
224 
225 /** Decode a NetBIOS name (from packet to string) */
226 static int
netbiosns_name_decode(char * name_enc,char * name_dec,int name_dec_len)227 netbiosns_name_decode(char *name_enc, char *name_dec, int name_dec_len)
228 {
229   char *pname;
230   char  cname;
231   char  cnbname;
232   int   idx = 0;
233 
234   LWIP_UNUSED_ARG(name_dec_len);
235 
236   /* Start decoding netbios name. */
237   pname  = name_enc;
238   for (;;) {
239     /* Every two characters of the first level-encoded name
240      * turn into one character in the decoded name. */
241     cname = *pname;
242     if (cname == '\0') {
243       break;  /* no more characters */
244     }
245     if (cname == '.') {
246       break;  /* scope ID follows */
247     }
248     if (!lwip_isupper(cname)) {
249       /* Not legal. */
250       return -1;
251     }
252     cname -= 'A';
253     cnbname = cname << 4;
254     pname++;
255 
256     cname = *pname;
257     if (!lwip_isupper(cname)) {
258       /* Not legal. */
259       return -1;
260     }
261     cname -= 'A';
262     cnbname |= cname;
263     pname++;
264 
265     /* Do we have room to store the character? */
266     if (idx < NETBIOS_NAME_LEN) {
267       /* Yes - store the character. */
268       name_dec[idx++] = (cnbname != ' ' ? cnbname : '\0');
269     }
270   }
271 
272   return 0;
273 }
274 
275 #if 0 /* function currently unused */
276 /** Encode a NetBIOS name (from string to packet) - currently unused because
277     we don't ask for names. */
278 static int
279 netbiosns_name_encode(char *name_enc, char *name_dec, int name_dec_len)
280 {
281   char         *pname;
282   char          cname;
283   unsigned char ucname;
284   int           idx = 0;
285 
286   /* Start encoding netbios name. */
287   pname = name_enc;
288 
289   for (;;) {
290     /* Every two characters of the first level-encoded name
291      * turn into one character in the decoded name. */
292     cname = *pname;
293     if (cname == '\0') {
294       break;  /* no more characters */
295     }
296     if (cname == '.') {
297       break;  /* scope ID follows */
298     }
299     if ((cname < 'A' || cname > 'Z') && (cname < '0' || cname > '9')) {
300       /* Not legal. */
301       return -1;
302     }
303 
304     /* Do we have room to store the character? */
305     if (idx >= name_dec_len) {
306       return -1;
307     }
308 
309     /* Yes - store the character. */
310     ucname = cname;
311     name_dec[idx++] = ('A' + ((ucname >> 4) & 0x0F));
312     name_dec[idx++] = ('A' + ( ucname     & 0x0F));
313     pname++;
314   }
315 
316   /* Fill with "space" coding */
317   for (; idx < name_dec_len - 1;) {
318     name_dec[idx++] = 'C';
319     name_dec[idx++] = 'A';
320   }
321 
322   /* Terminate string */
323   name_dec[idx] = '\0';
324 
325   return 0;
326 }
327 #endif /* 0 */
328 
329 /** NetBIOS Name service recv callback */
330 static void
netbiosns_recv(void * arg,struct udp_pcb * upcb,struct pbuf * p,const ip_addr_t * addr,u16_t port)331 netbiosns_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
332 {
333   LWIP_UNUSED_ARG(arg);
334 
335   /* if packet is valid */
336   if (p != NULL) {
337     char   netbios_name[NETBIOS_NAME_LEN + 1];
338     struct netbios_hdr      *netbios_hdr      = (struct netbios_hdr *)p->payload;
339     struct netbios_name_hdr *netbios_name_hdr = (struct netbios_name_hdr *)(netbios_hdr + 1);
340 
341     /* is the packet long enough (we need the header in one piece) */
342     if (p->len < (sizeof(struct netbios_hdr) + sizeof(struct netbios_name_hdr))) {
343       /* packet too short */
344       pbuf_free(p);
345       return;
346     }
347     /* we only answer if we got a default interface */
348     if (netif_default != NULL) {
349       /* @todo: do we need to check answerRRs/authorityRRs/additionalRRs? */
350       /* if the packet is a NetBIOS name query question */
351       if (((netbios_hdr->flags & PP_NTOHS(NETB_HFLAG_OPCODE)) == PP_NTOHS(NETB_HFLAG_OPCODE_NAME_QUERY)) &&
352           ((netbios_hdr->flags & PP_NTOHS(NETB_HFLAG_RESPONSE)) == 0) &&
353           (netbios_hdr->questions == PP_NTOHS(1))) {
354         /* decode the NetBIOS name */
355         netbiosns_name_decode((char *)(netbios_name_hdr->encname), netbios_name, sizeof(netbios_name));
356         /* check the request type */
357         if (netbios_name_hdr->type == PP_HTONS(NETB_QTYPE_NB)) {
358           /* if the packet is for us */
359           if (lwip_strnicmp(netbios_name, NETBIOS_LOCAL_NAME, sizeof(NETBIOS_LOCAL_NAME)) == 0) {
360             struct pbuf *q;
361             struct netbios_resp *resp;
362 
363             q = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct netbios_resp), PBUF_RAM);
364             if (q != NULL) {
365               resp = (struct netbios_resp *)q->payload;
366 
367               /* prepare NetBIOS header response */
368               resp->resp_hdr.trans_id      = netbios_hdr->trans_id;
369               resp->resp_hdr.flags         = PP_HTONS(NETB_HFLAG_RESPONSE |
370                                                       NETB_HFLAG_OPCODE_NAME_QUERY |
371                                                       NETB_HFLAG_AUTHORATIVE |
372                                                       NETB_HFLAG_RECURS_DESIRED);
373               resp->resp_hdr.questions     = 0;
374               resp->resp_hdr.answerRRs     = PP_HTONS(1);
375               resp->resp_hdr.authorityRRs  = 0;
376               resp->resp_hdr.additionalRRs = 0;
377 
378               /* prepare NetBIOS header datas */
379               MEMCPY( resp->resp_name.encname, netbios_name_hdr->encname, sizeof(netbios_name_hdr->encname));
380               resp->resp_name.nametype     = netbios_name_hdr->nametype;
381               resp->resp_name.type         = netbios_name_hdr->type;
382               resp->resp_name.cls          = netbios_name_hdr->cls;
383               resp->resp_name.ttl          = PP_HTONL(NETBIOS_NAME_TTL);
384               resp->resp_name.datalen      = PP_HTONS(sizeof(resp->resp_name.flags) + sizeof(resp->resp_name.addr));
385               resp->resp_name.flags        = PP_HTONS(NETB_NFLAG_NODETYPE_BNODE);
386               ip4_addr_copy(resp->resp_name.addr, *netif_ip4_addr(netif_default));
387 
388               /* send the NetBIOS response */
389               udp_sendto(upcb, q, addr, port);
390 
391               /* free the "reference" pbuf */
392               pbuf_free(q);
393             }
394           }
395 #if LWIP_NETBIOS_RESPOND_NAME_QUERY
396         } else if (netbios_name_hdr->type == PP_HTONS(NETB_QTYPE_NBSTAT)) {
397           /* if the packet is for us or general query */
398           if (!lwip_strnicmp(netbios_name, NETBIOS_LOCAL_NAME, sizeof(NETBIOS_LOCAL_NAME)) ||
399               !lwip_strnicmp(netbios_name, "*", sizeof(NETBIOS_LOCAL_NAME))) {
400             /* general query - ask for our IP address */
401             struct pbuf *q;
402             struct netbios_answer *resp;
403 
404             q = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct netbios_answer), PBUF_RAM);
405             if (q != NULL) {
406               /* buffer to which a response is compiled */
407               resp = (struct netbios_answer *) q->payload;
408 
409               /* Init response to zero, especially the statistics fields */
410               memset(resp, 0, sizeof(*resp));
411 
412               /* copy the query to the response ID */
413               resp->answer_hdr.trans_id        = netbios_hdr->trans_id;
414               /* acknowledgment of termination */
415               resp->answer_hdr.flags           = PP_HTONS(NETB_HFLAG_RESPONSE | NETB_HFLAG_OPCODE_NAME_QUERY | NETB_HFLAG_AUTHORATIVE);
416               /* resp->answer_hdr.questions       = PP_HTONS(0); done by memset() */
417               /* serial number of the answer */
418               resp->answer_hdr.answerRRs       = PP_HTONS(1);
419               /* resp->answer_hdr.authorityRRs    = PP_HTONS(0); done by memset() */
420               /* resp->answer_hdr.additionalRRs   = PP_HTONS(0); done by memset() */
421               /* we will copy the length of the station name */
422               resp->name_size                  = netbios_name_hdr->nametype;
423               /* we will copy the queried name */
424               MEMCPY(resp->query_name, netbios_name_hdr->encname, (NETBIOS_NAME_LEN * 2) + 1);
425               /* NBSTAT */
426               resp->packet_type                = PP_HTONS(0x21);
427               /* Internet name */
428               resp->cls                        = PP_HTONS(1);
429               /* resp->ttl                        = PP_HTONL(0); done by memset() */
430               resp->data_length                = PP_HTONS(sizeof(struct netbios_answer) - offsetof(struct netbios_answer, number_of_names));
431               resp->number_of_names            = 1;
432 
433               /* make windows see us as workstation, not as a server */
434               memset(resp->answer_name, 0x20, NETBIOS_NAME_LEN - 1);
435               /* strlen is checked to be < NETBIOS_NAME_LEN during initialization */
436               MEMCPY(resp->answer_name, NETBIOS_LOCAL_NAME, strlen(NETBIOS_LOCAL_NAME));
437 
438               /* b-node, unique, active */
439               resp->answer_name_flags          = PP_HTONS(NETB_NFLAG_NAME_IS_ACTIVE);
440 
441               /* Set responder netif MAC address */
442               SMEMCPY(resp->unit_id, ip_current_input_netif()->hwaddr, sizeof(resp->unit_id));
443 
444               udp_sendto(upcb, q, addr, port);
445               pbuf_free(q);
446             }
447           }
448 #endif /* LWIP_NETBIOS_RESPOND_NAME_QUERY */
449         }
450       }
451     }
452     /* free the pbuf */
453     pbuf_free(p);
454   }
455 }
456 
457 /**
458  * @ingroup netbiosns
459  * Init netbios responder
460  */
461 void
netbiosns_init(void)462 netbiosns_init(void)
463 {
464   /* LWIP_ASSERT_CORE_LOCKED(); is checked by udp_new() */
465 #ifdef NETBIOS_LWIP_NAME
466   LWIP_ASSERT("NetBIOS name is too long!", strlen(NETBIOS_LWIP_NAME) < NETBIOS_NAME_LEN);
467 #endif
468 
469   netbiosns_pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
470   if (netbiosns_pcb != NULL) {
471     /* we have to be allowed to send broadcast packets! */
472     ip_set_option(netbiosns_pcb, SOF_BROADCAST);
473     udp_bind(netbiosns_pcb, IP_ANY_TYPE, LWIP_IANA_PORT_NETBIOS);
474     udp_recv(netbiosns_pcb, netbiosns_recv, netbiosns_pcb);
475   }
476 }
477 
478 #ifndef NETBIOS_LWIP_NAME
479 /**
480  * @ingroup netbiosns
481  * Set netbios name. ATTENTION: the hostname must be less than 15 characters!
482  *                              the NetBIOS name spec says the name MUST be upper case, so incoming name is forced into uppercase :-)
483  */
484 void
netbiosns_set_name(const char * hostname)485 netbiosns_set_name(const char *hostname)
486 {
487   size_t i;
488   size_t copy_len = strlen(hostname);
489   LWIP_ASSERT_CORE_LOCKED();
490   LWIP_ASSERT("NetBIOS name is too long!", copy_len < NETBIOS_NAME_LEN);
491   if (copy_len >= NETBIOS_NAME_LEN) {
492     copy_len = NETBIOS_NAME_LEN - 1;
493   }
494 
495   /* make name into upper case */
496   for (i = 0; i < copy_len; i++ ) {
497     netbiosns_local_name[i] = (char)lwip_toupper(hostname[i]);
498   }
499   netbiosns_local_name[copy_len] = '\0';
500 }
501 #endif /* NETBIOS_LWIP_NAME */
502 
503 /**
504  * @ingroup netbiosns
505  * Stop netbios responder
506  */
507 void
netbiosns_stop(void)508 netbiosns_stop(void)
509 {
510   LWIP_ASSERT_CORE_LOCKED();
511   if (netbiosns_pcb != NULL) {
512     udp_remove(netbiosns_pcb);
513     netbiosns_pcb = NULL;
514   }
515 }
516 
517 #endif /* LWIP_IPV4 && LWIP_UDP */
518