I have one comment about your port knock design. This may sound nit-picky, but following best practice and "structured" design helps make things easier to troubleshoot for both yourself and for anyone else who has to administrate a box after you.... May not be an issue if this is a home router, but good habits are always worth forming....
Your rules cause a successful knock to add the authenticated host to a dstnat rule. Otherwise, the pinhole "doesn't exist" for that source.
This is not the best way to do this.
It would be better for the dstnat to always exist w/o any criteria on who the source is, etc.
In essence, the dstnat rule means: "Port 1234 = ssh to my internal box"
This should be true for all cases.
Anyone you don't want having access to this pinhole should be filtered using the filter table. Don't get in the habit of making translations that work in some cases and not others. In your simple situation, there's no big difference except some obscure academic "best practice" concept - but imagine there were many more rules (hundreds) and the functionality of access filtering is woven between whether something nats or not / whether it's filtered or not. . . different behavior in different rules. It would be a nightmare to debug if something were to go wrong.
So make the pinhole work for all IP addresses, but then use the forward chain of the filter table to limit access to it - i.e.. the src-IP is in the "hosts-who-have-successfully-knocked" list.
And I'm not sure if I confused you, but in my original suggestion, I meant that there should be a list of "hosts-who-may-knock" which is not the same as "hosts-who-have-knocked-successfully" or the phase1, phase2, etc. lists. Just make the phase1 rule also require that the src-address be in the "hosts-who-may-knock" list. Think of it as a static permanent phase0
Well your design may work when you want to leave your pinhole ssh connectivity to the entire public internet when you attempt to do a knock sequence, it does not work when you want to restrict the access to a specific set of subnets or hosts. I have been playing with this setup and your suggestion to not have a src-address-lists on the dst-nat will in fact allow access in from unauthorized IP addresses from my testing (if you don't put a restriction on dst-nat rule)
Sorry I changed the original 1234 NAT port to 1022 so as to not confuse my port knocking ports (obfuscated from my config) of 1234, 567, 890
If I enable this rule #7 then it will allow connections from my test hosts of 192.168.1.15 and 192.168.1.11 WITHOUT PORT KNOCKING sequence in fact...
6 chain=dstnat action=dst-nat to-addresses=192.168.88.254 to-ports=22 protocol=tcp src-address-list=PORTKNOCK_ALLOWED in-interface=ether1 dst-port=1022 log=no log-prefix=""
7 X chain=dstnat action=dst-nat to-addresses=192.168.88.254 to-ports=22 protocol=tcp in-interface=ether1 dst-port=1022 log=no log-prefix=""
[admin@MikroTik] /ip firewall nat>
I found that if I use a jump rule I can in fact do the source based address list (hosts-who-may-knock) to then go into the port knocking test at that point to get access. I disabled my existing rules and create new rules under a chain called input-knock and jump to those based on the src-address-list.
15 chain=input action=jump jump-target=input-knock src-address-list=hosts-who-may-knock
16 X ;;; accept WAN connections inbound on port 1022 to Mikrotik RTR destined for computer on port 22
chain=input action=accept connection-state=new protocol=tcp src-address-list=PORTKNOCK_ALLOWED in-interface=ether1 dst-port=1022 log=no
log-prefix=""
17 X chain=input action=accept connection-state=established
18 X chain=input action=add-src-to-address-list connection-state=new protocol=tcp src-address-list=PORTKNOCK_STAGE_2 address-list=PORTKNOCK_ALLOWED
address-list-timeout=15m in-interface=ether1 dst-port=890 log=no log-prefix=""
19 X chain=input action=add-src-to-address-list connection-state=new protocol=tcp src-address-list=PORTKNOCK_STAGE_1 address-list=PORTKNOCK_STAGE_2
address-list-timeout=20s in-interface=ether1 dst-port=567 log=no log-prefix=""
20 X chain=input action=add-src-to-address-list connection-state=new protocol=tcp address-list=PORTKNOCK_STAGE_1 address-list-timeout=20s
in-interface=ether1 dst-port=1234 log=no log-prefix=""
21 ;;; drop all other WAN connections inbound to MikroTik RTR on WAN port (ether1)
chain=input action=drop in-interface=ether1 in-interface-list=WAN log=no log-prefix=""
..
..
29 ;;; accept WAN connections inbound on port 1022 to Mikrotik RTR destined for computer on port 22
chain=input-knock action=accept connection-state=new protocol=tcp src-address-list=PORTKNOCK_ALLOWED in-interface=ether1 dst-port=1022 log=no
log-prefix=""
30 chain=input-knock action=accept connection-state=established
31 chain=input-knock action=add-src-to-address-list connection-state=new protocol=tcp src-address-list=PORTKNOCK_STAGE_2
address-list=PORTKNOCK_ALLOWED address-list-timeout=15m in-interface=ether1 dst-port=890 log=no log-prefix=""
32 chain=input-knock action=add-src-to-address-list connection-state=new protocol=tcp src-address-list=PORTKNOCK_STAGE_1
address-list=PORTKNOCK_STAGE_2 address-list-timeout=20s in-interface=ether1 dst-port=567 log=no log-prefix=""
33 chain=input-knock action=add-src-to-address-list connection-state=new protocol=tcp address-list=PORTKNOCK_STAGE_1 address-list-timeout=20s
in-interface=ether1 dst-port=1234 log=no log-prefix=""
34 ;;; drop all other WAN connections inbound to MikroTik RTR on WAN port (ether1)
chain=input-knock action=drop in-interface=ether1 in-interface-list=WAN log=no log-prefix=""
35 chain=input-knock action=return
During my testing from 192.168.1.15 I can get in using the port knocking sequence but could not get in from my test node 192.168.1.11 until after adding to the hosts-who-may-knock address list and then following the port knocking sequence.
[admin@MikroTik] /ip firewall address-list> print
Flags: X - disabled, D - dynamic
# LIST ADDRESS CREATION-TIME TIMEOUT
0 ;;; TEST BOXES
hosts-who-may-knock 192.168.1.15 nov/14/2017 14:39:32
1 hosts-who-may-knock aaa.bbb.0.0/16 nov/14/2017 14:39:38
2 hosts-who-may-knock xx.yyy.zzz.0/28 nov/14/2017 14:39:41
3 hosts-who-may-knock ccc.ddd.ee.0/24 nov/14/2017 14:39:45
4 D PORTKNOCK_STAGE_1 192.168.1.15 nov/14/2017 17:44:06 4s
5 D PORTKNOCK_STAGE_2 192.168.1.15 nov/14/2017 17:44:09 6s
6 D PORTKNOCK_ALLOWED 192.168.1.15 nov/14/2017 17:44:12 14m50s
[admin@MikroTik] /ip firewall address-list>
##################
## 192.168.1.11 ##
##################
LibreELEC:~ # ssh -p 2222 me@192.168.1.111
^C
LibreELEC:~ # telnet 192.168.1.111 1234
^C
LibreELEC:~ # telnet 192.168.1.111 567
^C
LibreELEC:~ # telnet 192.168.1.111 890
^C
LibreELEC:~ # ssh -p 2222 me@192.168.1.111
^C
LibreELEC:~ # exit
Connection to 192.168.1.11 closed.
Mac-mini:~
##################
## 192.168.1.15 ##
##################
Mac-mini:~ me$ ssh -p 2222 me@192.168.1.111
^C
Mac-mini:~ me$ telnet 192.168.1.111 1234
Trying 192.168.1.111...
^C
Mac-mini:~ me$ telnet 192.168.1.111 567
Trying 192.168.1.111...
^C
Mac-mini:~ me$ telnet 192.168.1.111 890
Trying 192.168.1.111...
^C
Mac-mini:~ me$ ssh -p 2222 me@192.168.1.111
Password:
Last login: Tue Nov 14 17:42:25 2017 from macmini-wifi.lan
MacBook-Pro:~ me$
Once I add 192.168.1.11 to the address list then it starts working
[admin@MikroTik] /ip firewall address-list> add address=192.168.1.11 list=hosts-who-may-knock comment=new_test_host
[admin@MikroTik] /ip firewall address-list>
[admin@MikroTik] /ip firewall address-list> print
Flags: X - disabled, D - dynamic
# LIST ADDRESS CREATION-TIME TIMEOUT
0 ;;; TEST BOXES
hosts-who-may-knock 192.168.1.15 nov/14/2017 14:39:32
1 hosts-who-may-knock aaa.bbb.0.0/16 nov/14/2017 14:39:38
2 hosts-who-may-knock xx.yyy.zzz.0/28 nov/14/2017 14:39:41
3 hosts-who-may-knock ccc.ddd.ee.0/24 nov/14/2017 14:39:45
4 D PORTKNOCK_ALLOWED 192.168.1.15 nov/14/2017 17:44:12 5m16s
5 ;;; new_test_host
hosts-who-may-knock 192.168.1.11 nov/14/2017 17:53:53
[admin@MikroTik] /ip firewall address-list> print
Flags: X - disabled, D - dynamic
# LIST ADDRESS CREATION-TIME TIMEOUT
0 ;;; TEST BOXES
hosts-who-may-knock 192.168.1.15 nov/14/2017 14:39:32
1 hosts-who-may-knock aaa.bbb.0.0/16 nov/14/2017 14:39:38
2 hosts-who-may-knock xx.yyy.zzz.0/28 nov/14/2017 14:39:41
3 hosts-who-may-knock ccc.ddd.ee.0/24 nov/14/2017 14:39:45
4 D PORTKNOCK_ALLOWED 192.168.1.15 nov/14/2017 17:44:12 3m56s
5 ;;; new_test_host
hosts-who-may-knock 192.168.1.11 nov/14/2017 17:53:53
6 D PORTKNOCK_STAGE_1 192.168.1.11 nov/14/2017 17:54:51 0s
7 D PORTKNOCK_STAGE_2 192.168.1.11 nov/14/2017 17:54:55 0s
8 D PORTKNOCK_ALLOWED 192.168.1.11 nov/14/2017 17:55:01 14m45s
[admin@MikroTik] /ip firewall address-list>
resulting in a valid connection...
##################
## 192.168.1.11 ##
##################
LibreELEC:~ # ssh -p 2222 me@192.168.1.111
^C
LibreELEC:~ # telnet 192.168.1.111 1234
^C
LibreELEC:~ # telnet 192.168.1.111 567
^C
LibreELEC:~ # telnet 192.168.1.111 890
^C
LibreELEC:~ # ssh -p 2222 me@192.168.1.111
Password:
Last login: Tue Nov 14 17:44:18 2017 from macmini-wifi.lan
MacBook-Pro:~ me$
I hope this helps out someone else in the future that wants to restrict the port knocking to specific network segments/hosts and not leave it open to the public internet and as I said in my testing you need to put a source address list on the dst-nat or you are allowing access directly to the NATed port. You can restrict the port knocking to known address blocks or reverse the logic and put in known blacklists or countries known to have lots of hackers, etc For me I want to allow this only from the places I work or play or my devices
I suppose I could do like one of the posters suggested and make a more complex sequence for the general internet usage possibly in the future. I'd like to know how to send the string sequence for port knocking next.