用netfilter_queue在用户态实现NAT

合集下载

netfilter queue例子

netfilter queue例子

一、概述netfilter是Linux内核提供的一个功能强大的网络数据包过滤框架,它可以让用户对网络数据包进行分析和过滤。

netfilter queue是netfilter框架中的一个重要组件,可以让用户将数据包放入队列中,进行进一步处理。

本文将通过介绍netfilter queue的基本概念、工作原理和实际例子,帮助读者更好地理解和应用netfilter queue。

二、netfilter queue的基本概念netfilter queue是一个允许用户空间程序对数据包进行处理的接口。

当数据包经过netfilter时,可以选择将数据包放入netfilter queue中,然后用户空间程序可以从队列中取出数据包进行处理。

这种机制使得用户可以编写自定义的程序来处理数据包,实现更加灵活和个性化的数据包过滤和处理。

三、netfilter queue的工作原理1. 数据包经过netfilter当数据包经过netfilter时,netfilter会根据预先定义的规则对数据包进行处理,包括检查、修改以及丢弃等操作。

2. 数据包放入netfilter queue如果数据包符合某些条件,用户可以选择将数据包放入netfilterqueue中,而不是直接进行后续的处理。

3. 用户空间程序处理数据包用户空间程序可以通过netlink接口来监听netfilter queue,一旦有数据包进入队列,用户空间程序即可获取数据包并进行处理,可以根据自身需求来对数据包进行分析、修改以及决定是否将数据包继续投递给网络协议栈。

四、netfilter queue的实际例子为了更好地理解netfilter queue的使用,接下来通过一个实际例子来说明。

假设我们需要在Linux系统上对传入的数据包进行监控,并统计其中包含特定关键词的数据包数量,可以通过netfilter queue来实现此需求。

1. 编写用户空间程序我们需要编写一个用户空间程序,用来监听netfilter queue,并对接收到的数据包进行分析。

netfilter 连接追踪 原理

netfilter 连接追踪 原理

netfilter 连接追踪原理Netfilter是Linux内核的一个关键组件,主要用于网络数据包的过滤与处理。

它可以在内核层面对数据包进行处理,从而提供网络安全,网络流量控制,网络地址转换等多种服务。

其中netfilter连接跟踪是一个极为重要的组件,本文将深入探讨其原理。

一、什么是netfilter连接跟踪Netfilter连接跟踪是netfilter的一个模块,主要目的是在内核层面跟踪网络连接,记录连接状态,保存连接信息。

当网络数据包通过网卡接口进入内核时,netfilter连接跟踪模块会首先检查数据包,然后将其与已存在的连接进行匹配,最终决策是否要转发或丢弃数据包。

Netfilter连接跟踪模块是实现状态ful firewall的关键组件,与stateless firewall相比,它可以更为精确地识别数据包的状态,实现更为复杂的防火墙策略与NAT 转换等。

二、netfilter连接跟踪的原理1. 连接跟踪状态表netfilter连接跟踪通过状态表记录已有的连接信息。

状态表是一个内存结构,保存了所有已建立的连接信息,其中包括源地址,目标地址,源端口,目标端口等元数据信息。

当一个新的数据包到达时,它必须与状态表中的连接信息进行匹配,从而确定它是否属于已经存在的连接。

状态表是由多个hash桶组成的,每个桶都维护了一个连接列表。

在新接收到一个数据包时,netfilter连接跟踪首先使用四元组(源IP,源端口,目标IP,目标端口)查询状态表中已有的连接,并将数据包分配给匹配到的连接。

2. 数据包流转当一个数据包通过网卡接口进入内核时,内核会先将其送到协议栈的网络层。

在网络层中,数据包会进行路由选择并将目标地址与本地地址进行比较,从而决定是否将数据包直接传递到目标主机内。

在进行路由选择时,可能会进行NAT转换。

如果数据包的目标地址不是本地地址,那么它将被发送到下一跳路由器。

在这个过程中,数据包可能会通过多个路由器进行传递,每个路由器会再次检查数据包的目标地址并进行路由选择。

linux nat实现方式

linux nat实现方式

linux nat实现方式在Linux系统中,Network Address Translation(网络地址转换)是一种常用的网络技术,它允许将内部网络中的私有IP地址与外部网络中的公有IP地址进行映射。

