Giter Site home page Giter Site logo

get_conntrack's People

Contributors

jursonmo avatar

Stargazers

 avatar

Watchers

 avatar  avatar

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_registernf_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);  // 添加序列号调整功能模块

  1. 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 表里

  1. 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()回调函数什么时候调用呢????

  1. 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层的序列号。
	},
}

image
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 回调函数了
image
比如 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 之间的结构关系。
image
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 photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.