Upgrade to Pro — share decks privately, control downloads, hide ads and more …

nftables: the Next Generation Firewall in Linux

Avatar for Tomofumi Hayashi Tomofumi Hayashi
June 06, 2015
92

nftables: the Next Generation Firewall in Linux

Presented in Kernel/VM tankentai vol.11, June 6, 2015.

Avatar for Tomofumi Hayashi

Tomofumi Hayashi

June 06, 2015
Tweet

Transcript

  1. お詫び • LinuxConとネタが被りましたww – 気付いたのは発表申し込みした後です… • タイトルは意図的にダブらせました • LinuxCon怖いところ…っ! –

    こわいのでLinuxConには参加していません – 内容がLinuxConとダブっていたら申し訳ありません – ↑の内容知ってる人いらっしゃいましたら後で教えて下さい • 知らないなりにカーネル/VMらしい発表をする方向で
  2. お詫び • LinuxConとネタが被りましたwwせんでした – 気付いたのは2日前です… • タイトルは意図的にダブらせました • LinuxCon怖いところ…っ! –

    こわいのでLinuxConには参加していません – 内容がLinuxConとダブっていたら申し訳ありません – ↑の内容知ってる人いらっしゃいましたら後で教えて下さい • 知らないなりにカーネル/VMらしい発表をする方向で
  3. netfilter, iptables and nftables? • netfilter – Linux にあるパケット書き換えのフレームワーク –

    NAT, NAPT, IP MASQUERADE等を実装 – conntrackもnetfilterの機能 • iptables, ip6tables, ebtables and arptables – netfilterを使って実装したパケットフィルタリング コマンド – ‘-m udp’のように必要な機能がコマンド・カーネルで拡張されている – fedora‘s ’firewalld‘ も実際呼んでるのはこのコマンド • nftables <- これ! – パケットフィルタリングコマンド – iptables等と同様にnetfilterを使用している
  4. netfilter, iptables and nftables? • netfilter – Linux にあるパケット書き換えのフレームワーク –

    NAT, NAPT, IP MASQUERADE等を実装 – conntrackもnetfilterの機能 • iptables, ip6tables, ebtables and arptables – netfilterを使って実装したパケットフィルタリング コマンド – ‘-m udp’のように必要な機能がコマンド・カーネルで拡張されている – fedora‘s ’firewalld‘ も実際呼んでるのはこのコマンド • nftables <- これ! – パケットフィルタリングコマンド – iptables等と同様にnetfilterを使用している
  5. netfilter, iptables and nftables? なので、hookを指定して自分の関数を登録すれば以下のような カーネルがパケットを処理するタイミングでその関数が呼ばれ ることになります net/ipv4/ip_forward.c: int ip_forward(struct

    sk_buff *skb) { u32 mtu; struct iphdr *iph; /* Our header */ struct rtable *rt; /* Route we use */ struct ip_options *opt = &(IPCB(skb)->opt); (snip) return NF_HOOK(NFPROTO_IPV4, NF_INET_FORWARD, skb, skb->dev, rt->dst.dev, ip_forward_finish); sr_failed: (snip) } SKB!!
  6. netfilter, iptables and nftables? • netfilter – Linux にあるパケット書き換えのフレームワーク –

    NAT, NAPT, IP MASQUERADE等を実装 – conntrackもnetfilterの機能 • iptables, ip6tables, ebtables and arptables – netfilterを使って実装したパケットフィルタリング コマンド – ‘-m udp’のように必要な機能がコマンド・カーネルで拡張されている – fedora‘s ’firewalld‘ も実際呼んでるのはこのコマンド • nftables <- これ! – パケットフィルタリングコマンド – iptables等と同様にnetfilterを使用している
  7. {ip,ip6,arp,eb}tables? 各種通信プロトコル・ネットワーク機能毎に以下のコマ ンドが存在します • IPv4: iptables • IPv6: ip6tables •

    ARP: arptables (ロードバランサ・LVS/Linux Virtual Server等で使用) • Bridge: ebtables (カーネルのBridge内で処理)
  8. netfilter, iptables and nftables? • netfilter – Linux にあるパケット書き換えのフレームワーク –

    NAT, NAPT, IP MASQUERADE等を実装 – conntrackもnetfilterの機能 • iptables, ip6tables, ebtables and arptables – netfilterを使って実装したパケットフィルタリング コマンド – ‘-m udp’のように必要な機能がコマンド・カーネルで拡張されている – fedora‘s ’firewalld‘ も実際呼んでるのはこのコマンド • nftables <- 今日はこれ! – パケットフィルタリングコマンド – iptables等と同様にnetfilterを使用している
  9. nftables? iptablesが持つ技術的負債 • iptablesが産まれたのは1999年11月 – http://www.netfilter.org/about.html#history – 16年経過! • Extension

    Modulesの増加 – 現在70個以上のModuleが存在 – それぞれカーネル側・ユーザランド側に存在 • プロトコル毎に別コマンド – 似たようなコードが各種コマンドに存在 • そもそもシンタックス・ルールが複雑化
  10. nftablesの使い方 • カーネルにNF_TABLES(と好きなOPTION)を付けてビルド • ユーザ側のコマンドをビルド (Gentooならばnet- firewall/nftables をemerge) • iptablesを使っている場合はiptablesを止める

    (モジュールのビルド・ロードだけならば大丈夫) • `service nftables start`等でサービスを開始 • `nft`コマンドでルールの追加・削除が可能 – `nft –f <filename>`でファイルからの読み込み – `nft –i`でインタラクティブモード nft_test ~ $ nft -i nft> list tables table nat table filter nft>
  11. nftablesのシンタックス % sudo iptables -t filter -S -P INPUT ACCEPT

    -P FORWARD ACCEPT -P OUTPUT ACCEPT -N ssh_whitelist -A INPUT -i lo -j ACCEPT -A INPUT -p tcp -m tcp --dport 22 --tcp-flags FIN,SYN,RST,ACK SYN –j ssh_whitelist // (略) -A ssh_whitelist -s 192.168.0.0/16 -j ACCEPT -A ssh_whitelist -s 10.0.0.0/8 -j ACCEPT -A ssh_whitelist -j DROP nftables: # nft list table ip filter table ip filter { chain input { type filter hook input priority 0; } chain forward { type filter hook forward priority 0; iif eth0 oif != eth0 jump miniupnpd drop } chain output { type filter hook output priority 0; } chain miniupnpd { iif eth0 ip daddr 192.168.1.10 tcp dport ssh accept } } iptables:
  12. nftablesのフロー libnftnl/examples/nft-rule-get でルールを見ると… ip saddr 192.168.1.0/24 oif eth0 snat 10.0.0.1

    => ip nat postrouting 7 6 [ payload load 4b @ network header + 12 => reg 1 ] [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ] [ cmp eq reg 1 0x0001a8c0 ] [ meta load oif => reg 1 ] [ cmp eq reg 1 0x00000004 ] [ immediate reg 1 0x100000a ] [ nat snat ip addr_min reg 1 addr_max reg 1 ]
  13. nftables (internal) カーネル内のnftablesのフィルタリング実装はpseudo- state machineとして実装されています • bpf (Berkeley Packet Filter)

    からインスパイア (*1原文ママ) – 4 registers – 1 verdict (e.g. 'accept', 'drop', 'jump' or so ...) – A extensive instruction set reject, meta, masq, bitwise, byteorder, cmp, counter, ct (conntrack), exthdr, immediate, limit, log, lookup, nat, payload, queue (順不同、適当に検索) *1 http://www.slideshare.net/ennael/2013-kernel-recipesnftables
  14. nftables (internal) カーネル内のnftablesのフィルタリング実装はpseudo- state machineとして実装されています = カーネル内のVM → カーネル/VM!! •

    bpf (Berkeley Packet Filter) からインスパイア (*1原文ママ) – 4 registers – 1 verdict (e.g. 'accept', 'drop', 'jump' or so ...) – A extensive instruction set reject, meta, masq, bitwise, byteorder, cmp, counter, ct (conntrack), exthdr, immediate, limit, log, lookup, nat, payload, queue (順不同、適当に検索) *1 http://www.slideshare.net/ennael/2013-kernel-recipesnftables
  15. nftablesの読み方 libnftnl/examples/nft-rule-get ip saddr 192.168.1.0/24 oif eth0 snat 10.0.0.1 =>

    ip nat postrouting 7 6 [ payload load 4b @ network header + 12 => reg 1 ] [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ] [ cmp eq reg 1 0x0001a8c0 ] [ meta load oif => reg 1 ] [ cmp eq reg 1 0x00000004 ] [ immediate reg 1 0x100000a ] [ nat snat ip addr_min reg 1 addr_max reg 1 ]
  16. nftablesの読み方 libnftnl/examples/nft-rule-get ip saddr 192.168.1.0/24 oif eth0 snat 10.0.0.1 =>

    ip nat postrouting 7 6 // 7:handle, 6:position [ payload load 4b @ network header + 12 => reg 1 ] ネットワークヘッダの12byte (saddr)から4byteロードしてreg1に [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ] reg1を0x00ffffffでマスクして0でxorをreg1に [ cmp eq reg 1 0x0001a8c0 ] reg1 が 0x0001a8c0と比較(0x0001a8c0 => 192.168.1.0) もしマッチしないならばここでリターン [ meta load oif => reg 1 ] [ cmp eq reg 1 0x00000004 ] [ immediate reg 1 0x100000a ] [ nat snat ip addr_min reg 1 addr_max reg 1 ] ip saddr 192.168.1.0/24
  17. nftablesの読み方 libnftnl/examples/nft-rule-get ip saddr 192.168.1.0/24 oif eth0 snat 10.0.0.1 =>

    ip nat postrouting 7 6 [ payload load 4b @ network header + 12 => reg 1 ] [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ] [ cmp eq reg 1 0x0001a8c0 ] [ meta load oif => reg 1 ] oifのifindex値をreg1に [ cmp eq reg 1 0x00000004 ] reg1と0x4を比較 [ immediate reg 1 0x100000a ] [ nat snat ip addr_min reg 1 addr_max reg 1 ] oif eth0
  18. nftablesの読み方 libnftnl/examples/nft-rule-get ip saddr 192.168.1.0/24 oif eth0 snat 10.0.0.1 =>

    ip nat postrouting 7 6 [ payload load 4b @ network header + 12 => reg 1 ] [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ] [ cmp eq reg 1 0x0001a8c0 ] [ meta load oif => reg 1 ] [ cmp eq reg 1 0x00000004 ] [ immediate reg 1 0x100000a ] reg1に0x100000aを代入 (0x100000a = 10.0.0.1) [ nat snat ip addr_min reg 1 addr_max reg 1 ] snatを行なう (sourceはreg1に入っている値) snat 10.0.0.1
  19. nftablesの読み方 libnftnl/examples/nft-rule-get ip saddr 192.168.1.0/24 oif eth0 snat 10.0.0.1 =>

    ip nat postrouting 7 6 [ payload load 4b @ network header + 12 => reg 1 ] [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ] [ cmp eq reg 1 0x0001a8c0 ] [ meta load oif => reg 1 ] [ cmp eq reg 1 0x00000004 ] [ immediate reg 1 0x100000a ] [ nat snat ip addr_min reg 1 addr_max reg 1 ]
  20. nftablesの読み方 libnftnl/examples/nft-rule-get ip saddr 192.168.1.0/24 oif eth0 snat 10.0.0.1 =>

    ip nat postrouting 7 6 [ payload load 4b @ network header + 12 => reg 1 ] [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ] [ cmp eq reg 1 0x0001a8c0 ] [ meta load oif => reg 1 ] [ cmp eq reg 1 0x00000004 ] [ immediate reg 1 0x100000a ] [ nat snat ip addr_min reg 1 addr_max reg 1 ] ね、簡単でしょ?
  21. Agenda • 自己紹介 • nftablesについて • nftablesの使い方 • nftablesの読み方 •

    nftablesの内部のVMコードの書き方 • 宣伝 • まとめ
  22. nftablesにルールを書きたい! libnftnlを使うことでnftablesのルールを追加・削除することが可 能です • libnftnl/examples/* と libnftnl/tests/* を参考にすれば、ほら この通り! e

    = nft_rule_expr_alloc("nat"); nft_rule_expr_set_u32(e, NFT_EXPR_NAT_TYPE, NFT_NAT_SNAT); nft_rule_expr_set_u32(e, NFT_EXPR_NAT_FAMILY, AF_INET); nft_rule_expr_set_u32(e, NFT_EXPR_NAT_REG_ADDR_MIN, NFT_REG_1); nft_rule_expr_set_u32(e, NFT_EXPR_NAT_REG_ADDR_MAX, NFT_REG_1); nft_rule_add_expr(r, e); [ immediate reg 1 0x100000a ] [ nat snat ip addr_min reg 1 addr_max reg 1 ] =>
  23. nftablesにルールを書きたい! libnftnlを使うことでnftablesのルールを追加・削除することが可 能です • libnftnl/examples/* と libnftnl/tests/* を参考にすれば、ほら この通り! e

    = nft_rule_expr_alloc("nat"); nft_rule_expr_set_u32(e, NFT_EXPR_NAT_TYPE, NFT_NAT_SNAT); nft_rule_expr_set_u32(e, NFT_EXPR_NAT_FAMILY, AF_INET); nft_rule_expr_set_u32(e, NFT_EXPR_NAT_REG_ADDR_MIN, NFT_REG_1); nft_rule_expr_set_u32(e, NFT_EXPR_NAT_REG_ADDR_MAX, NFT_REG_1); nft_rule_add_expr(r, e); [ immediate reg 1 0x100000a ] [ nat snat ip addr_min reg 1 addr_max reg 1 ] =>
  24. nftablesにルールを書きたい! nl = mnl_socket_open(NETLINK_NETFILTER); if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0)

    { perror("mnl_socket_bind"); return -1; } } batch = mnl_nlmsg_batch_start(buf, sizeof(buf)); nft_mnl_batch_put(mnl_nlmsg_batch_current(batch), NFNL_MSG_BATCH_BEGIN, seq++); mnl_nlmsg_batch_next(batch); nlh = nft_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), cmd, nft_rule_attr_get_u32(rule, NFT_RULE_ATTR_FAMILY), NLM_F_APPEND|NLM_F_CREATE|NLM_F_ACK, seq++); nft_rule_nlmsg_build_payload(nlh, rule); nft_rule_free(rule); mnl_nlmsg_batch_next(batch); nft_mnl_batch_put(mnl_nlmsg_batch_current(batch), NFNL_MSG_BATCH_END, seq++); mnl_nlmsg_batch_next(batch); ret = mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch)); mnl_nlmsg_batch_stop(batch); ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); ret = mnl_cb_run(buf, ret, 0, mnl_socket_get_portid(nl), NULL, NULL); Netlink (libnml等)でカーネルに送信!!!
  25. nftablesにルールを書きたい! nl = mnl_socket_open(NETLINK_NETFILTER); if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0)

    { perror("mnl_socket_bind"); return -1; } } batch = mnl_nlmsg_batch_start(buf, sizeof(buf)); nft_mnl_batch_put(mnl_nlmsg_batch_current(batch), NFNL_MSG_BATCH_BEGIN, seq++); mnl_nlmsg_batch_next(batch); nlh = nft_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), cmd, nft_rule_attr_get_u32(rule, NFT_RULE_ATTR_FAMILY), NLM_F_APPEND|NLM_F_CREATE|NLM_F_ACK, seq++); nft_rule_nlmsg_build_payload(nlh, rule); nft_rule_free(rule); mnl_nlmsg_batch_next(batch); nft_mnl_batch_put(mnl_nlmsg_batch_current(batch), NFNL_MSG_BATCH_END, seq++); mnl_nlmsg_batch_next(batch); ret = mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch)); mnl_nlmsg_batch_stop(batch); ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); ret = mnl_cb_run(buf, ret, 0, mnl_socket_get_portid(nl), NULL, NULL); ほら、 簡単でしょ? Netlink (libnml等)でカーネルに送信!!!