Skip to content
DevOps AI ToolKit
Newsletter

Kali Linux Networking for DevOps · Part 4 of 15

Linux Routing With Kali Linux for DevOps Engineers

Difficulty: Beginner ~22 min Part 4/15
Prerequisites: Network interfacesIP addresses & CIDR
Series progress4 / 15
Series curriculum (15 lessons)

Every packet that leaves your machine faces the same question: which way out? Your host might have one network card or five, a link to the office LAN and a tunnel to a cloud VPC, plus the loopback interface — and for every destination address the kernel has to pick exactly one path. The set of rules it uses to make that choice is the routing table, and the tool you use to read and reason about it is ip route. In this lesson you will learn to read a routing table line by line, understand why the kernel selects one route over another, and use ip route get to remove all guesswork from “where is this traffic actually going?” This is one of the most valuable diagnostic skills you can build, because a huge share of “the service is unreachable” incidents are quietly a routing problem wearing a firewall’s clothing.

What You Will Learn

  • What a routing table is and what each field in a route means
  • Default routes, connected routes, next hop, gateway, and source IP
  • Longest-prefix matching — the single rule that decides which route wins
  • How to use ip route get to see the exact path the kernel would choose
  • How to recognize and diagnose the common routing failures you meet in production

The Routing Table: What It Is

A routing table is an ordered set of rules the kernel consults for every outbound packet. Each rule maps a destination network to a way of reaching it — either “the network is directly attached to this interface” or “send it to another router, and let that router forward it onward.”

You read the table with ip route:

ip route

That command prints the main routing table. Here is a representative example from a multi-homed host — a machine with two network interfaces:

default via 192.168.1.1 dev eth0
10.10.0.0/16 dev eth1
192.168.1.0/24 dev eth0

Three lines, three rules. Before we decide which one wins for a given destination, let’s read each field so the output stops looking like noise.

Reading a single route

Take the last line:

192.168.1.0/24 dev eth0
  • 192.168.1.0/24 is the destination network — the range of addresses this rule covers. The /24 is the CIDR prefix length: the first 24 bits are the network, so this rule matches every address from 192.168.1.0 to 192.168.1.255. (If prefixes and /24 notation are hazy, revisit IP Addresses & CIDR.)
  • dev eth0 means this network is directly connected to interface eth0. There is no intermediate router — the destination lives on the same link, and the host reaches it directly. This is called a connected route, and the kernel creates it automatically when you assign an address to an interface (see Network Interfaces & iproute2).

Now the first line:

default via 192.168.1.1 dev eth0
  • default is shorthand for the network 0.0.0.0/0 — a prefix length of /0, which matches every possible destination. It is the catch-all.
  • via 192.168.1.1 names the next hop: the router (the gateway) to hand the packet to when this rule is used. “Via” always means “not directly connected — forward it to this address first.”
  • dev eth0 is the interface used to reach that gateway.

So the default route says: for any destination I don’t have a more specific rule for, send the packet to 192.168.1.1 out of eth0, and trust that router to move it along. The default route is how your laptop reaches the entire internet through a single home router.

The middle line, 10.10.0.0/16 dev eth1, is a second connected route: the 10.10.0.0 through 10.10.255.255 range lives directly on eth1.

Next hop vs. connected: the one distinction that matters

There are only two kinds of route, and telling them apart is most of the battle:

  • Connected route (dev eth0, no via): the destination is on a directly attached link. The host delivers the packet itself, resolving the destination’s hardware address with ARP (the subject of Part 5).
  • Gateway route (via 192.168.1.1 dev eth0): the destination is somewhere else. The host forwards the packet to the named next-hop router, which repeats the whole decision on its own table.

🛠️ DevOps Perspective — This is exactly why a Kubernetes node, a multi-NIC VM, or a container can reach one service but not another. The node’s routing table decides that pod traffic goes out the overlay interface while node-management traffic goes out eth0. When “the app can’t reach the database but I can ping it from the host,” you are almost always looking at two different routes being selected. Reading ip route on the node tells you which path each destination takes.

Longest-Prefix Matching: How the Kernel Chooses