通过NAT,内部网络中的主机可以与外部网络进行通信,而外部网络无法直接访问内部网络中的主机。

实现NAT的方式有多种,其中一种常见的方式是使用iptables命令。

iptables是Linux系统中的一个工具集,用于配置Linux内核的网络层防火墙规则。

要实现NAT,首先需要配置iptables的转发规则。

可以通过以下命令来配置转发规则:```iptables -t nat -A POSTROUTING -o 外部网络接口 -j MASQUERADE```其中,外部网络接口指的是连接到外部网络的网络接口,例如eth0。

这条规则的作用是将从内部网络发出的数据包的源IP地址替换为外部网络接口的IP地址,从而实现地址转换。

除了配置转发规则,还需要配置iptables的过滤规则,以允许内部网络中的主机与外部网络进行通信。

可以使用以下命令来配置过滤规则:```iptables -A FORWARD -i 内部网络接口 -o 外部网络接口 -j ACCEPT iptables -A FORWARD -i 外部网络接口-o 内部网络接口-m state --state RELATED,ESTABLISHED -j ACCEPT```其中,内部网络接口指的是连接到内部网络的网络接口,例如eth1。

第一条规则的作用是允许从内部网络到外部网络的数据包通过,第二条规则的作用是允许从外部网络到内部网络的已建立或相关的数据包通过。

在配置完iptables规则后,还需要开启IP转发功能,以使Linux系统能够实现NAT。

可以通过修改/sys文件系统中的配置文件来开启IP转发功能:```echo 1 > /proc/sys/net/ipv4/ip_forward```这样,就完成了Linux系统中NAT的实现。

Linux命令高级技巧使用iptables进行端口转发和NAT

Linux命令高级技巧使用iptables进行端口转发和NAT

Linux命令高级技巧使用iptables进行端口转发和NAT在Linux系统中,iptables是一个非常强大的工具,用于配置和管理网络包过滤规则。

除了基本的网络包过滤功能,iptables还可以用于端口转发和网络地址转换(NAT)。

本文将介绍如何使用iptables进行端口转发和NAT,以及一些高级技巧。

1. 端口转发端口转发是一种将网络流量从一个端口转发到另一个端口的技术。

它在网络中广泛应用于代理服务器、端口映射、负载均衡等场景。

下面是使用iptables进行端口转发的示例命令:```iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 192.168.0.100:80```在上述命令中,`-t nat`表示我们要操作的是`nat`表,`-A PREROUTING`表示将规则添加到`PREROUTING`链中,`-p tcp --dport 8080`表示匹配TCP协议和目标端口号8080,`-j DNAT`表示采取目标网络地址转换,`--to-destination 192.168.0.100:80`表示将数据包转发到目标IP地址192.168.0.100的80端口。

2. 网络地址转换(NAT)网络地址转换(NAT)是一种将私有网络中的IP地址转换为公共网络中的IP地址的技术。

它广泛应用于家庭网络和企业网络中,允许多台设备共享一个公共IP地址。

下面是使用iptables进行NAT的示例命令:```iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -o eth0 -j MASQUERADE```在上述命令中,`-t nat`表示我们要操作的是`nat`表,`-A POSTROUTING`表示将规则添加到`POSTROUTING`链中,`-s192.168.0.0/24`表示源IP地址为192.168.0.0/24的网络,`-o eth0`表示出去的网络接口为eth0,`-j MASQUERADE`表示使用动态地址转换。

防火墙软件Netfilter之NAT技术

防火墙软件Netfilter之NAT技术

防火墙软件Netfilter之NAT技术ZDNet 网络频道频道更新时间:2008-06-10 作者:来源:路由器技术资讯网本文关键词:NAT网络地址转换什么是nat本文档主要描述怎样进行IP伪装(masquerading)、透明代理(transparent proxying)、端口转发(port forwarding)和其他形式的网络地址翻译技术。

1.什么是网络地址翻译NAT(Network Address Translation)?当一个包在网络上传输时,从它的源地址(例如你自己的主机)到达目的地址(例如),中间经过很多节点和网络。

这些节点通常不会改变你的包。

他们仅仅转发你的包。

如果一个节点执行NAT,他将会修改包的源或目的地址。

