NF_INET_PRE_ROUTING 做DNAT (做了DNAT后在做路由决定是local_in还是forwarding)数据包进入路由表之前
NF_INET_POST_ROUTING 做SNAT (离开协议栈时,做源ip替换)发送到网卡接口之前
NF_INET_LOCAL_OUT:本机发包时,做DNAT,由于发包时,在local_out之前已经做了路由选择,所以做了DNAT后如果发现目的ip做了替换,则需要重新路由!!
NF_INET_LOCAL_IN:通过路由表后目的地为本机,做SNAT,报文送往本机,被nginx等服务读取之前做源ip替换。
原因如下: 报文pkt进入内核协议栈时,还没有查找路由,由于路由选择是在PREROUTEING 和 FORWARD之间,所以先替换目的ip 后在选择路由,
如果先做了路由结果为forwarding,但是去做dnat可能去本机,这样就冲突了,需要重新路由来矫正。所以还是需要先dnat在做路由。
之前存在一个问题:在内核使用双向nat,local_out替换目的ip后,就会重新路由,导致出口有问题,所以为此重新设计了一套代码。 请参考之前的博客:双向nat
具体逻辑就是:
/* We must be after connection tracking and before packet filtering. */
static struct nf_hook_ops nf_nat_ops[] __read_mostly = {
/* Before packet filtering, change destination */
{
.hook = nf_portal_nat_in,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_PRE_ROUTING,
.priority = NF_IP_PRI_CONNTRACK + 1,
},
/* After packet filtering, change source */
{
.hook = nf_portal_nat_out,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_LOCAL_OUT,
.priority = NF_IP_PRI_CONNTRACK + 1,
},
};
主要逻辑就是:client ----sw ------server;
第一步:client 和sw 之间做双线nat, 此时收包pre_routeing 以及反方向 output 做source dst ip同时替换。
第二步:client知道需要访问的真实ip,此时在sw上做源ip替换, sw做代理,访问server获取相关信息。
auth_info = nf_ct_ext_add(ct, NF_CT_EXT_PORTAL, GFP_ATOMIC);
-------------------------------
//保存源mac,原ip, 原端口
memcpy(auth_info->org_mac, eth->h_source,sizeof(auth_info->org_mac));
auth_info->org_sip = iph->saddr;
auth_info->org_dip = iph->daddr;
auth_info->org_port = tcph->source;
//分配源端口
auth_info->alloc_port = sw_alloc_snat_port();
-----------------------------------
ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip = htonl(DP_PORTAL_IP);
ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip = htonl(DP_PORTAL_SRC_XLATE_IP);
//ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.tcp.port;
ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.tcp.port = htons(auth_info->alloc_port);
return NF_ACCEPT;
//此时做了sip dip替换后,路由转发到local in。
对应local_out就调用ct保留的信息复原即可。
详细情况就不说了。
http代理服务器(3-4-7层代理)-网络事件库公共组件、内核kernel驱动 摄像头驱动 tcpip网络协议栈、netfilter、bridge 好像看过!!!! 但行好事 莫问前程 --身高体重180的胖子