tcpreplay源码解析

一:前言:

tcpreplay的作者在写sendpacket()函数时说:希望写一个通用的数据包发送api接口支持BPF, libpcap, libdnet, and Linux's PF_PACKET,因为libnet缺乏活动性,libpcap支持模块比较新,并且缺乏非linux支持,所以作者决定同时支持这四个,他们的匹配顺序如下,如果平台支持其中最先匹配的函数,就使用它发包。由于libpcap不提供可靠的方法获取MAC地址,所以使用PF_PACKET or BPF代替。

51 * 1. PF_PACKET  send()                    (int)send(sp->handle.fd, (void *)data, len, 0); linux上面使用
52 * 2. BPF send()                                            write(sp->handle.fd, (void *)data, len);    freebsd上使用
 53 * 3. libdnet eth_send()                      eth_send(sp->handle.ldnet, (void*)data, (size_t)len);
 54 * 4. pcap_inject()                            pcap_inject(sp->handle.pcap, (void*)data, len);{

                                                                     return (p->inject_op(p, buf, size));

                                                                      }

                                                                 handle->inject_op = pcap_inject_linux;

                                                                  pcap_inject_linux(pcap_t *handle, const void *buf, size_t size){

                                                                ret = send(handle->fd, buf, size, 0);

                                                                   }
 55 * 5. pcap_sendpacket()     pcap_sendpacket(sp->handle.pcap, data, (int)len); /* out of buffers, or hit max PHY speed, silently retry */从缓存发送或者使用最大速度发送

   {
if (p->inject_op(p, buf, size) == -1)
return (-1);
return (0);
}

(1)PF_PACKET:linux上使用,不经过协议栈,直接到用户层收发数据数据

(2)BPF:是类Unix系统上数据链路层的一种原始接口,提供原始链路层封包的收发,bsd系统上面使用,不经过协议栈,直接到用户层收发数据


(3)libnet,一个小型的接口函数库,建立一个简单统一的网络编程接口以屏蔽不同操作系统低层网络编程的差别,libnet目前可以在Linux、FreeBSD、Solaris、WindowsNT等操作系统上运行,并且提供了统一的接口

(4) libpcap:一个网络捕获数据包的开放源码,被tcpdump、snort等著名软件包使用。可以在绝大多数类unix平台下工作,如果希望libpcap能在linux上正常工作,则必须使内核支持"packet"协议,也即在编译内核时打开配置选项 CONFIG_PACKET(选项缺省为打开)。windows版本为winpcap。


pcap_inject()来源于OpenBSD,调用p->inject_op,pcap_inject_linux,send发送数据;

pcap_send-packet() 则来源于WinPcap, 与pcap_inject实现一样,只是更改了接口,,返回0表示成功,-1表示失败。两个函数都提供是为了兼容,


1,tcpreplay有tcpreplay tcpbridge tcpprep tcprewrite等几个软件组成的软件包。

http://tcpreplay.sourceforge.net/

http://packages.debian.org/sid/sparc/tcpreplay

http://tcpreplay.synfin.net/wiki/Download#Source

http://tcpreplay.synfin.net/

在以上网站可以查看说明和下载源码,不过都是英文的.


2,这里主要查看tcpreplay的源码

tcpreplay的源码在/tcpreplay-3.4.4/src下面

(1)使用到的发送数据包的函数封装在send_packets.c文件下的send_packets(pcap, file_idx)函数中, 

(2)send_packets(pcap, file_idx)的发送函数封装在sendpack.c(在/tcpreplay-3.4.4/src/common)文件中的sendpacket(sendpacket_t *sp, const u_char *data, size_t len)函数里,。

(3)
sendpack()的发送函数封装在send()或者write里面,
#ifdef HAVE_PF_PACKET
#undef INJECT_METHOD
#define INJECT_METHOD "PF_PACKET send()"

#if defined HAVE_BPF && ! defined INJECT_METHOD
#undef INJECT_METHOD
#define INJECT_METHOD "bpf send()"

245 #elif defined HAVE_BPF
246 retcode = write(sp->handle.fd, (void *)data, len);
---------------------------------------eth_send()------------------------------------
267 #elif defined HAVE_LIBDNET
268 retcode = eth_send(sp->handle.ldnet, (void*)data, (size_t)len);
(4),send()和 write():是封装了sendto()的函数,只能在connect建立连接确定接口后才能使用


struct sendpacket_s {
tcpr_dir_t cache_dir;
int open;
char device[20];
char errbuf[SENDPACKET_ERRBUF_SIZE];
COUNTER retry_enobufs;
COUNTER retry_eagain;
COUNTER failed;
COUNTER sent;
COUNTER bytes_sent;
COUNTER attempt;
enum sendpacket_type_t handle_type;
union sendpacket_handle handle;
struct tcpr_ether_addr ether;
#ifdef HAVE_PF_PACKET
struct sockaddr_ll sa;
#endif
};

union sendpacket_handle {
pcap_t *pcap;
int fd;
#ifdef HAVE_LIBDNET
eth_t *ldnet;
#endif
};

