totofugaのブログ

ネットワークとかc言語、perlの話。

conntrackの勉強(1)

conntrackのフック

IPTableと同じようにNetFilter経由で実装されている。

使用しているフックは

  • PREROUTING => ipv4_conntrack_in
  • LOCAL_OUT => ipv4_conntrack_local
  • POSTROUTING => ipv4_confirm
  • NF_INET_LOCAL_IN => ipv4_confirm

となっている。

フックの優先順位

優先順位は

enum nf_ip_hook_priorities {
...
    NF_IP_PRI_CONNTRACK = -200,           
    NF_IP_PRI_MANGLE = -150,              
    NF_IP_PRI_NAT_DST = -100,             
    NF_IP_PRI_FILTER = 0,                 
    NF_IP_PRI_SECURITY = 50,              
    NF_IP_PRI_NAT_SRC = 100,              
    NF_IP_PRI_SELINUX_LAST = 225,         
    NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX,
...
}

のようになっており、 iptablesとの関係は f:id:totofuga:20171125202918p:plain PREROUTING, OUTPUTでIPTABLESの処理に入る前に 必ずconntrackを作るをようになっており、 POSTROUTING,INPUTで登録を行うが、こちらはIPTABLESでフィルタをかけられたものは登録されないようになっている。

nf_conntrackとsk_buffの関連付け

PREROUTINGとINPUTのskbufにconntrackの関連付けを行う skbufに結び付けられるconntrackのパラメータは以下の二つ

struct sk_buff {
...
    struct nf_conntrack *nfct;
    __u8 nfctinfo:3;
...
}

nf_conntrackは実際にはnf_connが入っている。 nfctinfoはステータスが入り、ステータスは以下の5パターンがある

  • IP_CT_ESTABLISHED,
  • IP_CT_RELATED,
  • IP_CT_NEW,
  • IP_CT_IS_REPLY + IP_CT_ESTABLISHED
  • IP_CT_IS_REPLY + IP_CT_RELATED

nf_conntrack_tuple

nf_connに結びついていてるハッシュのに使われるタプル情報 conntrackでは行きと戻り、両方をペアとして保存する必要があるため、 nc_conn構造体には2つのタプル情報がある

struct nf_conntrack_tuple_hash {        
    struct hlist_nulls_node hnnode;     
    struct nf_conntrack_tuple tuple;    
};           

struct nf_conn {
...
    struct nf_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX];
....
}

enum ip_conntrack_dir {
    IP_CT_DIR_ORIGINAL,
    IP_CT_DIR_REPLY,
    IP_CT_DIR_MAX
};    

IP_CT_DIR_ORIGINALが行きパケットで、IP_CT_REPLYが戻りパケットになる。

nf_conntrack_tupleには以下の情報が入っている

実際にハッシュ値を生成するときはdirectionは含まれておらず、 これはtupleからnf_conntrackを取得する際に使われる。 directionがわかることで以下のようにnf_connの位置がわかりtupleからnf_connを取得できる

static inline struct nf_conn *                                        
nf_ct_tuplehash_to_ctrack(const struct nf_conntrack_tuple_hash *hash) 
{                                                                     
    return container_of(hash, struct nf_conn,                         
                tuplehash[hash->tuple.dst.dir]);                      
}                                                                     

tupleの管理

tupleはネームスペースごとに管理される net->netns_ct->hashがハッシュ情報となる。 ハッシュに入るのはPOSTROUTINGとINPUT時なのでそれまでの間、 ハッシュに入っていないtuple情報はnet->netns_ct->unconfirmedで管理される。

insertは__nf_conntrack_hash_insertで行われる。 行きと戻りセットで入れるため、ORIGINALとREPLY両方のinsertが行われる。