我們對於進行這類整合行計畫的經驗不多,很感謝成大總計畫給予我們的指導與 協助。本計畫的參與者利用一年的時間,在有限的經費下,做了最大的努力,對 網路攻防上進行研究與開發。由於時間等種種因素,很多技術我們尚不能完全掌 握,而且我們在測試的規模上也不夠擬真。對於這些技術,我們還必需要付出更 出的努力才能達到整合並且自動化的最終目標。
參考文獻
[1] S. M. Bellovin. Security Problems in the TCP/IP Protocol Suite. ACM Computer Communications Review, 19(2):32–48, Apr. 1989.
[2] S. M. Bellovin. ICMP Traceback Messages. Internet Draft:
draft-bellovin-itrace-00.txt, Oct. 2001.
[3] H. Burch and B. Cheswick. Tracing Anonymous Packets to Their Approximate Source. Unpublished paper, Dec. 1999.
[4] S. Deering. Internet protocol, version 6 (ipv6). RFC 2460, Dec. 1998.
[5] P. Ferguson and D. Senie. Network Ingress Filtering: Defeating Denial of Service Attacks Which Employ IP Source Address Spoofing. RFC 2267, Jan.
1998.
[6] R. Govindan and H. Tangmunarunkit. Heuristics for Internet Map Discovery.
In Proceedings of the 2000 IEEE INFOCOM Conference, Tel Aviv, Israel, Mar.
2000.
[7] C. Meadows. A Formal Framework and Evaluation Method for Network Denial of Service. In Proceedings of the 1999 IEEE Computer Security Foundations Workshop, Mordano,Italy, June 1999.
[8] O. Spatscheck and L. Peterson. Defending Against Denial of Service Attacks in Scout. In Proceedings of the 1999 USENIX/ACM Symposium on Operating System Design and Implementation, pages 59–72, Feb. 1999.
[9] R. Stone. CenterTrack: An IP Overlay Network for Tracking DoS Floods.
Proceedings of the 2000 USENIX Security Symposium, Denver, CO, July 2000.
[10] W. Theilmann and K. Rothermel. Dynamic Distance Maps of the Internet. In Proceedings of the 2000 IEEE INFOCOM Conference, Tel Aviv, Israel, Mar.
2000.
[11] Dave Dittrich. Distributed Denial of Service (DDoS) attacks/tools resource page. http://staff.washington.edu/dittrich/misc/ddos/.
[12] Stefan Savage, David Wetherall, Anna Karlin, and Tom Anderson. Practical network support for ip traceback. In Proceedings of the 2000 ACM SIGCOMM Conference, August 2000.
[13] K. Park and H. Lee. On the effectiveness of probabilistic packet marking for IP traceback under denial of service attack. In Proc. IEEE INFOCOM '01, pages 338-347, 2001.
[14] D. Song and A. Perrig. Advanced and authenticated marking schemes for IP traceback. Technical Report UCB/CSD-00-1107, University of California, Berkeley, June 2000.
[15] S. Deering and R. Hinden. Internet protocol, version 6 (IPv6) specification.
RFC 2474, Dec. 1995.
[16] D. Schnackenberg, K. Djahandari, and D. Sterne. Infrastructure for Intrusion Detection and Response. Proceedings of the DARPA Information Survivability Conference and Exposition (DISCEX), Hilton Head Island, SC, January 25-27, 2000.
[17]
J. Postel. Internet Control Message Protocol. RFC 792, Internet Engineering Task Force, September 1981.[18] John Ioannidis, Steven M. Bellovin. Proceedings of Network and Distributed System Security Symposium, Catamaran Resort Hotel San Diego, C alifornia 6-8 February 2002.
[19] Alex C. Snoeren, Craig Partridge, Luis A. Sanchez, Christine E. Jones, Fabrice Tchakountio, Stephen T. Kent, and W. Timothy Strayer. “Hash-Based IP Traceback”. Proceedings of the ACM/SIGCOMM 2001 Conference on Applications, Technologies, Architectures, and Protocols for Computer Communication (SIGCOMM '01), pp. 3-14, San Diego, CA, August 2001.
[20] Alex C. Snoeren, Craig Partridge, Luis A. Sanchez, Christine E. Jones, Fabrice Tchakountio, Beverly Schwartz, Stephen T. Kent, and W. Timothy Strayer.
“Single-Packet IP Traceback”. IEEE/ACM Transactions on Networking (ToN), Volume 10, Number 6, December 2002. Pages 721-734.
[21] SPIE User's Guide http://www.ir.bbn.com/projects/SPIE/UsersGuide.pdf [22] Installing Freebsd, Mysql, and Snort Tutorial
http://www.snort.org/docs/FreeBSD47RELEASE-Snort-MySQLVer1-3.pdf.
計畫成果自評
I. 原訂計畫目標:
本子計畫的目標在研發對應 DoS 及 DDoS 攻擊的追蹤技術,而參與此子 計畫的台大與東華,則分別進行來源追蹤及分流攻擊偵測技術,針對這類攻 擊大流量,攻擊點多的特性,進行技術的研究及系統的實作開發。
II. 研究內容與原計畫相符程度
完全符合。
III. 預期目標達成情況與綜合自評
我們對於分流偵測與來源追蹤技術進行研究與實作,本計畫除了讓參與 計畫的研究生都有了良好的知識與實戰經驗,我們的成果還包括了最後的研 發成果展示,以及資訊安全訓練教材。對於一個整合型計畫,能在不到一年 的時間內達成這樣的成果,我們已盡了最大的努力,也謝謝成大的指導。
附錄 A : ICMP 訊息發送與流量統程式原始碼
(一):產生 ICMP 追蹤封包的程式碼 z icmpd.h
#ifndef __ICMPD_H__
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define MD5KEY "The NBEN Project"
struct stamprecord {
struct in_addr stamper;
struct in_addr ip_src;
struct in_addr ip_dst;
unsigned long tv_sec;
unsigned long tv_usec;
};
#define UDP_DEFAULT_QUERY_PORT 36100
#define UDP_NULL 0
#define UDP_QUERY 1
#define UDP_RESPONSE 2
#define UDP_RESPONSE_NULL 0
#define UDP_RESPONSE_REC_FOUND 1
#define UDP_RESPONSE_REC_NOTFOUND 2
#define UDP_OP_SIGNATURE 0x2be2dd05
struct udpop {
unsigned int signature;
unsigned int magic;
unsigned short opcode;
unsigned short result;
struct in_addr ip_src;
struct in_addr ip_dst;
unsigned char md5sum[16];
};
#endif
z icmpd.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <fcntl.h>
#include <pcap.h>
#include <sys/types.h>
/* md5 */
#ifdef LINUX
#include <openssl/md5.h>
#else
#include <md5.h>
#endif /* ntohs */
#include <netinet/in.h>
/* inet_ntoa */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/* ether_ntoa */
#include <sys/socket.h>
#include <net/ethernet.h>
/* ip header */
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include "icmpd.h"
/* FreeBSD -> Linux */
#ifdef LINUX
#define MD5Init MD5_Init
#define MD5Update MD5_Update
#define MD5Final MD5_Final
#else char*
MD5(unsigned char *input, int len, unsigned char *output) { MD5_CTX md5;
MD5Init(&md5);
MD5Update(&md5, (unsigned char *) input, len);
MD5Final(output, &md5);
return(output);
}
#endif
#define MAXPKTSIZE 1600
#define ICMP_PKTSTAMP 32
pcap_t *p = NULL;
struct in_addr myid = {0};
FILE *logfp = NULL;
/* passing from parameters */
int noconsole = 0;
char *dev = NULL;
char *logfile = NULL;
int logsize = 10000; /* in entries, default 10000 */
int logpos = 0;
int maxlog = 0;
int probability = 1000, magic = 7;
int qport = UDP_DEFAULT_QUERY_PORT;
int qsocket = -1;
extern int errno;
void cbreak(int s) {
fprintf(stderr, "** break\n");
if(logfp) {
u_char icmp_type;
u_char icmp_code;
u_short icmp_sum;
/* private message */
u_int unused;
u_int stamper;
u_int srcip;
if((fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW))==-1) return(-1);
if(setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &optval, sizeof(optval))==-1) { close(fd);
send_raw(struct in_addr ip_dst, u_char *raw, int len) { static int fd = -1;
struct sockaddr_in sin;
if(fd < 0) {
if((fd = init_raw())==-1) {
fprintf(stderr, "raw: cannot init raw socket.\n");
return;
} }
bzero(&sin, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = ip_dst.s_addr;
if(sendto(fd, raw, len, 0, (struct sockaddr*) &sin, sizeof(sin)) < 0) {
fprintf(stderr, "raw: sendto() failed(%d): %s.\n", errno, strerror(errno));
return;
}
#if 0
fprintf(stderr, "raw: send icmp to %s\n", inet_ntoa(ip_dst));
#endif }
unsigned short
in_cksum(unsigned short *addr, int len) { register int sum = 0;
u_short answer = 0;
register u_short *w = addr;
register int nleft = len;
while (nleft > 1) {
*(u_char *)(&answer) = *(u_char *)w ; sum += answer;
return(answer);
}
void
send_icmp(long tv_sec, long tv_usec, struct in_addr ip_src, struct in_addr ip_dst) { u_char buf[MAXPKTSIZE];
struct ip *ip;
struct icmp *icmp;
int pktsize;
pktsize = sizeof(struct ip) + sizeof(struct icmp);
bzero(buf, pktsize);
ip = (struct ip*) buf;
icmp = (struct icmp*) (buf + sizeof(struct ip));
ip->ip_hl = 5; /* 5*4 == 20 bytes */
ip->ip_v = 4;
ip->ip_tos = 0;
#ifdef LINUX
ip->ip_len = htons(pktsize);
#else
ip->ip_len = pktsize; /* in FreeBSD: do NOT use htons() */
#endif
ip->ip_id = rand() % 0x0ffff;
ip->ip_off = 0;
ip->ip_sum = in_cksum((unsigned short *) ip, sizeof(struct ip));
icmp->icmp_type = ICMP_PKTSTAMP;
icmp->icmp_code = 0;
icmp->icmp_sum = 0;
icmp->unused = 0;
icmp->stamper = myid.s_addr;
icmp->srcip = ip_src.s_addr;
icmp->dstip = ip_dst.s_addr;
icmp->tv_sec = tv_sec;
icmp->tv_usec = tv_usec;
/* md5 */
do {
MD5_CTX md5;
MD5Init(&md5);
MD5Update(&md5, (unsigned char *) icmp, sizeof(struct icmp) - 16);
MD5Update(&md5, (unsigned char*) MD5KEY, strlen(MD5KEY));
MD5Final(icmp->md5, &md5);
} while(0);
icmp->icmp_sum = in_cksum((unsigned short *) icmp, sizeof(struct icmp));
send_raw(ip_dst, buf, pktsize);
}
#endif // SEND ICMP
unsigned char *vector = NULL;
void
bloom_filter(unsigned int ip_src, unsigned int ip_dst) {
//printf("enter\n");
int i=0;
static int first = 0;
u_int src_dst_address[2];
u_int output[4];// sizeof(u_int) = 4
if (first == 0) { first = 1;
// allocate 28 bit vector
vector = malloc(1024*1024*256);
if (vector == NULL) {
printf("no enough memory space, so no bloom filter\n");
first = 0;
return;
} }
src_dst_address[0] = ip_src;
src_dst_address[1] = ip_dst;
MD5((unsigned char *)src_dst_address, 2*sizeof(u_int), (unsigned char *)output);
for (i=0; i<4; i++) {
unsigned char *position = vector;
unsigned char mask = 1;
output[i] &= 0x0fffffff;
position += ((output[i])>>3);
mask <<= (output[i] & 0x07);
(*position) |= mask;
} }
int
query_bloom(u_int src, u_int dst) {
int i;
u_int src_dst_address[2];
u_int output[4];// sizeof(u_int) = 4
if(vector) {
src_dst_address[0] = src;
src_dst_address[1] = dst;
MD5((unsigned char *)src_dst_address, 2*sizeof(u_int), (unsigned char *)output);
for (i=0; i<4; i++) {
unsigned char *position = vector;
unsigned char mask = 1;
output[i] &= 0x0fffffff;
position += ((output[i])>>3);
mask <<= (output[i] & 0x07);
if(((*position) & mask)==0)
unsigned short
process_ethernet(u_char *user, const struct pcap_pkthdr *hdr, const u_char *payload) { u_int caplen = hdr->caplen;
//u_int length = hdr->len;
struct ether_header *eptr; /* net/ethernet.h */
u_short ether_type;
if (caplen < ETHER_HDR_LEN) { /* not a ethernet packet */
if(noconsole==0)
fprintf(stdout, "* not an etherned packet, too short\n");
return -1;
}
/* lets start with the ether header... */
eptr = (struct ether_header *) payload;
ether_type = ntohs(eptr->ether_type);
return(ether_type);
}
int process_ip(u_char *user, const struct pcap_pkthdr *hdr, const u_char *payload) { const struct ip *ip;
/* jump pass the ethernet header */
ip = (struct ip*) (payload + sizeof(struct ether_header));
if (hdr->len < sizeof(struct ip)) { /* bad length, packet too short */
//fprintf(stdout, "* not an ip packet, too short\n");
return(-1);
}
if(ip->ip_v != 4) { /* bad version */
//fprintf(stdout, "* bad ip version\n");
return(-1);
}
if(ip->ip_hl < 5) { /* bad header length */
//fprintf(stdout, "* not an ip packet, header too short\n");
return(-1);
}
if(ip->ip_p==IPPROTO_UDP) { struct udphdr *udp;
struct udpop *opdata, oprep;
struct sockaddr_in sin;
udp = (struct udphdr*) (payload + sizeof(struct ether_header) + ((ip->ip_hl) <<
2));
opdata = (struct udpop*) (payload + sizeof(struct ether_header) + ((ip->ip_hl)
<< 2) + sizeof(*udp));
#if 0
if(ntohs(udp->uh_dport) > 2000)
fprintf(stderr, "got UDP from %s: dport=%d len=%d signature=0x%08x!\n", inet_ntoa(ip->ip_src),
ntohs(udp->uh_dport), ntohs(udp->uh_ulen), ntohl(opdata->signature));
#endif
if(ip->ip_dst.s_addr==myid.s_addr) if(ntohs(udp->uh_dport) == qport) { /********************/
int slen = sizeof(sin);
recvfrom(qsocket, &oprep, sizeof(oprep), 0, (struct sockaddr*) &sin,
&slen);
if(ntohs(udp->uh_ulen) == sizeof(struct udpop)+sizeof(struct udphdr)) if(ntohl(opdata->signature) == UDP_OP_SIGNATURE) {
unsigned char md5str[16];
MD5_CTX md5;
MD5Init(&md5);
MD5Update(&md5, (unsigned char *) opdata, sizeof(struct udpop) - 16);
MD5Update(&md5, (unsigned char*) MD5KEY, strlen(MD5KEY));
MD5Final(md5str, &md5);
if(memcmp(md5str, opdata->md5sum, 16)==0) { if(ntohs(opdata->opcode)==UDP_QUERY) {
int ret;
bcopy(opdata, &oprep, sizeof(oprep)-16);
oprep.opcode = htons(UDP_RESPONSE);
if(query_bloom(opdata->ip_src.s_addr, opdata->ip_dst.s_addr) >
0) {
oprep.result = htons(UDP_RESPONSE_REC_FOUND);
} else {
oprep.result = htons(UDP_RESPONSE_REC_NOTFOUND);
}
MD5Init(&md5);
MD5Update(&md5, (unsigned char *) &oprep, sizeof(oprep) - 16);
MD5Update(&md5, (unsigned char*) MD5KEY, strlen(MD5KEY));
MD5Final(md5str, &md5);
#ifndef LINUX
sin.sin_len = sizeof(sin);
#endif
sendto(qsocket, &oprep, sizeof(oprep), 0, (struct sockaddr*)
&sin, sizeof(sin));
ret = htons(oprep.result);
fprintf(stderr, "query 0x%08x->0x%08x from %s, ret=%d (%s).\n", ntohl(opdata->ip_src.s_addr),
ntohl(opdata->ip_dst.s_addr),
inet_ntoa(ip->ip_src), ret,
ret==1 ? "found" : (ret==2 ? "not found" : "unknown"));
} } }
/********************/
}
} else if(ip->ip_p==IPPROTO_ICMP) { struct icmp *icmp;
icmp = (struct icmp*) (payload + sizeof(struct ether_header) + ((ip->ip_hl) <<
2));
if(in_cksum((unsigned short *) icmp, sizeof(struct icmp))==0) if(icmp->icmp_type==ICMP_PKTSTAMP) {
char id[24], srcip[24];
MD5Update(&md5, (unsigned char *) icmp, sizeof(struct icmp) - 16);
MD5Update(&md5, (unsigned char*) MD5KEY, strlen(MD5KEY));
MD5Final(md5strx, &md5);
if(memcmp(md5str, md5strx, 16)==0) {
if(icmp->stamper==myid.s_addr) return(0);
snprintf(id, 23, inet_ntoa(rec.stamper));
snprintf(srcip, 23, inet_ntoa(rec.ip_src));
if(noconsole==0)
snprintf(srcip, 23, inet_ntoa(ip->ip_src));
fprintf(stdout, "%10ld.%-6ld %15s -> %-15s\n", hdr->ts.tv_sec, hdr->ts.tv_usec, srcip, inet_ntoa(ip->ip_dst));
#endif
/* add bloom filter here*/
bloom_filter(ip->ip_src.s_addr, ip->ip_dst.s_addr);
if((rand()%probability)==magic)
send_icmp(hdr->ts.tv_sec, hdr->ts.tv_usec, ip->ip_src, ip->ip_dst);
} while(0);
return(0);
}
void
handler(u_char *user, const struct pcap_pkthdr *hdr, const u_char *payload) { unsigned short type = process_ethernet(user, hdr, payload);
if(type == ETHERTYPE_IP) {
process_ip(user, hdr, payload);
} }
void usage(char *progname) {
fprintf(stderr, "usage: %s -i dev -m myid [-l logfile] [-s logsize] [-p prob] [-q port]
[-x]\n"
"\t-i: specify binding device\n"
"\t-m: specify router identifier\n"
"\t-l: specify log filename\n"
"\t-s: specify log filesize (in entries), default = 10000.\n"
"\t-p: specify generating probability, default = 1/1000.\n"
"\t-q: specify udp query port, default = 36100.\n"
"\t-x: no console output\n", progname);
}
int
main(int argc, char *argv[]) { int ch;
char errbuf[PCAP_ERRBUF_SIZE];
char *progname = argv[0];
srand(time(0));
while((ch = getopt(argc, argv, "i:m:s:l:p:q:x"))!=-1) { switch(ch) {
magic = rand() % probability;
break;
case '?':
fprintf(stderr, "error: no device specified.\n");
usage(progname);
return(-1);
}
if(myid.s_addr==0) {
fprintf(stderr, "error: no id specified.\n");
usage(progname);
return(-1);
}
if((p = pcap_open_live(dev, MAXPKTSIZE, 1, 1000, errbuf))==NULL) { fprintf(stderr, "pcap open failed: %s\n", errbuf);
return(-1);
}
if(qport > 0) {
int fl;
struct sockaddr_in sin;
if((qsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1) { fprintf(stderr, "socket() failed: %s\n", strerror(errno));
return(-1);
}
bzero(&sin, sizeof(sin));
sin.sin_family = AF_INET;
//sin.sin_addr = myid;
sin.sin_port = htons(qport);
if(bind(qsocket, (struct sockaddr*) &sin, sizeof(sin))==-1) {
fprintf(stderr, "bind() on port %d failed: %s\n", qport, strerror(errno));
return(-1);
}
if((fl = fcntl(qsocket, F_GETFL, NULL))==-1)
fl = 0;
fcntl(qsocket, F_SETFL, fl|O_NONBLOCK);
}
if(logfile) {
struct stamprecord rec;
maxlog = logsize * sizeof(rec);
if((logfp = fopen(logfile, "r+"))==NULL) { if((logfp = fopen(logfile, "w"))==NULL) {
fprintf(stderr, "cannot open logfile\n");
goto exit_icmpd;
} }
fprintf(stderr, "logmax: %d\n", maxlog);
fseek(logfp, 0, SEEK_END);
logpos = ftell(logfp);
if(logpos >= maxlog) {
int len;
long last = 0;
fseek(logfp, 0, SEEK_SET);
while((len = fread(&rec, sizeof(rec), 1, logfp)) > 0) { if(rec.tv_sec <= last)
break;
last = rec.tv_sec;
}
logpos = ftell(logfp);
if(logpos > 0 && logpos < maxlog) logpos -= sizeof(rec);
else
logpos = 0;
fseek(logfp, 0, SEEK_SET);
}
fprintf(stderr, "log: starting from %d\n", logpos/sizeof(rec));
}
#if 0
if(errbuf[0]!='\0')
fprintf(stderr, "warning: %s\n", errbuf);
#endif
fprintf(stderr, "dev=%s id[%s] p=1/%d", dev, inet_ntoa(myid), probability);
if(logfp)
fprintf(stderr, " logfile=%s (max=%d)", logfile, logsize);
fprintf(stderr, "%s.\n", noconsole ? ", console disabled" : "");
if(qport > 0)
fprintf(stderr, "enable query on udp port %d\n", qport);
signal(SIGTERM, cbreak);
pcap_loop(p, -1, handler, NULL);
if(logfp)
fclose(logfp);
exit_icmpd:
pcap_close(p);
return(0);
}
(二):查詢封包真正來源的程式碼 z iquery.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <fcntl.h>
#include <sys/types.h>
/* md5 */
#ifdef LINUX
#include <openssl/md5.h>
#else
#include <md5.h>
#endif /* ntohs */
#include <netinet/in.h>
/* inet_ntoa */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "icmpd.h"
/* FreeBSD -> Linux */
#ifdef LINUX
#define MD5Init MD5_Init
#define MD5Update MD5_Update
#define MD5Final MD5_Final
#else char*
MD5(unsigned char *input, int len, unsigned char *output) { MD5_CTX md5;
MD5Init(&md5);
MD5Update(&md5, (unsigned char *) input, len);
MD5Final(output, &md5);
return(output);
}
#endif
extern int errno;
#define MAX_STAMPER 32767
#define MAX_TRIES 3
struct stamper {
struct in_addr id;
int count;
};
int totals = 0;
struct stamper all[MAX_STAMPER];
int
id_comp(const void *a, const void *b) { struct stamper *sa, *sb;
sa = (struct stamper*) a;
sb = (struct stamper*) b;
if(sa->id.s_addr == sb->id.s_addr) return(0);
if(sa->id.s_addr > sb->id.s_addr) return(1);
return(-1);
}
int
c_comp(const void *a, const void *b) { struct stamper *sa, *sb;
sa = (struct stamper*) a;
sb = (struct stamper*) b;
if(sa->count== sb->count) return(0);
if(sa->count < sb->count) return(1);
return(-1);
}
void
add_stamper(unsigned int id) { struct stamper *s, tmp;
tmp.id.s_addr = id;
tmp.count = -1;
if((s = bsearch(&tmp, all, totals, sizeof(struct stamper), id_comp))!=NULL) { s->count++;
} else {
if(totals < MAX_STAMPER) {
all[totals].id.s_addr = id;
all[totals].count = 1;
totals++;
qsort(all, totals, sizeof(struct stamper), id_comp);
} else {
fprintf(stderr, "too much stampers.\n");
} } }
void
dump_stamper(int count) {
int i;
qsort(all, totals, sizeof(struct stamper), c_comp);
fprintf(stdout, "+---+---+---+\n"
"| ## | count | stamper |\n"
"+---+---+---+\n");
for(i = 0; i < totals; i++)
fprintf(stdout, "| %5d | %8d | %-15s |\n", i+1, all[i].count, inet_ntoa(all[i].id));
fprintf(stdout, "+---+---+---+\n");
fprintf(stdout, "+ %8d entries parsed. |\n", count);
fprintf(stdout, "+---+\n");
}
int qsocket = -1;
int
do_query(unsigned int ip_src, unsigned int ip_dst, unsigned int target) {
int i;
struct udpop query, response;
struct sockaddr_in sin, rsin;
if(qsocket==-1) {
struct timeval optval;
if((qsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1) { fprintf(stderr, "socket() failed: %s\n", strerror(errno));
exit(-1);
}
optval.tv_sec = 5;
optval.tv_usec = 0;
setsockopt(qsocket, SOL_SOCKET, SO_RCVTIMEO, &optval, sizeof(optval));
}
query.signature = htonl(UDP_OP_SIGNATURE);
query.magic = rand() & 0xffffffff;
query.opcode = htons(UDP_QUERY);
query.result = htons(UDP_RESPONSE_NULL);
query.ip_src.s_addr = ip_src;
query.ip_dst.s_addr = ip_dst;
do { /* MD5 */
MD5_CTX md5;
MD5Init(&md5);
MD5Update(&md5, (unsigned char *) &query, sizeof(query)-16);
MD5Update(&md5, (unsigned char*) MD5KEY, strlen(MD5KEY));
MD5Final(query.md5sum, &md5);
} while(0);
bzero(&sin, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = target;
sin.sin_port = htons(UDP_DEFAULT_QUERY_PORT);
#ifndef LINUX
sin.sin_len = sizeof(sin);
#endif
for(i = 0; i < MAX_TRIES; i++) { int slen = sizeof(rsin);
if(sendto(qsocket, &query, sizeof(query), 0, (struct sockaddr*) &sin, sizeof(sin))==-1) {
fprintf(stdout, " txx");
continue;
}
bzero(&rsin, sizeof(rsin));
if(recvfrom(qsocket, &response, sizeof(response), 0, (struct sockaddr*) &rsin,
&slen)==-1) {
fprintf(stdout, " rxx");
continue;
}
if(response.signature==htonl(UDP_OP_SIGNATURE) && response.opcode==ntohs(UDP_RESPONSE)
&& response.magic==query.magic) { return(ntohs(response.result));
} }
return(0);
}
int main(int argc, char *argv[]) { int i, ret, count = 0;
unsigned int ip_src, ip_dst;
char *p, *target = NULL;
struct stamprecord rec;
FILE *fp;
if(argc < 3) {
fprintf(stderr, "usage: %s query-pair logfile|target\n", argv[0]);
return(-1);
}
ip_src = ip_dst = 0;
if((p = strtok(argv[1], ":"))!=NULL) { ip_src = inet_addr(p);
if((p = strtok(NULL, ":"))!=NULL) { ip_dst = inet_addr(p);
fprintf(stderr, "cannot get q-src.\n");
return(-1);
}
if((fp = fopen(argv[2], "r"))==NULL) { target = strdup(argv[2]);
if(inet_addr(target)==INADDR_NONE) {
fprintf(stderr, "'%s' is neigher a file nor an invalid address.\n", argv[2]);
return(-1);
while(fread(&rec, sizeof(rec), 1, fp) > 0) { add_stamper(rec.stamper.s_addr);
count++;
}
fclose(fp);
dump_stamper(count);
srand(time(0));
for(i = 0; i < totals; i++) {
fprintf(stdout, "query %s", inet_ntoa(*((struct in_addr *) &ip_src)));
fprintf(stdout, "->%s from ", inet_ntoa(*((struct in_addr *) &ip_dst)));
fprintf(stdout, "%s ...", inet_ntoa(all[i].id));
if((ret = do_query(ip_src, ip_dst, all[i].id.s_addr)) > 0) { if(ret==UDP_RESPONSE_REC_FOUND)
fprintf(stdout, " [FOUND]\n");
else if(ret==UDP_RESPONSE_REC_NOTFOUND) fprintf(stdout, " [NOT FOUND]\n");
else
fprintf(stdout, " [UNKNOWN]\n");
} else {
fprintf(stdout, " [FAILED]\n");
} }
/***********************************/
} else {
fprintf(stdout, "query 0x%08x->0x%08x from %s ...", ntohl(ip_src), ntohl(ip_dst),
target);
if((ret = do_query(ip_src, ip_dst, inet_addr(target))) > 0) { if(ret==UDP_RESPONSE_REC_FOUND)
fprintf(stdout, " [FOUND]\n");
else if(ret==UDP_RESPONSE_REC_NOTFOUND) fprintf(stdout, " [NOT FOUND]\n");
else
fprintf(stdout, " [UNKNOWN]\n");
} else {
fprintf(stdout, " [FAILED]\n");
} }
fprintf(stdout, "done.\n");
return(0);
}
附錄 B: 分流系統程式原始碼
Packet generator
#include <netinet/ip.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/tcp.h>
#include <getopt.h>
#include <sys/types.h>
#include <netdb.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <math.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
inline long getrandom (int, int);
void random_init (void);
unsigned short ip_sum (unsigned short *, int);
unsigned short cksum (unsigned short *, int);
unsigned short checksum (unsigned short *, int);
int isip (char *);
unsigned long resolve (char *);
char rseed[65535];
int rcounter;
int main (int argc, char **argv)
{
unsigned short seqrandom = 1;
unsigned short ackrandom = 1;
unsigned short idrandom =1 ;
unsigned short sportrandom = 1;
unsigned short dportrandom = 1;
u_int16_t urgflag=0x0;
u_int16_t ackflag=0x0;
u_int16_t pshflag=0x0;
u_int16_t rstflag=0x0;
u_int16_t synflag=0x0;
u_int16_t finflag=0x0;
unsigned long count = 1;
unsigned long loop = 0;
unsigned long interval = 200; //200ns
u_int8_t ttl = 0x20;
u_int16_t id = 0x1;
u_int16_t frag = 0x4000; // DF
u_int8_t tos = 0x0;
unsigned long ipsrc = -33511232; // 192.168.0.254
unsigned long ipdst = 184789184; // 192.168.3.11
u_int16_t sport = 1234;
u_int16_t dport = 80;
u_int32_t seq = 0x1;
u_int32_t ack = 0x1020;
int c;
int digit_optind = 0;
unsigned long chsum = 0;
struct sockaddr_in pothead;
struct iphdr *iph;
struct tcphdr *tcph;
int sockfd;
char *packet;
int pktsize = sizeof (struct iphdr) + sizeof (struct tcphdr);
while (1)
{
int this_option_optind = optind ? optind : 1;
int option_index = 0;
static struct option long_options[] = {
{"help", 0, 0, 0},
{"dport", 1, 0, 0},
{"sport", 1, 0, 0},
{"seq", 1, 0, 0},
{"ack", 1, 0, 0},
{"syn", 0, 0, 0},
{"urg", 0, 0, 0},
{"rst", 0, 0, 0},
{"psh", 0, 0, 0},
{"fin", 0, 0, 0},
{0, 0, 0, 0}
};
c = getopt_long (argc, argv, "c:d:f:i:s:p:q:t:v:", long_options, &option_index);
if (c == -1)
break;
switch (c)
{
case 0:
if (strcmp (long_options[option_index].name, "help") == 0)
{
fprintf(stderr,"./transp [--option1] [-option2]\n");
fprintf(stderr,"option1:\n");
fprintf(stderr,"--sport arg : specify the source port\n");
fprintf(stderr,"--dport arg : specify the destination port\n");
fprintf(stderr,"--seq arg : specify the sequence field in TCP header\n");
fprintf(stderr,"--ack arg : specify the acknowledge field in TCP header and enable the ack
flag\n");
fprintf(stderr,"--urg : enable the urg flag in TCP header\n");
fprintf(stderr,"--psh : enable the psh flag in TCP header\n");
fprintf(stderr,"--rst : enable the rst flag in TCP header\n");
fprintf(stderr,"--syn : enable the syn flag in TCP header\n");
fprintf(stderr,"--fin : enable the fin flag in TCP header\n");
fprintf(stderr,"--help arg : you will see this\n");
fprintf(stderr,"option2:\n");
fprintf(stderr,"-c arg : how many packet do you want to transit\n");
fprintf(stderr,"-d arg : specify the destionation IP field in IP header\n");
fprintf(stderr,"-i arg : specify the identificatioin field in IP header\n");
fprintf(stderr,"-s arg : specify the source IP field in IP header\n");
fprintf(stderr,"-p arg : specify the payload length after IP header\n");
fprintf(stderr,"-q [T|R|C] : specify the tos field in IP header\n");
fprintf(stderr," T : stands for max throughput\n");
fprintf(stderr," R : stands for max relibility\n");
fprintf(stderr," C : stands for min cost\n");
fprintf(stderr,"-t arg : specify the ttl field in IP headre\n");
fprintf(stderr,"-v arg : specify the interval of each packet\n");
}
if (strcmp (long_options[option_index].name, "sport") == 0)
{ sport = atoi (optarg);
sportrandom = 0;
}
if (strcmp (long_options[option_index].name, "dport") == 0)
{ dport = atoi (optarg);
dportrandom =0;
}
if (strcmp (long_options[option_index].name, "seq") == 0)
{
seq=atoi (optarg);
seqrandom=0;
}
if (strcmp (long_options[option_index].name, "ack") == 0)
{
ack=atoi(optarg);
ackflag=0x1;
ackrandom=0;
}
if (strcmp (long_options[option_index].name, "syn") == 0)
{
synflag=1;
}
if (strcmp (long_options[option_index].name, "rst") == 0)
{
rstflag=1;
}
if (strcmp (long_options[option_index].name, "psh") == 0)
{
pshflag=1;
}
if (strcmp (long_options[option_index].name, "urg") == 0)
{
urgflag=1;
}
if (strcmp (long_options[option_index].name, "fin") == 0)
{
finflag=1;
}
break;
case 'c':
count = atoi (optarg);
break;
case 'd':
ipdst = resolve (optarg);
break;
case 'f':
if (strncmp (optarg, "R", 1) == 0)
frag = 0x8000;
else if (strncmp (optarg, "D", 1) == 0)
frag = 0x4000;
else if (strncmp (optarg, "M", 1) == 0)
frag = 0x2000;
break;
case 'i':
id = atoi (optarg);
idrandom = 0;
break;
case 's':
ipsrc = resolve (optarg);
break;
case 'p':
pktsize+=atoi(optarg);
break;
case 'q':
if (strncmp (optarg, "D", 1) == 0)
tos = 0x10;
else if (strncmp (optarg, "T", 1) == 0)
tos = 0x08;
else if (strncmp (optarg, "R", 1) == 0)
tos = 0x04;
else if (strncmp (optarg, "C", 1) == 0)
tos = 0x02;
break;
case 't':
ttl = atoi (optarg);
break;
case 'v':
interval = atoi (optarg);
break;
}
}
packet = (char *) malloc (sizeof (char) * pktsize);
sockfd = socket (AF_INET, SOCK_RAW, 255);
iph = (struct iphdr *) (packet);
tcph = (struct tcphdr *) (packet + sizeof (struct iphdr));
memset (packet, 0, pktsize);
iph->version = 4;
iph->ihl = 5;
iph->tos = tos;
iph->tot_len = htons (pktsize);
iph->id = htons (id);
iph->frag_off = htons (frag);
iph->ttl = ttl;
iph->protocol = 0x6;
// iph->saddr = inet_addr ("192.168.0.254");
iph->saddr = ipsrc;
// iph->daddr = inet_addr ("192.168.3.11");
iph->daddr = ipdst;
iph->check = ip_sum ((short int *) &iph, sizeof (iph));
tcph->source = htons (sport);
tcph->dest = htons (dport);
tcph->seq = htonl (seq);
tcph->ack_seq = htonl (ack);
tcph->doff = 5;
tcph->urg=urgflag;
tcph->ack=ackflag;
tcph->psh=pshflag;
tcph->rst=rstflag;
tcph->syn=synflag;
tcph->fin=finflag;
tcph->window = htons (1024);
chsum += htons (tcph->source);
chsum += htons (tcph->dest);
chsum += (short) (htonl (tcph->seq) >> 16);
chsum += (short) (htonl (tcph->seq) & 0x0000ffff);
chsum += (short) (htonl (tcph->ack_seq) >> 16);
chsum += (short) (htonl (tcph->ack_seq) & 0x0000ffff);
chsum += 0x5002;
chsum += htons (tcph->window);
chsum += (short) (htonl (iph->saddr) >> 16);
chsum += (short) (htonl (iph->saddr) & 0x0000ffff);
chsum += (short) (htonl (iph->daddr) >> 16);
chsum += (short) (htonl (iph->daddr) & 0x0000ffff);
chsum += iph->protocol;
chsum += 20;
chsum = (chsum >> 16) + (chsum & 0xffff);
(unsigned short) chsum += (chsum >> 16);
tcph->check = ~htons (chsum) - 512;
pothead.sin_family = AF_INET;
pothead.sin_addr.s_addr = iph->daddr;
setsockopt (sockfd, IPPROTO_IP, IP_HDRINCL, "1", sizeof ("1"));
for (loop = 0; loop < count; loop++)
{
if (seqrandom == 1)
tcph->seq = htonl (getrandom(1,65535));
if (ackrandom == 1)
tcph->ack_seq = htonl (getrandom(1,65535));
if (idrandom == 1)
iph->id = htons (getrandom(1,65535));
if (sportrandom==1)
tcph->source = htons (getrandom(1024,65535));
if (dportrandom ==1)
{
dport = getrandom(1,65535);
tcph->dest = htons (dport);
pothead.sin_port = htons (dport);
}
chsum=0;
chsum += htons (tcph->source);
chsum += htons (tcph->dest);
chsum += (short) (htonl (tcph->seq) >> 16);
chsum += (short) (htonl (tcph->seq) & 0x0000ffff);
chsum += (short) (htonl (tcph->ack_seq) >> 16);
chsum += (short) (htonl (tcph->ack_seq) & 0x0000ffff);
chsum += 0x5002;
chsum += htons (tcph->window);
chsum += (short) (htonl (iph->saddr) >> 16);
chsum += (short) (htonl (iph->saddr) & 0x0000ffff);
chsum += (short) (htonl (iph->daddr) >> 16);
chsum += (short) (htonl (iph->daddr) & 0x0000ffff);
chsum += iph->protocol;
chsum += 20;
chsum = (chsum >> 16) + (chsum & 0xffff);
(unsigned short) chsum += (chsum >> 16);
tcph->check = ~htons (chsum) - 512;
usleep (interval);
sendto (sockfd, packet, pktsize, 0, (struct sockaddr_in *)
&pothead,
sizeof (struct sockaddr_in));
}
free (packet);
exit(0);
}
unsigned short
checksum (addr, len)
unsigned short *addr;
int len;
{
register int nleft = len;
register unsigned short *w = addr;
register int sum = 0;
unsigned short answer = 0;
while (nleft > 1)
{
sum += *w++;
nleft -= 2;
}
if (nleft == 1)
{
*(unsigned char *) (&answer) = *(unsigned char *) w;
sum += answer;
}
return (sum);
}
unsigned short
ip_sum (addr, len)
unsigned short *addr;
int len;
{
register int nleft = len;
register unsigned short *w = addr;
register int sum = 0;
unsigned short answer = 0;
while (nleft > 1)
{
sum += *w++;
nleft -= 2;
}
if (nleft == 1)
{
*(unsigned char *) (&answer) = *(unsigned char *) w;
sum += answer;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
answer = ~sum;
return (answer);
}
unsigned short
cksum (unsigned short *buf, int nwords)
{
unsigned long sum;
for (sum = 0; nwords > 0; nwords--)
sum += *buf++;
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
return ~sum;
}
int
isip (char *ip)
{
int a, b, c, d;
sscanf (ip, "%d.%d.%d.%d", &a, &b, &c, &d);
if (a < 0)
return 0;
if (a > 255)
return 0;
if (b < 0)
return 0;
if (b > 255)
return 0;
if (c < 0)
return 0;
if (c > 255)
return 0;
if (d < 0)
return 0;
if (d > 255)
return 0;
return 1;
}
unsigned long
resolve (char *host)
{
struct hostent *he;
struct sockaddr_in tmp;
if (isip (host))
return (inet_addr (host));
he = (struct hostent *) gethostbyname (host);
if (he)
{
memcpy ((caddr_t) & tmp.sin_addr.s_addr, he->h_addr,
he->h_length);
}
else
return (0);
return (tmp.sin_addr.s_addr);
}
void
random_init (void)
{
int rfd = open ("/dev/urandom", O_RDONLY);
if (rfd < 0)
rfd = open ("/dev/random", O_RDONLY);
rcounter = read (rfd, rseed, 65535);
close (rfd);
}
inline
long
getrandom (int min, int max)
{
if (rcounter < 2)
random_init ();
srand (rseed[rcounter] + (rseed[rcounter - 1] << 8));
rcounter -= 2;
return ((random () % (int) (((max) + 1) - (min))) + (min));
}
Monitor
/* monitor.php */
<?php
include("snmpconf.php");
require("xtpl.p");
$xtpl=New XTemplate("monitor.xtpl");
if (!$_COOKIE[loginsession]) {
$xtpl->parse("main.leftmain.login");
$xtpl->parse("main.leftmain");
} else {
if ($_POST["submit"]) {
switch ($_POST["function"]) { case "settime":
$nodetime=exec("/usr/local/snort-2.0.0/bin/nodetime [email protected]");
$settime=exec("/usr/local/snort-2.0.0/bin/settime root@".$_POST[ip]." ".$nodetime);
break;
case "editrule":
$fd=fopen("/usr/local/snort-2.0.0/bin/editrule","w");
fputs($fd,"#!/usr/bin/expect -f\n");
fputs($fd,"spawn ssh [lrange \$argv 0 0] sed \\'\\n");
for($i=0;$name=checkrule.$i,!empty($$name);$i++) {
if (ereg("^#",$$name)==1) fputs($fd,"s/^.*\\\(include
".str_replace('/','\\\/',str_replace('$','\\$',str_replace("#","",$$name)))."\\\)/#\\\\1/\\n");
else
fputs($fd,"s/^.*\\\(include
".str_replace('/','\\\/',str_replace('$','\\$',$$name))."\\\)/\\\\1/\\n");
}
fputs($fd,"\\' /usr/local/snort-2.0.0/bin/snort.conf >
/usr/local/snort-2.0.0/bin/snort.try\\;command cp /usr/local/snort-2.0.0/bin/snort.try /usr/local/snort-2.0.0/bin/snort.conf\nexpect {\nAre {\nsend
\"yes\\r\"\nexp_continue\n}\nroot@\n{send \"east1121\\r\"}\n}\nexpect root\nexit\n");
fclose($fd);
chmod("/usr/local/snort-2.0.0/bin/editrule",0770);
exec("/usr/local/snort-2.0.0/bin/editrule root@".$_GET[ip]);
exec("/usr/local/snort-2.0.0/bin/restartsnort root@".$_GET[ip]);
break;
case "start":
$snortstate=exec("/usr/local/snort-2.0.0/bin/snortstate root@".$_GET[ip]);
if (ereg("\/snort",$snortstate)>0)
$xtpl->assign(SNORTSTATE,$snortstate."...");
else
exec("/usr/local/snort-2.0.0/bin/startsnort root@".$_GET[ip]);
break;
} }
$xtpl->parse("main.leftmain.logout");
$menu[0][menuname]="test1";
$menu[1][menuname]="manage";
$menu[2][menuname]="time";
$menu[2][menuname]="time";