#include<stdio.h>
#include<string.h>
#include<netdb.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netinet/in_systm.h>
#include<netinet/in.h>
#include<netinet/ip.h>
#include<netinet/ip_icmp.h>
#include<sys/stat.h>
#include<arpa/inet.h>

#include"sitar.h"
#include"sitar_scan.h"
#include"sitar_com.h"
#include<almemsys/almemsys.h>
#include"jpreturn.h"

extern global_data_t gd;

/* 1-> port No' 2-> Ipsddr 3-> return data,, return status code 0=open or=close
int scan_udp_connect(int, char *, char *, int);
*/


/*----------------- SCAN UDP CONNECT --------------------*/
char * scan_udp_connect(int port, char * url_data, char * backdata, int timeout, int * stat)
{
char ipa2[IP_LEN];
char * ip_addr2 = ipa2;
char buff[1024];
char ntb[IP_LEN];
char * ntopbuff = ntb;
char ip[BUF_URL];
char * ip_addr = ip;
char pas[BUF_URL];
char * url_pass = pas;

int send_sk, recv_sk, select_stat, port2, resolv_ret;
unsigned long resoip;
struct icmp *icmp;
struct sockaddr_in send_addr;
struct timeval tv;
fd_set select_fd;

send_addr.sin_family = AF_INET;


memset(ip_addr, 0x00, BUF_URL);
memset(url_pass, 0x00, BUF_URL);

// portの設定よりもURLに含まれるポートを優先する
port2 = urldompass_port(url_data, ip_addr, url_pass, strlen(url_data));
if(port2 > 0){
   port = port2;
   }


resoip = 0;
resolv_ret = 0;

// backdata = resolvename_th(backdata, ip_addr, timeout, &resoip);
// backdata = resolvename_sk(backdata, ip_addr, timeout, &resoip, &resolv_ret);

if(0 == self_memcmp(gd.di.dns_name, "RESOLV")){
   backdata = resolvename_th(backdata, ip_addr, timeout, &resoip);
   }
else{
   backdata = resolvename_sk(backdata, ip_addr, timeout, &resoip, gd.di.dns_name, &resolv_ret, '4');
   if(resolv_ret < 0){
      backdata = resolvename_sk(backdata, ip_addr, DEFAULT_TIMEOUT, &resoip, gd.di.dns_name2, &resolv_ret, '4');
      fprintf(stderr,"RESOLV ERR: DNS name resolution failure <%s> %s\n", ip_addr, backdata);
      }
   }


send_addr.sin_addr.s_addr = resoip;

if(0 == (int)send_addr.sin_addr.s_addr || resoip == (int)NULL){
// backdata=safe_sprintf(backdata,BUF_MAX,"%s %s %d\n", SOCK_2, ip_addr, (int)send_addr.sin_addr.s_addr);
   backdata=safe_sprintf(backdata,BUF_MAX,"%s %s\n", SOCK_2, ip_addr);
   #ifdef UDP_BUG
   printf("UDP: scan_udp_connect(1): START %s\n", backdata);
   #endif
   * stat = -1;
   return backdata;
   }

// ip_addr2 = inet_ntoa(send_addr.sin_addr);
ip_addr2 = (char *)inet_ntop(AF_INET, &send_addr.sin_addr, ntopbuff, IP_LEN);

#ifdef UDP_BUG
printf("UDP: scan_udp_connect(2): UDP host<%s> ip<%s>\n",ip_addr2, ip_addr);
#endif

if((send_sk = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
   backdata=safe_sprintf(backdata,BUF_MAX,
    "HOST=%s IP=%s Port=%d UDP %s", ip_addr, ip_addr2, port, SOCK_1);
   #ifdef UDP_BUG
   printf("UDP: scan_udp_connect(3): SEND UDP PACKET %s\n", backdata);
   #endif
   * stat = -10;
   return backdata;
   }

if((recv_sk = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0){
   backdata=safe_sprintf(backdata,BUF_MAX,
    "HOST=%s IP=%s Port=%d UDP %s", ip_addr, ip_addr2, port, SOCK_1);
   * stat = -10;
   #ifdef UDP_BUG
   printf("UDP: scan_udp_connect(4): SEND ROW PACKET %s\n", backdata);
   #endif
   return backdata;
   }

send_addr.sin_port = htons(port);
sendto(send_sk, NULL, 0, 0, (struct sockaddr *)(long int)&send_addr, sizeof(send_addr));

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

while(1){
   FD_ZERO(&select_fd);
   FD_SET(recv_sk, &select_fd);

   if((select_stat = select(recv_sk + 1, &select_fd, NULL, NULL, &tv)) > 0){
      struct ip *ip;
      int hlen;
      int ports;
      if(recvfrom(recv_sk, buff, 1024, 0, NULL, NULL) != 56){
         #ifdef UDP_BUG
         printf("UDP: scan_udp_connect(5): ");
         #endif
         continue;
         }

      ip = (struct ip *)(long int)buff;
      hlen = ip->ip_hl << 2;
      icmp = (struct icmp*)(buff + hlen);
      ports = ntohs(*(u_short *)(buff + 20 + 8 + 20 + 2));
      if((ip->ip_src.s_addr != send_addr.sin_addr.s_addr)
         || (icmp->icmp_type != ICMP_UNREACH)
         || (icmp->icmp_code != ICMP_UNREACH_PORT)
         || (ports != port)){
         #ifdef UDP_BUG
         printf("UDP: scan_udp_connect(6): ");
         #endif
         continue;
         }
      else{
         backdata=safe_sprintf(backdata,BUF_MAX,
           "HOST=%s IP=%s Port=%d UDP %s", ip_addr, ip_addr2, port, SOCK_7);
         #ifdef UDP_BUG
         printf("UDP: scan_udp_connect(7): ");
         #endif
         close(send_sk);
         close(recv_sk);
         * stat = 1;
         return backdata;
         }
      }

   else{
      struct servent *se;
      se = getservbyport(htons(port), "udp");
      backdata=safe_sprintf(backdata,BUF_MAX,
       "HOST=%s IP=%s Port=%d %s UDP %s", ip_addr, ip_addr2, port, (se==NULL)?"unknown":se->s_name, SOCK_3);
      #ifdef UDP_BUG
      printf("UDP: scan_udp_connect(8): RECV %s", backdata);
      #endif
      close(send_sk);
      close(recv_sk);
      * stat = 0;
      return backdata;
      }

   #ifdef UDP_BUG
   printf("UDP: scan_udp_connect(9): RECV %s", backdata);
   #endif
   break;
   }

backdata=safe_sprintf(backdata,BUF_MAX,
 "HOST=%s IP=%s Port=%d UDP %s", ip_addr, ip_addr2, port, SOCK_5);
#ifdef UDP_BUG
printf("UDP: scan_udp_connect(10): END %s", backdata);
#endif


close(send_sk);
close(recv_sk);
* stat = 1;
return backdata;
}






