Dual upstream IP issues - router sending packets with wrong source mac?

My ISP provides a public IP which is locked to my previous router’s MAC address and additional carrier-grade nat IPs. I want my mikrotik router to pick up both the public IP and an additional “anonymous” IP and to use the anonymous IP for all regular outbound traffic, and the public IP only for traffic that originates as inbound traffic to the public IP. My setup is currently not working right; I believe that this is because my ISP requires that the source mac matches the assigned IP for outbound traffic, and my mikrotik router is sending out all traffic with the same source mac.

My configuration is setup like this:
ether1 runs a DHCP client with the mac from my old router XX
ether2 runs a vlan trunk to a vlan switch for my local lan
ether3 is connected to my ISP incoming fiber converter

my vlan setup is:
2: internet connection
11: local lan
12: other local lan
21: ISP ip phone
99: admin vlan

my vlan router is setup to expose vlan 2 untagged on a port that is looped back to ether1 on my mikrotik router

So basically, internet comes in on ether3. It is tagged with vlan=2 and a dhcp client runs on vlan2 to pick up the cgnat anonymous ip. It is the exposed over the vlan trunk ether2 to my other switch, which returns it on ether1 on which another dhcp client runs to pick up the public ip.

The DHCP client running on ether1 is configured to not add a default route, but rather runs a script to set up its default route in a separate routing table named public_ip
I have configured the firewall with the intent that any inbound connection on ether1 is marked with “public_ip_connection” and any connection marked “public_ip_connection” looks up its routing information from the public_ip routing table.

However, incoming connections on my public IP do not seem to work right. TCP connections take a long time to set up and it seems that packets are dropped. I have tried to debug the issue using wireshark and what I believe to be happening is that the router is sending out packets with the wrong source mac address - not the mac address that matches the source ip, and that my ISP filters out packets based on mac address vs DHCP assigned ip. But obviously something else could be wrong, if so I would much appreciate any suggestions at all.

This is my configuration with addresses redacted:

