Overview of WireGuard packet flow

I feel like this question must have been asked before but I cannot find it for the life of me in the forum (maybe I’m just bad at searching, if that’s the case I apologize). I’m trying to understand the general packet flow of a wireguard packet to determine the best way to assign firewall filter rules. I was reading through the overall Packet Flow in RouterOS but that doesn’t seem to include WireGuard packets, which appear to be different.

For context, I wanted to setup 3 different types of wireguard tunnels:

  1. The first tunnel type only has access to my home media servers static IP and will be shared with friends and family. It has subnet 172.16.50.0/24
  2. The second tunnel type is only for me, and allows access to my entire LAN but not the broader public IP space. It has subnet 172.17.50.0/24
  3. The third tunnel is also only for me, but it forwards all traffic through the router (AllowedIps=0.0.0.0/0,::/0)

For the purposes of this post, I am mostly just considering the first tunnel type which should be locked down to only accessing a single IP address on my LAN. I was looking at the docs some WireGuard filter rules on the forum, the default ones that get applied when creating a back-to-home VPN, and playing around in wireshark with a wireguard connection I have setup so I can get an idea of how I should be making my filter rules. It seems like the primary recommendation is just accepting packets based on the udp port specified when setting up the wireguard interface. eg.

/ip firewall filter add action=accept chain=input dst-port=13231 protocol=udp in-interface-list=WAN

and any inter-subnet rules are done on the default forward chain:

/ip firewall filter add action=accept chain=forward dst-address=10.1.202.0/24 src-address=10.1.101.0/24

After playing around with packet inspection via WireShark, it seems like the flow is the following:

  1. A packet comes in on the WAN port (ether1 in my case) using the UDP port specified when I setup the WG1 interface
  2. A firewall rule is setup to accept the WAN WG traffic
  • /ip firewall filter add action=accept chain=input dst-port=13231 protocol=udp in-interface-list=WAN
  1. The packet is accepted, and then routed to the WG1 interface
  2. A standard routing decision is applied to the packet to determine if it should be on the input chain (like for a DNS request to the mikrotik itself) or on the forward chain (like communicating with the media server)
  3. The packet goes through the filter rules again, only this time with an interface of WG1

My questions are the following:

  1. Did I correctly deduce the flow of a wireguard packet or is there anything Im missing / got wrong?
  2. When I setup a interface=WG1 chain=input passthrough rule and a interface=WG1 chain=forward passthrough rule, the sum of the input and forward chains is always less than the WAN:wg-port accept rule shown above, as listed by the rule counters. Is this a sign some packets are getting dropped? Or do keep-alive packets, for example, not get placed on the forward or input chains?
  3. At what point does decryption occur?
  4. At what point does WireGuard drop packets that are unauthenticated or disallowed by the servers AllowedIps config? I assume this is the same place as decryption?

My ideal scenario is a where I can make an interface list with all wireguard interfaces, have a rule at the top of my default chains with action=jump, which takes it to a custom wg chain where I have very specific rules. Would there be anything wrong with the following? (Assuming a default filter rule config, and noting the place-before’s on some rules)

/interface list add name=WG_IN_INTFLST
/interface list member add interface=WG1 list=WG_IN_INTFLST
/interface list member add interface=WG2 list=WG_IN_INTFLST

/ip firewall filter add action=accept chain=input dst-port=13231 protocol=udp in-interface-list=WAN place-before=1 comment=”accept the WAN WG traffic” 
/ip firewall filter add chain=forward action=jump jump-target=wg_forward in-interface-list=WG_IN_INTFLST place-before=1 comment=”send WG forward traffic to a custom chain”
/ip firewall filter add chain=wg_forward src-address=172.16.50.0/24 dst-address=10.42.50.51/32 (media server on LAN) dst-port=5056,8096 action=accept comment=”accept media wg tunnel to server:port”
/ip firewall filter add chain=wg_forward src-address=172.17.50.0/24 dst-address=10.0.0.0/8,172.16.0.0/12,192.168.0.0/16 action=accept comment=”accept lan wg tunnel to private IP space”
/ip firewall filter add chain=wg_forward action=drop comment=”drop all other WG traffic”

(keeping it simple and only looking at the forward chain for this example)

Essentially, I just want to make sure I have a solid foundational understanding of how routing wireguard packets work so that I can reason over the filter rules better. Thank you all in advance!

Conceptually speaking you only need two tunnels or two interfaces. The one for you to use your own internet while at a remote location (0.0.0.0/0) has to be on its own Wireguard interface.
Also, consider the traffic coming out of the tunnel and hitting your router, being subject to firewall rules as L3 traffic and on the same plane as your subnets.

Thus simply limit the access via firewall rules.
add chain=forward action=accept comment=“remote users to media” in-interface=wireguard1 src-address-list=WG-Users dst-address=SUBNET or IP of media/servers

So make a firewall address list of such users and your golden
Same for your admin needs to see all subnets!

add chain=forward action=accept comment=“admin to all” in-interface-list=WIREGUARD src-address-list=AdminRemote out-interface-list=LAN
where
add interface=wireguard1 list=WIREGUARD
add interface=wireguard2 list=WIREGUARD

and AdminRemote is a list that includes all your remote devices ( laptop, smartphones etc, for both interfaces above )
Same rule on input chain
add chain=forward action=accept comment=“admin to all” in-interface-list=WIREGUARD src-address-list=AdminRemote

Hmm, you make a good point. If it’s guaranteed that only I will be using a specific interface, then I can merge all of them into one tunnel because Im able to trust the client config (since I set it up!). And in the client config I can define the connection to enable split tunneling or routing all traffic as a default gateway via the AllowedIps field. I could still add firewall rules if I really wanted to since I can rely on the IP addresses provided via the client config as well. It definitely simplifies my Mikrotik config if I can offload some of that into the client config.

Just as a followup, though, did I correctly understand the general packet flow of a WireGuard packet? Where the packet goes over the filter rules twice:

  1. First when it is still encrypted and encapsulated, coming in the WAN interface to the WG port on the input chain
  2. And then again as the decrypted internal packet now coming from the wireguard interface and placed and the appropriate chain

Yes, one needs the handshake negotiation to take place via the input chain and then manage traffic exiting and entering the tunnel from the LAN (forward chain)