본문 바로가기

nftables

체인 설정 / Configuring chains

source: https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains

이전 글: 테이블 설정 / Configuring tables

다음 글: 룰 설정 / Simple rule management

 

iptables 처럼 nftables에서도 체인에 rule을 선언하여 추가할 수 있습니다. 다만 iptables과 달리, INPUT, OUTOUT, FORWARD와 같은 pre-defined chain은 없습니다. 패켓을 필터링하기 위해서 base chain을 생성하고, 그것을 netfilter hook에 추가하여 줍니다. 설정을 매우 유연하게 해 주며, 불필요한 pre-defined chain에 의한 지연을 피할 수 있게 해 줍니다.  

 

netfilter hook에 대해서는 https://www.teldat.com/blog/en/nftables-and-netfilter-hooks-via-linux-kernel/와 https://wiki.nftables.org/wiki-nftables/index.php/Netfilter_hooks를 참고하기 바랍니다. 패켓이 시스템에 들어오면 아래 그림과 같이 개념적인 경로를 지나가는데, 이 경로에 있는 prerouting, input, output, forward, postrouting을 hook 이라고 합니다. nftables에서는 table과 chain을 선언하고 ruleset을 만들어 각 hook에 적용합니다. 그래서 hook을 지나는 패켓은 그곳에 적용된 table/chain/ruleset에 따라 통과(accept)되거나 차단(drop) 됩니다. 

 

netfilter hooks

 

Base chain 추가

base chain은 hook에 기본으로 적용하는 chain입니다. 따라서 chain을 추가할 때 type, hook, priority를 선언해 줘야 합니다. 

% nft add chain [<family>] <table-name> <chain-name> { type <type> hook <hook> priority <value> \; [policy <policy>] }

다음은 family ip에 대해 table:foo에 새로운 chain input을 input hook에 base chain으로 추가하는 예입니다. table:foo는 먼저 생성했다고 가정합니다.  

salsal@r3:~$ sudo nft list chains
table inet filter {
	chain input {
		type filter hook input priority 0; policy accept;
	}
	chain forward {
		type filter hook forward priority 0; policy accept;
	}
	chain output {
		type filter hook output priority 0; policy accept;
	}
}
table ip filter {
}
table ip foo {
}

# shell에서 중괄호를 입력할 때 작은 따옴표로 감싸줘야 제대로 입력할 수 있습니다. 
# table foo에 chain input을 추가하는 예입니다. 

salsal@r3:~$ sudo nft 'add chain ip foo input { type filter hook input priority 0 ; }'

salsal@r3:~$ sudo nft list chains
table inet filter {
	chain input {
		type filter hook input priority 0; policy accept;
	}
	chain forward {
		type filter hook forward priority 0; policy accept;
	}
	chain output {
		type filter hook output priority 0; policy accept;
	}
}
table ip filter {
}
table ip foo {
	chain input {
		type filter hook input priority 0; policy accept;
	}
}

위와 같이 설정을 했다면 hook input에는 2가지 chain이 적용되어 있는 것입니다. 다만 priority가 0 으로 둘 다 동일하며 어떤 것이 먼저 적용될지는 알 수 없습니다. 

  • table inet filter - chain input 
  • table ip foo - chain input

아래와 같이 설정을 하였을 때 Input hook을 보여줍니다. priority 숫자가 적은 것을 먼저 적용합니다. 

salsal@r3:~$ sudo nft add table ip myfilter
salsal@r3:~$ sudo nft add chain ip myfilter foo '{ type filter hook input priority 0; }'
salsal@r3:~$ sudo nft add chain ip myfilter bar '{ type filter hook input priority 50; }’

salsal@r3:~$ sudo nft list chains
table inet filter {
	chain input {
		type filter hook input priority 0; policy accept;
	}
	chain forward {
		type filter hook forward priority 0; policy accept;
	}
	chain output {
		type filter hook output priority 0; policy accept;
	}
}
table ip filter {
}
table ip foo {
	chain input {
		type filter hook input priority 0; policy accept;
	}
}
table ip myfilter {
	chain foo {
		type filter hook input priority 0; policy accept;
	}
	chain bar {
		type filter hook input priority 50; policy accept;
	}
}

아래 그램을 보면 input hook에 4개의 chain이 적용된 것을 알 수 있습니다. 3개는 prioiry 0으로 값이 같아 어떤 것이 먼저 적용될지 알 수는 없지만, 1개(bar)는 마지막에 적용됩니다. 

 

nft 를 nft interacive mode에서 이용할 수도 있습니다. 

salsal@r3:~$ sudo nft -i
nft> list chains
table inet filter {
	chain input {
		type filter hook input priority 0; policy accept;
	}
	chain forward {
		type filter hook forward priority 0; policy accept;
	}
	chain output {
		type filter hook output priority 0; policy accept;
	}
}
table ip filter {
}
table ip foo {
	chain input {
		type filter hook input priority 0; policy accept;
	}
}
nft> quit

 

다음은 family ip에 대해 table:foo에 새로운 base chain output 을 추가하는 예입니다. 그리고 이것을 hook output에 적용합니다. 