通常这个节点会记住他怎样修改了这个包,因此当相应的应答包从另一个方向到达时,他知道如何反向修改这个应答包。

2.为什么要使用NAT?l 用modem上网大多数的ISPs只给你提供一个IP地址。

你可以以任何源地址发出包,但是只有包含这个IP地址的包的应答包才会到达你的网络。

如果你想使用多台机器(比如有个自己的网络)利用这个IP地址上网。

需要NAT。

这是NAT使用得最为常见的情况,在linux的世界里称为IP伪装(masquerading)。

又称之为SNAT,因为你要改变包的源地址。

l Multiple Servers有时候你想改变到达你的网络的包的去向。

通常因为你只有一个IP地址,但是你又想用户到达这个真实IP地址之后的各个机器。

方法是修改这些包的目的地址,让他们到达不同的机器。

还有就是用于负载均衡。

这种类型的NAT在linux上叫做端口转发(port-forwarding)。

l Transparent Proxying(透明代理)透明代理是在你的网络和外部世界之间的程序,所有的进或出都要经过这个代理。

之所以叫做“透明”,因为你的网络无需考虑他的存在。

例如,squid软件能够配置为透明代理。

思科路由器如何配置NAT功能

思科路由器如何配置NAT功能

思科路由器如何配置NAT功能很多网络技术上的新手,还不知道如何配置思科路由器的NAT功能。

不过没关系,看完小编这个文章应该对你帮助会很大。

那么接下来就让小编来教你如何配置思科路由器NAT功能吧。

首先,小编必须要介绍下什么是NAT。

NAT,英文全称为Network Address Translation,是指网络IP 地址转换。

NAT的出现是为了解决IP日益短缺的问题,将多个内部地址映射为少数几个甚至一个公网地址。

这样,就可以让我们内部网中的计算机通过伪IP访问INTERNET的资源。

如我们局域网中的192.168.1.1地址段属私网地址,就是通过NAT转换过来的。

NAT分为静态地址转换、动态地址转换、复用动态地址转换。

下面是小编将列出思科路由器NAT配置实例,希望对您有所帮助。

Current configuration:!version 12.0service timestamps debug uptimeservice timestamps log uptimeno service password-encryption!hostname 2611!enable secret 5 $JIeG$UZJNjKhcptJXHPc/BP5GG0enable password 2323ipro!ip subnet-zerono ip source-routeno ip finger!!!interface Ethernet0/0ip address 192.168.10.254 255.255.255.0 secondary ip address 218.27.84.249 255.255.255.248no ip directed-broadcastip accounting output-packetsno ip mroute-cacheno cdp enable!interface Serial0/0ip unnumbered Ethernet0/0no ip directed-broadcastip accounting output-packetsip nat outsideno ip mroute-cacheno fair-queueno cdp enable!interface Ethernet0/1ip address 192.168.2.254 255.255.255.0no ip directed-broadcastip nat insideno ip mroute-cacheno cdp enable!interface Virtual-T okenRing35no ip addressno ip directed-broadcastno ip mroute-cacheshutdownring-speed 16!router ripredistribute connectednetwork 192.168.2.0network 192.168.10.0network 218.27.84.0!ip default-gateway 218.27.127.217ip nat pool nat-pool 218.27.84.252 218.27.84.254 netmask 255.255.255.248ip nat inside source list 1 pool nat-pool overloadip nat inside source static 192.168.2.254 218.27.84.249ip classlessip route 0.0.0.0 0.0.0.0 Serial0/0ip http serverip http port 9091ip ospf name-lookup!ip access-list extended filterinpermit tcp any host 218.27.84.249 eq www reflect httpfilter access-list 1 permit 192.168.2.0 0.0.0.255no cdp run!line con 0transport input noneline aux 0line vty 0 4password routrlogin!end按照步骤敲完这些代码,那么你应该就会了解到如何配置思科路由器NAT功能了。

思科交换机NAT配置介绍及实例

思科交换机NAT配置介绍及实例CISCONAT 配置一、NAT简介NAT(Network Address Translation)的功能,就是指在一个网络内部,根据需要可以随意自定义的IP地址,而不需要经过申请。

在网络内部,各计算机间通过内部的IP地址进行通讯。

