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との関係は 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が行われる。