I want to get the IP of the default gateway (internal router IP) using Python. I'm really new to Python so not sure how this works.
I know you can get the IP of your machine with:
import socket
internal_ip = socket.gethostbyname(socket.gethostname())
print internal_ip
So I'm thinking it must be something similar?
On Windows, you should use WMI along with proper query to lookup properties of an object (e.g. network devices). The following Python code prints IPv4 and default gateway addresses on my Windows 7 machine:
Code:
import wmi
wmi_obj = wmi.WMI()
wmi_sql = "select IPAddress,DefaultIPGateway from Win32_NetworkAdapterConfiguration where IPEnabled=TRUE"
wmi_out = wmi_obj.query( wmi_sql )
for dev in wmi_out:
print "IPv4Address:", dev.IPAddress[0], "DefaultIPGateway:", dev.DefaultIPGateway[0]
Output:
IPv4Address: 192.168.0.2 DefaultIPGateway: 192.168.0.1
You can find more details and tricks of performing WMI operations on network devices on this page.
For Linux, PyNetInfo as suggested on this page would be a good approach. Although on Linux you can get around having to depend on an additional module by reading PROC entries among other import os; os.system(...) tricks.
Related
In Python, is there a way to detect whether a given network interface is up?
In my script, the user specifies a network interface, but I would like to make sure that the interface is up and has been assigned an IP address, before doing anything else.
I'm on Linux and I am root.
The interface can be configured with an IP address and not be up so the accepted answer is wrong. You actually need to check /sys/class/net/<interface>/flags. If the content is in the variable flags, flags & 0x1 is whether the interface is up or not.
Depending on the application, the /sys/class/net/<interface>/operstate might be what you really want, but technically the interface could be up and the operstate down, e.g. when no cable is connected.
All of this is Linux-specific of course.
As suggested by #Gabriel Samfira, I used netifaces. The following function returns True when an IP address is associated to a given interface.
def is_interface_up(interface):
addr = netifaces.ifaddresses(interface)
return netifaces.AF_INET in addr
The documentation is here
Answer using psutil:
import psutil
import socket
def check_interface(interface):
interface_addrs = psutil.net_if_addrs().get(interface) or []
return socket.AF_INET in [snicaddr.family for snicaddr in interface_addrs]
With pyroute2.IPRoute:
from pyroute2 import IPRoute
ip = IPRoute()
state = ip.get_links(ip.link_lookup(ifname='em1'))[0].get_attr('IFLA_OPERSTATE')
ip.close()
With pyroute2.IPDB:
from pyroute2 import IPDB
ip = IPDB()
state = ip.interfaces.em1.operstate
ip.release()
You can see the content of the file in /sys/class/net/<interface>/operstate. If the content is not down then the interface is up.
If the question is about checking if the cable is conencted (FreeBSD);
[status for status in run.cmd(' /usr/local/bin/sudo ifconfig %s ' % interface).split("\t") if status.strip().startswith("status")][0].strip().endswith("active")
For this, no api support so far :( ...
We know that Python Allows enabling promiscuous mode under Windows through
s.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)
However, The RCVALL_* and SIO_* is only available in windows.
Using C socket api, in Linux, one can use :
ethreq.ifr_flags |= IFF_PROMISC;
ioctl(sock, SIOCSIFFLAGS, ðreq);
or through,
setsockopt(sock, SOL_PACKET, PACKET_ADD_MEMBERSHIP, PACKET_MR_PROMISC)
Is there any option in python socket API that allows us to set promiscuous mode in Linux?
Use an AF_NETLINK socket to issue a request to turn on IFF_PROMISC. Python can construct AF_NETLINK sockets on Linux:
>>> from socket import AF_NETLINK, SOCK_DGRAM, socket
>>> s = socket(AF_NETLINK, SOCK_DGRAM)
>>>
See the example at the end of the netlink(7) manual page for an example of how to issue a netlink request. You can use ctypes (or even struct) to construct the serialized nlmsghdr message to send over the netlink socket. You may also need it to call sendmsg and recvmsg, since Python still doesn't expose these APIs. Alternatively, there are some third-party modules available which expose these two APIs.
Alternatively, you can go the old school route of using ioctl, which sadly turns out to be rather simpler.
First define the ifreq structure using ctypes:
import ctypes
class ifreq(ctypes.Structure):
_fields_ = [("ifr_ifrn", ctypes.c_char * 16),
("ifr_flags", ctypes.c_short)]
Then make a socket to use with the ioctl call:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
Then copy a couple constant values out of /usr/include since they're not exposed by Python:
IFF_PROMISC = 0x100
SIOCGIFFLAGS = 0x8913
SIOCSIFFLAGS = 0x8914
Create an instance of the ifreq struct and populate it to have the desired effect:
ifr = ifreq()
ifr.ifr_ifrn = "eth4"
Populate the ifr_flags field with an ioctl call so that you don't clobber whatever flags are already set on the interface:
import fcntl
fcntl.ioctl(s.fileno(), SIOCGIFFLAGS, ifr) # G for Get
Add the promiscuous flag:
ifr.ifr_flags |= IFF_PROMISC
And set the flags on the interface:
fcntl.ioctl(s.fileno(), SIOCSIFFLAGS, ifr) # S for Set
To remove the flag, mask it off and set again:
ifr.ifr_flags &= ~IFF_PROMISC
fcntl.ioctl(s.fileno(), SIOCSIFFLAGS, ifr)
There is another way I thought of. Maybe not as elegant but seems to work fine.
In linux (with root permissions), one can use :
# ifconfig eth0 promisc
# ifconfig eth0 -promisc
To enable/ disable promisc mode on your interface (eth0 in this case).
So, in python (with root permissions) one could use :
import os
ret = os.system("ifconfig eth0 promisc")
if ret == 0:
<Do something>
Comments are welcome on this way of doing it.
I posted Python find first network hop about trying to find the first hop and the more I thought about it, the easier it seemed like it would be a process the routing table in python. I'm not a programmer, I don't know what I'm doing. :p
This is what I came up with, the first issue I noticed is the loopback interface doesn't show up in the /proc/net/route file- so evaluating 127.0.0.0/8 will give you the default route... for my application, that doesn't matter.
Anything else major I'm overlooking? Is parsing ip route get <ip> still a better idea?
import re
import struct
import socket
'''
Read all the routes into a list. Most specific first.
# eth0 000219AC 04001EAC 0003 0 0 0 00FFFFFF ...
'''
def _RtTable():
_rt = []
rt_m = re.compile('^[a-z0-9]*\W([0-9A-F]{8})\W([0-9A-F]{8})[\W0-9]*([0-9A-F]{8})')
rt = open('/proc/net/route', 'r')
for line in rt.read().split('\n'):
if rt_m.match(line):
_rt.append(rt_m.findall(line)[0])
rt.close()
return _rt
'''
Create a temp ip (tip) that is the entered ip with the host
section striped off. Matching to routers in order,
the first match should be the most specific.
If we get 0.0.0.0 as the next hop, the network is likely(?)
directly attached- the entered IP is the next (only) hop
'''
def FindGw(ip):
int_ip = struct.unpack("I", socket.inet_aton(ip))[0]
for entry in _RtTable():
tip = int_ip & int(entry[2], 16)
if tip == int(entry[0], 16):
gw_s = socket.inet_ntoa(struct.pack("I", int(entry[1], 16)))
if gw_s == '0.0.0.0':
return ip
else:
return gw_s
if __name__ == '__main__':
import sys
print FindGw(sys.argv[1])
In the man page of proc file system it is given that.
/proc/net
various net pseudo-files, all of which give the status of some part of
the networking layer. These files contain ASCII structures and are,
there‐fore, readable with cat(1).
However, the standard netstat(8) suite provides much
cleaner access to these files.
Just rely on the tools designed for those purposes. Use netstat, traceroute or any other standard tool. Wrap those commands cleanly using subprocess module and get the information for what you are looking for.
With pyroute2.IPRoute, get the next hop on the way to some distant host, here — 8.8.8.8:
from pyroute2 import IPRoute
with IPRoute() as ipr:
print(ipr.route('get', dst='8.8.8.8'))
Is there anyway to get the names of the NIC cards in the machine etc. eth0, lo? If so how do you do it?
I have researched but so far I have only found code to get IP addresses and MAC addresses only such as
import socket
socket.gethostbyname(socket.gethostname())
Advice on the code would really be appreciated.
A great Python library I have used to do this is psutil. It can be used on Linux, Windows, and OSX among other platforms and is supported from Python 2.6 to 3.6.
Psutil provides the net_if_addrs() function which returns a dictionary where keys are the NIC names and value is a list of named tuples for each address assigned to the NIC which include the address family, NIC address, netmask, broadcast address, and destination address.
A simple example using net_if_addrs() which will print a Python list of the NIC names:
import psutil
addrs = psutil.net_if_addrs()
print(addrs.keys())
On Linux, you can just list the links in /sys/class/net/ by
os.listdir('/sys/class/net/')
Not sure if this works on all distributions.
Since this answer pops up in Google when I search for this information, I thought I should add my technique for getting the available interfaces (as well as IP addresses). The very nice module netifaces takes care of that, in a portable manner.
socket module in Python >= 3.3:
import socket
# Return a list of network interface information
socket.if_nameindex()
https://docs.python.org/3/library/socket.html#socket.if_nameindex
I don't think there's anything in the standard library to query these names.
If I needed these names on a Linux system I would parse the output of ifconfig or the contents of /proc/net/dev. Look at this blog entry for a similar problem.
Using python's ctypes you can make a call to the C library function getifaddrs:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from ctypes import *
class Sockaddr(Structure):
_fields_ = [('sa_family', c_ushort), ('sa_data', c_char * 14)]
class Ifa_Ifu(Union):
_fields_ = [('ifu_broadaddr', POINTER(Sockaddr)),
('ifu_dstaddr', POINTER(Sockaddr))]
class Ifaddrs(Structure):
pass
Ifaddrs._fields_ = [('ifa_next', POINTER(Ifaddrs)), ('ifa_name', c_char_p),
('ifa_flags', c_uint), ('ifa_addr', POINTER(Sockaddr)),
('ifa_netmask', POINTER(Sockaddr)), ('ifa_ifu', Ifa_Ifu),
('ifa_data', c_void_p)]
def get_interfaces():
libc = CDLL('libc.so.6')
libc.getifaddrs.restype = c_int
ifaddr_p = pointer(Ifaddrs())
ret = libc.getifaddrs(pointer((ifaddr_p)))
interfaces = set()
head = ifaddr_p
while ifaddr_p:
interfaces.add(ifaddr_p.contents.ifa_name)
ifaddr_p = ifaddr_p.contents.ifa_next
libc.freeifaddrs(head)
return interfaces
if __name__ == "__main__":
print(get_interfaces())
Do note though this method is not portable.
To add to what #Kristian Evensen's mentions, here is what I used for a problem i was having.
If you are looking to just get a list of the interfaces, use:
interface_list = netifaces.interfaces()
If you are wanting a specific interface, but don't know what the number at the end is (ie: eth0), use:
interface_list = netifaces.interfaces()
interface = filter(lambda x: 'eth' in x,interface_list)
Like David Breuer say, you can just list the directory "/ sys / class / net" on Linux. (It works on Fedora at least). If you need detailled information about some interface you can navigate on the intefaces's directories for more.
def getAllInterfaces():
return os.listdir('/sys/class/net/')
There is a python package get-nic which gives NIC status, up\down, ip addr, mac addr etc
pip install get-nic
from get_nic import getnic
getnic.interfaces()
Output: ["eth0", "wlo1"]
interfaces = getnic.interfaces()
getnic.ipaddr(interfaces)
Output:
{'lo': {'state': 'UNKNOWN', 'inet4': '127.0.0.1/8', 'inet6': '::1/128'}, 'enp3s0': {'state': 'DOWN', 'HWaddr': 'a4:5d:36:c2:34:3e'}, 'wlo1': {'state': 'UP', 'HWaddr': '48:d2:24:7f:63:10', 'inet4': '10.16.1.34/24', 'inet6': 'fe80::ab4a:95f7:26bd:82dd/64'}}
Refer GitHub page for more information: https://github.com/tech-novic/get-nic-details
I am running my code on multiple VPSes (with more than one IP, which are set up as aliases to the network interfaces) and I am trying to figure out a way such that my code acquires the IP addresses from the network interfaces on the fly and bind to it. Any ideas on how to do it in python without adding a 3rd party library ?
Edit I know about socket.gethostbyaddr(socket.gethostname()) and about the 3rd party package netifaces, but I am looking for something more elegant from the standard library ... and parsing the output of the ifconfig command is not something elegant :)
The IP addresses are assigned to your VPSes, no possibility to change them on the fly.
You have to open a SSH tunnel to or install a proxy on your VPSes.
I think a SSH tunnel would be the best way how to do it, and then use it as SOCKS5 proxy from Python.
This is how to get all IP addresses of the server the script is running on:
(this is as much elegant as possible and it only needs the standard library)
import socket
import fcntl
import struct
import array
def all_interfaces():
max_possible = 128 # arbitrary. raise if needed.
bytes = max_possible * 32
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
names = array.array('B', '\0' * bytes)
outbytes = struct.unpack('iL', fcntl.ioctl(
s.fileno(),
0x8912, # SIOCGIFCONF
struct.pack('iL', bytes, names.buffer_info()[0])
))[0]
namestr = names.tostring()
return [namestr[i:i+32].split('\0', 1)[0] for i in range(0, outbytes, 32)]