3. 넷필터 아키텍처

넷필터는 단지 프로토콜 스택의 다양한 포인트에 존재하는 훅의 연속일 뿐이다. 이상적인 IPv4의 진행경로 다이어그램은 다음과 같다.
A Packet Traversing the Netfilter System:
   --->[1]--->[ROUTE]--->[3]--->[4]--->
                 |            ^
                 |            |
                 |         [ROUTE]
                 v            |
                [2]          [5]
                 |            ^
                 |            |
                 v            |
패킷은 그림의 좌측으로부터 들어와서 단순한 데이터 체크(즉, 데이터가 잘렸는지, 혹은 IP 체크 섬의 이상유무, 뒤죽박죽 되지는 않았는 지 등)를 거쳐, 넷필터 프레임웍의 NF_IP_PRE_ROUTING[1] 훅으로 전달된다.

다음으로, 패킷은 라우팅 코드로 들어가며, 여기서 패킷이 다른 인터페이스로 향하는지 또는 로컬 프로세스로 향하는지 결정된다. 패킷이 라우팅될 수 없는 경우, 라우팅 코드는 패킷을 버리기도 한다.

만일 패킷의 목적지가 들어온 박스라면, 넷필터 프레임웍은 패킷을 프로세스로 전달하기 전에 NF_IP_LOCAL_IN [2] 훅을 다시 한번 호출하게 된다.

만일 다른 인터페이스로 전달하고자 한다면, 넷필터 프레임웍은 NF_IP_FORWARD [3] 훅을 호출한다.

그리고 나서 패킷이 넷트웍 라인으로 보내지기 전에 마지막 넷필터 훅인 NF_IP_POST_ROUTING [4] 훅으로 전달된다.

