首页 > 编程语言 >网络编程-包过滤防火墙简单实现

网络编程-包过滤防火墙简单实现

时间:2023-04-15 14:24:54浏览次数:35  
标签:val int ip 编程 防火墙 filter 过滤 ban port

一、netfilter框架

这次实验使用netfilter框架,参考《网络编程》相关知识以及样例代码。

Netfilter是 Linux 内核中的一个框架,它为以定制处理器形式实施的各种网络相关操作提供了灵活性。Netfilter提供数据包过滤、网络地址翻译和端口翻译的各种选项。

检查点

在netfilter中,对于IPv4协议栈上传输过程,设置了5个检查点,PREROUTINGLOCAL-INLOCAL-OUTFORWARDPOSTROUTING

  • PREROUTING:二层收包结束后,根据注册协议和回调函数分发数据包,对于IPv4的数据包,会送入三层进行合法性检测处理,并经过PREROUTING检查点。该检查点的处理过程在报文做路由前执行。
  • LOCAL-IN:在经过PREROUTING检查点,会根据报文判断转发或输入本地,若输入本地,则需要对分片进行检查重组,之后经过LOCAL-IN检查点。该检查点的处理过程在流入本地的报文做路由前执行。
  • LOCAL-OUT:从本机发出的数据包,在查询路由成功后,经过LOCAL-OUT检查点,该检查点的处理过程在本地报文做流出路由前执行。
  • FORWARD:在经过PREROUTING检查点,会根据报文判断转发或输入本地,若需要转发,则经过FORWARD检查点。
  • POSTROUTING:转发的数据包或者是本地输出的数据包在最后输出之前,都需要经过POSTROUTING检查点。

本次实验主要只用LOCAL-INLOCAL-OUT检查点,实现一个简单的包过滤防火墙。

HOOK

包过滤防火墙实现对出入站的ip地址,端口以及ping进行检测过滤,实现方式是在对应检查点挂接回调函数,即在检查检点注册hook,函数为nf_register_hook()

二、设计思路

设计思路

包过滤防火墙主要针对入站以及出站流量,选择LOCAL-INLOCAL-OUT检查点对本机相关的流量进行检测过滤,设计出入站过滤规则开关,控制是否开启过滤规则,建立出站和入站的过滤表,对过滤ip以及端口进行管理。

数据结构

struct filter_status {
    /* 0:放行,1:过滤 */
    int ping_status;    //禁ping
    int ip_status;      //禁ip
    int port_status;    //禁port
    int debug_level;    //0不打印信息,1打印信息
    struct in_addr ban_ip_in[IPSIZE];   //禁用入站ip数组
    struct in_addr ban_ip_out[IPSIZE];   //禁用出站ip数组
    int ban_port_in[PORTSIZE]; //禁用入站端口
    int ban_port_out[PORTSIZE]; //禁用出站端口
};

filter_status过滤器,是防火墙的规则集,防火墙根据其中的状态信息以及数组元素执行规则。

  • ping_statusip_statusport_status,控制ping过滤,ip地址过滤以及端口过滤是否开启。
  • debug_level控制是否打印hook调用数量。
  • ban_ip_inban_ip_out分别用于记录入站和出站ip过滤的ip地址。
  • ban_port_inban_port_out分别用于记录入站和出站端口过滤的端口号。
struct val_status {
    unsigned int parameter;  //协议编号, ip地址, 端口号
    unsigned int rule;   //a|r   0放行 1过滤
    unsigned int ip_port_switch;  //用于ip和port是否同时修改出站和入栈规则   1:修改入站规则,2:修改出站规则,3:都修改,4:开启规则,5:关闭规则
};

val_status是用于用户态的控制程序向内核防火墙传输数据的数据结构

  • parameter指定用户操作的类型,如具体协议编号,ip地址或端口号。
  • rule规定防火墙规则,0放行,1丢弃。
  • ip_port_switch对ip或端口设置规则时,指定设置出站或入站规则。

常量定义

#define CMD_MIN		0x6000
#define CMD_DEBUG		0x6001
#define CMD_PROTOCOL	0x6002
#define CMD_IP			0x6003
#define CMD_PORT		0x6004
#define CMD_MAX		0x6100
//定义协议标识常量
#define DEBUG_SYN   99
#define ICMP_SYN    100
#define IP_SYN      300
#define PORT_SYN    301
//定义ip过滤数组以及端口过滤数组的容量
#define IPSIZE 100
#define PORTSIZE 65535

定义协议标识规范数据传输,100-299为协议编号,300为ip标识,301为端口标识。

三、源代码

//myfw.h

