2 Netlink message generation/parsing
4 Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
6 GPLv2+; See copying for details.
12 # try to use python 2.5's netlink support
13 _dummysock
= socket
.socket(socket
.AF_NETLINK
, socket
.SOCK_RAW
, 0)
14 _dummysock
.bind((0, 0))
16 def _nl_bind(descriptor
, addr
):
18 def _nl_getsockname(descriptor
):
19 return descriptor
.getsockname()
20 def _nl_send(descriptor
, msg
):
22 def _nl_recv(descriptor
, bufs
=16384):
23 return descriptor
.recvfrom(bufs
)
25 # or fall back to the _netlink C module
28 def _nl_bind(descriptor
, addr
):
29 _netlink
.bind(descriptor
.fileno(), addr
[1])
30 def _nl_getsockname(descriptor
):
31 return _netlink
.getsockname(descriptor
.fileno())
32 def _nl_send(descriptor
, msg
):
33 _netlink
.send(descriptor
.fileno(), msg
)
34 def _nl_recv(descriptor
, bufs
=16384):
35 return _netlink
.recvfrom(descriptor
.fileno(), bufs
)
37 # or fall back to the ctypes module
41 libc
= ctypes
.CDLL(None)
43 class SOCKADDR_NL(ctypes
.Structure
):
44 _fields_
= [("nl_family", ctypes
.c_ushort
),
45 ("nl_pad", ctypes
.c_ushort
),
46 ("nl_pid", ctypes
.c_int
),
47 ("nl_groups", ctypes
.c_int
)]
49 def _nl_bind(descriptor
, addr
):
50 addr
= SOCKADDR_NL(socket
.AF_NETLINK
, 0, os
.getpid(), 0)
51 return libc
.bind(descriptor
.fileno(),
55 def _nl_getsockname(descriptor
):
56 addr
= SOCKADDR_NL(0, 0, 0, 0)
57 len = ctypes
.c_int(ctypes
.sizeof(addr
));
58 libc
.getsockname(descriptor
.fileno(),
61 return addr
.nl_pid
, addr
.nl_groups
;
63 def _nl_send(descriptor
, msg
):
64 return libc
.send(descriptor
.fileno(), msg
, len(msg
), 0);
66 def _nl_recv(descriptor
, bufs
=16384):
67 addr
= SOCKADDR_NL(0, 0, 0, 0)
68 len = ctypes
.c_int(ctypes
.sizeof(addr
))
69 buf
= ctypes
.create_string_buffer(bufs
)
71 r
= libc
.recvfrom(descriptor
.fileno(),
73 ctypes
.pointer(addr
), ctypes
.pointer(len))
75 ret
= ctypes
.string_at(ctypes
.pointer(buf
), r
)
76 return ret
, (addr
.nl_pid
, addr
.nl_groups
)
93 def __init__(self
, attr_type
, data
, *values
):
96 self
.data
= struct
.pack(data
, *values
)
101 hdr
= struct
.pack("HH", len(self
.data
)+4, self
.type)
102 length
= len(self
.data
)
103 pad
= ((length
+ 4 - 1) & ~
3 ) - length
104 return hdr
+ self
.data
+ '\0' * pad
107 return '<Attr type %d, data "%s">' % (self
.type, repr(self
.data
))
110 return struct
.unpack('H', self
.data
)[0]
112 return struct
.unpack('h', self
.data
)[0]
114 return struct
.unpack('I', self
.data
)[0]
116 return struct
.unpack('i', self
.data
)[0]
120 return self
.data
.split('\0')[0]
122 return parse_attributes(self
.data
)
125 def __init__(self
, attr_type
, data
):
126 Attr
.__init
__(self
, attr_type
, "%ds" % len(data
), data
)
128 class NulStrAttr(Attr
):
129 def __init__(self
, attr_type
, data
):
130 Attr
.__init
__(self
, attr_type
, "%dsB" % len(data
), data
, 0)
133 def __init__(self
, attr_type
, val
):
134 Attr
.__init
__(self
, attr_type
, "I", val
)
137 def __init__(self
, attr_type
, val
):
138 Attr
.__init
__(self
, attr_type
, "B", val
)
141 def __init__(self
, attr_type
, attrs
):
143 self
.type = attr_type
147 for attr
in self
.attrs
:
148 contents
.append(attr
._dump
())
149 contents
= ''.join(contents
)
150 length
= len(contents
)
151 hdr
= struct
.pack("HH", length
+4, self
.type)
152 return hdr
+ contents
158 NETLINK_INET_DIAG
= 4
164 NETLINK_FIB_LOOKUP
= 10
165 NETLINK_CONNECTOR
= 11
166 NETLINK_NETFILTER
= 12
169 NETLINK_KOBJECT_UEVENT
= 15
173 def __init__(self
, msg_type
, flags
=0, seq
=-1, payload
=None):
178 payload
= payload
or []
179 if isinstance(payload
, list):
182 contents
.append(attr
._dump
())
183 self
.payload
= ''.join(contents
)
185 self
.payload
= payload
187 def send(self
, conn
):
189 self
.seq
= conn
.seq()
192 length
= len(self
.payload
)
194 hdr
= struct
.pack("IHHII", length
+ 4*4, self
.type,
195 self
.flags
, self
.seq
, self
.pid
)
196 conn
.send(hdr
+ self
.payload
)
199 return '<netlink.Message type=%d, pid=%d, seq=%d, flags=0x%x "%s">' % (
200 self
.type, self
.pid
, self
.seq
, self
.flags
, repr(self
.payload
))
203 def __init__(self
, nltype
, groups
=0, unexpected_msg_handler
=None):
204 self
.descriptor
= socket
.socket(socket
.AF_NETLINK
,
205 socket
.SOCK_RAW
, nltype
)
206 self
.descriptor
.setsockopt(socket
.SOL_SOCKET
, socket
.SO_SNDBUF
, 65536)
207 self
.descriptor
.setsockopt(socket
.SOL_SOCKET
, socket
.SO_RCVBUF
, 65536)
208 _nl_bind(self
.descriptor
, (0, groups
))
209 self
.pid
, self
.groups
= _nl_getsockname(self
.descriptor
)
211 self
.unexpected
= unexpected_msg_handler
213 _nl_send(self
.descriptor
, msg
)
215 contents
, (nlpid
, nlgrps
) = _nl_recv(self
.descriptor
)
216 # XXX: python doesn't give us message flags, check
217 # len(contents) vs. msglen for TRUNC
218 msglen
, msg_type
, flags
, seq
, pid
= struct
.unpack("IHHII",
220 msg
= Message(msg_type
, flags
, seq
, contents
[16:])
222 if msg
.type == NLMSG_ERROR
:
224 errno
= -struct
.unpack("i", msg
.payload
[:4])[0]
226 err
= OSError("Netlink error: %s (%d)" % (
227 os
.strerror(errno
), errno
))
235 def parse_attributes(data
):
238 attr_len
, attr_type
= struct
.unpack("HH", data
[:4])
239 attrs
[attr_type
] = Attr(attr_type
, data
[4:attr_len
])
240 attr_len
= ((attr_len
+ 4 - 1) & ~
3 )
241 data
= data
[attr_len
:]