nbns_responder.c
Go to the documentation of this file.
1 /**
2  * @file nbns_responder.c
3  * @brief NBNS responder (NetBIOS Name Service)
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2025 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.5.4
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL NBNS_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/net.h"
36 #include "netbios/nbns_responder.h"
37 #include "netbios/nbns_common.h"
38 #include "dns/dns_debug.h"
39 #include "debug.h"
40 
41 //Check TCP/IP stack configuration
42 #if (NBNS_RESPONDER_SUPPORT == ENABLED && IPV4_SUPPORT == ENABLED)
43 
44 
45 /**
46  * @brief Process NBNS query message
47  * @param[in] interface Underlying network interface
48  * @param[in] pseudoHeader UDP pseudo header
49  * @param[in] udpHeader UDP header
50  * @param[in] message Pointer to the NBNS query message
51  * @param[in] length Length of the message
52  **/
53 
55  const Ipv4PseudoHeader *pseudoHeader, const UdpHeader *udpHeader,
56  const NbnsHeader *message, size_t length)
57 {
58  size_t pos;
59  uint16_t destPort;
61  DnsQuestion *question;
62 
63  //The NBNS query shall contain one question
64  if(ntohs(message->qdcount) != 1)
65  return;
66 
67  //Parse NetBIOS name
68  pos = nbnsParseName(message, length, sizeof(DnsHeader), NULL);
69 
70  //Invalid name?
71  if(!pos)
72  return;
73  //Malformed NBNS query message?
74  if((pos + sizeof(DnsQuestion)) > length)
75  return;
76 
77  //Point to the corresponding entry
78  question = DNS_GET_QUESTION(message, pos);
79 
80  //Check the class of the request
81  if(ntohs(question->qclass) != DNS_RR_CLASS_IN)
82  return;
83 
84  //A response packet is always sent to the source UDP port and source IP
85  //address of the request packet
86  destIpAddr.length = sizeof(Ipv4Addr);
87  destIpAddr.ipv4Addr = pseudoHeader->srcAddr;
88 
89  //Convert the port number to host byte order
90  destPort = ntohs(udpHeader->srcPort);
91 
92  //Check the type of the request
93  if(ntohs(question->qtype) == DNS_RR_TYPE_NB)
94  {
95  //Compare NetBIOS names
97  interface->hostname))
98  {
99  //Send positive name query response
100  nbnsSendResponse(interface, &destIpAddr, destPort, message->id,
102  }
103  }
104  else if(ntohs(question->qtype) == DNS_RR_TYPE_NBSTAT)
105  {
106  //Send node status response
107  nbnsSendResponse(interface, &destIpAddr, destPort, message->id,
109  }
110  else
111  {
112  //Unknown request
113  }
114 }
115 
116 
117 /**
118  * @brief Send NBNS response message
119  * @param[in] interface Underlying network interface
120  * @param[in] destIpAddr Destination IP address
121  * @param[in] destPort destination port
122  * @param[in] id 16-bit identifier to be used when sending NBNS query
123  * @param[in] qtype Resource record type
124  **/
125 
127  uint16_t destPort, uint16_t id, uint16_t qtype)
128 {
129  error_t error;
130  size_t length;
131  size_t offset;
132  NetBuffer *buffer;
134  DnsResourceRecord *record;
135  NetTxAncillary ancillary;
136 
137  //Initialize status code
138  error = NO_ERROR;
139 
140  //Allocate a memory buffer to hold the NBNS response message
141  buffer = udpAllocBuffer(DNS_MESSAGE_MAX_SIZE, &offset);
142  //Failed to allocate buffer?
143  if(buffer == NULL)
144  return ERROR_OUT_OF_MEMORY;
145 
146  //Point to the NBNS header
147  message = netBufferAt(buffer, offset, 0);
148 
149  //Take the identifier from the query message
150  message->id = id;
151 
152  //Format NBNS response header
153  message->qr = 1;
154  message->opcode = DNS_OPCODE_QUERY;
155  message->aa = 1;
156  message->tc = 0;
157  message->rd = 0;
158  message->ra = 0;
159  message->z = 0;
160  message->b = 0;
161  message->rcode = DNS_RCODE_NOERROR;
162  message->qdcount = 0;
163  message->ancount = 0;
164  message->nscount = 0;
165  message->arcount = 0;
166 
167  //NBNS response message length
168  length = sizeof(DnsHeader);
169 
170  //Check the type of the requested resource record
171  if(qtype == DNS_RR_TYPE_NB)
172  {
173  uint_t i;
174  Ipv4AddrEntry *entry;
175  NbnsAddrEntry *addrEntry;
176 
177  //Set RD and RA flags
178  message->rd = 1;
179  message->ra = 1;
180 
181  //Loop through the list of IPv4 addresses assigned to the interface
182  for(i = 0; i < IPV4_ADDR_LIST_SIZE && message->ancount == 0; i++)
183  {
184  //Point to the current entry
185  entry = &interface->ipv4Context.addrList[i];
186 
187  //Check the state of the address
188  if(entry->state == IPV4_ADDR_STATE_VALID)
189  {
190  //Check whether the address belongs to the same subnet as the source
191  //address of the query
192  if(ipv4IsOnSubnet(entry, destIpAddr->ipv4Addr))
193  {
194  //Encode the host name using the NBNS name notation
195  length += nbnsEncodeName(interface->hostname,
196  (uint8_t *) message + length);
197 
198  //Point to the corresponding resource record
200 
201  //Fill in resource record
202  record->rtype = HTONS(DNS_RR_TYPE_NB);
203  record->rclass = HTONS(DNS_RR_CLASS_IN);
205  record->rdlength = HTONS(sizeof(NbnsAddrEntry));
206 
207  //The ADDR_ENTRY ARRAY a sequence of zero or more ADDR_ENTRY
208  //records (refer to RFC 1002, section 4.2.13)
209  addrEntry = (NbnsAddrEntry *) record->rdata;
210 
211  //Each ADDR_ENTRY record represents an owner of a name
212  addrEntry->flags = HTONS(NBNS_FLAG_ONT_BNODE);
213  addrEntry->addr = entry->addr;
214 
215  //Update the length of the NBNS response message
216  length += sizeof(DnsResourceRecord) + sizeof(NbnsAddrEntry);
217 
218  //Number of resource records in the answer section
219  message->ancount++;
220  }
221  }
222  }
223  }
224  else if(qtype == DNS_RR_TYPE_NBSTAT)
225  {
226  size_t i;
227  size_t n;
228  NbnsNodeNameArray *nodeNameArray;
229  NbnsStatistics *statistics;
230 
231  //Determine the length of the host name
232  n = osStrlen(interface->hostname);
233 
234  //Valid host name assigned to the interface?
235  if(n >= 1 && n <= 15)
236  {
237  //RR_NAME is the requesting name
238  length += nbnsEncodeName("*", (uint8_t *) message + length);
239 
240  //Point to the corresponding resource record
242 
243  //Fill in resource record
244  record->rtype = HTONS(DNS_RR_TYPE_NBSTAT);
245  record->rclass = HTONS(DNS_RR_CLASS_IN);
246  record->ttl = HTONL(0);
247 
248  //Calculate the length of the resource record
249  record->rdlength = HTONS(sizeof(NbnsNodeNameArray) +
250  sizeof(NbnsNodeNameEntry) + sizeof(NbnsStatistics));
251 
252  //The NODE_NAME ARRAY is an array of zero or more NUM_NAMES entries
253  //of NODE_NAME records (refer to RFC 1002, section 4.2.18)
254  nodeNameArray = (NbnsNodeNameArray *) record->rdata;
255 
256  //Set NUM_NAMES field
257  nodeNameArray->numNames = 1;
258 
259  //Each NODE_NAME entry represents an active name in the same NetBIOS
260  //scope as the requesting name in the local name table of the responder
261  for(i = 0; i < n; i++)
262  {
263  nodeNameArray->names[0].name[i] = osToupper(interface->hostname[i]);
264  }
265 
266  //Pad NetBIOS name with space characters
267  for(; i < 15; i++)
268  {
269  nodeNameArray->names[0].name[i] = ' ';
270  }
271 
272  //The 16th character is the NetBIOS suffix
273  nodeNameArray->names[0].name[15] = 0;
274 
275  //Set NAME_FLAGS field
276  nodeNameArray->names[0].flags = HTONS(NBNS_NAME_FLAG_ONT_BNODE |
278 
279  //Point to the STATISTICS field
280  statistics = (NbnsStatistics *) (record->rdata +
281  sizeof(NbnsNodeNameArray) + sizeof(NbnsNodeNameEntry));
282 
283  //Clear statistics
284  osMemset(statistics, 0, sizeof(NbnsStatistics));
285  //The UNIT_ID field specifies the unique unit ID
286  statistics->unitId = interface->macAddr;
287 
288  //Update the length of the NBNS response message
289  length += sizeof(DnsResourceRecord) + sizeof(NbnsNodeNameArray) +
290  sizeof(NbnsNodeNameEntry) + sizeof(NbnsStatistics);
291 
292  //Number of resource records in the answer section
293  message->ancount++;
294  }
295  }
296  else
297  {
298  //Just for sanity
299  }
300 
301  //Valid NBNS response?
302  if(message->ancount > 0)
303  {
304  //The ANCOUNT field specifies the number of resource records in the
305  //answer section
306  message->ancount = htons(message->ancount);
307 
308  //Adjust the length of the multi-part buffer
309  netBufferSetLength(buffer, offset + length);
310 
311  //Debug message
312  TRACE_INFO("Sending NBNS message (%" PRIuSIZE " bytes)...\r\n", length);
313  //Dump message
315 
316  //Additional options can be passed to the stack along with the packet
317  ancillary = NET_DEFAULT_TX_ANCILLARY;
318 
319  //This flag tells the stack that the destination is on a locally attached
320  //network and not to perform a lookup of the routing table
321  ancillary.dontRoute = TRUE;
322 
323  //A response packet is always sent to the source UDP port and source IP
324  //address of the request packet
325  error = udpSendBuffer(interface, NULL, NBNS_PORT, destIpAddr, destPort,
326  buffer, offset, &ancillary);
327  }
328 
329  //Free previously allocated memory
330  netBufferFree(buffer);
331 
332  //Return status code
333  return error;
334 }
335 
336 #endif
void nbnsProcessQuery(NetInterface *interface, const Ipv4PseudoHeader *pseudoHeader, const UdpHeader *udpHeader, const NbnsHeader *message, size_t length)
Process NBNS query message.
#define htons(value)
Definition: cpu_endian.h:413
Ipv4Addr addr
IPv4 address.
Definition: ipv4.h:387
NbnsNodeNameArray
Definition: nbns_common.h:164
const NetTxAncillary NET_DEFAULT_TX_ANCILLARY
Definition: net_misc.c:72
size_t nbnsParseName(const NbnsHeader *message, size_t length, size_t pos, char_t *dest)
Decode a NetBIOS name.
Definition: nbns_common.c:222
error_t nbnsSendResponse(NetInterface *interface, const IpAddr *destIpAddr, uint16_t destPort, uint16_t id, uint16_t qtype)
Send NBNS response message.
IP network address.
Definition: ip.h:90
@ DNS_OPCODE_QUERY
Query.
Definition: dns_common.h:81
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
uint8_t message[]
Definition: chap.h:154
#define TRUE
Definition: os_port.h:50
NbnsAddrEntry
Definition: nbns_common.h:142
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
#define ipv4IsOnSubnet(entry, ipAddr)
Definition: ipv4.h:163
Ipv4AddrState state
IPv4 address state.
Definition: ipv4.h:388
@ DNS_RR_CLASS_IN
Internet.
Definition: dns_common.h:124
DnsHeader
Definition: dns_common.h:202
uint16_t destPort
Definition: tcp.h:347
NbnsNodeNameEntry
Definition: nbns_common.h:153
#define osStrlen(s)
Definition: os_port.h:168
#define NBNS_PORT
Definition: nbns_common.h:46
uint32_t Ipv4Addr
IPv4 network address.
Definition: ipv4.h:298
@ DNS_RCODE_NOERROR
No error.
Definition: dns_common.h:95
@ NBNS_FLAG_ONT_BNODE
Owner node type (B node)
Definition: nbns_common.h:65
@ DNS_RR_TYPE_NBSTAT
NetBIOS node status.
Definition: dns_common.h:149
#define osToupper(c)
Definition: os_port.h:276
NbnsHeader
Definition: nbns_common.h:131
@ DNS_RR_TYPE_NB
NetBIOS name.
Definition: dns_common.h:148
#define HTONL(value)
Definition: cpu_endian.h:411
error_t
Error codes.
Definition: error.h:43
#define DNS_GET_QUESTION(message, offset)
Definition: dns_common.h:63
@ NBNS_NAME_FLAG_ACT
Active name flag.
Definition: nbns_common.h:79
#define DNS_GET_RESOURCE_RECORD(message, offset)
Definition: dns_common.h:64
Definitions common to NBNS client and NBNS responder.
#define NetInterface
Definition: net.h:36
void netBufferFree(NetBuffer *buffer)
Dispose a multi-part buffer.
Definition: net_mem.c:282
error_t udpSendBuffer(NetInterface *interface, const IpAddr *srcIpAddr, uint16_t srcPort, const IpAddr *destIpAddr, uint16_t destPort, NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send a UDP datagram.
Definition: udp.c:658
#define NetTxAncillary
Definition: net_misc.h:36
#define Ipv4PseudoHeader
Definition: ipv4.h:39
#define TRACE_INFO(...)
Definition: debug.h:105
#define IPV4_ADDR_LIST_SIZE
Definition: ipv4.h:69
uint8_t length
Definition: tcp.h:375
void dnsDumpMessage(const DnsHeader *message, size_t length)
Dump DNS message for debugging purpose.
Definition: dns_debug.c:52
NetBuffer * udpAllocBuffer(size_t length, size_t *offset)
Allocate a buffer to hold a UDP packet.
Definition: udp.c:948
IPv4 address entry.
Definition: ipv4.h:386
UdpHeader
Definition: udp.h:85
size_t nbnsEncodeName(const char_t *src, uint8_t *dest)
Encode a NetBIOS name.
Definition: nbns_common.c:148
#define ntohs(value)
Definition: cpu_endian.h:421
#define NBNS_DEFAULT_RESOURCE_RECORD_TTL
Definition: nbns_common.h:40
#define HTONS(value)
Definition: cpu_endian.h:410
uint8_t n
NbnsStatistics
Definition: nbns_common.h:193
#define DNS_MESSAGE_MAX_SIZE
Definition: dns_common.h:45
error_t netBufferSetLength(NetBuffer *buffer, size_t length)
Adjust the length of a multi-part buffer.
Definition: net_mem.c:322
DnsQuestion
Definition: dns_common.h:213
void * netBufferAt(const NetBuffer *buffer, size_t offset, size_t length)
Returns a pointer to a data segment.
Definition: net_mem.c:418
@ IPV4_ADDR_STATE_VALID
An address assigned to an interface whose use is unrestricted.
Definition: ipv4.h:204
#define PRIuSIZE
unsigned int uint_t
Definition: compiler_port.h:57
#define osMemset(p, value, length)
Definition: os_port.h:138
TCP/IP stack core.
DnsResourceRecord
Definition: dns_common.h:227
@ NBNS_NAME_FLAG_ONT_BNODE
Owner node type (B node)
Definition: nbns_common.h:83
Data logging functions for debugging purpose (DNS)
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
NBNS responder (NetBIOS Name Service)
bool_t nbnsCompareName(const NbnsHeader *message, size_t length, size_t pos, const char_t *name)
Compare NetBIOS names.
Definition: nbns_common.c:316
Ipv4Addr destIpAddr
Definition: ipcp.h:80