最近有点走火入魔了!本文所用技术非标准,较真儿者慎入!!
一个局域网内,两台机器拥有同样的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. Xcode 7.3.1的模拟器路径

    /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Library/Core ...

  2. Hadoop Datanode节点无法启动(All directories in dfs.data.dir are invalid)

    Hadoop Datanode节点无法启动(All directories in dfs.data.dir are invalid) java.io.IOException: All director ...

  3. ruby的gem和boundle安装解决办法

    gem和boundle安装在国内被墙,淘宝提供了淘宝提供了RubyGems的国内镜像站点,解决办法是: 对于gem: $ gem sources --remove https://rubygems.o ...

  4. 使用text-overflow:ellipsis对溢出文本显示省略号有两个好处

    使用text-overflow:ellipsis对溢出文本显示省略号有两个好处,一是不用通过程序限定字数:二是有利于SEO.需要使用对对溢出文本显示省略号的通常是文章标题列表,这样处理对搜索引擎更友好 ...

  5. MySQL表结构为InnoDB类型从ibd文件恢复数据

    客户的机器系统异常关机,重启后mysql数据库不能正常启动,重装系统后发现数据库文件损坏,悲催的是客户数据库没有进行及时备份,只能想办法从数据库文件当中恢复,查找资料,试验各种方法,确认下面步骤可行: ...

  6. Java泛型反射机制(二)

    /** * @author Administrator * 好处:泛型:1安全 2减少代码重用率 */ package com.test; import java.lang.reflect.Metho ...

  7. 对QT的产品,以及QT的一些综合评论 good

    QT你不能说他不流行吧, WPS, Wirshark, KDE, dropbox, skype, virtualbox都和qt有关吧, 你想写个跨平台的C++程序, QT是个不错的选择, 普通PC应用 ...

  8. Android 自定义seekbar中,thumb被覆盖掉一部分问题

    (图一)  (图二)    (图三) 做一个自定义的seekbar,更改其背景图片: <com.android.Progress android:id="@+id/focus_seek ...

  9. BrandZ:2016年全球最具价值品牌百强榜(完整报告)

    https://wppbaz.com/admin/uploads/files/BZ_Global_2016_Report.pdf Millward Brown编制的BrandZ最新排行榜(2016 B ...

  10. UIButton图片与文字位置调整

    1:左图右文 默认效果就行 2:左文右图 UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom]; [btn addTarget:se ...