embkernel
 All Classes Functions Variables Typedefs Groups Pages
NetClientDns.cpp
1 //------------------------------------------------------------------------------
2 //This file is part of embKernel.
3 //See license.txt for the full license governing this code.
4 //------------------------------------------------------------------------------
5 
6 #include "Net.hpp"
7 #include "NetClientDns.hpp"
8 #include "LibEndian.hpp"
9 #include "RtosInclude.hpp"
10 #include "LibStreamOutArray.hpp"
11 
12 NetUdpSocket NetClientDns::sSocket;
13 RtosSemaphore NetClientDns::sSema(1, 1);
14 
15 bool NetClientDns::resolve(const char* name, NetDefs::IP_ADDR* ipAddr) {
16  sSema.take(Rtos::TICK_INFINITE);
17  sSocket.open();
18 
19  NetUdpSocket::TX_PACKET* txPkt = sSocket.allocTxPacket(512);
20  if (txPkt == 0) {
21  sSema.give(Rtos::TICK_INFINITE);
22  return false;
23  }
24 
25  uint16_t id = Rtos::getTick();
26 
27  { //Send request
28  NetDefs::DNS_PKT* dnsPkt = (NetDefs::DNS_PKT*) txPkt->data;
29 
30  dnsPkt->hdr.id = id;
31  dnsPkt->hdr.flags.value = 0;
32  dnsPkt->hdr.flags.bits.qr = true;
33  dnsPkt->hdr.questionCount = 1;
34  dnsPkt->hdr.answerRecordCount = 0;
35  dnsPkt->hdr.authorityRecordCount = 0;
36  dnsPkt->hdr.additionalRecordCount = 0;
37  swapHeader(&dnsPkt->hdr);
38 
39  bool loop = true;
40  LibStreamOutArray stream(dnsPkt->data, 512 - sizeof(dnsPkt->hdr));
41  for (int i = 0; loop;) {
42  int next = i;
43  while (true) {
44  char c = name[next++];
45  if (c == '.') {
46  break;
47  }
48  else if (c == 0) {
49  loop = false;
50  break;
51  }
52  else if (next >= 64) {
53  loop = false;
54  break;
55  }
56  }
57  uint8_t len = (next - i) - 1;
58  stream.write(&len, 1);
59  stream.write((uint8_t*) &name[i], len);
60  i = next;
61  }
62 
63  uint8_t trail[] = {
64  0x00, 0x00, 0x01, 0x00, 0x01 };
65  stream.write(trail, sizeof(trail));
66 
67  txPkt->hdr.port = 53;
68  txPkt->hdr.ip = Net::getConfig().dnsIpAddr;
69  sSocket.sendPacket(*txPkt, sizeof(dnsPkt->hdr) + stream.getPosition());
70  }
71 
72  bool result = false;
73  { //Recv Reply
74  NetUdpSocket::RX_PACKET* rxPkt = sSocket.recvPacket(Rtos::convertMsToTick(5000));
75 
76  if (rxPkt != 0) {
77  NetDefs::DNS_PKT* dnsPkt = (NetDefs::DNS_PKT*) rxPkt->data;
78  swapHeader(&dnsPkt->hdr);
79  if (dnsPkt->hdr.id == id && dnsPkt->hdr.answerRecordCount > 0 && dnsPkt->hdr.flags.bits.qr /*&& (dnsPkt->hdr.flags.bits.rcode == 0)*/) {
80 
81  int i = 0;
82  bool exit = false;
83  for (int count = 0; count < dnsPkt->hdr.questionCount; count++) {
84  if (dnsPkt->data[i] < 64) {
85  while (dnsPkt->data[i++] != 0) {
86  }
87  i += 4;
88  }
89  else if (dnsPkt->data[i] >= 192) {
90  i += 6;
91  }
92  else {
93  exit = true;
94  break;
95  }
96  }
97 
98  //Iterate through responses
99  for (int count = 0; !exit && count < dnsPkt->hdr.answerRecordCount; count++) {
100  if (dnsPkt->data[i] < 64) {
101  while (dnsPkt->data[i++] != 0) {
102  }
103  }
104  else if (dnsPkt->data[i] >= 192) {
105  i += 2;
106  }
107  else {
108  exit = true;
109  break;
110  }
111 
112  if ((dnsPkt->data[i] == 0) && (dnsPkt->data[i + 1] == 1) && //Type == Type A
113  (dnsPkt->data[i + 2] == 0) && (dnsPkt->data[i + 3] == 1) && //Class = IN
114  (dnsPkt->data[i + 8] == 0) && (dnsPkt->data[i + 9] == 4)) { //Rdata len == 4
115  memcpy(ipAddr, &dnsPkt->data[i + 10], 4);
116  exit = true;
117  result = true;
118  break;
119  }
120  else {
121  //Skip type, class, TTL, Rdata len, Rdata
122  i += 10 + (uint16_t) dnsPkt->data[i + 8] + (uint16_t) dnsPkt->data[i + 9];
123  }
124  }
125  }
126  sSocket.discardRxPacket(rxPkt);
127  }
128  }
129 
130  sSocket.close();
131  sSema.give(Rtos::TICK_INFINITE);
132 
133  return result;
134 }
135 
136 void NetClientDns::swapHeader(NetDefs::DNS_HEADER* header) {
137  header->id = LibEndian::hwToBe(header->id);
138  header->questionCount = LibEndian::hwToBe(header->questionCount);
139  header->answerRecordCount = LibEndian::hwToBe(header->answerRecordCount);
140  header->authorityRecordCount = LibEndian::hwToBe(header->authorityRecordCount);
141  header->additionalRecordCount = LibEndian::hwToBe(header->additionalRecordCount);
142 }