/*
 *	        	UPsCaN - by psychoid
 *
 *             you need to be root for running this :P
 */


#include <stdio.h>
#include <fcntl.h>
#include <netdb.h>
#include <signal.h>
#include <linux/sockios.h>
#include <sys/time.h>
#include <nessus/net/bpf.h>
#include <pcap.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <errno.h>
#include <string.h>
#include <getopt.h>
#include <setjmp.h>

#define TH_FIN  0x01
#define TH_SYN  0x02
#define TH_RST  0x04
#define TH_PUSH 0x08
#define TH_ACK  0x10
#define TH_URG  0x20

#define DEBUG_NET 0
#define DEBUG_PARSE 0
#define DEBUG_CHECKOS 0

#define ALARM_PCAP 2
#define ALARM_BLOCKING_IO 3

int tcpconnect (unsigned long sip,unsigned long ip, unsigned short port, unsigned short timeout, unsigned short iiport, char *param, FILE *output);

char deviceglobal[100];
u_long myip;
u_long microsoft;
int iiport;
int delay;

struct tcphdr
{
    u_int16_t th_sport;         /* source port */
    u_int16_t th_dport;         /* destination port */
    u_int32_t th_seq;             /* sequence number */
    u_int32_t th_ack;             /* acknowledgement number */
    u_int8_t th_x2:4;           /* (unused) */
    u_int8_t th_off:4;          /* data offset */
    u_int8_t th_flags;
    u_int16_t th_win;           /* window */
    u_int16_t th_sum;           /* checksum */
    u_int16_t th_urp;           /* urgent pointer */
};                                                                                                  

struct ifmap
{
    unsigned long mem_start;
    unsigned long mem_end;
    unsigned short base_addr;
    unsigned char irq;
    unsigned char dma;
    unsigned char port;
};

struct ifreq
{
#define IFHWADDRLEN	 6
#define IFNAMSIZ	 16
    union
    {
	char ifrn_name[IFNAMSIZ];
    } ifr_ifrn;
    
    union {
	struct sockaddr ifru_addr;
	struct sockaddr ifru_dstaddr;
	struct sockaddr ifru_broadaddr;
	struct sockaddr ifru_netmask;
	struct sockaddr ifru_hwaddr;
	short  ifru_flags;
	int    ifru_metric;
	int    ifru_mtu;
	struct ifmap ifru_map;
	char ifru_slave[IFNAMSIZ];
	caddr_t ifru_data;
    } ifr_ifru;
};

#define ifr_name 	ifr_ifrn.ifrn_name
#define ifr_hwaddr 	ifr_ifru.ifru_hwaddr
#define ifr_addr	ifr_ifru.ifru_addr
#define ifr_dstaddr	ifr_ifru.ifru_dstaddr
#define ifr_broadaddr	ifr_ifru.ifru_broadaddr
#define ifr_netmask	ifr_ifru.ifru_netmask
#define ifr_flags	ifr_ifru.ifru_flags
#define ifr_metric	ifr_ifru.ifru_metric
#define ifr_mtu		ifr_ifru.ifru_mtu
#define ifr_map		ifr_ifru.ifru_map
#define ifr_slave	ifr_ifru.ifru_slave
#define ifr_data	ifr_ifru.ifru_data	

struct ifconf
{
    int	ifc_len;
    union
    {
	caddr_t ifcu_buf;
	struct ifreq * ifcu_req;    
    
    } ifc_ifcu;
};

#define ifc_buf ifc_ifcu.ifcu_buf
#define ifc_req ifc_ifcu.ifcu_req

pcap_t *pcap_global_descriptor;
static int offset;

int
startpcap (void)
{
  char errbuf[1028];
  int datalink;
  struct pcap_pkthdr useless;
  if (!deviceglobal || !strcmp (deviceglobal, "default")) {
    strcpy(deviceglobal,pcap_lookupdev (errbuf));
   }
  if (!deviceglobal)
    {
      printf ("Error getting device - %s\n", errbuf);
      exit (1);
    }
  pcap_global_descriptor = pcap_open_live (deviceglobal, 10000, 0, 1000, errbuf);
  if (pcap_global_descriptor == NULL)
    {
      printf ("error opening pcap: %s\n", errbuf);
      printf ("Please enter a valid device (e.g. ppp0 or eth0\n");
      exit (1);
    }

  datalink = pcap_datalink (pcap_global_descriptor);
  bzero (&useless, sizeof (struct pcap_pkthdr));
  switch (datalink)
    {
    case DLT_EN10MB:
      offset = 14;
      break;
    case DLT_NULL:
    case DLT_PPP:
      offset = 4;
      break;
    case DLT_SLIP:
      offset = 16;
      break;
    case DLT_RAW:
      offset = 0;
      break;
    case DLT_SLIP_BSDOS:
    case DLT_PPP_BSDOS:
      offset = 24;
      break;
    case DLT_ATM_RFC1483:
      offset = 8;
      break;
    case DLT_IEEE802:
      offset = 22;
      break;
    default:
      fprintf (stderr, "unknown datalink type (%d)", datalink);
      return (0);
    }
  return 1;
}

