Mailing List Archive

Get 'ifconfig' information via Python
So, I think I'm getting close...

import fcntl
import IN
import struct

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

res = fcntl.ioctl(s, IN.SIOCSIFHWADDR, ??????)

I can't seem to find what goes in ?????.

Is this the right way to be doing things? I suppose I can always go
pull apart the sources for ifconfig itself, and make a .so that does
what I need, but I get the feeling that I can do what I need from
within Python.

Yeah, I could popen ifconfig, too, but that's ugly.

Downloading python sources now to see what I can see in the fcntl
module...

Thanks,
--
David N. Welton, Web Engineer, Linuxcare, Inc.
415.354.4878 x241 tel, 415.701.7457 fax
dwelton@linuxcare.com, http://www.linuxcare.com/
Linuxcare. At the center of Linux.
Get 'ifconfig' information via Python [ In reply to ]
David N. Welton wrote:
>
> So, I think I'm getting close...
>
> import fcntl
> import IN
> import struct
>
> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>
> res = fcntl.ioctl(s, IN.SIOCSIFHWADDR, ??????)
>
> I can't seem to find what goes in ?????.
>
> Is this the right way to be doing things? I suppose I can always go
> pull apart the sources for ifconfig itself, and make a .so that does
> what I need, but I get the feeling that I can do what I need from
> within Python.
>
> Yeah, I could popen ifconfig, too, but that's ugly.
>
> Downloading python sources now to see what I can see in the fcntl
> module...

The .ioctl() function can take a string or an integer as
third argument. To find out what to pass for a given option,
look at man ioctl and man ioctl_list. The exact meaning is
not mentioned there unfortunately, though.

On Linux, just dig into the net/core/dev.c file to find out
what happens for the above option:

The argument is being interpreted as struct ifreq and then copied
to ifr...