#define CMD_MIN		0x6000
#define CMD_DEBUG		0x6001
#define CMD_PROTOCOL	0x6002
#define CMD_IP			0x6003
#define CMD_PORT		0x6004
#define CMD_MAX		0x6100
//定义协议标识常量
#define DEBUG_SYN   99
#define ICMP_SYN    100
#define IP_SYN      300
#define PORT_SYN    301
#define IPSIZE 100
#define PORTSIZE 65535
struct val_status {
    unsigned int parameter;  //协议编号, ip地址, 端口号
    unsigned int rule;   //a|r   0通过 1过滤
    unsigned int ip_port_switch;  //用于ip和port是否同时修改出站和入栈规则   1:修改入站规则,2:修改出站规则,3:都修改,4:开启规则,5:关闭规则
};
struct filter_status {
    /* 0:通过,1:过滤 */
    int ping_status;    //禁ping
    int ip_status;      //禁ip
    int port_status;    //禁port
    int debug_level;    //0不打印信息,1打印信息
    struct in_addr ban_ip_in[IPSIZE];   //禁用入站ip数组
    struct in_addr ban_ip_out[IPSIZE];   //禁用出站ip数组
    int ban_port_in[PORTSIZE]; //禁用入站端口
    int ban_port_out[PORTSIZE]; //禁用出站端口
};
int find_ip(int ip, struct in_addr* ip_list)
{
    int i;
    for(i = 0; i < IPSIZE; i++) {
        if(ip == ip_list[i].s_addr) {
            return i;
        }
    }
    return -1;
}
int find_port(short port, int *port_list)
{
    int i;
    for(i = 0; i < PORTSIZE; i++) {
        if(port == port_list[i]) {
            return i;
        }
    }
    return -1;
}
//myfw.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <net/tcp.h>
#include <linux/netdevice.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/string.h>

#include "myfw.h"

static struct nf_hook_ops nfhoLocalIn;
static struct nf_hook_ops nfhoLocalOut;
static struct nf_hook_ops nfhoPreRouting;
static struct nf_hook_ops nfhoForward;
static struct nf_hook_ops nfhoPostRouting;
static struct nf_sockopt_ops nfhoSockopt;
static struct filter_status filter = {0, 0, 0, 0, {0}, {0}, {0}, {0}};	//过滤器
static struct val_status val;	//信号接收结构体,用于接收控制程序发出的控制信号

static int nfcount = 0;

void debugInfo(char * msg)
{
	if (filter.debug_level) {
		nfcount++;
		printk("%s, nfcount: %d\n", msg, nfcount);
	}
}

unsigned int hookLocalIn(void *priv,
	struct sk_buff *skb,
	const struct nf_hook_state *state)
{
	unsigned rc = NF_ACCEPT;

	struct iphdr *iph = ip_hdr(skb);
	struct tcphdr *tcph = NULL;
	struct udphdr *ucph = NULL;
	int i;
	//icmp过滤
	if (iph->protocol == IPPROTO_ICMP && filter.ping_status)
		rc = NF_DROP; 
    //ip入站过滤
	if (filter.ip_status) {
		for(i = 0; i < IPSIZE; i++) {	//遍历入站ip过滤数组
			if(filter.ban_ip_in[i].s_addr == iph->saddr) {
				rc = NF_DROP;
				break;
			}
		}
	}
    //端口入站过滤
	if(filter.port_status) {
		if(iph->protocol == IPPROTO_TCP) {	//判定为tcp数据包
			tcph = tcp_hdr(skb);			//获取tcp头
			for(i = 0; i < PORTSIZE; i++) {	//遍历入站端口过滤数组
				if(filter.ban_port_in[i] == ntohs(tcph->dest)) {
					rc = NF_DROP;
					break;
				}
			}
		}
		if(iph->protocol == IPPROTO_UDP) {	//判定为udp数据包
			ucph = udp_hdr(skb);			//获取udp头
			for(i = 0; i < PORTSIZE; i++) {	//遍历入站端口过滤数组
				if(filter.ban_port_in[i] == ntohs(ucph->dest)) {
					rc = NF_DROP;
					break;
				}
			}
		}
	}
	debugInfo("hookLocalIn");

	return rc;
}