void
endpcap (void)
{
  pcap_close (pcap_global_descriptor);
}

char
 *
rlookup (u_long ip)
{
  static char hostname[256];
  struct hostent *host;
  struct sockaddr_in addr;

  addr.sin_addr.s_addr = ip;

  host = gethostbyaddr ((char *) &addr.sin_addr, sizeof (addr.sin_addr), AF_INET);

  if (host == NULL)
    snprintf (hostname,256, "%s\0", inet_ntoa (ip));
  else
    snprintf (hostname, sizeof (hostname), "%s\0", host->h_name);

  return hostname;
}

int recvtcp( char *buf, int sizeofbuffer)
{
    int datalink;
    struct pcap_pkthdr useless;
    
    struct tcppacket
      {
         struct iphdr ip;
	 struct tcphdr tcp;
	 u_char *data;
      
      } *tcppacket;

    tcppacket = (struct tcppacket *) pcap_next (pcap_global_descriptor, &useless);
    (char *) tcppacket += offset;

/*    fprintf(stdout,"Got Packet.. LEN: %d - FROM: %s - FROMPORT: %d - TOPORT: %d\n",
            ntohs(tcppacket->ip.tot_len),rlookup(tcppacket->ip.saddr),
	    ntohs(tcppacket->tcp.th_sport),ntohs(tcppacket->tcp.th_dport));*/

    if (ntohs(tcppacket->ip.tot_len) > sizeofbuffer -1)
       return 0;
    memcpy(buf,tcppacket,ntohs(tcppacket->ip.tot_len));
    return 1;
}

u_long getlocalip(void)
{
    int f, count, traverse;
    struct sockaddr_in *blob;
    char buf[512];
    struct ifreq *i;
    struct ifconf ic;
    f = socket(AF_INET,SOCK_STREAM,0);
    ic.ifc_len = 512;
    ic.ifc_buf = buf;
    ioctl(f,SIOCGIFCONF, (char *) &ic);
    i = ic.ifc_req;
    count = ic.ifc_len / sizeof(struct ifreq);
    for (traverse = 0; traverse < count; traverse++)
    {
	ioctl(f,SIOCGIFADDR,(char *) &i);
	blob = (struct sockaddr_in *) & i->ifr_ifru.ifru_addr;
	if (!strcmp(i->ifr_name,deviceglobal))
	   return blob->sin_addr.s_addr;
	i++;
    }
    return 0x0;
}

unsigned short
in_cksum (unsigned short *ptr, int nbytes)
{

  register long sum;
  u_short oddbyte;
  register u_short answer;

  sum = 0;
  while (nbytes > 1)
    {
      sum += *ptr++;
      nbytes -= 2;
    }

  if (nbytes == 1)
    {
      oddbyte = 0;
      *((u_char *) & oddbyte) = *(u_char *) ptr;
      sum += oddbyte;
    }

  sum = (sum >> 16) + (sum & 0xffff);
  sum += (sum >> 16);	
  answer = ~sum;
  return (answer);
}



unsigned long int
lookup (char *hostname)
{
  struct hostent *name;
  unsigned long int address;

  if ((address = inet_addr (hostname)) != -1)
    return address;
  if ((name = gethostbyname (hostname)) == NULL)
    return -1;

  memcpy (&address, name->h_addr, name->h_length);
  return address;
}


struct igmp
{
        unsigned char igmp_type;
        unsigned char igmp_code;
        unsigned short igmp_cksum;
        struct in_addr igmp_group;
};

int iamchild=0;

