I found these lines awhile ago reading forums, that allow me to access ssh from inside my VPN when it's turned on. Can someone explain what they do so I may tweak it to allow other traffic from outside the VPN. I've read man pages but to me it doesn't make sense.

ip rule add table 128 from
ip route add table 128 to dev eth0
ip route add table 128 default via

2 Answers 2

  1. For ip rule add table 128 from

    The ip rule manipulates routing rules. It takes both a SELECTOR and an ACTION. So in this case the SELECTOR is from ( is the PREFIX) and the ACTION is table 128. In totality, it is saying, "Add a routing rule for table 128 for traffic coming from

  2. For ip route add table 128 to dev eth0:

    The ip route command manipulates entires to routing tables (in your case, table 128 is being manipulated). You are adding a rule that says, "All trafic destined for use the output device eth0.

  3. For ip route add table 128 default via

    Same as before, the ip route command is manipulating route table 128. But here, the route is saying, "Route all traffic (default= IP0/0 or IPv6 ::/0) to the nexthop router address of (This is most likely the default gateway of your private network.)

I hope that way of explaining it is more helpful than confusing for you.

  • It's making a little bit more sense now but I'm still confused with how it's allowing ssh traffic to flow normally with the vpn enabled on tun0.
    – rathel
    Mar 24, 2018 at 15:31
  • @rathel a new rule set by an ip rule command gets by default a lower (earlier) precedence over those already here (including the rule calling the main routing table). So this rule is creating an exception to the routes already in place and already changed by the tunnel. Not having all informations on your settings, not much more can be said
    – A.B
    Apr 20, 2018 at 21:01
  • There isn't any other custom settings. Thanks for the replies though.
    – rathel
    May 2, 2018 at 2:38

I know this question is kind of old, but I just spent hours piecing this together, so in case it helps others who find their way here, I'll take a stab at a not-too-technical answer.

There are a few things you need to understand in order to make sense of these commands and what they do.

First off, if you have a VPN client running on your machine capturing traffic and directing it through the VPN, you do have custom routing rules already. If you're connecting to a VPN service, as opposed to a VPN server under your own control, the remote service will typically push routing rules to your machine via openvpn when you connect. You can see them by issuing ip route show while the vpn is connected. All the lines that contain tun0 are referring to your VPN connection.

That tun0 is key. From the kernel's point of view, your network card (eth0 or enp1s0 or whatever) is one network interface, and the VPN connection is a second, 'virtual', network interface. If you issue ip address while the VPN is up, you can see both of them are defined with their own separate IP addresses. Any traffic that gets routed over the tun0 virtual network interface goes out over the VPN, and any traffic that gets routed over the eth0 interface goes out directly, bypassing the VPN.

As mentioned in the openvpn wiki, traffic generated on your machine will have its 'from' IP address set to the device you're routing traffic to by default, which means the VPN, which means the IP address assigned to tun0. But! When connections come in on the regular physical network device (ie not over the VPN), the replies will have that device's IP address as their 'from' address. Now, the routing rules pushed to you by the VPN provider don't care, they just see outgoing traffic and redirect it to the VPN over tun0 and that's that. So you try to ssh in to the box, it gets the request and answers it, but the answer goes out through the VPN. Then your ssh client goes "whoa now, that reply is coming from a totally different IP address than where I'm trying to connect to" and ignores it. Thus you can't establish a connection inbound to the machine running the VPN client, which is where the ip rule and ip route commands come in.

What these commands are setting up is policy-based routing, which is a complex topic. As simply as possible, the kernel uses a 'routing table' to differentiate what traffic stays here on this machine (this is the network device lo, short for 'loopback', which has IP address, what traffic is on the same LAN and thus gets sent direct to the destination without going through a router (also known as a gateway), and traffic going elsewhere. In order to have internet access, your machine has to have a 'default gateway' routing entry that directs all 'elsewhere' traffic to a router that is connected to the outside world. All of this takes place in the default routing table, which is usually the only one you need to be concerned about.

But the VPN routing setup has rewritten your default routing table to set the VPN connection (the tun0 device) as your default route for all traffic headed out to 'elsewhere'. Luckily, Linux allows us to have multiple routing tables, and pick which routing table will apply to what traffic based on various rules—aka policies—hence "policy-based routing".

Now let's look at the specific ip commands in question, given the context above:

  • ip rule add table 128 from
    This creates a policy-based-routing rule saying that any traffic with a 'from' address of shall be routed according to routing table 128 instead of the default routing table. [1]
  • ip route add table 128 to dev eth0
    This adds a route in table 128 that directs all traffic with a 'to' address in the local 192.168.10.* subnet to eth0.
  • ip route add table 128 default via
    This sets the default route in table 128 to use your regular local gateway instead of the VPN's gateway.

Now any traffic that's in reply to a connection on eth0 (and thus automatically has a 'from' address of will be looked up in table 128 first. Table 128 says, in effect, if the destination is here on the LAN just route directly via eth0, otherwise route via the normal non-VPN gateway But the overall default for traffic originating on this machine is to get its 'from' address from tun0 because that's the default interface in your default routing table. All of that traffic won't match the from rule, so table 128 doesn't apply and it'll fall through to table 'default', which says to route it via the VPN.

Note: There's nothing special about 128 here, you're simply creating a new routing table with an arbitrarily chosen number. The default routing table is number 253, and you're free to use any number from 1 to 252 for your custom table(s).

  1. Technically, it just checks packets against each table's policy rules in numerical order and routes them according to the first match, so 128 gets consulted before 252, and packets that get sent to a custom routing table and don't match any of the routes in it will fall through and get checked against subsequent rules, and ultimately find their way to the default routing table if nothing else matches, but since table 128 has a default route in it, all packets that get directed to that table are guaranteed not to fall through.
  • Great answer! But still something's vague to me. Where does this have any relations to SSH? This seems to be targetting anything, how come this works for the SSH problem as described by the OP?
    – aderchox
    Jul 31, 2020 at 6:36
  • @aderchox: That's true. The original problem was that SSH failed to connect due to the (mis)configuration of the underlying network routing rules, not because anything was wrong with SSH itself. Fixing the network routing rules fixed the "reply packets coming from different IP than where I'm trying to connect to" problem that was breaking ssh, so now OP can successfully ssh in to the box running the VPN client. Technically, SSH was doing the right thing all along: the client end refused to complete the connection because the IP address mismatch might indicate a man-in-the-middle attack.
    – Askeli
    Aug 1, 2020 at 15:53
  • Now any traffic that's in reply to a connection on eth0 (and thus automatically has a 'from' address of When a packet is not in reply to a connection, how does the kernel determine the source address? Dec 11, 2020 at 2:24
  • @markasoftware: Keep in mind that my answer is focused entirely on outgoing packets. So the kernel doesn't so much "determine" the source address, more accurately it "assigns" a 'from' address. So: traffic generated on your machine will have its 'from' IP address set to the device you're routing traffic to by default, which means the VPN, which means the IP address assigned to tun0. IOW, outgoing packets that don't have their 'from' address specifically set by a higher-priority rule wind up with the address of the default routing table's default device, meaning the VPN's tun0 device.
    – Askeli
    Dec 11, 2020 at 19:14
  • I see. So the way the kernel assigns the source address is fundamentally different depending on whether a packet is a response to a connection (in which case it uses the destination IP of the packet that initiated the connection), or a new outgoing connection (in which case it uses the IP of the interface it's going out on)? Dec 11, 2020 at 20:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.