VC++实现防火墙过滤


所谓防火墙指的是一个由软件和硬件设备组合而成、在内部网和外部网之间、专用网与公共网之间的界面上构造的保护屏障.是一种获取安全性方法的形象说法,它是一种计算机硬件和软件的结合,使Internet与Intranet之间建立起一个安全网关(Security Gateway),从而保护内部网免受非法用户的侵入,防火墙主要由服务访问规则、验证工具、包过滤和应用网关4个部分组成,防火墙就是一个位于计算机和它所连接的网络之间的软件或硬件。该计算机流入流出的所有网络通信和数据包均要经过此防火墙。
  在网络中,所谓“防火墙”,是指一种将内部网和公众访问网(如Internet)分开的方法,它实际上是一种隔离技术。防火墙是在两个网络通讯时执行的一种访问控制尺度,它能允许你“同意”的人和数据进入你的网络,同时将你“不同意”的人和数据拒之门外,最大限度地阻止网络中的黑客来访问你的网络。换句话说,如果不通过防火墙,公司内部的人就无法访问Internet,Internet上的人也无法和公司内部的人进行通信。
 网络层防火墙
  网络层防火墙可视为一种 IP 封包过滤器,运作在底层的 TCP/IP 协议堆栈上。我们可以以枚举的方式,只允许符合特定规则的封包通过,其余的一概禁止穿越防火墙(病毒除外,防火墙不能防止病毒侵入)。这些规则通常可以经由管理员定义或修改,不过某些防火墙设备可能只能套用内置的规则。
  我们也能以另一种较宽松的角度来制定防火墙规则,只要封包不符合任何一项“否定规则”就予以放行。现在的操作系统及网络设备大多已内置防火墙功能。
  较新的防火墙能利用封包的多样属性来进行过滤,例如:来源 IP 地址、来源端口号、目的 IP 地址或端口号、服务类型(如 WWW 或是 FTP)。也能经由通信协议、TTL 值、来源的网域名称或网段...等属性来进行过滤。
  应用层防火墙
  应用层防火墙是在 TCP/IP 堆栈的“应用层”上运作,您使用浏览器时所产生的数据流或是使用 FTP 时的数据流都是属于这一层。应用层防火墙可以拦截进出某应用程序的所有封包,并且封锁其他的封包(通常是直接将封包丢弃)。理论上,这一类的防火墙可以完全阻绝外部的数据流进到受保护的机器里。
  防火墙借由监测所有的封包并找出不符规则的内容,可以防范电脑蠕虫或是木马程序的快速蔓延。不过就实现而言,这个方法既烦且杂(软件有千千百百种啊),所以大部分的防火墙都不会考虑以这种方法设计。
  XML 防火墙是一种新型态的应用层防火墙。
  根据侧重不同,可分为:包过滤型防火墙、应用层网关型防火墙、服务器型防火墙。
我们来简单实现一个数据包防火墙,请见代码!




#include "pcap.h"   
/*  
-----------------------------------------------------------------------------------------------------------------------  
下面是以太网协议格式  
-----------------------------------------------------------------------------------------------------------------------  
 */   
struct ether_header   
{   
    u_int8_t ether_dhost[6];   
    /* 目的以太网地址 */   
    u_int8_t ether_shost[6];   
    /* 源以太网地址 */   
    u_int16_t ether_type;   
    /* 以太网类型 */   
};   
/* 下面是IP地址格式 */   
typedef u_int32_t in_addr_t;   
struct in_addr   
{   
    in_addr_t s_addr; /* 存放IP地址 */   
};   
/*  
-----------------------------------------------------------------------------------------------------------------------  
下面是ARP协议格式  
-----------------------------------------------------------------------------------------------------------------------  
 */   
struct arp_header   
{   
    u_int16_t arp_hardware_type;   
    /* 硬件地址类型 */   
    u_int16_t arp_protocol_type;   
    /* 协议地址类型 */   
    u_int8_t arp_hardware_length;   
    /* 硬件地址长度 */   
    u_int8_t arp_protocol_length;   
    /* 协议地址长度 */   
    u_int16_t arp_operation_code;   
    /* 操作类型 */   
    u_int8_t arp_source_ethernet_address[6];   
    /* 源以太网地址 */   
    u_int8_t arp_source_ip_address[4];   
    /* 源IP地址 */   
    u_int8_t arp_destination_ethernet_address[6];   
    /* 目的以太网地址 */   
    u_int8_t arp_destination_ip_address[4];   
    /* 目的IP地址 */   
};   
/*  
=======================================================================================================================  
下面是实现ARP协议分析的函数定义  
=======================================================================================================================  
 */   
