2 Netlink message generation/parsing
4 Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
6 GPLv2+; See copying for details.
14 # try to use python 2.5's netlink support
15 _dummysock
= socket
.socket(socket
.AF_NETLINK
, socket
.SOCK_RAW
, 0)
16 _dummysock
.bind((0, 0))
19 def _nl_bind(descriptor
, addr
):
22 def _nl_getsockname(descriptor
):
23 return descriptor
.getsockname()
25 def _nl_send(descriptor
, msg
):
28 def _nl_recv(descriptor
, bufs
=16384):
29 return descriptor
.recvfrom(bufs
)
31 # or fall back to the _netlink C module
35 def _nl_bind(descriptor
, addr
):
36 _netlink
.bind(descriptor
.fileno(), addr
[1])
38 def _nl_getsockname(descriptor
):
39 return _netlink
.getsockname(descriptor
.fileno())
41 def _nl_send(descriptor
, msg
):
42 _netlink
.send(descriptor
.fileno(), msg
)
44 def _nl_recv(descriptor
, bufs
=16384):
45 return _netlink
.recvfrom(descriptor
.fileno(), bufs
)
47 # or fall back to the ctypes module
50 libc
= ctypes
.CDLL(None)
52 class SOCKADDR_NL(ctypes
.Structure
):
53 _fields_
= [("nl_family", ctypes
.c_ushort
),
54 ("nl_pad", ctypes
.c_ushort
),
55 ("nl_pid", ctypes
.c_int
),
56 ("nl_groups", ctypes
.c_int
)]
58 def _nl_bind(descriptor
, addr
):
59 addr
= SOCKADDR_NL(socket
.AF_NETLINK
, 0, os
.getpid(), 0)
60 return libc
.bind(descriptor
.fileno(),
64 def _nl_getsockname(descriptor
):
65 addr
= SOCKADDR_NL(0, 0, 0, 0)
66 len = ctypes
.c_int(ctypes
.sizeof(addr
))
67 libc
.getsockname(descriptor
.fileno(),
70 return addr
.nl_pid
, addr
.nl_groups
72 def _nl_send(descriptor
, msg
):
73 return libc
.send(descriptor
.fileno(), msg
, len(msg
), 0)
75 def _nl_recv(descriptor
, bufs
=16384):
76 addr
= SOCKADDR_NL(0, 0, 0, 0)
77 len = ctypes
.c_int(ctypes
.sizeof(addr
))
78 buf
= ctypes
.create_string_buffer(bufs
)
80 r
= libc
.recvfrom(descriptor
.fileno(),
82 ctypes
.pointer(addr
), ctypes
.pointer(len))
84 ret
= ctypes
.string_at(ctypes
.pointer(buf
), r
)
85 return ret
, (addr
.nl_pid
, addr
.nl_groups
)
103 def __init__(self
, attr_type
, data
, *values
):
104 self
.type = attr_type
106 self
.data
= struct
.pack(data
, *values
)
111 hdr
= struct
.pack("HH", len(self
.data
) + 4, self
.type)
112 length
= len(self
.data
)
113 pad
= ((length
+ 4 - 1) & ~
3) - length
114 return hdr
+ self
.data
+ b
'\0' * pad
117 return '<Attr type %d, data "%s">' % (self
.type, repr(self
.data
))
120 return struct
.unpack('H', self
.data
)[0]
123 return struct
.unpack('h', self
.data
)[0]
126 return struct
.unpack('I', self
.data
)[0]
129 return struct
.unpack('i', self
.data
)[0]
135 return self
.data
.split('\0')[0]
138 return parse_attributes(self
.data
)
142 def __init__(self
, attr_type
, data
):
143 Attr
.__init
__(self
, attr_type
, "%ds" % len(data
), data
.encode('utf-8'))
146 class NulStrAttr(Attr
):
147 def __init__(self
, attr_type
, data
):
149 attr_type
, "%dsB" % len(data
), data
.encode('utf-8'), 0)
153 def __init__(self
, attr_type
, val
):
154 Attr
.__init
__(self
, attr_type
, "I", val
)
158 def __init__(self
, attr_type
, val
):
159 Attr
.__init
__(self
, attr_type
, "B", val
)
163 def __init__(self
, attr_type
, attrs
):
165 self
.type = attr_type
169 for attr
in self
.attrs
:
170 contents
.append(attr
._dump
())
171 contents
= ''.join(contents
)
172 length
= len(contents
)
173 hdr
= struct
.pack("HH", length
+ 4, self
.type)
174 return hdr
+ contents
180 NETLINK_INET_DIAG
= 4
186 NETLINK_FIB_LOOKUP
= 10
187 NETLINK_CONNECTOR
= 11
188 NETLINK_NETFILTER
= 12
191 NETLINK_KOBJECT_UEVENT
= 15
196 def __init__(self
, msg_type
, flags
=0, seq
=-1, payload
=None):
201 payload
= payload
or []
202 if isinstance(payload
, list):
205 contents
.append(attr
._dump
())
206 self
.payload
= b
''.join(contents
)
208 self
.payload
= payload
210 def send(self
, conn
):
212 self
.seq
= conn
.seq()
215 length
= len(self
.payload
)
217 hdr
= struct
.pack("IHHII", length
+ 4 * 4, self
.type,
218 self
.flags
, self
.seq
, self
.pid
)
219 conn
.send(hdr
+ self
.payload
)
222 return '<netlink.Message type=%d, pid=%d, seq=%d, flags=0x%x "%s">' % (
223 self
.type, self
.pid
, self
.seq
, self
.flags
, repr(self
.payload
))
228 def __init__(self
, nltype
, groups
=0, unexpected_msg_handler
=None):
229 self
.descriptor
= socket
.socket(socket
.AF_NETLINK
,
230 socket
.SOCK_RAW
, nltype
)
231 self
.descriptor
.setsockopt(socket
.SOL_SOCKET
, socket
.SO_SNDBUF
, 65536)
232 self
.descriptor
.setsockopt(socket
.SOL_SOCKET
, socket
.SO_RCVBUF
, 65536)
233 _nl_bind(self
.descriptor
, (0, groups
))
234 self
.pid
, self
.groups
= _nl_getsockname(self
.descriptor
)
236 self
.unexpected
= unexpected_msg_handler
239 _nl_send(self
.descriptor
, msg
)
242 contents
, (nlpid
, nlgrps
) = _nl_recv(self
.descriptor
)
243 # XXX: python doesn't give us message flags, check
244 # len(contents) vs. msglen for TRUNC
245 msglen
, msg_type
, flags
, seq
, pid
= struct
.unpack("IHHII",
247 msg
= Message(msg_type
, flags
, seq
, contents
[16:])
249 if msg
.type == NLMSG_ERROR
:
250 errno
= -struct
.unpack("i", msg
.payload
[:4])[0]
252 err
= OSError("Netlink error: %s (%d)" % (
253 os
.strerror(errno
), errno
))
263 def parse_attributes(data
):
266 attr_len
, attr_type
= struct
.unpack("HH", data
[:4])
267 attrs
[attr_type
] = Attr(attr_type
, data
[4:attr_len
])
268 attr_len
= ((attr_len
+ 4 - 1) & ~
3)
269 data
= data
[attr_len
:]