unsigned int hookLocalOut(void *priv,
	struct sk_buff *skb,
	const struct nf_hook_state *state)
{
	unsigned rc = NF_ACCEPT;

	struct iphdr *iph = ip_hdr(skb);
	struct tcphdr *tcph = NULL;
	struct udphdr *ucph = NULL;
	int i;

	if(filter.ip_status) {
		for(i = 0; i < IPSIZE; i++) {	//遍历出站ip过滤数组
			if(filter.ban_ip_out[i].s_addr == iph->daddr) {
				rc = NF_DROP;
				break;
			}
		}
	}
	if(filter.port_status) {
		if(iph->protocol == IPPROTO_TCP) {	//判定为tcp数据包
			tcph = tcp_hdr(skb);			//获取tcp头
			for(i = 0; i < PORTSIZE; i++) {	//遍历入站端口过滤数组
				if(filter.ban_port_out[i] == ntohs(tcph->source)) {
					rc = NF_DROP;
					break;
				}
			}
		}
		if(iph->protocol == IPPROTO_UDP) {	//判定为udp数据包
			ucph = udp_hdr(skb);			//获取udp头
			for(i = 0; i < PORTSIZE; i++) {	//遍历入站端口过滤数组
				if(filter.ban_port_out[i] == ntohs(ucph->source)) {
					rc = NF_DROP;
					break;
				}
			}
		}
	}
	debugInfo("hookLocalOut");

	return rc;
}

unsigned int hookPreRouting(void *priv,
	struct sk_buff *skb,
	const struct nf_hook_state *state)
{
	debugInfo("hookPreRouting");

	return NF_ACCEPT;
}

unsigned int hookPostRouting(void *priv,
	struct sk_buff *skb,
	const struct nf_hook_state *state)
{
	debugInfo("hookPostRouting");

	return NF_ACCEPT;
}

unsigned int hookForward(void *priv,
	struct sk_buff *skb,
	const struct nf_hook_state *state)
{
	debugInfo("hookForwarding");

	return NF_ACCEPT;
}