void arp_protocol_packet_callback(u_char *argument, const struct pcap_pkthdr *packet_header, const u_char *packet_content)   
{   
    struct arp_header *arp_protocol;   
    /* ARP协议变量 */   
    u_short protocol_type;   
    /* 协议类型 */   
    u_short hardware_type;   
    /* 硬件类型 */   
    u_short operation_code;   
    /* 操作类型 */   
    u_char *mac_string;   
    /* 以太网地址 */   
    struct in_addr source_ip_address;   
    /* 源IP地址 */   
    struct in_addr destination_ip_address;   
    /* 目的IP地址 */   
    u_char hardware_length;   
    /* 硬件地址长度 */   
    u_char protocol_length;   
    /* 协议地址长度 */   
    printf("--------   ARP Protocol (Network Layer)    --------\n");   
    arp_protocol = (struct arp_header*)(packet_content + 14);   
    /*  
     * 获得ARP协议数据。注意在这里要跳过以太网数据部分,它的长度刚好是14,所以在这里加上14,是指针跳过14个字节  
     */   
    hardware_type = ntohs(arp_protocol->arp_hardware_type);   
    /* 获得硬件类型 */   
    protocol_type = ntohs(arp_protocol->arp_protocol_type);   
    /* 获得协议类型 */   
    operation_code = ntohs(arp_protocol->arp_operation_code);   
    /* 获得操作码 */   
    hardware_length = arp_protocol->arp_hardware_length;   
    /* 获得硬件地址长度 */   
    protocol_length = arp_protocol->arp_protocol_length;   
    /* 获得协议地址长度 */   
    printf("ARP Hardware Type:%d\n", hardware_type);   
    printf("ARP Protocol Type:%d\n", protocol_type);   
    printf("ARP Hardware Length:%d\n", hardware_length);   
    printf("ARP Protocol Length:%d\n", protocol_length);   
    printf("ARP Operation:%d\n", operation_code);   
    switch (operation_code) /* 根据操作码进行判断是ARP什么类型协议 */   
    {   
        case 1:   
            printf("ARP Request Protocol\n");   
            break;   
            /* 是ARP查询协议 */   
        case 2:   
            printf("ARP Reply Protocol\n");   
            break;   
            /* 是ARP应答协议 */   
        case 3:   
            printf("RARP Request Protocol\n");   
            break;   
            /* 是RARP查询协议 */   
        case 4:   
            printf("RARP Reply Protocol\n");   
            break;   
            /* 是RARP应答协议 */   
        default:   
            break;   
    }   
    printf("Ethernet Source Address is : \n");   
    mac_string = arp_protocol->arp_source_ethernet_address;   
    printf("%02x:%02x:%02x:%02x:%02x:%02x\n", *mac_string, *(mac_string + 1), *(mac_string + 2), *(mac_string + 3), *(mac_string + 4), *(mac_string + 5));   
    /* 获得源以太网地址 */   
    memcpy((void*) &source_ip_address, (void*) &arp_protocol->arp_source_ip_address, sizeof(struct in_addr));   
    printf("Source IP Address:%s\n", inet_ntoa(source_ip_address));   
    /* 获得源IP地址 */   
    printf("Ethernet Destination Address is : \n");   
    mac_string = arp_protocol->arp_destination_ethernet_address;   
    printf("%02x:%02x:%02x:%02x:%02x:%02x\n", *mac_string, *(mac_string + 1), *(mac_string + 2), *(mac_string + 3), *(mac_string + 4), *(mac_string + 5));   
    /* 获得目的以太网地址 */   
    memcpy((void*) &destination_ip_address, (void*) &arp_protocol->arp_destination_ip_address, sizeof(struct in_addr));   
    printf("Destination IP Address:%s\n", inet_ntoa(destination_ip_address));   
    /* 获得目的IP地址 */   
}   
/*  
=======================================================================================================================  
下面是回调函数,实现以太网协议分析  
=======================================================================================================================  
 */   