Here is the crucial part. When a packet needs to be sent, its destination address may match several routes at once. In our table, a packet for 192.168.1.50 matches both:

default          (0.0.0.0/0   — matches everything)
192.168.1.0/24   (matches 192.168.1.0–192.168.1.255)

So which rule wins? The kernel uses longest-prefix matching: among all routes whose network contains the destination, it picks the one with the longest prefix — the largest number after the slash — because that is the most specific rule.

Let’s make it concrete. Sending to 192.168.1.50:

Candidate routes that match 192.168.1.50:
  192.168.1.0/24   → prefix length 24   ✅ most specific
  default 0.0.0.0/0 → prefix length 0

Winner: 192.168.1.0/24 (dev eth0, connected)

The /24 is longer than the /0, so the connected route wins and the packet is delivered directly on eth0. The default route is ignored.

Now sending to 8.8.8.8 (a public DNS server):

Candidate routes that match 8.8.8.8:
  default 0.0.0.0/0 → prefix length 0   ✅ only match

Winner: default (via 192.168.1.1, dev eth0)

No connected or specific route contains 8.8.8.8, so only the catch-all /0 matches. The packet goes to the gateway.

And sending to 10.10.20.5:

Candidate routes that match 10.10.20.5:
  10.10.0.0/16     → prefix length 16   ✅ most specific
  default 0.0.0.0/0 → prefix length 0

Winner: 10.10.0.0/16 (dev eth1, connected)

It matches the /16 on eth1, which beats the default, so this traffic leaves on the second interface. Notice that nothing in the table’s ordering decided this — longest-prefix match is about specificity, not line order. The default route (/0) is always the least specific and is used only when nothing else matches. That is precisely why it is called the default.

🏭 Why This Matters in Production — Overlay networks and VPNs work by installing more-specific routes. A VPN client adds something like 10.0.0.0/8 dev tun0, which is more specific than your default, so private-range traffic silently redirects into the tunnel while everything else keeps using the normal gateway. When a VPN “breaks the internet” or “captures too much,” it is longest-prefix match doing exactly what it was told — the fix is understanding which prefix got installed, not restarting the client.

ip route get: Removing the Guesswork

Reading the table and mentally running longest-prefix match works, but it is error-prone the moment the table has a dozen routes and a couple of interfaces. The kernel already runs this computation perfectly for every packet — so ask it directly. ip route get tells you the exact route the kernel would use for one specific destination:

ip route get 8.8.8.8

Typical output:

8.8.8.8 via 192.168.1.1 dev eth0 src 192.168.1.50 uid 1000
    cache

Read it left to right. To reach 8.8.8.8, the kernel would go via 192.168.1.1 (the gateway), out of dev eth0 (the interface), using src 192.168.1.50 as the packet’s source address. That src field is gold: it tells you which of the host’s own IPs will appear as the sender — the value that a remote firewall, security group, or reverse path filter will actually see.

Now the internal destination:

ip route get 10.10.20.5
10.10.20.5 dev eth1 src 10.10.5.2 uid 1000
    cache

No via this time — the destination is on a connected network, so the packet leaves dev eth1 directly, sourced from 10.10.5.2. In two commands you have proven that internet-bound traffic exits eth0 while 10.10.x.x traffic exits eth1, with the exact source IP for each.

🔎 Troubleshooting Tip — When someone says “the server can’t reach the API,” don’t start with the firewall. Start with ip route get <api-ip>. In one line it tells you the interface, the gateway, and the source IP the kernel actually chose. If any of the three is wrong — wrong NIC, wrong gateway, unexpected source — you have found the problem before touching a single packet capture. It is the fastest way to separate “wrong path” from “path is fine, something is dropping the packet.”

🧪 Try It — Run ip route get 1.1.1.1 and ip route get 127.0.0.1 on your Kali box. Note how the loopback destination resolves to dev lo with src 127.0.0.1, while the public address resolves to your real interface and gateway. Then run ip route get against your own default gateway’s address — you’ll see a connected result with no via, because the gateway itself is on a directly attached link.

A Packet’s Path Out of the Host