int send_raw_igmp(unsigned long fromip,unsigned long host)
{
 int nsock,cnt=0;
 char pkt[45], *data;
 struct ip *nip;
 struct igmp *nigmp;
 struct sockaddr_in s_addr_in;
 unsigned long srcaddr;
 int pd=0;
 int sze=45;

  if((nsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1) 
       { printf("no raw socket\n"); exit(0); }

 memset(&s_addr_in, 0, sizeof(s_addr_in));
 memset(pkt, 0, sze);

 nip = (struct ip *) pkt;
 nigmp = (struct igmp *) (pkt + sizeof(struct ip));
 data = (char *)(pkt + sizeof(struct ip) + sizeof(struct igmp));
 memset(data, '*', 45-(sizeof(struct ip) + sizeof(struct igmp)));

 s_addr_in.sin_addr.s_addr = host;
 srcaddr=fromip;

 nip->ip_v  = 4;
 nip->ip_hl  = 5;
 nip->ip_tos  = 0;
 nip->ip_id  = 69;
 nip->ip_ttl = 255;
 nip->ip_p  = IPPROTO_IGMP;
 nip->ip_sum  = 0;
 nip->ip_dst.s_addr = s_addr_in.sin_addr.s_addr;
 nigmp->igmp_type = 2;
 nigmp->igmp_code = 31;
 nigmp->igmp_cksum = 0;
 nigmp->igmp_group.s_addr = srcaddr;
 nip->ip_src.s_addr = srcaddr;
 nip->ip_len  = 45;
 sendto(nsock, pkt, 45, 0, (struct sockaddr *) &s_addr_in, sizeof(s_addr_in));
 usleep(delay);
 shutdown(nsock, 2);
 close(nsock);
}

int
ip_igmpscan (FILE *inr)
{
  char bufx[200];
  int cnt;
  int pd;
  int imps;
  u_long dest;
  int nsock;
  cnt=0;
  while (fgets(bufx,sizeof(bufx),inr)) {
      sscanf(bufx,"%s\n",bufx);
      dest = inet_addr (bufx);
      if (dest != -1) send_raw_igmp (myip, dest);
      usleep(delay);
  }
  send_raw_igmp(myip,inet_addr("206.252.191.1"));
}

int ip_receive (FILE *outm)
{
  int timer = 0, count = 0, portcount = 0;
  char readbuf[2048];
  u_long inip;
  struct ip *nip;
  struct tcppacket
    {
      struct iphdr ip;
      struct tcphdr tcp;
      char data[2000];
    }
   *tcppacket;
  while (1)
    {
      bzero (readbuf, sizeof (readbuf));
      if (recvtcp (readbuf, 2000))
	{
	    nip=(struct ip *)tcppacket;
	    tcppacket = (struct tcppacket *) readbuf;
    	    if (myip != tcppacket->ip.saddr) {
		if (nip->ip_p==IPPROTO_ICMP || nip->ip_p==IPPROTO_IGMP) {
		   if (tcppacket->ip.saddr==inet_addr("206.252.191.1"))
		       return 0x0;
		   fprintf(outm,"%s\n",inet_ntoa(tcppacket->ip.saddr));
		   fprintf(stdout,"%s: alive\n",inet_ntoa(tcppacket->ip.saddr));
		}
	    }	
	}
    }
end:
return 0;
}

int main (int argc, char **argv)
{
    int pid;
    FILE *infile;
    FILE *outfile;
    char param[400];
    char tempfx[300];
    char tempf[300];
    char ports[600];
    struct sigaction alarmaction;
    FILE *tout;
    char bufx[400];
    u_long dest;
    int sck;
    char *ept;
    char *upt;
    bzero(&alarmaction,sizeof(struct sigaction));
    fprintf(stdout,"\nUpScan 1.0 by psychoid/tCl\n\n",argv[0]);
    if (argc < 5) {
       fprintf(stdout,"Usage: %s infile outfile device(=ppp0/eth0) delay\n",argv[0]);
       fprintf(stdout,"delay depends on your connection speed. dialup = 500, t1 = 100, t3 = 50..\n");
       fprintf(stdout,"infile must be List of numerical ips\n\n");	
       fprintf(stdout,"Results will be in outfile\n");	
       exit(0x0);
    }
    delay=atoi(argv[4]);
    if (delay==0) delay=1; /* well, at least one tick */
    snprintf(deviceglobal,sizeof(deviceglobal),"%s",argv[3]);
    myip =getlocalip();
    if (myip == 0) {
       fprintf(stdout,"No IP found for device %s\n",deviceglobal);
    }    
    fprintf(stdout,"My IP : %s\n",rlookup(myip));
    fprintf(stdout,"Using File %s as input, writing to %s.\n",argv[1],argv[2]);
    fprintf(stdout,"\nStarting: Sending IGMPs\n\n");
    snprintf(tempf,sizeof(tempf),"%s",argv[2]);    
/*    alarmaction.sa_handler = pcap_alarm_handler;
    alarmaction.sa_flags = 0;
    sigaction(SIGALRM,&alarmaction,NULL);*/
    startpcap ();
    pid=fork();
    if (pid < 0) {
       printf("Could not fork.. breaking\n");
       exit (0x0);
    }
    if (pid==0) {
	if ((infile = fopen(argv[1],"r")) == NULL) {
           fprintf(stdout,"Cannot open %s, aborting..\n",argv[1]);
	}
       	ip_igmpscan(infile);
        fclose(infile);
        exit(0x0);
    }
    if (pid>0) {
	if ((tout = fopen(tempf,"w")) == NULL) {
           fprintf(stdout,"Cannot open %s, aborting..\n",argv[1]);
	}
	ip_receive(tout);
        fclose(tout);
    }
    endpcap ();
    exit(0x0);
}
