
#include<sys/socket.h>
#include<sys/time.h>
#include<errno.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
#include<unistd.h>

#include<almemsys/almemsys.h>


// #define DNS_BUG


// prototype
//char * scan_dns_connect(int, char *, char *, char *, int, int *, char);
//
//
//int main(int argc, char ** argv)
//{
//int ret;
//char * backdata = (char * )calloc(512, sizeof(char));
//ret = 0;
//
//if(argc != 3){
//   printf("1 > dns host 2 > qudata\n");
//   exit(1);
//   }
//
//printf("IP V6 Address %s\n", scan_dns_connect(53, argv[1], argv[2], backdata, 5, &ret, '6'));
//printf("IP V4 Address %s\n", scan_dns_connect(53, argv[1], argv[2], backdata, 5, &ret, '4'));
//
//return ret;
//}




int qudata_make(unsigned char * qdata, char * hostname, char type)
{
unsigned char swap[512];
int co, inco, ttco, lenco, dmax;


memset(swap, 0x00, 512);
dmax = 0;
co = 0;
inco = 0;
ttco = 0;
lenco = 0;

// ID
qdata[0] =  0xc6; 
qdata[1] =  0xac; 
// QR
qdata[2] =  0x01; 
qdata[3] =  0x00; 
// QDCOUNT
qdata[4] =  0x00; 
qdata[5] =  0x01; 
// NSCOUNT
qdata[6] =  0x00; 
qdata[7] =  0x00; 
//
qdata[8] =  0x00; 
qdata[9] =  0x00; 
//
qdata[10] =  0x00; 
qdata[11] =  0x00; 

ttco = 11 + 1;

dmax = char_count(hostname, '.');
#ifdef DNS_BUG
printf("-%s--%d\n", hostname, dmax);
#endif

for(co = 0; co <= dmax; co++){
    if(-1 < self_delim_get(hostname, (char *)swap, '.', co, 512)){
       lenco = (int)strlen((char * )swap);
       #ifdef DNS_BUG
       printf("==%d==%s\n", lenco, swap);
       #endif
       qdata[ttco] =  lenco; 
       for(inco = 0; inco <= lenco; inco++){
          ttco = ttco + 1;
          qdata[ttco] =  swap[inco]; 
          }
       memset(swap, 0x00, 512);
       lenco = 0;
       }
    else{
//     fprintf(stderr,"err data\n");
       }
    }
 
qdata[ttco] = 0; 

// QTYPE (A 1)
if(type == '4'){
   ttco = ttco + 1;
   qdata[ttco] = 0x00; 
   ttco = ttco + 1;
   qdata[ttco] = 0x01; 
   }
// QTYPE (AAAA 28)
else if(type == '6'){
   ttco = ttco + 1;
   qdata[ttco] = 0x00; 
   ttco = ttco + 1;
   qdata[ttco] = 0x1c; 
   }
else{
   ttco = ttco + 1;
   qdata[ttco] = 0x00; 
   ttco = ttco + 1;
   qdata[ttco] = 0x01; 
   }

// QCLASS
ttco = ttco + 1;
qdata[ttco] = 0x00; 
ttco = ttco + 1;
qdata[ttco] = 0x01; 

#ifdef DNS_BUG
printf("ttco %d\n", ttco);
#endif

return ttco;
}





int chk_ip6(char * hostname, int max)
{
char ret;
ret = 0;

if(max > 2){
   if(2 <= char_count((char *)hostname, ':')){

      if(ch_int_v6((char *)hostname) != -1){
         ret = 0;
         }
      else{
         ret = -1;
         }

      }
   else{
      ret = -1;
      }
   }
else{
   ret = -1;
   }

return ret;
}










int chk_ip(char * hostname, int max)
{
char ret;
ret = 0;
unsigned char swap[max];

memset(swap, 0x00, max);

if(self_delim_get(hostname, (char *)swap, '.', 0, max) > -1){
   if(ch_int2((char *)swap) != -1){
      memset(swap, 0x00, max);
      if(self_delim_get(hostname, (char *)swap, '.', 1, max) > -1){
         if(ch_int2((char *)swap) != -1){
            memset(swap, 0x00, max);
            if(self_delim_get(hostname, (char *)swap, '.', 2, max) > -1){
               if(ch_int2((char *)swap) != -1){
                  memset(swap, 0x00, max);
                  if(self_delim_get(hostname, (char *)swap, '.', 3, max) > -1){
                     if(ch_int2((char *)swap) != -1){
                        memset(swap, 0x00, max);
                        #ifdef DNS_BUG
                        printf("====%s====\n", hostname);
                        #endif
                        ret = 0;
                        }
                     else{
                        ret = -1;
                        }
                     }
                  else{
                     ret = -1;
                     }
                  }
               else{
                  ret = -1;
                  }
               }
            else{
               ret = -1;
               }
            }
         else{
            ret = -1;
            }
         }
      else{
         ret = -1;
         }
      }
   else{
      ret = -1;
      }
   }
else{
   ret = -1;
   }

return ret;
}





