/*============================================================================= Ethernet Packet Sniffer 'GreedyDog' Version 1.30 The Shadow Penguin Security (http://shadowpenguin.backsection.net) Written by UNYUN (shadowpenguin@backsection.net) [compile] gcc gdd.c -lnsl -D[OSNAME] or gcc gdd.c -D[OSNAME] ([OSNAME] = IRIX or SOLARIS or LINUX or FREEBSD) [ex] gcc gdd.c -lnsl -DSOLARIS ============================================================================= */ #include #include #include #ifndef FREEBSD #include #endif #include #include #include #ifdef SUNOS4 #include #include #include #include #include #include #include #include #endif #ifdef LINUX #include #define __FAVOR_BSD #endif #ifdef FREEBSD #include #include #include #include #include #include #endif #ifdef IRIX #include #include #include #include #endif #ifdef SOLARIS #include #include #include #include #include #include #endif #include #include #include #ifdef SUNOS4 /*--------< SUN OS4 用 パケットキャプチャ関連定数 >-----------*/ #define NIT_DEV "/dev/nit" /* NITデバイス名 */ #define DEFAULT_NIC "le0" /* NICデバイス名 */ #define CHUNKSIZE 4096 /* チャンクサイズ */ #endif #ifdef LINUX /*--------< LINUX 用 パケットキャプチャ関連定数 >-------------*/ #define NIT_DEV "" #define DEFAULT_NIC "eth0" /* NICデバイス名 */ #define CHUNKSIZE 32000 /* チャンクサイズ */ #endif #ifdef FREEBSD /*--------< FreeBSD 用 パケットキャプチャ関連定数 >-----------*/ #define NIT_DEV "/dev/bpf" /* NITデバイス名 */ #define DEFAULT_NIC "ed0" /* NICデバイス名 */ #define CHUNKSIZE 32000 /* チャンクサイズ */ #endif #ifdef IRIX /*-----------< IRIX 用 パケットキャプチャ関連定数 >--------------*/ #define NIT_DEV "" #define DEFAULT_NIC "" #define CHUNKSIZE 60000 /* チャンクサイズ */ #define ETHERHDRPAD RAW_HDRPAD(sizeof(struct ether_header)) #endif #ifdef SOLARIS /*--------< Solaris 用 パケットキャプチャ関連定数 >-----------*/ #define NIT_DEV "/dev/hme" /* NITデバイス名 */ #define DEFAULT_NIC "" #define CHUNKSIZE 32768 /* チャンクサイズ */ #endif #define S_DEBUG /* DEBUGフラグ */ #define SIZE_OF_ETHHDR 14 /* Length of Thernet Hdr */ #define LOGFILE "./snif.log" /* 保存ログファイル名 */ #define TMPLOG_DIR "/tmp/" /* 臨時ログファイルdir */ struct conn_list{ /*------< 接続テーブルリスト >-----------------------------*/ struct conn_list *next_p; /* 次のElementへのポインタ */ char sourceIP[16],destIP[16]; /* 元、先のIPアドレス */ unsigned long sourcePort,destPort; /* 元、先のポート番号 */ }; struct conn_list *cl; /* 接続テーブルリスト */ struct conn_list *org_cl; /* clの先頭アドレス */ /************************************************ NICをPROMISCUSモードに設定する [Input] nit_dev : NITデバイス名(SUNOSのみ有効) nic_name : NICデバイス名 [Output] -1 : PACKETソケット作成不可 -2 : デバイス状態フラグ取得不可 -3 : 状態フラグセット不可 それ以外 : Socket ************************************************ */ #ifdef SOLARIS int strgetmsg(fd, ctlp, flagsp, caller) int fd; struct strbuf *ctlp; int *flagsp; char *caller; { int rc; static char errmsg[80]; *flagsp = 0; if ((rc=getmsg(fd,ctlp,NULL,flagsp))<0) return(-2); if (alarm(0)<0) return(-3); if ((rc&(MORECTL|MOREDATA))==(MORECTL|MOREDATA)) return(-4); if (rc&MORECTL) return(-5); if (rc&MOREDATA) return(-6); if (ctlp->lendl_primitive != DL_OK_ACK) return(-3); pr.dl_primitive=DL_PROMISCON_REQ; pr.dl_level=DL_PROMISC_PHYS; c.maxlen = 0; c.len=sizeof(dl_promiscon_req_t); c.buf=(char *)≺ if (putmsg(sock,&c,NULL,0)<0) return(-4); c.maxlen=CHUNKSIZE; c.len=0; c.buf=(void *)buf; strgetmsg(sock,&c,&flags,"dlokack"); dp=(union DL_primitives *)c.buf; if (dp->dl_primitive != DL_OK_ACK) return(-5); bind_req.dl_primitive=DL_BIND_REQ; bind_req.dl_sap=0x800; bind_req.dl_max_conind=0; bind_req.dl_service_mode=DL_CLDLS; bind_req.dl_conn_mgmt=0; bind_req.dl_xidtest_flg=0; c.maxlen=0; c.len=sizeof(dl_bind_req_t); c.buf=(char *)&bind_req; if (putmsg(sock,&c,NULL,0)<0) return(-6); c.maxlen=CHUNKSIZE; c.len=0; c.buf=(void *)buf; strgetmsg(sock,&c,&flags,"dlbindack"); dp=(union DL_primitives *)c.buf; if (dp->dl_primitive != DL_BIND_ACK) return(-7); si.ic_cmd=DLIOCRAW; si.ic_timout=-1; si.ic_len=0; si.ic_dp=NULL; if (ioctl(sock, I_STR, &si)<0) return(-8); if (ioctl(sock,I_FLUSH,FLUSHR)<0) return(-9); #endif return(sock); } /************************************************ 接続テーブルリストclの内容を表示(DEBUG用) ************************************************ */ void show_connection_table() { struct conn_list *ncl; int i; #ifdef S_DEBUF return; #endif ncl=org_cl; printf("\n>\n"); printf("No. SrcIP SrcPort DstIP DstPort\n"); for (i=0;;i++){ if (ncl->next_p==NULL) break; printf("%-5d %-16s %-5d -> %-16s %-5d\n",i, ncl->sourceIP, ncl->sourcePort, ncl->destIP, ncl->destPort); ncl=ncl->next_p; } printf("\n"); } /************************************************ パケット中の表示可能文字だけをファイルに書く [Input] data : パケット len : パケット長 fp : ログファイルポインタ ************************************************ */ void printable_fwrite(data,len,fp) char *data; int len; FILE *fp; { int i; for (i=0;i--------------------------*/ if (ip_header->ip_p==IPPROTO_TCP){ #ifdef SOLARIS iph_len=4*(packet[SIZE_OF_ETHHDR]&0x0f); tcph_len=4*(packet[SIZE_OF_ETHHDR+iph_len+12]>>4); tcp_header = (struct tcphdr *)((char *)ip_header+iph_len); #else iph_len=(ip_header->ip_hl)*4; tcp_header = (struct tcphdr *)((char *)ip_header+iph_len); tcph_len=(tcp_header->th_off)*4; #endif tcp_data = (char *)tcp_header+tcph_len; /*-------< ログ対象ポートかどうか検査 >-------------------*/ for (i=0;;i++){ if (snif_port[i]==-1) return; if (tcp_header->th_dport==htons(snif_port[i]) || tcp_header->th_sport==htons(snif_port[i])) break; } /*-------< ヘッダ中の有用データ抽出 >---------------------*/ len_data = ntohs(ip_header->ip_len)-iph_len-tcph_len; sourcePort = ntohs(tcp_header->th_sport); destPort = ntohs(tcp_header->th_dport); memcpy(&ia,&(ip_header->ip_src),sizeof(struct in_addr)); strcpy(sourceIP,(char *)inet_ntoa(ia)); memcpy(&ia,&(ip_header->ip_dst),sizeof(struct in_addr)); strcpy(destIP,(char *)inet_ntoa(ia)); /*-------< 3-wayのSTEP-1 SYNでの処理 >--------------------*/ if (tcp_header->th_flags & TH_SYN && !(tcp_header->th_flags & TH_ACK)){ /*---< Connectionテーブルに情報をセット >-------------*/ if ((cl->next_p=(struct conn_list *)malloc(sizeof(struct conn_list)))==NULL){ printf("Can not allocate memory\n"); return; } strcpy(cl->sourceIP ,sourceIP); strcpy(cl->destIP ,destIP); cl->sourcePort = sourcePort; cl->destPort = destPort; cl = cl->next_p; cl->next_p = NULL; show_connection_table(); /*---< ログファイルにConnection情報を書く >----------*/ sprintf(buf,"%s%s.%lu.%s.%lu", TMPLOG_DIR, sourceIP, sourcePort, destIP, destPort); if ((fp=fopen(buf,"w"))==NULL){ printf("Can not append to temp logfile '%s'",buf); return; } fprintf(fp,"\n\n\n"); for (i=0;i<60;i++) putc('=',fp); fprintf(fp,"\n"); fprintf(fp,"CONNECTION %s(%d) -> %s(%d)\n", sourceIP,sourcePort,destIP,destPort); for (i=0;i<60;i++) putc('=',fp); fprintf(fp,"\n"); fclose(fp); return; } /*-------< Connection切断時の処理 >-----------------------*/ if (tcp_header->th_flags & TH_FIN || tcp_header->th_flags & TH_RST){ /*---< 接続テーブルからこの接続を求める >-------------*/ bcl=org_cl; ncl=org_cl->next_p; for (;;){ if (ncl->sourcePort == sourcePort && ncl->destPort == destPort && !strcmp(ncl->sourceIP,sourceIP) && !strcmp(ncl->destIP,destIP)) break; bcl=ncl; if ((ncl=ncl->next_p)==NULL) break; } if (ncl==NULL) return; /*---< 本ログファイルにTEMPログを追加する >----------*/ sprintf(buf,"%s%s.%lu.%s.%lu", TMPLOG_DIR, ncl->sourceIP, ncl->sourcePort, ncl->destIP, ncl->destPort); if ((fp=fopen(LOGFILE,"a"))!=NULL){ if ((fp2=fopen(buf,"r"))!=NULL){ for (;;){ if ((i=fread(fbuf,1,8000,fp2))<=0) break; fwrite(fbuf,1,i,fp); } fclose(fp2); }else printf("Can not read temp logfile '%s'",buf); fclose(fp); }else printf("Can not append to logfile '%s'",LOGFILE); /*---< TEMPログを消し、接続テーブルから除去する >-----*/ remove(buf); bcl->next_p=ncl->next_p; free(ncl); show_connection_table(); return; } /*-------< 接続テーブルからこの接続を求める >-------------*/ ncl=org_cl->next_p; for (;;){ if (ncl->sourcePort == sourcePort && ncl->destPort == destPort && !strcmp(ncl->sourceIP,sourceIP) && !strcmp(ncl->destIP,destIP)) break; if (ncl->sourcePort == destPort && ncl->destPort == sourcePort && !strcmp(ncl->sourceIP,destIP) && !strcmp(ncl->destIP,sourceIP)) break; if ((ncl=ncl->next_p)==NULL) break; } if (ncl==NULL) return; /*-------< TEMPログファイルに追加する >------------------*/ sprintf(buf,"%s%s.%lu.%s.%lu", TMPLOG_DIR, ncl->sourceIP, ncl->sourcePort, ncl->destIP, ncl->destPort); if ((fp=fopen(buf,"a"))==NULL){ printf("Can not append to temp logfile '%s'",buf); return; } printable_fwrite(tcp_data,len_data,fp); fclose(fp); } } /************************************************ プログラムエントリ ************************************************ */ int main() { static unsigned char packet[CHUNKSIZE]; int sock; int l; #ifdef SUNOS4 unsigned char *buffer_p; struct nit_bufhdr *nit_buffer_header; #endif #ifdef FREEBSD unsigned char *buffer_p; struct bpf_hdr *nit_buffer_header; #endif #ifdef IRIX struct snooppacket { struct snoopheader snoop; char pad[ETHERHDRPAD]; struct ether_header ether; char data[ETHERMTU]; }*sp; #endif #ifdef SOLARIS struct strbuf data; int flags,result; data.buf=packet; data.maxlen=16000; data.len=0; #endif /*-----------< 接続テーブル初期化 >---------------------------*/ if ((cl=(struct conn_list *)malloc(sizeof(struct conn_list)))==NULL){ printf("Can not allocate memory\n"); exit(1); } org_cl = cl; cl->sourcePort = 0; cl->destPort = 0; strcpy(cl->sourceIP ,"Start"); strcpy(cl->destIP ,"Start"); cl->next_p = (struct conn_list *)malloc(sizeof(struct conn_list)); cl = cl->next_p; cl->next_p = NULL; show_connection_table(); /*-----------< NICをPROMISCUSモードに設定する >---------------*/ if ((sock=setnic_promisc(NIT_DEV,DEFAULT_NIC))<0){ switch(sock){ case -1 : printf("Can not create PACKET socket.\n"); break; case -2 : printf("Can not get device status flag.\n"); break; case -3 : printf("Can not set nic to promisc mode.\n"); break; } printf("%d\n",sock); return(-1); } /*-----------< パケットを拾って解析する >---------------------*/ for (;;){ #ifdef SOLARIS result=getmsg(sock,NULL,&data,&flags); if (result==0 || result==MOREDATA || result ==MORECTL) packet_analysis(data.buf,data.len); { #else if ((l=read(sock,packet,sizeof(packet)))>0){ #endif #ifdef SUNOS4 buffer_p = packet; while (buffer_p < packet+l) { nit_buffer_header = (struct nit_bufhdr *)buffer_p; packet_analysis(buffer_p+sizeof(struct nit_bufhdr), nit_buffer_header->nhb_msglen); buffer_p += nit_buffer_header->nhb_totlen; } #endif #ifdef LINUX packet_analysis(packet,l); #endif #ifdef FREEBSD buffer_p = packet; while (buffer_p < packet+l) { nit_buffer_header = (struct bpf_hdr *)buffer_p; packet_analysis(buffer_p+nit_buffer_header->bh_hdrlen, sizeof(packet)-nit_buffer_header->bh_hdrlen); buffer_p += BPF_WORDALIGN(nit_buffer_header->bh_caplen+nit_buffer_header->bh_hdrlen); } #endif #ifdef IRIX sp = (struct snooppacket *)packet; packet_analysis((struct ether_header *)(&(sp->ether)),l); #endif } } }