Details | Last modification | View Log | SVN | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 363 | johboh | 1 | /********************************************************************* |
| 2 | * |
||
| 3 | * DNS Client Module for Microchip TCP/IP Stack |
||
| 4 | * -Provides DNS resolution (client) |
||
| 5 | * |
||
| 6 | ********************************************************************* |
||
| 7 | * FileName: DNS.c |
||
| 8 | * Dependencies: UDP, ARP, Tick |
||
| 9 | * Processor: PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F |
||
| 10 | * Complier: Microchip C18 v3.02 or higher |
||
| 11 | * Microchip C30 v2.01 or higher |
||
| 12 | * Company: Microchip Technology, Inc. |
||
| 13 | * |
||
| 14 | * Software License Agreement |
||
| 15 | * |
||
| 16 | * This software is owned by Microchip Technology Inc. ("Microchip") |
||
| 17 | * and is supplied to you for use exclusively as described in the |
||
| 18 | * associated software agreement. This software is protected by |
||
| 19 | * software and other intellectual property laws. Any use in |
||
| 20 | * violation of the software license may subject the user to criminal |
||
| 21 | * sanctions as well as civil liability. Copyright 2006 Microchip |
||
| 22 | * Technology Inc. All rights reserved. |
||
| 23 | * |
||
| 24 | * This software is provided "AS IS." MICROCHIP DISCLAIMS ALL |
||
| 25 | * WARRANTIES, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, NOT LIMITED |
||
| 26 | * TO MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND |
||
| 27 | * INFRINGEMENT. Microchip shall in no event be liable for special, |
||
| 28 | * incidental, or consequential damages. |
||
| 29 | * |
||
| 30 | * |
||
| 31 | * Author Date Comment |
||
| 32 | *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
||
| 33 | * Howard Schlunder 7/31/06 Original |
||
| 34 | ********************************************************************/ |
||
| 35 | #define THIS_IS_DNS |
||
| 36 | |||
| 37 | #include "..\Include\Compiler.h" |
||
| 38 | #include "..\Include\UDP.h" |
||
| 39 | #include "..\Include\Tick.h" |
||
| 40 | #include "..\Include\ARP.h" |
||
| 41 | #include "..\Include\ARPTsk.h" |
||
| 42 | #include "..\Include\DNS.h" |
||
| 43 | #include "..\Include\Helpers.h" |
||
| 44 | |||
| 45 | #if defined(STACK_USE_DNS) |
||
| 46 | |||
| 47 | #define DNS_PORT 53 |
||
| 48 | #define DNS_TIMEOUT (TICK_1S*2) |
||
| 49 | |||
| 50 | |||
| 51 | static BYTE *DNSHostName; |
||
| 52 | static enum |
||
| 53 | { |
||
| 54 | DNS_HOME = 0, |
||
| 55 | DNS_RESOLVE_ARP, |
||
| 56 | DNS_OPEN_SOCKET, |
||
| 57 | DNS_QUERY, |
||
| 58 | DNS_GET_RESULT, |
||
| 59 | DNS_DONE |
||
| 60 | } smDNS = DNS_DONE; |
||
| 61 | |||
| 62 | typedef struct _DNS_HEADER |
||
| 63 | { |
||
| 64 | WORD_VAL TransactionID; |
||
| 65 | WORD_VAL Flags; |
||
| 66 | WORD_VAL Questions; |
||
| 67 | WORD_VAL Answers; |
||
| 68 | WORD_VAL AuthoritativeRecords; |
||
| 69 | WORD_VAL AdditionalRecords; |
||
| 70 | } DNS_HEADER; |
||
| 71 | |||
| 72 | typedef struct _DNS_ANSWER_HEADER |
||
| 73 | { |
||
| 74 | WORD_VAL ResponseName; |
||
| 75 | WORD_VAL ResponseType; |
||
| 76 | WORD_VAL ResponseClass; |
||
| 77 | DWORD_VAL ResponseTTL; |
||
| 78 | WORD_VAL ResponseLen; |
||
| 79 | } DNS_ANSWER_HEADER; |
||
| 80 | |||
| 81 | static void DNSPutString(BYTE *String); |
||
| 82 | static void DNSGetString(BYTE *String); |
||
| 83 | |||
| 84 | /********************************************************************* |
||
| 85 | * Function: void DNSResolve(BYTE *Hostname) |
||
| 86 | * |
||
| 87 | * PreCondition: Stack is initialized() |
||
| 88 | * |
||
| 89 | * Input: *Hostname: Null terminated string specifying the |
||
| 90 | * host address to resolve to an IP |
||
| 91 | * address. |
||
| 92 | * |
||
| 93 | * Output: None |
||
| 94 | * |
||
| 95 | * Side Effects: None |
||
| 96 | * |
||
| 97 | * Overview: Call DNSIsResolved() until the host is resolved. |
||
| 98 | * |
||
| 99 | * Note: A UDP socket must be available before this |
||
| 100 | * function is called. It is freed at the end of |
||
| 101 | * the resolution. MAX_UDP_SOCKETS may need to be |
||
| 102 | * increased if other modules use UDP sockets. |
||
| 103 | * |
||
| 104 | * You must not modify *Hostname until DNSIsResolved() |
||
| 105 | * returns TRUE. |
||
| 106 | ********************************************************************/ |
||
| 107 | void DNSResolve(BYTE *Hostname) |
||
| 108 | { |
||
| 109 | DNSHostName = Hostname; |
||
| 110 | smDNS = DNS_HOME; |
||
| 111 | } |
||
| 112 | |||
| 113 | |||
| 114 | /********************************************************************* |
||
| 115 | * Function: BOOL DNSIsResolved(IP_ADDR *HostIP) |
||
| 116 | * |
||
| 117 | * PreCondition: DNSResolve() was called. |
||
| 118 | * |
||
| 119 | * Input: HostIP: Pointer to IP_ADDR structure to store the |
||
| 120 | * returned host IP address when DNS |
||
| 121 | * resolution is complete. |
||
| 122 | * |
||
| 123 | * Output: *HostIP, 4 byte IP address |
||
| 124 | * |
||
| 125 | * Side Effects: None |
||
| 126 | * |
||
| 127 | * Overview: Call DNSIsResolved() until the host is resolved. |
||
| 128 | * |
||
| 129 | * Note: You cannot start two DNS resolution proceedures |
||
| 130 | * concurrently. |
||
| 131 | * |
||
| 132 | * You must not modify *Hostname until DNSIsResolved() |
||
| 133 | * returns TRUE. |
||
| 134 | ********************************************************************/ |
||
| 135 | BOOL DNSIsResolved(IP_ADDR *HostIP) |
||
| 136 | { |
||
| 137 | static UDP_SOCKET MySocket; |
||
| 138 | static NODE_INFO Remote; |
||
| 139 | static TICK StartTime; |
||
| 140 | BYTE i; |
||
| 141 | WORD_VAL w; |
||
| 142 | DNS_HEADER DNSHeader; |
||
| 143 | DNS_ANSWER_HEADER DNSAnswerHeader; |
||
| 144 | |||
| 145 | switch(smDNS) |
||
| 146 | { |
||
| 147 | case DNS_HOME: |
||
| 148 | ARPResolve(&AppConfig.PrimaryDNSServer); |
||
| 149 | StartTime = tickGet(); |
||
| 150 | smDNS++; |
||
| 151 | break; |
||
| 152 | case DNS_RESOLVE_ARP: |
||
| 153 | if(!ARPIsResolved(&AppConfig.PrimaryDNSServer, &Remote.MACAddr)) |
||
| 154 | { |
||
| 155 | if(tickGet() - StartTime > DNS_TIMEOUT) |
||
| 156 | { |
||
| 157 | smDNS--; |
||
| 158 | } |
||
| 159 | break; |
||
| 160 | } |
||
| 161 | Remote.IPAddr.Val = AppConfig.PrimaryDNSServer.Val; |
||
| 162 | smDNS++; |
||
| 163 | // No need to break, we can immediately start resolution |
||
| 164 | |||
| 165 | case DNS_OPEN_SOCKET: |
||
| 166 | MySocket = UDPOpen(0, &Remote, DNS_PORT); |
||
| 167 | if(MySocket == INVALID_UDP_SOCKET) |
||
| 168 | break; |
||
| 169 | |||
| 170 | smDNS++; |
||
| 171 | // No need to break, we can immediately start resolution |
||
| 172 | |||
| 173 | case DNS_QUERY: |
||
| 174 | if(!UDPIsPutReady(MySocket)) |
||
| 175 | break; |
||
| 176 | |||
| 177 | // Put DNS query here |
||
| 178 | UDPPut(0x12); // User chosen ID |
||
| 179 | UDPPut(0x34); |
||
| 180 | UDPPut(0x01); // Standard query with recursion |
||
| 181 | UDPPut(0x00); |
||
| 182 | UDPPut(0x00); // 0x0001 questions |
||
| 183 | UDPPut(0x01); |
||
| 184 | UDPPut(0x00); // 0x0000 answers |
||
| 185 | UDPPut(0x00); |
||
| 186 | UDPPut(0x00); // 0x0000 name server resource records |
||
| 187 | UDPPut(0x00); |
||
| 188 | UDPPut(0x00); // 0x0000 additional records |
||
| 189 | UDPPut(0x00); |
||
| 190 | |||
| 191 | // Put hostname string to resolve |
||
| 192 | DNSPutString(DNSHostName); |
||
| 193 | |||
| 194 | UDPPut(0x00); // Type: A (host address) |
||
| 195 | UDPPut(0x01); |
||
| 196 | UDPPut(0x00); // Class: IN (Internet) |
||
| 197 | UDPPut(0x01); |
||
| 198 | |||
| 199 | UDPFlush(); |
||
| 200 | StartTime = tickGet(); |
||
| 201 | smDNS++; |
||
| 202 | break; |
||
| 203 | |||
| 204 | case DNS_GET_RESULT: |
||
| 205 | if(!UDPIsGetReady(MySocket)) |
||
| 206 | { |
||
| 207 | if(tickGet() - StartTime > DNS_TIMEOUT) |
||
| 208 | { |
||
| 209 | smDNS--; |
||
| 210 | } |
||
| 211 | break; |
||
| 212 | } |
||
| 213 | |||
| 214 | // Retrieve the DNS header and de-big-endian it |
||
| 215 | UDPGet(&DNSHeader.TransactionID.v[1]); |
||
| 216 | UDPGet(&DNSHeader.TransactionID.v[0]); |
||
| 217 | UDPGet(&DNSHeader.Flags.v[1]); |
||
| 218 | UDPGet(&DNSHeader.Flags.v[0]); |
||
| 219 | UDPGet(&DNSHeader.Questions.v[1]); |
||
| 220 | UDPGet(&DNSHeader.Questions.v[0]); |
||
| 221 | UDPGet(&DNSHeader.Answers.v[1]); |
||
| 222 | UDPGet(&DNSHeader.Answers.v[0]); |
||
| 223 | UDPGet(&DNSHeader.AuthoritativeRecords.v[1]); |
||
| 224 | UDPGet(&DNSHeader.AuthoritativeRecords.v[0]); |
||
| 225 | UDPGet(&DNSHeader.AdditionalRecords.v[1]); |
||
| 226 | UDPGet(&DNSHeader.AdditionalRecords.v[0]); |
||
| 227 | |||
| 228 | // Remove all questions |
||
| 229 | while(DNSHeader.Questions.Val--) |
||
| 230 | { |
||
| 231 | DNSGetString(NULL); |
||
| 232 | UDPGet(&w.v[1]); // Question type |
||
| 233 | UDPGet(&w.v[0]); |
||
| 234 | UDPGet(&w.v[1]); // Question class |
||
| 235 | UDPGet(&w.v[0]); |
||
| 236 | } |
||
| 237 | |||
| 238 | // Scan through answers |
||
| 239 | while(DNSHeader.Answers.Val--) |
||
| 240 | { |
||
| 241 | UDPGet(&DNSAnswerHeader.ResponseName.v[1]); // Response name |
||
| 242 | UDPGet(&DNSAnswerHeader.ResponseName.v[0]); |
||
| 243 | UDPGet(&DNSAnswerHeader.ResponseType.v[1]); // Response type |
||
| 244 | UDPGet(&DNSAnswerHeader.ResponseType.v[0]); |
||
| 245 | UDPGet(&DNSAnswerHeader.ResponseClass.v[1]); // Response class |
||
| 246 | UDPGet(&DNSAnswerHeader.ResponseClass.v[0]); |
||
| 247 | UDPGet(&DNSAnswerHeader.ResponseTTL.v[3]); // Time to live |
||
| 248 | UDPGet(&DNSAnswerHeader.ResponseTTL.v[2]); |
||
| 249 | UDPGet(&DNSAnswerHeader.ResponseTTL.v[1]); |
||
| 250 | UDPGet(&DNSAnswerHeader.ResponseTTL.v[0]); |
||
| 251 | UDPGet(&DNSAnswerHeader.ResponseLen.v[1]); // Response length |
||
| 252 | UDPGet(&DNSAnswerHeader.ResponseLen.v[0]); |
||
| 253 | |||
| 254 | // Make sure that this is a 4 byte IP address, response type A, class 1 |
||
| 255 | // Check if this is Type A |
||
| 256 | if( DNSAnswerHeader.ResponseType.Val == 0x0001 && |
||
| 257 | DNSAnswerHeader.ResponseClass.Val == 0x0001 && // Internet class |
||
| 258 | DNSAnswerHeader.ResponseLen.Val == 0x0004) |
||
| 259 | { |
||
| 260 | UDPGet(&HostIP->v[0]); |
||
| 261 | UDPGet(&HostIP->v[1]); |
||
| 262 | UDPGet(&HostIP->v[2]); |
||
| 263 | UDPGet(&HostIP->v[3]); |
||
| 264 | break; |
||
| 265 | } |
||
| 266 | else |
||
| 267 | { |
||
| 268 | while(DNSAnswerHeader.ResponseLen.Val--) |
||
| 269 | { |
||
| 270 | UDPGet(&i); |
||
| 271 | } |
||
| 272 | } |
||
| 273 | } |
||
| 274 | |||
| 275 | UDPDiscard(); |
||
| 276 | UDPClose(MySocket); |
||
| 277 | MySocket = INVALID_UDP_SOCKET; |
||
| 278 | smDNS++; |
||
| 279 | // No need to break, we are done and need to return TRUE |
||
| 280 | |||
| 281 | case DNS_DONE: |
||
| 282 | return TRUE; |
||
| 283 | } |
||
| 284 | |||
| 285 | return FALSE; |
||
| 286 | } |
||
| 287 | |||
| 288 | static void DNSPutString(BYTE *String) |
||
| 289 | { |
||
| 290 | BYTE *RightPtr; |
||
| 291 | BYTE i; |
||
| 292 | BYTE Len; |
||
| 293 | |||
| 294 | RightPtr = String; |
||
| 295 | |||
| 296 | while(1) |
||
| 297 | { |
||
| 298 | do |
||
| 299 | { |
||
| 300 | i = *RightPtr++; |
||
| 301 | } while((i != 0x00) && (i != '.') && (i != '/')); |
||
| 302 | |||
| 303 | // Put the length parameter |
||
| 304 | Len = (BYTE)(RightPtr-String-1); |
||
| 305 | UDPPut(Len); |
||
| 306 | while(Len--) |
||
| 307 | { |
||
| 308 | UDPPut(*String++); |
||
| 309 | } |
||
| 310 | if(i == 0x00 || i == '/') |
||
| 311 | break; |
||
| 312 | |||
| 313 | // Skip over the '.' in the input string |
||
| 314 | String++; |
||
| 315 | } |
||
| 316 | |||
| 317 | // Put the string terminator character |
||
| 318 | UDPPut(0x00); |
||
| 319 | } |
||
| 320 | |||
| 321 | static void DNSGetString(BYTE *String) |
||
| 322 | { |
||
| 323 | BYTE i; |
||
| 324 | BYTE j; |
||
| 325 | |||
| 326 | if(String == NULL) |
||
| 327 | { |
||
| 328 | UDPGet(&i); |
||
| 329 | while(i) |
||
| 330 | { |
||
| 331 | while(i--) |
||
| 332 | { |
||
| 333 | UDPGet(&j); |
||
| 334 | } |
||
| 335 | UDPGet(&i); |
||
| 336 | } |
||
| 337 | } |
||
| 338 | else |
||
| 339 | { |
||
| 340 | UDPGet(&i); |
||
| 341 | while(i) |
||
| 342 | { |
||
| 343 | while(i--) |
||
| 344 | { |
||
| 345 | UDPGet(String); |
||
| 346 | String++; |
||
| 347 | } |
||
| 348 | UDPGet(&i); |
||
| 349 | } |
||
| 350 | } |
||
| 351 | } |
||
| 352 | |||
| 353 | |||
| 354 | #endif //#if defined(STACK_USE_DNS) |