IP隧道基础研究
static char banner[] __initdata = KERN_INFO "IPv4 over IPv4 tunneling driver\n";
static struct xfrm_tunnel ipip_handler = {
.handler = ipip_rcv, //看下面接收处理函数实现
.err_handler = ipip_err,
.priority = ,
};
static int __init ipip_init(void) // net/ipv4/ipip.c
{
int err;
printk(banner); //打印信息 //注册ipip接收处理函数
if (xfrm4_tunnel_register(&ipip_handler)) {
printk(KERN_INFO "ipip init: can't register tunnel\n");
return -EAGAIN;
}
//分配一个网络设备,设备名tunl0
ipip_fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), "tunl0", ipip_tunnel_setup);
if (!ipip_fb_tunnel_dev) {
err = -ENOMEM;
goto err1;
}
ipip_fb_tunnel_dev->init = ipip_fb_tunnel_init; //初始化函数 //注册这个网络设备,会调用上面的初始化函数
if ((err = register_netdev(ipip_fb_tunnel_dev)))
goto err2;
out:
return err;
err2:
free_netdev(ipip_fb_tunnel_dev);
err1:
xfrm4_tunnel_deregister(&ipip_handler);
goto out;
}
//注册处理函数
static struct xfrm_tunnel *tunnel4_handlers;
int xfrm4_tunnel_register(struct xfrm_tunnel *handler)
{
struct xfrm_tunnel **pprev;
int ret = -EEXIST;
int priority = handler->priority; //权限 mutex_lock(&tunnel4_mutex);
for (pprev = &tunnel4_handlers; *pprev; pprev = &(*pprev)->next) {
if ((*pprev)->priority > priority) //找到位置,从小到大排列
break; if ((*pprev)->priority == priority) //重复,出错
goto err;
}
handler->next = *pprev;
*pprev = handler;
ret = ;
err:
mutex_unlock(&tunnel4_mutex);
return ret;
} ipip协议
static struct net_protocol tunnel4_protocol = { //IPIP协议处理
.handler = tunnel4_rcv,
.err_handler = tunnel4_err,
.no_policy = ,
};
ipip协议注册
static int __init tunnel4_init(void)
{
//向核心注册ipip协议
if (inet_add_protocol(&tunnel4_protocol, IPPROTO_IPIP)) {
printk(KERN_ERR "tunnel4 init: can't add protocol\n");
return -EAGAIN;
}
return ;
}
static int tunnel4_rcv(struct sk_buff *skb)
{
struct xfrm_tunnel *handler; if (!pskb_may_pull(skb, sizeof(struct iphdr)))
goto drop; //调用连表中的所有处理函数,已经安大小排过序了
for (handler = tunnel4_handlers; handler; handler = handler->next)
if (!handler->handler(skb)) //处理函数返回0,正确结束
return ;
//有一个不对就发送icmp目的和端口不可达包
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, );
drop:
kfree_skb(skb);
return ;
}
现在我们看出只要是调用了xfrm4_tunnel_register函数向ipip协议注册了处理函数那么就会被ipip协议接收函数调用,权限字段值越小越先被调用.
在ip_local_deliver_finish函数中(可以参考linux协议占函数流程一文)会根据ip协议中的协议字段调用相应的协议处理函数。 ......
int protocol = skb->nh.iph->protocol;
......
if ((ipprot = rcu_dereference(inet_protos[hash])) != NULL) {
......
ret = ipprot->handler(skb); //调用ipip协议的处理函数tunnel4_rcv
......
}
[接收处理函数实现]
每一个IP数据包均交由ip_rcv函数处理,在进行一些必要的判断后,ip_rcv对于发送给本机的数据包将交给上层处理程序。
对于IPIP包来说,其处理函数是ipip_rcv(就如TCP包的处理函数是tcp_rcv一样,IP层不加区分)。
也就是说,当一个目的地址为本机的封包到达后,ip_rcv函数进行一些基本检查并除去IP头,然后交由ipip_rcv解封。
ipip_rcv所做的工作就是去掉封包头,还原数据包,然后把还原后的数据包放入相应的接收队列netif_rx().
static int ipip_rcv(struct sk_buff *skb)
{
struct iphdr *iph;
struct ip_tunnel *tunnel;
iph = skb->nh.iph; read_lock(&ipip_lock);
//在hash表中查询
if ((tunnel = ipip_tunnel_lookup(iph->saddr, iph->daddr)) != NULL) {
if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { //检测IPSEC包策略
read_unlock(&ipip_lock);
kfree_skb(skb);
return ;
} secpath_reset(skb); //释放sec_path skb->mac.raw = skb->nh.raw;
skb->nh.raw = skb->data; //指向这个封装的ip头
skb->protocol = htons(ETH_P_IP);//协议变为IP
skb->pkt_type = PACKET_HOST; tunnel->stat.rx_packets++;
tunnel->stat.rx_bytes += skb->len;
skb->dev = tunnel->dev;//指向这个虚拟设备
dst_release(skb->dst); //释放路由缓存,需要从新查找
skb->dst = NULL;
nf_reset(skb); //释放ip_conntrack结构
ipip_ecn_decapsulate(iph, skb); //ECN解封,IPSEC相关
netif_rx(skb);//重新递交
read_unlock(&ipip_lock);
return ;
}
read_unlock(&ipip_lock);
return -; //查询不到出错
} static struct ip_tunnel *tunnels_r_l[HASH_SIZE]; //(remote,local)
static struct ip_tunnel *tunnels_r[HASH_SIZE]; //(remote,*)
static struct ip_tunnel *tunnels_l[HASH_SIZE]; //(*,local)
static struct ip_tunnel *tunnels_wc[]; //(*,*)
static struct ip_tunnel **tunnels[] = { tunnels_wc, tunnels_l, tunnels_r, tunnels_r_l };
static struct ip_tunnel * ipip_tunnel_lookup(u32 remote, u32 local)
{
//计算出hash值
unsigned h0 = HASH(remote);
unsigned h1 = HASH(local);
struct ip_tunnel *t;
//在源和目的地址都在的hash表中寻找
for (t = tunnels_r_l[h0^h1]; t; t = t->next) {
if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP))
return t;
}
//在只有目的地址hash表中寻找
for (t = tunnels_r[h0]; t; t = t->next) {
if (remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP))
return t;
}
//在只有源地址hash表中寻找
for (t = tunnels_l[h1]; t; t = t->next) {
if (local == t->parms.iph.saddr && (t->dev->flags&IFF_UP))
return t;
}
if ((t = tunnels_wc[]) != NULL && (t->dev->flags&IFF_UP))
return t;
return NULL;
}
[\接收处理函数实现]
IP隧道基础研究的更多相关文章
- TCP/IP协议基础(转)
转自 http://www.chinaunix.net 作者:Bernardus160 发表于:2003-12-03 17:33:15 TCP/IP协议基础 -------------------- ...
- 什么是 IP 隧道,Linux 怎么实现隧道通信?
本文首发于我的公众号 Linux云计算网络(id: cloud_dev),专注于干货分享,号内有 10T 书籍和视频资源,后台回复「1024」即可领取,欢迎大家关注,二维码文末可以扫. 通过之前的文章 ...
- 内网安全---隐藏通信隧道基础&&网络通信隧道之一ICMP隧道
一,隐藏通信隧道基础知识 在完成信息收集之后,我们要判断流量是否出的去.进的来.隐藏通信隧道技术常用于在受限的网络环境中追踪数据流向和在非受信任的网络中实现安全的数据传输. 1.常见的隧道: .网络层 ...
- lvs之ip-tun(ip隧道)技术的学习与实践
1.配置测试环境 修改IP windows 200.168.10.4 lvs server ip:200.168.10.1 因为IP隧道模式只需要一个网卡 所以就停掉其他网卡 web server ...
- IP地址基础知识
IP地址基础知识 网络号:用于识别主机所在的网络:主机号:用于识别该网络中的主机. 一 OSI/RM模型 应用层 表示层 会话层 传输层 网络层 数据链路层 物理层 二 TCP/IP模型 数据链路层( ...
- 关于埃博拉(Ebola)基础研究病毒
关于埃博拉(Ebola)病毒的基础研究 2005年.美国哈佛大学医学研究院(Harvard Medical School)James Cunningham教授关于埃博拉病毒有一项基础研究,研究成果发表 ...
- (转) HTTP & HTTPS网络协议重点总结(基于SSL/TLS的握手、TCP/IP协议基础、加密学)
HTTP & HTTPS网络协议重点总结(基于SSL/TLS的握手.TCP/IP协议基础.加密学) 原文:http://blog.csdn.net/itermeng/article/detai ...
- LVS负载均衡IP隧道模式原理介绍以及配置实战
LVS 基本工作原理 当用户向负载均衡调度器(Director Server)发起请求,调度器将请求发往至内核空间 PREROUTING 链首先会接收到用户请求,判断目标 IP 确定是本机 IP,将数 ...
- http隧道的研究
1.reDuh为什么要bind一个udp,如何维持tcp的? 似乎只要不close,就不会关闭打开过的socket 2.如果web超时,或者脚本超时,是否意味着会断开连接. 似乎并不会 3.是否针对可 ...
随机推荐
- java集合 collection-list-LinkedList 模拟一个堆栈或者队列数据结构。
/* 使用LinkedList模拟一个堆栈或者队列数据结构. 堆栈:先进后出 如同一个杯子. 队列:先进先出 First in First out FIFO 如同一个水管. */ import jav ...
- 学习C++ Primer 的个人理解(七)
类,后面还有两章是介绍有关于类的内容的.这一张依然只是个概括.但也已经将大致用法介绍完了. 重点如下: 1.成员函数的声明,必须在类的内部. 2.引用const成员函数 我们知道成员函数中有一个名为t ...
- Android SDK下载技巧
转载说明 本篇文章可能已经更新,最新文章请转:http://www.sollyu.com/android-sdk-download-tips/ 说明 想必在国内的你,是不是经常在下载Android S ...
- 使用WebClient上传文件时的一些问题
最近在使用WebClient做一个客户端上传图片到IIS虚拟目录的程序的时候,遇到了一些问题,这里主要给出参考步骤分享给大家. 测试环境 服务器端:Windows Server 2003,IIS6.0 ...
- 今日吐槽20151208.net服务器控件
正文 今天有个小任务是给页面添加一个搜索条件,复选框多选.因为页面都是服务器控件,我也只能用服务器控件配合了.然后给页面加了一个 CheckBoxList 控件.后台通过数据表加载数据. fore ...
- json 筛选数据 $.grep过滤数据
var data = { status: "ok", image_size_list: [ { image_size_id: "22", ad_class: & ...
- python(二)基础
1.lambda表达式(一般格式为冒号前边是参数冒号后边是返回值) 单参数: 多参数: 我们如果实现一个普通的filter过滤函数过滤掉偶数: 而我们如果用lambda表达式就很简便: 2.递归 普通 ...
- 企业生产环境下不同业务的linux分区建议
常规分区方案: /boot: 100M swap:内存的1至1.5倍 / : 剩余硬盘大小 DB及存储:有大量重要的数据 /boot : 100M swap: 内存的1至1.5倍,如果内存大于等于1 ...
- 2014年度辛星css教程夏季版第三节
第二节我们讲述的几乎全是CSS的选择器,那么下面这一节我们来讲一下CSS的颜色和文本的一些东西,虽然我对调色不大敏感,但是对于颜色还是比较感兴趣的. *********CSS中的颜色********* ...
- TypeScript学习指南--目录索引
关于TypeScript: TypeScript是一种由微软开发的自由和开源的编程语言.它是JavaScript的一个超集,而且本质上向这个语言添加了可选的静态类型和基于类的面向对象编程. TypeS ...