int hookSockoptSet(struct sock *sock,
	int cmd,
	sockptr_t user,
	unsigned int len)
{
	int ret;
	int parameter;
	char function[10] = {0};
	char rule[2] = {0};
	char *p;
	debugInfo("hookSockoptSet");
	
	switch (cmd) {
	case CMD_DEBUG:	//debug开启或关闭
		ret = copy_from_user(&val, user.user, sizeof(val));
		filter.debug_level = val.rule;
		printk("set debug level to %d", val.rule);
		break;
	case CMD_PROTOCOL:	//协议规则,目前只有icmp ping
		ret = copy_from_user(&val, user.user, sizeof(val));
		filter.ping_status = val.rule;
		printk("ICMP:%d rule:%d", val.parameter, val.rule);
		break;
	case CMD_IP:	//ip规则,出入规则
		ret = copy_from_user(&val, user.user, sizeof(val));
		if(val.ip_port_switch != 4 && val.ip_port_switch != 5 && (val.parameter < 1 || val.parameter > 4294967295)) break; // 合法ip范围 0.0.0.1 ~ 255.255.255.255
		if(val.ip_port_switch == 1) {		//入站规则
			if(val.rule == 1) {				//添加ip
				int flag = find_ip(val.parameter, filter.ban_ip_in);
				if(flag == -1) {
					int i;
					for(i = 0; i < IPSIZE; i++) {
						if(filter.ban_ip_in[i].s_addr == 0) {
							printk("add input ip %u\n", val.parameter);
							filter.ban_ip_in[i].s_addr = val.parameter;
							break;
						}
					}
				}
			}
			else if(val.rule == 0) {		//删除ip
				int flag = find_ip(val.parameter, filter.ban_ip_in);
				printk("delete input ip %u\n", val.parameter);
				if(flag != -1) {
					filter.ban_ip_in[flag].s_addr = 0;
				}
			}
		}
		else if(val.ip_port_switch == 2) {	//出站规则
			if(val.rule == 1) {				//添加ip
				int flag = find_ip(val.parameter, filter.ban_ip_out);
				if(flag == -1) {
					int i;
					for(i = 0; i < IPSIZE; i++) {
						if(filter.ban_ip_out[i].s_addr == 0) {
							printk("add output ip %u\n", &val.parameter);
							filter.ban_ip_out[i].s_addr = val.parameter;
							break;
						}
					}
				}
			}
			else if(val.rule == 0) {		//删除ip
				int flag = find_ip(val.parameter, filter.ban_ip_out);
				printk("delete output ip %u\n", val.parameter);
				if(flag != -1) {
					filter.ban_ip_out[flag].s_addr = 0;
				}
			}
		}
		else if(val.ip_port_switch == 3) {	//出入规则
			if(val.rule == 1) {				//添加ip
				int flag = find_ip(val.parameter, filter.ban_ip_in);
				if(flag == -1) {
					int i;
					for(i = 0; i < IPSIZE; i++) {
						if(filter.ban_ip_in[i].s_addr == 0) {
							printk("add input ip %u\n", val.parameter);
							filter.ban_ip_in[i].s_addr = val.parameter;
							break;
						}
					}
				}
				flag = find_ip(val.parameter, filter.ban_ip_out);
				if(flag == -1) {
					int i;
					for(i = 0; i < IPSIZE; i++) {
						if(filter.ban_ip_out[i].s_addr == 0) {
							printk("add output ip %u\n", val.parameter);
							filter.ban_ip_out[i].s_addr = val.parameter;
							break;
						}
					}
				}
			}
			else if(val.rule == 0) {		//删除ip
				int flag = find_ip(val.parameter, filter.ban_ip_in);
					printk("delete input ip %u\n", val.parameter);
					if(flag != -1) {
						filter.ban_ip_in[flag].s_addr = 0;
					}
				flag = find_ip(val.parameter, filter.ban_ip_out);
				printk("delete output ip %u\n", val.parameter);
				if(flag != -1) {
					filter.ban_ip_out[flag].s_addr = 0;
				}
			}
		}
		else if(val.ip_port_switch == 4) {	//开启ip过滤
			filter.ip_status = 1;
		}
		else if(val.ip_port_switch == 5) {	//关闭ip过滤
			filter.ip_status = 0;
		}
		break;
	case CMD_PORT:
		ret = copy_from_user(&val, user.user, sizeof(val));
		if(val.ip_port_switch != 4 && val.ip_port_switch != 5 && (val.parameter < 1 || val.parameter > 65535)) break; // 合法端口范围 1 ~ 65535
		if(val.ip_port_switch == 1) {	//入站规则
			if(val.rule == 1) {			//添加port
				int flag = find_port(val.parameter, filter.ban_port_in);
				if(flag == -1) {
					int i;
					for(i = 0; i < PORTSIZE; i++) {
						if(filter.ban_port_in[i] == -1) {
							printk("add input port %d\n", val.parameter);
							filter.ban_port_in[i] = val.parameter;
							break;
						}
					}
				}
			}
			else if(val.rule == 0) {	//删除port
				int flag = find_port(val.parameter, filter.ban_port_in);
				if(flag != -1) {
					filter.ban_port_in[flag] = -1;
				}
			}
		}
		if(val.ip_port_switch == 2) {	//出站规则
			if(val.rule == 1) {			//添加port
				int flag = find_port(val.parameter, filter.ban_port_out);
				if(flag == -1) {
					int i;
					for(i = 0; i < PORTSIZE; i++) {
						if(filter.ban_port_out[i] == -1) {
							filter.ban_port_out[i] = val.parameter;
							break;
						}
					}
				}
			}
			else if(val.rule == 0) {	//删除port
				int flag = find_port(val.parameter, filter.ban_port_out);
				if(flag != -1) {
					filter.ban_port_out[flag] = -1;
				}
			}
		}
		if(val.ip_port_switch == 3) {	//出入规则
			if(val.rule == 1) {			//添加port
				int flag = find_port(val.parameter, filter.ban_port_in);
				if(flag == -1) {
					int i;
					for(i = 0; i < PORTSIZE; i++) {
						if(filter.ban_port_in[i] == -1) {
							filter.ban_port_in[i] = val.parameter;
							break;
						}
					}
				}
				flag = find_port(val.parameter, filter.ban_port_out);
				if(flag == -1) {
					int i;
					for(i = 0; i < PORTSIZE; i++) {
						if(filter.ban_port_out[i] == -1) {
							filter.ban_port_out[i] = val.parameter;
							break;
						}
					}
				}
			}
			else if(val.rule == 0) {	//删除port
				int flag = find_port(val.parameter, filter.ban_port_in);
				if(flag != -1) {
					filter.ban_port_in[flag] = -1;
				}
				flag = find_port(val.parameter, filter.ban_port_out);
				if(flag != -1) {
					filter.ban_port_out[flag] = -1;
				}
			}
		}
		if(val.ip_port_switch == 4) {	//开启port过滤
			filter.port_status = 1;
		}
		if(val.ip_port_switch == 5) {	//关闭port过滤
			filter.port_status = 0;
		}
	}
	if (ret != 0) {
		printk("copy_from_user error");
		ret = -EINVAL;
	}
	return ret;
}

