Один фаервол для IPv4 и IPv6 (iptables и ip6tables)

    После настройки IPv6 появляется задача настройки фаервола для нового протокола. Ниже я предлагаю свой скрипт, который позволяет настроить фаервол сразу для IPv4 и IPv6. Хотя общих правил для обоих фаерволов получилось не так уж и много, мне всё-таки удобнее править один общий файл, чем два разных.


    Рассматривать будем самую обычную сеть с одним подключением к интернету и одной локальной сетью за фаерволом. Для локальной сети в IPv4 нужно сделать NAT, в IPv6 нужно маршрутизировать и фильтровать пакеты.

    Если у вас просто один компьютер, то убирая все упоминания о локальной сети получим подходящий фаервол.

    Особых пояснений не привожу, нужно просто исправить несколько переменных в начале и несколько «таблиц» в середине.

    #!/bin/bash<br>
    # License: GPL3<br>
    # Author: Dmitri Gribenko <gribozavr@gmail.com><br>
    <br>

    LAN_IF="eth0"<br>
    INET_IF="eth1"<br>
    INET_IP="192.0.2.123"<br>
    INET6_IF="he-ipv6"<br>
    <br>

    # for dynamic IPs:<br>
    # INET_IP=$(get_ip_ipv4 $INET_IF)<br>
    <br>
    LOOPBACK_IF="lo"<br>
    <br>
    IPTABLES="/sbin/iptables"<br>
    IP6TABLES="/sbin/ip6tables"<br>

    #IPTABLES="echo 4"<br>
    #IP6TABLES="echo 6"<br>
    IP="/sbin/ip"<br>
    <br>
    # IPs that need to be NAT'ed to our $INET_IP.<br>
    NAT_IPV4='<br>

    192.168.1.3  pc1<br>
    192.168.1.4  pc2<br>
    192.168.1.5<br>
    '<br>
    <br>
    # Set to 0 to disable updating IPv4 or IPv6 firewall.<br>
    DO_IPV4="1"<br>

    DO_IPV6="1"<br>
    <br>
    function get_ip_ipv4<br>
    {<br>
      $IP addr show dev $1 primary | sed -n -e '/^\s*inet / s/^\s*inet \(.*\)\/.\{1,2\} .*$/\1/ p'<br>

    }<br>
    <br>
    ipt4()<br>
    {<br>
      [ "$DO_IPV4" = "1" ] && $IPTABLES "$@"<br>
    }<br>

    <br>
    ipt6()<br>
    {<br>
      [ "$DO_IPV6" = "1" ] && $IP6TABLES "$@"<br>
    }<br>
    <br>
    ipt46()<br>

    {<br>
      ipt4 "$@"<br>
      ipt6 "$@"<br>
    }<br>
    <br>
    ##############################################################################<br>
    ################################ filter table ################################<br>
    ##############################################################################<br>

    <br>
    ipt46 -t filter -P INPUT   ACCEPT<br>
    ipt46 -t filter -P OUTPUT  ACCEPT<br>
    ipt46 -t filter -P FORWARD ACCEPT<br>

    <br>
    ipt46 -t filter -F<br>
    ipt46 -t filter -X<br>
    <br>
    FILTER_CHAINS46="bad_tcp inet_input inet_output inet_banned_input inet_banned_output inet_tcp_input inet_tcp_output inet_udp_input inet_udp_output"<br>
    for i in $FILTER_CHAINS46; do<br>

      ipt46 -t filter -N $i<br>
      ipt46 -t filter -F $i<br>
    done<br>
    <br>
    FILTER_CHAINS4="inet_icmp_input inet_icmp_output"<br>

    for i in $FILTER_CHAINS4; do<br>
      ipt4  -t filter -N $i<br>
      ipt4  -t filter -F $i<br>

    done<br>
    <br>
    FILTER_CHAINS6="inet_icmpv6_input inet_icmpv6_output inet_icmpv6_forward"<br>
    for i in $FILTER_CHAINS6; do<br>
      ipt6  -t filter -N $i<br>

      ipt6  -t filter -F $i<br>
    done<br>
    <br>
    #################################<br>
    ## filter -- INPUT<br>
    ##<br>
    <br>
    # allow ipv6 in ipv4<br>

    ipt4  -t filter -A INPUT -p ipv6 -j ACCEPT<br>
    <br>
    ipt46 -t filter -A INPUT -i $LOOPBACK_IF -j ACCEPT<br>

    ipt46 -t filter -A INPUT -i $LAN_IF      -j ACCEPT<br>
    ipt4  -t filter -A INPUT -i $INET_IF     -j inet_input<br>

    ipt6  -t filter -A INPUT -i $INET6_IF    -j inet_input<br>
    <br>
    #ipt46 -t filter -A INPUT -m limit --limit 3/minute --limit-burst 3 -j LOG --log-level INFO --log-prefix "IPT INPUT packet died: "<br>
    #ipt46 -t filter -A INPUT -j LOG --log-level INFO --log-prefix "IPT INPUT packet died: "<br>

    ipt46 -t filter -A INPUT -j DROP<br>
    <br>
    #################################<br>
    ## filter -- OUTPUT<br>
    ##<br>
    <br>
    ipt46 -t filter -A OUTPUT -o $LOOPBACK_IF -j ACCEPT<br>

    ipt46 -t filter -A OUTPUT -o $LAN_IF      -j ACCEPT<br>
    ipt4  -t filter -A OUTPUT -o $INET_IF     -j inet_output<br>

    ipt6  -t filter -A OUTPUT -o $INET6_IF    -j inet_output<br>
    <br>
    #ipt46 -t filter -A OUTPUT -j LOG --log-level INFO --log-prefix "IPT OUTPUT: "<br>
    ipt46 -t filter -A OUTPUT -j ACCEPT<br>

    <br>
    #################################<br>
    ## filter -- bad_tcp<br>
    ##<br>
    <br>
    ipt46 -t filter -A bad_tcp -p tcp -m state --state NEW ! --syn -j DROP<br>

    ipt46 -t filter -A bad_tcp        -m state --state INVALID -j DROP<br>
    <br>
    ipt46 -t filter -A bad_tcp -j RETURN<br>

    <br>
    ################################<br>
    ## filter -- inet_input<br>
    ##<br>
    <br>
    # filter out bad packets so they don't even reach other checks<br>
    ipt46 -t filter -A inet_input        -j inet_banned_input<br>

    ipt46 -t filter -A inet_input -p tcp -j bad_tcp<br>
    <br>
    ipt46 -t filter -A inet_input -m state --state ESTABLISHED,RELATED -j ACCEPT<br>

    <br>
    ipt46 -t filter -A inet_input -p tcp    -j inet_tcp_input<br>
    ipt46 -t filter -A inet_input -p udp    -j inet_udp_input<br>

    ipt4  -t filter -A inet_input -p icmp   -j inet_icmp_input<br>
    ipt6  -t filter -A inet_input -p icmpv6 -j inet_icmpv6_input<br>

    ipt4  -t filter -A inet_input -p igmp   -j ACCEPT<br>
    <br>
    ipt46 -t filter -A inet_input -j RETURN<br>

    <br>
    ################################<br>
    ## filter -- inet_output<br>
    ##<br>
    <br>
    ipt46 -t filter -A inet_output -j inet_banned_output<br>
    <br>

    # allow established -- fast path<br>
    ipt46 -t filter -A inet_output -m state --state ESTABLISHED,RELATED -j ACCEPT<br>
    <br>
    ipt46 -t filter -A inet_output -p tcp    -j inet_tcp_output<br>

    ipt46 -t filter -A inet_output -p udp    -j inet_udp_output<br>
    ipt4  -t filter -A inet_output -p icmp   -j inet_icmp_output<br>

    ipt6  -t filter -A inet_output -p icmpv6 -j inet_icmpv6_output<br>
    ipt4  -t filter -A inet_output -p igmp   -j ACCEPT<br>

    <br>
    ipt46 -t filter -A inet_output -j RETURN<br>
    <br>
    #################################<br>
    ## filter -- inet_banned_input, inet_banned_output<br>
    ##<br>
    <br>

    # Drop packets from private, local and reserved addresses.<br>
    # You can add 10.0.0.0/8 if your ISP doesn't use it.<br>
    # You can also add 224.0.0.0/4 if you don't use multicast.<br>
    for ip in 172.16.0.0/12 192.168.0.0/16 127.0.0.0/8 240.0.0.0/5; do<br>
      ipt4  -t filter -A inet_banned_input   -s $ip -j DROP<br>

      ipt4  -t filter -A inet_banned_output  -d $ip -j REJECT --reject-with icmp-admin-prohibited<br>
    done<br>
    <br>
    if [ -e /etc/firewall/inet_banned4 ]; then<br>

      while read ext_ip; do<br>
        ipt4  -t filter -A inet_banned_input  -s $ext_ip -j DROP<br>
        ipt4  -t filter -A inet_banned_output -d $ext_ip -j REJECT --reject-with icmp-admin-prohibited<br>

      done < /etc/firewall/inet_banned4<br>
    fi<br>
    <br>
    if [ -e /etc/firewall/inet_banned6 ]; then<br>
      while read ext_ip; do<br>

        ipt6  -t filter -A inet_banned_input  -s $ext_ip -j DROP<br>
        ipt6  -t filter -A inet_banned_output -d $ext_ip -j REJECT --reject-with adm-prohibited<br>

      done < /etc/firewall/inet_banned6<br>
    fi<br>
    <br>
    ipt46 -t filter -A inet_banned_input  -j RETURN<br>
    ipt46 -t filter -A inet_banned_output -j RETURN<br>

    <br>
    #################################<br>
    ## filter -- inet_tcp_input<br>
    ##<br>
    <br>
    while read proto port comment; do<br>
      if [ -n "$proto" ]; then<br>

        $proto -t filter -A inet_tcp_input -p tcp --dport $port -j ACCEPT<br>
      fi<br>
    done <<__EOF__<br>
    ipt46 20          ftp-data<br>

    ipt46 21          ftp<br>
    ipt46 12500:13000 ftp-data<br>
    <br>
    ipt46 22          ssh<br>
    __EOF__<br>
    <br>
    # drop all MS stuff so that it won't clutter logs<br>
    ipt46 -t filter -A inet_tcp_input -p tcp -m multiport --ports 137,138,139,445 -j DROP<br>

    <br>
    ipt46 -t filter -A inet_tcp_input -j RETURN<br>
    <br>
    #################################<br>
    ## filter -- inet_tcp_output<br>
    ##<br>
    <br>

    # drop all MS stuff so that it won't clutter logs<br>
    ipt46 -t filter -A inet_tcp_output -p tcp -m multiport --ports 137,138,139,445 -j DROP<br>

    <br>
    ipt46 -t filter -A inet_tcp_output -j RETURN<br>
    <br>
    #################################<br>
    ## filter -- inet_udp_input<br>
    ##<br>
    <br>

    # iptv<br>
    ipt4  -t filter -A inet_udp_input -p udp -d 224.0.0.0/4 -j ACCEPT<br>
    <br>
    # drop all MS stuff so that it won't clutter logs<br>

    ipt46 -t filter -A inet_udp_input -p udp -m multiport --ports 137,138,139,445 -j DROP<br>

    <br>
    # some unknown flood on my ISP's net<br>
    ipt4  -t filter -A inet_udp_input -p udp --dport 631 -j DROP<br>
    <br>
    ipt46 -t filter -A inet_udp_input -j RETURN<br>

    <br>
    #################################<br>
    ## filter -- inet_udp_output<br>
    ##<br>
    <br>
    # drop all MS stuff so that it won't clutter logs<br>
    ipt46 -t filter -A inet_udp_output -p udp -m multiport --ports 137,138,139,445 -j DROP<br>

    <br>
    ipt46 -t filter -A inet_udp_output -j RETURN<br>
    <br>
    #################################<br>
    ## filter -- inet_icmp_input<br>
    ##<br>
    <br>

    # echo-reply should be handled by conntrack<br>
    ipt4  -t filter -A inet_icmp_input -p icmp -m icmp --icmp-type echo-request            -j ACCEPT<br>
    ipt4  -t filter -A inet_icmp_input -p icmp -m icmp --icmp-type time-exceeded           -j ACCEPT<br>

    ipt4  -t filter -A inet_icmp_input -p icmp -m icmp --icmp-type destination-unreachable -j ACCEPT<br>
    ipt4  -t filter -A inet_icmp_input -p icmp -j DROP<br>

    <br>
    ipt4  -t filter -A inet_icmp_input -j RETURN<br>
    <br>
    #################################<br>
    ## filter -- inet_icmp_output<br>
    ##<br>
    <br>

    ipt4  -t filter -A inet_icmp_output -j RETURN<br>
    <br>
    #################################<br>
    ## filter -- inet_icmpv6_input<br>
    ##<br>
    <br>
    # See RFC 4890.<br>

    <br>
    # echo-reply should be handled by conntrack<br>
    ipt6  -t filter -A inet_icmpv6_input -p icmpv6 -m icmp6 --icmpv6-type echo-request            -j ACCEPT<br>

    ipt6  -t filter -A inet_icmpv6_input -p icmpv6 -m icmp6 --icmpv6-type destination-unreachable -j ACCEPT<br>
    ipt6  -t filter -A inet_icmpv6_input -p icmpv6 -m icmp6 --icmpv6-type packet-too-big          -j ACCEPT<br>

    ipt6  -t filter -A inet_icmpv6_input -p icmpv6 -m icmp6 --icmpv6-type time-exceeded           -j ACCEPT<br>
    ipt6  -t filter -A inet_icmpv6_input -p icmpv6 -m icmp6 --icmpv6-type parameter-problem       -j ACCEPT<br>

    <br>
    ipt6  -t filter -A inet_icmpv6_input -p icmpv6 -m icmp6 --icmpv6-type router-solicitation     -m hl --hl-eq 255 -j ACCEPT<br>

    ipt6  -t filter -A inet_icmpv6_input -p icmpv6 -m icmp6 --icmpv6-type router-advertisement    -m hl --hl-eq 255 -j ACCEPT<br>

    ipt6  -t filter -A inet_icmpv6_input -p icmpv6 -m icmp6 --icmpv6-type neighbour-solicitation  -m hl --hl-eq 255 -j ACCEPT<br>

    ipt6  -t filter -A inet_icmpv6_input -p icmpv6 -m icmp6 --icmpv6-type neighbour-advertisement -m hl --hl-eq 255 -j ACCEPT<br>

    ipt6  -t filter -A inet_icmpv6_input -p icmpv6 -m icmp6 --icmpv6-type redirect                -m hl --hl-eq 255 -j ACCEPT<br>

    ipt6  -t filter -A inet_icmpv6_input -p icmpv6 -m icmp6 --icmpv6-type 141                     -m hl --hl-eq 255 -j ACCEPT # Inverse neighbour discovery solicitation<br>

    ipt6  -t filter -A inet_icmpv6_input -p icmpv6 -m icmp6 --icmpv6-type 142                     -m hl --hl-eq 255 -j ACCEPT # Inverse neighbour discovery advertisement<br>

    <br>
    ipt6  -t filter -A inet_icmpv6_input -p icmpv6 -s fe80::/10 -m icmp6 --icmpv6-type 130 -j ACCEPT # Listener query<br>

    ipt6  -t filter -A inet_icmpv6_input -p icmpv6 -s fe80::/10 -m icmp6 --icmpv6-type 131 -j ACCEPT # Listener report<br>

    ipt6  -t filter -A inet_icmpv6_input -p icmpv6 -s fe80::/10 -m icmp6 --icmpv6-type 132 -j ACCEPT # Listener done<br>

    ipt6  -t filter -A inet_icmpv6_input -p icmpv6 -s fe80::/10 -m icmp6 --icmpv6-type 143 -j ACCEPT # Listener report v2<br>

    <br>
    ipt6  -t filter -A inet_icmpv6_input -p icmpv6 -m icmp6 --icmpv6-type 148 -m hl --hl-eq 255 -j ACCEPT # Certificate path solicitation<br>

    ipt6  -t filter -A inet_icmpv6_input -p icmpv6 -m icmp6 --icmpv6-type 149 -m hl --hl-eq 255 -j ACCEPT # Certificate path advertisement<br>

    <br>
    ipt6  -t filter -A inet_icmpv6_input -p icmpv6 -s fe80::/10 -m icmp6 --icmpv6-type 151 -m hl --hl-eq 1 -j ACCEPT # Multicast router advertisement<br>

    ipt6  -t filter -A inet_icmpv6_input -p icmpv6 -s fe80::/10 -m icmp6 --icmpv6-type 152 -m hl --hl-eq 1 -j ACCEPT # Multicast router solicitation<br>

    ipt6  -t filter -A inet_icmpv6_input -p icmpv6 -s fe80::/10 -m icmp6 --icmpv6-type 153 -m hl --hl-eq 1 -j ACCEPT # Multicast router termination<br>

    <br>
    ipt6  -t filter -A inet_icmpv6_input -j RETURN<br>
    <br>
    #################################<br>
    ## filter -- inet_icmpv6_output<br>
    ##<br>
    <br>

    ipt6  -t filter -A inet_icmpv6_output -j RETURN<br>
    <br>
    #################################<br>
    ## filter -- inet_icmpv6_forward<br>
    ##<br>
    <br>
    ipt6  -t filter -A inet_icmpv6_forward -p icmpv6 -m icmp6 --icmpv6-type echo-request            -j ACCEPT<br>

    ipt6  -t filter -A inet_icmpv6_forward -p icmpv6 -m icmp6 --icmpv6-type destination-unreachable -j ACCEPT<br>
    ipt6  -t filter -A inet_icmpv6_forward -p icmpv6 -m icmp6 --icmpv6-type packet-too-big          -j ACCEPT<br>

    ipt6  -t filter -A inet_icmpv6_forward -p icmpv6 -m icmp6 --icmpv6-type time-exceeded           -j ACCEPT<br>
    ipt6  -t filter -A inet_icmpv6_forward -p icmpv6 -m icmp6 --icmpv6-type parameter-problem       -j ACCEPT<br>

    <br>
    ipt6  -t filter -A inet_icmpv6_forward -j RETURN<br>
    <br>
    #################################<br>
    ## filter -- FORWARD<br>
    ##<br>
    <br>

    ipt46 -t filter -A FORWARD -i $INET_IF -j inet_banned_input<br>
    ipt46 -t filter -A FORWARD -o $INET_IF -j inet_banned_output<br>

    ipt46 -t filter -A FORWARD -p tcp -j bad_tcp<br>
    <br>
    # don't forward MS stuff<br>
    ipt46 -t filter -A FORWARD -p tcp -m multiport --ports 137,138,139,445 -j DROP<br>

    ipt46 -t filter -A FORWARD -p udp -m multiport --ports 137,138,139,445 -j DROP<br>

    <br>
    ipt6  -t filter -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT<br>
    <br>
    ipt6  -t filter -A FORWARD -p icmpv6 -j inet_icmpv6_forward<br>

    <br>
    while read proto port ip comment; do<br>
      if [ -n "$proto" ]; then<br>
        ipt6 -t filter -A FORWARD -d $ip -p $proto --dport $port -j ACCEPT<br>

      fi<br>
    done <<__EOF__<br>
    tcp 22 ::/0 ssh<br>
    tcp 80 2001:db8::1 http<br>
    __EOF__<br>
    <br>
    ipt6  -t filter -A FORWARD -i $INET6_IF -p tcp -j REJECT --reject-with tcp-reset<br>

    ipt6  -t filter -A FORWARD -i $INET6_IF -j DROP<br>
    ipt6  -t filter -A FORWARD -o $INET6_IF -j ACCEPT<br>

    <br>
    echo "$NAT_IPV4" | while read int_ip comment; do<br>
      if [ -n "$int_ip" ]; then<br>

        ipt4  -t filter -A FORWARD -s $int_ip -o $INET_IF -j ACCEPT<br>
        ipt4  -t filter -A FORWARD -d $int_ip -i $INET_IF -j ACCEPT<br>

      fi<br>
    done<br>
    <br>
    #ipt46 -t filter -A FORWARD -j LOG --log-level INFO --log-prefix "IPT FORWARD packet died: "<br>
    ipt46 -t filter -A FORWARD -j DROP<br>
    <br>

    ##############################################################################<br>
    ################################ mangle table ################################<br>
    ##############################################################################<br>
    <br>
    ipt46 -t mangle -P INPUT       ACCEPT<br>
    ipt46 -t mangle -P OUTPUT      ACCEPT<br>

    ipt46 -t mangle -P FORWARD     ACCEPT<br>
    ipt46 -t mangle -P PREROUTING  ACCEPT<br>
    ipt46 -t mangle -P POSTROUTING ACCEPT<br>

    <br>
    ipt46 -t mangle -F<br>
    ipt46 -t mangle -X<br>
    <br>
    ##############################################################################<br>
    ################################## nat table #################################<br>
    ##############################################################################<br>

    <br>
    ipt4  -t nat -P OUTPUT      ACCEPT<br>
    ipt4  -t nat -P PREROUTING  ACCEPT<br>
    ipt4  -t nat -P POSTROUTING ACCEPT<br>

    <br>
    ipt4  -t nat -F<br>
    ipt4  -t nat -X<br>
    <br>
    ####################################<br>
    ## nat -- PREROUTING<br>
    ##<br>

    <br>
    # Port forwarding<br>
    while read proto port int_ip comment; do<br>
      if [ -n "$proto" ]; then<br>

        ipt4  -t nat -A PREROUTING -i $INET_IF -p $proto --dport $port -j DNAT --to-destination $int_ip:$port<br>

      fi<br>
    done <<__EOF__<br>
    tcp 1234 192.168.1.3 something<br>
    udp 5678 192.168.1.3 something else<br>
    __EOF__<br>
    <br>
    ####################################<br>
    ## nat -- POSTROUTING<br>
    ##<br>

    <br>
    echo "$NAT_IPV4" | while read int_ip comment; do<br>
      if [ -n "$int_ip" ]; then<br>

        ipt4  -t nat -A POSTROUTING -s $int_ip -o $INET_IF -j SNAT --to-source $INET_IP<br>
      fi<br>
    done<br>

    <br>
    echo 1 > /proc/sys/net/ipv4/ip_forward<br>
    <br>
    ##<br>
    ## __END__<br>
    #################################


    Скачать: bin-login.name/rc.firewall.txt
    Здесь можно проверить работу фаервола для TCP в IPv6: www.subnetonline.com/pages/ipv6-network-tools/online-ipv6-port-scanner.php
    Поделиться публикацией

    Похожие публикации

    Комментарии 8

      0
      Хозяин — барин, конечно. Но стоит ли дублировать текстовик по ссылке? Тем более в целевом дебиане или убунте браузер всё равно txt скорее всего откроет во вкладке рядом для просмотра, а не сохранит. :)
        0
        Не мне конечно объяснять, но клик правой кнопкой -> Сохранить как. Из топика копировать не удобно, а отдельный текстовый файл можно легко сохранить.
          0
          Всё верно, только я как раз и имел в виду, что полотенце в топике — не верх эргономичности, при наличии удобного источника сразу после него. ;)
        0
        Объясните, зачем в конец некоторых цепочек вставлено "-j RETURN". Это ж вроде действие по умолчанию.
        И ещё, почему б не объединить, например,
        --dport 137
        --dport 138
        --dport 139

        в
        --dport 137:139

        Ещё можно объединить 4 фрагмента "# drop all MS stuff so that it won't clutter logs" в один с циклом.

        И, наконец, как я понимаю, этот скрипт — не панацея, а, скорее, некоторые идеи администратору на заметку.
          0
          > Объясните, зачем в конец некоторых цепочек вставлено "-j RETURN". Это ж вроде действие по умолчанию.

          Спасибо, не знал. Просто всегда так писал правила.

          > И ещё, почему б не объединить

          Да их вообще можно как-то красиво вынести, но не вижу как будет красивее. Поэтому пока оставил копи-пастой, так как у меня там ещё свои правила рядом, которые режут «локальный» флуд, встречающийся только в моей сети.

          > И, наконец, как я понимаю, этот скрипт — не панацея, а, скорее, некоторые идеи администратору на заметку.

          Конечно. Но в среднестатистической в вакууме локальной сети с 1 подключением к интернету в этом скрипте должно быть достаточно только изменить IP и вписать свои открываемые порты. По крайней мере, я на это ориентировался.
          0
          В FreeBSD-CURRENT (9) уже произошло объединение конфигов IPv4 и IPv6 ipfw в один файл. Тенденция.
            0
            Когда начинаешь писать второй конфиг отдельно, сразу чувствуешь, что делаешь одно и то же два раза.
            0
            Сама идея вполне нормальная и удобная, у самого правила iptables генерятся ruby-скриптом;)

            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

            Самое читаемое