用户操作
[即时聊天] [发私信] [加为好友]
heiyelurenID:heiyeshuwu
893422次访问,排名39好友93人,关注者146
既然决定远行,便只顾风雨兼程。
heiyeshuwu的文章
原创 282 篇
翻译 3 篇
转载 210 篇
评论 517 篇
heiyeluren的公告

联系方式:


访问统计: free hit counter code
FeedSky订阅:
FeedSky订阅
最近评论
heiyeluren:注册发帖后才能下载。。。。不知道论坛咋设置。。。 :-)
kong:注册了也不能下载.....提示您的操作将会导致您的 金钱 低于系统规定的下限值 0
赵舜尧:感谢博主的分享,期待你的“下章接着讲述数据分割和散列方面的内容”
adobe cs4:呃,LAMP经典应用……
俺的
Adobe cs4也是
bluehouse1985:Linux 环境下的多核调试
— Intel + Totalview 强强联合!
目前,在软件开发行业,各种性能优异的调试工具层出不穷。但是,它们中的绝大部分都只支持windows环境。即使能支持linux平台,操作起来也很不方便。因此,对于长期在linux上编写程序的开发人员来说,如何调试就成了一个令人头痛的问题!Intel软件 和 Total……
文章分类
收藏
    相册
    技术图片
    搜索引擎
    ::eYou::
    kevin world
    lewis - 老吕
    qyb - BT的花
    Realzay的blog
    叶金荣
    天堂地狱鬼-dulao5's Blog
    沙漠之周
    狐狸糊涂
    老韩
    與子觀化
    ::Yahoo::
    glemir’s blog
    happy_fish - 分布式文件系统FastDFS
    LinZi's Blog
    Rainx
    stauren
    互联网,请记住我 - 162同学的技术博客
    冰的河
    小蚂蚁同学滴测试博客
    张彪同学
    随网之舞 - kaven的DHTML博客
    风雪之隅
    ::朋友::
    【推荐】中文分类网
    DDR的博客
    kevin world
    miky
    PHPCup.cn论坛
    俺兄弟的blog
    冰河的技术博客:心随风动
    好旅网
    小少的技术博客
    无尘居
    晋陵路人的Blog
    李天华同学滴技术博客
    沙狐部落
    轻量级的editor
    ::网友::
    blankyao同学
    Code & Stock.
    LionD8的Blog
    MooPHP - 轻量级PHP框架
    Phzzy
    张贺同学的博客
    技术大牛老余的博客
    抚琴居
    旋木木同学滴博客
    矛盾网
    程序人生
    邢红瑞的blog
    阿健的博客
    :PHP博客:
    .: Easy style :.
    [琴剑楼]
    CoolCode.cn
    Haohappy的Blog
    Hightman
    iwind的blog
    Javascript开发站
    JD Space
    Nio's Weblog
    Open Source PHP
    PHP面对对象
    SourceForge.net
    trip的专栏
    UGIA.cn
    windix's blog
    Windix's Weblog
    一个藏袍
    俊麟 Michael`s blog
    偶然的blog
    刘敏的blog
    大龄青年的Blog
    廖宇雷的blog
    懒猫开始新生活blog
    某人的栖息地
    王春生的博客
    神仙
    :牛人blog:
    DBA notes
    http://blog.csdn.net/tingya/
    侯捷网站
    孟岩
    搜索引擎研究
    方舟
    王咏刚的BLOG
    竹笋炒肉
    荣耀
    车东[Blog^2]
    透明思考
    陈硕的Blog
    DHTML
    DHTMLGoodies
    FCKEditor
    Google Code
    Google Web Toolkit
    HTML Goodies
    HTML.it
    HTMLAre
    HTMLdog
    JavaScript Kit
    jQuery
    KindEditor
    Prototype
    TinyMCE
    W3 Schools
    Yahoo JavaScript Developer Center
    Yahoo! Developer Network
    Yahoo! UI Library (YUI)
    网页设计师Web标准
    Java国内站
    ChinaJavaWorld.com技术论坛
    IBM developerWorks 中国: Java
    Java中文站
    Java开源大全
    Java爱好者
    JR - Java翻译站
    J道-JDON
    Matrix: 与Java共舞
    中国Java开发网
    中文java技术网
    PHP国内站点
    CSDN PHP论坛
    Discuz!
    FleaPHP
    Google--PHP用户组
    IBM DeveloperWorks
    JavsScript技术讨论
    Nirvana Studio
    OpenPHP.cn
    PHPChina
    TiM Club
    中文 PFC 1.0 手册--PHP5的开发包
    中文 PFC 1.0 手册--PHP5的开发包
    中文PHP网
    太平洋--PHP开发区
    爱MySQL
    超越PHP
    PHP国外站点
    ADOdb
    Agavi Framework
    Cake PHP
    MySQL Performance Blog
    MySQL Performance Blog
    Nonaweb
    PEAR
    PECL
    PECL Windows
    PHP Builder
    PHP Classes
    PHP Classes
    PHP New Download
    PHP Security Consortium
    php.MVC
    php.MVC
    PHPkitchen(OO & MVC)
    phpPatterns
    PHP国外图书下载
    smart template
    Smarty
    SourceForge.net
    Symfony Framework
    Zend
    Zend Framework
    Unix C/C++
    Free Gentux
    周立发的blog(Linux C)
    Unix/Linux
    BSD智库
    ChinaUnix
    FreeBSDChina
    FreeLAMP
    IBM开发者Linux专区
    Linux Byte
    LinuxKit
    LinuxTS
    Linux伊甸园
    Linux技术中坚站
    Linux非常空间
    Love Unix
    NetBSD&OpenBSD中文用户组
    NetBSD中国社区
    Oracle中国用户讨论组
    OurLinux
    Unix中文
    Unix中文
    Unix中文宝库
    中国Linux公社
    中国Unix用户技术论坛
    中文FreeBSD用户组
    永远的Unix
    炎黄角马
    程序设计
    CSDN
    IBM开发者中心
    Microsoft TechNet: 主页
    MSDN 中文网站
    PHP中文站
    Sun技术社区
    中国IT认证实验室--企业应用技术
    中国协议分析网
    喜悦国际村
    太平洋电脑网---开发特区
    实用网站
    veBook(国外大量免费图书下载网站)
    Whois.net
    中国Web信息博物馆
    中国互联网络信息中心whois查询
    服务器系统信息查看
    网络安全
    AnySide.com
    CGI Secutiry
    K-OTik Security Monitoring
    Linux Security
    Packet Storm Security
    PHP Secure
    RFC中文文档索引
    Safemode.org
    SecuriTeam.com
    Security Corporation
    SecurityFocus
    SecurityTracker
    Zone-h (区域黑客,每天公布各国被黑的网站)
    中华安全网
    中国信息安全组织
    国家计算机网络应急处理中心
    安全天使
    安全焦点
    幻影旅团
    绿盟科技
    网络安全评估中心(cnns )
    在线手册
    Apache2.0中文文档
    Beyond Linux From Scratch
    Debian参考手册
    FreeBSD Porter 手册
    FreeBSD使用手册
    Linux C函数中文参考手册
    MySQL 4.1.0 中文参考手册
    NetBSD在线手册
    OpenBSD在线FAQ
    PHP ADODB 1.99版手册中文翻译(Tripc)
    PHP中文手册(国内)
    PHP中文手册(国外)
    PostgreSQL中文文档
    Red Hat Linux 9入门指南
    Red Hat Linux 9安装指南
    Red Hat Linux 9定制手册
    中国OSS技术手册中心
    技术文档手册中心-ChinaUnix
    存档
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    转载 [转]网络安全工具开发函数库介绍收藏

    新一篇: [转]chroot使用方法和安全相关 | 旧一篇: [转]Network Programming Using Libevent

     

    网络安全工具开发函数库介绍


    作者:backend <backend@nsfocus.com>
                  <http://www.nsfocus.com>             
    日期:2000-07-16
                     
                        

    ---[[ 前言 ]]--------------------------------------------

    本文主要介绍几个在UNIX系统平台上开发网络安全工具时最常用的library。此外还提供一些如何使用这些开发库进行网络安全工具开发的设计框架和流程。希望能和对网络安全工具开发有兴趣的朋友共同交流,互相促进。

    众所周知,基于socket的网络编程已成为当今不可替代的编程方法。这种编程思想将网络通讯当作“文件”描述字进行处理,对这个“网络文件”(即 socket,套接字/套接口)的操作从编程者的角度来讲与普通的文件操作(如读、写、打开、关闭等)大同小异,从而极大地简化了网络程序开发过程。

    在众多的网络安全程序、工具和软件中都是基于socket设计和开发的。由于在安全程序中通常需要对网络通讯的细节(如连接双方地址/端口、服务类型、传输控制等)进行检查、处理或控制,象数据包截获、数据包头分析、数据包重写、甚至截断连接等,都几乎在每个网络安全程序中必须实现。为了简化网络安全程序的编写过程,提高网络安全程序的性能和健壮性,同时使代码更易重用与移植,最好的方法就是将最常用和最繁复的过程函数,如监听套接口的打开/关闭、数据包截获、数据包构造/发送/接收等,封装起来,以API library的方式提供给开发人员使用。


    ---[[ C开发库简介 ]]-------------------------------------

    在Unix系统平台上的网络安全工具开发中,目前最为流行的C API library有libnet、libpcap、libnids和libicmp等。它们分别从不同层次和角度提供了不同的功能函数。使网络开发人员能够忽略网络底层细节的实现,从而专注于程序本身具体功能的设计与开发。其中,

    * libnet提供的接口函数主要实现和封装了数据包的构造和发送过程。

    * libpcap提供的接口函数主要实现和封装了与数据包截获有关的过程。

    * libnids提供的接口函数主要实现了开发网络入侵监测系统所必须的一些结构框架。

    * libicmp等相对较为简单,它封装的是ICMP数据包的主要处理过程(构造、发送、接收等)。

    利用这些C函数库的接口,网络安全工具开发人员可以很方便地编写出具有结构化强、健壮性好、可移植性高等特点的程序,如scanner、sniffer、firewall、IDS等。

     


    ---[[ libnet ]]------------------------------------------

    libnet库的最新版本为1.0.0,它一共约7600行C源代码,33个源程序文件,12个C头文件,50余个自定义函数,提供的接口函数包含15种数据包生成器和两种数据包发送器(IP层和数据链路层)。目前只支持IPv4,不支持IPv6。已经过测试的系统平台包括:

    * OpenBSD 2.6snap, 2.5, 2.4, 2.3, 2.2 (i386)
    * FreeBSD 4.0-STABLE, 3.3-STABLE, 3.2-RELEASE, 3.1-CURRENT, 3.0, 2.2 (i386)
    * NetBSD 1.3.2 (i386)
    * BSD/OS 3.x (i386)
    * BSDi 3.0 (i386)
    * Linux 2.2.x, 2.0.3x, 2.1.124 (i386, alpha) (libc: 2.4.x, glibc: 2.0.x)
    * Solaris 7 (SPARC, gcc 2.7.2[13], 2.8.2), 2.6 (SPARC, gcc 2.8.2),
    2.5.x (SPARC, gcc 2.7.2[13])
    * IRIX 6.2
    * MacOS 5.3rhapsody (powerpc)

    libnet提供的接口函数按其作用可分为四类:

    * 内存管理(分配和释放)函数
    * 地址解析函数
    * 数据包构造函数
    * 数据包发送函数

    以下分别列出这些接口函数及其功能(其参数含义简单易懂,不再解释):


    ★ 内存管理函数

    单数据包内存初始化:
    int libnet_init_packet(u_short packet_size, u_char **buf);

    单数据包内存释放:
    void libnet_destroy_packet(u_char **buf);

    多数据包内存初始化:
    int libnet_init_packet_arena(struct libnet_arena **arena,
    u_short packet_num, u_short packet_size);

    访问多数据包内存中的下一个数据包:
    u_char *libnet_next_packet_from_arena(struct libnet_arena **arena,
    u_short packet_size);

    多数据包内存释放:
    void libnet_destroy_packet_arena(struct libnet_arena **arena);


    ★ 地址解析函数

    解析主机名:
    u_char *libnet_host_lookup(u_long ip, u_short use_name);

    解析主机名(可重入函数):
    void libnet_host_lookup_r(u_long ip, u_short use_name, u_char *buf);

    域名解析:
    u_long libnet_name_resolve(u_char *ip, u_short use_name);

    获取接口设备IP地址:
    u_long libnet_get_ipaddr(struct libnet_link_int *l,
    const u_char *device, const u_char *ebuf);

    获取接口设备硬件地址:
    struct ether_addr *libnet_get_hwaddr(struct libnet_link_int *l,
    const u_char *device,
    const u_char *ebuf);


    ★ 数据包构造函数

    ARP协议数据包:
    int libnet_build_arp(u_short hrdw, u_short prot, u_short h_len,
    u_short p_len, u_short op, u_char *s_ha,
    u_char *s_pa, u_char *t_ha, u_char *t_pa,
    const u_char *payload, int payload_len,
    u_char *packet_buf);

    DNS协议数据包:
    int libnet_build_dns(u_short id, u_short flags, u_short num_q,
    u_short num_answ_rr, u_short num_auth_rr,
    u_short num_add_rr, const u_char * payload,
    int payload_len, u_char *packet_buf);

    以太网协议数据包:
    int libnet_build_ethernet(u_char *daddr, u_char *saddr, u_short id,
    const u_char *payload, int payload_len,
    u_char *packet_buf);

    ICMP协议数据包(ICMP_ECHO / ICMP_ECHOREPLY):
    int libnet_build_icmp_echo(u_char type, u_char code, u_short id,
    u_short seq, const u_char *payload,
    int payload_len, u_char *packet_buf);

    ICMP协议数据包(ICMP_MASKREQ / ICMP_MASKREPLY):
    int libnet_build_icmp_mask(u_char type, u_char code, u_short id,
    u_short seq, u_long mask,
    const u_char *payload, int payload_len,
    u_char *packet_buf);

    ICMP协议数据包(ICMP_UNREACH):
    int libnet_build_icmp_unreach(u_char type, u_char code,
    u_short orig_len, u_char orig_tos,
    u_short orig_id, u_short orig_frag,
    u_char orig_ttl, u_char orig_prot,
    u_long orig_saddr, u_long orig_daddr,
    const u_char *payload, int payload_len,
    u_char *packet_buf);

    ICMP协议数据包(ICMP_TIMEXCEED):
    int libnet_build_icmp_timeexceed(u_char type, u_char code,
    u_short orig_len, u_char orig_tos,
    u_short orig_id, u_short orig_frag,
    u_char orig_ttl, u_char orig_prot,
    u_long orig_saddr, u_long orig_daddr,
    const u_char *payload, int payload_len,
    u_char *packet_buf);

    ICMP协议数据包(ICMP_REDIRECT):
    int libnet_build_icmp_redirect(u_char type, u_char code, u_long gateway,
    u_short orig_len, u_char orig_tos,
    u_short orig_id, u_short orig_frag,
    u_char orig_ttl, u_char orig_prot,
    u_long orig_saddr, u_long orig_daddr,
    const u_char *payload, int payload_len,
    u_char *packet_buf);

    ICMP协议数据包(ICMP_TSTAMP / ICMP_TSTAMPREPLY):
    int libnet_build_icmp_timestamp(u_char type, u_char code, u_short id,
    u_short seq, n_time otime, n_time rtime,
    n_time ttime, const u_char *payload,
    int payload_len, u_char *packet_buf);

    IGMP协议数据包:
    int libnet_build_igmp(u_char type, u_char code, u_long ip,
    const u_char *payload, int payload_len,
    u_char *packet_buf);

    IP协议数据包:
    int libnet_build_ip(u_short len, u_char tos, u_short ip_id, u_short frag,
    u_char ttl, u_char protocol, u_long saddr,
    u_long daddr, const u_char *payload, int payload_len,
    u_char *packet_buf);

    OSPF路由协议数据包:
    int libnet_build_ospf(u_short len, u_char type, u_long router_id,
    u_long area_id, u_short auth_type,
    const char *payload, int payload_s, u_char *buf);

    OSPF路由协议数据包(Hello):
    int libnet_build_ospf_hello(u_long netmask, u_short interval,
    u_char options, u_char priority,
    u_int dead_interval, u_long des_router,
    u_long backup, u_long neighbor,
    const char *payload, int payload_s,
    u_char *buf);

    OSPF路由协议数据包(DataBase Description (DBD)):
    int libnet_build_ospf_dbd(u_short len, u_char options, u_char type,
    u_int sequence_num, const char *payload,
    int payload_s, u_char *buf);

    OSPF路由协议数据包(Link State Request (LSR)):
    int libnet_build_ospf_lsr(u_int type, u_int ls_id, u_long adv_router,
    const char *payload, int payload_s,
    u_char *buf);

    OSPF路由协议数据包(Link State Update (LSU)):
    int libnet_build_ospf_lsu(u_int num, const char *payload,
    int payload_s, u_char *buf);

    OSPF路由协议数据包(Link State Acknowledgement (LSA)):
    int libnet_build_ospf_lsa(u_short age, u_char options, u_char type,
    u_int ls_id, u_long adv_router,
    u_int sequence_num, u_short len,
    const char *payload, int payload_s,
    u_char *buf);

    OSPF路由协议数据包(OSPF Link Sate NetworkLink State Router):
    int libnet_build_ospf_lsa_net(u_long netmask, u_int router_id,
    const char *payload, int payload_s,
    u_char *buf);

    OSPF路由协议数据包(Link State Router):
    int libnet_build_ospf_lsa_rtr(u_short flags, u_short num, u_int id,
    u_int data, u_char type, u_char tos,
    u_short metric, const char *payload,
    int payload_s, u_char *buf);

    OSPF路由协议数据包(Link State Summary):
    int libnet_build_ospf_lsa_sum(u_long netmask, u_int metric, u_int tos,
    const char *payload, int payload_s,
    u_char *buf);

    OSPF路由协议数据包(Link State AS External):
    int libnet_build_ospf_lsa_as(u_long netmask, u_int metric,
    u_long fwd_addr, u_int tag,
    const char *payload, int payload_s,
    u_char *buf);

    RIP路由协议数据包:
    int libnet_build_rip(u_char cmd, u_char ver, u_short domain,
    u_short addr_fam, u_short route_tag, u_long ip,
    u_long mask, u_long next_hop, u_long metric,
    const u_char *payload, int payload_len,
    u_char *packet_buf);

    TCP协议数据包:
    int libnet_build_tcp(u_short th_sport, u_short th_dport, u_long th_seq,
    u_long th_ack, u_char th_flags, u_short th_win,
    u_short th_urg, const u_char *payload,
    int payload_len, u_char *packet_buf);

    UDP协议数据包:
    int libnet_build_udp(u_short sport, u_short dport, const u_char *payload,
    int payload_len, u_char *packet_buf);

    IP协议数据包选项:
    int libnet_insert_ipo(struct ipoption *opt, u_char opt_len,
    u_char *packet_buf);

    TCP协议数据包选项:
    int libnet_insert_tcpo(struct tcpoption *opt, u_char opt_len,
    u_char *packet_buf);


    ★ 数据包发送函数

    打开raw socket:
    int libnet_open_raw_sock(int protocol);

    关闭raw socket:
    int libnet_close_raw_sock(int socket);

    选择接口设备:
    int libnet_select_device(struct sockaddr_in *sin,
    u_char **device, u_char *ebuf);

    打开链路层接口设备:
    struct libnet_link_int *libnet_open_link_interface(char *device,
    char *ebuf);

    关闭链路层接口设备:
    int libnet_close_link_interface(struct libnet_link_int *l);

    发送IP数据包:
    int libnet_write_ip(int socket, u_char *packet, int packet_size);

    发送链路层数据包:
    int libnet_write_link_layer(struct libnet_link_int *l,
    const u_char *device, u_char *packet,
    int packet_size);

    检验和计算:
    int libnet_do_checksum(u_char *packet, int protocol, int packet_size);


    ★ 相关的支持函数

    随机数种子生成器:
    int libnet_seed_prand();

    获取随机数:
    u_long libnet_get_prand(int modulus);

    16进制数据输出:
    void libnet_hex_dump(u_char * buf, int len, int swap, FILE *stream);

    端口列表链初始化:
    int libnet_plist_chain_new(struct libnet_plist_chain **plist,
    char *token_list);

    获取端口列表链的下一项(端口范围):
    int libnet_plist_chain_next_pair(struct libnet_plist_chain *plist,
    u_short *bport, u_short *eport);

    端口列表链输出显示:
    int libnet_plist_chain_dump(struct libnet_plist_chain *plist);

    获取端口列表链:
    u_char *libnet_plist_chain_dump_string(struct libnet_plist_chain *plist);

    端口列表链内存释放:
    void libnet_plist_chain_free(struct libnet_plist_chain *plist);


    ★ 数据常量

    ==================================================================================
    数据包头大小定义:

    常量名 数值(字节数)
    LIBNET_ARP_H 28
    LIBNET_DNS_H 12
    LIBNET_ETH_H 14
    LIBNET_ICMP_H 4
    LIBNET_ICMP_ECHO_H 8
    LIBNET_ICMP_MASK_H 12
    LIBNET_ICMP_UNREACH_H 8
    LIBNET_ICMP_TIMXCEED_H 8
    LIBNET_ICMP_REDIRECT_H 8
    LIBNET_ICMP_TS_H 20
    LIBNET_IGMP_H 8
    LIBNET_IP_H 20
    LIBNET_RIP_H 24
    LIBNET_TCP_H 20
    LIBNET_UDP_H 8

    ==================================================================================
    数据包内存常量:

    常量名 含义
    LIBNET_PACKET TCP/UDP数据包头 + IP数据包头使用的内存
    LIBNET_OPTS IP或TCP选项使用的内存
    LIBNET_MAX_PACKET IP_MAXPACKET (65535字节)使用的内存

    ==================================================================================
    随机数发生器常量(libnet_get_prand()函数使用):

    常量名 数值
    LIBNET_PRAND_MAX 65535
    LIBNET_PR2 0 - 2
    LIBNET_PR8 0 - 255
    LIBNET_PR16 0 - 32767
    LIBNET_PRu16 0 - 65535
    LIBNET_PR32 0 - 2147483647
    LIBNET_PRu32 0 - 4294967295

    ==================================================================================
    错误消息常量(libnet_error()函数使用):

    常量名 含义
    LIBNET_ERR_WARNING 警告类型消息
    LIBNET_ERR_CRITICAL 紧急类型消息
    LIBNET_ERR_FATAL 致命错误消息

    ==================================================================================
    libnet_host_lookup()、libnet_host_lookup_r()和libnet_name_resolve()函数使用的常量:

    常量名 含义
    LIBNET_DONT_RESOLVE 不将IP地址解析为FQDN名
    LIBNET_RESOLVE 尝试将IP地址解析为FQDN名

    ==================================================================================
    宏定义

    宏名 功能
    LIBNET_GET_ARENA_SIZE(arena) 返回多数据包内存缓冲区大小(字节数)
    LIBNET_GET_ARENA_REMAINING_BYTES(arena) 返回多数据包内存缓冲区剩余空间大小(字节数)
    LIBNET_PRINT_ETH_ADDR(e) 输出显示ether_addr结构中的以太网地址

    ==================================================================================


    ---[[ libnet应用实例 ]]----------------------------------

    利用libnet函数库开发应用程序的基本步骤非常简单:

    1、数据包内存初始化;
    2、网络接口初始化;
    3、构造所需数据包;
    4、计算数据包检验和;
    5、发送数据包;
    6、关闭网络接口;
    7、释放数据包内存。

    以下是四个使用了libnet接口函数编写的数据包发送程序。在编译前必须确保libnet库已成功安装。


    ============================ cut here ============================

    /* Example 1 [raw socket api - TCP packet] */
    /* gcc -Wall `libnet-config --defines` libnet-example-x.c -o libnet-example-x \
    `libnet-config --libs` */

    #include <libnet.h>

    void usage(char *);

    int main(int argc, char **argv)
    {
    int network, /* our network interface */
    packet_size, /* packet size */
    c; /* misc */
    u_long src_ip, dst_ip; /* ip addresses */
    u_short src_prt, dst_prt; /* ports */
    u_char *cp, *packet; /* misc / packet */

    printf("libnet example code:\tmodule 1\n\n");
    printf("packet injection interface:\traw socket\n");
    printf("packet type:\t\t\tTCP [no payload]\n");

    src_ip = 0;
    dst_ip = 0;
    src_prt = 0;
    dst_prt = 0;

    while((c = getopt(argc, argv, "d:s:")) != EOF)
    {
    switch (c)
    {
    /*
    * We expect the input to be of the form `ip.ip.ip.ip.port`. We
    * point cp to the last dot of the IP address/port string and
    * then seperate them with a NULL byte. The optarg now points to
    * just the IP address, and cp points to the port.
    */
    case 'd':
    if (!(cp = strrchr(optarg, '.')))
    {
    usage(argv[0]);
    }
    *cp++ = 0;
    dst_prt = (u_short)atoi(cp);
    if (!(dst_ip = libnet_name_resolve(optarg, LIBNET_RESOLVE)))
    {
    libnet_error(LIBNET_ERR_FATAL,
    "Bad destination IP address: %s\n", optarg);
    }
    break;
    case 's':
    if (!(cp = strrchr(optarg, '.')))
    {
    usage(argv[0]);
    }
    *cp++ = 0;
    src_prt = (u_short)atoi(cp);
    if (!(src_ip = libnet_name_resolve(optarg, LIBNET_RESOLVE)))
    {
    libnet_error(LIBNET_ERR_FATAL,
    "Bad source IP address: %s\n", optarg);
    }
    break;
    }
    }
    if (!src_ip || !src_prt || !dst_ip || !dst_prt)
    {
    usage(argv[0]);
    exit(EXIT_FAILURE);
    }

    /*
    * We're just going to build a TCP packet with no payload using the
    * raw sockets API, so we only need memory for a TCP header and an IP
    * header.
    */
    packet_size = LIBNET_IP_H + LIBNET_TCP_H;

    /*
    * Step 1: Memory initialization (interchangable with step 2).
    */
    libnet_init_packet(packet_size, &packet);
    if (packet == NULL)
    {
    libnet_error(LIBNET_ERR_FATAL, "libnet_init_packet failed\n");
    }

    /*
    * Step 2: Network initialization (interchangable with step 1).
    */
    network = libnet_open_raw_sock(IPPROTO_RAW);
    if (network == -1)
    {
    libnet_error(LIBNET_ERR_FATAL, "Can't open network.\n");
    }

    /*
    * Step 3: Packet construction (IP header).
    */
    libnet_build_ip(LIBNET_TCP_H, /* size of the packet sans IP header */
    IPTOS_LOWDELAY, /* IP tos */
    242, /* IP ID */
    0, /* frag stuff */
    48, /* TTL */
    IPPROTO_TCP, /* transport protocol */
    src_ip, /* source IP */
    dst_ip, /* destination IP */
    NULL, /* payload (none) */
    0, /* payload length */
    packet); /* packet header memory */

    /*
    * Step 3: Packet construction (TCP header).
    */
    libnet_build_tcp(src_prt, /* source TCP port */
    dst_prt, /* destination TCP port */
    0xa1d95, /* sequence number */
    0x53, /* acknowledgement number */
    TH_SYN, /* control flags */
    1024, /* window size */
    0, /* urgent pointer */
    NULL, /* payload (none) */
    0, /* payload length */
    packet + LIBNET_IP_H); /* packet header memory */

    /*
    * Step 4: Packet checksums (TCP header only).
    */
    if (libnet_do_checksum(packet, IPPROTO_TCP, LIBNET_TCP_H) == -1)
    {
    libnet_error(LIBNET_ERR_FATAL, "libnet_do_checksum failed\n");
    }

    /*
    * Step 5: Packet injection.
    */
    c = libnet_write_ip(network, packet, packet_size);
    if (c < packet_size)
    {
    libnet_error(LN_ERR_WARNING,
    "libnet_write_ip only wrote %d bytes\n", c);
    }
    else
    {
    printf("construction and injection completed, wrote all %d bytes\n", c);
    }

    /*
    * Shut down the interface.
    */
    if (libnet_close_raw_sock(network) == -1)
    {
    libnet_error(LN_ERR_WARNING,
    "libnet_close_raw_sock couldn't close the interface");
    }


    /*
    * Free packet memory.
    */
    libnet_destroy_packet(&packet);

    return (c == -1 ? EXIT_FAILURE : EXIT_SUCCESS);
    }


    void usage(char *name)
    {
    fprintf(stderr, "usage: %s -s s_ip.s_port -d d_ip.d_port\n", name);
    }


    ============================ cut here ============================

    /* Example 2 [link layer api - ICMP_MASK] */
    /* gcc -Wall `libnet-config --defines` libnet-example-x.c -o libnet-example-x `libnet-config --libs` */

    #include <libnet.h>

    void usage(char *);

    u_char enet_src[6] = {0x0d, 0x0e, 0x0a, 0x0d, 0x00, 0x00};
    u_char enet_dst[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};

    int
    main(int argc, char *argv[])
    {
    int packet_size, /* size of our packet */
    c; /* misc */
    u_long src_ip, dst_ip; /* source ip, dest ip */
    u_char *packet; /* pointer to our packet buffer */
    char err_buf[LIBNET_ERRBUF_SIZE]; /* error buffer */
    u_char *device; /* pointer to the device to use */
    struct libnet_link_int *network; /* pointer to link interface struct */

    printf("libnet example code:\tmodule 2\n\n");
    printf("packet injection interface:\tlink layer\n");
    printf("packet type:\t\t\tICMP net mask [no payload]\n");

    device = NULL;
    src_ip = 0;
    dst_ip = 0;

    while ((c = getopt(argc, argv, "i:d:s:")) != EOF)
    {
    switch (c)
    {
    case 'd':
    if (!(dst_ip = libnet_name_resolve(optarg, LIBNET_RESOLVE)))
    {
    libnet_error(LIBNET_ERR_FATAL,
    "Bad destination IP address: %s\n", optarg);

    }
    break;
    case 'i':
    device = optarg;
    break;
    case 's':
    if (!(src_ip = libnet_name_resolve(optarg, LIBNET_RESOLVE)))
    {
    libnet_error(LIBNET_ERR_FATAL,
    "Bad source IP address: %s\n", optarg);
    }
    break;
    default:
    exit(EXIT_FAILURE);
    }
    }

    if (!src_ip || !dst_ip)
    {
    usage(argv[0]);
    exit(EXIT_FAILURE);
    }

    /*
    * Step 1: Network Initialization (interchangable with step 2).
    */
    if (device == NULL)
    {
    struct sockaddr_in sin;
    /*
    * Try to locate a device.
    */
    if (libnet_select_device(&sin, &device, err_buf) == -1)
    {
    libnet_error(LIBNET_ERR_FATAL,
    "libnet_select_device failed: %s\n", err_buf);
    }
    printf("device:\t\t\t\t%s\n", device);
    }

    if ((network = libnet_open_link_interface(device, err_buf)) == NULL)
    {
    libnet_error(LIBNET_ERR_FATAL,
    "libnet_open_link_interface: %s\n", err_buf);
    }

    /*
    * We're going to build an ICMP packet with no payload using the
    * link-layer API, so this time we need memory for a ethernet header
    * as well as memory for the ICMP and IP headers.
    */
    packet_size = LIBNET_IP_H + LIBNET_ETH_H + LIBNET_ICMP_MASK_H;


    /*
    * Step 2: Memory Initialization (interchangable with step 1).
    */
    if (libnet_init_packet(packet_size, &packet) == -1)
    {
    libnet_error(LIBNET_ERR_FATAL, "libnet_init_packet failed\n");
    }


    /*
    * Step 3: Packet construction (ethernet header).
    */
    libnet_build_ethernet(enet_dst,
    enet_src,
    ETHERTYPE_IP,
    NULL,
    0,
    packet);

    /*
    * Step 3: Packet construction (ICMP header).
    */
    libnet_build_icmp_mask(ICMP_MASKREPLY, /* type */
    0, /* code */
    242, /* id */
    0, /* seq */
    0xffffffff, /* mask */
    NULL, /* payload */
    0, /* payload_s */
    packet + LIBNET_ETH_H + LIBNET_IP_H);


    /*
    * Step 3: Packet construction (IP header).
    */
    libnet_build_ip(ICMP_MASK_H,
    0, /* IP tos */
    242, /* IP ID */
    0, /* Frag */
    64, /* TTL */
    IPPROTO_ICMP, /* Transport protocol */
    src_ip, /* Source IP */
    dst_ip, /* Destination IP */
    NULL, /* Pointer to payload (none) */
    0,
    packet + LIBNET_ETH_H); /* Packet header memory */

    /*
    * Step 4: Packet checksums (ICMP header *AND* IP header).
    */
    if (libnet_do_checksum(packet + ETH_H, IPPROTO_ICMP, LIBNET_ICMP_MASK_H) == -1)
    {
    libnet_error(LIBNET_ERR_FATAL, "libnet_do_checksum failed\n");
    }
    if (libnet_do_checksum(packet + ETH_H, IPPROTO_IP, LIBNET_IP_H) == -1)
    {
    libnet_error(LIBNET_ERR_FATAL, "libnet_do_checksum failed\n");
    }


    /*
    * Step 5: Packet injection.
    */
    c = libnet_write_link_layer(network, device, packet, packet_size);
    if (c < packet_size)
    {
    libnet_error(LN_ERR_WARNING,
    "libnet_write_link_layer only wrote %d bytes\n", c);
    }
    else
    {
    printf("construction and injection completed, wrote all %d bytes\n", c);
    }


    /*
    * Shut down the interface.
    */
    if (libnet_close_link_interface(network) == -1)
    {
    libnet_error(LN_ERR_WARNING,
    "libnet_close_link_interface couldn't close the interface");
    }


    /*
    * Free packet memory.
    */
    libnet_destroy_packet(&packet);

    return (c == -1 ? EXIT_FAILURE : EXIT_SUCCESS);
    }

    void usage(char *name)
    {
    fprintf(stderr, "usage: %s [-i interface] -s s_ip -d d_ip\n", name);
    }


    ============================ cut here ============================

    /* Example 3 [raw socket api - ICMP_ECHO using an arena] */
    /* gcc -Wall `libnet-config --defines` libnet-example-x.c -o libnet-example-x \
    `libnet-config --libs` */

    #include <libnet.h>

    void usage(char *);


    int main(int argc, char **argv)
    {
    int network, n, c, number_of_packets, packet_size;
    struct libnet_arena arena, *arena_p;
    u_char *packets[10];
    u_long src_ip, dst_ip;

    printf("libnet example code:\tmodule 3\n\n");
    printf("packet injection interface:\tlink layer\n");
    printf("packet type:\t\t\tICMP_ECHO [no payload] using an arena\n");

    src_ip = 0;
    dst_ip = 0;
    while((c = getopt(argc, argv, "d:s:")) != EOF)
    {
    switch (c)
    {
    case 'd':
    if (!(dst_ip = libnet_name_resolve(optarg, LIBNET_RESOLVE)))
    {
    libnet_error(LIBNET_ERR_FATAL,
    "Bad destination IP address: %s\n", optarg);
    }
    break;
    case 's':
    if (!(src_ip = libnet_name_resolve(optarg, LIBNET_RESOLVE)))
    {
    libnet_error(LIBNET_ERR_FATAL,
    "Bad source IP address: %s\n", optarg);
    }
    break;
    }
    }
    if (!src_ip || !dst_ip)
    {
    usage(argv[0]);
    exit(EXIT_FAILURE);
    }

    /*
    * We're just going to build an ICMP packet with no payload using the
    * raw sockets API, so we only need memory for a ICMP header and an IP
    * header.
    */
    packet_size = LIBNET_IP_H + LIBNET_ICMP_ECHO_H;

    /*
    * Let's just build say, 10 packets.
    */
    number_of_packets = 10;

    arena_p = &arena;
    if (libnet_init_packet_arena(&arena_p, number_of_packets, packet_size) == -1)
    {
    libnet_error(LIBNET_ERR_FATAL, "libnet_init_packet_arena failed\n");
    }
    else
    {
    printf("Allocated an arena of %ld bytes..\n",
    LIBNET_GET_ARENA_SIZE(arena));
    }

    network = libnet_open_raw_sock(IPPROTO_RAW);
    if (network == -1)
    {
    libnet_error(LIBNET_ERR_FATAL, "Can't open the network.\n");
    }

    for (n = 0; n < number_of_packets; n++)
    {
    printf("%ld bytes remaining in arena\n",
    LIBNET_GET_ARENA_REMAINING_BYTES(arena));
    packets[n] = libnet_next_packet_from_arena(&arena_p, packet_size);
    if (!packets[n])
    {
    libnet_error(LIBNET_ERR_WARNING, "Arena is empty\n");
    continue;
    }

    libnet_build_ip(ICMP_ECHO_H, /* Size of the payload */
    IPTOS_LOWDELAY | IPTOS_THROUGHPUT, /* IP tos */
    242, /* IP ID */
    0, /* frag stuff */
    48, /* TTL */
    IPPROTO_ICMP, /* transport protocol */
    src_ip, /* source IP */
    dst_ip, /* destination IP */
    NULL, /* pointer to payload */
    0, /* payload length */
    packets[n]); /* packet header memory */

    libnet_build_icmp_echo(ICMP_ECHO, /* type */
    0, /* code */
    242, /* id */
    5, /* seq */
    NULL, /* pointer to payload */
    0, /* payload length */
    packets[n] + LIBNET_IP_H); /* packet header memory */

    if (libnet_do_checksum(packets[n], IPPROTO_ICMP, LIBNET_ICMP_ECHO_H) == -1)
    {
    libnet_error(LIBNET_ERR_FATAL, "libnet_do_checksum failed\n");
    }

    c = libnet_write_ip(network, packets[n], packet_size);
    if (c < packet_size)
    {
    libnet_error(LN_ERR_WARNING,
    "libnet_write_ip only wrote %d bytes\n", c);
    }
    else
    {
    printf("construction and injection of packet %d of %d completed, wrote all %d bytes\n",
    n + 1, number_of_packets, c);
    }
    }

    libnet_destroy_packet_arena(&arena_p);
    return (c == -1 ? EXIT_FAILURE : EXIT_SUCCESS);
    }


    void usage(char *name)
    {
    fprintf(stderr, "usage: %s -s source_ip -d destination_ip\n ", name);
    }


    ============================ cut here ============================

    /* Example 4 [link-layer api - UDP packet using port list chaining] */
    /* gcc -Wall `libnet-config --defines` libnet-example-x.c -o libnet-example-x \
    `libnet-config --libs` */

    #include <libnet.h>

    #define MAX_PAYLOAD_SIZE 1024

    void usage(char *);

    u_char enet_src[6] = {0x0d, 0x0e, 0x0a, 0x0d, 0x00, 0x00};
    u_char enet_dst[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};

    int main(int argc, char *argv[])
    {
    int packet_size, /* size of our packet */
    payload_size, /* size of our packet */
    c; /* misc */
    u_long src_ip, dst_ip; /* source ip, dest ip */
    u_short bport, eport; /* beginning and end ports */
    u_short cport; /* current port */
    u_char payload[MAX_PAYLOAD_SIZE]; /* packet payload */
    u_char *packet; /* pointer to our packet buffer */
    char err_buf[LIBNET_ERRBUF_SIZE]; /* error buffer */
    u_char *device; /* pointer to the device to use */
    struct libnet_link_int *network; /* pointer to link interface struct */
    struct libnet_plist_chain plist; /* plist chain */
    struct libnet_plist_chain *plist_p; /* plist chain pointer */

    printf("libnet example code:\tmodule 4\n\n");
    printf("packet injection interface:\tlink layer\n");
    printf("packet type:\t\t\tUDP [with payload] using port list chaining\n");

    plist_p = NULL;
    device = NULL;
    src_ip = 0;
    dst_ip = 0;

    while ((c = getopt(argc, argv, "i:d:s:p:")) != EOF)
    {
    switch (c)
    {
    case 'd':
    if (!(dst_ip = libnet_name_resolve(optarg, LIBNET_RESOLVE)))
    {
    libnet_error(LIBNET_ERR_FATAL,
    "Bad destination IP address: %s\n", optarg);

    }
    break;
    case 'i':
    device = optarg;
    break;
    case 's':
    if (!(src_ip = libnet_name_resolve(optarg, LIBNET_RESOLVE)))
    {
    libnet_error(LIBNET_ERR_FATAL,
    "Bad source IP address: %s\n", optarg);
    }
    break;
    case 'p':
    plist_p = &plist;
    if (libnet_plist_chain_new(&plist_p, optarg) == -1)
    {
    libnet_error(LIBNET_ERR_FATAL,
    "Could not build port list\n");
    }
    break;
    default:
    usage(argv[0]);
    exit(EXIT_FAILURE);
    }
    }

    if (!src_ip || !dst_ip || !plist_p)
    {
    usage(argv[0]);
    exit(EXIT_FAILURE);
    }

    c = argc - optind;
    if (c != 1)
    {
    usage(argv[0]);
    exit(EXIT_FAILURE);
    }
    memset(payload, 0, sizeof(payload));
    strncpy(payload, argv[optind], strlen(argv[optind]));


    /*
    * Step 1: Network Initialization (interchangable with step 2).
    */
    if (device == NULL)
    {
    struct sockaddr_in sin;
    /*
    * Try to locate a device.
    */
    if (libnet_select_device(&sin, &device, err_buf) == -1)
    {
    libnet_error(LIBNET_ERR_FATAL,
    "libnet_select_device failed: %s\n", err_buf);
    }
    printf("device:\t\t\t\t%s\n", device);
    }
    if ((network = libnet_open_link_interface(device, err_buf)) == NULL)
    {
    libnet_error(LIBNET_ERR_FATAL,
    "libnet_open_link_interface: %s\n", err_buf);
    }

    /*
    * Get the payload from the user. Hrm. This might fail on a Sparc
    * if byte alignment is off...
    */
    payload_size = strlen(payload);

    /*
    * We're going to build a UDP packet with a payload using the
    * link-layer API, so this time we need memory for a ethernet header
    * as well as memory for the ICMP and IP headers and our payload.
    */
    packet_size = LIBNET_IP_H + LIBNET_ETH_H + LIBNET_UDP_H + payload_size;

    /*
    * Step 2: Memory Initialization (interchangable with step 1).
    */
    if (libnet_init_packet(packet_size, &packet) == -1)
    {
    libnet_error(LIBNET_ERR_FATAL, "libnet_init_packet failed\n");
    }


    /*
    * Step 3: Packet construction (ethernet header).
    */
    libnet_build_ethernet(enet_dst,
    enet_src,
    ETHERTYPE_IP,
    NULL,
    0,
    packet);

    /*
    * Step 3: Packet construction (IP header).
    */
    libnet_build_ip(LIBNET_UDP_H + payload_size,
    0, /* IP tos */
    242, /* IP ID */
    0, /* Frag */
    64, /* TTL */
    IPPROTO_UDP, /* Transport protocol */
    src_ip, /* Source IP */
    dst_ip, /* Destination IP */
    NULL, /* Pointer to payload (none) */
    0,
    packet + LIBNET_ETH_H); /* Packet header memory */

    while (libnet_plist_chain_next_pair(plist_p, &bport, &eport))
    {

    while (!(bport > eport) && bport != 0)
    {
    cport = bport++;
    /*
    * Step 3: Packet construction (UDP header).
    */
    libnet_build_udp(242, /* source port */
    cport, /* dest. port */
    payload, /* payload */
    payload_size, /* payload length */
    packet + LIBNET_ETH_H + LIBNET_IP_H);

    /*
    * Step 4: Packet checksums (ICMP header *AND* IP header).
    */
    if (libnet_do_checksum(packet + ETH_H, IPPROTO_UDP, LIBNET_UDP_H + payload_size) == -1)
    {
    libnet_error(LIBNET_ERR_FATAL, "libnet_do_checksum failed\n");
    }
    if (libnet_do_checksum(packet + ETH_H, IPPROTO_IP, LIBNET_IP_H) == -1)
    {
    libnet_error(LIBNET_ERR_FATAL, "libnet_do_checksum failed\n");
    }

    /*
    * Step 5: Packet injection.
    */
    c = libnet_write_link_layer(network, device, packet, packet_size);
    if (c < packet_size)
    {
    libnet_error(LN_ERR_WARNING,
    "libnet_write_link_layer only wrote %d bytes\n", c);
    }
    else
    {
    printf("construction and injection completed, wrote all %d bytes, port %d\n",
    c, cport);
    }
    }
    }
    /*
    * Shut down the interface.
    */
    if (libnet_close_link_interface(network) == -1)
    {
    libnet_error(LN_ERR_WARNING,
    "libnet_close_link_interface couldn't close the interface");
    }


    /*
    * Free packet memory.
    */
    libnet_destroy_packet(&packet);

    return (c == -1 ? EXIT_FAILURE : EXIT_SUCCESS);
    }


    void usage(char *name)
    {
    fprintf(stderr, "usage: %s [-i interface] -s s_ip -d d_ip -p port list payload\n", name);
    }

     

     


    ---[[ libpcap ]]------------------------------------------

      libpcap的英文意思是 Packet Capturelibrary,即数据包捕获函数库。该库提供的C函数接口可用于需要捕获经过网络接口(只要经过该接口,目标地址不一定为本机)数据包的系统开发上。由Berkeley大学Lawrence Berkeley National Laboratory研究院的Van Jacobson、CraigLeres和Steven McCanne编写,目前的最新版本为0.4。该函数库支持Linux、Solaris和*BSD系统平台。

      主要接口函数说明如下:

    pcap_t *pcap_open_live(char *device, int snaplen,
    int promisc, int to_ms, char *ebuf)

    获得用于捕获网络数据包的数据包捕获描述字。device参数为指定打开
    的网络设备名。snaplen参数定义捕获数据的最大字节数。promisc指定
    是否将网络接口置于混杂模式。to_ms参数指定超时时间(毫秒)。
    ebuf参数则仅在pcap_open_live()函数出错返回NULL时用于传递错误消
    息。

    pcap_t *pcap_open_offline(char *fname, char *ebuf)

    打开以前保存捕获数据包的文件,用于读取。fname参数指定打开的文
    件名。该文件中的数据格式与tcpdump和tcpslice兼容。"-"为标准输
    入。ebuf参数则仅在pcap_open_offline()函数出错返回NULL时用于传
    递错误消息。

    pcap_dumper_t *pcap_dump_open(pcap_t *p, char *fname)

    打开用于保存捕获数据包的文件,用于写入。fname参数为"-"时表示
    标准输出。出错时返回NULL。p参数为调用pcap_open_offline()或
    pcap_open_live()函数后返回的pcap结构指针。fname参数指定打开
    的文件名。如果返回NULL,则可调用pcap_geterr()函数获取错误消
    息。

    char *pcap_lookupdev(char *errbuf)

    用于返回可被pcap_open_live()或pcap_lookupnet()函数调用的网络
    设备名指针。如果函数出错,则返回NULL,同时errbuf中存放相关的
    错误消息。

    int pcap_lookupnet(char *device, bpf_u_int32 *netp,
    bpf_u_int32 *maskp, char *errbuf)

    获得指定网络设备的网络号和掩码。netp参数和maskp参数都是
    bpf_u_int32指针。如果函数出错,则返回-1,同时errbuf中存放相
    关的错误消息。

    int pcap_dispatch(pcap_t *p, int cnt,
    pcap_handler callback, u_char *user)

    捕获并处理数据包。cnt参数指定函数返回前所处理数据包的最大值。
    cnt=-1表示在一个缓冲区中处理所有的数据包。cnt=0表示处理所有
    数据包,直到产生以下错误之一:读取到EOF;超时读取。callback
    参数指定一个带有三个参数的回调函数,这三个参数为:一个从
    pcap_dispatch()函数传递过来的u_char指针,一个pcap_pkthdr结构
    的指针,和一个数据包大小的u_char指针。如果成功则返回读取到的
    字节数。读取到EOF时则返回零值。出错时则返回-1,此时可调用
    pcap_perror()或pcap_geterr()函数获取错误消息。

    int pcap_loop(pcap_t *p, int cnt,
    pcap_handler callback, u_char *user)

    功能基本与pcap_dispatch()函数相同,只不过此函数在cnt个数据包
    被处理或出现错误时才返回,但读取超时不会返回。而如果为
    pcap_open_live()函数指定了一个非零值的超时设置,然后调用
    pcap_dispatch()函数,则当超时发生时pcap_dispatch()函数会返回。
    cnt参数为负值时pcap_loop()函数将始终循环运行,除非出现错误。

    void pcap_dump(u_char *user, struct pcap_pkthdr *h,
    u_char *sp)

    向调用pcap_dump_open()函数打开的文件输出一个数据包。该函数可
    作为pcap_dispatch()函数的回调函数。

    int pcap_compile(pcap_t *p, struct bpf_program *fp,
    char *str, int optimize, bpf_u_int32 netmask)

    将str参数指定的字符串编译到过滤程序中。fp是一个bpf_program结
    构的指针,在pcap_compile()函数中被赋值。optimize参数控制结果
    代码的优化。netmask参数指定本地网络的网络掩码。

    int pcap_setfilter(pcap_t *p, struct bpf_program *fp)

    指定一个过滤程序。fp参数是bpf_program结构指针,通常取自
    pcap_compile()函数调用。出错时返回-1;成功时返回0。

    u_char *pcap_next(pcap_t *p, struct pcap_pkthdr *h)

    返回指向下一个数据包的u_char指针。

    int pcap_datalink(pcap_t *p)

    返回数据链路层类型,例如DLT_EN10MB。

    int pcap_snapshot(pcap_t *p)

    返回pcap_open_live被调用后的snapshot参数值。

    int pcap_is_swapped(pcap_t *p)

    返回当前系统主机字节与被打开文件的字节顺序是否不同。

    int pcap_major_version(pcap_t *p)

    返回写入被打开文件所使用的pcap函数的主版本号。

    int pcap_minor_version(pcap_t *p)

    返回写入被打开文件所使用的pcap函数的辅版本号。

    int pcap_stats(pcap_t *p, struct pcap_stat *ps)

    向pcap_stat结构赋值。成功时返回0。这些数值包括了从开始
    捕获数据以来至今共捕获到的数据包统计。如果出错或不支持
    数据包统计,则返回-1,且可调用pcap_perror()或
    pcap_geterr()函数来获取错误消息。

    FILE *pcap_file(pcap_t *p)

    返回被打开文件的文件名。

    int pcap_fileno(pcap_t *p)

    返回被打开文件的文件描述字号码。

    void pcap_perror(pcap_t *p, char *prefix)

    在标准输出设备上显示最后一个pcap库错误消息。以prefix参
    数指定的字符串为消息头。

    char *pcap_geterr(pcap_t *p)

    返回最后一个pcap库错误消息。

    char *pcap_strerror(int error)

    如果strerror()函数不可用,则可调用pcap_strerror函数替代。

    void pcap_close(pcap_t *p)

    关闭p参数相应的文件,并释放资源。

    void pcap_dump_close(pcap_dumper_t *p)

    关闭相应的被打开文件。

     

    <<< 待续 >>>

     


    <<< 续前 >>>

    ---[[ libnids ]]------------------------------------------


    一、简介

        libnids的英文意思是 Network Intrusion Detect System library,即网络入侵监测系统函数库。它是在前面介绍的两种C函数接口库libnet和libpcap的基础上开发的,封装了开发NIDS所需的许多通用型函数。linids提供的接口函数监视流经本地的所有网络通信,检查数据包等。除此之外,还具有重组TCP数据段、处理IP分片包和监测TCP端口扫描的功能。利用libnids接口函数库,NIDS开发者不需要再编写底层的网络处理代码,只需专注于NIDS本身功能的实现即可。
        libnids支持Linux、Solaris和*BSD系统平台,目前最新版本为1.13。


    二、IP分片数据包

        为了使libnids能接收所有的IP数据包(包括分片包、畸形包等),程序员需要定义如下的回调函数:

            void ip_frag_func(struct ip * a_packet)

    在调用nids_init()函数初始化后,使用nids的函数进行注册:

            nids_register_ip_frag(ip_frag_func);

    这样回调函数ip_frag_func会在适当的时候由libnids调用,参数a_packet指针将指向接收到的数据报。
        类似地,如果仅接收目标主机会接受的数据包(如非碎片包、重组包或头部校验正确的数据包等),需要定义如下回调函数:

            void ip_func(struct ip * a_packet)

    然后注册:

            nids_register_ip(ip_func);


    三、TCP数据流重组

        要接收TCP流在交换的数据,必须定义如下回调函数:

            void tcp_callback(struct tcp_stream * ns, void ** param)

    tcp_stream结构提供了一个TCP连接的所有信息。例如,它包含了客户端与服务器端的half_stream结构。下文会对该结构的字段进行解释。
        tcp_stream结构有一个名为nids_state的字段。此字段的数值将决定tcp_callback的操作。
       
        (a) ns->nids_state==NIDS_JUST_EST时,ns表示一个刚刚建立的连接。
            tcp_callback可以据此决定是否对该连接的后续数据进行检查。如
            需要检查,tcp_callback回调函数将通知libnids它希望接收哪些
            数据(如到客户端的数据、到服务器端的数据、到客户端的紧急数
            据或到服务器端的紧急数据等),然后返回。
        (b) ns->nids_state==NIDS_DATA时,表示ns连接接收到新的数据。
            half_stream结构中的缓冲区用于存放这些数据。
        (c) nids_state字段为其它数值(NIDS_CLOSE、NIDS_RESET、
            NIDS_TIMEOUT)时,表示该连接已经关闭了。tcp_callback函数应
            释放相关资源。


    四、一个简单的实例

        下面的源代码是一个非常简单的程序,它将libnids捕获的所有TCP连接交换的数据输出显示到标准输出设备上。

    -----------------------BEGINING OF CODE--------------------------------

    #include "nids.h"
    #include <string.h>
    #include <stdio.h>

    extern char * inet_ntoa(unsigned long);

    // tuple4结构包含了TCP连接两端的IP地址和端口,以下函数将它们转换为字符串
    // 格式,如10.0.0.1,1024, 10.0.0.2,23
    char *
    adres (struct tuple4 addr)
    {
      static char buf[256];
      strcpy (buf, inet_ntoa (addr.saddr));
      sprintf (buf + strlen (buf), ",%i,", addr.source);
      strcat (buf, inet_ntoa (addr.daddr));
      sprintf (buf + strlen (buf), ",%i", addr.dest);
      return buf;
    }

    void
    tcp_callback (struct tcp_stream *a_tcp, void ** this_time_not_needed)
    {
      char buf[1024];
      strcpy (buf, adres (a_tcp->addr)); // we put conn params into buf
      if (a_tcp->nids_state == NIDS_JUST_EST)
        {
        // a_tcp所定义的连接已经建立。此处可视程序需要添加额外
        // 的判断处理。如if (a_tcp->addr.dest != 23) return;表
        // 示不处理目标端口为23的数据包。
        // 本例需要处理(显示)所有数据包,故:
          a_tcp->client.collect++; // 需要处理客户端接收的数据
          a_tcp->server.collect++; // 和服务器端接收的数据
          a_tcp->server.collect_urg++; // 需要处理服务器端接收的紧急数据
    #ifdef WE_WANT_URGENT_DATA_RECEIVED_BY_A_CLIENT
          a_tcp->client.collect_urg++; // 需要处理客户端接收的紧急数据
                                       // (打开编译选项才有效)
    #endif
          fprintf (stderr, "%s established\n", buf);
          return;
        }
      if (a_tcp->nids_state == NIDS_CLOSE)
        {
          // TCP连接正常关闭
          fprintf (stderr, "%s closing\n", buf);
          return;
        }
      if (a_tcp->nids_state == NIDS_RESET)
        {
          // TCP连接因RST数据包而关闭
          fprintf (stderr, "%s reset\n", buf);
          return;
        }

      if (a_tcp->nids_state == NIDS_DATA)
        {
          // 接收到新数据,下面判断决定是否显示

          struct half_stream *hlf;

          if (a_tcp->server.count_new_urg)
          {
            // 服务器端接收的紧急数据
            strcat(buf,"(urgent->)");
            buf[strlen(buf)+1]=0;
            buf[strlen(buf)]=a_tcp->server.urgdata;
            write(1,buf,strlen(buf));
            return;
          }

    #ifdef WE_WANT_URGENT_DATA_RECEIVED_BY_A_CLIENT
          if (a_tcp->client.count_new_urg)
          {
            // 客户端接收的紧急数据
            strcat(buf,"(urgent->)");
            buf[strlen(buf)+1]=0;
            buf[strlen(buf)]=a_tcp->server.urgdata;
            write(1,buf,strlen(buf));
            return;
          }
    #endif

          if (a_tcp->client.count_new)
            {
              // 客户端接收的数据
              hlf = &a_tcp->client; // 准备显示客户端接收的数据
              strcat (buf, "(<-)"); // 指示数据流方向
            }
          else
            {
              hlf = &a_tcp->server; // 准备显示服务器端接收的数据
              strcat (buf, "(->)"); // 指示数据流方向
            }
        fprintf(stderr,"%s",buf); // 首先输出显示连接双方的IP地址、端口
                                  // 和数据流方向

       write(2,hlf->data,hlf->count_new); // 输出显示接收到的新数据
         
        }
      return ;
    }

    int
    main ()
    {
      // 此处可自定义libnids的全局变量,如:
      // nids_params.n_hosts=256;
      if (!nids_init () )
      {
            fprintf(stderr,"%s\n",nids_errbuf);
            exit(1);
      }
      nids_register_tcp (tcp_callback);
      nids_run ();
      // NOT REACHED
      return 0;
    }

    ---------------------------END OF CODE------------------------------------ 


    五、libnids的数据结构及接口函数

        libnids库的所有数据结构及接口函数都在"nids.h"头文件中声明。

       struct tuple4 // TCP连接参数
       {
       unsigned short source,dest; // 客户端和服务器端的端口号
       unsigned long saddr,daddr;  // 客户端和服务器端的IP地址
       };


       struct half_stream // TCP连接一端的数据结构
       {
       char state;            // 套接字状态(如TCP_ESTABLISHED)
       char collect;          // 如果大于0,则保存其数据到缓冲区中,否则忽略
       char collect_urg;      // 如果大于0,则保存紧急数据,否则忽略
       char * data;           // 正常数据的缓冲区
       unsigned char urgdata; // 紧急数据缓冲区
       int count;             // 自从连接建立以来保存到"data"缓冲区的数据字节
                              // 数总和
       int offset;            // 保存到"data"缓冲区的首字节数据偏移量
       int count_new;         // 最近一次接收到的数据字节数;如果为0,则无数
                              // 到达
       char count_new_urg;    // 如果非0,表示有新的紧急数据到达

       ... // libnids库使用的辅助字段

       };


       struct tcp_stream
       {
       struct tuple4 addr;   // TCP连接参数(saddr, daddr, sport, dport)
       char nids_state;                  // TCP连接的逻辑状态
       struct half_stream client,server; // 描述客户端与服务器端的数据结构
       ...                               // libnids库使用的辅助字段
       };

        在上面的实例程序中,回调函数tcp_callback输出显示hlf->data缓冲区中的数据到标准输出设备上。这些数据在tcp_callback函数返回后,由libnids自动释放这些数据所占用的内存空间。同时,hlf->offset字段将增加被丢弃数据的字节数,而新接收到的数据则存放到"data"缓冲区的起始处。
        如果在其它应用中不进行如上例的操作(例如,数据处理过程至少需要N个字节的输入数据,而libnids只接收到的数据字节数count_new<N),则需要在tcp_callback函数返回前调用如下函数:

            void nids_discard(struct tcp_stream * a_tcp, int num_bytes)

    此时,当回调函数tcp_callback返回后linids将"data"缓冲区的前num_bytes字节数据,同时计算调整offset字段的数值,并将剩余数据移动到缓冲区的起始处。
        如果始终不调用nids_discard()函数(如上面实例),hlf->data缓冲区中将包含hlf->count_new字节数据。通常情况下,在hlf->data缓冲区中的数据字节数等于hlf->count - hlf->offset。
        有了nids_discard()函数,程序员就不必拷贝接收到的数据到另外的缓冲区中,hlf->data缓冲区将总是尽可能保存足够的数据。然后,有时会有保留数据包特定数据的需要。例如,我们希望能监测到针对wu-ftpd服务器的"CWD"溢出攻击,就需要跟踪检查ftp客户端发送的"CWD"命令。此时就需要tcp_callback回调函数具有第二个参数了。此参数是某TCP连接私有数据的指针。处理过程如下:
       
       void
       tcp_callback_2 (struct tcp_stream * a_tcp, struct conn_param **ptr)
       {
       if (a_tcp->nids_state==NIDS_JUST_EST)
       {
            struct conn_param * a_conn;
            if the connection is uninteresting, return;
            a_conn=malloc of some data structure
            init of a_conn
            *ptr=a_conn // this value will be passed to tcp_callback_2 in future
                        // calls
            increase some of "collect" fields
            return;
       }
       if (a_tcp->nids_state==NIDS_DATA)
       {
            struct conn_param *current_conn_param=*ptr;
            using current_conn_param and the newly received data from the net
            we search for attack signatures, possibly modyfying
            current_conn_param 
            return ;

       }

       ...

       }

        nids_register_tcp和nids_register_ip*函数可被任意次调用。在同一个TCP连接中使用两种不同的回调函数是允许的。
        libnids库定义了一个全局变量结构nids_params,其声明如下:
       
       struct nids_prm
       {
       int n_tcp_streams; // 存放tcp_stream结构的hash表大小。
                          // 缺省值:1024
       int n_hosts;       // 存放IP分片信息的hash表大小
                          // 缺省值:256
       char * device;     // libnids监听的接口设备名
                          // 缺省值 == NULL,即由pcap_lookupdev函数确定
       int sk_buff_size;  // (Linux内核)sk_buff结构大小
                          // 缺省值:168
       int dev_addon;     // sk_buff为网络接口保留的字节数
                          // 如果dev_addon==-1,则由nids_init函数确定
                          // 缺省值:-1
       void (*syslog)();  // 日志函数指针
       int syslog_level;  // 如果nids_params.syslog==nids_syslog,则此字段值
                          // 将确定日志等级loglevel
                          // 缺省值:LOG_ALERT
       int scan_num_hosts;// 存放端口扫描信息的hash表大小。
                          // 如果为0,则关闭端口扫描监测功能。
                          // 缺省值:256
       int scan_num_ports;// 来自同一IP地址所扫描的TCP端口数上限
                          // 缺省值:10
       int scan_delay;    // 在两次端口扫描中的间隔时间上限(毫秒)
                          // 缺省值:3000
       void (*no_mem)();  // 内存不足时被调用,此时应终止当前进程
       int (*ip_filter)(struct ip*);  // 当接收到一个IP数据包时调用。如返回值
                                      // 非零,则处理该数据包,否则忽略。
                                      // 缺省为(nids_ip_filter)且总返回1
       char *pcap_filter; // 传递给pcap过滤器的字符串。
                          // 缺省值:NULL
       } nids_params;

        nids_params的syslog字段缺省时指向nids_syslog函数,声明如下:

            void nids_syslog (int type, int errnum, struct ip *iph, void *data);

        nids_params.syslog函数用于记录异常情况,如端口扫描企图,无效TCP头标志等。该字段应指向自定义的日志处理函数。nids_syslog()仅作为一个例子。nids_syslog()函数向系统守护服务syslogd发送日志消息。

        使用nids_run有一个缺陷:应用程序将完全由数据包驱动(运行)。有时需要在没有数据包到达时也能处理一些任务,则作为nids_run()函数的替代,程序员可使用如下函数:

            int nids_next()

    此函数将调用pcap_next()函数(而不是pcap_loop()函数)。(详细资料请参阅《网络安全工具开发函数库介绍之二 ——libpcap》。) nids_next()函数成功时返回1,出错时返回0,且nids_errbuf缓冲区存放相应错误消息。
        典型地,当使用nids_next()函数时,应用程序调用I/O复用函数select()阻塞,监听套接字fd在“读”描述字集合fd_set中设置。该套接字可通过如下函数获得:

            int nids_getfd()

    成功时返回一个文件描述字,出错时返回-1,且nids_errbuf缓冲区存放相应错误消息。

     


    ---[[ libnids应用实例 ]]----------------------------------

    1、nids_next()函数的应用

    ============================ cut here ============================

    /*
    This is an example how one can use nids_getfd() and nids_next() functions.
    You can replace printall.c's function main with this file.
    */

    #include <sys/time.h>
    #include <sys/types.h>
    #include <unistd.h>

    int
    main ()
    {
      // here we can alter libnids params, for instance:
      // nids_params.n_hosts=256;
      int fd;
      int time = 0;
      fd_set rset;
      struct timeval tv;

      if (!nids_init ())
      {
            fprintf(stderr,"%s\n",nids_errbuf);
            exit(1);
      }
      nids_register_tcp (tcp_callback);
      fd = nids_getfd ();
      for (;;)
        {
          tv.tv_sec = 1;
          tv.tv_usec = 0;
          FD_ZERO (&rset);
          FD_SET (fd, &rset);
          // add any other fd we need to take care of
          if (select (fd + 1, &rset, 0, 0, &tv))
            {
                    if (FD_ISSET(fd,&rset)  // need to test it if there are other
                                            // fd in rset
                            if (!nids_next ()) break;
            }
          else
            fprintf (stderr, "%i ", time++);
        }
      return 0;
    }

    ============================ cut here ============================

    2、Simple sniffer

    ============================ cut here ============================

    /*
       Copyright (c) 1999 Rafal Wojtczuk <nergal@avet.com.pl>. All rights reserved.
       See the file COPYING for license details.
    */

    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netinet/in_systm.h>
    #include <arpa/inet.h>
    #include <stdio.h>
    #include <fcntl.h>
    #include "nids.h"

    #define LOG_MAX 100
    #define SZLACZEK "\n--------------------------------------------------\n"

    #define int_ntoa(x)     inet_ntoa(*((struct in_addr *)&x))

    char *
    adres (struct tuple4 addr)
    {
      static char buf[256];
      strcpy (buf, int_ntoa (addr.saddr));
      sprintf (buf + strlen (buf), ",%i,", addr.source);
      strcat (buf, int_ntoa (addr.daddr));
      sprintf (buf + strlen (buf), ",%i : ", addr.dest);
      return buf;
    }

    int logfd;
    void
    do_log (char *adres_txt, char *data, int ile)
    {
      write (logfd, adres_txt, strlen (adres_txt));
      write (logfd, data, ile);
      write (logfd, SZLACZEK, strlen (SZLACZEK));
    }

    void
    sniff_callback (struct tcp_stream *a_tcp, void **this_time_not_needed)
    {
      int dest;
      if (a_tcp->nids_state == NIDS_JUST_EST)
        {
          dest = a_tcp->addr.dest;
          if (dest == 21 || dest == 23 || dest == 110 || dest == 143 || dest == 513)
            a_tcp->server.collect++;
          return;
        }
      if (a_tcp->nids_state != NIDS_DATA)
        {
          // seems the stream is closing, log as much as possible
          do_log (adres (a_tcp->addr), a_tcp->server.data,
                  a_tcp->server.count - a_tcp->server.offset);
          return;
        }
      if (a_tcp->server.count - a_tcp->server.offset < LOG_MAX)
        {
          // we haven't got enough data yet; keep all of it
          nids_discard (a_tcp, 0);
          return;
        }
       
      // enough data 
      do_log (adres (a_tcp->addr), a_tcp->server.data, LOG_MAX);

      // Now procedure sniff_callback doesn't want to see this stream anymore.
      // So, we decrease all the "collect" fields we have previously increased.
      // If there were other callbacks following a_tcp stream, they would still
      // receive data
      a_tcp->server.collect--;
    }


    int
    main ()
    {
      logfd = open ("./logfile", O_WRONLY | O_CREAT | O_TRUNC, 0600);
      if (logfd < 0)
        {
          perror ("opening ./logfile:");
          exit (1);
        }
      if (!nids_init ())
        {
          fprintf (stderr, "%s\n", nids_errbuf);
          exit (1);
        }
      nids_register_tcp (sniff_callback);
      nids_run ();
      return 0;
    }

    ============================ cut here ============================

    3、Wu-FTPd overflow attack detector

    ============================ cut here ============================

    /*
    Copyright (c) 1999 Rafal Wojtczuk <nergal@avet.com.pl>. All rights reserved.
    See the file COPYING for license details.
    */

    /*
    This code attempts to detect attack against imapd (AUTHENTICATE hole) and
    wuftpd (creation of deep directory). This code is to ilustrate use of libnids;
    in order to improve readability, some simplifications were made, which enables
    an attacker to bypass this code (note, the below routines should be improved,
    not libnids)
    */ 

    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netinet/in_systm.h>
    #include <arpa/inet.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <syslog.h>
    #include "nids.h"

    #define int_ntoa(x)     inet_ntoa(*((struct in_addr *)&x))

    char *
    adres (struct tuple4 addr)
    {
      static char buf[256];
      strcpy (buf, int_ntoa (addr.saddr));
      sprintf (buf + strlen (buf), ",%i,", addr.source);
      strcat (buf, int_ntoa (addr.daddr));
      sprintf (buf + strlen (buf), ",%i", addr.dest);
      return buf;
    }


    /*
    if we find a pattern AUTHENTICATE {an_int} in data stream sent to an imap
    server, where an_int >1024, it means an buffer overflow attempt. We kill the
    connection.
    */

    #define PATTERN "AUTHENTICATE {"
    #define PATLEN strlen(PATTERN)
    void
    detect_imap (struct tcp_stream *a_tcp)
    {
      char numbuf[30];
      int i, j, datalen, numberlen;
      struct half_stream *hlf;
      if (a_tcp->nids_state == NIDS_JUST_EST)
        {
          if (a_tcp->addr.dest == 143)
            {
              a_tcp->server.collect++;
              return;
            }
          else
            return;
        }
      if (a_tcp->nids_state != NIDS_DATA)
        return;
      hlf = &a_tcp->server;
      datalen = hlf->count - hlf->offset;
      if (datalen < PATLEN)
        {
          // we have too small amount of data to work on. Keep all data in buffer.
          nids_discard (a_tcp, 0);
          return;
        }
      for (i = 0; i <= datalen - PATLEN; i++)
        if (!memcmp (PATTERN, hlf->data + i, PATLEN)) //searching for a pattern
          break;
      if (i > datalen - PATLEN)
        {
          // retain PATLEN bytes in buffer
          nids_discard (a_tcp, datalen - PATLEN);
          return;
        }
      for (j = i + PATLEN; j < datalen; j++) // searching for a closing '}'
        if (*(hlf->data + j) == '}')
          break;
      if (j > datalen)
        {
          if (datalen > 20)
            {
              //number too long, perhaps we should log it, too
            }
          return;
        }
      numberlen = j - i - PATLEN;
      memcpy (numbuf, hlf->data + i + PATLEN, numberlen); //numbuf contains
                                                          // AUTH argument
      numbuf[numberlen] = 0;
      if (atoi (numbuf) > 1024)
        {
          // notify admin
          syslog(nids_params.syslog_level,
          "Imapd exploit attempt, connection %s\n",adres(a_tcp->addr));
          // kill the connection
          nids_killtcp (a_tcp);
        }
      nids_discard (a_tcp, datalen - PATLEN);
      return;
    }

    // auxiliary structure, needed to keep current dir of ftpd daemon
    struct supp
    {
      char *currdir;
      int last_newline;
    };

    // the below function adds "elem" string to "path" string, taking care of
    // ".." and multiple '/'. If the resulting path is longer than 768,
    // return value is 1, otherwise 0
    int
    add_to_path (char *path, char *elem, int len)
    {
    int plen;
    char * ptr;
      if (len > 768)
        return 1;
      if (len == 2 && elem[0] == '.' && elem[1] == '.')
        {
          ptr = rindex (path, '/');
          if (ptr != path)
            *ptr = 0;
        }
      else if (len > 0)
        {
          plen = strlen (path);
          if (plen + len + 1 > 768)
            return 1;
            if (plen==1)
            {
            strncpy(path+1,elem,len);
            path[1+len]=0;
            }
            else
            {
          path[plen] = '/';
          strncpy (path + plen + 1, elem, len);
          path[plen + 1 + len] = 0;
            }
        }
    return 0;
    }

    void
    do_detect_ftp (struct tcp_stream *a_tcp, struct supp **param_ptr)
    {
      struct supp *p = *param_ptr;
      int index = p->last_newline + 1;
      char *buf = a_tcp->server.data;
      int offset = a_tcp->server.offset;
      int n_bytes = a_tcp->server.count - offset;
      int path_index, pi2, index2, remcaret;
      for (;;)
        {
          index2 = index;
          while (index2 - offset < n_bytes && buf[index2 - offset] != '\n')
            index2++;
          if (index2 - offset >= n_bytes)
            break;
          if (!strncasecmp (buf + index - offset, "cwd ", 4))
            {
              path_index = index + 4;
              if (buf[path_index - offset] == '/')
                {
                  strcpy (p->currdir, "/");
                  path_index++;
                }
              for (;;)
                {
                  pi2 = path_index;
                  while (buf[pi2 - offset] != '\n' && buf[pi2 - offset] != '/')
                    pi2++;
                    if (buf[pi2-offset]=='\n' && buf[pi2-offset-1]=='\r')
                    remcaret=1;
                    else remcaret=0;
                  if (add_to_path (p->currdir, buf + path_index-offset, pi2 - path_index-remcaret))
                    {
                      // notify admin
                      syslog(nids_params.syslog_level,
                      "Ftpd exploit attempt, connection %s\n",adres(a_tcp->addr));
                      nids_killtcp (a_tcp);
                      return;
                    }
                  if (buf[pi2 - offset] == '\n')
                    break;
                  path_index = pi2 + 1;
                }
            }
          index = index2 + 1;
        }
      p->last_newline = index - 1;
      nids_discard (a_tcp, index - offset);
    }

    void
    detect_ftpd (struct tcp_stream *a_tcp, struct supp **param)
    {
      if (a_tcp->nids_state == NIDS_JUST_EST)
        {
          if (a_tcp->addr.dest == 21)
            {
              struct supp *one_for_conn;
              a_tcp->server.collect++;
              one_for_conn = (struct supp *) malloc (sizeof (struct supp));
              one_for_conn->currdir = malloc (1024);
              strcpy (one_for_conn->currdir, "/");
              one_for_conn->last_newline = 0;
              *param=one_for_conn;
            }
          return;
        }
      if (a_tcp->nids_state != NIDS_DATA)
        {
          free ((*param)->currdir);
          free (*param);
          return;
        }
      do_detect_ftp (a_tcp, param);
    }

    int
    main ()
    {
      if (!nids_init ())
      {
            fprintf(stderr,"%s\n",nids_errbuf);
            exit(1);
      }
      nids_register_tcp (detect_imap);
      nids_register_tcp (detect_ftpd);
      nids_run ();
      return 0;
    }

    ============================ cut here ============================

     

    <<< 待续 >>>

     

     

     

    libpcap使用举例

    作者:小四 < mailto: scz@nsfocus.com >
    主页:http://www.nsfocus.com
    日期:2001-01-10
    URL :http://www.nsfocus.net/index.php?act=magazine&do=view&mid=760


    我们曾经提供过<<libnet使用举例(1-12)>>,比较详细地介绍了报文发送编程。始终
    没有介绍libpcap报文捕捉编程的原因很多,tcpdump、snort等著名软件包都是基于
    libpcap,加上W.Richard.Stevens的<<Unix Network Programming Vol I>>第26章推
    波助澜,实在觉得没有必要继续介绍libpcap编程。更真实的原因可能是BPF、DLPI、
    SOCK_PACKET三种接口编程已经被演练得太多太滥。

    今天讨论的不是效率,而是可能的移植性要求。没办法,第一次使用libpcap库,举
    例能深入到什么地步,不知道。如果你也是第一次用这个库,跟我来,第N次使用?
    那还是忙你的去吧,别来看这篇无聊的灌水,:-P。我无聊是因为有程序要广泛可移
    植,你无聊是为什么。

    char * pcap_lookupdev ( char * errbuf );

    该函数返回一个网络设备接口名,类似libnet_select_device(),对于Linux就是
    "eth0"一类的名字。pcap_open_live()、pcap_lookupnet()等函数将用到这个网络设
    备接口名。失败时返回NULL,errbuf包含了失败原因。errbuf一般定义如下:

    /usr/include/pcap.h

    #define PCAP_ERRBUF_SIZE 256

    char errbuf[ PCAP_ERRBUF_SIZE ];

    pcap_t * pcap_open_live ( char * device, int snaplen, int promisc,
                              int to_ms, char * errbuf );

    该函数用于获取一个抽象的包捕捉句柄,后续很多libpcap函数将使用该句柄,类似
    文件操作函数频繁使用文件句柄。device指定网络接口设备名,比如"eth0。snaplen
    指定单包最大捕捉字节数,为了保证包捕捉不至于太低效率,snaplen尽量适中,以
    恰能获得所需协议层数据为准。promisc指定网络接口是否进入混杂模式,注意即使
    该参数为false(0),网络接口仍然有可能因为其他原因处在混杂模式。to_ms指定毫
    秒级读超时,man手册上并没有指明什么值意味着永不超时,测试下来的结论,0可能
    代表永不超时。如果调用失败返回NULL,errbuf包含失败原因。

    --------------------------------------------------------------------------
    /usr/include/pcap.h

    typedef struct pcap pcap_t;

    pcap-int.h里定义了struct pcap {}

    struct pcap
    {
        int                fd;
        int                snapshot;
        int                linktype;
        int                tzoff;    /* timezone offset                                   */
        int                offset;   /* offset for proper alignment                       */
        struct pcap_sf     sf;
        struct pcap_md     md;
        int                bufsize;  /* Read buffer                                       */
        u_char *           buffer;
        u_char *           bp;
        int                cc;
        u_char *           pkt;      /* Place holder for pcap_next()                      */
        struct bpf_program fcode;    /* Placeholder for filter code if bpf not in kernel. */
        char               errbuf[PCAP_ERRBUF_SIZE];
    };
    --------------------------------------------------------------------------

    int pcap_lookupnet ( char * device, bpf_u_int32 * netp,
                         bpf_u_int32 * maskp, char * errbuf );

    该函数用于获取指定网络接口的IP地址、子网掩码。不要被netp的名字所迷惑,它对
    应的就是IP地址,maskp对应子网掩码。

    /usr/include/pcap.h

    typedef u_int bpf_u_int32;

    显然简单理解成32-bit即可。如果调用失败则返回-1,errbuf包含失败原因。

    int pcap_compile ( pcap_t * p, struct bpf_program * fp, char * str,
                       int optimize, bpf_u_int32 netmask );

    该函数用于解析过滤规则串,填写bpf_program结构。str指向过滤规则串,格式参看
    tcpdump的man手册,比如:

    tcpdump -x -vv -n -t ip proto \\tcp and dst 192.168.8.90 and tcp[13] \& 2 = 2

    这条过滤规则将捕捉所有携带SYN标志的到192.168.8.90的TCP报文。过滤规则串可以
    是空串(""),表示抓取所有过路的报文。

    optimize为1表示对过滤规则进行优化处理。netmask指定子网掩码,一般从
    pcap_lookupnet()调用中获取。返回值小于零表示调用失败。

    这个函数可能比较难于理解,涉及的概念源自BPF,Linux系统没有这种概念,但是
    libpcap采用pcap_compile()和pcap_setfilter()结合的办法屏蔽了各种链路层支持
    的不同,无论是SOCK_PACKET、DLPI。曾在华中Security版上写过一篇
    <<内核包捕获过滤机制介绍>>,参看该文加强理解。

    --------------------------------------------------------------------------
    # tcpdump -d ip proto \\tcp and dst 192.168.8.90 and tcp[13] \& 2 = 2
    (000) ldh      [-4096]
    (001) jeq      #0x800           jt 2    jf 13
    (002) ldb      [9]
    (003) jeq      #0x6             jt 4    jf 13
    (004) ld       [16]
    (005) jeq      #0xc0a8085a      jt 6    jf 13
    (006) ldh      [6]
    (007) jset     #0x1fff          jt 13   jf 8
    (008) ldxb     4*([0]&0xf)
    (009) ldb      [x + 13]
    (010) and      #0x2
    (011) jeq      #0x2             jt 12   jf 13
    (012) ret      #65535
    (013) ret      #0
    #

    /usr/include/net/bpf.h

    /* Structure for BIOCSETF. */
    struct bpf_program
    {
        u_int             bf_len;
        struct bpf_insn * bf_insns;
    };

    /*
    * The instruction data structure.
    */
    struct bpf_insn
    {
        u_short   code;
        u_char    jt;
        u_char    jf;
        bpf_int32 k;
    };

    /*
    * Macros for insn array initializers.
    */
    #define BPF_STMT(code, k) { (u_short)(code), 0, 0, k }
    #define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k }
    --------------------------------------------------------------------------

    int pcap_setfilter ( pcap_t * p, struct bpf_program * fp );

    该函数用于设置pcap_compile()解析完毕的过滤规则,如果你足够聪明(愚公?),完
    全可以自己提供过滤规则,无须pcap_compile()介入,就象你写
    Password Sniffer For I386/FreeBSD时常做的那样。成功返回0,失败返