/*----------------- SCAN DNS CONNECT --------------------*/
char * scan_dns_connect(int port, char * ip_addr, char * hostname, char * backdata, int timeout, int * ret, char type)
{
int send_sk, adata_len, retval, send_len, host_len, co, ancount, sender_len, colen, tyin;
char domain_co, chco;
struct sockaddr_in server;
struct sockaddr_in client;
struct timeval tv;
unsigned char qdata[512];
unsigned char adata[512];
unsigned char domain[512];
unsigned char ip_data[30];
struct timeval tv_tts, tv_vts; 

union{
   short sh;
   char shbuf[1];
   } un16;

fd_set select_fd;
adata_len = 0;
* ret = 0;
retval = 0;
send_len = 0;
domain_co = 0;
co = 0;
chco = 0;
sender_len = 0;
colen = 0;
tyin = 4;

memset(qdata, 0x00, 512);
memset(domain, 0x00, 512);
memset(ip_data, 0x00, 30);
memset(adata, 0x00, 512);

host_len = (int)strlen(hostname);
if(host_len < 3 || host_len > 256){
   backdata = safe_sprintf(backdata, BUF_MAX,"hostname size err. seze = <%d>", host_len);
   return(backdata);
   }

if(type == '4'){
   if(0 == chk_ip(hostname, host_len)){
      backdata = safe_sprintf(backdata, BUF_MAX,"%s", hostname);
      return(backdata);
      }
   }
else if(type == '6'){
   if(0 == chk_ip6(hostname, host_len)){
      backdata = safe_sprintf(backdata, BUF_MAX,"%s", hostname);
      return(backdata);
      }
   }


// create socket
if((send_sk = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
   backdata = safe_sprintf(backdata, BUF_MAX,"Socket generation error: IP=%s Port=%d dgram socket error!",
     ip_addr, port);
   * ret = -1;
   return(backdata);
   }

client.sin_family = AF_INET;
client.sin_addr.s_addr = htonl(INADDR_ANY);
client.sin_port = htons(0);

if(bind(send_sk, (void *)&client, sizeof(client)) < 0){
   backdata = safe_sprintf(backdata, BUF_MAX,"IP bind error: IP=%s Port=%d not bind ip or port.",
     ip_addr, port);
   * ret = -1;
   return(backdata);
   }

server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr(ip_addr);

if(0 == (int)server.sin_addr.s_addr){
   backdata=safe_sprintf(backdata,BUF_MAX,"Illegal Internet Protocol address: %s %d",
     ip_addr, (int)server.sin_addr.s_addr);
   * ret = -1;
   return backdata;
   }
server.sin_port = htons(port);

// DNS問い合わせパケットの生成
send_len = qudata_make((unsigned char *)&qdata, hostname, type);

gettimeofday(&tv_tts, NULL);

// パケットの送信
if((sender_len = sendto(send_sk, (char *)&qdata, (send_len + 1), 0, (void *)&server, sizeof(server))) <= 0){
   #ifdef DNS_BUG
   printf("DNS: scan-dns(0): sentto() err send len<%d> ERRNO: %d %s\n", sender_len, errno, strerror(errno));
   #endif
   backdata = safe_sprintf(backdata, BUF_MAX,"Data transmission error: len<%d> ERRNO: %d %s",
     sender_len, errno, strerror(errno));
   * ret = -1;
   close(send_sk);
   return(backdata);
   }

tv.tv_sec = timeout;
tv.tv_usec = 0;

// パケットの受信
while(1){
   FD_ZERO(&select_fd);
   FD_SET(send_sk, &select_fd);
   retval = select(send_sk + 1, &select_fd, NULL, NULL, &tv);

   // select()に関するエラー、タイムアウトなど
   if(retval < 0){
      #ifdef DNS_BUG
      printf("DNS: scan-dns(1): retval <%d> ERRNO: %d %s\n", retval, errno, strerror(errno));
      #endif
      backdata = safe_sprintf(backdata, BUF_MAX,"Network abnormal error: retval <%d> ERRNO: %d %s",
        retval, errno, strerror(errno));
      * ret = -1;
      close(send_sk);
      return(backdata);
      }
   if(retval == 0){
      #ifdef DNS_BUG
      printf("DNS: scan-dns(2): retval <%d> ERRNO: %d %s\n", retval, errno, strerror(errno));
      #endif
      backdata = safe_sprintf(backdata, BUF_MAX, "Reception time-out error: retval <%d> ERRNO: %d %s",
        retval, errno, strerror(errno));
      * ret = -1;
      close(send_sk);
      return(backdata);
      }
   if(retval >= 1){
      adata_len = recvfrom(send_sk, (char *)&adata, 512, 0, NULL, NULL);
      gettimeofday(&tv_vts, NULL);
      #ifdef DNS_BUG
      printf("DNS: scan-dns(3): retval <%d> ERRNO: %d %s size <%d>\n", retval, errno, strerror(errno), adata_len);
      #endif
      * ret = 1;
      close(send_sk);
      break;
      }
   } /* while */


// int coco;
// for(coco = send_len + 1; coco < adata_len; coco++){
//    printf("<%d><%x><%d><%c>\n", coco, adata[coco], adata[coco], adata[coco]);
//   }



// 受け取ったデータ数から送信したデータ数を引いた数が0か0以下の場合はエラー
if(0 >= (adata_len - send_len + 1)){
   #ifdef DNS_BUG
   printf("DNS: scan-dns(4): recve data size error. send<%d> recv<%d>\n", send_len, adata_len);
   #endif
   backdata = safe_sprintf(backdata, BUF_MAX, "recve data size error. send<%d> recv<%d>", send_len, adata_len);
   * ret = 1;
   close(send_sk);
   return(backdata);
   }

#ifdef DNS_BUG
un16.shbuf[0] = adata[1];
un16.shbuf[1] = adata[0];
printf("=識別=%d\n", un16.sh);

un16.shbuf[0] = adata[3];
un16.shbuf[1] = adata[2];
printf("=flag=%d\n", un16.sh);

un16.shbuf[0] = adata[5];
un16.shbuf[1] = adata[4];
printf("=問い合わせ数=%d\n", un16.sh);
#endif

un16.shbuf[0] = adata[7];
un16.shbuf[1] = adata[6];
ancount = un16.sh;

#ifdef DNS_BUG
printf("=回答数=%d\n", un16.sh);
un16.shbuf[0] = adata[9];
un16.shbuf[1] = adata[8];
printf("=権威RR=%d\n", un16.sh);

un16.shbuf[0] = adata[11];
un16.shbuf[1] = adata[10];
printf("=追加RR=%d\n", un16.sh);
#endif


// 回答数が0の場合エラー
if(ancount <= 0){
   #ifdef DNS_BUG
   printf("DNS: scan-dns(5): DNS Non-responding error <%d>\n", ancount);
   #endif
   backdata = safe_sprintf(backdata, BUF_MAX, "DNS Non-responding error <%d>", ancount);
   * ret = 1;
   close(send_sk);
   return(backdata);
   }

// 最初に引けたIPアドレスをreturnバッファに書き込む
if(type == '6'){
   tyin = 16;
   }
else if(type == '4'){
   tyin = 4;
   }
else{
   tyin = 4;
   }



if(adata_len - (tyin + 2) >= 0){
   for(co = send_len + 11; co <= (adata_len - (tyin + 2)); co++){
      if(0 == (int)adata[co]){
         if(tyin == (int)adata[co + 1]){
            if((0 == (int)adata[co + tyin + 2 + 2] && 192 == (int)adata[co + tyin + 2]) || (co + (tyin + 2)) == adata_len){

               for(colen = 0; colen < (tyin + 2); colen++){
                  ip_data[colen] = (int)adata[co + colen + 2];
                  }

               if(type =='6'){
                  backdata = safe_sprintf(backdata,BUF_MAX,"%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
                    (int)ip_data[0],
                    (int)ip_data[1],
                    (int)ip_data[2],
                    (int)ip_data[3],
                    (int)ip_data[4],
                    (int)ip_data[5],
                    (int)ip_data[6],
                    (int)ip_data[7],
                    (int)ip_data[8],
                    (int)ip_data[9],
                    (int)ip_data[10],
                    (int)ip_data[11],
                    (int)ip_data[12],
                    (int)ip_data[13],
                    (int)ip_data[14],
                    (int)ip_data[15]
                    );
                  }
               else if(type == '4'){
                  backdata = safe_sprintf(backdata, BUF_MAX,"%d.%d.%d.%d",
                    (int)ip_data[0],
                    (int)ip_data[1],
                    (int)ip_data[2],
                    (int)ip_data[3]
                    );
                  }
               else{
                  backdata = safe_sprintf(backdata, BUF_MAX, "Error: Protocols other than 4 and 6.");
                  * ret = 1;
                  }

               break;
               }

            else{
               backdata = safe_sprintf(backdata, BUF_MAX, "recve data size error(1).");
               * ret = 1;
               }
            }
         else{
            backdata = safe_sprintf(backdata, BUF_MAX, "recve data size error(2).");
            * ret = 1;
            }
         }
      else{
         backdata = safe_sprintf(backdata, BUF_MAX, "recve data size error(3).");
         * ret = 1;
         }
      }
   }
else{
   backdata = safe_sprintf(backdata, BUF_MAX, "recve data size error. send<%d> recv<%d>", send_len, adata_len);
   * ret = 1;
   return(backdata);
   }

return(backdata);
}




