6

I'm trying to redirect a subsection of incoming traffic to a different destination using fwmarks.

The procedure

1) Mark matching incoming packets:

iptables -t mangle -A PREROUTING -i pppoe0 -p tcp -m tcp --dport 80 -j MARK --set-xmark 6

2) Add a rule to direct the marked packets to routing table "200".

ip rule add fwmark 6 table 200

3) Add a default route on routing table "200" to the new destination.

ip route all default via 192.168.33.2 table 200

The problem

iptables -L PREROUTING -t mangle -v shows packets matching the rule I made in step 1, however they never get forwarded to where I expect.

I think the problem is that the traffic is destined for an address which is considered local to the host, and the local ip rules are matching being the rule I added in step 2, e.g.

~# ip rule show
0:      from all lookup local   <--- taking priority...
32765:  from all fwmark 0x6 lookup 200   <--- ... over this.
32766:  from all lookup main
32767:  from all lookup default

Question: is there a way to make my rule take priority over the local rules?

Coops
  • 6,055
  • 1
  • 34
  • 54
  • 1
    Sounds like you simply need additional `DNAT`. – Tom Yan Apr 27 '20 at 03:22
  • While answering the title of the question wouldn't be difficult (but I doubt it would help), I'd rather ask you instead what is your configuration. Maybe providing `ip -br link; ip -4 -br address; ip -br route` and an example of source and destination could help. And unless you explain why you wouldn't do that, Tom Yan's comment looks that's what's needed. – A.B May 14 '20 at 19:30
  • I have exactly this question. It looks like a good and complete question to me, I don't get why no straight-forward answer was given. Is the answer "no, it's not possible to change that"? Or "it is easy to change (how?) but it won't solve anything / is not the right way to do things"? – pgr May 20 '21 at 12:39
  • 1
    @pgr the title of the question is straightforward. But OP asked two questions within the question: the title and then a fuzzy unasked question about "if I then do this will it work?" that's because of this second part that I hesitated to answer. – A.B May 20 '21 at 15:23

1 Answers1

4

You can specify the rule priority with the preference (or prio or pref etc.) keyword to override the default priority (which is usually "one below the lowest priority not equal to 0") that would be chosen for the rule.

You can also create a rule which duplicates an other rule but using a different priority, then delete the original rule that was at an other priority: that's the equivalent of changing the rule's priority.

Here's how you can do it here:

ip rule add preference 200 fwmark 0x6 lookup 200
ip rule add preference 300 lookup local
ip rule delete preference 0

This moves the rule looking up the local routing table from 0 to 300, leaving room for other rules to take precedence, like now the rule with preference 200. This order prevents any loss of connectivity (assuming routing table 200 doesn't create any loss of connectivity itself).


Example on SU where I made use of this in an answer to route (and tunnel) traffic normally intended for the local system without NAT nor fwmark:

Using Wireguard to essentially give a machine in local network a public address from VPS


Avoiding iptables for this is often the best way to get it working. This requires kernel >= 4.17:

Extends fib rule match support to include sport, dport and ip proto match (to complete the 5-tuple match support). Common use-cases of Policy based routing in the data center require 5-tuple match

Without iptables and marks this would look like:

ip rule add preference 200 iif pppoe0 ipproto tcp dport 80 lookup 200

Plus the reverse direction which depending on the problem could be an other interface or in some case the special words iif lo meaning locally initiated:

ip rule add preference 201 iif ... ipproto tcp sport 80 lookup 200

I can't give a complete answer because many factors are involved and it depends on the end goal, which isn't very clear here (you can take a look at my SU answer to see all what could go wrong and have to be altered, like ARP in some cases).

A.B
  • 11,090
  • 2
  • 24
  • 45
  • Thanks, this is very helpful for me. That `ip rule` with port numbers sounded like the perfect solution for my problem here: https://serverfault.com/questions/1063428/routing-traffic-for-specific-port-range/1064086 ... but unfortunately the kernel there is 4.1.37... :-( – pgr May 20 '21 at 21:12
  • I tried to put two different comments on your linked question. But each time I think there would be a lot of invisible caveats that would be difficult to address blindly. I'd rather write back here the last comment I thought about: you'd like to have a route `10.0.0.1/32 dev br8 via 10.0.10.10` working on the UDM despite 10.0.0.1 also being a local address on the UDM? And that's why you want to move the local rule? – A.B May 20 '21 at 22:16
  • Yes, that's my temporary hack while the old system is phased out! It would be a mess if it wasn't limited to just a specific kind of packets. I finally got this working (sooo happy) and will be posting a reply on my own question as soon as I settle the configuration and find some time. Thanks for your help! I was being misled by a comment I read somewhere on the internet, that there was no way to change the `local` rule's priority, that it had to be zero. That wrong info had made me think this was more complicated than it really was. Your commands to edit priorities worked. – pgr May 21 '21 at 10:05
  • But I left comments on your question stating that there are minor side effects for the 10.0.10.0/24 LAN if the UDM isn't acting as a switch (to be able to do something about it) – A.B May 21 '21 at 10:11