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-2024 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.4.0
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 
54 void nbnsProcessQuery(NetInterface *interface, const Ipv4PseudoHeader *pseudoHeader,
55  const UdpHeader *udpHeader, const NbnsHeader *message, size_t length)
56 {
57  size_t pos;
58  DnsQuestion *question;
59 
60  //The NBNS query shall contain one question
61  if(ntohs(message->qdcount) != 1)
62  return;
63 
64  //Parse NetBIOS name
65  pos = nbnsParseName(message, length, sizeof(DnsHeader), NULL);
66 
67  //Invalid name?
68  if(!pos)
69  return;
70  //Malformed NBNS query message?
71  if((pos + sizeof(DnsQuestion)) > length)
72  return;
73 
74  //Point to the corresponding entry
75  question = DNS_GET_QUESTION(message, pos);
76 
77  //Check the class and the type of the request
78  if(ntohs(question->qclass) != DNS_RR_CLASS_IN)
79  return;
80  if(ntohs(question->qtype) != DNS_RR_TYPE_NB)
81  return;
82 
83  //Compare NetBIOS names
84  if(nbnsCompareName(message, length, sizeof(DnsHeader), interface->hostname))
85  {
86  uint16_t destPort;
88 
89  //A response packet is always sent to the source UDP port and source IP
90  //address of the request packet
91  destIpAddr.length = sizeof(Ipv4Addr);
92  destIpAddr.ipv4Addr = pseudoHeader->srcAddr;
93 
94  //Convert the port number to host byte order
95  destPort = ntohs(udpHeader->srcPort);
96 
97  //Send NBNS response
98  nbnsSendResponse(interface, &destIpAddr, destPort, message->id);
99  }
100 }
101 
102 
103 /**
104  * @brief Send NBNS response message
105  * @param[in] interface Underlying network interface
106  * @param[in] destIpAddr Destination IP address
107  * @param[in] destPort destination port
108  * @param[in] id 16-bit identifier to be used when sending NBNS query
109  **/
110 
112  const IpAddr *destIpAddr, uint16_t destPort, uint16_t id)
113 {
114  error_t error;
115  uint_t i;
116  size_t length;
117  size_t offset;
118  NetBuffer *buffer;
120  NbnsAddrEntry *addrEntry;
121  DnsResourceRecord *record;
122  Ipv4AddrEntry *entry;
123  NetTxAncillary ancillary;
124 
125  //Initialize status code
126  error = NO_ERROR;
127 
128  //Allocate a memory buffer to hold the NBNS response message
129  buffer = udpAllocBuffer(DNS_MESSAGE_MAX_SIZE, &offset);
130  //Failed to allocate buffer?
131  if(buffer == NULL)
132  return ERROR_OUT_OF_MEMORY;
133 
134  //Point to the NBNS header
135  message = netBufferAt(buffer, offset);
136 
137  //Take the identifier from the query message
138  message->id = id;
139 
140  //Format NBNS response header
141  message->qr = 1;
142  message->opcode = DNS_OPCODE_QUERY;
143  message->aa = 1;
144  message->tc = 0;
145  message->rd = 1;
146  message->ra = 1;
147  message->z = 0;
148  message->b = 0;
149  message->rcode = DNS_RCODE_NOERROR;
150  message->qdcount = 0;
151  message->ancount = 0;
152  message->nscount = 0;
153  message->arcount = 0;
154 
155  //NBNS response message length
156  length = sizeof(DnsHeader);
157 
158  //The NBNS response contains 1 answer resource record
159  for(i = 0; i < IPV4_ADDR_LIST_SIZE && message->ancount == 0; i++)
160  {
161  //Point to the current entry
162  entry = &interface->ipv4Context.addrList[i];
163 
164  //Check the state of the address
165  if(entry->state == IPV4_ADDR_STATE_VALID)
166  {
167  //Check whether the address belongs to the same subnet as the source
168  //address of the query
169  if(ipv4IsOnSubnet(entry, destIpAddr->ipv4Addr))
170  {
171  //Encode the host name using the NBNS name notation
172  length += nbnsEncodeName(interface->hostname,
173  (uint8_t *) message + length);
174 
175  //Point to the corresponding resource record
177 
178  //Fill in resource record
179  record->rtype = HTONS(DNS_RR_TYPE_NB);
180  record->rclass = HTONS(DNS_RR_CLASS_IN);
182  record->rdlength = HTONS(sizeof(NbnsAddrEntry));
183 
184  //Point to the address entry array
185  addrEntry = (NbnsAddrEntry *) record->rdata;
186 
187  //Fill in address entry
188  addrEntry->flags = HTONS(NBNS_G_UNIQUE | NBNS_ONT_BNODE);
189  addrEntry->addr = entry->addr;
190 
191  //Update the length of the NBNS response message
192  length += sizeof(DnsResourceRecord) + sizeof(NbnsAddrEntry);
193 
194  //Number of resource records in the answer section
195  message->ancount++;
196  }
197  }
198  }
199 
200  //Valid NBNS response?
201  if(message->ancount > 0)
202  {
203  //The ANCOUNT field specifies the number of resource records in the
204  //answer section
205  message->ancount = htons(message->ancount);
206 
207  //Adjust the length of the multi-part buffer
208  netBufferSetLength(buffer, offset + length);
209 
210  //Debug message
211  TRACE_INFO("Sending NBNS message (%" PRIuSIZE " bytes)...\r\n", length);
212  //Dump message
214 
215  //Additional options can be passed to the stack along with the packet
216  ancillary = NET_DEFAULT_TX_ANCILLARY;
217 
218  //This flag tells the stack that the destination is on a locally attached
219  //network and not to perform a lookup of the routing table
220  ancillary.dontRoute = TRUE;
221 
222  //A response packet is always sent to the source UDP port and source IP
223  //address of the request packet
224  error = udpSendBuffer(interface, NULL, NBNS_PORT, destIpAddr, destPort,
225  buffer, offset, &ancillary);
226  }
227 
228  //Free previously allocated memory
229  netBufferFree(buffer);
230 
231  //Return status code
232  return error;
233 }
234 
235 #endif
uint8_t message[]
Definition: chap.h:154
unsigned int uint_t
Definition: compiler_port.h:50
#define PRIuSIZE
#define HTONS(value)
Definition: cpu_endian.h:410
#define htons(value)
Definition: cpu_endian.h:413
#define ntohs(value)
Definition: cpu_endian.h:421
#define HTONL(value)
Definition: cpu_endian.h:411
Debugging facilities.
#define TRACE_INFO(...)
Definition: debug.h:95
DnsHeader
Definition: dns_common.h:199
#define DNS_GET_RESOURCE_RECORD(message, offset)
Definition: dns_common.h:64
DnsResourceRecord
Definition: dns_common.h:224
#define DNS_GET_QUESTION(message, offset)
Definition: dns_common.h:63
@ DNS_RCODE_NOERROR
No error.
Definition: dns_common.h:95
#define DNS_MESSAGE_MAX_SIZE
Definition: dns_common.h:45
@ DNS_OPCODE_QUERY
Query.
Definition: dns_common.h:81
@ DNS_RR_TYPE_NB
NetBIOS name service.
Definition: dns_common.h:148
@ DNS_RR_CLASS_IN
Internet.
Definition: dns_common.h:124
DnsQuestion
Definition: dns_common.h:210
void dnsDumpMessage(const DnsHeader *message, size_t length)
Dump DNS message for debugging purpose.
Definition: dns_debug.c:52
Data logging functions for debugging purpose (DNS)
error_t
Error codes.
Definition: error.h:43
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
Ipv4Addr destIpAddr
Definition: ipcp.h:80
#define Ipv4PseudoHeader
Definition: ipv4.h:39
#define IPV4_ADDR_LIST_SIZE
Definition: ipv4.h:69
uint32_t Ipv4Addr
IPv4 network address.
Definition: ipv4.h:267
@ IPV4_ADDR_STATE_VALID
An address assigned to an interface whose use is unrestricted.
Definition: ipv4.h:197
#define ipv4IsOnSubnet(entry, ipAddr)
Definition: ipv4.h:156
size_t nbnsEncodeName(const char_t *src, uint8_t *dest)
Encode a NetBIOS name.
Definition: nbns_common.c:150
size_t nbnsParseName(const NbnsHeader *message, size_t length, size_t pos, char_t *dest)
Decode a NetBIOS name.
Definition: nbns_common.c:202
bool_t nbnsCompareName(const NbnsHeader *message, size_t length, size_t pos, const char_t *name)
Compare NetBIOS names.
Definition: nbns_common.c:286
Definitions common to NBNS client and NBNS responder.
NbnsAddrEntry
Definition: nbns_common.h:124
@ NBNS_ONT_BNODE
Definition: nbns_common.h:64
@ NBNS_G_UNIQUE
Definition: nbns_common.h:67
#define NBNS_DEFAULT_RESOURCE_RECORD_TTL
Definition: nbns_common.h:40
NbnsHeader
Definition: nbns_common.h:113
#define NBNS_PORT
Definition: nbns_common.h:46
error_t nbnsSendResponse(NetInterface *interface, const IpAddr *destIpAddr, uint16_t destPort, uint16_t id)
Send NBNS response message.
void nbnsProcessQuery(NetInterface *interface, const Ipv4PseudoHeader *pseudoHeader, const UdpHeader *udpHeader, const NbnsHeader *message, size_t length)
Process NBNS query message.
NBNS responder (NetBIOS Name Service)
TCP/IP stack core.
#define NetInterface
Definition: net.h:36
void * netBufferAt(const NetBuffer *buffer, size_t offset)
Returns a pointer to the data at the specified position.
Definition: net_mem.c:415
void netBufferFree(NetBuffer *buffer)
Dispose a multi-part buffer.
Definition: net_mem.c:282
error_t netBufferSetLength(NetBuffer *buffer, size_t length)
Adjust the length of a multi-part buffer.
Definition: net_mem.c:322
const NetTxAncillary NET_DEFAULT_TX_ANCILLARY
Definition: net_misc.c:71
#define NetTxAncillary
Definition: net_misc.h:36
#define TRUE
Definition: os_port.h:50
IP network address.
Definition: ip.h:79
IPv4 address entry.
Definition: ipv4.h:343
Ipv4AddrState state
IPv4 address state.
Definition: ipv4.h:345
Ipv4Addr addr
IPv4 address.
Definition: ipv4.h:344
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
uint8_t length
Definition: tcp.h:368
uint16_t destPort
Definition: tcp.h:340
NetBuffer * udpAllocBuffer(size_t length, size_t *offset)
Allocate a buffer to hold a UDP packet.
Definition: udp.c:905
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:627
UdpHeader
Definition: udp.h:85