It helps to picture where the routing decision sits in the journey of a packet:

  Your Server
      |
   [ ip route decision ]   <- longest-prefix match
      |  chooses interface + next hop
      v
    eth0
      |
      v
  Default Gateway (192.168.1.1)
      |
      v
    Router  ->  Router  ->  ...
      |
      v
   Destination (e.g. 8.8.8.8)

The routing table governs only the first step — how the packet leaves this host. Once it reaches the gateway, that router consults its table and repeats the decision, hop after hop, until the packet arrives. Following those hops end to end is what traceroute and mtr are for; routing is the local half of that same story.

🛠️ DevOps Perspective — On a Kubernetes node this diagram gains extra branches: a route for pod-to-pod traffic over the overlay, one for the service CIDR, and a default out the node’s primary NIC. When a pod can’t reach an external endpoint, ip route get <external-ip> run inside the pod’s network namespace shows whether it took the overlay path (wrong) or the node gateway (right). Same tool, same longest-prefix rule — just more routes.

Common Routing Problems

Routing failures have recognizable signatures. For each below, note the symptom and how ip route / ip route get exposes the cause. Work the problem as Observe → Hypothesis → Test → Evidence, not “restart networking and hope.”

Missing default route

Symptom: Local hosts are reachable, but anything off-subnet fails, often with Network is unreachable or No route to host. DNS and the internet are dead; the LAN is fine.

Reveal it: Run ip route and look for a line starting with default. If there is none, the host has no catch-all — any destination not covered by a connected route has nowhere to go.

ip route | grep '^default'

Empty output confirms the diagnosis. ip route get 8.8.8.8 will report RTNETLINK answers: Network is unreachable — the kernel is telling you plainly that no rule matched.

Wrong gateway

Symptom: Off-subnet traffic times out (connection timeout) rather than being refused. A default route exists, but packets vanish.

Reveal it: ip route get 8.8.8.8 shows the via address. Compare it to the real gateway on your subnet. If the route points to 192.168.1.254 but the actual router is 192.168.1.1, packets are being handed to a next hop that either doesn’t exist or won’t forward them. The gateway must be an address on a connected network — if it isn’t, that’s your smoking gun.

Traffic using the wrong NIC

Symptom: On a multi-NIC host, a service works from one interface but not another; or return traffic seems to disappear; or a health check from the wrong source IP is rejected by a firewall.

Reveal it: ip route get <dest> prints both dev (interface) and src (source IP). If a destination that should leave the management NIC is resolving out the data NIC — or the src is an address the remote firewall isn’t expecting — a more-specific route is pulling traffic the wrong way. This is longest-prefix match working correctly on a table that’s wrong.

Asymmetric routing

Symptom: Intermittent or one-way connectivity; TCP handshakes that half-complete; packets that arrive but replies that never come back. Common on multi-homed hosts and across VPCs with multiple gateways.

Reveal it: Packets go out one interface but the reply comes back on another, and reverse-path filtering (rp_filter) may silently drop them. Compare ip route get <dest> (your outbound path and src) against how the remote end routes back to that src. If your host sends from eth1’s IP but the network routes replies to eth0, you have an asymmetric path. The fix usually lives in making the routes — and the source IP — consistent, not in the application.

Overlapping networks

Symptom: A destination that should be remote is treated as local (or vice versa); a container or VPN can reach some of a range but not the rest.

Reveal it: Two routes cover overlapping address space — say a VPN pushes 10.0.0.0/8 while a local bridge owns 10.10.0.0/16. Longest-prefix match sends 10.10.x.x to the bridge and everything else in 10.0.0.0/8 to the tunnel. ip route get against specific addresses in each range shows which route claims them. Overlaps are a design problem the table faithfully reports; the tool just makes the overlap visible.

Incorrect subnet mask

Symptom: Some hosts on “the same LAN” are reachable and some aren’t, seemingly at random.

Reveal it: A connected route with the wrong prefix — 192.168.1.0/25 when the LAN is really a /24 — means addresses above .127 fall outside the connected route and get punted to the default gateway instead of delivered locally. ip route shows the prefix length on the connected line; check it against the subnet the interface is actually on. A one-character mask error is a classic “works for half the hosts” bug.