而当内部的计算机要与外部internet网络进行通讯时,具有NAT功能的设备(比如:路由器)负责将其内部的IP地址转换为合法的IP地址(即经过申请的IP地址)进行通信。

二、NAT的应用环境:情况1:一个企业不想让外部网络用户知道自己的网络内部结构,可以通过NAT将内部网络与外部Internet隔离开,则外部用户根本不知道通过NAT设置的内部IP地址。

情况2:一个企业申请的合法Internet IP地址很少,而内部网络用户很多。

可以通过NAT功能实现多个用户同时公用一个合法IP与外部Internet进行通信。

三、设置NAT所需路由器的硬件配置和软件配置:设置NAT功能的路由器至少要有一个内部端口(Inside),—个外部端口(Outside)。

内部端口连接的网络用户使用的是内部IP地址。

内部端口可以为任意一个路由器端口。

外部端口连接的是外部的网络,如Internet。

外部端口可以为路由器上的任意端口。

设置NAT功能的路由器的IOS应支持NAT功能(本文事例所用路由器为C isco2501,其IOS为11.2版本以上支持NAT功能)。

四、关于NAT的几个概念:内部本地地址(Inside local address ):分配给内部网络中的计算机的内部IP地址。

内部合法地址(Inside global address):对外进入IP通信时,代表一个或多个内部本地地址的合法IP地址。

需要申请才可取得的IP地址。

五、NAT的设置方法:NAT设置可以分为静态地址转换、动态地址转换、复用动态地址转换。

1、静态地址转换适用的环境静态地址转换将内部本地地址与内部合法地址进行一对一的转换,且需要指定和哪个合法地址进行转换。

用netfilter_queue在用户态实现NAT

