发信人: coobear(有一天我飞) 
整理人: zhcharles(2002-02-18 16:16:09), 站内信件
 | 
 
 
/**********************************************************************  
 Function: addtarget  
 
 Purpose:  Adds a new IP address to the list of hosts to watch.  
 **********************************************************************/  
 struct scaninfo *addtarget(addr)  
 u_long addr;  
 {  
     struct scaninfo *si;  
 
     if((si = (struct scaninfo *)malloc(sizeof(struct scaninfo))) == NULL)  
     {  
     perror("malloc scaninfo");  
     exit(-1);  
     }  
     memset(si, 0, sizeof(struct scaninfo));  
     si->addr = addr;  
     si->next = Gsilist;  
     Gsilist = si;  
     return(si);  
 }  
 
 /**********************************************************************  
 Function: process_packet  
 
 Purpose:  Process raw packet and figure out what we need to to with it.  
 
 Pulls the packet apart and stores key data in global areas for reference  
 by other functions.  
 **********************************************************************/  
 void process_packet(pkt, pktlen)  
 u_char *pkt;  
 int pktlen;  
 {  
     struct ethhdr *ep;  
     struct iphdr *ip;  
     static struct align { struct iphdr ip; char buf[PKTLEN]; } a1;  
     u_short off;  
 
     Gtimein = time((time_t *)0);  
     ep = (struct ethhdr *) pkt;  
     if(ntohs(ep->h_proto) != ETH_P_IP)  
     return;  
 
     pkt += sizeof(struct ethhdr);  
     pktlen -= sizeof(struct ethhdr);  
     memcpy(&a1, pkt, pktlen);  
     ip = &a1.ip;  
     Gsaddr = ip->saddr;  
     Gdaddr = ip->daddr;  
 
     if((Gsi = doicare(Gdaddr)) == NULL)  
     return;  
 
     off = ntohs(ip->frag_off);  
     Gisfrag = (off & IP_MF);    /* Set if packet is fragmented */  
     Giplen = ntohs(ip->tot_len);  
     Gid = ntohs(ip->id);  
     pkt = (u_char *)ip + (ip->ihl << 2);  
     Giplen -= (ip->ihl << 2);  
     switch(ip->protocol)  
     {  
     case IPPROTO_TCP:  
         do_tcp(ep, pkt);  
         break;  
     case IPPROTO_UDP:  
         do_udp(ep, pkt);  
         break;  
     case IPPROTO_ICMP:  
         do_icmp(ep, pkt);  
         break;  
     default:  
         break;  
     }  
 }  
 
 /**********************************************************************  
 Function: do_tcp  
 
 Purpose:  Process this TCP packet if it is important.  
 **********************************************************************/  
 void do_tcp(ep, pkt)  
 struct ethhdr *ep;  
 u_char *pkt;  
 {  
     struct tcphdr *thdr;  
     u_short sport, dport;  
 
     thdr = (struct tcphdr *) pkt;  
     if(thdr->th_flags & TH_RST) /* RST generates no response */  
     return;            /* Therefore can't be used to scan. */  
     sport = ntohs(thdr->th_sport);  
     dport = ntohs(thdr->th_dport);  
 
     if(thdr->th_flags & TH_SYN)  
     {  
     if(Gsaddr == Gdaddr && sport == dport)  
     {  
         Gsi->land.atktime = Gtimein;  
         Gsi->land.saddr = Gsaddr;  
         memcpy(Gsi->land.eaddr, ep->h_source, ETH_ALEN);  
     }  
     }  
     addtcp(sport, dport, thdr->th_flags, ep->h_source);  
 }  
 
 /**********************************************************************  
 Function: addtcp  
 
 Purpose:  Add this TCP packet to our list.  
 **********************************************************************/  
 void addtcp(sport, dport, flags, eaddr)  
 u_short sport;  
 u_short dport;  
 u_char flags;  
 u_char *eaddr;  
 {  
     struct pktin *pi, *last, *tpi;  
 
     /* See if this packet relates to other packets already received. */  
 
     for(pi = Gsi->tcpin; pi; pi = pi->next)  
     {  
     if(pi->saddr == Gsaddr && pi->dport == dport)  
     {  
         if(flags == TH_SYN)  
         addfloodinfo(pi, sport);  
         else if((flags & TH_FIN) || (flags & TH_ACK))  
         rmfloodinfo(pi, sport);  
         return;  
     }  
     last = pi;  
     }  
     /* Must be new entry */  
 
     if((tpi = (struct pktin *)malloc(sizeof(struct pktin))) == NULL)  
     {  
     perror("Malloc");  
     exit(-1);  
     }  
     memset(tpi, 0, sizeof(struct pktin));  
     memcpy(tpi->eaddr, eaddr, ETH_ALEN);  
     tpi->saddr = Gsaddr;  
     tpi->sport = sport;  
     tpi->dport = dport;  
     tpi->timein = Gtimein;  
     if(flags == TH_SYN)  
     addfloodinfo(tpi, sport);  
     if(Gsi->tcpin)  
     last->next = tpi;  
     else  
     Gsi->tcpin = tpi;  
 }  
 
 /**********************************************************************  
 Function: addfloodinfo  
 
 Purpose:  Add floodinfo information  
 **********************************************************************/  
 void addfloodinfo(pi, sport)  
 struct pktin *pi;  
 u_short sport;  
 {  
     struct floodinfo *fi;  
 
     fi = (struct floodinfo *)malloc(sizeof(struct floodinfo));  
     if(fi == NULL)  
     {  
         perror("Malloc of floodinfo");  
         exit(-1);  
     }  
     memset(fi, 0, sizeof(struct floodinfo));  
     fi->sport = sport;  
     fi->next = pi->fi;  
     pi->fi = fi;  
 }  
 
 /**********************************************************************  
 Function: rmfloodinfo  
 
 Purpose:  Removes floodinfo information  
 **********************************************************************/  
 void rmfloodinfo(pi, sport)  
 struct pktin *pi;  
 u_short sport;  
 {  
     struct floodinfo *fi, *prev = NULL;  
 
     for(fi = pi->fi; fi; fi = fi->next)  
     {  
     if(fi->sport == sport)  
         break;  
     prev = fi;  
     }  
     if(fi == NULL)  
     return;  
     if(prev == NULL)    /* First element */  
     pi->fi = fi->next;  
     else  
     prev->next = fi->next;  
     free(fi);  
 }  
 
 /**********************************************************************  
 Function: do_udp  
 
 Purpose:  Process this udp packet.  
 
 Currently teardrop and all its derivitives put 242 in the IP id field.  
 This could obviously be changed.  The truly paranoid might want to flag all  
 fragmented UDP packets.  The truly adventurous might enhance the code to  
 track fragments and check them for overlaping boundaries.  
 **********************************************************************/  
 void do_udp(ep, pkt)  
 struct ethhdr *ep;  
 u_char *pkt;  
 {  
     struct udphdr *uhdr;  
     u_short sport, dport;  
 
     uhdr = (struct udphdr *) pkt;  
     if(Gid == 242 && Gisfrag)    /* probable teardrop */  
     {  
     Gsi->teardrop.saddr = Gsaddr;  
     memcpy(Gsi->teardrop.eaddr, ep->h_source, ETH_ALEN);  
     Gsi->teardrop.atktime = Gtimein;  
     }  
     sport = ntohs(uhdr->source);  
     dport = ntohs(uhdr->dest);  
     addudp(sport, dport, ep->h_source);  
 }  
 
 /**********************************************************************  
 Function: addudp  
 
 Purpose:  Add this udp packet to our list.  
 **********************************************************************/  
 void addudp(sport, dport, eaddr)  
 u_short sport;  
 u_short dport;  
 u_char *eaddr;  
 {  
     struct pktin *pi, *last, *tpi;  
 
     for(pi = Gsi->udpin; pi; pi = pi->next)  
     {  
     if(pi->saddr == Gsaddr && pi->dport == dport)  
     {  
         pi->timein = Gtimein;  
         return;  
     }  
     last = pi;  
     }  
     /* Must be new entry */  
 
     if((tpi = (struct pktin *)malloc(sizeof(struct pktin))) == NULL)  
     {  
     perror("Malloc");  
     exit(-1);  
     }  
     memset(tpi, 0, sizeof(struct pktin));  
     memcpy(tpi->eaddr, eaddr, ETH_ALEN);  
     tpi->saddr = Gsaddr;  
     tpi->sport = sport;  
     tpi->dport = dport;  
     tpi->timein = Gtimein;  
     if(Gsi->udpin)  
     last->next = tpi;  
     else  
     Gsi->udpin = tpi;  
 }  
 
 /**********************************************************************  
 Function: do_icmp  
 
 Purpose:  Process an ICMP packet.  
 
 We assume there is no valid reason to receive a fragmented ICMP packet.  
 **********************************************************************/  
 void do_icmp(ep, pkt)  
 struct ethhdr *ep;  
 u_char *pkt;  
 {  
     struct icmphdr *icmp;  
 
     icmp = (struct icmphdr *) pkt;  
     if(Gisfrag)    /* probable ICMP attack (i.e. Ping of Death) */  
     {  
     Gsi->icmpfrag.saddr = Gsaddr;  
     memcpy(Gsi->icmpfrag.eaddr, ep->h_source, ETH_ALEN);  
     Gsi->icmpfrag.atktime = Gtimein;  
     }  
     if(icmp->type == ICMP_ECHOREPLY)  
     Gsi->icmpcnt++;  
     return;  
 }  
 
 /**********************************************************************  
 Function: clear_pkt  
 
 Purpose:  Delete and free space for any old packets.  
 **********************************************************************/  
 void clear_pktin(si)  
 struct scaninfo *si;  
 {  
     struct pktin *pi;  
     struct floodinfo *fi, *tfi;  
     time_t t, t2;  
 
     t = time((time_t *)0);  
     while(si->tcpin)  
     {  
     t2 = t - si->tcpin->timein;  
     if(t2 > Gtimer)  
     {  
         pi = si->tcpin;  
         fi = pi->fi;  
         while(fi)  
         {  
         tfi = fi;  
         fi = fi->next;  
         free(tfi);  
         }  
         si->tcpin = pi->next;  
         free(pi);  
     }  
     else  
         break;  
     }  
     while(si->udpin)  
     {  
     t2 = t - si->udpin->timein;  
     if(t2 > Gtimer)  
     {  
         pi = si->udpin;  
         si->udpin = pi->next;  
         free(pi);  
     }  
     else  
         break;  
     }  
 }  
 
 /**********************************************************************  
 Function: print_info  
 
 Purpose:  Print out any alerts.  
 **********************************************************************/  
 void print_info()  
 {  
     struct pktin *pi;  
     struct addrlist *tcplist = NULL, *udplist = NULL, *al;  
     struct floodinfo *fi;  
     char buf[1024], *eaddr, abuf[32];  
     int i;  
 
     strcpy(abuf, anetaddr(Gsi->addr));  
     if(Greportlevel == REPORTALL || Greportlevel == REPORTDOS)  
     {  
         if(Gsi->teardrop.atktime)  
         {  
         eaddr = ether_ntoa(Gsi->teardrop.eaddr);  
         sprintf(buf, "Possible teardrop attack from %s (%s) against %s",  
             anetaddr(Gsi->teardrop), eaddr, abuf);  
         syslog(LOG_ALERT, buf);  
         memset(&Gsi->teardrop, 0, sizeof(struct atk));  
         }  
         if(Gsi->land.atktime)  
         {  
         eaddr = ether_ntoa(Gsi->land.eaddr);  
         sprintf(buf, "Possible land attack from (%s) against %s",  
             eaddr, abuf);  
         syslog(LOG_ALERT, buf);  
         memset(&Gsi->land, 0, sizeof(struct atk));  
         }  
         if(Gsi->icmpfrag.atktime)  
         {  
         eaddr = ether_ntoa(Gsi->icmpfrag.eaddr);  
         sprintf(buf, "ICMP fragment detected from %s (%s) against %s",  
             anetaddr(Gsi->icmpfrag), eaddr, abuf);  
         syslog(LOG_ALERT, buf);  
         memset(&Gsi->icmpfrag, 0, sizeof(struct atk));  
         }  
         if(Gsi->icmpcnt > Gicmplimit)  
         {  
         sprintf(buf, "ICMP ECHO threshold exceeded, smurfs up.  I saw %d packets\n", Gsi->icmpcnt);  
         syslog(LOG_ALERT, buf);  
         Gsi->icmpcnt = 0;  
         }  
       
     }  
     for(pi = Gsi->tcpin; pi; pi = pi->next)  
     {  
     i = 0;  
     for(fi = pi->fi; fi; fi = fi->next)  
         i++;  
           
     if(Greportlevel == REPORTALL || Greportlevel == REPORTDOS)  
     {  
         if(i > Gsynflood)  
         {  
             eaddr = ether_ntoa(pi->eaddr);  
             sprintf(buf, "Possible SYNFLOOD from %s (%s), against %s.  I saw %d packets\n",  
             anetaddr(pi->saddr), eaddr, abuf, i);  
             syslog(LOG_ALERT, buf);  
         }  
     }  
     for(al = tcplist; al; al = al->next)  
     {  
         if(pi->saddr == al->saddr)  
         {  
         al->cnt++;  
         if(pi->sport == 80)  
             al->wwwcnt++;  
         break;  
         }  
     }  
     if(al == NULL)    /* new address */  
     {  
         al = (struct addrlist *)malloc(sizeof(struct addrlist));  
         if(al == NULL)  
         {  
         perror("Malloc address list");  
         exit(-1);  
         }  
         memset(al, 0, sizeof(struct addrlist));  
         al->saddr = pi->saddr;  
         al->cnt = 1;  
         if(pi->sport == 80)  
         al->wwwcnt = 1;  
         al->next = tcplist;  
         tcplist = al;  
         }  
     }  
     if(Greportlevel == REPORTALL || Greportlevel == REPORTSCAN)  
     {  
         for(al = tcplist; al; al = al->next)  
         {  
         if((al->cnt - al->wwwcnt) > Gportlimit || al->wwwcnt > Gwebcount)  
         {  
             sprintf(buf, "Possible TCP port scan from %s (%d ports) against %s\n",  
             anetaddr(al->saddr), al->cnt, abuf);  
             syslog(LOG_ALERT, buf);  
         }  
         }  
 
         for(pi = Gsi->udpin; pi; pi = pi->next)  
         {  
         for(al = udplist; al; al = al->next)  
         {  
             if(pi->saddr == al->saddr)  
             {  
             al->cnt++;  
             break;  
             }  
         }  
         if(al == NULL)    /* new address */  
         {  
             al = (struct addrlist *)malloc(sizeof(struct addrlist));  
             if(al == NULL)  
             {  
             perror("Malloc address list");  
             exit(-1);  
             }  
             memset(al, 0, sizeof(struct addrlist));  
             al->saddr = pi->saddr;  
             al->cnt = 1;  
             al->next = udplist;  
             udplist = al;  
         }  
         }  
         for(al = udplist; al; al = al->next)  
         {  
         if(al->cnt > Gportlimit)  
         {  
             sprintf(buf, "Possible UDP port scan from %s (%d ports) against %s\n",  
             anetaddr(al->saddr), al->cnt, abuf);  
             syslog(LOG_ALERT, buf);  
         }  
         }  
     }  
 
     while(tcplist)  
     {  
     al = tcplist->next;  
     free(tcplist);  
     tcplist = al;  
     }  
     while(udplist)  
     {  
     al = udplist->next;  
     free(udplist);  
     udplist = al;  
     }  
 }  
 
 /************************************************************************  
 Function:  anetaddr  
 
 Description:  
 
 Another version of the intoa function.  
 ************************************************************************/  
 
 char *anetaddr(addr)  
 u_long addr;  
 {  
     u_long naddr;  
     static char buf[16];  
     u_char b[4];  
     int i;  
 
     naddr = ntohl(addr);  
     for(i = 3; i >= 0; i--)  
     {  
         b[i] = (u_char) (naddr & 0xff);  
         naddr >>= 8;  
     }  
     sprintf(buf, "%d.%d.%d.%d", b[0], b[1], b[2], b[3]);  
     return(buf);  
 }  
 
 /************************************************************************  
 Function:  initdevice  
 
 Description: Set up the network device so we can read it.  
 
 **************************************************************************/  
 initdevice(fd_flags, dflags)  
 int fd_flags;  
 u_long dflags;  
 {  
     struct ifreq ifr;  
     int fd, flags = 0;  
 
     if((fd = socket(PF_INET, SOCK_PACKET, htons(0x0003))) < 0)  
     {  
     perror("Cannot open device socket");  
     exit(-1);  
     }  
 
     /* Get the existing interface flags */  
 
     strcpy(ifr.ifr_name, Gdevice);  
     if(ioctl(fd, SIOCGIFFLAGS, &ifr) < 0)  
     {  
     perror("Cannot get interface flags");  
     exit(-1);  
     }  
 
     ifr.ifr_flags |= IFF_PROMISC;  
     if(ioctl(fd, SIOCSIFFLAGS,  &ifr) < 0)  
     {  
     perror("Cannot set interface flags");  
     exit(-1);  
     }  
       
     return(fd);  
 }  
 
 /************************************************************************  
 Function:  readdevice  
 
 Description: Read a packet from the device.  
 
 **************************************************************************/  
 u_char *readdevice(fd, pktlen)  
 int fd;  
 int *pktlen;  
 {  
     int cc = 0, from_len, readmore = 1;  
     struct sockaddr from;  
     static u_char pktbuffer[PKTLEN];  
     u_char *cp;  
 
     while(readmore)  
     {  
     from_len = sizeof(from);  
     if((cc = recvfrom(fd, pktbuffer, PKTLEN, 0, &from, &from_len)) < 0)  
     {  
         if(errno != EWOULDBLOCK)  
         return(NULL);  
     }  
     if(strcmp(Gdevice, from.sa_data) == 0)  
         readmore = 0;  
     }  
     *pktlen = cc;  
     return(pktbuffer);  
 }  
 
 /*************************************************************************  
 Function: ether_ntoa  
 
 Description:  
 
 Translates a MAC address into ascii.  This function emulates  
 the ether_ntoa function that exists on Sun and Solaris, but not on Linux.  
 It could probably (almost certainly) be more efficent, but it will do.  
 *************************************************************************/  
 char *ether_ntoa(etheraddr)  
 u_char etheraddr[ETH_ALEN];  
 {  
     int i, j;  
     static char eout[32];  
     char tbuf[10];  
 
     for(i = 0, j = 0; i < 5; i++)  
     {  
     eout[j++] = etheraddr[i] >> 4;  
     eout[j++] = etheraddr[i] & 0xF;  
     eout[j++] = ':';  
     }  
     eout[j++] = etheraddr[i] >> 4;  
     eout[j++] = etheraddr[i] & 0xF;  
     eout[j++] = '\0';  
     for(i = 0; i < 17; i++)  
     {  
     if(eout[i] < 10)  
         eout[i] += 0x30;  
     else if(eout[i] < 16)  
         eout[i] += 0x57;  
     }  
     return(eout);  
 }  
 /*至少要加入一个linux/sockios.h的头文件--在我的linux box中,我还改了netinet/tcp.h ,它才肯跑……:( *********************/ 
 
 
  ---- 喔,你是智慧之石,你是投石器之石
 
 你是击碎星辰之人
 
 你将自己高高地投出
 
     | 
 
 
 |