Linux Kernel-netfilter-based kernel-level packet filtering Firewall implementation

Source: Internet
Author: User
Tags knowledge base

Test kernel version: Linux kernel 2.6.35 ---- Linux kernel 3.2.1

Original works, reprint please mark http://blog.csdn.net/yming0221/article/details/7572382

For more information, see column http://blog.csdn.net/column/details/linux-kernel-net.html

Author: Yan Ming

Knowledge Base: this firewall is developed based on a good concept of the Linux kernel network stack. My analysis of the network stack is based on the earlier version (Linux 1.2.13 ), after clarifying the network stack architecture, we will analyze the implementation principles of the netfilter firewall in the kernel of the advanced version, program modules or kernels, and develop a packet-based personal firewall.

Packet Filtering Firewall: A packet filtering Firewall uses a software to view the packet header that flows through, thus determining the fate of the entire package. It may decide to drop the package, accept the (accept) package (let this package pass), or perform other more complex actions. Working at the network layer, the IP datagram can be checked first. For example, IP Source Address, Destination Address, source port, and destination port.

The packet filtering function of this firewall is as follows:

* Deny all connections from a host or network segment.
* Allow all connections from a host or network segment.
* Reject a connection from a host or a specified port of a network segment.
* Allows connections from a host or a specified port of a network segment.
* Refuse to send all connections to a host or CIDR block.
* Allow all connections to a host or CIDR block.
* Refuse to send a connection to a host or a specified port of a network segment.
* Allows sending a connection to a host or a specified port of a network segment.

The netfilter framework is a Linux kernel framework for analyzing and filtering specific protocol data packets. It provides a convenient way for other modules to dynamically participate in packet processing at the network layer.

The overall structure of the firewall is as follows:

The simple function of this firewall is to check whether the data packet meets the filtering conditions. If the data packet does not meet the filtering conditions, drop the data packet; otherwise, accept the data packet (accept). Eight linked list header nodes are defined here.

Struct ip_node ip_allowed_in_node_head;/* allowed remote host or network IP address header node */struct ip_node deny;/* Rejected remote host or network IP address header node */struct ip_node ip_allowed_out_node_head; /* allowed local host or network IP address header node */struct ip_node ip_denied_out_node_head;/* Rejected local host or network IP address header node */struct port_node port_allowed_in_node_head; /* allowed remote host or network transport layer port number header node */struct port_node port_denied_in_node_head;/* Rejected remote host or network transport layer port number header node */struct port_node port_allowed_out_node_head; /* allowed local host or network transport layer port number header node */struct port_node port_denied_out_node_head;/* Rejected local host or network transport layer port number header node */

Saves the address or port information in the configuration file.

Define two hook functions, hook_func_in and hook_func_out, and mount them to the inet protocol family entry nf_inet_local_in and exit nf_inet_local_out:

static struct nf_hook_ops my_netfilter[] ={{.hook=hook_func_in,.owner=THIS_MODULE,.pf=PF_INET,.hooknum=NF_INET_LOCAL_IN,.priority=100},{.hook=hook_func_out,.owner=THIS_MODULE,.pf=PF_INET,.hooknum=NF_INET_LOCAL_OUT,.priority=100}};

Describe some of the macros and referenced header files you have defined:

# Ifndef Module # define Module # endif # ifndef _ KERNEL __# DEFINE _ KERNEL __# endif // # define net_down # define my_firewall_debug # include <ASM/system. h> # include <Linux/module. h> # include <Linux/types. h> # include <Linux/kernel. h> # include <Linux/string. h> # include <Linux/net. h> # include <Linux/socket. h> # include <Linux/sockios. h> # include <Linux/in. h> # include <Linux/inet. h> # include <net/IP. h> # include <net/protocol. h> # include <Linux/skbuff. h> # include <net/sock. h> # include <net/ICMP. h> # include <net/raw. h> # include <net/checksum. h> # include <Linux/netfilter_00004.h> # include <Linux/TCP. h> # include <Linux/UDP. h> # include <Linux/IGMP. h> # include <Linux/Fs. h> # include <Linux/mm. h> # include <ASM/uaccess. h> # define Yes 1 # define no 0 # define ip_max_len 20 # define port_max_len 20 # define limit 0 # define limit 1 # define allowed_ip_out 2 # define limit 3 # define allowed_port_in 0 # define lifecycle 1 # define allowed_port_out 2 # define denied_port_out 3 # define layout "/etc/my_firewall/ip_allowed_in" # define layout "/etc/my_firewall/layout" # define Layout /port_allowed_in "# define layout"/etc/my_firewall/port_denied_in "# define layout"/etc/my_firewall/ip_allowed_out "# define layout"/etc/my_firewall/layout "# define layout" /etc/my_firewall/port_allowed_out "# define denied_out_port_conf_file_dir"/etc/my_firewall/port_denied_out "// define for work_mode/* not working, default */# define mode_free 0/* allow all connections from a host or network segment */# define mode_ip_only_allowed_in 1/* deny all connections from a host or network segment */# define mode_ip_only_denied_in 2/* allow connections from a host or a specified port in a network segment */# define mode_ip_port_allowed_in 3/* reject connections from a host or a specified port in a network segment */# define mode_ip_port_denied_in 4/* allow all connections between the local host or local network and other hosts or networks */# define mode_ip_only_allowed_out 5/* reject all connections between the local host or local network and other hosts or networks */# define mode_ip_only_denied_out 6/* allow the local host or network to connect to the specified port of another host or other Network */# define mode_ip_port_allowed_out 7/* reject the connection between the local host or network or a connection to the specified port of another Network */# define mode_ip_port_denied_out 8

The initialization function of the firewall module is as follows:

int init_firewall(){(&ip_allowed_in_node_head)->next = NULL;(&ip_denied_in_node_head)->next = NULL;(&port_allowed_in_node_head)->next = NULL;(&port_denied_in_node_head)->next = NULL;(&ip_allowed_out_node_head)->next = NULL;(&ip_denied_out_node_head)->next = NULL;(&port_allowed_out_node_head)->next = NULL;(&port_denied_out_node_head)->next = NULL;switch(work_mode){case MODE_IP_ONLY_ALLOWED_IN:open_ip_cfg_file(ALLOWED_IN_IP_CONF_FILE_DIR,ALLOWED_IP_IN);break;case MODE_IP_ONLY_DENIED_IN:open_ip_cfg_file(DENIED_IN_IP_CONF_FILE_DIR,DENIED_IP_IN);break;case MODE_IP_PORT_ALLOWED_IN:open_port_cfg_file(ALLOWED_IN_PORT_CONF_FILE_DIR,ALLOWED_PORT_IN);open_ip_cfg_file(ALLOWED_IN_IP_CONF_FILE_DIR,ALLOWED_IP_IN);break;case MODE_IP_PORT_DENIED_IN:open_port_cfg_file(DENIED_IN_PORT_CONF_FILE_DIR,DENIED_PORT_IN);open_ip_cfg_file(ALLOWED_IN_IP_CONF_FILE_DIR,ALLOWED_IP_IN);break;case MODE_IP_ONLY_ALLOWED_OUT:open_ip_cfg_file(ALLOWED_OUT_IP_CONF_FILE_DIR,ALLOWED_IP_OUT);break;case MODE_IP_ONLY_DENIED_OUT:open_ip_cfg_file(DENIED_OUT_IP_CONF_FILE_DIR,DENIED_IP_OUT);break;case MODE_IP_PORT_ALLOWED_OUT:open_port_cfg_file(ALLOWED_OUT_PORT_CONF_FILE_DIR,ALLOWED_PORT_OUT);open_ip_cfg_file(ALLOWED_OUT_IP_CONF_FILE_DIR,ALLOWED_IP_OUT);break;case MODE_IP_PORT_DENIED_OUT:open_port_cfg_file(DENIED_OUT_PORT_CONF_FILE_DIR,DENIED_PORT_OUT);open_ip_cfg_file(ALLOWED_OUT_IP_CONF_FILE_DIR,ALLOWED_IP_OUT);break;default:break;}//open_port_cfg_file(DENIED_PORT_CONF_FILE,DENIED_PORT);nf_register_hook(&my_netfilter[0]);nf_register_hook(&my_netfilter[1]);printk("INIT my firewall OK!\n");return 0;}

First read the configuration file from the file, load it to the kernel, and then register the hook operation structure my_netfilter [0], my_netfilter [1]

Is the structure of Netfilter IPv4

The Mount locations of the above two functions are nf_inet_local_in and nf_inet_local_out, which process packets sent from and sent to the local machine respectively.

The following is the hook function mounted to these two mount points for packet inspection.

static unsigned int hook_func_in(unsigned int hook,struct sk_buff *skb,const struct net_device *in,const struct net_device *out,int (*okfn)(struct sk_buff *)){#ifdef NET_DOWNreturn NF_DROP;#elsestruct iphdr *iph = ip_hdr(skb);__be32 saddr = ntohl(iph->saddr);__be16 sport = 0,dport = 0;if(trans_port(iph,skb,&sport,&dport) == NO && \work_mode == MODE_IP_PORT_ALLOWED_IN || \work_mode == MODE_IP_PORT_DENIED_IN)return NF_ACCEPT;#ifdef MY_FIREWALL_DEBUG__be32 daddr = ntohl(iph->daddr);printk("saddr= %u : %u  daddr= %u : %d\n",saddr,sport,daddr,dport);#endifswitch(work_mode){case MODE_FREE:return NF_ACCEPT;case MODE_IP_ONLY_ALLOWED_IN:if(ip_in_cfg_file(saddr,&ip_allowed_in_node_head))return NF_ACCEPT;else return NF_DROP;break;case MODE_IP_ONLY_DENIED_IN:if(ip_in_cfg_file(saddr,&ip_denied_in_node_head))return NF_DROP;else return NF_ACCEPT;break;case MODE_IP_PORT_ALLOWED_IN:if(ip_in_cfg_file(saddr,&ip_allowed_in_node_head) && \port_in_cfg_file(sport,&port_allowed_in_node_head))return NF_ACCEPT;else return NF_DROP;break;case MODE_IP_PORT_DENIED_IN:if(ip_in_cfg_file(saddr,&ip_allowed_in_node_head) && \!port_in_cfg_file(sport,&port_denied_in_node_head))return NF_ACCEPT;else return NF_DROP;break;default:return NF_DROP;break;}#endif}static unsigned int hook_func_out(unsigned int hook,struct sk_buff *skb,const struct net_device *in,const struct net_device *out,int (*okfn)(struct sk_buff *)){#ifdef NET_DOWNreturn NF_DROP;#elsestruct iphdr *iph = ip_hdr(skb);__be32 daddr = ntohl(iph->daddr);__be16 sport = 0,dport = 0;if(trans_port(iph,skb,&sport,&dport) == NO && \work_mode == MODE_IP_PORT_ALLOWED_OUT && \work_mode == MODE_IP_PORT_DENIED_OUT)return NF_ACCEPT;#ifdef MY_FIREWALL_DEBUG__be32 saddr = ntohl(iph->saddr);printk("saddr= %u : %u  daddr= %u : %d\n",saddr,sport,daddr,dport);#endifswitch(work_mode){case MODE_FREE:return NF_ACCEPT;case MODE_IP_ONLY_ALLOWED_OUT:if(ip_in_cfg_file(daddr,&ip_allowed_out_node_head))return NF_ACCEPT;else return NF_DROP;break;case MODE_IP_ONLY_DENIED_OUT:if(ip_in_cfg_file(daddr,&ip_denied_out_node_head))return NF_DROP;else return NF_ACCEPT;break;case MODE_IP_PORT_ALLOWED_OUT:if(ip_in_cfg_file(daddr,&ip_allowed_out_node_head) && \port_in_cfg_file(dport,&port_allowed_out_node_head))return NF_ACCEPT;else return NF_DROP;break;case MODE_IP_PORT_DENIED_OUT:if(ip_in_cfg_file(daddr,&ip_allowed_out_node_head) && \!port_in_cfg_file(dport,&port_denied_out_node_head))return NF_ACCEPT;else return NF_DROP;break;default:return NF_DROP;break;}#endif}

The following is a function for opening a file and reading information. Here we use the configuration file for opening an IP address as an example.

static int open_ip_cfg_file(char * file_dir,int flag){struct file * filp = NULL;char str[IP_MAX_LEN];int i = 0;if((filp = filp_open(file_dir,O_RDONLY,0)) < 0) return NO;mm_segment_t fs;fs = get_fs();set_fs(KERNEL_DS);struct ip_node * work = NULL;while((filp->f_op->read(filp,&str[i],1,&filp->f_pos)) == 1){if(str[i] == '\n')//next line{str[i] = '\0';//the end of a stringi = 0;#ifdef MY_FIREWALL_DEBUGprintk("%s\n",str);#endifwork = (struct ip_node *)kmalloc(sizeof(ip_allowed_in_node_head),GFP_ATOMIC);if( ip_to_unsigned(str,&(work->ip_start),&(work->ip_end)) == 0 )return NO;switch(flag){case ALLOWED_IP_IN:work->next = (&ip_allowed_in_node_head)->next;(&ip_allowed_in_node_head)->next = work;//head insertbreak;case DENIED_IP_IN:work->next = (&ip_denied_in_node_head)->next;(&ip_denied_in_node_head)->next = work;//head insertbreak;case ALLOWED_IP_OUT:work->next = (&ip_allowed_out_node_head)->next;(&ip_allowed_out_node_head)->next = work;//head insertbreak;case DENIED_IP_OUT:work->next = (&ip_denied_out_node_head)->next;(&ip_denied_out_node_head)->next = work;//head insertbreak;default:break;}filp->f_op->read(filp,&str[0],1,&filp->f_pos);//eat the '\r'}if(i > IP_MAX_LEN) return NO;i++;}return YES;}

The configuration file not only supports specific IP addresses, but also supports IP address CIDR blocks, such

192.168.1.1

192.168.1 .*

192. 168 .*.*

192 .*.*.*

The following are the processing functions.

/************************************************str:The IP Address like 192.168.1.1start:The pointer to the start IPend:The pointer to the end IP***********************************************/static int ip_to_unsigned(const char * str,unsigned int * start,unsigned int * end){char cache[4][4];/*split the IP address*/int i;int k = 0;int j = 0;for(i = 0;str[i] != '\0';i++){cache[j][k] = str[i];if(str[i] == '.'){cache[j][k] = '\0';k = 0;j++;}else k++;if(j > 3) return NO;}cache[3][k] = '\0';short int a[4];for(i = 0;i < 4;i++){if(cache[i][0] != '*'){a[i] = (short)simple_strtol(cache[i],NULL,0);if(a[i] < 0 || a[i] > 255) return NO;}else{break;}}switch(i){case 4:/*Specific IP Address eg.  192.168.1.1   */*start = *end = (a[0]<<24) + (a[1]<<16) + (a[2]<<8 )+a[3];break;case 3:/*  eg. 192.168.1.*   */*start = (a[0]<<24) + (a[1]<<16) + (a[2]<<8);*end = *start + (1<<8) - 1;break;case 2:/*  eg. 192.168.*.*   */*start = (a[0]<<24) + (a[1]<<16);*end = *start + (1<<16) - 1;break;case 1:/*  eg. 192.*.*.*    */*start = (a[0]<<24);*end = *start + (1<<24) - 1;break;default:*start = 0;*end = (1<<32) - 1;break;}return YES;}

Module Removal Function

void remove_firewall(){free_ip_list(&ip_allowed_in_node_head);free_ip_list(&ip_denied_in_node_head);free_ip_list(&ip_allowed_out_node_head);free_ip_list(&ip_denied_out_node_head);free_port_list(&port_allowed_in_node_head);free_port_list(&port_denied_in_node_head);free_port_list(&port_allowed_out_node_head);free_port_list(&port_denied_out_node_head);nf_unregister_hook(&my_netfilter[0]);nf_unregister_hook(&my_netfilter[1]);printk("CLEAN up my firewall OK!\n");}

MODULE_LICENSE("Dual BSD/GPL");MODULE_AUTHOR("yming0221@gmail.com");

This firewall supports command parameter settings. You only need to define and declare the working mode of the firewall according to the parameters.

static int work_mode = 0;//default modemodule_param(work_mode,int,S_IRUGO);

Currently, the firewall works normally.

We can see that the data packets can reach the network layer. However, due to the corresponding inspection rules enabled by the firewall, application-layer software such as the browser cannot be connected to the Internet, and the data packets are discarded.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.