int hookSockoptGet(struct sock *sock,
	int cmd,
	void __user *user,
	int * len)
{
	int ret;
	debugInfo("hookSockoptGet");
	int i;
	switch (cmd) {
	case CMD_DEBUG:
		ret = copy_to_user(user, &filter, sizeof(filter));
		break;
	case CMD_PROTOCOL:
		ret = copy_to_user(user, &filter, sizeof(filter));
		break;
	case CMD_IP:
		printk("input ip list:\n");
		for(i = 0; i < IPSIZE; i++) {
			printk("%u\n", filter.ban_ip_in[i].s_addr);
		}
		printk("output ip list:\n");
		for(i = 0; i < IPSIZE; i++) {
			printk("%u\n", filter.ban_ip_out[i].s_addr);
		}
		ret = copy_to_user(user, &filter, sizeof(filter));
		break;
	case CMD_PORT:
		printk("input port list:\n");
		for(i = 0; i < PORTSIZE; i++) {
			if(filter.ban_port_in[i] != -1)
				printk("%d\n", filter.ban_port_in[i]);
		}
		printk("output port list:\n");
		for(i = 0; i < PORTSIZE; i++) {
			if(filter.ban_port_out[i] != -1)
				printk("%d\n", filter.ban_port_out[i]);
		}
		ret = copy_to_user(user, &filter, sizeof(filter));
		break;
	}
	if (ret != 0) {
		ret = -EINVAL;
		debugInfo("copy_to_user error");
	}
	return ret;
}

int init_module()
{
	int i;
	//初始化过滤器
	for(i = 0; i < IPSIZE; i++) {
		filter.ban_ip_in[i].s_addr = 0;
		filter.ban_ip_out[i].s_addr = 0;
	}
	for(i = 0; i < PORTSIZE; i++) {
		filter.ban_port_in[i] = -1;
		filter.ban_port_out[i] = -1;
	}
	//初始化hookLocalIn
	nfhoLocalIn.hook = hookLocalIn;
	nfhoLocalIn.hooknum = NF_INET_LOCAL_IN;
	nfhoLocalIn.pf = PF_INET;
	nfhoLocalIn.priority = NF_IP_PRI_FIRST;
	nf_register_net_hook(&init_net, &nfhoLocalIn);
	//初始化hookLocalOut
	nfhoLocalOut.hook = hookLocalOut;
	nfhoLocalOut.hooknum = NF_INET_LOCAL_OUT; 
	nfhoLocalOut.pf = PF_INET;
	nfhoLocalOut.priority = NF_IP_PRI_FIRST;
	nf_register_net_hook(&init_net, &nfhoLocalOut);
	//初始化hookPreRouting
	nfhoPreRouting.hook = hookPreRouting;
	nfhoPreRouting.hooknum = NF_INET_PRE_ROUTING; 
	nfhoPreRouting.pf = PF_INET;
	nfhoPreRouting.priority = NF_IP_PRI_FIRST;
	nf_register_net_hook(&init_net, &nfhoPreRouting);
	//初始化hookForward
	nfhoForward.hook = hookForward;
	nfhoForward.hooknum = NF_INET_FORWARD; 
	nfhoForward.pf = PF_INET;
	nfhoForward.priority = NF_IP_PRI_FIRST;
	nf_register_net_hook(&init_net, &nfhoForward);
	//初始化hookPostRouting
	nfhoPostRouting.hook = hookPostRouting;
	nfhoPostRouting.hooknum = NF_INET_POST_ROUTING; 
	nfhoPostRouting.pf = PF_INET;
	nfhoPostRouting.priority = NF_IP_PRI_FIRST;
	nf_register_net_hook(&init_net, &nfhoPostRouting);
	//初始化hookSockoptSet和//初始化hookSockoptGet
	nfhoSockopt.pf = PF_INET;
	nfhoSockopt.set_optmin = CMD_MIN;
	nfhoSockopt.set_optmax = CMD_MAX;
	nfhoSockopt.set = hookSockoptSet;
	nfhoSockopt.get_optmin = CMD_MIN;
	nfhoSockopt.get_optmax = CMD_MAX;
	nfhoSockopt.get = hookSockoptGet;
	nf_register_sockopt(&nfhoSockopt);

	printk("myfw started\n");
	return 0;
}
void cleanup_module()
{
	nf_unregister_net_hook(&init_net, &nfhoLocalIn);
	nf_unregister_net_hook(&init_net, &nfhoLocalOut);
	nf_unregister_net_hook(&init_net, &nfhoPreRouting);
	nf_unregister_net_hook(&init_net, &nfhoForward);
	nf_unregister_net_hook(&init_net, &nfhoPostRouting);
	nf_unregister_sockopt(&nfhoSockopt);
	printk("myfw stopped\n");
}
MODULE_LICENSE("GPL");

//myfwctl.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include <errno.h>  
#include "myfw.h"

