LINUX C网络抓包分析
本文地址:http://dsyn.tongxinmao.com/Article/Detail/id/227
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <linux/if_packet.h>
#include <netinet/if_ether.h>
#include <netinet/in.h>
//#include <cap.h>
typedef unsigned char BYTE;
typedef struct _iphdr //定义IP首部
{
unsigned char h_verlen; //4位首部长度+4位IP版本号
unsigned char tos; //8位服务类型TOS
unsigned short total_len; //16位总长度(字节)
unsigned short ident; //16位标识
unsigned short frag_and_flags; //3位标志位
unsigned char ttl; //8位生存时间 TTL
unsigned char proto; //8位协议 (TCP, UDP 或其他)
unsigned short checksum; //16位IP首部校验和
unsigned int sourceIP; //32位源IP地址
unsigned int destIP; //32位目的IP地址
}IP_HEADER;
typedef struct _udphdr //定义UDP首部
{
unsigned short uh_sport; //16位源端口
unsigned short uh_dport; //16位目的端口
unsigned int uh_len;//16位UDP包长度
unsigned int uh_sum;//16位校验和
}UDP_HEADER;
typedef struct _tcphdr //定义TCP首部
{
unsigned short th_sport; //16位源端口
unsigned short th_dport; //16位目的端口
unsigned int th_seq; //32位序列号
unsigned int th_ack; //32位确认号
unsigned char th_lenres;//4位首部长度/6位保留字
unsigned char th_flag; //6位标志位
unsigned short th_win; //16位窗口大小
unsigned short th_sum; //16位校验和
unsigned short th_urp; //16位紧急数据偏移量
}TCP_HEADER;
typedef struct _icmphdr {
unsigned char icmp_type;
unsigned char icmp_code; /* type sub code */
unsigned short icmp_cksum;
unsigned short icmp_id;
unsigned short icmp_seq;
/* This is not the std header, but we reserve space for time */
unsigned short icmp_timestamp;
}ICMP_HEADER;
/* ip首部长度 */
#define IP_HEADER_LEN sizeof(IP_HEADER)
/* tcp首部长度 */
#define TCP_HEADER_LEN sizeof(TCP_HEADER)
/* ip首部 + tcp首部长度 */
#define IP_TCP_HEADER_LEN IP_HEADER_LEN + TCP_HEADER_LEN
void analyseIP(IP_HEADER *ip);
void analyseTCP(IP_HEADER *ip,TCP_HEADER *tcp);
void analyseUDP(UDP_HEADER *udp);
void analyseICMP(ICMP_HEADER *icmp);
#define ETH_NAME "eth0"
int revlen=0;
int iphlen=0;
int tcphlen=0;
BYTE buf[1024*1024];
int byteCount=0;
//ifconfig eth0 promisc 设置好网卡混杂模式则不需要编程实现,否则需要编程实现。
int do_promisc(void) {
int f, s;
struct ifreq ifr;
if ( (f=socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)))<0){
return -1;
}
strcpy(ifr.ifr_name, ETH_NAME);
if ((s = ioctl(f, SIOCGIFFLAGS, &ifr))<0){
close(f);
return-1;
}
if(ifr.ifr_flags & IFF_RUNNING){
printf("eth link up\n");
}else{
printf("eth link down\n");
}
ifr.ifr_flags |= IFF_PROMISC;
if ((s = ioctl(f, SIOCSIFFLAGS, &ifr)) < 0){
return -1;
}
printf("Setting interface ::: %s ::: to promisc\n\n", ifr.ifr_name);
return 0;
}
int check_nic(void)
{
struct ifreq ifr;
int skfd = socket(AF_INET, SOCK_DGRAM, 0);
strcpy(ifr.ifr_name, ETH_NAME);
if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
{
close(skfd);
return -1;
}
if(ifr.ifr_flags & IFF_RUNNING){
printf("link up\n");
close(skfd);
return 0; // 网卡已插上网线
}else {
printf("link down\n");
close(skfd);
return -1;
}
}
void savefile()
{
FILE *f;
char file[64];
time_t t;
if(byteCount>5){
sprintf(file,"tcp_%d.prn",time(&t)); //这里相对于当前工作路径
f=fopen(file,"wb");
if(f!=NULL)
{
fwrite(buf,byteCount,1,f);
fclose(f);
printf("save prn file:%s %d byte\n",file,byteCount);
}else
{
printf("can not create file:%s \n",file);
}
}else{
printf("invial data: %u bytes\n",byteCount);
}
byteCount=0;
}
int main(int32_t argc, char **argv)
{
int32_t opt = 0;
int sockfd;
IP_HEADER *ip;
char buf[1024*1000];
ssize_t n;
int sport=-1;
int dport=-1;
//如optstring="ab:c::d::",命令行为getopt.exe -a -b host -ckeke -d haha
while ((opt = getopt(argc, argv, "d:s:")) != -1) {
switch (opt) {
case 'd':
dport=atoi(optarg);
printf("dport=%s\n",optarg);
break;
case 's':
sport=atoi(optarg);
printf("sport=%s\n",optarg);
break;
default:
break;;
}
}
do_promisc();
/* capture ip datagram without ethernet header */
if ((sockfd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP)))== -1)
{
printf("socket error!\n");
return 1;
}
while (1)
{
n = recv(sockfd, buf, sizeof(buf), 0);
if (n == -1)
{
printf("recv error!\n");
break;
}
else if (n<20)
continue;
//接收数据不包括数据链路帧头
ip = ( IP_HEADER *)(buf);
revlen=ntohs(ip->total_len);
//analyseIP(ip);
size_t iplen = (ip->h_verlen&0x0f)*4;
iphlen=iplen;
TCP_HEADER *tcp = (TCP_HEADER *)(buf +iplen);
if (ip->proto == IPPROTO_TCP)
{
TCP_HEADER *tcp = (TCP_HEADER *)(buf +iplen);
if(22==ntohs(tcp->th_dport))continue;
if((sport>0 && sport==ntohs(tcp->th_sport)) || (dport>0 && dport==ntohs(tcp->th_dport)) )
{
printf("revlen len:%u total len:%u\n",n,ntohs(ip->total_len));
analyseTCP(ip,tcp);
}
}
/* else if (ip->proto == IPPROTO_UDP)
{
UDP_HEADER *udp = (UDP_HEADER *)(buf + iplen);
analyseUDP(udp);
} /*
else if (ip->proto == IPPROTO_ICMP)
{
ICMP_HEADER *icmp = (ICMP_HEADER *)(buf + iplen);
analyseICMP(icmp);
}
else if (ip->proto == IPPROTO_IGMP)
{
printf("IGMP----\n");
}
else
{
printf("other protocol!\n");
}
*/
//printf(".");
}
close(sockfd);
return 0;
}
void analyseIP(IP_HEADER *ip)
{
unsigned char* p = (unsigned char*)&ip->sourceIP;
unsigned char* p2;
p2 = (unsigned char*)&ip->destIP;
printf("IPP:\t: %u.%u.%u.%u -->\t: %u.%u.%u.%u\n",p[0],p[1],p[2],p[3], p2[0],p2[1],p2[2],p2[3]);
}
//https://wenku.baidu.com/view/04b0d780e53a580216fcfeaa.html
void analyseTCP(IP_HEADER *ip,TCP_HEADER *tcp)
{
#define FIN 0x01 //FIN:标记数据是否发送完毕
#define SYN 0x02 //当SYN=1,ACK=0时,表示这是一个请求建立连接的报文段;当SYN=1,ACK=1时,表示对方同意建立连接
#define RST 0x04 //说明你与主机的连接出现了严重错误(如主机崩溃),必须释放连接,然后再重新建立连接
#define PSH 0x08 //PSH:告诉对方收到该报文段后是否应该立即把数据推送给上层
#define ACK 0x10 //TCP规定,连接建立后,ACK必须为1。
#define URG 0x20
int len;
BYTE *pData;
unsigned char* p = (unsigned char*)&ip->sourceIP;
unsigned char* p2;
short int flag;
flag=tcp->th_flag;
p2 = (unsigned char*)&ip->destIP;
printf("tcp:\t %u.%u.%u.%u:%d -->%u.%u.%u.%u:%d flag=0x%x[%s %s %s %s %s %s] SEQ:%u ACKNUM:%u\n",p[0],p[1],p[2],p[3],ntohs(tcp->th_sport), p2[0],p2[1],p2[2],p2[3],ntohs(tcp->th_dport),flag,(flag & ACK)?"ACK":"",(flag & SYN)?"SYN":"",(flag & FIN)?"FIN":"",(flag & PSH)?"PSH":"",(flag & RST)?"RST":"",(flag & URG)?"URG":"",ntohl(tcp->th_seq),ntohl(tcp->th_ack));
if((flag & SYN) && !(flag & ACK))
{
printf("request connect\n");
}
if( (flag & ACK))
{
// printf("ack\n");
}
if(flag & FIN )
{
printf("FINISH & disconnected\n");
savefile();
}
if(flag & RST )
{
printf("connection reset\n");
byteCount=0;
}
if(flag & PSH )
{
}
len =(tcp->th_lenres)>>4;
len *=4;
tcphlen=len;
pData = ( (BYTE *)tcp )+len;
if(revlen-iphlen-tcphlen>0)
{
int datalen=revlen-iphlen-tcphlen;
printf("====get data byte:%d-%d-%d=%d \n", revlen,iphlen,tcphlen,datalen);
if(byteCount+datalen<=sizeof(buf))
{
memcpy(buf+byteCount,pData,datalen);
byteCount+=datalen;
}
}
}
void analyseUDP(UDP_HEADER *udp)
{
printf("UDP Source port: %u--> Dest port: %u\n", ntohs(udp->uh_sport),ntohs(udp->uh_dport));
}
void analyseICMP(ICMP_HEADER *icmp)
{
printf("ICMP -----\n");
printf("type: %u\n", icmp->icmp_type);
printf("sub code: %u\n", icmp->icmp_code);
}上一篇:VCB计算String数组元素个数
下一篇:USB声卡描述符