Linux netfilter 학습 노트 의 8 ip 층 netfilter 연결 추적 모듈 초기 화

13653 단어
linux 2.6.21 기반
지난 절 에서 연결 추적 모듈 과 관련 된 데이터 구 조 를 분 석 했 고 이 절 은 연결 추적 모듈 과 관련 된 초기 화 를 분석 하기 시 작 했 으 며 다음 절 은 연결 추적 모듈 의 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]。
 
이로써 연결 추적 모듈 의 초기 화 코드 부분 을 분석 했다.

좋은 웹페이지 즐겨찾기