void ethernet_protocol_packet_callback(u_char *argument, const struct pcap_pkthdr *packet_header, const u_char *packet_content)   
{   
    u_short ethernet_type;   
    /* 以太网类型 */   
    struct ether_header *ethernet_protocol;   
    /* 以太网协议变量 */   
    u_char *mac_string;   
    /* 以太网地址 */   
    static int packet_number = 1;   
    printf("**************************************************\n");   
    printf("The %d  ARP  packet is captured.\n", packet_number);   
    printf("--------   Ehternet Protocol (Link Layer)    --------\n");   
    ethernet_protocol = (struct ether_header*)packet_content;   
    /* 获得以太网协议数据 */   
    printf("Ethernet type is :\n");   
    ethernet_type = ntohs(ethernet_protocol->ether_type);   
    /* 获得以太网类型 */   
    printf("%04x\n", ethernet_type);   
    switch (ethernet_type) /* 根据以太网类型判断上层协议类型 */   
    {   
        case 0x0800:   
            printf("The network layer is IP protocol\n");   
            break;   
        case 0x0806:   
            printf("The network layer is ARP protocol\n");   
            break;   
        case 0x8035:   
            printf("The network layer is RARP protocol\n");   
            break;   
        default:   
            break;   
    }   
    printf("Mac Source Address is : \n");   
    mac_string = ethernet_protocol->ether_shost;   
    printf("%02x:%02x:%02x:%02x:%02x:%02x\n", *mac_string, *(mac_string + 1), *(mac_string + 2), *(mac_string + 3), *(mac_string + 4), *(mac_string + 5));   
    /* 获得源以太网地址 */   
    printf("Mac Destination Address is : \n");   
    mac_string = ethernet_protocol->ether_dhost;   
    printf("%02x:%02x:%02x:%02x:%02x:%02x\n", *mac_string, *(mac_string + 1), *(mac_string + 2), *(mac_string + 3), *(mac_string + 4), *(mac_string + 5));   
    /* 获得目的以太网地址 */   
    switch (ethernet_type)   
    {   
        case 0x0806:   
            arp_protocol_packet_callback(argument, packet_header, packet_content);   
            break;   
            /*  
             * 如果以太网类型是0x0806,表示上层协议是ARP协议,应该调用分析ARP协议的函数。注意此时的参数传递,全部是回调函数的参数,它代表的是同一个网络数据包,所以在这里,既分析此数据包的以太网协议部分,又分析来了此数据包的ARP协议部分。  
             */   
        default:   
            break;   
    }   
    printf("**************************************************\n");   
    packet_number++;   
}   
void main()   
{   
    pcap_t *pcap_handle;   
    /* Libpcap句柄 */   
    char error_content[PCAP_ERRBUF_SIZE];   
    /* 错误信息 */   
    char *net_interface;   
    /* 网路接口 */   
    struct bpf_program bpf_filter;   
    /* bpf过滤规则 */   
    char bpf_filter_string[] = "arp";   
    /* 过滤规则字符串,这里表示本程序只是捕获所有ARP协议的网络数据包 */   
    bpf_u_int32 net_mask;   
    /* 网络掩码 */   
    bpf_u_int32 net_ip;   
    /* 网络地址 */   
    net_interface = pcap_lookupdev(error_content);   
    /* 获得网络接口 */   
    pcap_lookupnet(net_interface, &net_ip, &net_mask, error_content);   
    /* 获得网络地址和网络掩码 */   
    pcap_handle = pcap_open_live(net_interface, BUFSIZ, 1, 0, error_content);   
    /* 打开网路接口 */   
    pcap_compile(pcap_handle, &bpf_filter, bpf_filter_string, 0, net_ip);   
    /* 编译过滤规则 */   
    pcap_setfilter(pcap_handle, &bpf_filter);   
    /* 设置过滤规则 */   
    if (pcap_datalink(pcap_handle) != DLT_EN10MB)   
        return ;   
    pcap_loop(pcap_handle,  - 1, ethernet_protocol_packet_callback, NULL);   
    /* 注册回到函数,循环捕获数据包 */   
    pcap_close(pcap_handle);   
    /* 关闭Libpcap操作 */   
}   


原文地址:https://www.cnblogs.com/new0801/p/6177680.html