case SIOCGIFHWADDR:
memcpy(ifr.ifr_hwaddr.sa_data,dev->dev_addr, MAX_ADDR_LE
ifr.ifr_hwaddr.sa_family=dev->type;
goto rarok;

case SIOCSIFHWADDR:
if(dev->set_mac_address==NULL)
return -EOPNOTSUPP;
if(securelevel > 0)
return -EPERM;
if(ifr.ifr_hwaddr.sa_family!=dev->type)
return -EINVAL;
ret=dev->set_mac_address(dev,&ifr.ifr_hwaddr);
break;

The basic ifreq struct is defined in include/linux/if.h:

/*
* Interface request structure used for socket
* ioctl's. All interface ioctl's must have parameter
* definitions which begin with ifr_name. The
* remainder may be interface specific.
*/

struct ifreq
{
#define IFHWADDRLEN 6
#define IFNAMSIZ 16
union
{
char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" *
} ifr_ifrn;

union {
struct sockaddr ifru_addr;
struct sockaddr ifru_dstaddr;
struct sockaddr ifru_broadaddr;
struct sockaddr ifru_netmask;
struct sockaddr ifru_hwaddr;
short ifru_flags;
int ifru_metric;
int ifru_mtu;
struct ifmap ifru_map;
char ifru_slave[IFNAMSIZ]; /* Just fits the size */
caddr_t ifru_data;
} ifr_ifru;
};

#define ifr_name ifr_ifrn.ifrn_name /* interface name */
#define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */
#define ifr_addr ifr_ifru.ifru_addr /* address */
#define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-p lnk */
#define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */
#define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */
#define ifr_flags ifr_ifru.ifru_flags /* flags */
#define ifr_metric ifr_ifru.ifru_metric /* metric */
#define ifr_mtu ifr_ifru.ifru_mtu /* mtu */
#define ifr_map ifr_ifru.ifru_map /* device map */
#define ifr_slave ifr_ifru.ifru_slave /* slave device */
#define ifr_data ifr_ifru.ifru_data /* for use by interface */

Building these structs can be done using the Python struct
module... playing around with this can probably crash your system
though.

In the end, I think you're better off hacking together a
new extension module.

Hope that helps.

--
Marc-Andre Lemburg
______________________________________________________________________
Y2000: 149 days left
Business: http://www.lemburg.com/
Python Pages: http://www.lemburg.com/python/
Get 'ifconfig' information via Python [ In reply to ]
M.-A. Lemburg wrote:
>
> David N. Welton wrote:
> >
> > So, I think I'm getting close...
> >
> > import fcntl
> > import IN
> > import struct
> >
> > s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
> >
> > res = fcntl.ioctl(s, IN.SIOCSIFHWADDR, ??????)

And one more thing: the first argument must be the file handle,
i.e. s.fileno() in this case.

Setting the hardware address is only allowed for super users,
BTW:

>>> fcntl.ioctl(s.fileno(), IN.SIOCSIFHWADDR, '')
Traceback (innermost last):
File "<stdin>", line 1, in ?
IOError: (1, 'Operation not permitted')

--

Would be nice to have an output interface for ioctl() too. That
way we could access many interesting technical details
about the system running the program. This should be easy to
implement: instead of returning just the return code integer,
the function could return a tuple (RC, buffer) and then leave
the parsing of the buffer to the user.

--
Marc-Andre Lemburg
______________________________________________________________________
Y2000: 149 days left
Business: http://www.lemburg.com/
Python Pages: http://www.lemburg.com/python/
Get 'ifconfig' information via Python [ In reply to ]
Hi All--

"M.-A. Lemburg" wrote:
>
> David N. Welton wrote:
> >
> > So, I think I'm getting close...
> >
> > import fcntl
> > import IN
> > import struct
> >
> > s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
> >
> > res = fcntl.ioctl(s, IN.SIOCSIFHWADDR, ??????)
> >
> > I can't seem to find what goes in ?????.
> >

[snip]

> The .ioctl() function can take a string or an integer as
> third argument.

[snip]

>
> Building these structs can be done using the Python struct
> module... playing around with this can probably crash your system
> though.
>
> In the end, I think you're better off hacking together a
> new extension module.
>

Why on earth would reading this information into a struct crash his
system? Or am I missing something here? At worst, writing a messed-up
struct might hose his ethernet connection, but I really doubt that he
would be any more likely to crash his system using Python than C.

<c-is-your-friend-while-it-gnaws-your-hand-off>-ly y'rs,
Ivan
----------------------------------------------
Ivan Van Laningham
Callware Technologies, Inc.
ivanlan@callware.com
ivanlan@home.com
http://www.pauahtun.org
See also:
http://www.foretec.com/python/workshops/1998-11/proceedings.html
Army Signal Corps: Cu Chi, Class of '70
----------------------------------------------
Get 'ifconfig' information via Python [ In reply to ]
Ivan Van Laningham <ivanlan@callware.com> writes:

> Hi All--
>
> "M.-A. Lemburg" wrote:
> >
> > David N. Welton wrote:

> > > res = fcntl.ioctl(s, IN.SIOCSIFHWADDR, ??????)
^^^^^^^^^^^^^

> > Building these structs can be done using the Python struct
> > module... playing around with this can probably crash your system
> > though.

> > In the end, I think you're better off hacking together a
> > new extension module.

This is what I've been working towards... seems easier than futzing
with the 'struct' module stuff.

> Why on earth would reading this information into a struct crash his
> system? Or am I missing something here? At worst, writing a
> messed-up struct might hose his ethernet connection, but I really
> doubt that he would be any more likely to crash his system using
> Python than C.

I made a mistake and put SIOC*S*IFHWADDR instead of SIOC*G*IFHWADDR,
which is what I really meant.

Ciao,
--
David N. Welton, Web Engineer, Linuxcare, Inc.
415.354.4878 x241 tel, 415.701.7457 fax
dwelton@linuxcare.com, http://www.linuxcare.com/
Linuxcare. At the center of Linux.
Get 'ifconfig' information via Python [ In reply to ]
Dear David,
I really like the idea of writing an extension module.
I was writing Java aplications under windows and
ran into a complete brick wall because there was
no "inherent" way to get this data with the defined APIs.
There was just no expectation for multi-homed systems
as far as I could tell.

Please add me to your list of interested parties, if you
are compiling such a thing.
I've never written an extension module for python
but have done several python scripts which grabbed the relevant
numbers out of os.popen("ifconfig").read()
I'm really interested in seing this solved "the right way".
Perhaps a request should be made on cosource.com?

This is a problem that needs a real cross-platform solution.
-pehr


"M.-A. Lemburg" wrote:

> David N. Welton wrote:
> >
> > So, I think I'm getting close...
> >
> > import fcntl
> > import IN
> > import struct
> >
> > s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
> >
> > res = fcntl.ioctl(s, IN.SIOCSIFHWADDR, ??????)
> >
> > I can't seem to find what goes in ?????.
> >
> > Is this the right way to be doing things? I suppose I can always go
> > pull apart the sources for ifconfig itself, and make a .so that does
> > what I need, but I get the feeling that I can do what I need from
> > within Python.
> >
> > Yeah, I could popen ifconfig, too, but that's ugly.
> >
> > Downloading python sources now to see what I can see in the fcntl
> > module...
>
> The .ioctl() function can take a string or an integer as
> third argument. To find out what to pass for a given option,
> look at man ioctl and man ioctl_list. The exact meaning is
> not mentioned there unfortunately, though.
>
> On Linux, just dig into the net/core/dev.c file to find out
> what happens for the above option:
>
> The argument is being interpreted as struct ifreq and then copied
> to ifr...
>
> case SIOCGIFHWADDR:
> memcpy(ifr.ifr_hwaddr.sa_data,dev->dev_addr, MAX_ADDR_LE
> ifr.ifr_hwaddr.sa_family=dev->type;
> goto rarok;
>
> case SIOCSIFHWADDR:
> if(dev->set_mac_address==NULL)
> return -EOPNOTSUPP;
> if(securelevel > 0)
> return -EPERM;
> if(ifr.ifr_hwaddr.sa_family!=dev->type)
> return -EINVAL;
> ret=dev->set_mac_address(dev,&ifr.ifr_hwaddr);
> break;
>
> The basic ifreq struct is defined in include/linux/if.h:
>
> /*
> * Interface request structure used for socket
> * ioctl's. All interface ioctl's must have parameter
> * definitions which begin with ifr_name. The
> * remainder may be interface specific.
> */
>
> struct ifreq
> {
> #define IFHWADDRLEN 6
> #define IFNAMSIZ 16
> union
> {
> char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" *
> } ifr_ifrn;
>
> union {
> struct sockaddr ifru_addr;
> struct sockaddr ifru_dstaddr;
> struct sockaddr ifru_broadaddr;
> struct sockaddr ifru_netmask;
> struct sockaddr ifru_hwaddr;
> short ifru_flags;
> int ifru_metric;
> int ifru_mtu;
> struct ifmap ifru_map;
> char ifru_slave[IFNAMSIZ]; /* Just fits the size */
> caddr_t ifru_data;
> } ifr_ifru;
> };
>
> #define ifr_name ifr_ifrn.ifrn_name /* interface name */
> #define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */
> #define ifr_addr ifr_ifru.ifru_addr /* address */
> #define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-p lnk */
> #define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */
> #define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */
> #define ifr_flags ifr_ifru.ifru_flags /* flags */
> #define ifr_metric ifr_ifru.ifru_metric /* metric */
> #define ifr_mtu ifr_ifru.ifru_mtu /* mtu */
> #define ifr_map ifr_ifru.ifru_map /* device map */
> #define ifr_slave ifr_ifru.ifru_slave /* slave device */
> #define ifr_data ifr_ifru.ifru_data /* for use by interface */
>
> Building these structs can be done using the Python struct
> module... playing around with this can probably crash your system
> though.
>
> In the end, I think you're better off hacking together a
> new extension module.
>
> Hope that helps.
>
> --
> Marc-Andre Lemburg
> ______________________________________________________________________
> Y2000: 149 days left
> Business: http://www.lemburg.com/
> Python Pages: http://www.lemburg.com/python/
Get 'ifconfig' information via Python [ In reply to ]
Ivan Van Laningham wrote:
>
> > The fcntl.ioctl() function can take a string or an integer as
> > third argument.
>
> [snip]
>
> >
> > Building these structs can be done using the Python struct
> > module... playing around with this can probably crash your system
> > though.
> >
> > In the end, I think you're better off hacking together a
> > new extension module.
> >
>
> Why on earth would reading this information into a struct crash his
> system? Or am I missing something here? At worst, writing a messed-up
> struct might hose his ethernet connection, but I really doubt that he
> would be any more likely to crash his system using Python than C.

The ioctl() gives you access to very low-level structures of
the whole system, not only the ethernet devices. Started as root
(which he would have to do to set the ethernet hardware address),
such a script could do plenty of damage in all kinds of weird areas
that are accessible to ioctl().

In David's case only his ethernet device would go wild, I guess.
I still think that accessing the data via an extension is safer
-- at least the module won't work on platforms that the extension
was not compiled for. The Python version will run on all platforms
having fcntl.ioctl() and it is likely that the device struct
layout changes from platform to platform.

--
Marc-Andre Lemburg
______________________________________________________________________
Y2000: 147 days left
Business: http://www.lemburg.com/
Python Pages: http://www.lemburg.com/python/