struct pcap [pcap-int.h]


    int fd; /* 文件描述字,实际就是 socket */  
      
        /* 在 socket 上,可以使用 select() 和 poll() 等 I/O 复用类型函数 */  
    int selectable_fd; 

    int snapshot; /* 用户期望的捕获数据包最大长度 */  
    int linktype; /* 设备类型 */  
    int tzoff;        /* 时区位置,实际上没有被使用 */  
    int offset;    /* 边界对齐偏移量 */  

    int break_loop; /* 强制从读数据包循环中跳出的标志 */  

    struct pcap_sf sf; /* 数据包保存到文件的相关配置数据结构 */  
    struct pcap_md md; /* 具体描述如下 */  
      
    int bufsize; /* 读缓冲区的长度 */  
    u_char buffer; /* 读缓冲区指针 */  
    u_char *bp;  
    int cc;  
    u_char *pkt;  

    /* 相关抽象操作的函数指针,最终指向特定操作系统的处理函数 */  
    int    (*read_op)(pcap_t *, int cnt, pcap_handler, u_char *);  
    int    (*setfilter_op)(pcap_t *, struct bpf_program *);  
    int    (*set_datalink_op)(pcap_t *, int);  
    int    (*getnonblock_op)(pcap_t *, char *);  
    int    (*setnonblock_op)(pcap_t *, int, char *);  
    int    (*stats_op)(pcap_t *, struct pcap_stat *);  
    void (*close_op)(pcap_t *);  

    /*如果 BPF 过滤代码不能在内核中执行,则将其保存并在用户空间执行 */  
    struct bpf_program fcode; 

    /* 函数调用出错信息缓冲区 */  
    char errbuf[PCAP_ERRBUF_SIZE + 1]; 
      
    /* 当前设备支持的、可更改的数据链路类型的个数 */  
    int dlt_count;  
    /* 可更改的数据链路类型号链表,在 linux 下没有使用 */  
    int *dlt_list;  

    /* 数据包自定义头部,对数据包捕获时间、捕获长度、真实长度进行描述 [pcap.h] */  
    struct pcap_pkthdr pcap_header;      

}; 

完整pcap结构体代码。

   245 struct pcap {
    246 #ifdef WIN32
    247         ADAPTER *adapter;
    248         LPPACKET Packet;
    249         int nonblock;
    250 #else
    251         int fd;
    252         int selectable_fd;
    253         int send_fd;
    254 #endif /* WIN32 */
    255 
    256 #ifdef HAVE_LIBDLPI
    257         dlpi_handle_t dlpi_hd;
    258 #endif
    259         int snapshot;
    260         int linktype;           /* Network linktype */
    261         int linktype_ext;       /* Extended information stored in the linktype field of a file */
    262         int tzoff;              /* timezone offset */
    263         int offset;             /* offset for proper alignment */
    264         int activated;          /* true if the capture is really started */
    265         int oldstyle;           /* if we're opening with pcap_open_live() */
    266 
    267         int break_loop;         /* flag set to force break from packet-reading loop */
    268 
    269 #ifdef PCAP_FDDIPAD
    270         int fddipad;
    271 #endif
    272 
    273 #ifdef MSDOS
    274         void (*wait_proc)(void); /*          call proc while waiting */
    275 #endif
    276 
    277         struct pcap_sf sf;
    278         struct pcap_md md;
    279         struct pcap_opt opt;
    280 
    281         /*
    282          * Read buffer.
    283          */
    284         int bufsize;
    285         u_char *buffer;
    286         u_char *bp;
    287         int cc;
    288 
    289         /*
    290          * Place holder for pcap_next().
    291          */
    292         u_char *pkt;
    293 
    294         /* We're accepting only packets in this direction/these directions. */
    295         pcap_direction_t direction;
    296 
    297         /*
    298          * Methods.
    299          */
    300         activate_op_t activate_op;
    301         can_set_rfmon_op_t can_set_rfmon_op;
    302         read_op_t read_op;
    303         inject_op_t inject_op;
    304         setfilter_op_t setfilter_op;
    305         setdirection_op_t setdirection_op;
    306         set_datalink_op_t set_datalink_op;
    307         getnonblock_op_t getnonblock_op;
    308         setnonblock_op_t setnonblock_op;
    309         stats_op_t stats_op;
    310 
    311         /*
    312          * Routine to use as callback for pcap_next()/pcap_next_ex().
    313          */
    314         pcap_handler oneshot_callback;
    315 
    316 #ifdef WIN32
    317         /*
    318          * These are, at least currently, specific to the Win32 NPF
    319          * driver.
    320          */
    321         setbuff_op_t setbuff_op;
    322         setmode_op_t setmode_op;
    323         setmintocopy_op_t setmintocopy_op;
    324 #endif
    325         cleanup_op_t cleanup_op;
    326 
    327         /*
    328          * Placeholder for filter code if bpf not in kernel.
    329          */
    330         struct bpf_program fcode;
    331 
    332         char errbuf[PCAP_ERRBUF_SIZE + 1];
    333         int dlt_count;
    334         u_int *dlt_list;
    335         int tstamp_type_count;
    336         u_int *tstamp_type_list;
    337 
    338         struct pcap_pkthdr pcap_header; /* This is needed for the pcap_next_ex() to work */
    339 };



你可能感兴趣的:(linux)