FortiGate
FortiGate Next Generation Firewall utilizes purpose-built security processors and threat intelligence security services from FortiGuard labs to deliver top-rated protection and high performance, including encrypted traffic.
darisandy
Staff
Staff
Article Id 404791
Description This article describes how to configure custom ICMPv6 services on FortiGate to allow specific ICMPv6 types and codes while blocking others, and how to trigger IPv6 traffic to verify using Scapy.
Scope FortiGate.
Solution

In this scenario, FortiGate is configured to allow only ICMPv6 Type 128 Code 0.

This is an ICMPv6 Echo Request.

And to block any other Code number.

 

Topology :

 

FGT-A (port2) -- (port1)FGT-B(port2) -- Windows Machine.

FGT-A port2 : fd01:af0:8003:2::af/64.
FGT-B port1 : fd01:af0:8003:2::aa/64, port2 : fd01:af0:8005:2::af/64.
Windows Machine : fd01:af0:8005:2:45c3:2a0b:f009:521.

 

Configuration on FGT-B:

 

config firewall service custom
    edit "icmp6-128-0"
        set protocol ICMP6
        set icmptype 128
        set icmpcode 0
    next
end

 

config firewall policy
    edit 2
  --> Only to allow ICMPv6 Echo Request, Type 128 Code 0.
        set name "ipv6"
        set srcintf "port2"
        set dstintf "port1"
        set action accept
        set srcaddr6 "all"
        set dstaddr6 "all"
        set schedule "always"
        set service "icmp6-128-0"
        set logtraffic all
    next
    edit 3 
--> DENY other ICMPv6 type.
        set name "icmpv6"
        set srcintf "port2"
        set dstintf "port1"
        set srcaddr6 "all"
        set dstaddr6 "all"
        set schedule "always"
        set service "ALL_ICMP6"
        set logtraffic all
    next
end

 

To trigger IPv6 traffic from a Windows Machine, tools Scapy tool can be used.

Download and Installation

 

Scapy command to send ICMPv6 Echo Request:

 

send(IPv6(dst="fd01:af0:8003:2::af",src="fd01:af0:8005:2:45c3:2a0b:f009:521")/ICMPv6EchoRequest(type=128, code=0))

 

Packet Capture :

 

FGT-B:

 

2123.955444 port2 in fd01:af0:8005:2:45c3:2a0b:f009:521 -> fd01:af0:8003:2::af: icmp6: echo request seq 0
2123.955595 port1 out fd01:af0:8005:2:45c3:2a0b:f009:521 -> fd01:af0:8003:2::af: icmp6: echo request seq 0
2123.957367 port1 in fd01:af0:8003:2::af -> fd01:af0:8005:2:45c3:2a0b:f009:521: icmp6: echo reply seq 0
2123.957390 port2 out fd01:af0:8003:2::af -> fd01:af0:8005:2:45c3:2a0b:f009:521: icmp6: echo reply seq 0

 

FGT-A:

 

2149.961050 port2 in fd01:af0:8005:2:45c3:2a0b:f009:521 -> fd01:af0:8003:2::af: icmp6: echo request seq 0
2149.961142 port2 out fd01:af0:8003:2::af -> fd01:af0:8005:2:45c3:2a0b:f009:521: icmp6: echo reply seq 0

 

When using different ICMPv6 Code:

 

send(IPv6(dst="fd01:af0:8003:2::af",src="fd01:af0:8005:2:45c3:2a0b:f009:521")/ICMPv6EchoRequest(type=128, code=1))

 

Packet Capture FGT-B:

 

2248.332626 port2 in fd01:af0:8005:2:45c3:2a0b:f009:521 -> fd01:af0:8003:2::af: icmp6: echo request seq 0

 

Debug Flow FGT-B:

 

id=65308 trace_id=115 func=resolve_ip6_tuple_fast line=5315 msg="vd-root:0 received a packet(proto=58, fd01:af0:8005:2:45c3:2a0b:f009:521:0->fd01:af0:8003:2::af:384) from port2. type=128, code=1, id=0, seq=0."
id=65308 trace_id=115 func=resolve_ip6_tuple line=5474 msg="allocate a new session-00015936"
id=65308 trace_id=115 func=ip6_route_input line=2208 msg="find a route: gw-:: via port1 err 0 flags 400c0001"
id=65308 trace_id=115 func=fw6_forward_handler line=585 msg="Check policy between port2 -> port1"
id=65308 trace_id=115 func=__iprope6_fwd_check line=595 msg="in-[port2], out-[port1], skb_flags-00000000, vid-0, app_id: 0, url_cat_id: 0"
id=65308 trace_id=115 func=__iprope6_tree_check line=618 msg="use addr/intf dst tree: len=3 saddr=::, eaddr=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"
id=65308 trace_id=115 func=iprope6_check_one_policy line=1616 msg="checked gnum-100004 policy-2, ret-no-match, act-accept"
id=65308 trace_id=115 func=iprope6_check_one_policy line=1616 msg="checked gnum-100004 policy-3, ret-matched, act-accept"
id=65308 trace_id=115 func=__iprope6_check line=1810 msg="gnum-4e20, check-ffffffffa0133f40"
id=65308 trace_id=115 func=iprope6_check_one_policy line=1616 msg="checked gnum-4e20 policy-6, ret-no-match, act-accept"
id=65308 trace_id=115 func=iprope6_check_one_policy line=1616 msg="checked gnum-4e20 policy-6, ret-no-match, act-accept"
id=65308 trace_id=115 func=iprope6_check_one_policy line=1787 msg="policy-3 is matched, act-drop"
id=65308 trace_id=115 func=__iprope6_fwd_check line=613 msg="after iprope6_captive_check(): is_captive-0, ret-matched, act-drop, idx-3"
id=65308 trace_id=115 func=fw6_forward_handler line=609 msg="Denied by forward policy check (policy 3)" <====== it's matching policy ID 3 that block all ICMPv6

 

Logs FGT-B:

 

date=2025-08-03 time=17:03:08 eventtime=1754265788133226307 tz="-0700" logid="0000000013" type="traffic" subtype="forward" level="notice" vd="root" srcip=fd01:af0:8005:2:45c3:2a0b:f009:521 identifier=0 srcintf="port2" srcintfrole="undefined" dstip=fd01:af0:8003:2::af dstintf="port1" dstintfrole="undefined" sessionid=88374 proto=58 action="deny" policyid=3 policytype="policy" poluuid="8561b662-6c3d-51f0-ea93-81723869cdea" policyname="icmpv6" service="PING6" trandisp="noop" appcat="unscanned" duration=0 sentbyte=0 rcvdbyte=0 sentpkt=0 rcvdpkt=0 crscore=30 craction=131072 crlevel="high"

 

More options about IPv6 packets using Scapy :

Scapy - IPv6 Packet Creation With Scapy