加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

一个简单的抓包程序&代码(linux)

(2013-02-27 11:09:30)
标签:

it

抓包

pcap

网络

tcpdump

分类: 软件开发
最近测试媒体流的时候, 有时候需要分析抓包,趁着有空研究了一下pcap的文件头和包头,以及。 自己写了一个简单的抓包程序,该程序在抓包同时会打印ip和udp的信息。 写这个是为后续从抓包中提取rtp载荷做准备。当然,如果你没有tcpdump也可以用这个抓包。这里面有很多功能还可以完善比如校验和之类的。
注意这个程序只能用root用户执行。因为只有在root下才能让网卡处于混杂模式抓所有的包 

首先是makefile文件,非常简单:
INC_FLAGS:= -I./ -I../
cc:=gcc
mysniffer: ff_sniffer.c  ff_tcpip.c  ff_tcpip.h
$(cc) $(INC_FLAGS) ff_sniffer.c  ff_tcpip.c -o mysniffer


其次是头文件 ff_tcpip.h

#ifndef __FF_TCPIP_H__
#define __FF_TCPIP_H__


typedef  int int32;
typedef  unsigned int u_int32;
typedef  unsigned char u_char;
typedef  unsigned short u_short;


typedef struct ip_hdr{//ipv4头部
#ifdef __LITTLE_ENDIAN_BITFIELD
u_char ip_length:4,  
  ip_version:4;                
#else
u_char ip_version:4,
  ip_length:4;
#endif
u_char ip_tos;                        
u_short ip_total_length;              
u_short ip_id;                        
u_short ip_flags;                    
u_char ip_ttl;                        
u_char ip_protocol;                  
u_short ip_cksum;                    
u_int32 ip_source;                    
u_int32 ip_dest;                      
}__attribute__((packed)) IP_HDR;
//注意__attribute__((packed))很重要, 它保证了结构体里面的元素存储位置不会被优化

typedef struct udp_hdr{//udp头部
u_short s_port;      
u_short d_port;      
u_short length;      
u_short cksum;      
}__attribute__((packed)) UDP_HDR;

typedef struct psd_header{//伪头部,用于计算校验和
u_int32 s_ip;//source ip
u_int32 d_ip;//dest ip
u_char mbz;//0
u_char proto;//proto type
u_short plen;//length
}__attribute__((packed)) PSD_HEADER;

typedef struct _MAC_FRAME_HEADER{
char m_cDstMacAddress[6];   //目的mac地址
char m_cSrcMacAddress[6];   //源mac地址
short m_cType;              //上一层协议类型,如0x0800代表上一层是IP协议,0x0806为arp
}__attribute__((packed)) MAC_FRAME_HDR;


typedef struct pcap_file_header {
u_int32 magic;
u_short version_major;
u_short version_minor;
int32   thiszone;    
u_int32 sigfigs;    
u_int32 snaplen;    
u_int32 linktype;  
}__attribute__((packed)) PCAP_FILE_HDR;


typedef struct pcap_pkthdr {
u_int32 iTimeSecond;
u_int32 iTimeSS;
u_int32 caplen;    
u_int32 len;        
}__attribute__((packed)) PCAP_PKT_HDR;



unsigned short checksum(unsigned short* buffer, int size);

void ip_analyze_pkt(void *buffer, int size);
void ip_ass_pcap_filehead(PCAP_FILE_HDR *pcap_file_hdr);
void ip_ass_pcap_pkthead(PCAP_PKT_HDR *pcap_pkt_hdr, int size);

#endif


然后是tcpip的核心程序: ff_tcpip.c 
#include "ff_tcpip.h"
#include <stdio.h>
#include <string.h>
#include <linux/in.h>
#include <sys/time.h>

#ifdef ANDROID_LOG
#include <android/log.h>
#define LOGI(format,...)  //__android_log_print(ANDROID_LOG_INFO ,"hello_hl","file[%s] line[%d] "format"",__FILE__, __LINE__ ,##__VA_ARGS__)
#define LOGE(format,...)  __android_log_print(ANDROID_LOG_ERROR,"hello_hl","file[%s] line[%d] "format"",__FILE__, __LINE__ ,##__VA_ARGS__)
#else
#define LOGI(format,...)  printf("file[%s] line[%d] "format"\n",__FILE__, __LINE__ ,##__VA_ARGS__)
#define LOGE(format,...)  printf("file[%s] line[%d] "format"\n",__FILE__, __LINE__ ,##__VA_ARGS__)
#endif


unsigned short checksum(unsigned short* buffer, int size)//校验和
{
    unsigned long cksum = 0;
    while(size>1)
    {
        cksum += *buffer++;
        size -= sizeof(unsigned short);
    }
    if(size)
    {
        cksum += *(unsigned char*)buffer;
    }
        cksum = (cksum>>16) + (cksum&0xffff); //将高16bit与低16bit相加
        cksum += (cksum>>16); //将进位到高位的16bit与低16bit 再相加
    return (unsigned short)(~cksum);
}

