#!rsc by RouterOS # # Set up NPTv6. # # GUA prefix is reserved by allocating a network from $argWanPool # on $argLoopbackInt. Once GUA network is available, its address-prefix # is used to set up mangling rules to perform network prefix translation # with addresses from $argUlaPool. # # Since mangling is performed after connection tracking, all mangled packets # continue processing with connection-state=invalid. Thus raw rules are added # to mark these packets for notrack. Adjust your filter rules accordingly. # # Optional arg*Extra can be used to further narrow matching criteria. # E.g. to perform translation only when the packet is routed through WAN: # # :global argSnptMangleExtra {"out-interface-list"="WAN"} # # # Arguments: # argLoopbackInt (str): name of the loopback interface # argWanPool (str): name of the WAN pool # argUlaPool (str): name of the ULA pool # argManagedID (str): regex-escaped unique ID of the managed objects # [argSnptMangleExtra] (array): Optional extra properties for the SNPT mangle rule # [argDnptMangleExtra] (array): Optional extra properties for the DNPT mangle rule # [argSnptRawExtra] (array): Optional extra properties for the SNPT raw rule # [argDnptRawExtra] (array): Optional extra properties for the DNPT raw rule # # # Affects: # /ipv6/address # /ipv6/firewall/mangle # /ipv6/firewall/raw # # # Requirements: # - mod/ipv6-functions :global GlobalFunctionsReady; :while ($GlobalFunctionsReady != true) do={ :delay 500ms; } :local SetupRules do={ :global argLoopbackInt :global argWanPool :global argManagedID :global argSnptMangleExtra :global argDnptMangleExtra :global argSnptRawExtra :global argDnptRawExtra :global WaitIP6Address :global SetIfExistsElseAdd :global SetIfExistsElseAddUnlessEqual $SetIfExistsElseAddUnlessEqual /ipv6/address\ ({"comment~\"$argManagedID\\\$\""})\ ({\ interface="$argLoopbackInt";\ advertise=false;\ "from-pool"="$argWanPool"\ })\ ({\ interface=$argLoopbackInt;\ advertise="no";\ "from-pool"=$argWanPool;\ comment="\"Managed: NPTv6 / $argManagedID\""\ }) :local varGuaPrefix [$WaitIP6Address $argLoopbackInt $2 ("$argManagedID\$")] $SetIfExistsElseAdd /ipv6/firewall/mangle\ ({"comment~\"snpt-$argManagedID\\\$\""})\ ($argSnptMangleExtra , {\ chain="postrouting";\ action="snpt";\ "src-address"=$1;\ "src-prefix"=$1;\ "dst-prefix"=$varGuaPrefix;\ comment="\"Managed: NPTv6 / snpt-$argManagedID\""\ }) $SetIfExistsElseAdd /ipv6/firewall/mangle\ ({"comment~\"dnpt-$argManagedID\\\$\""})\ ($argDnptMangleExtra , {\ chain="prerouting";\ action="dnpt";\ "dst-address"=$varGuaPrefix;\ "src-prefix"=$varGuaPrefix;\ "dst-prefix"=$1;\ comment="\"Managed: NPTv6 / dnpt-$argManagedID\""\ }) $SetIfExistsElseAdd /ipv6/firewall/raw\ ({"comment~\"snpt-$argManagedID\\\$\""})\ ($argSnptRawExtra , {\ chain="prerouting";\ action="notrack";\ "src-address"=$1;\ comment="\"Managed: NPTv6 / snpt-$argManagedID\""\ }) $SetIfExistsElseAdd /ipv6/firewall/raw\ ({"comment~\"dnpt-$argManagedID\\\$\""})\ ($argDnptRawExtra , {\ chain="prerouting";\ action="notrack";\ "dst-address"=$varGuaPrefix;\ comment="\"Managed: NPTv6 / dnpt-$argManagedID\""\ }) } :local TearDown do={ :global argManagedID /ipv6/address/remove [find comment~"$argManagedID\$"] /ipv6/firewall/mangle/remove [find comment~"$argManagedID\$"] /ipv6/firewall/raw/remove [find comment~"$argManagedID\$"] } :global LogPrint :global AssertNotEmpty :global argLoopbackInt :global argWanPool :global argUlaPool :global argManagedID $AssertNotEmpty "argLoopbackInt" $argLoopbackInt $AssertNotEmpty "argWanPool" $argWanPool $AssertNotEmpty "argUlaPool" $argUlaPool $AssertNotEmpty "argManagedID" $argManagedID /ipv6/pool :local varWanPrefix [get value-name=prefix $argWanPool] :local varUlaPrefix [get value-name=prefix $argUlaPool] :do { $SetupRules $varUlaPrefix $varWanPrefix $LogPrint info $0 ("Add NPT: $varUlaPrefix <-> $varWanPrefix") } on-error={ $LogPrint warning $0 ("Failed to update NPTv6, retrying from scratch") :do { $TearDown $SetupRules $varUlaPrefix $varWanPrefix } on-error={ $TearDown $LogPrint error $0 ("Failed to set up NPTv6") :error "fatal error in ipv6-npt.rsc" } }