zoukankan      html  css  js  c++  java
  • snort_inline中与防火墙联动的实现以及代码inline.c分析

         近来想测试一个防ddos的算法的性能怎么样,但是这总要用代码实现啊,一开始是想在netfiler中实现,即在某个钩子函数下注册一个模块,但是还没怎么开始就停止了,原因就是内核编程可以使你想跳楼!其次想在iptables下实现,因为想到既然iptables能建立一些规则来阻止攻击包,那么至少iptables中应该可以见到内核的包,另外就是有权限控制包的去留,但是要改iptables的代码也不是很好扩展。
         今天在snort的官方主页上见到有是snort-inline,以前用过snort,也见别人用过无线下的snort(wireless snort),但是这个snort绝对不同,因为可以用它和iptables实现IPS!!!而且它可以设置成nf_queue模式,即它分析的包都是防火墙内核中返回到用户态的,只要加这样的命令iptables -A INPUT -p icmp -j QUEUE 即可,其实这归根于Netfiler的NF_queue功能(暂时这么说吧,只是内核于用户态通信的一个机制),当然少不了iptables中libipq库的支持,libipq提供一些函数直接和netfilter通信。
        首先我们要下载snort-inline,它要libnet的支持以及libipq的支持,版本问题也要注意,网上有安装这个的一些解答但相对较少。
        其次我们要知道snort-inline是怎么实现于防火墙的通信的。看inline.h和inline.c
    inline.h:

    void InitInlinePostConfig(void);

    #ifndef IPFW
    void IpqLoop();
    #else
    void IpfwLoop();
    #endif /* IPFW */

    int InlineDrop(); /* call to drop current packet */
    int InlineReject(Packet *); /* call to reject current packet */
    int InlineAccept();
    int InlineReplace();
    int InlineMode();

    #else
    #define InlineMode(a)    (0)
    #endif /* GIDS */


    #endif /* __INLINE_H__ */

    其实由inlilne.h可以看出来以后要DROP只需在你的头文件中包括inline.h然后调用相关的InlineDrop(); 即可。

    inline.c部分代码

    // $Id: inline.c,v 1.3 2003/02/15 21:46:14 redmaze Exp $

    #ifdef GIDS
    #include "inline.h"
    #include "rules.h"
    #include <pcap.h>
    #include <string.h>
    #include <stdlib.h>
    #include <libnet.h>

    #define PKT_BUFSIZE 65536

    /* Most of the code related to libnet (resets and icmp unreach) was
     * taken from sp_respond.c */


    /* vars */
    int libnet_nd; /* libnet descriptor */
    char errbuf[LIBNET_ERRBUF_SIZE];

    Packet *tmpP;

    char *l_tcp, *l_icmp;

    /* predeclarations */
    #ifndef IPFW
    void HandlePacket(ipq_packet_msg_t *);
    void TranslateToPcap(ipq_packet_msg_t *, struct pcap_pkthdr *);
    #else
    void HandlePacket();
    void TranslateToPcap(struct pcap_pkthdr *phdr, ssize_t len);
    #endif /* IPFW */
    void ResetIV(void);


    /**
     * InlineMode - determine if we are in inline mode
     *
     * @returns 1 if we are in inline mode, 0 otherwise
     */

    int InlineMode()
    {
        if (pv.inline_flag)    /*设置了inline模试flag就等于1*/
            return 1;

        return 0;
    }


    #ifndef IPFW
    void TranslateToPcap(ipq_packet_msg_t *m, struct pcap_pkthdr *phdr)
    {
        static struct timeval t;
        if (!m->timestamp_sec)
        {
            memset (&t, 0, sizeof(struct timeval));
            gettimeofday(&t, NULL);
            phdr->ts.tv_sec = t.tv_sec;
            phdr->ts.tv_usec = t.tv_usec;
        }
        else
        {
            phdr->ts.tv_sec = m->timestamp_sec;
            phdr->ts.tv_usec = m->timestamp_usec;
        }
        phdr->caplen = m->data_len;
        phdr->len = m->data_len;
        /* copy the mark to the iv struct, so we can reach it inside stream4 */
        iv.mark = m->mark;

    }
    #else
    #endif


    void ResetIV()
    {
        iv.drop = 0;
        iv.reject = 0;
        iv.replace = 0;
        iv.mark = 0;
    }


    /*
     * Function: void InitInlinePostConfig
     *
     * Purpose: perform initialization tasks that depend on the configfile
     *
     * Args: none
     *
     * Returns: nothing void function
     */

    void InitInlinePostConfig(void)
    {
        int tcp_size = 0;
        int icmp_size = 0;

        //printf("InitInline stage 2: InitInlinePostConfig starting...\n");


        /* Let's initialize Libnet, but not if we are in
         * layer 2 resets mode, because we use the link
         * layer then... */

    #ifndef IPFW
        if(pv.layer2_resets)
        {
            tcp_size = ETH_H + IP_H + TCP_H;
            icmp_size = 128 + ETH_H;
        }
        else
    #endif
        {
            //printf("opening raw socket in IP-mode\n");

     
        if((libnet_nd = libnet_open_raw_sock(IPPROTO_RAW)) < 0)
        {
         fprintf(stdout, "InitInline: Could not open raw socket for libnet\n");
         exit(-1);
        }

            tcp_size = IP_H + TCP_H;
            icmp_size = 128;
        }

        /* init */
        l_tcp = calloc(tcp_size, sizeof(char));
        if (l_tcp == NULL)
        {
            perror("InitInline: Could not allocate l_tcp\n");
            exit(-1);
        }
        l_icmp = calloc(icmp_size, sizeof(char));
        if (l_icmp == NULL)
        {
            perror("InitInline: Could not allocate l_icmp\n");
            exit(-1);
        }


    #ifndef IPFW
        if(pv.layer2_resets)
        {
            /* Building Layer 2 Reset Packets */
            printf("building cached link layer reset packets\n");
       
            libnet_build_ip(TCP_H, 0, libnet_get_prand(PRu16), 0, 255,
                            IPPROTO_TCP, 0, 0, NULL, 0, l_tcp + ETH_H);

            libnet_build_tcp(0, 0, 0, 0, TH_RST|TH_ACK, 0, 0, NULL, 0,
                             l_tcp + ETH_H + IP_H);

            /* create icmp cached packet */
            libnet_build_ip(ICMP_UNREACH_H, 0, libnet_get_prand(PRu16), 0,
                            255, IPPROTO_ICMP, 0, 0, NULL, 0, l_icmp + ETH_H);
            libnet_build_icmp_unreach(3, 3, 0, 0, 0, 0, 0, 0, 0, 0, NULL, 0,
                                      l_icmp + ETH_H + IP_H);
        }
        else
    #endif
        {
            /* Building Socket Reset Packets */
            printf("building cached socket reset packets\n");
      
            libnet_build_ip(TCP_H, 0, libnet_get_prand(PRu16), 0, 255,
                            IPPROTO_TCP, 0, 0, NULL, 0, l_tcp);

            libnet_build_tcp(0, 0, 0, 0, TH_RST|TH_ACK, 0, 0, NULL, 0,
                             l_tcp + IP_H);

            /* create icmp cached packet */
            libnet_build_ip(ICMP_UNREACH_H, 0, libnet_get_prand(PRu16), 0,
                            255, IPPROTO_ICMP, 0, 0, NULL, 0, l_icmp);
            libnet_build_icmp_unreach(3, 3, 0, 0, 0, 0, 0, 0, 0, 0, NULL, 0,
                                      l_icmp + IP_H);
        }

    }


    /* InitInline is called before the Snort_inline configuration file is read. */
    int InitInline()//初始化
    {
        int status;

    #ifdef DEBUG_GIDS
        printf("Initializing Inline mode \n");
    #endif

        printf("Initializing Inline mode \n");

    #ifndef IPFW
        ipqh = ipq_create_handle(0, PF_INET);
        if (!ipqh)
        {
            ipq_perror("InlineInit: ");
            ipq_destroy_handle(ipqh);
            exit(1);
        }
     
        status = ipq_set_mode(ipqh, IPQ_COPY_PACKET, PKT_BUFSIZE);
        if (status < 0)
        {
            ipq_perror("InitInline: ");
            ipq_destroy_handle(ipqh);
            exit(1);
        }
    #endif /* IPFW */

        ResetIV();//重设iv结构

        /* Just in case someone wants to write to a pcap file
         * using DLT_RAW because iptables does not give us datalink layer.
         */

        pd = pcap_open_dead(DLT_RAW, SNAPLEN);

        return 0;
    }

    #ifndef IPFW
    void IpqLoop()  //对捕获的包进行的操作
    {
        int status;
        struct pcap_pkthdr PHdr;
        unsigned char buf[PKT_BUFSIZE];
        static ipq_packet_msg_t *m;

    #ifdef DEBUG_GIDS
        printf("Reading Packets from ipq handle \n");
    #endif

        while(1)
        {
            ResetIV();
            status = ipq_read(ipqh, buf, PKT_BUFSIZE, 0);
            if (status < 0)
            {
                ipq_perror("IpqLoop: ");
            }
            else
            {
                switch(ipq_message_type(buf))
                {
                    case NLMSG_ERROR:
                        fprintf(stderr, "Received error message %d\n",
                                ipq_get_msgerr(buf));
                        break;

                    case IPQM_PACKET:
                        m = ipq_get_packet(buf);
    #ifdef DEBUG_INLINE
                        printf("%02X:%02X:%02X:%02X:%02X:%02X\n", m->hw_addr[0], m->hw_addr[1],
                               m->hw_addr[2], m->hw_addr[3], m->hw_addr[4], m->hw_addr[5]);
    #endif

                        TranslateToPcap(m, &PHdr);
                        ProcessPacket(NULL, &PHdr, (u_char *)m->payload);
                        HandlePacket(m);//以上两个函数是对包处理,处理结果有这函数决定
                        break;
                } /* switch */
            } /* if - else */
        } /* while() */
    }
    #else


    /* Loop reading packets from IPFW
       - borrowed mostly from the TCP-MSSD daemon in FreeBSD ports tree
        Questions, comments send to: nick@rogness.net
    */

    #endif


    /*
     * Function: static void RejectSocket
     *
     * Purpose: send a reject packet (tcp-reset or icmp-unreachable
     *
     * Args: none
     *
     * Returns: nothing void function
     */



    /*
     * Function: static void RejectLayer2(ipq_packet_msg_t *m)
     *
     * Purpose: send a reject packet (tcp-reset or icmp-unreachable
     *
     * Args: the ipq_packet_msg_t m for determining the output interface
     * and the source mac for our packet.
     *
     * Returns: nothing void function
     *
     * TODO: make it also work on *BSD.
     */

    #ifndef IPFW
    #ifndef IPFW
    void HandlePacket(ipq_packet_msg_t *m)
    #else
    void HandlePacket()
    #endif
    {
        int status;

        if (iv.drop)
        {
    #ifndef IPFW
            status = ipq_set_verdict(ipqh, m->packet_id, NF_DROP, 0, NULL);
            if (status < 0)
            {
                ipq_perror("NF_DROP: ");
            }
    #endif
            if (iv.reject)
            {
    #ifndef IPFW
         if(pv.layer2_resets)
         {
            RejectLayer2(m);
         }
         else
    #endif
         {
            RejectSocket();
         }
            }
        }
    #ifndef IPFW
        else if (!iv.replace)
        {
            status = ipq_set_verdict(ipqh, m->packet_id, NF_ACCEPT, 0, NULL);
            if (status < 0)
            {
                ipq_perror("NF_ACCEPT: ");
            }
        }
        else
        {
            status = ipq_set_verdict(ipqh, m->packet_id, NF_ACCEPT,
                     m->data_len, m->payload);
            if (status < 0)
            {
                ipq_perror("NF_ACCEPT: ");
            }
        }
    #endif
    }
      

    int InlineDrop()
    {
        //printf("InlineDrop(): dropping\n");

        iv.drop = 1;
        return 0;
    }

    int InlineReject(Packet *p)
    {
        //printf("InlineReject(): rejecting\n");

        iv.reject = 1;
        iv.drop = 1;
        tmpP = p;
        return 0;
    }

    int InlineAccept()
    {
        iv.drop = 0;
        return 0;
    }

    int InlineReplace()
    {
        iv.replace = 1;
        return 0;
    }

    #endif /* GIDS */

    只要稍微分析一下,联系上下文就可看出有了这个inline的实现,在snort中可以任由我们的发挥了,你可以在你的预处理器中#include"inline.h",然后判断后调用相关的DROP即可以实现在防火墙的功能。
  • 相关阅读:
    会计基础-资本与资本公积核算
    FORM 基本控件2
    EBS form的一些知识
    EBS功能安全性基本原理
    主物料界面数据来源
    organization --form 表单中organization 数据来源
    form 相关
    jar/war/ear文件的区别
    ORACLE判别字段是否包含中文
    亲测可用:SecureCRT 7 注册码/序列号
  • 原文地址:https://www.cnblogs.com/Safe3/p/1401204.html
Copyright © 2011-2022 走看看