1、NETFILTER
数据包进入linux内核的网络层时,其总入口为kernel/linux/net/ipv4/ip_input.c的函数ip_rcv(),在对数据包进行正确性检查和校验之后,路由判断之前,会进入到一个netfilter的钩子NF_INET_PRE_ROUTING,数据包在这个钩子里进行一些处理,处理完之后,如果是接收包,则调用该钩子的ok函数,即下一步的处理函数。对于iptables来说,这里是PREROUTING规则链,能在这里设置iptables规则的只有mangle表和nat表,mangle表主要是对数据包打标记等操作。而nat表主要对数据包进行重定向,丢弃或接收数据包。
注意mangle表比nat表优先级高,所以在内核中会先处理mangle表的规则,然后再处理nat表的规则。
当路由判定后决定数据包是发往本地即Linux系统本身的,则其入口为kernel/linux/net/ipv4/ip_input.c的函数ip_local_deliver(),在这个函数最后会调用INPUT链的钩子函数NF_INET_LOCAL_IN,在这个钩子中可以设置mangle表和filter表的规则,mangle表比filter表优先级要高,filter表的主要作用是过滤数据包。
而当路由判定后数据包是发往其他主机的,则进入到kernel/linux/net/ipv4/ip_forward.c的函数ip_forward(),在函数最后同样要执行NF_INET_FORWARD这个钩子函数,在FORWARD链里,同样只能设置mangle表和filter表的规则,mangle表的优先级比filter表高。
数据包由本地发出的时候,执行到kernel/linux/net/ipv4/ip_output.c的函数__ip_local_out(),在这里会执行钩子函数NF_INET_LOCAL_OUT,在OUTPUT链里可以有mangle表、nat表、filter表的规则,优先级分别为mangle表到nat表再到filter表。
数据包在离开本机之前会调用到kernel/linux/net/ipv4/ip_output.c的函数ip_output(),这里执行的是NF_INET_POST_ROUTING钩子函数,在这个钩子里只能有mangle和nat表,而mangle表比nat表优先级高。
其中,在NF_INET_PRE_ROUTING处进行DNAT,在NF_INET_POST_ROUTING处进行SNAT。
2、CODE
-
#include <linux/module.h>
-
#include <linux/kernel.h>
-
#include <linux/init.h>
-
-
#include <linux/netfilter.h>
-
#include <linux/types.h>
-
#include <linux/version.h>
-
#include <linux/skbuff.h>
-
#include <linux/ip.h>
-
#include <linux/netfilter.h>
-
#include <linux/netfilter_ipv4/ip_tables.h>
-
#include <linux/netdevice.h>
-
#include <linux/if_ether.h>
-
#include <linux/if_packet.h>
-
#include <linux/inet.h>
-
#include <linux/string.h>
-
#include <net/tcp.h>
-
#include <net/udp.h>
-
#include <net/icmp.h>
-
#include <linux/netfilter_ipv4.h>
-
-
-
MODULE_LICENSE("GPL");
-
MODULE_AUTHOR("who");
-
-
#define IP_HDR_LEN 20
-
#define UDP_HDR_LEN 8
-
#define TOT_HDR_LEN 28
-
#define ADDRLEN 16
-
#define CHECKSUM_NONE 0
-
static char dstIP[ADDRLEN] = {0};//接受由用户态传递过来的目标IP地址
-
-
static struct nf_hook_ops send_ops;
-
static struct nf_hook_ops rcv_ops;
-
-
struct rtphdr
-
{
-
__u8 cc:4;
-
__u8 x:1;
-
__u8 p:1;
-
__u8 v:2;
-
__u8 pt:7;
-
__u8 m:1;
-
-
__u16 seq;
-
__u16 ts;
-
__u32 ssrc;
-
__u32 csrc[1];
-
};
-
-
//tcp checksum计算
-
void tcp_checksum(struct iphdr *pIph, unsigned short *ipPayload) {
-
unsigned long sum = 0;
-
unsigned short tcpLen = ntohs(pIph->tot_len) - IP_HDR_LEN;
-
struct tcphdr *tcphdrp = (struct tcphdr*)(ipPayload);
-
-
sum += (pIph->saddr>>16)&0xFFFF;
-
sum += (pIph->saddr)&0xFFFF;
-
-
sum += (pIph->daddr>>16)&0xFFFF;
-
sum += (pIph->daddr)&0xFFFF;
-
-
sum += htons(IPPROTO_TCP);
-
-
sum += htons(tcpLen);
-
-
tcphdrp->check = 0;
-
while (tcpLen > 1) {
-
sum += * ipPayload++;
-
tcpLen -= 2;
-
}
-
-
if(tcpLen > 0) {
-
sum += ((*ipPayload)&htons(0xFF00));
-
}
-
-
while (sum>>16) {
-
sum = (sum & 0xffff) + (sum >> 16);
-
}
-
sum = ~sum;
-
tcphdrp->check = (unsigned short)sum;
-
}
-
-
//udp checksum计算
-
void udp_checksum(struct iphdr *pIph, unsigned short *ipPayload) {
-
register unsigned long sum = 0;
-
struct udphdr *udphdrp = (struct udphdr*)(ipPayload);
-
unsigned short udpLen = htons(udphdrp->len);
-
-
sum += (pIph->saddr>>16)&0xFFFF;
-
sum += (pIph->saddr)&0xFFFF;
-
-
sum += (pIph->daddr>>16)&0xFFFF;
-
sum += (pIph->daddr)&0xFFFF;
-
-
sum += htons(IPPROTO_UDP);
-
-
sum += udphdrp->len;
-
-
udphdrp->check = 0;
-
while (udpLen > 1) {
-
sum += * ipPayload++;
-
udpLen -= 2;
-
}
-
-
if(udpLen > 0) {
-
sum += ((*ipPayload)&htons(0xFF00));
-
}
-
-
while (sum>>16) {
-
sum = (sum & 0xffff) + (sum >> 16);
-
}
-
-
sum = ~sum;
-
udphdrp->check = ((unsigned short)sum == 0x0000)?0xFFFF:(unsigned short)sum;
-
}
-
-
//发送加密函数
-
static unsigned int send(unsigned int hooknum, struct sk_buff * skb,
-
const struct net_device * in, const struct net_device * out,
-
int (*okfn)(struct sk_buff *))
-
{
-
struct iphdr* iph;
-
struct udphdr* udph;
-
struct tcphdr* tcph;
-
unsigned char *data = NULL;
-
unsigned short *ippay = NULL;
-
int datalen;
-
int mylen;
-
int ret = 0;
-
-
__u16 dst_port,src_port;
-
__be32 myip;
-
-
if(skb)
-
{
-
iph = (struct iphdr *)skb_header_pointer(skb,0,0,NULL);
-
if(iph)
-
{
-
if(strcmp(dstIP,"")!=0&&strcmp(dstIP,"0.0.0.0")!=0)
-
{
-
myip = in_aton(dstIP);
-
if(iph->daddr == myip)//判断截取到的报文的目的IP地址是否为需要进行加密的IP地址
-
{
-
ippay = (unsigned short *)skb_header_pointer(skb,IP_HDR_LEN,0,NULL);
-
if(iph->protocol == IPPROTO_UDP)//判断报文类型
-
{
-
udph = (struct udphdr *)skb_header_pointer(skb,IP_HDR_LEN,0,NULL);
-
data = (unsigned char *)skb_header_pointer(skb,TOT_HDR_LEN,0,NULL);//提取UDP报文中的载荷部分
-
datalen = ntohs(iph->tot_len)-TOT_HDR_LEN;//data部分的长度
-
-
//以下为对UDP报文中data进行加密
-
int a;
-
for(a=0; a<datalen; a++)
-
{
-
data[a] += 1;
-
}
-
-
//以下重新计算报文的checksum
-
iph->check = 0;
-
ip_send_check(iph);
-
-
udp_checksum(iph,ippay);
-
}
-
}
-
else if(iph->protocol == IPPROTO_TCP)
-
{
-
tcph = (struct tcphdr *)skb_header_pointer(skb,IP_HDR_LEN,0,NULL);
-
int offlen = IP_HDR_LEN + tcph->doff*4;
-
data = (char *)skb_header_pointer(skb,offlen,0,NULL);//提取TCP报文中的载荷
-
datalen = ntohs (iph->tot_len)-offlen;//data部分的长度
-
-
//以下为对TCP报文中data进行加密
-
int j;
-
for(j=0; j<datalen; j++)
-
{
-
data[j] += 1;
-
}
-
-
//以下重新计算报文的checksum
-
iph->check = 0;
-
ip_send_check(iph);
-
-
tcp_checksum(iph,ippay);
-
}
-
}
-
}
-
}
-
}
-
return NF_ACCEPT;
-
}
-
-
//接收解密函数
-
static unsigned int rcv(unsigned int hooknum, struct sk_buff * skb,
-
const struct net_device * in, const struct net_device * out,
-
int (*okfn)(struct sk_buff *))
-
{
-
struct iphdr* iph;
-
struct udphdr* udph;
-
struct tcphdr* tcph;
-
unsigned char *data = NULL;
-
unsigned short *ippay = NULL;
-
int datalen;
-
struct rtphdr * rtph;
-
int ret = 0;
-
-
__u16 dst_port,src_port;
-
__be32 myip;
-
-
if(skb)
-
{
-
iph = (struct iphdr *)skb_header_pointer(skb,0,0,NULL);
-
if(iph)
-
{
-
if(strcmp(dstIP,"")!=0&&strcmp(dstIP,"0.0.0.0")!=0)
-
{
-
myip = in_aton(dstIP);
-
if(iph->saddr == myip)//判断截取到的报文的源IP地址是否为需要进行解密的IP地址(即从用户态传入的其他安全网关的IP地址)
-
{
-
ippay = (unsigned short *)skb_header_pointer(skb,IP_HDR_LEN,0,NULL);
-
if(iph->protocol == IPPROTO_UDP)//判断报文类型
-
{
-
udph = (struct udphdr *)skb_header_pointer(skb,IP_HDR_LEN,0,NULL);
-
data = (char *)skb_header_pointer(skb,TOT_HDR_LEN,0,NULL);//提取UDP报文中的载荷部分
-
datalen = ntohs(iph->tot_len)-TOT_HDR_LEN;//data部分的长度
-
-
//以下为对UDP报文中data进行解密
-
int a;
-
for(a=0; a<datalen; a++)
-
{
-
data[a] -= 1;
-
}
-
-
//以下重新计算报文的checksum
-
iph->check = 0;
-
ip_send_check(iph);
-
-
udp_checksum(iph,ippay);
-
}
-
}
-
else if(iph->protocol == IPPROTO_TCP)//判断报文类型
-
{
-
tcph = (struct tcphdr *)skb_header_pointer(skb,IP_HDR_LEN,0,NULL);
-
int offlen = IP_HDR_LEN + tcph->doff*4;
-
data = (char *)skb_header_pointer(skb,offlen,0,NULL);//提取tcp报文中的载荷
-
datalen = ntohs (iph->tot_len)-offlen;//tcp报文中的载荷长度
-
-
//以下为对TCP有效载荷进行解密
-
int j;
-
for(j=0; j<datalen; j++)
-
{
-
data[j] -= 1;
-
}
-
-
//以下重新计算报文的checksum
-
iph->check = 0;
-
ip_send_check(iph);
-
-
tcp_checksum(iph,ippay);
-
}
-
}
-
}
-
}
-
}
-
return NF_ACCEPT;
-
}
-
-
static int __init init(void)
-
{
-
-
send_ops.hook = send;
-
send_ops.hooknum = NF_INET_POST_ROUTING;
-
send_ops.pf = PF_INET;
-
send_ops.priority = NF_IP_PRI_LAST;
-
-
rcv_ops.hook = rcv;
-
rcv_ops.hooknum = NF_INET_PRE_ROUTING;
-
rcv_ops.pf = PF_INET;
-
rcv_ops.priority = NF_IP_PRI_LAST;
-
-
nf_register_hook(&send_ops);
-
nf_register_hook(&rcv_ops);
-
}
-
-
static void __exit fini(void)
-
{
-
nf_unregister_hook(&send_ops);
-
nf_unregister_hook(&rcv_ops);
-
printk("%s\n", "remove modify skb module.");
-
}
-
-
module_init(init);
-
module_exit(fini);
阅读(1555) | 评论(0) | 转发(0) |