로컬에서 생성된 패킷에 대해서는 NF_IP_LOCAL_OUT [5] 훅이 호출된다. 이 때, 이 훅이 호출된 후 라우팅이 발생하는 것을 알 수 있다. 실제로는 라우팅 코드가 소스 IP 주소와 몇 가지 IP 옵션을 확인하기 위해 라우팅 코드가 먼저 호출이 된다. 즉, 라우팅을 변경하고자 한다면, NAT 코드에 되어 있는 것처럼 여러분 스스로 `skb->dst' 필드를 변경해야만 한다.

3.1. 넷필터의 기초

이 절에서는 IPv4에 대한 넷필터의 예를 보일 것이며, 이를 통해 여러분들은 각각의 훅이 동작하는 시점을 이해하게 될 것이다. 이 것이 바로 넷필터의 기초이다.

커널 모듈은 앞서 언급한 어떠한 훅에 대해서 응답할 수 있도록 등록할 수 있으며, 어떤 함수를 등록한 모듈은 훅 내에서 함수의 우선순위에 대하여 반드시 명시하여야 한다. 코어 네트워킹 코드로부터 넷필터 훅이 호출되는 경우, 각 포인트에 등록된 각각의 모듈은 우선순위에 따라 호출이 되고, 패킷을 자유로이 다룰 수 있다. 모듈은 넷필터에게 다음의 다섯 가지 동작을 하도록 요청한다.

  1. NF_ACCEPT: 보통처럼 계속 진행시킨다.

  2. NF_DROP: 패킷을 버린다. 즉 계속 진행시키지 않는다.

  3. NF_STOLEN: 패킷을 접수하겠다. 즉 계속 진행시키지 않는다.

  4. NF_QUEUE: 패킷을 큐로 보낸다.(보통 사용자 공간에서의 처리를 목적으로 한다.)

  5. NF_REPEAT: 현재 훅을 다시 호출한다.

넷필터의 다른 부분은 뒤에 나오는 커널 부분에서 다루기로 한다.

이상과 같은 것이 기초가 되어, 저자들은 다음 두 절에 보인 것과 같은 복잡한 패킷 처리를 만들 수 있다.

3.2. 패킷 선택: IP Tables

IP table을 호출하는 패킷 선택 시스템은 넷필터 프레임웍을 기반으로 구성되었으며, 이는 확장성을 가지고 ipchains로부터 직접 물려받은 유산이다.(ipchains는 ipfwadm으로부터 물려받고, ipfwadm은 BSD의 ipfw IIRC로부터 물려받았다.) 커널 모듈은 새로운 테이블을 등록할 수 있으며, 임의의 패킷이 주어진 테이블을 통과하도록 요청할 수 있다. 이러한 패킷 선택 방법은 패킷 필터링(즉 `필터' 테이블), 네트웍 주소 변환(`nat' 테이블) 그리고 종합적인 pre-route 패킷 mangling(`mangling' 테이블')에 사용한다.

넷필터에 등록된 훅은 다음과 같다.(여기서는 각각의 함수가 실제로 호출되는 순서로 각각의 훅에 있는 함수와 같이 보였다.)
   --->PRE------>[ROUTE]--->FWD---------->POST------>
       Conntrack    |       Filter   ^    NAT (Src)
       Mangle       |                |    Conntrack
       NAT (Dst)    |             [ROUTE]
       (QDisc)      v                |
                    IN Filter       OUT Conntrack
                    |  Conntrack     ^  Mangle
                    |                |  NAT (Dst)
                    v                |  Filter
		

3.2.1. 패킷 필터링

`filter'라는 테이블은 패킷을 절대로 변경시키지 않고 단지 걸러내기만 한다.

ipchains와 비교했을 때, iptables filter의 장점 중 하나는 작고 빠르다는 것이며, NF_IP_LOCAL_IN과 NF_IP_FORWARD, NF_IP_LOCAL_OUT 시점에서 넷필터로 훅킹된다. 이는, 주어진 패킷에 대하여 이를 필터링 하는 위치가 오직 하나 뿐이라는 것을 의미한다. 결국 사용자들이 ipchains를 사용한 것보다 더 단순하게 만들며, 또한 넷필터 프레임웍이 NF_IP_FORWARD 훅에 대하여 입력과 출력 인터페이스를 제공한다는 사실은 다양한 필터링이 훨씬 단순해진다는 것을 의미한다.

주: 필자는 업그레이드의 필요 없이 기존의 ipfwadm과 ipchains를 사용 가능하도록 넷필터의 최상위에 모듈로서 ipchains와 ipfwadm의 커널부분을 포팅 하였다.

3.2.2. NAT

이는 `nat' 테이블의 영역으로, 두 가지의 넷필터 훅으로 패킷을 전달한다. 즉, non-local 패킷에 대해, 각각 목적지와 소스 전환에 대하여 NF_IP_PRE_ROUTING과 NF_IP_POST_ROUTING 훅이 완벽하게 동작한다. CONFIG_IP_NF_NAT_LOCAL이 정의된 경우, NF_IP_LOCAL_OUT과 NF_IP_LOCAL_IN 훅이 로컬 패킷의 목적지를 전환하기 위해 사용된다.

이 테이블은 `filter' 테이블과는 약간 다르며, 새로운 커넥션의 첫 번째 패킷만이 테이블로 전달된다. 따라서 이와 같은 전달의 결과는 동일한 커넥션에 있어서 향후 전달되는 모든 패킷에 적용된다.

3.2.3. 매스커레이딩, 포트 포워딩, 투명한 프락시

필자는 NAT를 출발지 NAT(즉 첫 번째 패킷이 출발지를 변경하는 경우)와 목적지 NAT(첫 번째 패킷이 목적지를 변경하는 경우)로 구분하였다.

매스커레이딩은 출발지 NAT의 특별한 경우이며, 포트 포워딩과 투명한 프락시는 목적지 NAT의 특별한 경우이다. 이와 같은 것은 서로 독립적인 엔티티를 가지고 NAT 프레임웍을 이용하여 구현되었다.

3.2.4. 패킷 맹글링(packet mangling)

패킷 맹글링 테이블(`mangling' table)은 패킷의 정보를 실제로 변경하기 위해 사용되며, NF_IP_PRE_ROUTING과 NF_IP_LOCAL_OUT 시점에서 넷필터로 훅킹된다.

3.3. 연결 추적

연결추적(connection tracking)은 NAT의 기본이지만, 모듈로 분리되어 구현된다. 이는 연결추적을 단순하고 명확하게 사용할 수 있도록 패킷 필터링 코드에 대한 확장성을 제공한다.(`state' 모듈)

3.4. 그이외 추가된 사항

새로운 유연성 때문에 정말로 무서운 일을 겪을 기회가 많아졌지만, 다른 사람들이 향상된 코드를 작성하거나 기존의 코드를 완전히 대체해 버릴 수 있는 기회 역시 많아졌다.