Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

decoding ctypes structures

I'm trying to get my head around ctypes in python, and I'm able to get some simple things working, but when it comes to unpacking c structs I find myself running into some difficulties. I decided that to learn this I should play around a bit, and while I know the socket standard library implements gethostbyname_ex(), I thought I'd make an attempt at implementing it using ctypes and libc.gethostbyname().

I'm able to execute libc.gethostbyname() fairly easily:

#!/usr/bin/env python
from ctypes import *

cdll.LoadLibrary('libc.so.6')
libc = CDLL('libc.so.6')
he = libc.gethostbyname("www.google.com")

But that gives me a hostent data-structure. I thought the best way to unpack this would be to grab the c struct and create a class which inherits from ctypes.Structure, and so I came up with this (I found the hostent struct definition in netdb.h):

class hostent(Structure):
    '''
    struct hostent
    {
      char *h_name;                 /* Official name of host.  */
      char **h_aliases;             /* Alias list.  */
      int h_addrtype;               /* Host address type.  */
      int h_length;                 /* Length of address.  */
      char **h_addr_list;           /* List of addresses from name server. */
    }
    '''
    _fields_ = [("h_name", c_char_p), ("h_aliases", POINTER(c_char_p)),
                ("h_addrtype", c_int), ("h_length", c_int),
                ("h_addr_list", POINTER(c_char_p))]

Where I'm unclear is whether I've setup the h_aliases and the h_addr_list fields correctly, because whenever I attempt to access them as arrays, even at the 0th index after a lookup of something that I know has at least one alias and at least one address, I get a NULL pointer access ValueError exception:

>>> he = hostent(libc.gethostbyname("www.google.com"))
>>> pprint.pprint(he.h_addr_list)
<__main__.LP_c_char_p object at 0xb75dae84>
>>> print he.h_addr_list[0]
Traceback (most recent call last):
  File "/tmp/py2659JxK", line 24, in <module>
    print he.h_addr_list[0]
ValueError: NULL pointer access

Any suggestions would be welcome.

like image 505
mkomitee Avatar asked Jul 09 '26 21:07

mkomitee


1 Answers

You need to define what the return type of gethostbyname is:

>>> libc.gethostbyname.restype = POINTER(hostent)
>>> he = libc.gethostbyname("www.google.com")[0]
>>> he.h_aliases[0]
'www.google.com'

Also, h_addr_list should not be declared as POINTER(c_char_p), because c_char_p is used for null-terminated strings. In this case POINTER(POINTER(c_ubyte)) would be better, and then the first address would be he.h_addr_list[0][:4] if it's an IPv4 address.

like image 109
interjay Avatar answered Jul 11 '26 11:07

interjay