用netfilter_queue在用户态实现NAT偶尔在网上看到了<<用netfilter_queue 在用户态修改网络数据包的例子程序>>这篇文章,并结合libnetfilter_queue-0.0.17.tar.bz2中的例子,然后修改了一下tcp计算checksum部分,在linux2.6.24上用netfilter_queue在用户态实现NAT程序功能: 将输出端目的地为 220.181.37.55 的包,都改为目的地为 202.118.236.130,输入段反之,达到DNAT的一小半功能,完整的NAT要做状态记录的.直接上代码:nf_queue_test.c/** =====================================================================================** Filename: nf_queue_test.c** Description: 用netfilter_queue 在用户态修改网络数据包的例子程序** Version: 1.0* Created: 04/02/2010 09:49:48 AM* Revision: none* Compiler: gcc** Author: LeiuX (xulei), xulei@* Company: HIT** =====================================================================================*/#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<netdb.h>#include<string.h>#include<netinet/in.h>#include<arpa/inet.h>#include<asm/byteorder.h>#include<linux/netfilter.h>#include<libnetfilter_queue/libnetfilter_queue.h>#include<linux/ip.h>#include<linux/tcp.h>#ifdef__LITTLE_ENDIAN#define IPQUAD(addr)\((unsigned char*)&addr)[0],\((unsigned char*)&addr)[1],\((unsigned char*)&addr)[2],\((unsigned char*)&addr)[3]#else#define IPQUAD(addr)\((unsigned char*)&addr)[3],\((unsigned char*)&addr)[2],\((unsigned char*)&addr)[1],\((unsigned char*)&addr)[0]#endifstruct tcp_pseudo /*the tcp pseudo header*/{__u32 src_addr;__u32 dst_addr;__u8 zero;__u8 proto;__u16 length;}pseudohead;long checksum(unsigned short*addr,unsigned int count){/* Compute Internet Checksum for "count" bytes* beginning at location "addr".*/register long sum =0;while(count> 1 ){/* This is the inner loop */sum +=*addr++;count-=2;}/* Add left-over byte, if any */if(count>0 )sum +=*(unsigned char*)addr;/* Fold 32-bit sum to 16 bits */while(sum>>16)sum =(sum &0xffff)+(sum >>16);return~sum;}/*************************tcp checksum**********************/long get_tcp_checksum(struct iphdr *myip,struct tcphdr *mytcp){__u16 total_len =ntohs(myip->tot_len);int tcpopt_len =mytcp->doff*4 -20;int tcpdatalen =total_len -(mytcp->doff*4)-(myip->ihl*4);pseudohead.src_addr=myip->saddr;pseudohead.dst_addr=myip->daddr;pseudohead.zero=0;pseudohead.proto=IPPROTO_TCP;pseudohead.length=htons(sizeof(struct tcphdr)+tcpopt_len +tcpdatalen);int totaltcp_len =sizeof(struct tcp_pseudo)+sizeof(struct tcphdr)+tcpopt_len +tcpdatalen;//unsigned short * tcp = new unsigned short[totaltcp_len];unsigned short*tcp =malloc(totaltcp_len);memcpy((unsigned char*)tcp,&pseudohead,sizeof(struct tcp_pseudo));memcpy((unsigned char*)tcp+sizeof(struct tcp_pseudo),(unsigned char*)mytcp,sizeof(struct tcphdr));memcpy((unsigned char*)tcp+sizeof(struct tcp_pseudo)+sizeof(struct tcphdr),(unsigned char*)myip+ (myip->ihl*4)+(sizeof(struct tcphdr)),tcpopt_len);memcpy((unsigned char*)tcp+sizeof(struct tcp_pseudo)+sizeof(struct tcphdr)+tcpopt_len,(unsigned ch ar*)mytcp+(mytcp->doff*4),tcpdatalen);/* printf("pseud length: %d\n",pseudohead.length);printf("tcp hdr length: %d\n",mytcp->doff*4);printf("tcp hdr struct length: %d\n",sizeof(struct tcphdr));printf("tcp opt length: %d\n",tcpopt_len);printf("tcp total+psuedo length: %d\n",totaltcp_len);fflush(stdout);printf("tcp data len: %d, data start %u\n", tcpdatalen,mytcp + (mytcp->doff*4));*/return checksum(tcp,totaltcp_len);static u_int16_t tcp_checksum(struct iphdr*iphdrp){struct tcphdr *tcphdrp =(struct tcphdr*)((u_int8_t*)iphdrp +(iphdrp->ihl<<2));return get_tcp_checksum(iphdrp,tcphdrp);}static void set_tcp_checksum(struct iphdr*iphdrp){struct tcphdr *tcphdrp =(struct tcphdr*)((u_int8_t*)iphdrp +(iphdrp->ihl<<2));tcphdrp->check =0;tcphdrp->check =get_tcp_checksum(iphdrp,tcphdrp);}/****************************tcp checksum end****************************//********************************Ip checksum*****************************/ static u_int16_t ip_checksum(struct iphdr*iphdrp){return checksum((unsigned short*)iphdrp,iphdrp->ihl<<2);}static void set_ip_checksum(struct iphdr*iphdrp){iphdrp->check =0;iphdrp->check =checksum((unsigned short*)iphdrp,iphdrp->ihl<<2); }/****************************Ip checksum end******************************/static int cb(struct nfq_q_handle *qh,struct nfgenmsg *nfmsg, struct nfq_data *nfa,void*data){(void)nfmsg;(void)data;u_int32_t id =0;struct nfqnl_msg_packet_hdr *ph;unsigned char*pdata =NULL;int pdata_len;ph =nfq_get_msg_packet_hdr(nfa);if(ph){id =ntohl(ph->packet_id);}pdata_len =nfq_get_payload(nfa,(char**)&pdata);if(pdata_len ==-1){pdata_len =0;}struct iphdr *iphdrp =(struct iphdr *)pdata;printf("len %d iphdr %d %u.%u.%u.%u ->",pdata_len,iphdrp->ihl<<2,IPQUAD(iphdrp->saddr));printf(" %u.%u.%u.%u %s",IPQUAD(iphdrp->daddr),getprotobynumber(iphdrp->protocol)->p_name);printf(" ipsum %hu",ip_checksum(iphdrp));if(iphdrp->protocol ==IPPROTO_TCP){printf(" tcpsum %hu",tcp_checksum(iphdrp));}#define TO "220.181.37.55"#define DNAT_TO "202.118.236.130"if(iphdrp->daddr ==inet_addr(TO)){printf(" !hacked!");iphdrp->daddr =inet_addr(DNAT_TO);set_ip_checksum(iphdrp);if(iphdrp->protocol ==IPPROTO_TCP){set_tcp_checksum(iphdrp);printf(" ipsum+ %hu tcpsum+ %hu",ip_checksum(iphdrp),tcp_checksum(iphdrp));}}if(iphdrp->saddr ==inet_addr(DNAT_TO)){iphdrp->saddr =inet_addr(TO);printf(" !hacked!");set_ip_checksum(iphdrp);if(iphdrp->protocol ==IPPROTO_TCP){set_tcp_checksum(iphdrp);printf(" ipsum+ %hu tcpsum+ %hu",ip_checksum(iphdrp),tcp_checksum(iphdrp));}}printf("\n");return nfq_set_verdict_mark(qh,id,NF_REPEAT,1,(u_int32_t)pdata_len,pdata);}int main(int argc,char**argv){struct nfq_handle *h;struct nfq_q_handle *qh;struct nfnl_handle *nh;int fd;int rv;char buf[4096];h =nfq_open();if(!h){exit(1);}nfq_unbind_pf(h,AF_INET);/*2.6.24 的内核有BUG, nfq_unbind_pf 返回值不正确,见:/gmane.c ... ilter.general/33573*//*if (nfq_unbind_pf(h, AF_INET) < 0){exit(1);}*/if(nfq_bind_pf(h,AF_INET)<0){exit(1);}int qid =0;if(argc ==2){qid =atoi(argv[1]);}printf("binding this socket to queue %d\n",qid);qh =nfq_create_queue(h,qid,&cb,NULL);if(!qh){exit(1);}if(nfq_set_mode(qh,NFQNL_COPY_PACKET,0xffff)<0){load.sh#!/bin/bash#=============================================================================== ##FILE:load.sh##USAGE:./load.sh##DESCRIPTION:##OPTIONS:---#REQUIREMENTS:---#BUGS:---#NOTES:---#AUTHOR:LeiuX (),marksman.xu@#COMPANY:HIT#VERSION:1.0#CREATED:04/02/2010 09:51:36 AM CST#REVISION:---#=============================================================================== #!/bin/shTABLE=manglefunction remove_chain(){echo -n removing chain...{sudo /sbin/iptables -t ${TABLE}-D PREROUTING -j NF_QUEUE_CHAINsudo /sbin/iptables -t ${TABLE}-D OUTPUT -j NF_QUEUE_CHAINsudo /sbin/iptables -t ${TABLE}-F NF_QUEUE_CHAINsudo /sbin/iptables -t ${TABLE}-X NF_QUEUE_CHAIN}&>/dev/nullecho done}function create_chain(){echo -n creating chain...sudo /sbin/iptables -t ${TABLE}-N NF_QUEUE_CHAIN运行loader.sh就好了,如果你没有sudo,那就改改脚本自己用root运行吧要看效果,就ping 220.181.37.55,然后连 220.181.37.55 的80端口试试,并且注意程序的输出. PS: 220.181.37.55 是 baidu 的一个服务器的IP, 另外一个IP是 pact lab 的.reference:<<用netfilter_queue 在用户态修改网络数据包的例子程序>>libnetfilter_queue-0.0.17.tar.bz2tcp计算checksum<<tcp/ip详解卷一:协议>>/woods2001/article/details/8373628。

