RFC Errata
Found 3 records.
Status: Verified (2)
RFC 4890, "Recommendations for Filtering ICMPv6 Messages in Firewalls", May 2007
Source of RFC: v6ops (ops)
Errata ID: 2706
Status: Verified
Type: Technical
Publication Format(s) : TEXT
Reported By: Phil Whineray
Date Reported: 2011-02-06
Verifier Name: ron bonica
Date Verified: 2011-03-03
Section Appendix B. says:
if [ "$STATE_ENABLED" -eq "1" ] then # Allow incoming time exceeded code 0 messages # only for existing sessions for inner_prefix in $INNER_PREFIXES do ip6tables -A icmpv6-filter -m state -p icmpv6 \ -d $inner_prefix \ --state ESTABLISHED,RELATED --icmpv6-type packet-too-big \ -j ACCEPT done else # Allow incoming time exceeded code 0 messages for inner_prefix in $INNER_PREFIXES do ip6tables -A icmpv6-filter -p icmpv6 -d $inner_prefix \ --icmpv6-type ttl-zero-during-transit -j ACCEPT done fi
It should say:
if [ "$STATE_ENABLED" -eq "1" ] then # Allow incoming time exceeded code 0 messages # only for existing sessions for inner_prefix in $INNER_PREFIXES do ip6tables -A icmpv6-filter -m state -p icmpv6 \ -d $inner_prefix \ --state ESTABLISHED,RELATED --icmpv6-type ttl-zero-during-transmit \ -j ACCEPT done else # Allow incoming time exceeded code 0 messages for inner_prefix in $INNER_PREFIXES do ip6tables -A icmpv6-filter -p icmpv6 -d $inner_prefix \ --icmpv6-type ttl-zero-during-transit -j ACCEPT done fi
Notes:
Not sure if this is really editorial as it is in the example code, not the main RFC.
In any case, the example incorrectly specifies an icmpv6 type in one code path.
Errata ID: 3985
Status: Verified
Type: Technical
Publication Format(s) : TEXT
Reported By: James Robertson
Date Reported: 2014-05-13
Verifier Name: Joel Jaeggli
Date Verified: 2014-05-19
Section Appendix B says:
if [ "$STATE_ENABLED" -eq "1" ] then # Allow incoming time exceeded code 0 messages # only for existing sessions for inner_prefix in $INNER_PREFIXES do ip6tables -A icmpv6-filter -m state -p icmpv6 \ -d $inner_prefix \ --state ESTABLISHED,RELATED --icmpv6-type packet-too-big \ -j ACCEPT done else # Allow incoming time exceeded code 0 messages for inner_prefix in $INNER_PREFIXES do ip6tables -A icmpv6-filter -p icmpv6 -d $inner_prefix \ --icmpv6-type ttl-zero-during-transit -j ACCEPT done fi
It should say:
if [ "$STATE_ENABLED" -eq "1" ] then # Allow incoming time exceeded code 0 messages # only for existing sessions for inner_prefix in $INNER_PREFIXES do ip6tables -A icmpv6-filter -m state -p icmpv6 \ -d $inner_prefix \ --state ESTABLISHED,RELATED --icmpv6-type ttl-zero-during-transit \ -j ACCEPT done else # Allow incoming time exceeded code 0 messages for inner_prefix in $INNER_PREFIXES do ip6tables -A icmpv6-filter -p icmpv6 -d $inner_prefix \ --icmpv6-type ttl-zero-during-transit -j ACCEPT done fi
Notes:
RFC 4890 Errata ID 2706 states that icmpv6-type packet-too-big should
state icmpv6-type ttl-zero-during-transmit. This should read
ttl-zero-during-transit.
Status: Reported (1)
RFC 4890, "Recommendations for Filtering ICMPv6 Messages in Firewalls", May 2007
Source of RFC: v6ops (ops)
Errata ID: 7922
Status: Reported
Type: Technical
Publication Format(s) : TEXT
Reported By: William N.
Date Reported: 2024-05-03
Section Appendix B says:
#!/bin/bash # Set of prefixes on the trusted ("inner") side of the firewall export INNER_PREFIXES="2001:DB8:85::/60" # Set of hosts providing services so that they can be made pingable export PINGABLE_HOSTS="2001:DB8:85::/64" # Configuration option: Change this to 1 if errors allowed only for # existing sessions export STATE_ENABLED=0 # Configuration option: Change this to 1 if messages to/from link # local addresses should be filtered. # Do not use this if the firewall is a bridge. # Optional for firewalls that are routers. export FILTER_LINK_LOCAL_ADDRS=0 # Configuration option: Change this to 0 if the site does not support # Mobile IPv6 Home Agents - see Appendix A.14 export HOME_AGENTS_PRESENT=1 # Configuration option: Change this to 0 if the site does not support # Mobile IPv6 mobile nodes being present on the site - # see Appendix A.14 export MOBILE_NODES_PRESENT=1 ip6tables -N icmpv6-filter ip6tables -A FORWARD -p icmpv6 -j icmpv6-filter # Match scope of src and dest else deny # This capability is not provided for in base ip6tables functionality # An extension (agr) exists which may support it. #@TODO@ # ECHO REQUESTS AND RESPONSES # =========================== # Allow outbound echo requests from prefixes which belong to the site for inner_prefix in $INNER_PREFIXES do ip6tables -A icmpv6-filter -p icmpv6 -s $inner_prefix \ --icmpv6-type echo-request -j ACCEPT done # Allow inbound echo requests towards only predetermined hosts for pingable_host in $PINGABLE_HOSTS do ip6tables -A icmpv6-filter -p icmpv6 -d $pingable_host \ --icmpv6-type echo-request -j ACCEPT done if [ "$STATE_ENABLED" -eq "1" ] then # Allow incoming and outgoing echo reply messages # only for existing sessions ip6tables -A icmpv6-filter -m state -p icmpv6 \ --state ESTABLISHED,RELATED --icmpv6-type \ echo-reply -j ACCEPT else # Allow both incoming and outgoing echo replies for pingable_host in $PINGABLE_HOSTS do # Outgoing echo replies from pingable hosts ip6tables -A icmpv6-filter -p icmpv6 -s $pingable_host \ --icmpv6-type echo-reply -j ACCEPT done # Incoming echo replies to prefixes which belong to the site for inner_prefix in $INNER_PREFIXES do ip6tables -A icmpv6-filter -p icmpv6 -d $inner_prefix \ --icmpv6-type echo-reply -j ACCEPT done fi # Deny icmps to/from link local addresses # If the firewall is a router: # These rules should be redundant as routers should not forward # link local addresses but to be sure... # DO NOT ENABLE these rules if the firewall is a bridge if [ "$FILTER_LINK_LOCAL_ADDRS" -eq "1" ] then ip6tables -A icmpv6-filter -p icmpv6 -d fe80::/10 -j DROP ip6tables -A icmpv6-filter -p icmpv6 -s fe80::/10 -j DROP fi # Drop echo replies which have a multicast address as a # destination ip6tables -A icmpv6-filter -p icmpv6 -d ff00::/8 \ --icmpv6-type echo-reply -j DROP # DESTINATION UNREACHABLE ERROR MESSAGES # ====================================== if [ "$STATE_ENABLED" -eq "1" ] then # Allow incoming destination unreachable messages # only for existing sessions for inner_prefix in $INNER_PREFIXES do ip6tables -A icmpv6-filter -m state -p icmpv6 \ -d $inner_prefix \ --state ESTABLISHED,RELATED --icmpv6-type \ destination-unreachable -j ACCEPT done else # Allow incoming destination unreachable messages for inner_prefix in $INNER_PREFIXES do ip6tables -A icmpv6-filter -p icmpv6 -d $inner_prefix \ --icmpv6-type destination-unreachable -j ACCEPT done fi # Allow outgoing destination unreachable messages for inner_prefix in $INNER_PREFIXES do ip6tables -A icmpv6-filter -p icmpv6 -s $inner_prefix \ --icmpv6-type destination-unreachable -j ACCEPT done # PACKET TOO BIG ERROR MESSAGES # ============================= if [ "$STATE_ENABLED" -eq "1" ] then # Allow incoming Packet Too Big messages # only for existing sessions for inner_prefix in $INNER_PREFIXES do ip6tables -A icmpv6-filter -m state -p icmpv6 \ -d $inner_prefix \ --state ESTABLISHED,RELATED \ --icmpv6-type packet-too-big \ -j ACCEPT done else # Allow incoming Packet Too Big messages for inner_prefix in $INNER_PREFIXES do ip6tables -A icmpv6-filter -p icmpv6 -d $inner_prefix \ --icmpv6-type packet-too-big -j ACCEPT done fi # Allow outgoing Packet Too Big messages for inner_prefix in $INNER_PREFIXES do ip6tables -A icmpv6-filter -p icmpv6 -s $inner_prefix \ --icmpv6-type packet-too-big -j ACCEPT done # TIME EXCEEDED ERROR MESSAGES # ============================ if [ "$STATE_ENABLED" -eq "1" ] then # Allow incoming time exceeded code 0 messages # only for existing sessions for inner_prefix in $INNER_PREFIXES do ip6tables -A icmpv6-filter -m state -p icmpv6 \ -d $inner_prefix \ --state ESTABLISHED,RELATED --icmpv6-type packet-too-big \ -j ACCEPT done else # Allow incoming time exceeded code 0 messages for inner_prefix in $INNER_PREFIXES do ip6tables -A icmpv6-filter -p icmpv6 -d $inner_prefix \ --icmpv6-type ttl-zero-during-transit -j ACCEPT done fi #@POLICY@ # Allow incoming time exceeded code 1 messages for inner_prefix in $INNER_PREFIXES do ip6tables -A icmpv6-filter -p icmpv6 -d $inner_prefix \ --icmpv6-type ttl-zero-during-reassembly -j ACCEPT done # Allow outgoing time exceeded code 0 messages for inner_prefix in $INNER_PREFIXES do ip6tables -A icmpv6-filter -p icmpv6 -s $inner_prefix \ --icmpv6-type ttl-zero-during-transit -j ACCEPT done #@POLICY@ # Allow outgoing time exceeded code 1 messages for inner_prefix in $INNER_PREFIXES do ip6tables -A icmpv6-filter -p icmpv6 -s $inner_prefix \ --icmpv6-type ttl-zero-during-reassembly -j ACCEPT done # PARAMETER PROBLEM ERROR MESSAGES # ================================ if [ "$STATE_ENABLED" -eq "1" ] then # Allow incoming parameter problem code 1 and 2 messages # for an existing session for inner_prefix in $INNER_PREFIXES do ip6tables -A icmpv6-filter -m state -p icmpv6 \ -d $inner_prefix \ --state ESTABLISHED,RELATED --icmpv6-type \ unknown-header-type \ -j ACCEPT ip6tables -A icmpv6-filter -m state -p icmpv6 \ -d $inner_prefix \ --state ESTABLISHED,RELATED \ --icmpv6-type unknown-option \ -j ACCEPT done fi # Allow outgoing parameter problem code 1 and code 2 messages for inner_prefix in $INNER_PREFIXES do ip6tables -A icmpv6-filter -p icmpv6 -s $inner_prefix \ --icmpv6-type unknown-header-type -j ACCEPT ip6tables -A icmpv6-filter -p icmpv6 -s $inner_prefix \ --icmpv6-type unknown-option -j ACCEPT done #@POLICY@ # Allow incoming and outgoing parameter # problem code 0 messages for inner_prefix in $INNER_PREFIXES do ip6tables -A icmpv6-filter -p icmpv6 \ --icmpv6-type bad-header \ -j ACCEPT done # NEIGHBOR DISCOVERY MESSAGES # =========================== # Drop NS/NA messages both incoming and outgoing ip6tables -A icmpv6-filter -p icmpv6 \ --icmpv6-type neighbor-solicitation -j DROP ip6tables -A icmpv6-filter -p icmpv6 \ --icmpv6-type neighbor-advertisement -j DROP # Drop RS/RA messages both incoming and outgoing ip6tables -A icmpv6-filter -p icmpv6 \ --icmpv6-type router-solicitation -j DROP ip6tables -A icmpv6-filter -p icmpv6 \ --icmpv6-type router-advertisement -j DROP # Drop Redirect messages both incoming and outgoing ip6tables -A icmpv6-filter -p icmpv6 --icmpv6-type redirect -j DROP # MLD MESSAGES # ============ # Drop incoming and outgoing # Multicast Listener queries (MLDv1 and MLDv2) ip6tables -A icmpv6-filter -p icmpv6 --icmpv6-type 130 -j DROP # Drop incoming and outgoing Multicast Listener reports (MLDv1) ip6tables -A icmpv6-filter -p icmpv6 --icmpv6-type 131 -j DROP # Drop incoming and outgoing Multicast Listener Done messages (MLDv1) ip6tables -A icmpv6-filter -p icmpv6 --icmpv6-type 132 -j DROP # Drop incoming and outgoing Multicast Listener reports (MLDv2) ip6tables -A icmpv6-filter -p icmpv6 --icmpv6-type 143 -j DROP # ROUTER RENUMBERING MESSAGES # =========================== # Drop router renumbering messages ip6tables -A icmpv6-filter -p icmpv6 --icmpv6-type 138 -j DROP # NODE INFORMATION QUERIES # ======================== # Drop node information queries (139) and replies (140) ip6tables -A icmpv6-filter -p icmpv6 --icmpv6-type 139 -j DROP ip6tables -A icmpv6-filter -p icmpv6 --icmpv6-type 140 -j DROP # MOBILE IPv6 MESSAGES # ==================== # If there are mobile ipv6 home agents present on the # trusted side allow if [ "$HOME_AGENTS_PRESENT" -eq "1" ] then for inner_prefix in $INNER_PREFIXES do #incoming Home Agent address discovery request ip6tables -A icmpv6-filter -p icmpv6 -d $inner_prefix \ --icmpv6-type 144 -j ACCEPT #outgoing Home Agent address discovery reply ip6tables -A icmpv6-filter -p icmpv6 -s $inner_prefix \ --icmpv6-type 145 -j ACCEPT #incoming Mobile prefix solicitation ip6tables -A icmpv6-filter -p icmpv6 -d $inner_prefix \ --icmpv6-type 146 -j ACCEPT #outgoing Mobile prefix advertisement ip6tables -A icmpv6-filter -p icmpv6 -s $inner_prefix \ --icmpv6-type 147 -j ACCEPT done fi # If there are roaming mobile nodes present on the # trusted side allow if [ "$MOBILE_NODES_PRESENT" -eq "1" ] then for inner_prefix in $INNER_PREFIXES do #outgoing Home Agent address discovery request ip6tables -A icmpv6-filter -p icmpv6 -s $inner_prefix \ --icmpv6-type 144 -j ACCEPT #incoming Home Agent address discovery reply ip6tables -A icmpv6-filter -p icmpv6 -d $inner_prefix \ --icmpv6-type 145 -j ACCEPT #outgoing Mobile prefix solicitation ip6tables -A icmpv6-filter -p icmpv6 -s $inner_prefix \ --icmpv6-type 146 -j ACCEPT #incoming Mobile prefix advertisement ip6tables -A icmpv6-filter -p icmpv6 -d $inner_prefix \ --icmpv6-type 147 -j ACCEPT done fi # DROP EVERYTHING ELSE # ==================== ip6tables -A icmpv6-filter -p icmpv6 -j DROP
It should say:
#!/bin/bash # Prefixes on the trusted ("inner") side of the firewall readonly inner_prefixes=( "2001:db8:85::/60" ) # Hosts providing services so that they can be made pingable readonly pingable_hosts=( "2001:db8:85::/64" ) # 1 - if errors are allowed only for existing sessions readonly state_enabled=0 # 1 - if messages to/from link local addresses should be filtered # Do not use this if the firewall is a bridge. # Optional for firewalls that are routers. readonly filter_linklocal_addrs=0 # 0 - if the site does not support Mobile IPv6 Home Agents # 1 - if there are mobile ipv6 home agents present on the trusted side # see Appendix A.14 readonly home_agents_present=1 # 0 - if the site does not support Mobile IPv6 mobile nodes # 1 - if there are roaming mobile nodes present on the trusted side # see Appendix A.14 readonly mobile_nodes_present=1 ip6tables -N icmpv6-filter ip6tables -A FORWARD -p icmpv6 -j icmpv6-filter state_args=( '--match' 'state' '--state' 'ESTABLISHED,RELATED' ) (( state_enabled == 0 )) && state_args=() readonly state_args # Helper functions filter() { ip6tables -A icmpv6-filter -p icmpv6 "${@}"; } accept() { filter "${@}" -j ACCEPT; } drop() { filter "${@}" -j DROP; } # Match scope of src and dest else deny # This capability is not provided for in base ip6tables functionality # An extension (agr) exists which may support it. #@TODO@ # ECHO REQUESTS AND RESPONSES # =========================== # Outbound echo requests from prefixes belonging to the site for inner_prefix in "${inner_prefixes[@]}"; do accept \ -s "${inner_prefix}" \ --icmpv6-type echo-request done # Inbound echo requests only towards predetermined hosts for pingable_host in "${pingable_hosts[@]}"; do accept \ -d "${pingable_host}" \ --icmpv6-type echo-request done if (( state_enabled == 1 )); then # Incoming and outgoing messages # only for existing sessions accept \ "${state_args[@]}" \ --icmpv6-type echo-reply else # Both incoming and outgoing echo replies for pingable_host in "${pingable_hosts[@]}"; do # Outgoing echo replies from pingable hosts accept \ -s "${pingable_host}" \ --icmpv6-type echo-reply done # Incoming echo replies to prefixes belonging to the site for inner_prefix in "${inner_prefixes[@]}"; do accept \ -d "${inner_prefix}" \ --icmpv6-type echo-reply done fi # Deny icmps to/from link local addresses # If the firewall is a router: # These rules should be redundant as routers should not forward # link local addresses but to be sure... # DO NOT ENABLE these rules if the firewall is a bridge if (( filter_linklocal_addrs == 1 )); then drop -d fe80::/10 drop -s fe80::/10 fi # No echo replies for multicast destination addresses drop \ -d ff00::/8 \ --icmpv6-type echo-reply for inner_prefix in "${inner_prefixes[@]}"; do # DESTINATION UNREACHABLE ERROR MESSAGES # ====================================== # incoming accept \ -d "${inner_prefix}" \ "${state_args[@]}" \ --icmpv6-type destination-unreachable # outgoing accept \ -s "${inner_prefix}" \ --icmpv6-type destination-unreachable # PACKET TOO BIG ERROR MESSAGES # ============================= # incoming accept \ -d "${inner_prefix}" \ "${state_args[@]}" \ --icmpv6-type packet-too-big # outgoing accept \ -s "${inner_prefix}" \ --icmpv6-type packet-too-big # TIME EXCEEDED ERROR MESSAGES # ============================ # incoming w/ code 0 accept \ -d "${inner_prefix}" \ "${state_args[@]}" \ --icmpv6-type 3/0 # @POLICY@ # incoming w/ code 1 accept \ -d "${inner_prefix}" \ --icmpv6-type 3/1 # outgoing w/ code 0 accept \ -s "${inner_prefix}" \ --icmpv6-type 3/0 # @POLICY@ # outgoing w/ code 1 accept \ -s "${inner_prefix}" \ --icmpv6-type 3/1 # PARAMETER PROBLEM ERROR MESSAGES # ================================ if (( state_enabled == 1 )); then # incoming accept \ -d "${inner_prefix}" \ "${state_args[@]}" \ --icmpv6-type 4/1 accept \ -d "${inner_prefix}" \ "${state_args[@]}" \ --icmpv6-type 4/2 fi # outgoing accept \ -s "${inner_prefix}" \ --icmpv6-type 4/1 accept \ -s "${inner_prefix}" \ --icmpv6-type 4/2 # @POLICY@ # incoming and outgoing accept --icmpv6-type 4/0 done # Drop all these, both incoming and outgoing types=( # NEIGHBOR DISCOVERY MESSAGES # =========================== '135/0' # Neighbor solicitation '136/0' # Neighbor advertisement '133/0' # Router solicitation '134/0' # Router advertisement '137/0' # Rredirect' # Multicast Listener Discovery messages # ===================================== 130 # ML queries (MLDv1 and MLDv2) 131 # ML reports (MLDv1) 132 # ML Done messages (MLDv1) 143 # ML reports (MLDv2) 138 # Router renumbering messages # NODE INFORMATION QUERIES # ======================== 139 # Node information queries 140 # Node information replies ) for type in "${types[@]}"; do drop --icmpv6-type "${type}" done # MOBILE IPv6 MESSAGES # ==================== for inner_prefix in "${inner_prefixes[@]}"; do if (( home_agents_present == 1 )); then # incoming Home Agent address discovery request accept \ -d "${inner_prefix}" \ --icmpv6-type 144 # outgoing Home Agent address discovery reply accept \ -s "${inner_prefix}" \ --icmpv6-type 145 # incoming Mobile prefix solicitation accept \ -d "${inner_prefix}" \ --icmpv6-type 146 # outgoing Mobile prefix advertisement accept \ -s "${inner_prefix}" \ --icmpv6-type 147 fi if (( mobile_nodes_present == 1 )); then # outgoing Home Agent address discovery request accept \ -s "${inner_prefix}" \ --icmpv6-type 144 # incoming Home Agent address discovery reply accept \ -d "${inner_prefix}" \ --icmpv6-type 145 # outgoing Mobile prefix solicitation accept \ -s "${inner_prefix}" \ --icmpv6-type 146 # incoming Mobile prefix advertisement accept \ -d "${inner_prefix}" \ --icmpv6-type 147 fi done # DROP EVERYTHING ELSE # ==================== drop
Notes:
- Fix ShellCheck SC2086 warnings
- Code formatting: improve redability
- Remove unnecessary export statements
- Make uppercase variables lowercase constants
- Make pingable_hosts and inner_prefixes arrays, so that for loops make sense
- Use lowercase IPv6 addresses, as commonly accepted
- Remove useless newlines at the beginning of if-checks and for-loops
- Reduce code repetition by using state_args array
- Combine separate loops in sections
-- DESTINATION UNREACHABLE ERROR MESSAGES
-- PACKET TOO BIG ERROR MESSAGES
-- TIME EXCEEDED ERROR MESSAGES
-- PARAMETER PROBLEM ERROR MESSAGES
- Create filter, accept and drop functions to simplify code
- Reduce code repetition by using type array
- Simplify comments. Comments should explain why something is done, not what is done. If code needs explanation about what it does, it is not readable
NOTE: The original does not seem to address type codes as advised and claimed in the comments. Additionally, there is one pointless loop in the example code. In my errata, I use numerical codes and types to address all this.
Please test the code thoroughly.
P.S. Ideally, this RFC would need an nftables version of this too.