I do not think there is a definitive right answer to your question. Instead there is a big bundle of ways how to get close to what you wish. Hence I will provide some hints how to get it done.
If a machine has more than 2 interfaces (lo
counts as one) you will have problems to autodetect the right interface easily. Here are some recipes on how to do it.
The problem, for example, is if hosts are in a DMZ behind a NAT firewall which changes the public IP into some private IP and forwards the requests. Your machine may have 10 interfaces, but only one corresponds to the public one.
Even autodetection does not work in case you are on double-NAT, where your firewall even translates the source-IP into something completely different. So you cannot even be sure, that the default route leads to your interface with a public interface.
Detect it via the default route
This is my recommended way to autodetect things
Something like ip r get 1.1.1.1
usually tells you the interface which has the default route.
If you want to recreate this in your favourite scripting/programming language, use strace ip r get 1.1.1.1
and follow the yellow brick road.
Set it with /etc/hosts
This is my recommendation if you want to stay in control
You can create an entry in /etc/hosts
like
80.190.1.3 publicinterfaceip
Then you can use this alias publicinterfaceip
to refer to your public interface.
Sadly haproxy
does not grok this trick with IPv6
Use the environment
This is a good workaround for /etc/hosts
in case you are not root
Same as /etc/hosts
. but use the environment for this. You can try /etc/profile
or ~/.profile
for this.
Hence if your program needs a variable MYPUBLICIP
then you can include code like (this is C, feel free to create C++ from it):
#define MYPUBLICIPENVVAR "MYPUBLICIP"
const char *mypublicip = getenv(MYPUBLICIPENVVAR);
if (!mypublicip) { fprintf(stderr, "please set environment variable %s\n", MYPUBLICIPENVVAR); exit(3); }
So you can call your script/program /path/to/your/script
like this
MYPUBLICIP=80.190.1.3 /path/to/your/script
this even works in crontab
.
Enumerate all interfaces and eliminate those you do not want
The desperate way if you cannot use ip
If you do know what you do not want, you can enumerate all interfaces and ignore all the false ones.
Here already seems to be an answer https://stackoverflow.com/a/265978/490291 for this approach.
Do it like DLNA
The way of the drunken man who tries to drown himself in alcohol
You can try to enumerate all the UPnP gateways on your network and this way find out a proper route for some "external" thing. This even might be on a route where your default route does not point to.
For more on this perhaps see https://en.wikipedia.org/wiki/Internet_Gateway_Device_Protocol
This gives you a good impression which one is your real public interface, even if your default route points elsewhere.
There are even more
Where the mountain meets the prophet
IPv6 routers advertise themselves to give you the right IPv6 prefix. Looking at the prefix gives you a hint about if it has some internal IP or a global one.
You can listen for IGMP or IBGP frames to find out some suitable gateway.
There are less than 2^32 IP addresses. Hence it does not take long on a LAN to just ping them all. This gives you a statistical hint on where the majority of the Internet is located from your point of view. However you should be a bit more sensible than the famous https://de.wikipedia.org/wiki/SQL_Slammer
ICMP and even ARP are good sources for network sideband information. It might help you out as well.
You can use Ethernet Broadcast address to contact to all your network infrastructure devices which often will help out, like DHCP (even DHCPv6) and so on.
This additional list is probably endless and always incomplete, because every manufacturer of network devices is busily inventing new security holes on how to auto-detect their own devices. Which often helps a lot on how to detect some public interface where there shouln't be one.
'Nuff said. Out.
ifconfig
,route
etc are deprecated for theip
command. Now you should use that instead. – Anders