Clean old UPnP rules

This is a script I currently use. I left some of my work in progress comments in place - I was experiementing with a few different ways of getting this to work. No guarantees - but it seems to be working for me.

This script attempts to keep the NAT table current by removing unused UPnP rules.

This is done by scanning the NAT table and removing dynamic rules that belong

to unconnected hosts.

Temp storage for current NAT rule address

:local dynamicAddress;

List of all dynamic NAT addresses

:local usedAddresses;

Temp indicator for current NAT rule

:local hasConnections;

Obtain list of target addresses from dynamic rules

/ip firewall nat;
:foreach i in=[find dynamic] do={

Set temp variable for current rule

:set $dynamicAddress [get $i to-addresses];

Add to list. This may never be used - but maybe it becomes useful to speed things up in a future revision

:set usedAddresses ($usedAddresses, $dynamicAddress);

Now determine if active connections exist

:set $hasConnections false;
:foreach j in=[/ip firewall connection find where src-address~"$dynamicAddress:"] do={
:set $hasConnections true;
}
:foreach j in=[/ip firewall connection find where dst-address~"$dynamicAddress:"] do={
:set $hasConnections true;
}

Set comments to indicate condition of rule

:if ($hasConnections = true) do={

set $i comment="Active UPnP";

} else={

set $i comment="InActive UPnP";

}

Theoretically, if there are no active connections, then this rule isn't doing anything.

So...get rid of it.

:if ($hasConnections = true) do={
remove $i;
}
}

#:foreach i in=$usedAddresses do={

/ip firewall address-list add address=$i list="UPnP";

#}

The connections can still be open, till for one day, also if the device is off (default tcp estabilished timeout).

The device can be on, but not use any connection at the moment, if you delete the rule, you break the functionality.

If the device reply on ping, simply:

:log info "*** start unused dynamic NAT rules check ***";
:local dynamicRulesArray [/ip firewall nat find where dynamic=yes];
:local howManyPing 2;
:foreach singleRule in=$dynamicRulesArray do={
 :local ipTest value=[/ip firewall nat get $singleRule to-addresses];
 :local pingReply [:ping $ipTest count=$howManyPing]
 :if ($pingReply < 1) do={
  :log warning ("Dynamic NAT rule: ".$ipTest." not reply");
  /ip firewall nat remove $singleRule;
 }
};
:log info "*** end unused dynamic NAT rules check ***";

or to be more synthetic:

/ip firewall nat;
:foreach singleRule in=[find where dynamic=yes] do={
 :if ([:ping [get $singleRule to-addresses] count=2] < 1) do={remove $singleRule}
};