BadVPN – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 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 | */ |
||
44 | |||
45 | #include "lwip/apps/netbiosns.h" |
||
46 | |||
47 | #if LWIP_IPV4 && LWIP_UDP /* don't build if not configured for use in lwipopts.h */ |
||
48 | |||
49 | #include "lwip/def.h" |
||
50 | #include "lwip/udp.h" |
||
51 | #include "lwip/netif.h" |
||
52 | #include "lwip/prot/iana.h" |
||
53 | |||
54 | #include <string.h> |
||
55 | |||
56 | /** size of a NetBIOS name */ |
||
57 | #define NETBIOS_NAME_LEN 16 |
||
58 | |||
59 | /** The Time-To-Live for NetBIOS name responds (in seconds) |
||
60 | * Default is 300000 seconds (3 days, 11 hours, 20 minutes) */ |
||
61 | #define NETBIOS_NAME_TTL 300000u |
||
62 | |||
63 | /** NetBIOS header flags */ |
||
64 | #define NETB_HFLAG_RESPONSE 0x8000U |
||
65 | #define NETB_HFLAG_OPCODE 0x7800U |
||
66 | #define NETB_HFLAG_OPCODE_NAME_QUERY 0x0000U |
||
67 | #define NETB_HFLAG_AUTHORATIVE 0x0400U |
||
68 | #define NETB_HFLAG_TRUNCATED 0x0200U |
||
69 | #define NETB_HFLAG_RECURS_DESIRED 0x0100U |
||
70 | #define NETB_HFLAG_RECURS_AVAILABLE 0x0080U |
||
71 | #define NETB_HFLAG_BROADCAST 0x0010U |
||
72 | #define NETB_HFLAG_REPLYCODE 0x0008U |
||
73 | #define NETB_HFLAG_REPLYCODE_NOERROR 0x0000U |
||
74 | |||
75 | /** NetBIOS name flags */ |
||
76 | #define NETB_NFLAG_UNIQUE 0x8000U |
||
77 | #define NETB_NFLAG_NODETYPE 0x6000U |
||
78 | #define NETB_NFLAG_NODETYPE_HNODE 0x6000U |
||
79 | #define NETB_NFLAG_NODETYPE_MNODE 0x4000U |
||
80 | #define NETB_NFLAG_NODETYPE_PNODE 0x2000U |
||
81 | #define NETB_NFLAG_NODETYPE_BNODE 0x0000U |
||
82 | |||
83 | /** NetBIOS message header */ |
||
84 | #ifdef PACK_STRUCT_USE_INCLUDES |
||
85 | # include "arch/bpstruct.h" |
||
86 | #endif |
||
87 | PACK_STRUCT_BEGIN |
||
88 | struct netbios_hdr { |
||
89 | PACK_STRUCT_FIELD(u16_t trans_id); |
||
90 | PACK_STRUCT_FIELD(u16_t flags); |
||
91 | PACK_STRUCT_FIELD(u16_t questions); |
||
92 | PACK_STRUCT_FIELD(u16_t answerRRs); |
||
93 | PACK_STRUCT_FIELD(u16_t authorityRRs); |
||
94 | PACK_STRUCT_FIELD(u16_t additionalRRs); |
||
95 | } PACK_STRUCT_STRUCT; |
||
96 | PACK_STRUCT_END |
||
97 | #ifdef PACK_STRUCT_USE_INCLUDES |
||
98 | # include "arch/epstruct.h" |
||
99 | #endif |
||
100 | |||
101 | /** NetBIOS message name part */ |
||
102 | #ifdef PACK_STRUCT_USE_INCLUDES |
||
103 | # include "arch/bpstruct.h" |
||
104 | #endif |
||
105 | PACK_STRUCT_BEGIN |
||
106 | struct netbios_name_hdr { |
||
107 | PACK_STRUCT_FLD_8(u8_t nametype); |
||
108 | PACK_STRUCT_FLD_8(u8_t encname[(NETBIOS_NAME_LEN * 2) + 1]); |
||
109 | PACK_STRUCT_FIELD(u16_t type); |
||
110 | PACK_STRUCT_FIELD(u16_t cls); |
||
111 | PACK_STRUCT_FIELD(u32_t ttl); |
||
112 | PACK_STRUCT_FIELD(u16_t datalen); |
||
113 | PACK_STRUCT_FIELD(u16_t flags); |
||
114 | PACK_STRUCT_FLD_S(ip4_addr_p_t addr); |
||
115 | } PACK_STRUCT_STRUCT; |
||
116 | PACK_STRUCT_END |
||
117 | #ifdef PACK_STRUCT_USE_INCLUDES |
||
118 | # include "arch/epstruct.h" |
||
119 | #endif |
||
120 | |||
121 | /** NetBIOS message */ |
||
122 | #ifdef PACK_STRUCT_USE_INCLUDES |
||
123 | # include "arch/bpstruct.h" |
||
124 | #endif |
||
125 | PACK_STRUCT_BEGIN |
||
126 | struct netbios_resp { |
||
127 | struct netbios_hdr resp_hdr; |
||
128 | struct netbios_name_hdr resp_name; |
||
129 | } PACK_STRUCT_STRUCT; |
||
130 | PACK_STRUCT_END |
||
131 | #ifdef PACK_STRUCT_USE_INCLUDES |
||
132 | # include "arch/epstruct.h" |
||
133 | #endif |
||
134 | |||
135 | #ifdef NETBIOS_LWIP_NAME |
||
136 | #define NETBIOS_LOCAL_NAME NETBIOS_LWIP_NAME |
||
137 | #else |
||
138 | static char netbiosns_local_name[NETBIOS_NAME_LEN]; |
||
139 | #define NETBIOS_LOCAL_NAME netbiosns_local_name |
||
140 | #endif |
||
141 | |||
142 | struct udp_pcb *netbiosns_pcb; |
||
143 | |||
144 | /** Decode a NetBIOS name (from packet to string) */ |
||
145 | static int |
||
146 | netbiosns_name_decode(char *name_enc, char *name_dec, int name_dec_len) |
||
147 | { |
||
148 | char *pname; |
||
149 | char cname; |
||
150 | char cnbname; |
||
151 | int idx = 0; |
||
152 | |||
153 | LWIP_UNUSED_ARG(name_dec_len); |
||
154 | |||
155 | /* Start decoding netbios name. */ |
||
156 | pname = name_enc; |
||
157 | for (;;) { |
||
158 | /* Every two characters of the first level-encoded name |
||
159 | * turn into one character in the decoded name. */ |
||
160 | cname = *pname; |
||
161 | if (cname == '\0') { |
||
162 | break; /* no more characters */ |
||
163 | } |
||
164 | if (cname == '.') { |
||
165 | break; /* scope ID follows */ |
||
166 | } |
||
167 | if (cname < 'A' || cname > 'Z') { |
||
168 | /* Not legal. */ |
||
169 | return -1; |
||
170 | } |
||
171 | cname -= 'A'; |
||
172 | cnbname = cname << 4; |
||
173 | pname++; |
||
174 | |||
175 | cname = *pname; |
||
176 | if (cname == '\0' || cname == '.') { |
||
177 | /* No more characters in the name - but we're in |
||
178 | * the middle of a pair. Not legal. */ |
||
179 | return -1; |
||
180 | } |
||
181 | if (cname < 'A' || cname > 'Z') { |
||
182 | /* Not legal. */ |
||
183 | return -1; |
||
184 | } |
||
185 | cname -= 'A'; |
||
186 | cnbname |= cname; |
||
187 | pname++; |
||
188 | |||
189 | /* Do we have room to store the character? */ |
||
190 | if (idx < NETBIOS_NAME_LEN) { |
||
191 | /* Yes - store the character. */ |
||
192 | name_dec[idx++] = (cnbname != ' ' ? cnbname : '\0'); |
||
193 | } |
||
194 | } |
||
195 | |||
196 | return 0; |
||
197 | } |
||
198 | |||
199 | #if 0 /* function currently unused */ |
||
200 | /** Encode a NetBIOS name (from string to packet) - currently unused because |
||
201 | we don't ask for names. */ |
||
202 | static int |
||
203 | netbiosns_name_encode(char *name_enc, char *name_dec, int name_dec_len) |
||
204 | { |
||
205 | char *pname; |
||
206 | char cname; |
||
207 | unsigned char ucname; |
||
208 | int idx = 0; |
||
209 | |||
210 | /* Start encoding netbios name. */ |
||
211 | pname = name_enc; |
||
212 | |||
213 | for (;;) { |
||
214 | /* Every two characters of the first level-encoded name |
||
215 | * turn into one character in the decoded name. */ |
||
216 | cname = *pname; |
||
217 | if (cname == '\0') { |
||
218 | break; /* no more characters */ |
||
219 | } |
||
220 | if (cname == '.') { |
||
221 | break; /* scope ID follows */ |
||
222 | } |
||
223 | if ((cname < 'A' || cname > 'Z') && (cname < '0' || cname > '9')) { |
||
224 | /* Not legal. */ |
||
225 | return -1; |
||
226 | } |
||
227 | |||
228 | /* Do we have room to store the character? */ |
||
229 | if (idx >= name_dec_len) { |
||
230 | return -1; |
||
231 | } |
||
232 | |||
233 | /* Yes - store the character. */ |
||
234 | ucname = cname; |
||
235 | name_dec[idx++] = ('A' + ((ucname >> 4) & 0x0F)); |
||
236 | name_dec[idx++] = ('A' + ( ucname & 0x0F)); |
||
237 | pname++; |
||
238 | } |
||
239 | |||
240 | /* Fill with "space" coding */ |
||
241 | for (; idx < name_dec_len - 1;) { |
||
242 | name_dec[idx++] = 'C'; |
||
243 | name_dec[idx++] = 'A'; |
||
244 | } |
||
245 | |||
246 | /* Terminate string */ |
||
247 | name_dec[idx] = '\0'; |
||
248 | |||
249 | return 0; |
||
250 | } |
||
251 | #endif /* 0 */ |
||
252 | |||
253 | /** NetBIOS Name service recv callback */ |
||
254 | static void |
||
255 | netbiosns_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) |
||
256 | { |
||
257 | LWIP_UNUSED_ARG(arg); |
||
258 | |||
259 | /* if packet is valid */ |
||
260 | if (p != NULL) { |
||
261 | char netbios_name[NETBIOS_NAME_LEN + 1]; |
||
262 | struct netbios_hdr *netbios_hdr = (struct netbios_hdr *)p->payload; |
||
263 | struct netbios_name_hdr *netbios_name_hdr = (struct netbios_name_hdr *)(netbios_hdr + 1); |
||
264 | |||
265 | /* we only answer if we got a default interface */ |
||
266 | if (netif_default != NULL) { |
||
267 | /* @todo: do we need to check answerRRs/authorityRRs/additionalRRs? */ |
||
268 | /* if the packet is a NetBIOS name query question */ |
||
269 | if (((netbios_hdr->flags & PP_NTOHS(NETB_HFLAG_OPCODE)) == PP_NTOHS(NETB_HFLAG_OPCODE_NAME_QUERY)) && |
||
270 | ((netbios_hdr->flags & PP_NTOHS(NETB_HFLAG_RESPONSE)) == 0) && |
||
271 | (netbios_hdr->questions == PP_NTOHS(1))) { |
||
272 | /* decode the NetBIOS name */ |
||
273 | netbiosns_name_decode((char *)(netbios_name_hdr->encname), netbios_name, sizeof(netbios_name)); |
||
274 | /* if the packet is for us */ |
||
275 | if (lwip_strnicmp(netbios_name, NETBIOS_LOCAL_NAME, sizeof(NETBIOS_LOCAL_NAME)) == 0) { |
||
276 | struct pbuf *q; |
||
277 | struct netbios_resp *resp; |
||
278 | |||
279 | q = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct netbios_resp), PBUF_RAM); |
||
280 | if (q != NULL) { |
||
281 | resp = (struct netbios_resp *)q->payload; |
||
282 | |||
283 | /* prepare NetBIOS header response */ |
||
284 | resp->resp_hdr.trans_id = netbios_hdr->trans_id; |
||
285 | resp->resp_hdr.flags = PP_HTONS(NETB_HFLAG_RESPONSE | |
||
286 | NETB_HFLAG_OPCODE_NAME_QUERY | |
||
287 | NETB_HFLAG_AUTHORATIVE | |
||
288 | NETB_HFLAG_RECURS_DESIRED); |
||
289 | resp->resp_hdr.questions = 0; |
||
290 | resp->resp_hdr.answerRRs = PP_HTONS(1); |
||
291 | resp->resp_hdr.authorityRRs = 0; |
||
292 | resp->resp_hdr.additionalRRs = 0; |
||
293 | |||
294 | /* prepare NetBIOS header datas */ |
||
295 | MEMCPY( resp->resp_name.encname, netbios_name_hdr->encname, sizeof(netbios_name_hdr->encname)); |
||
296 | resp->resp_name.nametype = netbios_name_hdr->nametype; |
||
297 | resp->resp_name.type = netbios_name_hdr->type; |
||
298 | resp->resp_name.cls = netbios_name_hdr->cls; |
||
299 | resp->resp_name.ttl = PP_HTONL(NETBIOS_NAME_TTL); |
||
300 | resp->resp_name.datalen = PP_HTONS(sizeof(resp->resp_name.flags) + sizeof(resp->resp_name.addr)); |
||
301 | resp->resp_name.flags = PP_HTONS(NETB_NFLAG_NODETYPE_BNODE); |
||
302 | ip4_addr_copy(resp->resp_name.addr, *netif_ip4_addr(netif_default)); |
||
303 | |||
304 | /* send the NetBIOS response */ |
||
305 | udp_sendto(upcb, q, addr, port); |
||
306 | |||
307 | /* free the "reference" pbuf */ |
||
308 | pbuf_free(q); |
||
309 | } |
||
310 | } |
||
311 | } |
||
312 | } |
||
313 | /* free the pbuf */ |
||
314 | pbuf_free(p); |
||
315 | } |
||
316 | } |
||
317 | |||
318 | /** |
||
319 | * @ingroup netbiosns |
||
320 | * Init netbios responder |
||
321 | */ |
||
322 | void |
||
323 | netbiosns_init(void) |
||
324 | { |
||
325 | #ifdef NETBIOS_LWIP_NAME |
||
326 | LWIP_ASSERT("NetBIOS name is too long!", strlen(NETBIOS_LWIP_NAME) < NETBIOS_NAME_LEN); |
||
327 | #endif |
||
328 | |||
329 | netbiosns_pcb = udp_new_ip_type(IPADDR_TYPE_ANY); |
||
330 | if (netbiosns_pcb != NULL) { |
||
331 | /* we have to be allowed to send broadcast packets! */ |
||
332 | ip_set_option(netbiosns_pcb, SOF_BROADCAST); |
||
333 | udp_bind(netbiosns_pcb, IP_ANY_TYPE, LWIP_IANA_PORT_NETBIOS); |
||
334 | udp_recv(netbiosns_pcb, netbiosns_recv, netbiosns_pcb); |
||
335 | } |
||
336 | } |
||
337 | |||
338 | #ifndef NETBIOS_LWIP_NAME |
||
339 | /** |
||
340 | * @ingroup netbiosns |
||
341 | * Set netbios name. ATTENTION: the hostname must be less than 15 characters! |
||
342 | */ |
||
343 | void |
||
344 | netbiosns_set_name(const char *hostname) |
||
345 | { |
||
346 | size_t copy_len = strlen(hostname); |
||
347 | LWIP_ASSERT("NetBIOS name is too long!", copy_len < NETBIOS_NAME_LEN); |
||
348 | if (copy_len >= NETBIOS_NAME_LEN) { |
||
349 | copy_len = NETBIOS_NAME_LEN - 1; |
||
350 | } |
||
351 | MEMCPY(netbiosns_local_name, hostname, copy_len + 1); |
||
352 | } |
||
353 | #endif |
||
354 | |||
355 | /** |
||
356 | * @ingroup netbiosns |
||
357 | * Stop netbios responder |
||
358 | */ |
||
359 | void |
||
360 | netbiosns_stop(void) |
||
361 | { |
||
362 | if (netbiosns_pcb != NULL) { |
||
363 | udp_remove(netbiosns_pcb); |
||
364 | netbiosns_pcb = NULL; |
||
365 | } |
||
366 | } |
||
367 | |||
368 | #endif /* LWIP_IPV4 && LWIP_UDP */ |