最近有点走火入魔了!本文所用技术非标准,较真儿者慎入!!
一个局域网内,两台机器拥有同样的IP,可以吗?

这不就是IP地址冲突吗?当然不行!

可是要知道,如果搞点旁门左道,还是可以做到的!

首先要明白的是,IP数据报在以太网中的收发特征:

对于发送来讲:只要你有一个目标MAC供你封装成帧,就可以发出去,而这个MAC地址是由ARP来获取的;
对于接收来讲:只要收到帧的目标MAC是接收到帧的网卡的MAC地址,就可以正确接收!


现在我们逐步的来实现一个局域网内拥有同样IP还能正常越过默认网关访问不同外网的情景。实际上,在我实现的简版SDN中,一切都是保存在conntrack中的,它甚至可以保存一个流的上一跳和下一跳neighbour,这就意味着完全架空了本机的路由逻辑和arp逻辑!使本机完全退化成了一个switch!专注于数据包的转发!neighbour的定义是次要的,完全没有必要照抄Linux内核的neighbour结构体,它的实质就是一个MAC地址而已,思路很简单:

1.流头进来在正方向的PREROUTING中将其源MAC地址保存在conntrack;
2.属于同一流的数据包在反方向的POSTROUTING中获取conntrack中的MAC地址封装为目标MAC;
3.发送并返回STOLEN。


就是这么简单!实际上如果能在Linux中实现Policy ARP就好了,也就是说,可以为同一个IP地址映射多条ARP项,每个项有不同的MAC地址。毕竟neighbour是和dst_entry即路由表项相关联的,因此只要保证同一个IP地址的多个ARP映射属于不同的路由表项即可,而这很容易通过IPMARK+Policy Routing来实现!

        不幸的是,Linux并没有实现如此让人走火入魔的Policy ARP,现有的隔离措施就是使用NET命名空间,然而它是用于虚拟化的,同一个网卡只能属于同一个命名空间,此场景不适用!那么怎么办?只能自己写Netfilter代码了啊,还好,由于这个逻辑超级清晰,因此所做的修改也是很容易的,实现了这个的话,仰天长啸,嘲笑一下地址冲突!

        保存源MAC地址在ipv4_conntrack_in的最后来做,而还原保存的MAC地址到目标MAC地址的操作在ipv4_confirm中来做。代码如下:

//继续偷梁换柱借用nat的extend
struct nf_conn_nat {
//自动保存回复帧的目标MAC地址
unsigned char reply_gw_mac[ETH_ALEN];
//自动保存本机MAC地址
unsigned char orig_gw_mac[ETH_ALEN];
//自动保存设备
struct net_device *dev;
};
static unsigned int ipv4_conntrack_in(unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
unsigned int ret = nf_conntrack_in(dev_net(in), PF_INET, hooknum, skb);
if (ret == NF_ACCEPT) {
enum ip_conntrack_info ctinfo;
struct nf_conn *ct;
struct nf_conn_nat *automac;
ct = nf_ct_get(skb, &ctinfo);
if (!ct) {
goto out;
}
if (skb->dev->flags & IFF_LOOPBACK)
return ret;
if (CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL) {
goto out;
}
automac = nf_ct_ext_find(ct, NF_CT_EXT_NAT);
if (automac == NULL) {
automac = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC);
if (automac == NULL) {
goto out;
}
struct ethhdr *eth = (struct ethhdr*)(skb->data - ETH_HLEN);
memcpy(automac->reply_gw_mac, eth->h_source, ETH_ALEN);
memcpy(automac->orig_gw_mac, eth->h_dest, ETH_ALEN);
automac->dev = skb->dev;
}
} out:
return ret;;
} static unsigned int ipv4_confirm(unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
.............
out:
/* We've seen it coming out the other side: confirm it */
ret = nf_conntrack_confirm(skb);
if (ret == NF_ACCEPT) {
struct nf_conn_nat *automac = NULL;
struct net_device *dev = NULL;
unsigned int hh_len = 0;
if (skb->dev->flags & IFF_LOOPBACK)
return ret;
if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL)
return ret;
if (hooknum != NF_INET_POST_ROUTING)
return ret;
automac = nf_ct_ext_find(ct, NF_CT_EXT_NAT);
if (automac == NULL)
return ret;
dev = automac->dev;
skb->dev = dev;
hh_len = LL_RESERVED_SPACE(dev);
if (unlikely(skb_headroom(skb) < hh_len && dev->header_ops)) {
struct sk_buff *skb2; skb2 = skb_realloc_headroom(skb, LL_RESERVED_SPACE(dev));
if (skb2 == NULL) {
kfree_skb(skb);
return -ENOMEM;
}
if (skb->sk)
skb_set_owner_w(skb2, skb->sk);
kfree_skb(skb);
skb = skb2;
}
//填充以太帧头,注意偏移!
char *header = skb->data - hh_len;
header[0] = 0x0;
header[1] = 0x0;
struct ethhdr *eth = (struct ethhdr*)(header+2);
memcpy(eth->h_dest, automac->reply_gw_mac, ETH_ALEN);
memcpy(eth->h_source, automac->orig_gw_mac, ETH_ALEN);
eth->h_proto = htons(ETH_P_IP);
skb_push(skb, ETH_HLEN);
skb->_skb_dst = NULL;
dev_queue_xmit(skb);
return NF_STOLEN;
}
return ret;
}