# 2023-08-04 14:00:26 by RouterOS 7.10.1
#
# model = RB5009UG+S+
# serial number = HEE0XXXXXXX
/interface bridge
add admin-mac=48:A9:8A:YY:YY:YY auto-mac=no comment=defconf frame-types=admit-only-vlan-tagged name=bridge vlan-filtering=yes
/interface ethernet
set [ find default-name=ether1 ] mac-address=60:03:A6:XX:XX:XX
/interface vlan
add interface=bridge name=adminvlan vlan-id=99
add interface=bridge name=fakewanvlan vlan-id=12
add interface=bridge name=internalvlan vlan-id=11
add interface=bridge name=internetvlan vlan-id=2
/interface list
add comment="Internet WAN" name=Internet
add comment="Local and internal interfaces" name=Local
add comment="Internet Public Reachable IP" name=PublicIP
/interface wireless security-profiles
set [ find default=yes ] supplicant-identity=MikroTik
/ip pool
add name=dhcp ranges=192.168.88.10-192.168.88.254
add name=dhcp11 ranges=192.168.11.40-192.168.11.90
add name=adminpool ranges=192.168.99.100-192.168.99.150
add name=pool12 ranges=192.168.12.100-192.168.12.150
/ip dhcp-server
add address-pool=dhcp11 interface=internalvlan lease-time=10m name=internaldhcp
add address-pool=adminpool interface=adminvlan name=admindhcp
add address-pool=pool12 interface=fakewanvlan name=fakewandhcp
/routing table
add comment="Public IP source route" disabled=no fib name=public_ip
/interface bridge port
add bridge=bridge comment="GS1900-8HP trunk" frame-types=admit-only-vlan-tagged interface=ether2
add bridge=bridge comment="Internet WAN" frame-types=admit-only-untagged-and-priority-tagged interface=ether3 pvid=2
add bridge=bridge comment=hpskrivare interface=ether4 pvid=11
add bridge=bridge comment=defconf interface=ether5
add bridge=bridge comment=defconf interface=ether6
add bridge=bridge comment=defconf interface=ether7
add bridge=bridge comment="backup admin port" frame-types=admit-only-untagged-and-priority-tagged interface=ether8 pvid=99
add bridge=bridge comment=defconf interface=sfp-sfpplus1
/ip firewall connection tracking
set tcp-syn-received-timeout=1m5s tcp-syn-sent-timeout=1m5s
/ip neighbor discovery-settings
set discover-interface-list=Local
/interface bridge vlan
add bridge=bridge comment=LAN tagged=ether2,bridge,ether7 vlan-ids=11
add bridge=bridge comment="Admin VLAN" tagged=bridge,ether2 untagged=ether8 vlan-ids=99
add bridge=bridge comment=Internet tagged=ether2,bridge untagged=ether3 vlan-ids=2
add bridge=bridge comment=fakewan tagged=ether2,bridge vlan-ids=12
add bridge=bridge comment="IP Phone" tagged=ether2,ether3 vlan-ids=21
/interface list member
add comment=defconf interface=internalvlan list=Local
add comment=defconf interface=ether1 list=Internet
add interface=adminvlan list=Local
add interface=internetvlan list=Internet
add interface=fakewanvlan list=Local
add interface=ether1 list=PublicIP
/ip address
add address=192.168.11.1/24 interface=internalvlan network=192.168.11.0
add address=192.168.99.1/24 comment="Admin VLAN 99 router" interface=adminvlan network=192.168.99.0
add address=192.168.12.1/24 interface=fakewanvlan network=192.168.12.0
add address=192.168.1.77/24 comment="Only for communicating with old router" interface=internalvlan network=192.168.1.0
/ip dhcp-client
add comment=defconf interface=internetvlan
add add-default-route=no interface=ether1 script="{\r\
    \n  :local rmark \"public_ip\"\r\
    \n  :local gw \$\"gateway-address\"\r\
    \n  :local count [/ip route print count-only where comment=\"PUBLICIP\"]\r\
    \n  :if ( \$bound = 1 ) do={\r\
    \n    :if ( \$count = 0 ) do={\r\
    \n      :log info \"Public IP DHCP route created for gateway=\$gw\";\r\
    \n      /ip route add gateway=\$gw comment=\"PUBLICIP\" routing-table=\$rmark\r\
    \n    } else={\r\
    \n      :log info \"Public IP DHCP route updating for gateway=\$gw\";\r\
    \n      :if ( \$count = 1 ) do={\r\
    \n        :local routeid [/ip route find where comment=\"PUBLICIP\"]\r\
    \n        :if ([/ip route get \$test gateway] != \$gw) do={\r\
    \n          /ip route set \$test gateway=\$gw\r\
    \n        }\r\
    \n      } else={\r\
    \n        :error \"Multiple public IP routes found\"\r\
    \n      }\r\
    \n    }\r\
    \n  } else={\r\
    \n    :log info \"Public IP DHCP unbound\";\r\
    \n    /ip route remove [find comment=\"PUBLICIP\"]\r\
    \n  }\r\
    \n}" use-peer-dns=no use-peer-ntp=no
