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 */
|