static struct val_status val;
static struct filter_status filter = {0, 0, 0, {0}, {0}, {0}, {0}};

void printError(char * msg)
{
	printf("%s error %d: %s\n", msg, errno, strerror(errno));
}

void printSuccess(char * msg) 
{
	printf("%s success\n",msg);
}

void usage(char * program)
{
	printf("%s <set> <debug debug_level>|<ip input|output|all|open|close>[ip_addr a|r]|<port input|output|all|open|close>[port_no a|r]|<protocol protocol_name a|r>\n", program);
	printf("%s <get> <debug>|<ip>|<port>|<protocol>\n", program);
}

int set(int argc, char * argv[], int sockfd) {
	int ret = -1;
	if (argc > 3) {
		char * obj = argv[2];
		int val_len = sizeof(val);
		int cmd = 0;
		int syn;
		if (!strcmp(obj, "debug")) {
			cmd = CMD_DEBUG;
			val.parameter = DEBUG_SYN;
			val.rule = atoi(argv[3]);
		}
		else if (!strcmp(obj, "protocol")) {
			cmd = CMD_PROTOCOL;
			if (!strcmp(argv[3], "icmp")) {	//set protocol icmp a
				val.parameter = ICMP_SYN;
				if (!strcmp(argv[4], "a")) {
					val.rule = 0;
				}
				else if (!strcmp(argv[4], "r")) {
					val.rule = 1;
				}
			}
		}
		else if (!strcmp(obj, "ip")) {
			cmd = CMD_IP;
			struct in_addr ip;
			if (!strcmp(argv[3], "input")) {		//设定入站ip规则
				val.ip_port_switch = 1;
				inet_aton(argv[4], &ip.s_addr);
				val.parameter = ip.s_addr;	//网络序传输
				if (!strcmp(argv[5], "a")) {		//放行
					val.rule = 0;
				}
				else if (!strcmp(argv[5], "r")) {	//过滤
					val.rule = 1;
				}
			}
			else if (!strcmp(argv[3], "output")) {	//设定出站ip规则
				val.ip_port_switch = 2;
				inet_aton(argv[4], &ip.s_addr);
				val.parameter = ip.s_addr;	//网络序传输
				if (!strcmp(argv[5], "a")) {		//放行
					val.rule = 0;
				}
				else if (!strcmp(argv[5], "r")) {	//过滤
					val.rule = 1;
				}
			}
			else if (!strcmp(argv[3], "all")) {		//设定出入ip规则
				val.ip_port_switch = 3;				
				inet_aton(argv[4], &ip.s_addr);
				val.parameter = ip.s_addr;	//网络序传输
				if (!strcmp(argv[5], "a")) {		//放行
					val.rule = 0;
				}
				else if (!strcmp(argv[5], "r")) {	//过滤
					val.rule = 1;
				}
			}
			else if(!strcmp(argv[3], "open")) {		//开启ip过滤
				val.ip_port_switch = 4;
			}
			else if(!strcmp(argv[3], "close")) {	//关闭ip过滤
				val.ip_port_switch = 5;
			}
		}
		else if(!strcmp(obj, "port")) {		
			cmd = CMD_PORT;
			if (!strcmp(argv[3], "input")) {		//设定入站端口规则
				val.ip_port_switch = 1;
				val.parameter = atoi(argv[4]);
				if (!strcmp(argv[5], "a")) {		//放行
					val.rule = 0;
				}
				else if (!strcmp(argv[5], "r")) {	//过滤
					val.rule = 1;
				}
			}
			else if (!strcmp(argv[3], "output")) {	//设定出站端口规则
				val.ip_port_switch = 2;
				val.parameter = atoi(argv[4]);
				if (!strcmp(argv[5], "a")) {		//放行
					val.rule = 0;
				}
				else if (!strcmp(argv[5], "r")) {	//过滤
					val.rule = 1;
				}
			}
			else if (!strcmp(argv[3], "all")) {		//设定出入端口规则
				val.ip_port_switch = 3;				
				val.parameter = atoi(argv[4]);
				if (!strcmp(argv[5], "a")) {		//放行
					val.rule = 0;
				}
				else if (!strcmp(argv[5], "r")) {	//过滤
					val.rule = 1;
				}
			}
			else if(!strcmp(argv[3], "open")) {		//开启端口过滤
				val.ip_port_switch = 4;
			}
			else if(!strcmp(argv[3], "close")) {	//关闭端口过滤
				val.ip_port_switch = 5;
			}
		}
		if (cmd) {
			if (setsockopt(sockfd, IPPROTO_IP, cmd, &val, val_len)) {
				printError("setsockopt()");
			}
			else {
				// printSuccess("setsockopt()");
				ret = 0;
			}
		}
	}
	else {
		usage(argv[0]);
	}
	return ret;
}