void ip_analyze_pkt(void *buffer, int size){
UDP_HDR *udp_hdr;
IP_HDR *ip_hdr;
MAC_FRAME_HDR  *mac_hdr;
char *p,*q;
int n=0xFF,proto;

mac_hdr = buffer;
ip_hdr = buffer + sizeof(MAC_FRAME_HDR);
udp_hdr = buffer + sizeof(MAC_FRAME_HDR) + sizeof(IP_HDR);

p = mac_hdr->m_cSrcMacAddress;
q = mac_hdr->m_cDstMacAddress;
LOGI("MAC: %.2X:X:X:X:X:X==>"
                       "%.2X:%.2X:%.2X:%.2X:%.2X:%.2X",
        p[0]&n, p[1]&n, p[2]&n,p[3]&n, p[4]&n, p[5]&n,
q[0]&n, q[1]&n, q[2]&n,q[3]&n, q[4]&n, q[5]&n);

p = (char*)&ip_hdr->ip_source;
q = (char*)&ip_hdr->ip_dest;

LOGI("IP: %d.%d.%d.%d => %d.%d.%d.%d",
        p[0]&0XFF, p[1]&0XFF, p[2]&0XFF, p[3]&0XFF,  
        q[0]&0XFF, q[1]&0XFF, q[2]&0XFF, q[3]&0XFF);  

    switch(ip_hdr->ip_protocol)
    {      
        case IPPROTO_ICMP: LOGI("ICMP");break;
        case IPPROTO_IGMP: LOGI("IGMP");break;
        case IPPROTO_IPIP: LOGI("IPIP");break;
        case IPPROTO_TCP :
        case IPPROTO_UDP :
            LOGI("Protocol: %s", proto == IPPROTO_TCP ? "TCP": "UDP");
            LOGI("source port: %u , dest port: %u ", udp_hdr->s_port ,udp_hdr->d_port);
            break;
        case IPPROTO_RAW : LOGI("RAW");break;
        default:printf("Unkown, please query in include/linux/in.h\n");
    }
}

void ip_ass_pcap_pkthead(PCAP_PKT_HDR *pcap_pkt_hdr, int size){
struct timeval ts;
gettimeofday(&ts,NULL);
pcap_pkt_hdr->iTimeSS = ts.tv_usec;
pcap_pkt_hdr->iTimeSecond = ts.tv_sec;
pcap_pkt_hdr->caplen = size;
pcap_pkt_hdr->len = size;
}

void ip_ass_pcap_filehead(PCAP_FILE_HDR *pcap_file_hdr){
pcap_file_hdr->magic = 0xa1b2c3d4;
pcap_file_hdr->version_major = 0x02;
pcap_file_hdr->version_minor = 0x04;
pcap_file_hdr->thiszone = 0x00;
pcap_file_hdr->sigfigs = 0x00;
pcap_file_hdr->snaplen = 0xff;
pcap_file_hdr->linktype = 0x01;
}


主程序ff_sniffer.c :
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <linux/if_ether.h>
#include <linux/in.h>
#include <stdlib.h>
#include "ff_tcpip.h"

#define BUFFER_MAX 2048
FILE  *File_Save=NULL;

int Sock_Src;


int main(int argc, char *argv[])
{
       
    int sock, n_read, proto, count;
    char buffer[BUFFER_MAX];
    char path[100]={0};
    char  *ethhead, *iphead, *tcphead, *udphead, *icmphead, *p;  
    PCAP_FILE_HDR pcap_file_hdr={0};
    PCAP_PKT_HDR pcap_pkt_hdr={0};
       
   
    if( (Sock_Src =socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP)) ) < 0 )
    {
        fprintf(stdout, "create socket error\n");
        exit(0);
    }
    if(argc >=2)
    strcpy(path,argv[1]);
    File_Save = fopen(path,"wb");
    if(File_Save==NULL)
    fprintf(stdout, "open file  error\n");
    else{
    ip_ass_pcap_filehead(&pcap_file_hdr);
    fwrite(&pcap_file_hdr, sizeof(pcap_file_hdr), 1, File_Save);
    }
       
    while(count++ <= 100)
    {      
        n_read = recvfrom(Sock_Src, buffer, 2048, 0, NULL, NULL);
               
        if(n_read < 42)
        {
            fprintf(stdout, "Incomplete header, packet corrupt\n");
            continue;
        }
        printf("pkt size[%d] \n", n_read);
        if(File_Save!=NULL){
        ip_ass_pcap_pkthead(&pcap_pkt_hdr,n_read);
        fwrite(&pcap_pkt_hdr, sizeof(pcap_pkt_hdr), 1, File_Save);
        fwrite(buffer,n_read,1,File_Save);
        }
        ip_analyze_pkt(buffer,n_read);
    }
}


编译完之后,sudo ./mysniffer  xxx.cap 即可抓包到xxx.cap中,能用wireshark看。 同时可以再命令行看到ip信息。 正如你看到的,我这个程序只抓前100个包。想抓多少你自己可以修改。

参考文章:
http://blog.csdn.net/yhangleo/article/details/8484597

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有