Linux netfilter 학습 노트 의 8 ip 층 netfilter 연결 추적 모듈 초기 화
지난 절 에서 연결 추적 모듈 과 관련 된 데이터 구 조 를 분 석 했 고 이 절 은 연결 추적 모듈 과 관련 된 초기 화 를 분석 하기 시 작 했 으 며 다음 절 은 연결 추적 모듈 의 hook 체 제 를 이해 했다.
연결 추적 모듈 코드 를 분석 하기 전에 몇 가 지 를 설명 합 니 다.
1. 추적 모듈 을 연결 하 는 helper 구 조 는 기대 연결 의 구축 과 관련 프로 토 콜 의 ALG 기능 을 실현 할 수 있 습 니 다.
2. 연결 추적 은 NAT 또는 상태 방화벽 의 실현 에 근 거 를 제공한다.
연결 추적 모듈 의 초기 화 과정 은 각각 세 곳 에서 진행 되 며, 연결 추적 모듈 과 관련 된 hook 리 셋 함 수 를 등록 하 는 데 사 용 됩 니 다.연결 추적 항목 과 원 하 는 연결 항목 을 만 드 는 데 사용 되 는 slab 캐 시;연결 추적 에 프로 토 콜 과 관련 된 변 수 를 등록 합 니 다.
1. 전역 초기 화
1.1 nf_conntrack_init
주로 nf_conntrack_init 초기 화 작업 을 진행 합 니 다. 이 함 수 는 nf 에 정의 되 어 있 습 니 다.conntrack_core. c 중.
주로 다음 과 같은 기능 을 완성 합 니 다.
a. nf 설정conntrack_htable_size、nf_conntrack_max 의 값
b. nfconntrack_hash 메모리 신청 및 초기 화
c. 추적 항목 과 기대 연결 추적 항목 을 연결 하기 위해 slab 캐 시 를 만 듭 니 다.
int __init nf_conntrack_init(void)
{
unsigned int i;
int ret;
nf_conntrack_htable_size , 1GB ,
1/16384 hash ; 1GB
hash 8192
*/
if (!nf_conntrack_htable_size) {
nf_conntrack_htable_size
= (((num_physpages << PAGE_SHIFT) / 16384)
/ sizeof(struct list_head));
if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE))
nf_conntrack_htable_size = 8192;
if (nf_conntrack_htable_size < 16)
nf_conntrack_htable_size = 16;
}
/*
nf_conntrack_max , 。
nf_conntrack_hash[] ,
nf_conntrack_htable_size 8 。
*/
nf_conntrack_max = 8 * nf_conntrack_htable_size;
printk("nf_conntrack version %s (%u buckets, %d max)
",
NF_CONNTRACK_VERSION, nf_conntrack_htable_size,
nf_conntrack_max);
/*
hash , nf_conntrack_htable_size hash
*/
nf_conntrack_hash = alloc_hashtable(nf_conntrack_htable_size,
&nf_conntrack_vmalloc);
if (!nf_conntrack_hash) {
printk(KERN_ERR "Unable to create nf_conntrack_hash
");
goto err_out;
}
/* nf_conntrack_register_cache slab */
ret = nf_conntrack_register_cache(NF_CT_F_BASIC, "nf_conntrack:basic",
sizeof(struct nf_conn), NULL);
if (ret < 0) {
printk(KERN_ERR "Unable to create nf_conn slab cache
");
goto err_free_hash;
}
/* slab */
nf_conntrack_expect_cachep = kmem_cache_create("nf_conntrack_expect",
sizeof(struct nf_conntrack_expect),
0, 0, NULL, NULL);
if (!nf_conntrack_expect_cachep) {
printk(KERN_ERR "Unable to create nf_expect slab cache
");
goto err_free_conntrack_slab;
}
/* nf_ct_l3protos nf_conntrack_generic_l3proto
, ,
*/
write_lock_bh(&nf_conntrack_lock);
for (i = 0; i < PF_MAX; i++)
nf_ct_l3protos[i] = &nf_conntrack_generic_l3proto;
write_unlock_bh(&nf_conntrack_lock);
/* For use by REJECT target */
ip_ct_attach = __nf_conntrack_attach;
/* nf_conntrack_untracked 1, */
atomic_set(&nf_conntrack_untracked.ct_general.use, 1);
/* nf_conntrack_untracked confirmed,
, ,
iptables -t raw -A PREROUTING -d x.x.x.x-j NOTRACK, PRE_ROUTING
、OUTPUT , raw hook ,
nfct nf_conntrack_untracked */
set_bit(IPS_CONFIRMED_BIT, &nf_conntrack_untracked.status);
return ret;
err_free_conntrack_slab:
nf_conntrack_unregister_cache(NF_CT_F_BASIC);
err_free_hash:
free_conntrack_hash(nf_conntrack_hash, nf_conntrack_vmalloc,
nf_conntrack_htable_size);
err_out:
return -ENOMEM;
}
1.2init_or_cleanup
nfconntrack_standalone. c 에서 정의 하 는 함 수 는 주로 1.1 에 소 개 된 함 수 를 호출 하여 초기 화 한 다음 / proc / net 파일 시스템 에서 해당 하 는 파일 을 만 들 고 / proc / sys / net 에서 연결 추적 모듈 과 관련 된 파일 을 만 듭 니 다.
/*
nf_conntrack_standalone 의 초기 화 및 소각 함수
초기 화:
1. nf 호출conntrack_init 연결 모듈 초기 화
연결 추적 수의 최대 값 을 설정 하고 연결 추적 항목 이나 기대 연결 추적 을 위 한
slab 캐 시 를 만 드 는 등 작업 을 합 니 다.
2. proc / net 디 렉 터 리 에 연결 추적 과 관련 된 파일 을 만 듭 니 다. 주요 nfconntrack、nf_conntrack_expect
아래 보기:
# cat /proc/net/stat/nf_conntrack
entries searched found new invalid ignore delete delete_list insert insert_failed drop early_drop icmp_error expect_new expect_create expect_delete
00000001 00000027 00000b0b 000035a4 000053e5 000049fb 000034d8 000003c3 000003ea 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000001 00000000 000008e9 00000067 00007eec 00007d2b 00000132 0000008d 00000067 00000000 00000000 00000000 00000000 00000000 00000000 00000000
#
# cat /proc/net/nf_conntrack
/proc/net/nf_conntrack /proc/net/nf_conntrack_expect
# cat /proc/net/nf_conntrack
ipv4 2 unknown 2 492 src=192.168.1.1 dst=224.0.0.1 [UNREPLIED] src=224.0.0.1 dst=192.168.1.1 use=2
#
#
# cat /proc/net/nf_conntrack_expect
#
#
3. / proc / sys 파일 시스템 에 연결 추적 과 관련 된 내용 을 만 듭 니 다.
*/
static int init_or_cleanup(int init)
{
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *proc, *proc_exp, *proc_stat;
#endif
int ret = 0;
if (!init) goto cleanup;
ret = nf_conntrack_init();
if (ret < 0)
goto cleanup_nothing;
#ifdef CONFIG_PROC_FS
proc = proc_net_fops_create("nf_conntrack", 0440, &ct_file_ops);
if (!proc) goto cleanup_init;
proc_exp = proc_net_fops_create("nf_conntrack_expect", 0440,
&exp_file_ops);
if (!proc_exp) goto cleanup_proc;
proc_stat = create_proc_entry("nf_conntrack", S_IRUGO, proc_net_stat);
if (!proc_stat)
goto cleanup_proc_exp;
proc_stat->proc_fops = &ct_cpu_seq_fops;
proc_stat->owner = THIS_MODULE;
#endif
#ifdef CONFIG_SYSCTL
nf_ct_sysctl_header = register_sysctl_table(nf_ct_net_table, 0);
if (nf_ct_sysctl_header == NULL) {
printk("nf_conntrack: can't register to sysctl.
");
ret = -ENOMEM;
goto cleanup_proc_stat;
}
#endif
return ret;
cleanup:
#ifdef CONFIG_SYSCTL
unregister_sysctl_table(nf_ct_sysctl_header);
cleanup_proc_stat:
#endif
#ifdef CONFIG_PROC_FS
remove_proc_entry("nf_conntrack", proc_net_stat);
cleanup_proc_exp:
proc_net_remove("nf_conntrack_expect");
cleanup_proc:
proc_net_remove("nf_conntrack");
cleanup_init:
#endif /* CNFIG_PROC_FS */
nf_conntrack_cleanup();
cleanup_nothing:
return ret;
}
2 Ipv4 연결 추적 모듈 Hook 리 셋 함수 등록
Ivv 4 프로 토 콜 에 등 록 된 연결 추적 모듈 과 관련 된 리 셋 함 수 는 다음 과 같 습 니 다.
/*
연결 중 추적 PREROUTING 체인 에 등 록 된 hook 리 셋 함수, 주요
세그먼트 패 킷 재 구성 입 니 다.우선 순위 가 ipv 4 보다 높 음conntrack_in
*/
static struct nf_hook_ops ipv4_conntrack_defrag_ops = {
.hook = ipv4_conntrack_defrag,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_IP_PRE_ROUTING,
.priority = NF_IP_PRI_CONNTRACK_DEFRAG,
};
/*PREROUTING ipv4_conntrack_in,
*/
static struct nf_hook_ops ipv4_conntrack_in_ops = {
.hook = ipv4_conntrack_in,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_IP_PRE_ROUTING,
.priority = NF_IP_PRI_CONNTRACK,
};
/*
LOCAL_OUT hook ,
。 ipv4_conntrack_in
*/
static struct nf_hook_ops ipv4_conntrack_defrag_local_out_ops = {
.hook = ipv4_conntrack_defrag,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_IP_LOCAL_OUT,
.priority = NF_IP_PRI_CONNTRACK_DEFRAG,
};
/*LOCALOUT ipv4_conntrack_in*/
/*LOCAL_OUT ipv4_conntrack_local,
*/
static struct nf_hook_ops ipv4_conntrack_local_out_ops = {
.hook = ipv4_conntrack_local,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_IP_LOCAL_OUT,
.priority = NF_IP_PRI_CONNTRACK,
};
/* helpers */
/*
POST_ROUTING ipv4_conntrack_help, ,
,
helper , ALG 。
*/
static struct nf_hook_ops ipv4_conntrack_helper_out_ops = {
.hook = ipv4_conntrack_help,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_IP_POST_ROUTING,
.priority = NF_IP_PRI_CONNTRACK_HELPER,
};
/*
LOCAL_IN ipv4_conntrack_help, ,
,
helper , ALG 。
*/
static struct nf_hook_ops ipv4_conntrack_helper_in_ops = {
.hook = ipv4_conntrack_help,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_IP_LOCAL_IN,
.priority = NF_IP_PRI_CONNTRACK_HELPER,
};
/* Refragmenter; last chance. */
/*
POST_ROUTING ipv4_confirm。
,
*/
static struct nf_hook_ops ipv4_conntrack_out_ops = {
.hook = ipv4_confirm,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_IP_POST_ROUTING,
.priority = NF_IP_PRI_CONNTRACK_CONFIRM,
};
/*
PRE_ROUTING ipv4_confirm。
,
*/
static struct nf_hook_ops ipv4_conntrack_local_in_ops = {
.hook = ipv4_confirm,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_IP_LOCAL_IN,
.priority = NF_IP_PRI_CONNTRACK_CONFIRM,
};
그리고 nfconntrack_l3proto_initor_cleanup 에서 nf 를 통 해register_hook 이상 nfhook_ops nf 에 추가hooks [] [] 배열 의 해당 링크 에 있 습 니 다.
3. 3 층 프로 토 콜, 4 층 프로 토 콜 에서 연결 모듈 과 관련 된 전역 변수 정의
3.1 nf_conntrack_l3proto_ipv4
ipv 4 프로 토 콜 관련 nf 정의conntrack_l3 proto 변수, 그 중에서 중요 한 것 은 ipv 4pkt_to_tuple、
ipv4_invert_tuple、ipv4_tuple_to_nfattr、 ipv4_nfattr_to_tuple。다음은 일일이 분석 해 보 겠 습 니 다.
struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4 = {
.l3proto = PF_INET,
.name = "ipv4",
.pkt_to_tuple = ipv4_pkt_to_tuple,
.invert_tuple = ipv4_invert_tuple,
.print_tuple = ipv4_print_tuple,
.print_conntrack = ipv4_print_conntrack,
.prepare = ipv4_prepare,
.get_features = ipv4_get_features,
#if defined(CONFIG_NF_CT_NETLINK) || \
defined(CONFIG_NF_CT_NETLINK_MODULE)
.tuple_to_nfattr = ipv4_tuple_to_nfattr,
.nfattr_to_tuple = ipv4_nfattr_to_tuple,
#endif
.me = THIS_MODULE,
};
3.1.1 ipv4_pkt_to_tuple
기능: ip 헤드 에 따라 원본 ip 주소 와 목적 ip 주 소 를 가 져 오고 tuple 변수 에 기록 합 니 다.
static int ipv4_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff,
struct nf_conntrack_tuple *tuple)
{
u_int32_t _addrs[2], *ap;
ap = skb_header_pointer(skb, nhoff + offsetof(struct iphdr, saddr),
sizeof(u_int32_t) * 2, _addrs);
if (ap == NULL)
return 0;
tuple->src.u3.ip = ap[0];
tuple->dst.u3.ip = ap[1];
return 1;
}
3.1.2 ipv4_invert_tuple
기능: 원본 tuple 의 원본 ip, 목적 ip 값 에 따라 reply 의 tuple 값 을 설정 합 니 다. 새로운 tuple 값 의 원본, 목적 ip 값 과 원본 tuple 의 원본 ip, 목적 ip 값 은 반대 입 니 다.
static int ipv4_invert_tuple(struct nf_conntrack_tuple *tuple,
const struct nf_conntrack_tuple *orig)
{
tuple->src.u3.ip = orig->dst.u3.ip;
tuple->dst.u3.ip = orig->src.u3.ip;
return 1;
}
3.1.3 ipv4_prepare
/*
1. 패 킷 의 3 층 데이터 부분 이 skb - > data 에 비해 오프셋 을 계산 합 니 다.
2. 4 층 프로 토 콜 의 프로 토 콜 번호 가 져 오기
*/
static int
ipv4_prepare(struct sk_buff **pskb, unsigned int hooknum, unsigned int *dataoff,
u_int8_t *protonum)
{
/* Never happen */
if ((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) {
if (net_ratelimit()) {
printk(KERN_ERR "ipv4_prepare: Frag of proto %u (hook=%u)
",
(*pskb)->nh.iph->protocol, hooknum);
}
return -NF_DROP;
}
*dataoff = (*pskb)->nh.raw - (*pskb)->data + (*pskb)->nh.iph->ihl*4;
/* */
*protonum = (*pskb)->nh.iph->protocol;
return NF_ACCEPT;
}
3.1.4 ipv4_tuple_to_nfattr
기능: tuple 구조 중의 3 층 소스 ip, 목적 ip 주 소 는 nfnetlink 가 규정 한 형식 으로 채 웁 니 다.
static int ipv4_tuple_to_nfattr(struct sk_buff *skb,
const struct nf_conntrack_tuple *tuple)
{
NFA_PUT(skb, CTA_IP_V4_SRC, sizeof(u_int32_t),
&tuple->src.u3.ip);
NFA_PUT(skb, CTA_IP_V4_DST, sizeof(u_int32_t),
&tuple->dst.u3.ip);
return 0;
nfattr_failure:
return -1;
}
3.1.5 ipv4_nfattr_to_tuple
기능: nfnetlink 메 시 지 를 전달 하 는 변 수 를 tuple 구조의 3 층 소스 ip, 목적 ip 주소 로 변환 합 니 다.
static int ipv4_nfattr_to_tuple(struct nfattr *tb[],
struct nf_conntrack_tuple *t)
{
if (!tb[CTA_IP_V4_SRC-1] || !tb[CTA_IP_V4_DST-1])
return -EINVAL;
if (nfattr_bad_size(tb, CTA_IP_MAX, cta_min_ip))
return -EINVAL;
t->src.u3.ip =
*(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_SRC-1]);
t->dst.u3.ip =
*(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_DST-1]);
return 0;
}
그리고 nfconntrack_l3proto_initor_cleanup 에서 nf 를 통 해conntrack_l3proto_register 장 nfconntrack_l3proto_ipv 4 주 소 는 nf 에 저 장 됩 니 다.ct_l3protos[PF_INET]。
3.2 nf_conntrack_protocol_tcp4
tcp 프로 토 콜 관련 nf 정의conntrack_protocol 변수, 그 중에서 중요 한 것 은 tcppkt_to_tuple、
tcp_invert_tuple、nf_ct_port_tuple_to_nfattr、 nf_ct_port_nfattr_to_tuple。이 몇 가지 함수 가 실현 하 는 기능 과 nfconntrack_l3proto_ipv 4 에서 해당 하 는 함수 가 비슷 합 니 다. ipv 4 에서 ip 주 소 를 겨냥 한 것 일 뿐 포트 번 호 를 겨냥 한 것 입 니 다.
반면 함수 tcp패 킷 은 주로 tcp 프로 토 콜 의 상태 변화 에 대해 정 의 된 것 으로 상태 방화벽 에 사 용 됩 니 다.
struct nf_conntrack_protocol nf_conntrack_protocol_tcp4 =
{
.l3proto = PF_INET,
.proto = IPPROTO_TCP,
.name = "tcp",
.pkt_to_tuple = tcp_pkt_to_tuple,
.invert_tuple = tcp_invert_tuple,
.print_tuple = tcp_print_tuple,
.print_conntrack = tcp_print_conntrack,
.packet = tcp_packet,
.new = tcp_new,
.error = tcp_error4,
#if defined(CONFIG_NF_CT_NETLINK) || \
defined(CONFIG_NF_CT_NETLINK_MODULE)
.to_nfattr = tcp_to_nfattr,
.from_nfattr = nfattr_to_tcp,
.tuple_to_nfattr = nf_ct_port_tuple_to_nfattr,
.nfattr_to_tuple = nf_ct_port_nfattr_to_tuple,
#endif
};
그리고 nfconntrack_l3proto_initor_cleanup 에서 nf 를 통 해conntrack_protocol_register 장 nfconntrack_protocol_tcp 4 주 소 는 nf 에 저 장 됩 니 다.ct_protos[PF_INET][TCP]。
이로써 연결 추적 모듈 의 초기 화 코드 부분 을 분석 했다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.