精妙之处在于,只要有一个包到达该BOX,其源MAC地址就能被conntrack记住,当反方向的包到来并要发回去的时候,就能取出该源MAC地址作为目标MAC地址封装到以太帧中,然后无需经由ARP层直接发送出去。现在的问题是,两个相同IP地址的主机可以同时发包过来吗?答案无疑是肯定的,因为它们俩发包前解析BOX的MAC地址,该BOX无疑全部回复,它们总有个先来后到,唯一的副作用时后到的那个ARP请求会更新BOX的ARP表,将相同的那个IP的MAC地址覆盖成自己的MAC地址,然而这无所谓了,因为既然两台主机都得到了BOX的MAC地址,数据包肯定能发出去到达BOX,返回包在寻址这两台机器的时候,并不通过ARP来寻址,而是通过这两台机器自己携带过去的源MAC地址来作为目标MAC的,故而覆盖也无所谓了!

        只要保证没有五元组的冲突即可,而这种冲突的可能性是极其小的。

        严格来讲ARP属于IP的下层,是和链路层接口的协议,它是”下一跳解析协议“的一种,适用于IPv4到以太网的适配,ARP只是动态的帮你完成了映射,如果你知道该如何封装以太帧,完全可以不用ARP,要么手工设置static的映射,要么就是从某处得到一个映射,关键点不在ARP或者映射,关键点在于你能得到一个MAC地址!只要你能得到目标MAC地址,那么封装以太帧即可,此时是不关心源MAC的!

        我真的走火入魔了,不管是用MAC桥微端口搞定了OpenVPN的源地址选择,还是构造假网关在配置Windows路由时指定源地址,还是本文说的IP地址冲突情景下的数据通信,都不是标准的做法,希望较真的同学注意。如果想靠这个理解网络的行为,那是再好不过了...

