#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "dns_construct.h"
#include <string.h>

#include<stdlib.h>
#include<unistd.h>
#include<stdio.h>



#define SET_UINT16_TO_N(buf, val, count) *(uint16*)buf = htons(val);count += 2; buf += 2
#define SET_UINT32_TO_N(buf, val, count) *(uint32*)buf = htonl(val);count += 4; buf += 4
/*****************************************************************************/
/* this function encode the plain string in name to the domain name encoding 
 * see decode_domain_name for more details on what this function does. */
int dns_construct_name(char *name, char *encoded_name)
{
  int i,j,k,n;

  k = 0; /* k is the index to temp */
  i = 0; /* i is the index to name */
  while( name[i] ){

	 /* find the dist to the next '.' or the end of the string and add it*/
	 for( j = 0; name[i+j] && name[i+j] != '.'; j++);
	 encoded_name[k++] = j;

	 /* now copy the text till the next dot */
	 for( n = 0; n < j; n++)
		encoded_name[k++] = name[i+n];
	
	 /* now move to the next dot */ 
	 i += j + 1;

	 /* check to see if last dot was not the end of the string */
	 if(!name[i-1])break;
  }
  encoded_name[k++] = 0;
  return k;
}
#if 0
/*
 * TBS_TAG: by 翟海琛 2011-2-24
 * Desc:禁止掉该功能，此处计算TTL的方法非常不合理，会增加系统负担，
        而且仅为解决我司内部测试部测试ddns 更新缓慢问题，不合算，为了保证压力测试稳定，取消该修改
 */


/*
功能:根据是否启用ddns来设置ttl大小。
	如果没有启动ddns,则ttl为10000(这是开源软件本来的值)，如果启动ddns，则ttl值为60
*/
int dns_ttl()
{
	int ttl=10000;
	FILE *fp;
	char buffer[64];
	int chars_read=0;

	fp=popen("ps | grep 'inadyn'|grep -v 'grep'", "r");
	if(fp!=NULL)
	{
		chars_read=fread(buffer,sizeof(char),strlen(buffer),fp);
		if(chars_read>0)
			ttl=60;
		pclose(fp);
		
	}

	if(ttl==10000)//做一个判断，提高效率
	{
		fp=popen("ps | grep 'peanuthullc'|grep -v 'grep'", "r");
		if(fp!=NULL)
		{
			chars_read=fread(buffer,sizeof(char),strlen(buffer),fp);
			if(chars_read>0)
				ttl=60;
			pclose(fp);
		}
	}
	
	return ttl;	
}
#endif
/*****************************************************************************/
int dns_construct_header(dns_request_t *m)
{
  char *ptr = m->original_buf;
  int dummy;

  SET_UINT16_TO_N( ptr, m->message.header.id, dummy );
  SET_UINT16_TO_N( ptr, m->message.header.flags.flags, dummy );
  SET_UINT16_TO_N( ptr, m->message.header.qdcount, dummy );
  SET_UINT16_TO_N( ptr, m->message.header.ancount, dummy );
  SET_UINT16_TO_N( ptr, m->message.header.nscount, dummy );
  SET_UINT16_TO_N( ptr, m->message.header.arcount, dummy );
  
  return 0;
}