int get(int argc, char * argv[], int sockfd) {
	int ret = -1;
	if (argc > 2) {
		int cmd = 0;
		socklen_t filter_len = sizeof(filter);
		char * obj = argv[2];
		if (!strcmp(obj, "debug")) {
			cmd = CMD_DEBUG;
		}
		else if (!strcmp(obj, "protocol")) {
			cmd = CMD_PROTOCOL;
		}
		else if (!strcmp(obj, "ip")) {
			cmd = CMD_IP;
		}
		else if (!strcmp(obj, "port")) {
			cmd = CMD_PORT;
		}
		if (cmd) {
			if (getsockopt(sockfd, IPPROTO_IP, cmd, &filter, &filter_len)) {
				printError("getsockopt");
			}
			else {
				switch (cmd) {
				int i;
				case CMD_DEBUG:
					printf("debug level=%d\n", filter.debug_level);
					break;
				case CMD_PROTOCOL:
					if(filter.ping_status == 0)
						printf("allow ping\n");
					if(filter.ping_status == 1)
						printf("ban ping\n");
					break;
				case CMD_IP:
					printf("input ip list:\n");
					for(i = 0; i < IPSIZE; i++) {
						if(filter.ban_ip_in[i].s_addr != 0) {
							unsigned char bytes[4];
							bytes[0] = (filter.ban_ip_in[i].s_addr >> 24) & 0xFF;
							bytes[1] = (filter.ban_ip_in[i].s_addr >> 16) & 0xFF;
							bytes[2] = (filter.ban_ip_in[i].s_addr >> 8) & 0xFF;
							bytes[3] = (filter.ban_ip_in[i].s_addr >> 0) & 0xFF;
							printf("%d.%d.%d.%d\n", bytes[3], bytes[2], bytes[1], bytes[0]);	//输出点分十进制ip地址
						}
					}
					printf("\noutput ip list:\n");
					for(i = 0; i < IPSIZE; i++) {
						if(filter.ban_ip_out[i].s_addr != 0) {
							unsigned char bytes[4];
							bytes[0] = (filter.ban_ip_out[i].s_addr >> 24) & 0xFF;
							bytes[1] = (filter.ban_ip_out[i].s_addr >> 16) & 0xFF;
							bytes[2] = (filter.ban_ip_out[i].s_addr >> 8) & 0xFF;
							bytes[3] = (filter.ban_ip_out[i].s_addr >> 0) & 0xFF;
							printf("%d.%d.%d.%d\n", bytes[3], bytes[2], bytes[1], bytes[0]);	//输出点分十进制ip地址
						}
					}
					if(filter.ip_status == 0)
						printf("is open ip filter:	NO\n");
					if(filter.ip_status == 1)
						printf("is open ip filter:	YES\n");
					break;
				case CMD_PORT:
					printf("input port list\n");
					for(i = 0; i < PORTSIZE; i++) {
						if(filter.ban_port_in[i] != -1) {
							printf("%d\n", filter.ban_port_in[i]);
						}
					}
					printf("\noutput port list:\n");
					for(i = 0; i < PORTSIZE; i++) {
						if(filter.ban_port_out[i] != -1) {
							printf("%d\n", filter.ban_port_out[i]);
						}
					}
					if(filter.port_status == 0)
						printf("is open port filter:	NO\n");
					if(filter.port_status == 1)
						printf("is open port filter:	YES\n");
				}
			}
		}
	}
	return ret;
}

int main(int argc, char * argv[])
{
	int ret = -1;
	if (argc < 3) {
		usage(argv[0]);
	}
	else {
		int sockfd;
		if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1) {
			printError("socket()");
		}
		else {
			char * cmd = argv[1];
			if (!strcmp(cmd, "set")) {
				ret = set(argc, argv,sockfd);
			}
			else if (!strcmp(cmd, "get")) {
				ret = get(argc, argv,sockfd);
			}
			else {
				usage(argv[0]);
			}
			close(sockfd);
		}
	}
	return ret;
}

四、指令手册

//设置指令
<set> <debug debug_level>|<ip input|output|all|open|close>[ip_addr a|r]|<port input|output|all|open|close>[port_no a|r]|<protocol protocol_name a|r>

//回显指令
<get> <debug>|<ip>|<port>|<protocol_name>

五、程序测试

测试环境

防火墙部署主机:ubuntu20.04

