get_conntrack's People
get_conntrack's Issues
ALG 在 nf_conntrack的实现
ALG implementation in nf_conntrack
nf_conntrack, ftp :
ct , , 对于ftp, 被动模式下,是通过控制连接来告诉对方自己开放哪个ip和端口,由于经过nat 设备, nat helper 功能模块必须修改控制连接里的通知消息(也就是控制连接 的每个数据在postrouting ipv4_helper 点都会调用 ftp help 回调检查是否是通告ip 端口的消息,是就修改这个消息的内容,并且创建exp),本来是想告诉对方来连接“192.168.100.2:3333”,现在改成nat 出口ip和端口,比如“223.2.2.1:123”,这是修改控制连接的数据部分,所以控制连接的tcp 序列号及校验码也要改(在postrouting confirm 修改tcp 序列号及校验码),否则对方受无法正常接收这个数据。而且需要nat 设备开放某个ip和端口来让对方来连接(其实不用开放,创建exp 有相关连接信息就防火墙就接受对方的数据连接), 即netfilter 需要创建一个nf_conntrack_expect exp放在expect_hash表里, 记录这个数据连接信息,包括更改后的端口,就是为了未来有个连接能匹配到,这样对方发起新的连接时,即创建新连接是就可以通过查找expect 表匹配到这个nf_conntrack_expect exp。这个新连接即数据连接ct -->master = exp->master , 这样数据连接ct 就跟控制连接的ct 关联起来了。数据连接ct 是根据master 的nat 信息来做snat 或dnat 的修改。只有 IP_CT_NEW 状态才匹配iptables snat规则,IP_CT_RELATED 状态是不会去匹配的, 期望连接一个数据就是IP_CT_RELATED 状态, 期望连接 是根据master nat 信息来做数据的修改。
// nat 修改的是三四层的东西, help()是修改应用层上的数据,并创建expect 表项,设置序列号调整参数nf_ct_seqadj_set, 最后在confirm 再根据序列号调整参数真正修改skb tcp层的序列号nf_ct_seq_adjust。
创建新连接时nfct_seqadj_ext_add--> help()需要修改应用层上的数据时 nf_ct_seqadj_set--> 到POSTROUTING ipv4_confirm 时 nf_ct_seq_adjust
对于nat 修改:
SNAT :
static struct nf_hook_ops nf_nat_ipv4_ops[] __read_mostly = {
{
.hook = iptable_nat_ipv4_out,
.pf = NFPROTO_IPV4,
.priority = NF_IP_PRI_NAT_SRC,
},
iptable_nat_ipv4_out --> nf_nat_ipv4_out() --> nf_nat_ipv4_fn
--> nf_nat_packet -->
if (!l3proto->manip_pkt(skb, 0, l4proto, &target, mtype))
return NF_DROP;
nf_nat_l3proto_ipv4. manip_pkt = nf_nat_ipv4_manip_pkt;
nf_nat_ipv4_manip_pkt(): //三层修改报文的回调函数也会去调用四层的回调函数
if (!l4proto->manip_pkt(skb, &nf_nat_l3proto_ipv4, iphdroff, hdroff,
target, maniptype))
nf_nat_l3proto_register( nf_nat_l3proto_ipv4 ):
RCU_INIT_POINTER(nf_nat_l4protos[l3proto->l3proto][IPPROTO_TCP],
&nf_nat_l4proto_tcp);
RCU_INIT_POINTER(nf_nat_l4protos[l3proto->l3proto][IPPROTO_UDP],
&nf_nat_l4proto_udp);
RCU_INIT_POINTER(nf_nat_l3protos[l3proto->l3proto], l3proto);
在注册nf_nat_l3proto_ipv4 三层时,就默认注册四层的tcp 和udp
DNAT :
static struct nf_hook_ops nf_nat_ipv4_ops[] __read_mostly = {
/* Before packet filtering, change destination */
{
.hook = iptable_nat_ipv4_in,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_PRE_ROUTING,
.priority = NF_IP_PRI_NAT_DST,
},
iptable_nat_ipv4_in-->nf_nat_packet-->l3proto->manip_pkt(skb, 0, l4proto, &target, mtype) 修改pkt
如何确定dnat 后,路由之前,数据报文真的修改了目的地址
Netfilter中NAT的TARGET实现:
nf_nat_rule_find–>ipt_do_tables (iptable_nat_do_chain)处理snat rules. ???????
iptables .... -j SNAT , 就会匹配到 xt_target
static struct xt_target xt_nat_target_reg[] __read_mostly = {
{
.name = "SNAT",
.revision = 0,
.checkentry = xt_nat_checkentry_v0,
.target = xt_snat_target_v0,
.targetsize = sizeof(struct nf_nat_ipv4_multi_range_compat),
.family = NFPROTO_IPV4,
.table = "nat",
.hooks = (1 << NF_INET_POST_ROUTING) |
(1 << NF_INET_LOCAL_IN), //-j SNAT 使用的链表范围
.me = THIS_MODULE,
},
snat 扩展target的参数定义:
struct nf_nat_ipv4_multi_range_compat {
unsigned int rangesize;
struct nf_nat_ipv4_range range[1];
};
经过nat 设备--》 xt_snat_target_v0 --》
nf_nat_setup_info(ct, &range, NF_NAT_MANIP_SRC);
nat = nf_ct_nat_ext_add(ct);
struct nf_conn_nat *nat;
nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC); //nat 功能模块
if (nfct_help(ct)) ???????需要help
nfct_seqadj_ext_add(ct); // 添加序列号调整功能模块
- nf conntrack ftp 初始化:
static struct nf_conntrack_helper ftp[MAX_PORTS][2] __read_mostly;
nf_conntrack_ftp_init():
ftp[i][j].tuple.src.u.tcp.port = htons(ports[i]); FTP_PORT 21
ftp[i][j].tuple.dst.protonum = IPPROTO_TCP;
ftp[i][j].expect_policy = &ftp_exp_policy;
ftp[i][j].me = THIS_MODULE;
ftp[i][j].help = help;
ret = nf_conntrack_helper_register(&ftp[i][j]);
把ftp nf_conntrack_helper 注册到 nf_ct_helper_hash 表里
- init_conntrack() 创建一个新的连接:
if (!exp) {
__nf_ct_try_assign_helper(ct, tmpl, GFP_ATOMIC);
NF_CT_STAT_INC(net, new);
}
__nf_ct_try_assign_helper:
--> helper = __nf_ct_helper_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
help = nf_ct_helper_ext_add(ct, helper, flags); // struct nf_conn_help *help
rcu_assign_pointer(help->helper, helper);
以上就是给一个新建的ct 加入help 、helper, helper.help()回调函数什么时候调用呢????
- ipv4_helper 修改连接的内容
static struct nf_hook_ops ipv4_conntrack_ops[] __read_mostly = {
{
.hook = ipv4_helper,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_POST_ROUTING,
.priority = NF_IP_PRI_CONNTRACK_HELPER,
//优先级仅比NF_IP_PRI_CONNTRACK_CONFIRM高,即到最后才执行help回调函数
// nat 修改的是三四层的东西, help()是修改应用层上的数据,并创建expect 表项,设置序列号调整参数, 最后在confirm 再根据序列号调整参数真正修改skb tcp层的序列号。
},
}
4. ipv4_confirm:离开netfilter 模块的时候
//判断是否做了序列号调整IPS_SEQ_ADJUST_BIT
if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) &&
!nf_is_loopback_packet(skb)) {
if (!nf_ct_seq_adjust(skb, ct, ctinfo, ip_hdrlen(skb))) {
NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop);
return NF_DROP;
}
}
nf_ct_seq_adjust 才是真正修改报文的序列号地方
nf_conntrack_ftp_init ---》注册 ftp[i][j] 到 nf_ct_helper_hash, 控制连接创建时init_conntrack--》__nf_ct_try_assign_helper 尝试从nf_ct_helper_hash找到一个helper, 找到后nf_ct_helper_ext_add, 到了POSTROUTING 点---》 ipv4_helper ()
ipv4_helper ():
--》 help = nfct_help(ct);
return helper->help(skb, skb_network_offset(skb) + ip_hdrlen(skb),
ct, ctinfo); //这里就是执行 helper->help 回调函数了
比如 ftp helper. help():
ftp[i][j].help = help;
nf_conntrack_ftp.c -->help():
exp = nf_ct_expect_alloc(ct); //expect 表项
ret = nf_nat_ftp(skb, ctinfo, search[dir][i].ftptype,
protoff, matchoff, matchlen, exp);
struct nf_conn *ct = exp->master;
// 给exp 查找一个合适的端口,尽量保持端口不变
buflen = nf_nat_ftp_fmt_cmd(ct, type, buffer, sizeof(buffer),
&newaddr, port); //修改控制连接数据里的ftp命令
if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo, protoff, matchoff,
matchlen, buffer, buflen))
---》__nf_nat_mangle_tcp_packet(..., true) // 修改数据且调整tcp序列号
SKB_LINEAR_ASSERT(skb); //检查是否线性化
// 修改payload内容
mangle_contents(skb, protoff + tcph->doff*4,
match_offset, match_len, rep_buffer, rep_len);
if (adjust && rep_len != match_len)
nf_ct_seqadj_set(ct, ctinfo, tcph->seq,
(int)rep_len - (int)match_len);//只是设置序列号调整信息
真正修改skb的操作是在另一地方,就是离开netfilter 的时候
ipv4_confirm:
========================================================================
struct nf_conn, struct nf_conn_ext, struct nf_conn_help 及 struct nf_conntrack_helper 之间的结构关系。
ext->offset[ nf_ct_ext_id ] , 保存nf_ct_ext_id 内存对应于ext 结构体的偏移值
nf_nat_setup_info--》nat = nf_ct_nat_ext_add(ct);--》struct nf_conn_nat *nat =nfct_nat()-》
return nf_ct_ext_find(ct, NF_CT_EXT_NAT);到ct-->ext 去找id:NF_CT_EXT_NAT对应的信息
这个信息是 struct nf_conn_nat 结构体:
struct nf_conn_nat {
struct hlist_node bysource; //这个的用处是,为以后打洞用的,实际就
struct nf_conn *ct;
union nf_conntrack_nat_help help;
#if IS_ENABLED(CONFIG_NF_NAT_MASQUERADE_IPV4) || \
IS_ENABLED(CONFIG_NF_NAT_MASQUERADE_IPV6)
int masq_index;
#endif
};
ext_id 有哪些, NF_CT_EXT_NUM 代表最大值:
enum nf_ct_ext_id {
NF_CT_EXT_HELPER,
#if defined(CONFIG_NF_NAT) || defined(CONFIG_NF_NAT_MODULE)
NF_CT_EXT_NAT,
#endif
NF_CT_EXT_SEQADJ,
NF_CT_EXT_ACCT,
#ifdef CONFIG_NF_CONNTRACK_EVENTS
NF_CT_EXT_ECACHE,
#endif
#ifdef CONFIG_NF_CONNTRACK_ZONES
NF_CT_EXT_ZONE,
#endif
#ifdef CONFIG_NF_CONNTRACK_TIMESTAMP
NF_CT_EXT_TSTAMP,
#endif
#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
NF_CT_EXT_TIMEOUT,
#endif
#ifdef CONFIG_NF_CONNTRACK_LABELS
NF_CT_EXT_LABELS,
#endif
#if IS_ENABLED(CONFIG_NETFILTER_SYNPROXY)
NF_CT_EXT_SYNPROXY,
#endif
NF_CT_EXT_NUM,
};
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.