/ip dhcp-server alert
add interface=internalvlan
add interface=*11
/ip dhcp-server network
add address=192.168.11.0/24 dns-server=192.168.11.1 gateway=192.168.11.1 netmask=24
add address=192.168.12.0/24 dns-server=192.168.12.1 domain=local.lan gateway=192.168.12.1 netmask=24
add address=192.168.99.0/24 comment=adminvlan
/ip dns
set allow-remote-requests=yes
/ip dns static
add address=192.168.88.1 comment=defconf name=router.lan
/ip firewall address-list
add address=192.168.0.0/16 list=localips
/ip firewall filter
add action=accept chain=input comment="defconf: accept established,related,untracked" connection-state=established,related,untracked
add action=drop chain=input comment="defconf: drop invalid" connection-state=invalid
add action=accept chain=input comment="defconf: accept ICMP" protocol=icmp
add action=accept chain=input comment="defconf: accept to local loopback (for CAPsMAN)" dst-address=127.0.0.1
add action=accept chain=input comment="Accept connections from admin vlan" in-interface=adminvlan
add action=drop chain=input comment="defconf: drop all not coming from LAN" in-interface-list=!Local
add action=accept chain=forward comment="defconf: accept in ipsec policy" ipsec-policy=in,ipsec
add action=accept chain=forward comment="defconf: accept out ipsec policy" ipsec-policy=out,ipsec
add action=fasttrack-connection chain=forward comment="defconf: fasttrack" connection-state=established,related hw-offload=yes
add action=accept chain=forward comment="defconf: accept established,related, untracked" connection-state=established,related,untracked
add action=drop chain=forward comment="defconf: drop invalid" connection-state=invalid
add action=drop chain=forward comment="defconf: drop all from WAN not DSTNATed" connection-nat-state=!dstnat connection-state=new in-interface-list=Internet
/ip firewall mangle
add action=mark-connection chain=prerouting comment="Set connection mark on any inbound packets on public IP interfaces" connection-mark=no-mark in-interface-list=PublicIP new-connection-mark=public_ip_connection passthrough=yes
add action=mark-routing chain=prerouting comment="Set routing mark on connections marked public ip" connection-mark=public_ip_connection dst-address-list=!localips dst-address-type=!local new-routing-mark=public_ip passthrough=yes
/ip firewall nat
add action=masquerade chain=srcnat comment="defconf: masquerade" ipsec-policy=out,none out-interface-list=Internet
add action=dst-nat chain=dstnat dst-port=80,443 in-interface-list=PublicIP protocol=tcp to-addresses=192.168.11.22
add action=dst-nat chain=dstnat dst-port=19132,19133 in-interface-list=PublicIP protocol=tcp to-addresses=192.168.11.20
add action=dst-nat chain=dstnat dst-port=19132,19133 in-interface-list=PublicIP protocol=udp to-addresses=192.168.11.20
/ipv6 firewall address-list
add address=::/128 comment="defconf: unspecified address" list=bad_ipv6
add address=::1/128 comment="defconf: lo" list=bad_ipv6
add address=fec0::/10 comment="defconf: site-local" list=bad_ipv6
add address=::ffff:0.0.0.0/96 comment="defconf: ipv4-mapped" list=bad_ipv6
add address=::/96 comment="defconf: ipv4 compat" list=bad_ipv6
add address=100::/64 comment="defconf: discard only " list=bad_ipv6
add address=2001:db8::/32 comment="defconf: documentation" list=bad_ipv6
add address=2001:10::/28 comment="defconf: ORCHID" list=bad_ipv6
add address=3ffe::/16 comment="defconf: 6bone" list=bad_ipv6
/ipv6 firewall filter
add action=accept chain=input comment="defconf: accept established,related,untracked" connection-state=established,related,untracked
add action=drop chain=input comment="defconf: drop invalid" connection-state=invalid
add action=accept chain=input comment="defconf: accept ICMPv6" protocol=icmpv6
add action=accept chain=input comment="defconf: accept UDP traceroute" port=33434-33534 protocol=udp
add action=accept chain=input comment="defconf: accept DHCPv6-Client prefix delegation." dst-port=546 protocol=udp src-address=fe80::/10
add action=accept chain=input comment="defconf: accept IKE" dst-port=500,4500 protocol=udp
add action=accept chain=input comment="defconf: accept ipsec AH" protocol=ipsec-ah
add action=accept chain=input comment="defconf: accept ipsec ESP" protocol=ipsec-esp
add action=accept chain=input comment="defconf: accept all that matches ipsec policy" ipsec-policy=in,ipsec
add action=drop chain=input comment="defconf: drop everything else not coming from LAN" in-interface-list=!Local
add action=accept chain=forward comment="defconf: accept established,related,untracked" connection-state=established,related,untracked
add action=drop chain=forward comment="defconf: drop invalid" connection-state=invalid
add action=drop chain=forward comment="defconf: drop packets with bad src ipv6" src-address-list=bad_ipv6
add action=drop chain=forward comment="defconf: drop packets with bad dst ipv6" dst-address-list=bad_ipv6
add action=drop chain=forward comment="defconf: rfc4890 drop hop-limit=1" hop-limit=equal:1 protocol=icmpv6
add action=accept chain=forward comment="defconf: accept ICMPv6" protocol=icmpv6
add action=accept chain=forward comment="defconf: accept HIP" protocol=139
add action=accept chain=forward comment="defconf: accept IKE" dst-port=500,4500 protocol=udp
add action=accept chain=forward comment="defconf: accept ipsec AH" protocol=ipsec-ah
add action=accept chain=forward comment="defconf: accept ipsec ESP" protocol=ipsec-esp
add action=accept chain=forward comment="defconf: accept all that matches ipsec policy" ipsec-policy=in,ipsec
add action=drop chain=forward comment="defconf: drop everything else not coming from LAN" in-interface-list=!Local
/system clock
set time-zone-name=Europe/Stockholm
/system note
set show-at-login=no
/tool mac-server
set allowed-interface-list=Local
/tool mac-server mac-winbox
set allowed-interface-list=Local