salsal@r3:~$ sudo nft 'add chain ip foo outoput {type filter hook output priority 0;}'
salsal@r3:~$ sudo nft list table ip foo
table ip foo {
	chain outoput {
		type filter hook output priority 0; policy accept;
	}
}

Base chain types

chain은 3개의 형태가 있습니다. 

filter: 패켓 필터링(허용/차단)에 이용합니다. table arp, bridge, ip, ip6, inet 에서 이용할 수 있습니다. 

route: ip header를 변경하여 re-route 할 경우에 이용합니다. iptables에서 이용하는 mangle과 비슷합니다. 다만 output hook에만 적용할 수 있으며, table ip, ip6, inet 에서만 이용할 수 있습니다. 

nat: NAT (network address translation)에서 이용합니다. 패켓 필터링(허용/차단) 목적으로 이용하지 말아야 합니다. table ip, ip6, inet에서만 이용할 수 있습니다. 

 

아래 표는 chain 형태(filter, nat, route)별로 적용할 수 있는 family와 hook을 정리한 내용입니다. 

chain 형태별, 지원되는 netfilter hook

Base chain hook

사용할 수 있는 hook은 6개입니다. ingress, prerouting, input, forward, output, postrouting 입니다. 

ingress: 시스템의 NIC driver을 통과하자마자 prerouting hook보다 먼저 패켓을 처리하는 영역입니다. family inet과 netdev에만 적용할 수 있습니다. 

prerouting: 경로를 결정하기 전에 (before routing) 패켓을 처리하는 영역입니다. 패켓을 수신한 시스템이 목적지인 패켓이나, 시스템을 경유하는 패켓 모두 이 hook에 적용된 chain의 영향을 받습니다. 

input: 목적지가 시스템인 패켓을 처리하는 영역입니다. 

forward: 시스템을 경유하는 패켓을 처리하는 영역입니다. 

output: 시스템에서 발생한 패켓을 처리하는 영역입니다. 

postrouting: 시스템을 떠나는 패켓을 처리하는 영역입니다. 

 

netfilter hooks

 

Base chain priority

chain에 적용된 priority 숫자가 작을수록 hook 안에서는 먼저 처리합니다. 그런데 먼저 처리한 chain에서 패켓을 DROP하면 나머지 chain을 처리하지 않습니다. 먼저 처리한 chain에서 패켓을 ACCEPT 하면, 다름 priority를 가진 chain을 처리합니다. 

Base chain policy

2개 정책(판결)이 있습니다. 하나는 accept, 다른 하나는 drop 입니다. policy를 선언하지 않으면 default는 accept 입니다. 

accept: 이것으로 선언한 패켓은 chain을 통과하여 다른 chain이나 hook으로 계속 흘러갑니다. 

drop: 이것으로 선언한 패켓은 즉시 차단됩니다. 

Regular chain 추가

iptables에서 user-defined chain을 생성하듯, nftables 에서도 user-defined chain을 생성할 수 있습니다. chain_name은 임의의 문자열입니다. 

% nft add chain ip <table_name> <chain_name>

Base chain 추가하는 방법과 다르게 '{ type <type> hook <hook> priority <value> \; [policy <policy>] }'를 입력하지 않습니다. 즉 regular chain은 hook에 포함되어 있지 않으므로 패켓을 처리하지 않습니다. 그러나 base chain에서 regular chain을 호출하여 패켓 처리를 하게할 수 있습니다. regular chain을 호출하는 방법으로 jumpvmaps를 이용합니다. 

 

Chain 삭제

chain을 추가한 것처럼 삭제할 수 있습니다. 

% nft delete chain [<family>] <table-name> <chain-name>

아래는 chain bar가 포함된 table 입니다. chain foo와 chain bar가 있는데 여기에서 chain foo를 삭제합니다. 

salsal@r3:~$ sudo nft list table ip myfilter
table ip myfilter {
	chain foo {
		type filter hook input priority 0; policy accept;
	}

	chain bar {
		type filter hook input priority 50; policy accept;
	}
}
salsal@r3:~$ sudo nft delete chain ip myfilter foo
salsal@r3:~$ sudo nft list table ip myfilter
table ip myfilter {
	chain bar {
		type filter hook input priority 50; policy accept;
	}
}

 

Flushing chain

chain 아래 포함된 ruleset을 모두 삭제합니다. 

% nft flush chain <table-name> <chain-name>

아래는 chain bar 밑에 있는 ruleset을 모두 flush 하는 예입니다. flush는 ruleset만 지울뿐이며, base chain 관련 설정값 (type filter hook input priority 50; policy accept;) 을 지우지 않습니다. 

salsal@r3:~$ sudo nft list table ip myfilter
table ip myfilter {
	chain bar {
		type filter hook input priority 50; policy accept;
		ip daddr 8.8.8.9 counter packets 0 bytes 0
	}
}

# nft flush chain <table-name> <chain-name>
#
salsal@r3:~$ sudo nft flush chain myfilter bar

salsal@r3:~$ sudo nft list table ip myfilter
table ip myfilter {
	chain bar {
		type filter hook input priority 50; policy accept;
	}
}