Linux – How to get local ip address associated with default gateway

ip addresslinuxrouting

There may be several network interfaces on a server, e.g., lo, eth0, eth1

From the route table, I know that eth0 is connected to the default gateway. The address of the default gateway, for example, is 192.168.1.1. And the address of eth0 is, for example, 192.168.1.100.

How can I get the address "192.168.1.100"? Any approach is ok: Python, Shell, UNIX C API…

Currently I can only think of one way:

  1. Execute command "route" and get last line (default 192.168.1.1 0.0.0.0 …)
  2. Execute command "ifconfig" and get the address list (127.0.0.1, 192.168.1.100, …)
  3. Find the address which is in the same subnet with default gateway (192.168.1.1)
  4. Then we get address 192.168.1.100

Are there some better solutions?

PS: It has been suggested that we can call connect() on a udp socket, and then call getsockname() to get local address. However, it works only on part of the servers.

@EEAA

So this is my script:

route -n | awk '$1 == "0.0.0.0" { print $2 }' > gateway.tmp
ip -4 addr show | grep inet | awk '{ print $2 }' > addrs.tmp

The first line prints the default gateway:

10.1.40.1

The second line prints a list of interface addresses (in cidr notation):

127.0.0.1/8
10.1.46.122/21

Then I have to decide which network 10.1.40.1 belongs to. So I write a Python script:

import sys

def ip_to_binary(ip):
    bytes = ip.split(".")
    a = int(bytes[0])
    b = int(bytes[1])
    c = int(bytes[2])
    d = int(bytes[3])
    return "{0:08b}{1:08b}{2:08b}{3:08b}".format(a, b, c, d)

def mask_to_binary(bits):
    return "1" * bits + "0" * (32 - bits)

def binary_and(a, b):
    if len(a) == len(b):
        result = ""
        for i in range(0, len(a)):
            if a[i] == "1" and b[i] == "1":
                result += "1"
            else:
                result += "0"
        return result
    return None

def ip_in_net(ip, net_cidr_notation):
    net_addr, bits = net_cidr_notation.split("/")
    bin_mask = mask_to_binary(int(bits))
    bin_net = ip_to_binary(net_addr)
    bin_ip = ip_to_binary(ip)

    if binary_and(bin_ip, bin_mask) == binary_and(bin_net, bin_mask):
        return True
    return False

# usage: python autoaddr.py gateway_file addrs_file
gateway = open(sys.argv[1]).readline().strip()
addrs = open(sys.argv[2]).readlines()

for addr in addrs:
    if ip_in_net(gateway, addr):
        print addr.split("/")[0]

To avoid extra dependencies, I didnot use libraries like netaddr and ipaddress. Finally, I have to add the Python script to Shell script:

python autoaddr.py gateway.tmp addrs.tmp > auto.tmp
rm -f gateway.tmp
rm -f addrs.tmp

Now I have a file auto.tmp containing the automatically generated address:

10.1.46.122

Best Answer

A bash one-liner to get the "default IP address" of your machine:

ip -o route get 1.1.1.1 | cut -d " " -f 7

And if you need it in Python 3:

def get_default_ip():
    output = subprocess.check_output(["ip", "-o", "route", "get", "1.1.1.1"],
                                     universal_newlines=True)
    return output.split(" ")[6]