基于LIBPCAP的HTTP协议还原与模式匹配

#include <pcap.h>
#include <regex.h>
/*
*    基于Libpcap的HTTP协议还原与模式匹配
*                雨虹阳
* 执行 gcc -o test test.c -lpcap
* 模式串为 PATTERN 宏的内容
* 匹配输出 ("match at offset %d, length %d\n", match.rm_so, match.rm_eo)
*/
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/if_ether.h>
#include <net/ethernet.h>
#include <netinet/ether.h>
#include <netinet/ip.h>

#define PATTERN "www.hit.edu.cn"

/* tcpdump header (ether.h) defines ETHER_HDRLEN) */
#ifndef ETHER_HDRLEN
#define ETHER_HDRLEN 14
#endif

/* tcpdump header (tcp.h) defines tcp_seq */
#ifndef tcp_seq
typedef u_int32_t tcp_seq;
#endif

u_int16_t handle_ethernet
        (u_char *args,const struct pcap_pkthdr* pkthdr,const u_char*
        packet);
u_char* handle_IP
        (u_char *args,const struct pcap_pkthdr* pkthdr,const u_char*
        packet);
u_char* handle_TCP(const u_char* tcpdata, u_int16_t tcplen);
void print_Byte(const u_char* begin, u_int16_t len);

/*
* Structure of an internet header, naked of options.
*
* Stolen from tcpdump source (thanks tcpdump people)
*
* We declare ip_len and ip_off to be short, rather than u_short
* pragmatically since otherwise unsigned comparisons can result
* against negative integers quite easily, and fail in subtle ways.
*/
struct my_ip {
    u_int8_t    ip_vhl;        /* header length, version */
#define IP_V(ip)    (((ip)->ip_vhl & 0xf0) >> 4)
#define IP_HL(ip)    ((ip)->ip_vhl & 0x0f)
    u_int8_t    ip_tos;        /* type of service */
    u_int16_t    ip_len;        /* total length */
    u_int16_t    ip_id;        /* identification */
    u_int16_t    ip_off;        /* fragment offset field */
#define    IP_DF 0x4000            /* dont fragment flag */
#define    IP_MF 0x2000            /* more fragments flag */
#define    IP_OFFMASK 0x1fff        /* mask for fragmenting bits */
    u_int8_t    ip_ttl;        /* time to live */
    u_int8_t    ip_p;        /* protocol */
    u_int16_t    ip_sum;        /* checksum */
    struct    in_addr ip_src,ip_dst;    /* source and dest address */
};

struct tcphdr {
    u_int16_t    th_sport;        /* source port */
    u_int16_t    th_dport;        /* destination port */
    tcp_seq        th_seq;            /* sequence number */
    tcp_seq        th_ack;            /* acknowledgement number */
    u_int8_t    th_offx2;        /* data offset, rsvd */
#define TH_OFF(th)    (((th)->th_offx2 & 0xf0) >> 4)
    u_int8_t    th_flags;
#define    TH_FIN    0x01
#define    TH_SYN    0x02
#define    TH_RST    0x04
#define    TH_PUSH    0x08
#define    TH_ACK    0x10
#define    TH_URG    0x20
#define TH_ECNECHO    0x40    /* ECN Echo */
#define TH_CWR        0x80    /* ECN Cwnd Reduced */
    u_int16_t    th_win;            /* window */
    u_int16_t    th_sum;            /* checksum */
    u_int16_t    th_urp;            /* urgent pointer */
};

/* looking at ethernet headers */
void my_callback(u_char *args,const struct pcap_pkthdr* pkthdr,const u_char*
        packet)
{
    u_int16_t type = handle_ethernet(args,pkthdr,packet);

    if(type == ETHERTYPE_IP)
    {/* handle IP packet */
        handle_IP(args,pkthdr,packet);
    }else if(type == ETHERTYPE_ARP)
    {/* handle arp packet */
    }
    else if(type == ETHERTYPE_REVARP)
    {/* handle reverse arp packet */
    }
}

u_char* handle_IP
        (u_char *args,const struct pcap_pkthdr* pkthdr,const u_char*
        packet)
{
    const struct my_ip* ip;
    u_int length = pkthdr->len;
    u_int hlen,off,version;
    int i;

    int len;

    int protocol;
    /* jump pass the ethernet header */
    ip = (struct my_ip*)(packet + sizeof(struct ether_header));
    length -= sizeof(struct ether_header);

    /* check to see we have a packet of valid length */
    if (length < sizeof(struct my_ip))
    {
        printf("truncated ip %d",length);
        return NULL;
    }

    len     = ntohs(ip->ip_len);
    hlen    = IP_HL(ip); /* header length */
    version = IP_V(ip);/* ip version */
    protocol = ip->ip_p;

    /* check version */
    if(version != 4)
    {
      fprintf(stdout,"Unknown version %d\n",version);
      return NULL;
    }

    /* check header length */
    if(hlen < 5 )
    {
        fprintf(stdout,"bad-hlen %d \n",hlen);
    }

    /* see if we have as much packet as we should */
    if(length < len)
        printf("\ntruncated IP - %d bytes missing\n",len - length);

    /* Check to see if we have the first fragment */
    off = ntohs(ip->ip_off);
    if((off & 0x1fff) == 0 )/* aka no 1's in first 13 bits */
    {/* print SOURCE DESTINATION hlen version len offset */
        fprintf(stdout,"IP: ");
        fprintf(stdout,"%s ",
                inet_ntoa(ip->ip_src));
        fprintf(stdout,"%s %d %d %d %d %d\n",
                inet_ntoa(ip->ip_dst),
                hlen,version,len,off,protocol);
    }

    /* handle upper TCP protocol */
    if(protocol == 6)
        handle_TCP((u_char*)ip + hlen * 4, len - hlen * 4);
    return NULL;
}