/*****************************************************************************/
void dns_construct_warning_reply( dns_request_t *m )
{
  int len;


//获取路由器的IP地址
char szIPAddr[40]= {0};
CMM_GetStr("InternetGatewayDevice.LANDevice.1.LANHostConfigManagement.IPRouters",szIPAddr,sizeof(szIPAddr)-1, NULL, 0);


#if 0
//test code

	 if(CMM_SUCCESS == CMM_GetStr("InternetGatewayDevice.LANDevice.1.LANHostConfigManagement.IPRouters",szIPAddr,sizeof(szIPAddr)-1, NULL, 0))
	{
		system("echo ========dproxy get sucess!======\n");
		FILE *fp;
		fp=fopen("/var/testdproxy","w+");
		if(fp)
			{
			fprintf(fp,"%s",szIPAddr);
			fclose(fp);
			}
	}
	 else
	 	{
	 			system("echo ========dproxy get fail!======\n");
		FILE *fp;
		fp=fopen("/var/testdproxy","w+");
		if(fp)
			{
			fprintf(fp,"%s","fail");
			fclose(fp);
			}
	 	}
#endif
  /* point to end of orginal packet */ 
  m->here = &m->original_buf[m->numread];

  m->message.header.ancount = 1;
  m->message.header.flags.f.question = 1;
  dns_construct_header( m );

  if( m->message.question[0].type == A ){
    /* standard lookup so return and IP */
    struct in_addr in;
	//当达到限额时将所有DNS解析请求指向路由器IP
    strcpy(m->ip,szIPAddr);


    inet_aton( m->ip, &in );
    SET_UINT16_TO_N( m->here, 0xc00c, m->numread ); /* pointer to name */
    SET_UINT16_TO_N( m->here, A, m->numread );      /* type */
    SET_UINT16_TO_N( m->here, IN, m->numread );     /* class */
    SET_UINT32_TO_N( m->here, 1, m->numread );  /* ttl */
//   	SET_UINT32_TO_N( m->here, dns_ttl(), m->numread );  /* ttl */
    SET_UINT16_TO_N( m->here, 4, m->numread );      /* datalen */
    memcpy( m->here, &in.s_addr, sizeof(in.s_addr) ); /* data */
    m->numread += sizeof( in.s_addr);
  }else if ( m->message.question[0].type == PTR ){
    /* reverse look up so we are returning a name */
    SET_UINT16_TO_N( m->here, 0xc00c, m->numread ); /* pointer to name */
    SET_UINT16_TO_N( m->here, PTR, m->numread );    /* type */
    SET_UINT16_TO_N( m->here, IN, m->numread );     /* class */
    SET_UINT32_TO_N( m->here, 10000, m->numread );  /* ttl */
//	SET_UINT32_TO_N( m->here, dns_ttl(), m->numread );  /* ttl */
    len = dns_construct_name( m->cname, m->here + 2 );
    SET_UINT16_TO_N( m->here, len, m->numread );      /* datalen */
    m->numread += len;
  }
}
/*****************************************************************************/
void dns_construct_reply( dns_request_t *m )
{
  int len;
  /* point to end of orginal packet */ 
  m->here = &m->original_buf[m->numread];

  m->message.header.ancount = 1;
  m->message.header.flags.f.question = 1;
  dns_construct_header( m );

  if( m->message.question[0].type == A ){
    /* standard lookup so return and IP */
    struct in_addr in;
    inet_aton( m->ip, &in );
    SET_UINT16_TO_N( m->here, 0xc00c, m->numread ); /* pointer to name */
    SET_UINT16_TO_N( m->here, A, m->numread );      /* type */
    SET_UINT16_TO_N( m->here, IN, m->numread );     /* class */
    SET_UINT32_TO_N( m->here, 10000, m->numread );  /* ttl */
//   	SET_UINT32_TO_N( m->here, dns_ttl(), m->numread );  /* ttl */
    SET_UINT16_TO_N( m->here, 4, m->numread );      /* datalen */
    memcpy( m->here, &in.s_addr, sizeof(in.s_addr) ); /* data */
    m->numread += sizeof( in.s_addr);
  }else if ( m->message.question[0].type == PTR ){
    /* reverse look up so we are returning a name */
    SET_UINT16_TO_N( m->here, 0xc00c, m->numread ); /* pointer to name */
    SET_UINT16_TO_N( m->here, PTR, m->numread );    /* type */
    SET_UINT16_TO_N( m->here, IN, m->numread );     /* class */
    SET_UINT32_TO_N( m->here, 10000, m->numread );  /* ttl */
//	SET_UINT32_TO_N( m->here, dns_ttl(), m->numread );  /* ttl */
    len = dns_construct_name( m->cname, m->here + 2 );
    SET_UINT16_TO_N( m->here, len, m->numread );      /* datalen */
    m->numread += len;
  }
}
/*****************************************************************************/
void dns_construct_error_reply(dns_request_t *m)
{
  /* point to end of orginal packet */ 
  m->here = m->original_buf;

  m->message.header.flags.f.question = 1;
  m->message.header.flags.f.rcode = 2;
  dns_construct_header( m );
}
