I regularly configure IPv6 firewalls, and while services are relatively straight forward, there is an awful lot of ICMPv6 that needs to be handled in different ways. Fortunately the IETF issued RFC4890 as advice on this.
This is my attempt to summarise the basics from RFC4890 about what ICMPv6 should be treated how. I have probably made quite a few errors, so let me know if you spot any.
There is an example ip6tables script in Appendix B of RFC4890 which may be of use. I also provide some script snippets at the end of each section.
Individual host / firewall interfaces
These are packets which are not forwarded but are addressed to or handled (eg. multicast) by the host it's self rather than passed on to another address. With ip6tables these would be on the INPUT chain.
Always ACCEPT (4.4.1):
-
destination-unreachable* (1)
-
packet too big* (2)
-
time exceeded* (3) - code 0 only
-
parameter problem* (4) - code 1 & 2 only
-
echo request (useful)
Normally ACCEPT (4.4.2):
-
time exceeded* (3) - code 1
-
should only result from congestion so less important
-
parameter problem* (4) - code 0
-
would need human intervention (stack bug) so not much use
ACCEPT if hop limit == 255 (4.4.1):
-
router solicitation (133)
-
router advertisement (134)
-
neighbour solicitation (135)
-
neighbour advertisement (136)
-
inverse neighbour discovery solicitation (141)
-
inverse neighbour discovery advertisement (142)
-
certificate path solicitation (148)
-
certificate path advertisement (149)
ACCEPT if LL source address (4.4.1):
-
listener query (130)
-
listener report (131)
-
listener done (132)
-
listener report v2 (143)
ACCEPT if hop limit == 1, LL source address (4.4.1):
-
multicast router advertisement (151)
-
multicast router solicitation (152)
-
multicast router termination (153)
Shound be dropped anyway (4.4.3):
-
router renumbering (138)
-
home agent address discovery request (144)
-
home agent address discovery reply (145)
-
mobile prefix solicitation (146)
-
mobile prefix advertisement (147)
-
seamoby experimental (150)
Should have policy (4.4.4):
-
redirect (137)
-
node information query (139)
-
node information response (140)
-
unallocated error messages* (5-99,102-126)
DROP (4.4.5):
-
experimental (100,101,200,201)
-
extension types (127,255)
-
unallocated informational messages (154-199,202-254)
* = these should only be seen in response to other packets so with ip6tables a RELATED state should allow these
Code
Some shell (/bin/sh) code for filtering inbound (ip6tables INPUT chain) ICMP, with the assumption that the default policy/rule for the INPUT chain is DROP.... if not then see Marcus Ranum's site:
IP6TABLES=/sbin/ip6tables
ICMP6_LL=fe80::/10
ICMP6_MULTICAST=ff00::/8
ICMP6_ACCEPT_RESP="
destination-unreachable
packet-too-big
time-exceeded
bad-header
unknown-header-type
echo-reply
"
ICMP6_ACCEPT="
echo-request
"
ICMP6_HL255_ACCEPT="
router-solicitation
router-advertisement
neighbour-solicitation
neighbour-advertisement
141
142
148
149
"
ICMP6_LL_ACCEPT="
130
131
132
143
"
ICMP6_LOCAL_HL1_LL_ACCEPT="
151
152
153
"
for type in $ICMP6_ACCEPT_RESP; do
ip6tables --append INPUT --proto icmpv6 --icmpv6-type $type \
--match state --state RELATED --jump ACCEPT
done
for type in $ICMP6_ACCEPT; do
ip6tables --append INPUT --proto icmpv6 --icmpv6-type $type \
--match state --state NEW --jump ACCEPT
done
for type in $ICMP6_HL255_ACCEPT; do
ip6tables --append INPUT --proto icmpv6 --icmpv6-type $type \
--match state --state NEW \
--match hl --hl-eq 255 \
--jump ACCEPT
done
for type in $ICMP6_LL_ACCEPT; do
ip6tables --append INPUT --proto icmpv6 --icmpv6-type $type \
--source $ICMP6_LL \
--match state --state NEW \
--jump ACCEPT
done
for type in $ICMP6_LOCAL_HL1_LL_ACCEPT; do
ip6tables --append INPUT --proto icmpv6 --icmpv6-type $type \
--source $ICMP6_LL \
--match state --state NEW \
--match hl --hl-eq 1 \
--jump ACCEPT
done
ip6tables --append INPUT --proto icmpv6 \
--match state --state ESTABLISHED --jump ACCEPT
Forwarding (routing) firewalls
These will be on site boundaries and will be routing only traffic that will be off the local network. With ip6tables these would be on the FORWARD chain.
Always ACCEPT (4.3.1):
-
destination-unreachable* (1)
-
packet too big* (2)
-
time exceeded* (3) - code 0 only
-
parameter problem* (4) - code 1 & 2 only
-
echo request/response (useful)
Normally ACCEPT (4.3.2):
-
time exceeded* (3) - code 1
-
should only result from congestion so less important
-
parameter problem* (4) - code 0
-
would need human intervention (stack bug) so not much use
Shound be dropped anyway (4.3.3):
You may want to catch those with hop limit == 1 to stop Time Exceeded messages being generated, or maybe just drop the lot.
-
router solicitation (133)
-
router advertisement (134)
-
neighbor soloicitaion (135)
-
neighbor advertisement (136)
-
redirect (137)
-
inverse neighbor discovery solicitation (141)
-
inverse neighbor discovery advertisement (142)
-
listener query (130)
-
listener report (131)
-
listener done (132)
-
listener report v2 (143)
-
certificate path solicitation (148)
-
certificate path advertisement (149)
-
multicast router advertisement (151)
-
multicast router solicitation (152)
-
multicast router termination (153)
Should have policy (4.3.4):
-
seamoby experimental (150)
-
unallocated error messages* (5-99,102-126)
-
unallocated informational messages (154-199,202-254)
DROP (4.3.5):
-
node information query (139)
-
node information response (140)
-
router renumbering (138)
-
experimental (100,101,200,201)
-
extension types (127,255)
* = these should only be seen in response to other packets so with ip6tables a RELATED state should allow these
Code
Some shell (/bin/sh) code for filtering forwarded (ip6tables FORWARD chain) ICMP, with the assumption that the default policy/rule for the FORWARD chain is DROP.... if not then see Marcus Ranum's site:
ICMP6_ACCEPT_RESP="
destination-unreachable
packet-too-big
time-exceeded
bad-header
unknown-header-type
echo-reply
"
ICMP6_ACCEPT="
echo-request
"
for type in $ICMP6_ACCEPT_RESP; do
ip6tables --append FORWARD \
--proto icmpv6 --icmpv6-type $type \
--match state --state ESTABLISHED,RELATED --jump ACCEPT
done
for type in $ICMP6_ACCEPT; do
ip6tables --append INPUT \
--proto icmpv6 --icmpv6-type $type \
--match state --state NEW,ESTABLISHED,RELATED --jump ACCEPT
ip6tables --append FORWARD \
--proto icmpv6 --icmpv6-type $type \
--match state --state NEW,ESTABLISHED,RELATED --jump ACCEPT
done
Bridging (transparent) firewalls
Bridge filtering firewalls pass local network traffic which will be needed (eg. neighbor discovery) for hosts as well as traffic going over site boundaries.
As such, bridging firewalls will be filtering both of the above functions and really will need both sets of rules configuring with due care to filter according to it being a local network packet or from beyond site boundaries as to which rules to apply.