netfilter编程

netfilter编程Netfilter 是Linux 内核中的一个框架,用于实现包过滤和网络地址转换(NAT)等功能。

Netfilter 提供了一种在内核空间中拦截、修改和处理网络数据包的机制。

你可以通过使用Netfilter 提供的API 进行编程,实现自定义的网络包处理逻辑。

以下是一个简单的基于Netfilter 的例子,使用C 语言编写:1. 编写Netfilter 模块:```c#include <linux/kernel.h>#include <linux/module.h>#include <linux/netfilter.h>#include <linux/netfilter_ipv4.h>#include <linux/ip.h>static struct nf_hook_ops nfho;// Netfilter 处理函数static unsigned int my_hook_function(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) {struct iphdr *ip_header;// 获取IP 头ip_header = ip_hdr(skb);// 在此处添加你的自定义逻辑,例如修改IP 地址、丢弃包等// 打印原始IP 地址pr_info("Original Source IP: %pI4\n", &ip_header->saddr);return NF_ACCEPT; // 允许数据包通过}// 模块初始化函数static int __init my_netfilter_init(void) {pr_info("My Netfilter Module Loaded\n");// 初始化Netfilter 钩子nfho.hook = my_hook_function;nfho.pf = PF_INET;nfho.hooknum = NF_INET_PRE_ROUTING;nfho.priority = NF_IP_PRI_FIRST;nf_register_hook(&nfho);return 0;}// 模块退出函数static void __exit my_netfilter_exit(void) {pr_info("My Netfilter Module Unloaded\n");// 注销Netfilter 钩子nf_unregister_hook(&nfho);}module_init(my_netfilter_init);module_exit(my_netfilter_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Your Name");MODULE_DESCRIPTION("Netfilter Module");```在这个例子中,我们创建了一个简单的Netfilter 模块,它注册了一个钩子函数`my_hook_function`,用于处理IPv4 数据包。

