12

I am using Mac OSx to access my Pi via SSH. To access it, I know that I need the Pi's IP address. So, I decided to use a few Python commands which have always succeeded in giving me the local IP.

import socket
host_name = socket.gethostname()
host_ip = socket.gethostbyname(host_name)
print host_ip

Oddly enough, I have only gotten the local host IP (127.0.1.1).

Can someone please tell me how to get the proper local / global (whichever is better, this only needs to work over LAN for now) IP for the PI?

Ghanima
  • 15,578
  • 15
  • 58
  • 113
xxmbabanexx
  • 3,198
  • 7
  • 32
  • 56
  • 1
    Have you even tried googling this? – Alexander Mar 31 '13 at 23:20
  • Have a look at *lsleases*, see my answer for [SSH into Raspberry PI without knowing IP address][1]. [1]: http://raspberrypi.stackexchange.com/questions/12440/ssh-into-raspberry-pi-without-knowing-ip-address – sebastian Jan 15 '15 at 14:42
  • Are you trying to get the Pi to get its own address? How does this help you `ssh`, to it? Surely you need the IP address before you `ssh`. – ctrl-alt-delor May 05 '19 at 17:44

4 Answers4

12

If Python is a must, you can check this article: http://code.activestate.com/recipes/439094-get-the-ip-address-associated-with-a-network-inter/

They rightly point out that a computer has as many IP addresses as network interfaces.

Here is their code to get the IP address of a network adapter, I've tested the code and it works:

import socket
import fcntl
import struct

def get_ip_address(ifname):
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    return socket.inet_ntoa(fcntl.ioctl(
        s.fileno(),
        0x8915,  # SIOCGIFADDR
        struct.pack('256s', ifname[:15])
    )[20:24])

print get_ip_address('lo')
print get_ip_address('eth0')

If your RPi is connected via WiFi the adapter name should be wlan0

Otherwise you can get it with the ip command:

ip addr show eth0 | grep inet

You should get something like:

inet 192.168.0.140/24 brd ....

That's your IP address.

Of course none of this will work if you just boot up your RPi and could not connect to it because you don't know the IP address! If' that's the case your DHCP server will surely be able to tell you which IP address he just gave to the RPi (or you just try them all :) )

That said, you might benefit of referencing you RPi by name and, since you're using a Mac, probably the best solution would be to install avahi-daemon:

sudo apt-get install avahi-daemon

which implements the Apple Zeroconf specification (like Bonjour). You can then ssh to your RPi by name:

ssh pi@raspberry.local

I used a different approach for my two Raspberrys (named ygdrasill and dvalinn): I've opted for a fixed IP (192.168.0.140 and 192.168.0.142) so I can also use etc/hosts file on some of my other machines.

I could have set up an internal DNS or rely on Wins, but current solution works for me.

Remo.D
  • 534
  • 5
  • 11
  • Hi Remo, Thank for explaining this in detail. I tried you code on python 3.5 running on rasp pi 3. It doesn't work and result in a runtime error. "struct.error: argument for 's' must be a bytes object" – Amit Rai Sharma Dec 08 '16 at 12:45
  • I believe this should be `ssh pi@raspberrypi.local` given the default hostname for a RPi is `raspberrypi`. Why avahi-daemon is not universally installed in the Debian world is beyond me. Ad-hoc networks are a dream when it works out of the box. – Heath Raftery May 14 '19 at 22:38
  • In contrast to my previous comment, in the lastest Raspbian (Apr19) as of now (May19), both raspberrypi.local resolution and 169.254.x.x auto-assignment work without configuration out of the box! – Heath Raftery May 16 '19 at 05:21
2

This code :

import socket
import fcntl
import struct

def get_ip_address(ifname):
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    return socket.inet_ntoa(fcntl.ioctl(
        s.fileno(),
        0x8915,  # SIOCGIFADDR
        struct.pack('256s', ifname[:15])
    )[20:24])

print get_ip_address('lo')
print get_ip_address('eth0')

only works under python 2.7, it doesn't work with python 3, you'll get the error that the argument for 's' must be a byte object...

Odolyte
  • 21
  • 1
0

For any python version:

import os
print(os.system('hostname -I'))

Source

Or if you want to read the output:

import subprocess
res = str(subprocess.check_output(['hostname', '-I'])).split(' ')[0].replace("b'", "")
print(res)
  • Bar from the age of the question, are you aware that the user would have to be connected to the Pi to run the programs as listed to find the address to connect to? For others reading this - the `-I` option can return multiple addresses - both IPv4 and IPv6 and for each network adapter connected. As the OP was using a Mac and the Mac supports Bonjour by default a simple `ping raspberrypi.local` would work and is the simplest way. –  Dec 28 '20 at 03:06
  • I'm sorry, but it's not clear to me that the OP wants to run the code on his/her MAC. Even the accepted answer starts showing how to the get PI's address from the PI, not from the MAC. Anyway I think my answer may help someone. – Francisco Gomes Dec 28 '20 at 03:30
0

socket may return the localhost, depending on how the OS is set up. So it isn't portable.

This stackoverflow answer about getting IP via python is helpful- it explains the problem with /etc/hosts and gives a decent workaround. It isn't perfect (ipv6), and if you have several bound IPs it may not find the routable version, but for your needs it's a good oneliner.

From the commandline, ifconfig is your friend. It'll typically list all of your bound interfaces and such.

tedder42
  • 1,291
  • 1
  • 11
  • 16