u_char* handle_TCP(const u_char* tcpdata, u_int16_t tcplen)
{
    regex_t reg;
    regmatch_t match = {0, 0};
    u_char* appdata;
    const struct tcphdr* tcp;
   
    regcomp(®, PATTERN, 0);

    tcp = (struct tcphdr*)tcpdata;
    appdata = tcpdata + TH_OFF(tcp) * 4;

    if(regexec(®, appdata, 1, &match, 0) == 0)
        printf("match at offset %d, length %d\n", match.rm_so, match.rm_eo);

    fprintf(stdout, "Sport: %d, Dport: %d, Seq: %d, Ack: %d (len: %d)\t",
            ntohs(tcp->th_sport), ntohs(tcp->th_dport),
            ntohl(tcp->th_seq), ntohl(tcp->th_ack), tcplen-TH_OFF(tcp)*4);

    /* Check Tcp Data */

    if(TH_OFF(tcp)*4 < tcplen)
        print_Byte(appdata, tcplen-TH_OFF(tcp) * 4);
    printf("\n");

    regfree(®);
    return NULL;
}

void print_Byte(const u_char* begin, u_int16_t len)
{
    int i;
    u_char* pointer = begin;
    for(i=0; i<len; i++, pointer++)
        printf("%c", *pointer);
}
/* analyse upper protocol
*/

/* handle ethernet packets, much of this code gleaned from
* print-ether.c from tcpdump source
*/
u_int16_t handle_ethernet
        (u_char *args,const struct pcap_pkthdr* pkthdr,const u_char*
        packet)
{
    u_int caplen = pkthdr->caplen;
    u_int length = pkthdr->len;
    struct ether_header *eptr; /* net/ethernet.h */
    u_short ether_type;

    if (caplen < ETHER_HDRLEN)
    {
        fprintf(stdout,"Packet length less than ethernet header length\n");
        return -1;
    }

    /* lets start with the ether header... */
    eptr = (struct ether_header *) packet;
    ether_type = ntohs(eptr->ether_type);

    /* Lets print SOURCE DEST TYPE LENGTH */
    fprintf(stdout,"ETH: ");
    fprintf(stdout,"%s "
            ,ether_ntoa((struct ether_addr*)eptr->ether_shost));
    fprintf(stdout,"%s "
            ,ether_ntoa((struct ether_addr*)eptr->ether_dhost));

    /* check to see if we have an ip packet */
    if (ether_type == ETHERTYPE_IP)
    {
        fprintf(stdout,"(IP)");
    }else if (ether_type == ETHERTYPE_ARP)
    {
        fprintf(stdout,"(ARP)");
    }else if (eptr->ether_type == ETHERTYPE_REVARP)
    {
        fprintf(stdout,"(RARP)");
    }else {
        fprintf(stdout,"(?)");
    }
    fprintf(stdout," %d\n",length);

    return ether_type;
}


int main(int argc,char **argv)
{
    char *dev;
    char errbuf[PCAP_ERRBUF_SIZE];
    pcap_t* descr;
    struct bpf_program fp;      /* hold compiled program     */
    bpf_u_int32 maskp;          /* subnet mask               */
    bpf_u_int32 netp;           /* ip                        */
    u_char* args = NULL;

    /* Options must be passed in as a string because I am lazy */
    if(argc < 2){
        fprintf(stdout,"Usage: %s numpackets \"options\"\n",argv[0]);
        return 0;
    }

    /* grab a device to peak into... */
    dev = pcap_lookupdev(errbuf);
    if(dev == NULL)
    { printf("%s\n",errbuf); exit(1); }

    /* ask pcap for the network address and mask of the device */
    pcap_lookupnet(dev,&netp,&maskp,errbuf);

    /* open device for reading. NOTE: defaulting to
     * promiscuous mode*/
    descr = pcap_open_live(dev,BUFSIZ,0,-1,errbuf);
    if(descr == NULL)
    { printf("pcap_open_live(): %s\n",errbuf); exit(1); }


    if(argc > 2)
    {
        /* Lets try and compile the program.. non-optimized */
        if(pcap_compile(descr,&fp,argv[2],0,netp) == -1)
        { fprintf(stderr,"Error calling pcap_compile\n"); exit(1); }

        /* set the compiled program as the filter */
        if(pcap_setfilter(descr,&fp) == -1)
        { fprintf(stderr,"Error setting filter\n"); exit(1); }
    }

    /* ... and loop */
    pcap_loop(descr,atoi(argv[1]),my_callback,args);

    fprintf(stdout,"\nfinished\n");
    return 0;
}


  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值