| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705 |
- #include "luat_base.h"
- #include "luat_mcu.h"
- #include "luat_malloc.h"
- #ifdef LUAT_USE_DNS
- #include "platform_def.h"
- #include "dns_def.h"
- #include "ctype.h"
- #include "luat_network_adapter.h"
- #define dnsONE_QUESTION 0x0001
- #define dnsFLAG_QUERY_RESPONSE_BIT 0x8000
- #define dnsFLAG_OPERATION_CODE_BITS 0x7800
- #define dnsFLAG_TRUNCATION_BIT 0x0200
- #define dnsFLAG_RESPONSE_CODE_BITS 0x000f
- #define dnsOUTGOING_FLAGS 0x0100 /* Standard query. */
- #define dnsTYPE_IPV4 0x0001 /* A record (host address. */
- #define dnsCLASS 0x0001 /* IN */
- #define dnsRX_FLAGS_MASK 0x800f /* The bits of interest in the flags field of incoming DNS messages. */
- #define dnsEXPECTED_RX_FLAGS 0x8000 /* Should be a response, without any errors. */
- #define dnsTYPE_IPV6 0x001C
- #define dnsNAME_IS_OFFSET ( ( uint8_t ) 0xc0 )
- #define MAX_DOMAIN_LEN 255
- #define MAX_CHARACTER_NUM_PER_LABEL 63
- #define DNS_TO_BASE (900)
- #define DNS_TRY_MAX (3)
- //extern void DBG_Printf(const char* format, ...);
- //extern void DBG_HexPrintf(void *Data, unsigned int len);
- //#ifdef LUAT_LOG_NO_NEWLINE
- //#define DBG(x,y...) DBG_Printf("%s %d:"x, __FUNCTION__,__LINE__,##y)
- //#define DBG_ERR(x,y...) DBG_Printf("%s %d:"x, __FUNCTION__,__LINE__,##y)
- //#else
- //#define DBG(x,y...) DBG_Printf("%s %d:"x"\r\n", __FUNCTION__,__LINE__,##y)
- //#define DBG_ERR(x,y...) DBG_Printf("%s %d:"x"\r\n", __FUNCTION__,__LINE__,##y)
- //#endif
- #define LUAT_LOG_TAG "DNS"
- #include "luat_log.h"
- typedef struct
- {
- llist_head node;
- Buffer_Struct uri_buf; //静态不用释放
- luat_dns_ip_result ip_result[MAX_DNS_IP];
- uint64_t timeout_ms;
- uint16_t session_id;
- uint8_t retry_cnt;
- uint8_t dns_cnt;
- uint8_t ip_nums;
- uint8_t is_done;
- uint8_t ipv6_mode;
- uint8_t is_ipv6;
- uint8_t ipv6_done;
- }dns_process_t;
- typedef struct xDNSMessage
- {
- uint16_t usIdentifier;
- uint16_t usFlags;
- uint16_t usQuestions;
- uint16_t usAnswers;
- uint16_t usAuthorityRRs;
- uint16_t usAdditionalRRs;
- }xDNSMessage_t;
- static int32_t dns_find_process(void *pData, void *pParam)
- {
- uint16_t session_id = (uint32_t)pParam;
- dns_process_t *process = (dns_process_t *)pData;
- if (process->session_id == session_id)
- {
- return LIST_FIND;
- }
- return LIST_PASS;
- }
- static uint16_t dns_get_session_id(dns_client_t *client)
- {
- client->session_id++;
- if (!client->session_id)
- {
- client->session_id = 1;
- }
- return client->session_id;
- }
- static int32_t dns_skip_name_field(Buffer_Struct *buf)
- {
- if( ( buf->Data[buf->Pos] & dnsNAME_IS_OFFSET ) == dnsNAME_IS_OFFSET )
- {
- /* Jump over the two byte offset. */
- buf->Pos += sizeof( uint16_t );
- }
- else
- {
- /* pucByte points to the full name. Walk over the string. */
- while( buf->Data[buf->Pos] != 0x00 )
- {
- /* The number of bytes to jump for each name section is stored in the byte
- before the name section. */
- buf->Pos += ( buf->Data[buf->Pos] + 1 );
- if (buf->Pos >= buf->MaxLen)
- {
- return -1;
- }
- }
- buf->Pos++;
- }
- if (buf->Pos >= buf->MaxLen)
- {
- return -1;
- }
- return 0;
- }
- static int32_t dns_set_result(void *pData, void *pParam)
- {
- int i;
- dns_process_t *process = (dns_process_t *)pParam;
- luat_dns_require_t *require = (luat_dns_require_t *)pData;
- if (!require->result)
- {
- if (process->uri_buf.Pos == require->uri.Pos)
- {
- if (!memcmp(process->uri_buf.Data, require->uri.Data, require->uri.Pos))
- {
- require->result = -1;
- if (process->ip_nums)
- {
- for(i = 0; i < process->ip_nums; i++)
- {
- require->ip_result[i] = process->ip_result[i];
- }
- require->result = process->ip_nums;
- }
- }
- }
- }
- return LIST_PASS;
- }
- int32_t dns_get_ip(dns_client_t *client, Buffer_Struct *buf, uint16_t answer_num, dns_process_t *process)
- {
- uint16_t i, usTemp;
- luat_ip_addr_t ip_addr = {0};
- uint32_t ttl;
- uint8_t error = 0;
- PV_Union pvUn;
- for(i = 0; i < answer_num; i++)
- {
- if (dns_skip_name_field(buf) != ERROR_NONE)
- {
- error = 1;
- goto NET_DNSGETIP_DONE;
- }
- usTemp = BytesGetBe16(buf->Data + buf->Pos);
- switch (usTemp)
- {
- case dnsTYPE_IPV4:
- if ( (buf->Pos + 14) > buf->MaxLen)
- {
- error = 1;
- goto NET_DNSGETIP_DONE;
- }
- buf->Pos += 4;
- ttl = BytesGetBe32FromBuf(buf);
- usTemp = BytesGetBe16FromBuf(buf);
- if ( (buf->Pos + usTemp) > buf->MaxLen)
- {
- error = 1;
- goto NET_DNSGETIP_DONE;
- }
- network_set_ip_ipv4(&ip_addr, BytesGetLe32(buf->Data + buf->Pos));
- buf->Pos += usTemp;
- if (ttl > 0)
- {
- if (process && (process->ip_nums < MAX_DNS_IP))
- {
- // LLOGD("ipv4 result%d,%d.%d.%d.%d", process->ip_nums, pvUn.u8[0], pvUn.u8[1], pvUn.u8[2], pvUn.u8[3] );
- process->ip_result[process->ip_nums].ip = ip_addr;
- process->ip_result[process->ip_nums].ttl_end = ttl + ((uint32_t)(luat_mcu_tick64_ms()/1000));
- process->ip_nums++;
- }
- }
- break;
- case dnsTYPE_IPV6:
- if ( (buf->Pos + 14) > buf->MaxLen)
- {
- error = 1;
- goto NET_DNSGETIP_DONE;
- }
- buf->Pos += 4;
- ttl = BytesGetBe32FromBuf(buf);
- usTemp = BytesGetBe16FromBuf(buf);
- if ( (buf->Pos + usTemp) > buf->MaxLen)
- {
- error = 1;
- goto NET_DNSGETIP_DONE;
- }
- #ifdef LUAT_USE_LWIP
- #if LWIP_IPV6
- memcpy(ip_addr.u_addr.ip6.addr, buf->Data + buf->Pos, sizeof( uint32_t ) * 4);
- // ip_addr.u_addr.ip6.zone = 0;
- ip_addr.type = IPADDR_TYPE_V6;
- // LLOGI("ipv6 result %s", ipaddr_ntoa(&ip_addr));
- #endif
- #else
- memcpy(ip_addr.ipv6_u8_addr, buf->Data + buf->Pos, sizeof( uint32_t ) * 4);
- ip_addr.is_ipv6 = 1;
- #endif
- if (ttl > 0)
- {
- if (process && (process->ip_nums < MAX_DNS_IP))
- {
- process->ip_result[process->ip_nums].ip = ip_addr;
- process->ip_result[process->ip_nums].ttl_end = ttl + ((uint32_t)(luat_mcu_tick64_ms()/1000));
- process->ip_nums++;
- }
- }
- buf->Pos += usTemp;
- break;
- default:
- //DBG("%04x",usTemp);
- buf->Pos += 8;
- usTemp = BytesGetBe16FromBuf(buf);
- buf->Pos += usTemp;
- //OS(Dump)(buf->Data + buf->Pos, usTemp);
- break;
- }
- }
- NET_DNSGETIP_DONE:
- if (error)
- {
- return -1;
- }
- else
- {
- if (process)
- {
- if (process->ipv6_mode)
- {
- if (process->is_ipv6)
- {
- process->ipv6_done = 1;
- process->session_id = dns_get_session_id(client);
- process->is_ipv6 = 0;
- process->timeout_ms = 0;
- process->retry_cnt = 0;
- LLOGI("dns ipv6 done, now dns ipv4");
- return 0;
- }
- }
- process->is_done = 1;
- llist_traversal(&client->require_head, dns_set_result, process);
- }
- return 0;
- }
- }
- uint8_t dns_check_uri(const char *uri, uint32_t uri_len)
- {
- uint32_t dot_num = 0;
- uint32_t i = 0;
- uint32_t label_len = 0;
- char uri_last = 0;
- if(uri ==NULL)
- {
- return 0;
- }
- if(uri_len == 0 || uri_len > MAX_DOMAIN_LEN) //domain must less than 255
- {
- return 0;
- }
- if (!isalpha((int)uri[0])) // domain must start with a letter
- {
- return 0;
- }
- uri_last = uri[uri_len - 1];
- if (!isalnum((int)uri_last))//end with a letter or digit
- {
- return 0;
- }
- for(i = 0; i < uri_len ; i++)
- {
- if(!(isalnum((int)uri[i]) || uri[i]== '.' || uri[i] == '-'))//must a~z or A~Z or 0~9 or . or -
- {
- return 0;
- }
- if( uri [i] == '.')
- {
- dot_num++;
- if((label_len > MAX_CHARACTER_NUM_PER_LABEL) || (0 == label_len)) //Label must be 63 characters or less
- return 0;
- label_len = 0;
- }
- else
- {
- label_len++;
- }
- }
- if((label_len > MAX_CHARACTER_NUM_PER_LABEL) || (0 == dot_num))//the last label must be 63 characters or less
- return 0;
- return 1;
- }
- int32_t dns_make(dns_client_t *client, dns_process_t *process, Buffer_Struct *out)
- {
- int Result;
- xDNSMessage_t MsgHead;
- uint8_t *pucStart, *pucByte;
- // uint16_t usRecordType;
- // uint16_t usClass = BSP_Swap16(dnsCLASS);
- if (process->dns_cnt >= MAX_DNS_SERVER)
- {
- return -ERROR_PERMISSION_DENIED;
- }
- out->Pos = sizeof(xDNSMessage_t) + 6 + process->uri_buf.Pos;
- memset(&MsgHead, 0, sizeof(MsgHead));
- MsgHead.usIdentifier = BSP_Swap16(process->session_id);
- MsgHead.usFlags = BSP_Swap16(dnsOUTGOING_FLAGS);
- MsgHead.usQuestions = BSP_Swap16(dnsONE_QUESTION);
- memcpy(out->Data, &MsgHead, sizeof(MsgHead));
- pucStart = out->Data + sizeof( MsgHead );
- /* Leave a gap for the first length bytes. */
- pucByte = pucStart + 1;
- /* Copy in the host name. */
- memcpy( ( char * ) pucByte, process->uri_buf.Data, process->uri_buf.Pos );
- /* Mark the end of the string. */
- pucByte += process->uri_buf.Pos;
- *pucByte = 0x00;
- /* Walk the string to replace the '.' characters with byte counts.
- pucStart holds the address of the byte count. Walking the string
- starts after the byte count position. */
- pucByte = pucStart;
- do
- {
- pucByte++;
- while( ( *pucByte != 0x00 ) && ( *pucByte != '.' ) )
- {
- pucByte++;
- }
- /* Fill in the byte count, then move the pucStart pointer up to
- the found byte position. */
- *pucStart = ( uint8_t ) ( ( uint32_t ) pucByte - ( uint32_t ) pucStart );
- ( *pucStart )--;
- pucStart = pucByte;
- } while( *pucByte != 0x00 );
- pucByte++;
- /* Finish off the record. */
- if (process->is_ipv6)
- {
- BytesPutBe16(pucByte, dnsTYPE_IPV6);
- }
- else
- {
- BytesPutBe16(pucByte, dnsTYPE_IPV4);
- }
- pucByte += sizeof( uint16_t );
- BytesPutBe16(pucByte, dnsCLASS);
- process->timeout_ms = luat_mcu_tick64_ms() + DNS_TO_BASE * (process->retry_cnt + 1);
- return ERROR_NONE;
- }
- static int32_t dns_check_process(void *pData, void *pParam)
- {
- dns_process_t *process = (dns_process_t *)pData;
- Buffer_Struct *uri_buf = (Buffer_Struct *)pParam;
- if (uri_buf->Pos == process->uri_buf.Pos)
- {
- if (!memcmp(uri_buf->Data, process->uri_buf.Data, uri_buf->Pos))
- {
- return LIST_FIND;
- }
- }
- return LIST_PASS;
- }
- void dns_require(dns_client_t *client, const char *domain_name, uint32_t len, void *param)
- {
- luat_dns_require_t *require = zalloc(sizeof(luat_dns_require_t));
- require->uri.Data = domain_name;
- require->uri.Pos = len;
- require->uri.MaxLen = len;
- require->param = param;
- dns_process_t *process = llist_traversal(&client->process_head, dns_check_process, &require->uri);
- // if no same proc
- if (!process)
- {
- process = zalloc(sizeof(dns_process_t));
- Buffer_StaticInit(&process->uri_buf, require->uri.Data, require->uri.Pos);
- process->uri_buf.Pos = require->uri.Pos;
- process->session_id = dns_get_session_id(client);
- llist_add_tail(&process->node, &client->process_head);
- }
- llist_add_tail(&require->node, &client->require_head);
- }
- void dns_require_ex(dns_client_t *client, const char *domain_name, void *param, uint8_t adapter_index)
- {
- luat_dns_require_t *require = zalloc(sizeof(luat_dns_require_t));
- require->uri.Data = domain_name;
- require->uri.Pos = strlen(domain_name);
- require->uri.MaxLen = strlen(domain_name);
- require->param = param;
- require->adapter_index = adapter_index;
- dns_process_t *process = llist_traversal(&client->process_head, dns_check_process, &require->uri);
- // if no same proc
- if (!process)
- {
- process = zalloc(sizeof(dns_process_t));
- Buffer_StaticInit(&process->uri_buf, require->uri.Data, require->uri.Pos);
- process->uri_buf.Pos = require->uri.Pos;
- process->session_id = dns_get_session_id(client);
- llist_add_tail(&process->node, &client->process_head);
- }
- llist_add_tail(&require->node, &client->require_head);
- }
- void dns_require_ipv6(dns_client_t *client, const char *domain_name, void *param, uint8_t adapter_index, uint8_t is_ipv6)
- {
- luat_dns_require_t *require = zalloc(sizeof(luat_dns_require_t));
- require->uri.Data = domain_name;
- require->uri.Pos = strlen(domain_name);
- require->uri.MaxLen = strlen(domain_name);
- require->param = param;
- require->adapter_index = adapter_index;
- dns_process_t *process = llist_traversal(&client->process_head, dns_check_process, &require->uri);
- // if no same proc
- if (!process)
- {
- process = zalloc(sizeof(dns_process_t));
- Buffer_StaticInit(&process->uri_buf, require->uri.Data, require->uri.Pos);
- process->uri_buf.Pos = require->uri.Pos;
- process->session_id = dns_get_session_id(client);
- process->ipv6_mode = is_ipv6;
- process->is_ipv6 = is_ipv6;
- llist_add_tail(&process->node, &client->process_head);
- }
- llist_add_tail(&require->node, &client->require_head);
- }
- static int32_t dns_clear_require(void *pData, void *pParam)
- {
- luat_dns_require_t *require = (luat_dns_require_t *)pData;
- free(require->uri.Data);
- return LIST_DEL;
- }
- static int32_t dns_clear_process(void *pData, void *pParam)
- {
- dns_process_t *process = (dns_process_t *)pData;
- if (pParam)
- {
- return process->is_done?LIST_DEL:LIST_PASS;
- }
- return LIST_DEL;
- }
- void dns_clear(dns_client_t *client)
- {
- // uint64_t now_time = luat_mcu_tick64_ms();
- llist_traversal(&client->process_head, dns_clear_process, NULL);
- llist_traversal(&client->require_head, dns_clear_require, NULL);
- }
- static int32_t dns_find_need_tx_process(void *pData, void *pParam)
- {
- dns_process_t *process = (dns_process_t *)pData;
- if (!process->is_done && (process->timeout_ms < luat_mcu_tick64_ms()))
- {
- return LIST_FIND;
- }
- return LIST_PASS;
- }
- void dns_run(dns_client_t *client, Buffer_Struct *in, Buffer_Struct *out, int *server_cnt)
- {
- dns_process_t *process;
- int i;
- if (llist_empty(&client->process_head) && !llist_empty(&client->require_head))
- {
- dns_clear(client);
- if (client->is_run)
- {
- LLOGI("dns all done ,now stop");
- }
- client->is_run = 0;
- return;
- }
- if (in)
- {
- xDNSMessage_t MsgHead;
- while ( (in->Pos + sizeof(MsgHead)) < in->MaxLen)
- {
- memcpy(&MsgHead, in->Data + in->Pos, sizeof(MsgHead));
- MsgHead.usIdentifier = BSP_Swap16(MsgHead.usIdentifier);
- MsgHead.usFlags = BSP_Swap16(MsgHead.usFlags);
- in->Pos += sizeof(MsgHead);
- process = llist_traversal(&client->process_head, dns_find_process, MsgHead.usIdentifier);
- if (process)
- {
- if ( MsgHead.usFlags & 0x8000)
- {
- MsgHead.usQuestions = BSP_Swap16(MsgHead.usQuestions);
- MsgHead.usAnswers = BSP_Swap16(MsgHead.usAnswers);
- MsgHead.usAuthorityRRs = BSP_Swap16(MsgHead.usAuthorityRRs);
- MsgHead.usAdditionalRRs = BSP_Swap16(MsgHead.usAdditionalRRs);
- for(i = 0; i < MsgHead.usQuestions; i++)
- {
- if (dns_skip_name_field(in) != ERROR_NONE)
- {
- goto NET_DNS_RX_OUT;
- }
- in->Pos += 4;
- if (in->Pos >= in->MaxLen)
- {
- goto NET_DNS_RX_OUT;
- }
- }
- if (!(MsgHead.usFlags & 0x000f))
- {
- if (dns_get_ip(client, in, MsgHead.usAnswers, process))
- {
- goto NET_DNS_RX_OUT;
- }
- }
- else
- {
- if (dns_get_ip(client, in, MsgHead.usAnswers, NULL))
- {
- goto NET_DNS_RX_OUT;
- }
- }
- if (dns_get_ip(client, in, MsgHead.usAuthorityRRs, NULL))
- {
- goto NET_DNS_RX_OUT;
- }
- if (dns_get_ip(client, in, MsgHead.usAdditionalRRs, NULL))
- {
- goto NET_DNS_RX_OUT;
- }
- }
- else
- {
- goto NET_DNS_RX_OUT;
- }
- }
- }
- }
- else if (out)
- {
- NET_DNS_TX:
- process = llist_traversal(&client->process_head, dns_find_need_tx_process, NULL);
- if (!process)
- {
- goto NET_DNS_RX_OUT;
- }
- if (process->timeout_ms)
- {
- process->retry_cnt++;
- if (process->retry_cnt >= DNS_TRY_MAX)
- {
- process->retry_cnt = 0;
- if (process->ipv6_mode)
- {
- if (process->is_ipv6)
- {
- process->is_ipv6 = 0;
- goto NET_DNS_TX_IPV4;
- }
- else
- {
- if (process->ipv6_done && process->ip_nums)
- {
- LLOGD("get ipv6, no ipv4");
- process->ip_nums = 0;
- process->is_done = 1;
- client->new_result = 1;
- llist_traversal(&client->require_head, dns_set_result, process);
- llist_del(&process->node);
- free(process);
- goto NET_DNS_TX;
- }
- else
- {
- process->is_ipv6 = 1;
- }
- }
- }
- process->dns_cnt++;
- if (process->dns_cnt >= MAX_DNS_SERVER)
- {
- LLOGE("no ipv6, no ipv4");
- process->ip_nums = 0;
- process->is_done = 1;
- client->new_result = 1;
- llist_traversal(&client->require_head, dns_set_result, process);
- llist_del(&process->node);
- free(process);
- goto NET_DNS_TX;
- }
- }
- }
- NET_DNS_TX_IPV4:
- while(!network_ip_is_vaild(&client->dns_server[process->dns_cnt]))
- {
- process->dns_cnt++;
- if (process->dns_cnt >= MAX_DNS_SERVER)
- {
- process->ip_nums = 0;
- llist_traversal(&client->require_head, dns_set_result, process);
- llist_del(&process->node);
- free(process);
- goto NET_DNS_TX;
- }
- }
- LLOGD("%.*s state %d id %d ipv6 %d use dns server%d, try %d", process->uri_buf.Pos, process->uri_buf.Data, process->is_done, process->session_id, process->is_ipv6, process->dns_cnt, process->retry_cnt);
- process->is_done = 0;
- OS_InitBuffer(out, 512);
- dns_make(client, process, out);
- *server_cnt = process->dns_cnt;
- }
- NET_DNS_RX_OUT:
- if (!llist_empty(&client->process_head))
- {
- llist_traversal(&client->process_head, dns_clear_process, 1);
- }
- if (llist_empty(&client->process_head) && llist_empty(&client->require_head))
- {
- if (client->is_run)
- {
- LLOGI("dns all done ,now stop");
- }
- client->is_run = 0;
- return;
- }
- else
- {
- client->is_run = 1;
- }
- return ;
- }
- void dns_init_client(dns_client_t *client)
- {
- int i;
- INIT_LLIST_HEAD(&client->process_head);
- INIT_LLIST_HEAD(&client->require_head);
- for(i = 0; i < MAX_DNS_SERVER; i++)
- {
- if (!client->is_static_dns[i])
- {
- network_set_ip_invaild(&client->dns_server[i]);
- }
- }
- }
- #endif
|