🔎 Troubleshooting Tip — Match the error string to the layer. Network is unreachable / No route to host points squarely at routing — a missing route or dead gateway. Connection timeout on a route that looks correct suggests the packet leaves fine but is dropped downstream (firewall, security group, or a wrong/asymmetric return path). Connection refused means you reached the host and the route is fine — the problem is a port, not a route. Read the error before you touch the config.

Troubleshooting Workflow

When connectivity to some destination fails, walk the routing layer deliberately:

Application → TLS → Port → DNS → Gateway → Route → Interface
                                    ^^^^^^^^^^^^^^^^^^^^^^
                                    you are working here
  1. Observe — What exactly fails, and what’s the error? Network is unreachable vs. timeout vs. refused tells you which layer to suspect.
  2. Ask the kernelip route get <dest>. Capture the interface, gateway (via), and source IP it reports.
  3. Hypothesis — Is any of those three wrong? Wrong NIC, unexpected gateway, or a src the remote side won’t accept?
  4. Test against the tableip route to see the full set of rules. Confirm the winning route is the one you expected under longest-prefix match, and that a default route exists.
  5. Check the connected route — Is the destination supposed to be local? Verify the prefix length on its connected route matches the real subnet.
  6. Identify the layer, then correct — If the path is genuinely wrong, fix the route or mask. If the path is right but traffic still dies, move outward to the firewall or the remote’s return path — don’t keep editing routes that are already correct.
  7. Validate — Re-run ip route get, then confirm end to end with a real connectivity test.

🏭 Why This Matters in Production — Cloud instances make routing failures a daily event: a VM with a secondary NIC and no default route on it, a route table in the VPC that black-holes a subnet, an overlay that overlaps the corporate range. The instinct to “reboot the box” wastes an outage; ip route get <dest> answers “where would this packet actually go?” in one line and points you at the real layer. Diagnosis first, change second.

Try It Yourself

On your Kali workstation (all read-only and safe):

  1. Run ip route and identify every line as either a connected route (dev, no via) or a gateway route (via ...). Find your default route and note its gateway.
  2. Pick three destinations — a public IP (8.8.8.8), your gateway’s address, and a host on your LAN — and predict which route each will use before checking.
  3. Run ip route get <ip> for each and compare against your predictions. Were the interface, gateway, and src what you expected?
  4. Run ip route get 127.0.0.1 and confirm it resolves to dev lo.
  5. Optional, in a disposable lab only: temporarily delete your default route with sudo ip route del default, run ip route get 8.8.8.8 to watch it report Network is unreachable, then restore it with sudo ip route add default via <your-gateway> dev <iface>. This makes the “missing default route” signature unmistakable.

🔐 Security Note — Everything here is read-only inspection of your own host’s routing table, or a route change on a lab machine you own. Only inspect and modify systems you own or have explicit permission to manage. Deleting the default route drops a host off the network until you restore it — never rehearse step 5 on anything that matters.

What You Learned

  • The routing table (ip route) is an ordered set of rules mapping destination networks to either a directly attached interface (connected route) or a next-hop gateway (via).
  • A default route (0.0.0.0/0, shown as default) is the least-specific catch-all, used only when no better rule matches.
  • The kernel chooses among matching routes by longest-prefix matching — the most specific (longest /N) prefix wins, regardless of line order.
  • ip route get <dest> reports the exact interface, gateway, and source IP the kernel would use, removing all guesswork from “where does this traffic go?”
  • Most routing failures — missing default route, wrong gateway, wrong NIC, asymmetric routing, overlapping networks, and incorrect subnet masks — announce themselves in ip route / ip route get output, and the error string (unreachable vs. timeout vs. refused) tells you whether routing is even the right layer to suspect.

You can now read a routing table with confidence and prove exactly which path a packet takes. But once the kernel decides to deliver a packet on a connected route, one question remains: how does it find the destination’s hardware address on the local link? That is the job of ARP. Continue with Part 5: ARP and Neighbor Discovery.

Affiliate Disclosure: Some links on this page are affiliate links. If you purchase through one of these links, DevOps AI Toolkit may earn a commission at no additional cost to you. See our affiliate disclosure.

← Back to Kali Linux Networking for DevOps Back to Kali Linux

Related on DevOps AI Toolkit