參考資料 Watcher by hyperion in pharck
一、寫在前面
你如何了解系統是否被攻克?在你發現系統中多了些奇怪的帳號或者某些特洛伊程序時,一切已經太遲了。除非你的機器非常強大,否則你的機會只存在于當你在機器被掃描后、而攻擊發生前的短暫的時間段里。當然你可以用類似于tcp wrappers的程序來保證系統連接的安全,但它并不能監測到stealth掃描或者DOS攻擊,你也可以購買商業版本的入侵監測系統--只要你不嫌貴的話,其實性價比最高的就是從互聯網上獲取類似的免費的軟件,安裝或者改造它以適應你的需求,watcher就是這么一個家伙。
二、功能
watcher檢測所有通過的信息包,并且將它認為是惡意的攻擊行為記錄在syslog中,當前的watcher能夠檢測下列的攻擊行為:
所有的TCP掃描
所有的UDP掃描
Synflood攻擊
Teardrop攻擊
Land攻擊
Smurf攻擊
Ping of death攻擊
所有的參數以及配置都是在命令行給出的,你可以配置它僅僅監視掃描行為或者僅僅監視DOS攻擊。它的監測行為是這樣的:如果在短時間內有超過7個以上的端口收到信息包(不管類型如何),那么這一事件就被當成端口掃描記錄下來。UDP掃描認定的原理也一樣。當watcher在同一端口收到超過8個的syn包沒有帶ack或者fin位的話,就會認定是synflood攻擊事件。如果UDP的碎片包--IP包的id號是242,它就認為是teardrop攻擊,因為發布的攻擊代碼使用的是242的id號--這點存在不足;(。對同一端口的大量TCP SYN包,帶源地址及目標地址的,將被認為是land攻擊,如果有超過5個icmp echo replies在很短時間內出現(時間可以自定義),將記錄為smurf攻擊……
Watcher有三種監測模式,在默認的模式下,它僅僅監測對本臺主機的攻擊行為,第二種模式可以監測在C類子網內的所有主機,第三種模式則可以監測所有能接收到信息包的主機。當你把watcher放在外部主機上時,監測多主機特別有效,當一臺主機的log文件被破壞時,其它主機上還有記錄。
由于watcher把所有的信息包都當成“攻擊”,然后再進行分析,這種判斷是極為粗糙的,可能會誤判,所以在代碼中作者加入了一些過濾的技巧。
比如一些web server上會有漂亮的gif圖片或者flash等玩意兒,而客戶端這時往往會開了多個線程來下載它,這時watcher的規則就會認為這是一次tcp scan,所以作者只好加上了只有超過40個tcp連接才記錄下的的規則--這些都是可定制的。就不詳述了,你可以自行參看下面的代碼。
它的輸出是非常簡單的,每隔10秒它就將可能的攻擊行為記錄在syslog當中,同時源IP以及目標IP甚至相關的信息比如端口號,包的數量等等也將被記錄下來,如果該攻擊行為的IP是假的,那么它同時將記下MAC地址--如果攻擊來自外部,地址將是你本地接收到該包的route的地址,如果攻擊來自內部的話,呵,你可以用自己的方式來"感謝"攻擊者;)
三、程序參數
Watcher是用于linux系統的,通常你只需要在命令行后臺運行它就可以了,它的參數如下:
Usage: watcher [參數]
-d device 將device設定為當前的網卡,默認為第一個non-loopback的interface
-f flood 設定接收到多少不完全的連接后才認為是flood的攻擊
-h 幫助信息
-i icmplimit 設定接收到多少icmp echo replies就認為是smurf攻擊
-m level 可以設定監控的機器,比如subnet為子域中的機器,或者all為所有
-p portlimit 在timeout的限制時間內有多少端口接收到信息包算是一次端口掃描
-r reporttype 如果reporttype設為dos,那么只有拒絕服務攻擊會被記錄,如果是scan的話,只有掃描行為會被記錄,默認則記錄所有東西
-t timeout 每隔timeout的時間就記錄信息包并打印出潛在的攻擊行為
-w webcount 設定我們從80口接收到多少信息包才算是一次端口掃描(cgi)
希望這個小玩意能使你的系統稍微安全一些,但是得警告你的是,系統安全是多方面的,別指望一個應用程序或者什么東西能使你絕對安全--如果你不信,遲早都得重裝系統的;)
----[ 代碼
EX/Watcher.c
/*********************************************************************
Program: watcher
A network level monitoring tool to detect incoming packets indicative ofpotential attacks.This software detects low level packet scanners and several DOS attacks.Its primary use is to detect low level packet scans, since these are usuallydone first to identify active systems and services to mount further attacks.
The package assumes every incoming packet is potentially hostile. Some checksare done to minimize false positives, but on occasion a site may be falselyidentified as having performed a packet scan or SYNFLOOD attack. This usuallyoccurs if a large number of connections are done in a brief time right beforethe reporting timeout period (i.e. when browsing a WWW site with lots of little GIFs, each requiring a connection to download). You can also get false positives if you scan another site, since the targets responses will be viewedas a potential scan of your system.
By default, alerts are printed to SYSLOG every 10 seconds.
***********************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define PKTLEN 96 /* Should be enough for what we want */
#ifndef IP_MF
#define IP_MF 0x2000
#endif
/***** WATCH LEVELS ******/
#define MYSELFONLY 1
#define MYSUBNET 2
#define HUMANITARIAN 3
/***** REPORT LEVELS *****/
#define REPORTALL 1
#define REPORTDOS 2
#define REPORTSCAN 3
struct floodinfo {
u_short sport;
struct floodinfo *next;
};
struct addrlist {
u_long saddr;
int cnt;
int wwwcnt;
struct addrlist *next;
};
struct atk {
u_long saddr;
u_char eaddr[ETH_ALEN];
time_t atktime;
};
struct pktin {
u_long saddr;
u_short sport;
u_short dport;
time_t timein;
u_char eaddr[ETH_ALEN];
struct floodinfo *fi;
struct pktin *next;
};
struct scaninfo {
u_long addr;
struct atk teardrop;
struct atk land;
struct atk icmpfrag;
struct pktin *tcpin;
struct pktin *udpin;
struct scaninfo *next;
u_long icmpcnt;
} ;
struct scaninfo *Gsilist = NULL, *Gsi;
u_long Gmaddr;
time_t Gtimer = 10, Gtimein;
int Gportlimit = 7;
int Gsynflood = 8;
int Gwebcount = 40;
int Gicmplimit = 5;
int Gwatchlevel = MYSELFONLY;
int Greportlevel = REPORTALL;
char *Gprogramname, *Gdevice = "eth0";
/******** IP packet info ********/
u_long Gsaddr, Gdaddr;
int Giplen, Gisfrag, Gid;
/****** Externals *************/
extern int errno;
extern char *optarg;
extern int optind, opterr;
void do_tcp(), do_udp(), do_icmp(), print_info(), process_packet();
void addtcp(), addudp(), clear_pktin(), buildnet();
void doargs(), usage(), addfloodinfo(), rmfloodinfo();
struct scaninfo *doicare(), *addtarget();
char *anetaddr(), *ether_ntoa();
u_char *readdevice();
main(argc, argv)
int argc;
char *argv[];
{
int pktlen = 0, i, netfd;
u_char *pkt;
char hostname[32];
struct hostent *hp;
time_t t;
doargs(argc, argv);
openlog("WATCHER", 0, LOG_DAEMON);
if(gethostname(hostname, sizeof(hostname)) < 0)
{
perror("gethostname");
exit(-1);
}
if((hp = gethostbyname(hostname)) == NULL)
{
fprintf(stderr, "Cannot find own address");
exit(-1);
}
memcpy((char *)&Gmaddr, hp->h_addr, hp->h_length);
buildnet();
if((netfd = initdevice(O_RDWR, 0)) < 0)
exit(-1);
/* Now read packets forever and process them. */
t = time((time_t *)0);
while(pkt = readdevice(netfd, &pktlen))
{
process_packet(pkt, pktlen);
if(time((time_t *)0) - t > Gtimer)
{
/* Times up. Print what we found and clean out old stuff. */
for(Gsi = Gsilist, i = 0; Gsi; Gsi = Gsi->next, i++)
{
clear_pktin(Gsi);
print_info();
Gsi->icmpcnt = 0;
}
t = time((time_t *)0);
}
}
}
/**********************************************************************
Function: doargs
Purpose: sets values from environment or command line arguments. **********************************************************************/
void doargs(argc, argv)
int argc;
char **argv;
{
char c;
Gprogramname = argv[0];
while((c = getopt(argc,argv,"d:f:hi:m:p:r:t:w:")) != EOF)
{
switch(c)
{
case d:
Gdevice = optarg;
break;
case f:
Gsynflood = atoi(optarg);
break;
case h:
usage();
exit(0);
case i:
Gicmplimit = atoi(optarg);
break;
case m:
if(strcmp(optarg, "all") == 0)
Gwatchlevel = HUMANITARIAN;
else if(strcmp(optarg, "subnet") == 0)
Gwatchlevel = MYSUBNET;
else
{
usage();
exit(-1);
}
break;
case p:
Gportlimit = atoi(optarg);
break;
case :
if(strcmp(optarg, "dos") == 0)
Greportlevel = REPORTDOS;
else if(strcmp(optarg, "scan") == 0)
Greportlevel = REPORTSCAN;
else
{
exit(-1);
}
break;
case :
Gtimer = atoi(optarg);
break;
case w:
Gwebcount = atoi(optarg);
break;
default:
usage();
exit(-1);
}
}
}
/**********************************************************************
Function: usage
Purpose: Display the usage of the program **********************************************************************/
void usage()
{
printf("Usage: %s [options]", Gprogramname);
printf(" -d device Use device as the network interface device");
printf(" The first non-loopback interface is the default");
printf(" -f flood Assume a synflood attack occurred if more than");
printf(" flood uncompleted connections are received");
printf(" -h A little help here");
printf(" -i icmplimit Assume we may be part of a smurf attack if more");
printf(" than icmplimit ICMP ECHO REPLIES are seen");
printf(" -m level Monitor more than just our own host.");
printf(" A level of subnet watches all addresses in our");
printf(" subnet and all watches all addresses");
printf(" -p portlimit Logs a portscan alert if packets are received for");
printf(" more than portlimit ports in the timeout period.");
printf(" -r reporttype If reporttype is dos, only Denial Of Service");
printf(" attacks are reported. If reporttype is scan");
printf(" then only scanners are reported. Everything is");
printf(" reported by default.");
printf(" -t timeout Count packets and print potential attacks every");
printf(" timeout seconds");
printf(" -w webcount Assume we are being portscanned if more than");
printf(" webcount packets are received from port 80");
}
/**********************************************************************
Function: buildnet
Purpose: Setup for monitoring of our host or entire subnet.
**********************************************************************/
void buildnet()
{
u_long addr;
u_char *p;
int i;
if(Gwatchlevel == MYSELFONLY) /* Just care about me */
{
(void) addtarget(Gmaddr);
}
else if(Gwatchlevel == MYSUBNET) /* Friends and neighbors */
{
addr = htonl(Gmaddr);
addr = addr & 0xffffff00;
for(i = 0; i < 256; i++)
(void) addtarget(ntohl(addr + i));
}
}
/**********************************************************************
Function: doicare
Purpose: See if we monitor this address
**********************************************************************/
struct scaninfo *doicare(addr)
u_long addr;
{
struct scaninfo *si;
int i;
for(si = Gsilist; si; si = si->next)
{
if(si->addr == addr)
return(si);
}
if(Gwatchlevel == HUMANITARIAN) /* Add a new address, we always care */
{
si = addtarget(addr);
return(si);
}
return(NULL);
}
/**********************************************************************
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
unctions.
**********************************************************************/
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 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",
si->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",
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",
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",
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++] = ;
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 ,它才肯跑……:( *********************/
作者:quack