netfilter与用户空间通信二法

Linux内核态与用户态进程通信方法的提出与实现。

分为用户上下文环境、硬中断和软中断环境两种情况。

3.1 用户上下文环境运行在用户上下文环境中的代码是可以阻塞的,这样,便可以使用消息队列和UNIX 域套接字来实现内核态与用户态的通信。

但这些方法的数据传输效率较低,Linux 内核提供copy_from_user()/copy_to_user() 函数来实现内核态与用户态数据的拷贝,但这两个函数会引发阻塞,所以不能用在硬、软中断中。

一般将这两个特殊拷贝函数用在类似于系统调用一类的函数中,此类函数在使用中往往"穿梭"于内核态与用户态。

3.2 硬、软中断环境比起用户上下文环境,硬中断和软中断环境与用户态进程无丝毫关系,而且运行过程不能阻塞。

在Linux 2.4 版以后版本的内核中,几乎全部的中断过程与用户态进程的通信都是使用netlink 套接字实现的,netlink 套接字的最大特点是对中断过程的支持,同时还使用netlink 实现了ip queue 工具,但ip queue 的使用有其局限性,不能自由地用于各种中断过程。

还有重要的一点:netlink 套接字是不用经过TCP/IP协议栈处理的,效率方面没的说。

赞。

说了这么多,都是别人的东西。

但是磨刀不误砍柴工,没有前面的知识铺垫,只怕你对怎么样,为什么这样用也是一知半解,这可是工程技术人员的大忌。

4 netfilter与用户空间通信二法法1:nf_sockopt_ops通信方式此法在内核模块中注册nf_register_sockopt一个 nf_sockopt_ops结构体。

