记得三周前
导师给我个题目: 通过ARP协议解析指定IP的MAC地址
当时我的网络协议方面的知识是一片空白
虽说是网络专业的 不过出于对刻板教育模式的BS 上课从来没听过 要么睡觉 要么看书
突然让我编程实现这个东西 当时非常的茫然
于是赶紧拉了几个仁兄一起研究ARP协议
搞清楚之后又陷入了茫然
因为即便是对协议封包了如指掌 也不知道从何下手去解析它
于是开始上网查资料 泡图书馆
没敢去问导师具体的做法 怕他觉得我无能
天天抱着N百页的《UNIX网络编程》啃
终于了解了网络编程的内幕
自己也搞了现成的代码改了改
但是都是socket套接口之类的服务器/客户端程序
而ARP协议的实现是不需要这些东东的 它是封装在OS中自动实现的
显然 路走错了
前几天去导师那说起这事
他无意中说了句有现成的库函数包可用 叫个libpcap
我如获至宝
呵呵
果然如此
libpcap & libnet 包
一个抓 一个发
都是现成的API函数调用
呵呵
高兴啊~~~
下面放个向指定IP发送ARP请求包的代码
需要libpcap libnet库支持
安装方式见 GOOGLE
/**/
/* send_arp.c
* 编译: #gcc -o send_arp send_arp.c -Wall -lnet -lpcap
* 运行: #./send_arp <destination IP address>
*
*
*/
#include < stdio.h >
#include < stdlib.h >
#include < unistd.h >
#include < sys / time.h >
#include < sys / types.h >
#include < sys / socket.h >
#include < netinet / in .h >
#include < arpa / inet.h >
#include < libnet.h >
#include < pcap.h >
#ifndef ETH_ALEN
#define ETH_ALEN 6
#endif
#ifndef IP_ALEN
#define IP_ALEN 4
#endif
static u_char eth_xmas[ETH_ALEN] = ... {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} ;
static u_char eth_null[ETH_ALEN] = ... {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} ;
static u_char eth_src[ETH_ALEN];
static u_char eth_dst[ETH_ALEN] = ... {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} ;
static u_char ip_src[IP_ALEN];
static u_char ip_dst[IP_ALEN] ;
int main( int argc, char ** argv)
... {
libnet_t *libnet = NULL;
char error[LIBNET_ERRBUF_SIZE];
int i, c;
if (getuid() && geteuid()) ...{
fprintf(stderr, "must be run as root");
exit(1);
}
if(argc != 2)...{
printf("usage: %s <dst IP addr> ", argv[0]);
}
// open libnet
libnet = libnet_init(LIBNET_LINK, "eth0", error);
if(libnet == NULL) ...{
fprintf(stderr, "libnet_init() failed: %s", error);
exit(EXIT_FAILURE);
}
// get dst ip address
u_int32_t otherip;
otherip = libnet_name2addr4(libnet, argv[1], LIBNET_RESOLVE);
memcpy(ip_dst, (char*)&otherip, IP_ALEN);
printf("dst IP: %d.%d.%d.%d ",ip_dst[0],ip_dst[1],ip_dst[2],ip_dst[3]);
// get hwaddr
struct libnet_ether_addr *mymac;
mymac = libnet_get_hwaddr(libnet);
memcpy(eth_src, mymac, ETH_ALEN);
// get ipaddr
u_int32_t myip;
myip = libnet_get_ipaddr4(libnet);
memcpy(ip_src, (char*)&myip, IP_ALEN);
printf("src IP: %d.%d.%d.%d ",ip_src[0],ip_src[1],ip_src[2],ip_src[3]);
// print source MAC address
printf(" ");
for (i = 0; i < ETH_ALEN - 1; i++) ...{
printf("%.2x:", (u_int8_t)eth_src[i]);
}
printf("%.2x", (u_int8_t)eth_src[ETH_ALEN - 1]);
printf(" ");
static libnet_ptag_t arp=0, eth=0;
arp = libnet_build_arp(
ARPHRD_ETHER,
ETHERTYPE_IP,
ETH_ALEN, IP_ALEN,
ARPOP_REQUEST,
eth_src, ip_src,
eth_dst, ip_dst,
NULL, 0,
libnet,
0);
if (arp == -1)
...{
fprintf(stderr, "Can't build ARP header: %s ", libnet_geterror(libnet));
goto bad;
}
eth = libnet_build_ethernet(
eth_dst, eth_src,
ETHERTYPE_ARP,
NULL, 0,
libnet,
eth);
if (eth == -1)
...{
fprintf(stderr, "Can't build ethernet header: %s ", libnet_geterror(libnet));
goto bad;
}
c = libnet_write(libnet);
if (c == -1)
...{
fprintf(stderr, "Can't send ARP packet: %s ", libnet_geterror(libnet));
goto bad;
}
libnet_destroy(libnet);
return 0;
bad:
libnet_destroy(libnet);
return -1;
}
* 编译: #gcc -o send_arp send_arp.c -Wall -lnet -lpcap
* 运行: #./send_arp <destination IP address>
*
*
*/
#include < stdio.h >
#include < stdlib.h >
#include < unistd.h >
#include < sys / time.h >
#include < sys / types.h >
#include < sys / socket.h >
#include < netinet / in .h >
#include < arpa / inet.h >
#include < libnet.h >
#include < pcap.h >
#ifndef ETH_ALEN
#define ETH_ALEN 6
#endif
#ifndef IP_ALEN
#define IP_ALEN 4
#endif
static u_char eth_xmas[ETH_ALEN] = ... {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} ;
static u_char eth_null[ETH_ALEN] = ... {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} ;
static u_char eth_src[ETH_ALEN];
static u_char eth_dst[ETH_ALEN] = ... {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} ;
static u_char ip_src[IP_ALEN];
static u_char ip_dst[IP_ALEN] ;
int main( int argc, char ** argv)
... {
libnet_t *libnet = NULL;
char error[LIBNET_ERRBUF_SIZE];
int i, c;
if (getuid() && geteuid()) ...{
fprintf(stderr, "must be run as root");
exit(1);
}
if(argc != 2)...{
printf("usage: %s <dst IP addr> ", argv[0]);
}
// open libnet
libnet = libnet_init(LIBNET_LINK, "eth0", error);
if(libnet == NULL) ...{
fprintf(stderr, "libnet_init() failed: %s", error);
exit(EXIT_FAILURE);
}
// get dst ip address
u_int32_t otherip;
otherip = libnet_name2addr4(libnet, argv[1], LIBNET_RESOLVE);
memcpy(ip_dst, (char*)&otherip, IP_ALEN);
printf("dst IP: %d.%d.%d.%d ",ip_dst[0],ip_dst[1],ip_dst[2],ip_dst[3]);
// get hwaddr
struct libnet_ether_addr *mymac;
mymac = libnet_get_hwaddr(libnet);
memcpy(eth_src, mymac, ETH_ALEN);
// get ipaddr
u_int32_t myip;
myip = libnet_get_ipaddr4(libnet);
memcpy(ip_src, (char*)&myip, IP_ALEN);
printf("src IP: %d.%d.%d.%d ",ip_src[0],ip_src[1],ip_src[2],ip_src[3]);
// print source MAC address
printf(" ");
for (i = 0; i < ETH_ALEN - 1; i++) ...{
printf("%.2x:", (u_int8_t)eth_src[i]);
}
printf("%.2x", (u_int8_t)eth_src[ETH_ALEN - 1]);
printf(" ");
static libnet_ptag_t arp=0, eth=0;
arp = libnet_build_arp(
ARPHRD_ETHER,
ETHERTYPE_IP,
ETH_ALEN, IP_ALEN,
ARPOP_REQUEST,
eth_src, ip_src,
eth_dst, ip_dst,
NULL, 0,
libnet,
0);
if (arp == -1)
...{
fprintf(stderr, "Can't build ARP header: %s ", libnet_geterror(libnet));
goto bad;
}
eth = libnet_build_ethernet(
eth_dst, eth_src,
ETHERTYPE_ARP,
NULL, 0,
libnet,
eth);
if (eth == -1)
...{
fprintf(stderr, "Can't build ethernet header: %s ", libnet_geterror(libnet));
goto bad;
}
c = libnet_write(libnet);
if (c == -1)
...{
fprintf(stderr, "Can't send ARP packet: %s ", libnet_geterror(libnet));
goto bad;
}
libnet_destroy(libnet);
return 0;
bad:
libnet_destroy(libnet);
return -1;
}
其实代码都是网上DOWN的
我只不过按照自己的意愿改了改
第一次干这样的活
有意思诶
下面放上抓包的代码:
/**/
/*cap_arp.c*/
/**/ /*
* 编译: #gcc -o cap_arp cap_arp.c -lnet -lpcap
* 运行: #./cap_arp
*/
#include < stdio.h >
#include < stdlib.h >
#include < pcap.h > /**/ /* if this gives you an error try pcap/pcap.h */
#include < errno.h >
#include < sys / socket.h >
#include < netinet / in .h >
#include < arpa / inet.h >
#include < netinet / if_ether.h > /**/ /* includes net/ethernet.h */
int main( int argc, char ** argv)
... {
int i, cnt = 0;
char *dev;
char errbuf[PCAP_ERRBUF_SIZE];
pcap_t *descr; /**//*you can man it */
const u_char *packet;
struct pcap_pkthdr hdr; /**//* pcap.h */
struct ether_header *eptr; /**//* net/ethernet.h */
struct in_addr addr;
char *net; /**//* dot notation of the network address */
char *mask; /**//* dot notation of the network mask */
bpf_u_int32 netp; /**//* ip */
bpf_u_int32 maskp; /**//* subnet mask */
int ret; /**//* return code */
u_char *ptr; /**//* printing out hardware header info */
/**//* grab a device to peak into... */
dev = pcap_lookupdev(errbuf);
if (dev == NULL) ...{
printf("%s ", errbuf);
exit(1);
}
printf("DEV: %s ", dev);
/**//* open the device for sniffing.
pcap_t *pcap_open_live(char *device,int snaplen, int prmisc,int to_ms,
char *ebuf)
snaplen - maximum size of packets to capture in bytes
promisc - set card in promiscuous mode?
to_ms - time to wait for packets in miliseconds before read
times out
errbuf - if something happens, place error string here
Note if you change "prmisc" param to anything other than zero, you will
get all packets your device sees, whether they are intendeed for you or
not!! Be sure you know the rules of the network you are running on
before you set your card in promiscuous mode!! */
descr = pcap_open_live(dev, BUFSIZ, 0, -1, errbuf);
if (descr == NULL) ...{
printf("pcap_open_live(): %s ", errbuf);
exit(1);
}
/**//*
grab a packet from descr (yay!)
u_char *pcap_next(pcap_t *p,struct pcap_pkthdr *h)
so just pass in the descriptor we got from
our call to pcap_open_live and an allocated
struct pcap_pkthdr */
while (cnt < 2) ...{
while((packet = (const u_char *)(pcap_next(descr, &hdr))) == NULL) ...{ /**//* dinna work *sob* */
printf("Didn't grab packet ");
exit(1);
}
/**//* struct pcap_pkthdr {
struct timeval ts; time stamp
bpf_u_int32 caplen; length of portion present
bpf_u_int32; lebgth this packet (off wire)
}
*/
/**//* lets start with the ether header... */
eptr = (struct ether_header *) packet;
/**//* check to see what packet type we have.. */
if (ntohs(eptr->ether_type) == ETHERTYPE_ARP) ...{
++cnt;
printf("Grabbed packet of length %d ", hdr.len);
printf("Recieved at time..... %s",
ctime((const time_t *) &hdr.ts.tv_sec));
printf("Ethernet address length is %d ", ETHER_HDR_LEN);
printf("Ethernet type hex:%x dec:%d is an ARP packet ",
ntohs(eptr->ether_type), ntohs(eptr->ether_type));
/**//* THANK YOU RICHARD STEVENS!!! RIP */
ptr = eptr->ether_dhost;
i = ETHER_ADDR_LEN;
printf(" Destination MAC Address: ");
do ...{
printf("%s%x", (i == ETHER_ADDR_LEN) ? " " : ":", *ptr++);
} while (--i > 0);
printf(" Destination IP Address: ");
...{ /**//* 显示IP和MASK地址 */
ret = pcap_lookupnet(dev, &netp, &maskp, errbuf);
if (ret == -1) ...{
printf("%s ", errbuf);
exit(1);
}
/**//* get the network address in a human readable form */
addr.s_addr = netp;
net = inet_ntoa(addr);
if (net == NULL) ...{ /**//* thanks Scott :-P */
perror("inet_ntoa");
exit(1);
}
printf(" NET: %s ", net);
/**//* do the same as above for the device's mask */
addr.s_addr = maskp;
mask = inet_ntoa(addr);
if (mask == NULL) ...{
perror("inet_ntoa");
exit(1);
}
printf(" MASK: %s ", mask);
}
ptr = eptr->ether_shost;
i = ETHER_ADDR_LEN;
printf(" Source Address: ");
do ...{
printf("%s%x", (i == ETHER_ADDR_LEN) ? " " : ":", *ptr++);
} while (--i > 0);
printf(" ********************************* ");
}
}
return 0;
}
/**/ /*
* 编译: #gcc -o cap_arp cap_arp.c -lnet -lpcap
* 运行: #./cap_arp
*/
#include < stdio.h >
#include < stdlib.h >
#include < pcap.h > /**/ /* if this gives you an error try pcap/pcap.h */
#include < errno.h >
#include < sys / socket.h >
#include < netinet / in .h >
#include < arpa / inet.h >
#include < netinet / if_ether.h > /**/ /* includes net/ethernet.h */
int main( int argc, char ** argv)
... {
int i, cnt = 0;
char *dev;
char errbuf[PCAP_ERRBUF_SIZE];
pcap_t *descr; /**//*you can man it */
const u_char *packet;
struct pcap_pkthdr hdr; /**//* pcap.h */
struct ether_header *eptr; /**//* net/ethernet.h */
struct in_addr addr;
char *net; /**//* dot notation of the network address */
char *mask; /**//* dot notation of the network mask */
bpf_u_int32 netp; /**//* ip */
bpf_u_int32 maskp; /**//* subnet mask */
int ret; /**//* return code */
u_char *ptr; /**//* printing out hardware header info */
/**//* grab a device to peak into... */
dev = pcap_lookupdev(errbuf);
if (dev == NULL) ...{
printf("%s ", errbuf);
exit(1);
}
printf("DEV: %s ", dev);
/**//* open the device for sniffing.
pcap_t *pcap_open_live(char *device,int snaplen, int prmisc,int to_ms,
char *ebuf)
snaplen - maximum size of packets to capture in bytes
promisc - set card in promiscuous mode?
to_ms - time to wait for packets in miliseconds before read
times out
errbuf - if something happens, place error string here
Note if you change "prmisc" param to anything other than zero, you will
get all packets your device sees, whether they are intendeed for you or
not!! Be sure you know the rules of the network you are running on
before you set your card in promiscuous mode!! */
descr = pcap_open_live(dev, BUFSIZ, 0, -1, errbuf);
if (descr == NULL) ...{
printf("pcap_open_live(): %s ", errbuf);
exit(1);
}
/**//*
grab a packet from descr (yay!)
u_char *pcap_next(pcap_t *p,struct pcap_pkthdr *h)
so just pass in the descriptor we got from
our call to pcap_open_live and an allocated
struct pcap_pkthdr */
while (cnt < 2) ...{
while((packet = (const u_char *)(pcap_next(descr, &hdr))) == NULL) ...{ /**//* dinna work *sob* */
printf("Didn't grab packet ");
exit(1);
}
/**//* struct pcap_pkthdr {
struct timeval ts; time stamp
bpf_u_int32 caplen; length of portion present
bpf_u_int32; lebgth this packet (off wire)
}
*/
/**//* lets start with the ether header... */
eptr = (struct ether_header *) packet;
/**//* check to see what packet type we have.. */
if (ntohs(eptr->ether_type) == ETHERTYPE_ARP) ...{
++cnt;
printf("Grabbed packet of length %d ", hdr.len);
printf("Recieved at time..... %s",
ctime((const time_t *) &hdr.ts.tv_sec));
printf("Ethernet address length is %d ", ETHER_HDR_LEN);
printf("Ethernet type hex:%x dec:%d is an ARP packet ",
ntohs(eptr->ether_type), ntohs(eptr->ether_type));
/**//* THANK YOU RICHARD STEVENS!!! RIP */
ptr = eptr->ether_dhost;
i = ETHER_ADDR_LEN;
printf(" Destination MAC Address: ");
do ...{
printf("%s%x", (i == ETHER_ADDR_LEN) ? " " : ":", *ptr++);
} while (--i > 0);
printf(" Destination IP Address: ");
...{ /**//* 显示IP和MASK地址 */
ret = pcap_lookupnet(dev, &netp, &maskp, errbuf);
if (ret == -1) ...{
printf("%s ", errbuf);
exit(1);
}
/**//* get the network address in a human readable form */
addr.s_addr = netp;
net = inet_ntoa(addr);
if (net == NULL) ...{ /**//* thanks Scott :-P */
perror("inet_ntoa");
exit(1);
}
printf(" NET: %s ", net);
/**//* do the same as above for the device's mask */
addr.s_addr = maskp;
mask = inet_ntoa(addr);
if (mask == NULL) ...{
perror("inet_ntoa");
exit(1);
}
printf(" MASK: %s ", mask);
}
ptr = eptr->ether_shost;
i = ETHER_ADDR_LEN;
printf(" Source Address: ");
do ...{
printf("%s%x", (i == ETHER_ADDR_LEN) ? " " : ":", *ptr++);
} while (--i > 0);
printf(" ********************************* ");
}
}
return 0;
}