防火墙编译以及启动

使用make编译防火墙myfw.c

#Makefile

# Makefile 4.0
obj-m := myfw.o
CURRENT_PATH := $(shell pwd)
LINUX_KERNEL := $(shell uname -r)
LINUX_KERNEL_PATH := /usr/src/linux-headers-$(LINUX_KERNEL)

all:
	make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
clean:
	make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean

编译防火墙控制程序

gcc myfwctl.c -o myfwctl

启动防火墙

sudo insmod myfw.ko

对于防火墙功能的测试验证,可以使用wireshark等监听工具实时监听通信流量。

标签:val,int,ip,编程,防火墙,filter,过滤,ban,port
From: https://www.cnblogs.com/p1a0m1a0/p/17321039.html

相关文章

  • 每日编程一小时(第六天)
    一.问题描述。给定N个正整数,请统计奇数和偶数各有多少个?二.设计思路。1.输入一个整数n。2.循环输入n个整数。3.设计两个标志数a、b。4.n个整数依次对二求余,如果结果为0,a+1,否则b+1.三.流程图  四.代码实现#include<iostream>usingnamespacestd;intmain(){......
  • Shell编程自动化之Shell编程基础
    一、Shell可以用来做什么1.自动化批量系统初始化程序;2.自动化批量软件部署程序;3.应用程序管理;4.日志分析处理程序;5.自动化备份恢复程序;6.自动化信息采集及监控程序;7.自动化管理程序;二、Shell概述1.Shell是操作系统的外壳,是用户操作系统的命令接口,是一个介于用户和系统内核......
  • Java面向对象编程基础
    类与对象类和对象的区别和联系类是抽象的,概念的,代表一类事物,比如人类,猫类..,即它是数据类型.对象是具体的,实际的,代表一个具体事物,即是实例.类是对象的模板,对象是类的一个个体,对应一个实例对象在内存中存在形式!字符串本质上是一个引用类型,按照jvm的规则会把字符串放在方法区的......
  • linux shell编程作业
    使用for循环语句编写一段B-shell程序,完成显示用户注册目录下的a_sub,b_sub子目录下的所有C程序文件及其目标文件的列表。dirlst="a_subb_sub"foriin$dirlstdocd$HOME/$ils-l*.cdone编写一段shell程序完成:根据从键盘输入的学生成绩,显示相应的成绩标准(分出不及......
  • c++核心编程—内存分区模型
    一、概述c++在执行时,将内存大致分为4个区域1、代码区:存放函数体的二进制代码,由操作系统进行管理2、全局区:存放全局变量和静态变量以及常量3、栈区:由编译器自动分配释放,存放函数的参数,局部变量等4、堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收内存四区意义:不同区......
  • 品味布隆过滤器的设计之美
    布隆过滤器是一个精巧而且经典的数据结构。你可能没想到:RocketMQ、Hbase、Cassandra、LevelDB、RocksDB这些知名项目中都有布隆过滤器的身影。对于后端程序员来讲,学习和理解布隆过滤器有很大的必要性。来吧,我们一起品味布隆过滤器的设计之美。1缓存穿透我们先来看一个......
  • 模板元编程与函数式
    参考:【公开课】现代C++进阶:模板元编程与函数式ppt和代码在高性能计算中,一般使用函数式和元编程,而不使用面向对象。简单的介绍:类型自动推导模板参数、模板特化简单的实例:#include<iostream>template<classT>Ttwice(Tt){returnt*2;}std::stringtwice(std::......
  • SpringSecurity过滤器-CsrfFilter
    CsrfFilter是为了防御CSRF攻击的。CSRF攻击请参考松哥手把手教你在SpringBoot中防御CSRF攻击!soeasy!。CsrfFilter的源码在要学就学透彻!SpringSecurity中CSRF防御源码解析说的很清楚了。 在这里是对LazyCsrfTokenRepository的使用做个总结。 CsrfFilter#doFilterI......
  • 编程一小时2023.4.14
    1.#include<bits/stdc++.h>usingnamespacestd;classnumber{intfz,fm;friendnumberoperator+(number&n1,number&n2);public:number(inta=0,intb=1){fz=a;fm=b;}friendintgcd(inta,intb);friendintmin_gb(number&n1......
  • 每日编程一小时(第五天)
    一.问题描述输入一个整数,输出每个数字对应的拼音。当整数为负数时,先输出fu字二.设计思路1.创建一个字符数组2.输入一个字符串(数)3.利用switch来输出每一个字符所对应的读音三.流程图  四.代码实现#include<iostream>usingnamespacestd;intmain(){chara[10......