I think your DHCP client script’s logic is basically backwards.

When you set up a dstnat rule, the router remembers that the packet came in on the public IP and rewrites the replies to come back from that IP. Therefore, what you want is to set the default route to be toward the CGNAT IP and let the destination NAT do its thing, handling the public IP exception case.

Also, there is no rule that says there must be a 1:1 mapping between MACs and IPs. While it may well be true that your ISP uses the MAC to determine which static IP to assign you — this is called a static DHCP reservation — it is perfectly legal for your router to send packets addressed from the single public-facing MAC, but with different source IPs inside; it’s called multi-homing.

I would tend to look at this as a basic ROUTING issue easily handled by either mangling or routing rules the only nuance is assigning the WAN ethernet interface the mac address of your old router or CALL UP THE ISP and tell them its changed!!!

I copied the DHCP client script from an online sample and it seems to be working. I tested most of the cases when setting it up, and my routing tables look like this, so I think they are ok:

[admin@MikroTik] /ip/route> print 
Flags: D - DYNAMIC; A - ACTIVE; c, s, d, y - BGP-MPLS-VPN
Columns: DST-ADDRESS, GATEWAY, DISTANCE
#     DST-ADDRESS      GATEWAY       DISTANCE
  DAd 0.0.0.0/0        100.71.0.1           1
  DAc 81.170.X.0/24  ether1               0
  DAc 100.71.0.0/19    internetvlan         0
  DAc 192.168.1.0/24   internalvlan         0
  DAc 192.168.11.0/24  internalvlan         0
  DAc 192.168.12.0/24  fakewanvlan          0
  DAc 192.168.99.0/24  adminvlan            0
;;; PUBLICIP
0  As 0.0.0.0/0        81.170.X.X         1

The router knows that traffic to the 100.71.0.1 gateway is supposed to go out on internetvlan whereas traffic to the 81.170.X.X gateway is supposed to go out on ether1.

The MAC-address looks correct too; I have the old router’s MAC-adddress on ether1, and it is getting the public IP assigned from my ISP by DHCP:

[admin@MikroTik] /interface> print 
Flags: R - RUNNING; S - SLAVE
Columns: NAME, TYPE, ACTUAL-MTU, L2MTU, MAX-L2MTU, MAC-ADDRESS
 #    NAME          TYPE    ACTUAL-MTU  L2MTU  MAX-L2MTU  MAC-ADDRESS      
 0 R  ether1        ether         1500   1514       9796  60:03:A6:XX:XX:XX
 1 RS ether2        ether         1500   1514       9796  48:A9:8A:YY:YY:AA
 2 RS ether3        ether         1500   1514       9796  48:A9:8A:YY:YY:AB
 3 RS ether4        ether         1500   1514       9796  48:A9:8A:YY:YY:AC
 4  S ether5        ether         1500   1514       9796  48:A9:8A:YY:YY:AD
 5  S ether6        ether         1500   1514       9796  48:A9:8A:YY:YY:AE
 6  S ether7        ether         1500   1514       9796  48:A9:8A:YY:YY:AF
 7  S ether8        ether         1500   1514       9796  48:A9:8A:YY:YY:B0
 8  S sfp-sfpplus1  ether         1500   1514       9796  48:A9:8A:YY:YY:B1
 9 R  adminvlan     vlan          1500   1510             48:A9:8A:YY:YY:AA
;;; defconf
10 R  bridge        bridge        1500   1514             48:A9:8A:YY:YY:AA
11 R  fakewanvlan   vlan          1500   1510             48:A9:8A:YY:YY:AA
12 R  internalvlan  vlan          1500   1510             48:A9:8A:YY:YY:AA
13 R  internetvlan  vlan          1500   1510             48:A9:8A:YY:YY:AA

Yet replies sent out by the router are not received on internet. My only idea is that it is related to my ISP detecting that the replies are not sent from the correct MAC address for the source ip. Here is an example packet log run at a different location; first I ping www.google.com to verify that ping is not blocked from that site - a reply is received from ; then I ping my public ip and receive no reply:

listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
  google:
15:17:20.623412 IP 172.26.44.8 > 216.58.211.4: ICMP echo request, id 4, seq 1, length 64
15:17:20.626811 IP 216.58.211.4 > 172.26.44.8: ICMP echo reply, id 4, seq 1, length 64
  my public ip on mikrotik router:
15:18:11.954116 IP 172.26.44.8 > 81.170.Y.Y: ICMP echo request, id 5, seq 1, length 64

On the mikrotik router I am running packet sniffer forwarding to wireshark, and I can see the icmp ping request being received and the reply getting sent, but the reply is dropped (for some reason, the packets are sniffed multiple times on the mikrotik router):

No.	Time	Source	Destination	Protocol	Length	Info
1	0.000000	62.181.Z.Z	81.170.Y.Y	ICMP	145	Echo (ping) request  id=0x0005, seq=1/256, ttl=52 (no response found!)
2	0.000120	62.181.Z.Z	81.170.Y.Y	ICMP	145	Echo (ping) request  id=0x0005, seq=1/256, ttl=52 (reply in 3)
3	0.000120	81.170.Y.Y	62.181.Z.Z	ICMP	145	Echo (ping) reply    id=0x0005, seq=1/256, ttl=64 (request in 2)
4	0.000347	81.170.Y.Y	62.181.Z.Z	ICMP	149	Echo (ping) reply    id=0x0005, seq=1/256, ttl=64
5	0.000347	81.170.Y.Y	62.181.Z.Z	ICMP	149	Echo (ping) reply    id=0x0005, seq=1/256, ttl=64

Here are the detailed contents of packet no 3:

Frame 3: 145 bytes on wire (1160 bits), 145 bytes captured (1160 bits) on interface \Device\NPF_{5251BC78-C0FC-462C-B5F6-C5B125EBC8F4}, id 0
Ethernet II, Src: Routerbo_XX:XX:aa (48:a9:8a:XX:XX:aa), Dst: ASUSTekC_XX:XX:XX (2c:4d:54:XX:XX:XX)
Internet Protocol Version 4, Src: 192.168.99.1, Dst: 192.168.99.150
User Datagram Protocol, Src Port: 48675, Dst Port: 37008
TZSP: Ethernet 
    Version: 1
    Type: Received packet (0)
    Encapsulation: Ethernet (1)
    End
Ethernet II, Src: Routerbo_XX:XX:aa (48:a9:8a:XX:XX:aa), Dst: IETF-VRRP-VRID_9f (00:00:5e:00:01:9f)
    Destination: IETF-VRRP-VRID_9f (00:00:5e:00:01:9f)
    Source: Routerbo_bd:94:aa (48:a9:8a:XX:XX:aa)
    Type: IPv4 (0x0800)
Internet Protocol Version 4, Src: 81.170.Y.Y, Dst: 62.181.Z.Z
    0100 .... = Version: 4
    .... 0101 = Header Length: 20 bytes (5)
    Differentiated Services Field: 0x00 (DSCP: CS0, ECN: Not-ECT)
    Total Length: 84
    Identification: 0x5b79 (23417)
    000. .... = Flags: 0x0
    ...0 0000 0000 0000 = Fragment Offset: 0
    Time to Live: 64
    Protocol: ICMP (1)
    Header Checksum: 0x4fe1 [validation disabled]
    [Header checksum status: Unverified]
    Source Address: 81.170.Y.Y
    Destination Address: 62.181.Z.Z
Internet Control Message Protocol
    Type: 0 (Echo (ping) reply)
    Code: 0
    Checksum: 0xf095 [correct]
    [Checksum Status: Good]
    Identifier (BE): 5 (0x0005)
    Identifier (LE): 1280 (0x0500)
    Sequence Number (BE): 1 (0x0001)
    Sequence Number (LE): 256 (0x0100)
    [Request frame: 2]
    [Response time: 0,000 ms]
    Timestamp from icmp data: Aug  6, 2023 15:18:11.000000000 Västeuropa, sommartid
    [Timestamp from icmp data (relative): 1.371710000 seconds]
    Data (48 bytes)

As far as I can tell it is a perfectly valid ICMP reply except for the fact that it is being sent out from the mikrotik bridge mac address, which my ISP has assigned a 100.71.0.X ip instead of from the mac address assigned to ether1, 60:03:A6:XX:XX:XX, which is the proper owner of my public ip address 81.170.Y.Y.

The only reason I can see for connections not working is that my ISP is using subscriber mac address validation. And the mikrotik router not using the right mac.