/*  Copyright(c) 2009-2020 Shenzhen TP-LINK Technologies Co.Ltd.
 *
 * file		dns.c
 * brief	使用host ip回复dns request
 * details	
 *
 * version	
 * date		04Nov20
 *
 * history 	\arg	
 */


#include "dns.h"
#include "uip.h"
#include <common.h>

#define UDPBUF ((struct uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN])
struct dns_packet g_dnspacket;

#if 0
void dump(char *head, int len)
{
	int i = 0;
	for(; i < len; i++){
		if(i % 16 == 0){
			printf("\n");
		}
		printf("%02x ", *head++);
	}
    printf("\n");
}
#endif

int getDNSReqLen(char* DNSReqData)
{
	int len;
	len = 0;
	while(*DNSReqData)
	{
		len += *((unsigned char*)DNSReqData) + 1;
		DNSReqData += *((unsigned char*)DNSReqData) + 1;
		if(len > DNS_MAX_QUERIES_LEN)
		{
			return -1;
		}
	}
	len ++;    //last 0x00
	len += DNS_TYPE_AND_CLASS_LEN;  //req type && req class;
	return len;
}


void dns_init(void)
{
	uip_udp_listen(HTONS(DNS_PORT));
}


void udp_dns_send(struct dns_packet *packet, int len, uip_ipaddr_t dstIp, unsigned short srcPort, unsigned short dstPort)
{
	memcpy(uip_appdata, packet, len);

	uip_udp_conn->ttl = 1;
	uip_udp_conn->rport = dstPort;
	uip_udp_conn->lport = srcPort;

	uip_ipaddr_copy(uip_udp_conn->ripaddr, dstIp);

	uip_udp_send(len);
}


void create_dns_msg(void)
{
	char *pDNSReqData = NULL;
	char *pAnswer = NULL;
	int DNSReqLen = 0;
	unsigned short shortVal = 0;
	unsigned short queryType = 0;
	int intVal = 0;
	unsigned int unintVal = 0;
	int totalLen = 0;

	unsigned short srcPort = 0, dstPort = 0;
	uip_ipaddr_t dstIp;

	struct dns_packet *packet = &g_dnspacket;
	memset(packet, 0, sizeof(struct dns_packet));
	memcpy(packet, uip_appdata, uip_datalen());

	/* 构造固定的DNS回复报文 */
	packet->flags |= htons(0x8080);
	packet->answerRRs = htons(0x0001);
	
	DNSReqLen = getDNSReqLen(packet->data);  /* domain name length + \0 */

	if(DNSReqLen < 0){
		printf("\n DNSReqLen = %d, error\n", DNSReqLen);
		return;
	}

	memcpy((char *)&queryType, packet->data + DNSReqLen - DNS_TYPE_AND_CLASS_LEN, sizeof(queryType));
	queryType = ntohs(queryType);

	totalLen = uip_datalen();

	/* fill answer */
	pAnswer = packet->data + DNSReqLen;

	/* name pointer */
	shortVal = htons(DNS_RESPONSE_POINTER);
	memcpy(pAnswer, &shortVal, sizeof(shortVal));
	pAnswer += sizeof(shortVal);
	totalLen += sizeof(shortVal);

	/* type */
	/*shortVal = htons(queryType);*/
	shortVal = htons(DNS_RESPONSE_TYPE);
	memcpy(pAnswer, &shortVal, sizeof(shortVal));
	pAnswer += sizeof(shortVal);
	totalLen += sizeof(shortVal);

	/* class */
	shortVal = htons(DNS_QUERY_CLASS);
	memcpy(pAnswer, &shortVal, sizeof(shortVal));
	pAnswer += sizeof(shortVal);
	totalLen += sizeof(shortVal);

	/* ttl */
	unintVal = htonl(DNS_ANSWER_TTL);
	memcpy(pAnswer, &unintVal, sizeof(unintVal));
	pAnswer += sizeof(unintVal);
	totalLen += sizeof(unintVal);

	/* data length */
	shortVal = htons(DNS_ANSWER_LEN);
	memcpy(pAnswer, &shortVal, sizeof(shortVal));
	pAnswer += sizeof(shortVal);
	totalLen += sizeof(shortVal);

	/* ip address */
	shortVal = (unsigned short)((CONFIG_DNS_IP & 0xFFFF0000) >> 16);
	shortVal = htons(shortVal);
	memcpy(pAnswer, &shortVal, sizeof(shortVal));
	pAnswer += sizeof(shortVal);
	totalLen += sizeof(shortVal);

	shortVal = (unsigned short)(CONFIG_DNS_IP & 0x0000FFFF);
	shortVal = htons(shortVal);
	memcpy(pAnswer, &shortVal, sizeof(shortVal));
	pAnswer += sizeof(shortVal);
	totalLen += sizeof(shortVal);

	dstPort = UDPBUF->srcport;
	srcPort = htons(DNS_PORT);
	uip_ipaddr_copy(dstIp, UDPBUF->srcipaddr);
	
	udp_dns_send(packet, totalLen, dstIp, srcPort, dstPort);
}

void handle_dns(void)
{
	if(uip_newdata()){
		create_dns_msg();
	}
}

void dns_appcall(void)
{
	handle_dns();
}