关键在封装并发出了帧-IP冲突也无所谓的更多相关文章

  1. 局域网内IP冲突怎么办

      对于在Internet和Intranet网络上,使用TCP/IP协议时每台主机必须具有独立的IP地址,有了IP地址的主机才能与网络上的其它主机进行通讯.但IP地址冲突会造成网络客户不能正常工作,只 ...

  2. 如何在linux下检测(自身)IP冲突

    最近遇到一个需求,或者说是一个用户现场问题. 我们设备先安装,设置dhcp模式获取ip进行联网,后来又安装了其他设备,但该设备是手动设置的静态ip地址,正好与我们设备冲突,造成网络故障. 那我们就需要 ...

  3. Alwayson的IP冲突

    Alwayson的IP冲突 https://social.technet.microsoft.com/Forums/office/en-US/4d50cb1c-eef7-4dcc-b937-3c8eb ...

  4. FFmpeg4.0笔记:封装ffmpeg的视频帧转换功能类CSws

    Github https://github.com/gongluck/FFmpeg4.0-study/tree/master/Cff CSws.h /************************* ...

  5. 今天连续几次被其他电脑客户端踢下线,也不知是否是ip冲突

    可能是利用ip然后我的网络也没有关掉共享,其次就是远程开启了一个叫做"学生端"的应用,好在我改密码连续两次改的快

  6. 解决局域网IP冲突

    进入cmd ipconfig -all 查看现有IP,发现IP不是192.168.1.*的形式,而是192.168.0.*等异常 ipconfig -release  释放现有IP ipconfig ...

  7. IP冲突解决方案

    客人在我所供职的酒店上网的时候,经常会弹出一个对话框,显示一些提示,如上网的注意事项和消费标准等信息;并且有自己的电影和歌曲服务器,DHCP-server也是其中的一台服务器,宾馆.酒店就是用这台机器 ...

  8. IP冲突如何把冲突的IP挤下去

    把冲突IP挤下去的方法: ①进入网络和共享中心>本地连接>禁用. ②进入网络和共享中心>更改适配器设置>双击被禁用的连接,自动重新连接即可.

  9. 昨天晚上也弄不清楚是自己密码被盗了还是由于ip冲突

    所以还是尽量要相信自己所见到的,今天上午是安卓课程,说实话,昨天晚上都是2:30睡的,现在硬是要把时间待这么晚才回去睡,是因为我想尽快入睡,昨天晚上就是眼睛都有点睁不开了,所以就睡得很快,但是早上也是 ...

随机推荐

  1. 认识HTML

    基本框架: 1 <html> 2 <head> 3 <title>This Is Title</title> 4 </head> 5 6 & ...

  2. Automotive Security的一些资料和心得(6):AUTOSAR

    1.1 Introduction AUTOSAR(汽车开放系统架构)是一个开放的,标准化的汽车软件架构,由汽车制造商,供应商和开发工具共同开发.它联合了汽车OEM ,供应商和开发工具供应商,其目标是创 ...

  3. 标准初始化css样式表

    body { font-size:12px; line-height:1.3; font-family:'微软雅黑', Tahoma,Helvetica,Arial,'宋体', sans-serif; ...

  4. php smarty 缓存和配置文件的基本使用方法

    smarty高级部分包括缓存机制和配置文件的调用 下面是代码实现: 文件一,配置文件: #全局变量 title="网站主页" content="一个网站的主体部分&quo ...

  5. Jmeter java协议配置文件导入

    一. 方法一 通过ClassLoader获取当前路径,想在java脚本里读取druid.properties,路径如下 apache-jmeter --bin --druid.properties 相 ...

  6. http://www.linuxidc.com/Linux/2015-02/114265.htm

    http://www.linuxidc.com/Linux/2015-02/114265.htm

  7. FFT初步学习小结

    FFT其实没什么需要特别了解的,了解下原理,(特别推荐算法导论上面的讲解),模板理解就行了.重在运用吧. 处理过程中要特别注意精度. 先上个练习的地址吧: http://vjudge.net/vjud ...

  8. Python标准库之urllib,urllib2

    urllib模块提供了一些高级接口,用于编写需要与HTTP服务器交互的客户端.典型的应用程序包括从网页抓取数据.自动化.代理.网页爬虫等. 在Python 2中,urllib功能分散在几个不同的库模块 ...

  9. 【Quick 3.3】资源脚本加密及热更新(二)资源加密

    [Quick 3.3]资源脚本加密及热更新(二)资源加密 注:本文基于Quick-cocos2dx-3.3版本编写 一.介绍 在前一篇文章中介绍了代码加密,加密方式是XXTEA.对于资源文件来说,同样 ...

  10. Linux IP 路由实现

    以下代码取自 kernel . [数据结构] 该结构被基于路由表的classifier使用,用于跟踪与一个标签(tag)相关联的路由流量的统计信息,该统计信息中包含字节数和报文数两类信息. 这个结构包 ...