比如view plaincopy to clipboardprint?.........10........20........30........40........50........60........70........80........90........100.......110.......120.......130.......140. (150)1.static struct nf_sockopt_ops nso = {2. .pf = PF_INET, // 协议族3. .set_optmin = 常数, // 定义最小set命令字4. .set_optmax = 常数+N, // 定义最大set命令字5. .set = do_nso_set, // 定义set处理函数6. .get_optmin = 常数, // 定义最小get命令字7. .get_optmax = 常数+N, // 定义最大get命令字8. .get = do_nso_get, // 定义set处理函数9.};其中命令字不能和内核已有的重复,宜大不宜小。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

/********************************Ip checksum*****************************/ static u_int16_t ip_checksum(struct iphdr* iphdrp){ return checksum((unsigned short*)iphdrp, iphdrp->ihl<<2); } static void set_ip_checksum(struct iphdr* iphdrp){ iphdrp->check = 0; iphdrp->check = checksum((unsigned short*)iphdrp, iphdrp->ihl<<2); } /****************************Ip checksum end******************************/ static int cb(struct nfq_q_handle *qh, struct struct nfq_data *nfa, void *data){ (void)nfmsg; (void)data; u_int32_t id = 0; struct nfqnl_msg_packet_hdr *ph; unsigned char *pdata = NULL; int pdata_len; ph = nfq_get_msg_packet_hdr(nfa); if (ph){ id = ntohl(ph->packet_id); } pdata_len = nfq_get_payload(nfa, if(pdata_len == -1){ pdata_len = 0; } struct iphdr *iphdrp = (struct (char**)&pdata); nfgenmsg *nfmsg,
nf_queue_test.c /* * ===================================================================================== * * Filename: nf_queue_test.c * * Description: 用 netfilter_queue 在用户态修改网络数据包的例子程序 * * Version: 1.0 * Created: 04/02/2010 09:49:48 AM * Revision: none * Compiler: gcc * * Author: LeiuX (xulei), xulei@ * Company: HIT * * ===================================================================================== */ #include #include #include #include #include #include #include #include #include #include #include #include <stdio.h> <stdlib.h> <unistd.h> <netdb.h> <string.h> <netinet/in.h> <arpa/inet.h> <asm/byteorder.h> <linux/netfilter.h> <libnetfilter_queue/libnetfilter_queue.h> <linux/ip.h> <linux/tcp.h>
用 netfilter_queue 在用户态实现 NAT
偶尔在网上看到了<<用 netfilter_queue 在用户态修改网络数据包的例子程序>>这篇文章, 并结合 libnetfilter_queue-0.0.17.tar.bz2 中的例子, 然后修改了一下 tcp 计算 checksum 部分,在 linux2.6.24 上用 netfilter_queue 在用户态实现 NAT 程序功能: 将输出端目的地为 220.181.37.55 的包,都改为目的地为 202.118.236.130,输入段反之,达到 DNAT 的一小半功能,完整的 NAT 要做状 态记录的. 直接上代码:
\ \ \
\ \ \
struct tcp_pseudo /*the tcp pseudo header*/ { __u32 src_addr; __u32 dst_addr; __u8 zero; __u8 proto; __u16 length; } pseudohead;
long checksum(unsigned short *addr, unsigned int /* Compute Internet Checksum for "count" bytes * beginning at location "addr". */ register long sum = 0; while( count > 1 ) { /* This is the inner loop */ sum += * addr++; count -= 2; } /* Add left-over byte, if any */ if( count > 0 ) sum += * (unsigned char *) /* Fold 32-bit sum to 16 bits */ while (sum>>16) sum = (sum & 0xffff) + (sum return ~sum; }
iphdr
*)pdata;
printf("len %d iphdr %d %u.%u.%u.%u ->", pdata_len, iphdrp->ihl<<2, IPQUAD(iphdrp->saddr)); printf(" %u.%u.%u.%u %s", IPQUAD(iphdrp->daddr), getprotobynumber(iphdrp->protocol)->p_name); printf(" ipsum %hu", ip_checksum(iphdrp)); if(iphdrp->protocol == IPPROTO_TCP){ printf(" tcpsum %hu", tcp_checksum(iphdrp)); } #define TO "220.181.37.55" #define DNAT_TO "202.118.236.130" if(iphdrp->daddr == inet_addr(TO)){ printf(" !hacked!");
count)
{
addr;
>>
16);
/*************************tcp checksum**********************/ long get_tcp_checksum(struct iphdr * myip, struct tcphdr __u16 total_len = int tcpopt_len int tcpdatalen = = ntohs(myip->tot_len); mytcp->doff*4 - 20; total_len - (mytcp->doff*4)
#ifdef __LITTLE_ENDIAN #define IPQUAD(addr) \ ((unsigned char *)&addr)[0], ((unsigned char *)&addr)[1], ((unsigned char *)&addr)[2], ((unsigned char *)&addr)[3] #else #define IPQUAD(addr) \ ((unsigned char *)&addr)[3], ((unsigned char *)&addr)[2], ((unsigned char *)&addr)[1], ((unsigned char *)&addr)[0] #endif
*
mytcp)
{
-
(myip->ihl*4);
pseudohead.src_addr=myip->saddr; pseudohead.dst_addr=myip->daddr; pseudohead.zero=0; pseudohead.proto=IPPROTO_TCP; pseudohead.length=htons(sizeof(struct
memcpy((unsigned char memcpy((unsigned char memcpy((unsigned char myip->ihl*4)+(sizeof(struct memcpy((unsigned char r *)mytcp+(mytcp->doff*4),
*)tcp,&pseudohead,sizeof(struct tcp_pseudo)); *)tcp+sizeof(struct tcp_pseudo),(unsigned char*)mytcp,sizeof(struct tcphdr)); *)tcp+sizeof(struct tcp_pseudo)+sizeof(struct tcphdr),(unsigned char *)myip+( tcphdr)), tcpopt_len); *)tcp+sizeof(struct tcp_pseudo)+sizeof(structtcphdr)+tcpopt_len, (unsigned cha tcpdatalen);
相关文档
最新文档