我们知道,Linux的NAT是基于ip_conntrack的有状态NAT,其配置类似BSD的keep state的效果!如果看一下Netfilter的PREROUTING,就知道ip_conntrack依赖ip_defrag,也就是凡是分片的IP片必须重组后才可以进入ip_conntrack进而进入NAT,如果我们希望能针对每一个IP分片来做NAT的话,那就需要动一番脑筋了。
        下图是一个优化逻辑,在其它的文章中也屡次贴出:

注意此图中没有NAT的逻辑,只是conntrack逻辑。我先说一下NAT需要注意什么,其实没有什么要注意的,唯一的就是IP首部和TCP/UDP(如果有的话)首部的校验和,注意到这些校验和的计算并不是加解密,并不是摘要是重要的,因为当你知道校验和是如此的好计算后,你就从内心克服了针对优化IP分片NAT的恐惧心理!
        我们只需要揪出来第一个携带TCP头的分片即可。由于校验和的计算仅仅是一个算术计算的过程,类似小学学的加法,而加法满足交换律,结合律,因此我们可以假设检验和的数据载荷部分以及其它TCP部分是一个常数,需要改变的仅仅是伪头部分,而这很简单,公式如下:
新的校验和=老的检验和-老的伪首部校验和+新的伪首部校验和
受影响的仅仅是伪首部,而NAT影响也仅仅是伪首部,由于我已经恨透了动态NAT,鉴于XX银行实施不成功而不得不去排查问题导致回家晚了而饿着肚子和游离于文明边缘以外的老婆吵架,此处的NAT指的是一一映射的static NAT,哪怕是TMD我自己实现的static NAT!于是分片到循着上面的图的出口到达NAT模块,执行下面的逻辑:
1.判断是不是携带完整的TCP头,如果是,那么根据NAT的结果按照上述公式修改TCP的校验和(别提配角UDP了);
2.如果不是携带完整的TCP头,则不可能!因为上面的图示保证了总是能携带传输层头(但不绝对!);
3.由于2的结果是但不绝对,毕竟可能不针对conntrack做优化,而仅优化NAT!如果真的没有携带完整的TCP头,则按照上图的逻辑等待。
一个NAT,折腾了我这么久!唉,为了一个NAT,我期盼IPv6,现在又扯进了一个IP分片,我更期盼IPv6了,那时既没有NAT,也没有分片了!如今,我真的high不起来,游离于边缘之外的人总是嚎叫,Mac OS的network正玩的尽兴,蛮族人又在嚎叫,做打油诗一首:
责骂 误解 嚎叫!在我身边萦绕! 狂妄 自私 无聊!在我心头燃烧! 流露出的凶险,你并不比我更明了, 恃才放旷的傲慢,请你昂起头,我让你知道! 理解,或多或少。 我更在乎的,其实我比你更狂躁! 只是 有种东西在慢慢发育, 最终它就是他妈的一个勾当! shit,everything!shit,the life!