bd41348575a198a7c14c1c1912ee5f416084c289
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))
18 def _nl_bind(descriptor
, addr
):
20 def _nl_getsockname(descriptor
):
21 return descriptor
.getsockname()
22 def _nl_send(descriptor
, msg
):
24 def _nl_recv(descriptor
, bufs
=16384):
25 return descriptor
.recvfrom(bufs
)
27 # or fall back to the _netlink C module
30 def _nl_bind(descriptor
, addr
):
31 _netlink
.bind(descriptor
.fileno(), addr
[1])
32 def _nl_getsockname(descriptor
):
33 return _netlink
.getsockname(descriptor
.fileno())
34 def _nl_send(descriptor
, msg
):
35 _netlink
.send(descriptor
.fileno(), msg
)
36 def _nl_recv(descriptor
, bufs
=16384):
37 return _netlink
.recvfrom(descriptor
.fileno(), bufs
)
39 # or fall back to the ctypes module
42 libc
= ctypes
.CDLL(None)
44 class SOCKADDR_NL(ctypes
.Structure
):
45 _fields_
= [("nl_family", ctypes
.c_ushort
),
46 ("nl_pad", ctypes
.c_ushort
),
47 ("nl_pid", ctypes
.c_int
),
48 ("nl_groups", ctypes
.c_int
)]
50 def _nl_bind(descriptor
, addr
):
51 addr
= SOCKADDR_NL(socket
.AF_NETLINK
, 0, os
.getpid(), 0)
52 return libc
.bind(descriptor
.fileno(),
56 def _nl_getsockname(descriptor
):
57 addr
= SOCKADDR_NL(0, 0, 0, 0)
58 len = ctypes
.c_int(ctypes
.sizeof(addr
));
59 libc
.getsockname(descriptor
.fileno(),
62 return addr
.nl_pid
, addr
.nl_groups
;
64 def _nl_send(descriptor
, msg
):
65 return libc
.send(descriptor
.fileno(), msg
, len(msg
), 0);
67 def _nl_recv(descriptor
, bufs
=16384):
68 addr
= SOCKADDR_NL(0, 0, 0, 0)
69 len = ctypes
.c_int(ctypes
.sizeof(addr
))
70 buf
= ctypes
.create_string_buffer(bufs
)
72 r
= libc
.recvfrom(descriptor
.fileno(),
74 ctypes
.pointer(addr
), ctypes
.pointer(len))
76 ret
= ctypes
.string_at(ctypes
.pointer(buf
), r
)
77 return ret
, (addr
.nl_pid
, addr
.nl_groups
)
94 def __init__(self
, attr_type
, data
, *values
):
97 self
.data
= struct
.pack(data
, *values
)
102 hdr
= struct
.pack("HH", len(self
.data
)+4, self
.type)
103 length
= len(self
.data
)
104 pad
= ((length
+ 4 - 1) & ~
3 ) - length
105 return hdr
+ self
.data
+ b
'\0' * pad
108 return '<Attr type %d, data "%s">' % (self
.type, repr(self
.data
))
111 return struct
.unpack('H', self
.data
)[0]
113 return struct
.unpack('h', self
.data
)[0]
115 return struct
.unpack('I', self
.data
)[0]
117 return struct
.unpack('i', self
.data
)[0]
121 return self
.data
.split('\0')[0]
123 return parse_attributes(self
.data
)
126 def __init__(self
, attr_type
, data
):
127 Attr
.__init
__(self
, attr_type
, "%ds" % len(data
), data
.encode('utf-8'))
129 class NulStrAttr(Attr
):
130 def __init__(self
, attr_type
, data
):
131 Attr
.__init
__(self
, attr_type
, "%dsB" % len(data
), data
.encode('utf-8'), 0)
134 def __init__(self
, attr_type
, val
):
135 Attr
.__init
__(self
, attr_type
, "I", val
)
138 def __init__(self
, attr_type
, val
):
139 Attr
.__init
__(self
, attr_type
, "B", val
)
142 def __init__(self
, attr_type
, attrs
):
144 self
.type = attr_type
148 for attr
in self
.attrs
:
149 contents
.append(attr
._dump
())
150 contents
= ''.join(contents
)
151 length
= len(contents
)
152 hdr
= struct
.pack("HH", length
+4, self
.type)
153 return hdr
+ contents
159 NETLINK_INET_DIAG
= 4
165 NETLINK_FIB_LOOKUP
= 10
166 NETLINK_CONNECTOR
= 11
167 NETLINK_NETFILTER
= 12
170 NETLINK_KOBJECT_UEVENT
= 15
174 def __init__(self
, msg_type
, flags
=0, seq
=-1, payload
=None):
179 payload
= payload
or []
180 if isinstance(payload
, list):
183 contents
.append(attr
._dump
())
184 self
.payload
= b
''.join(contents
)
186 self
.payload
= payload
188 def send(self
, conn
):
190 self
.seq
= conn
.seq()
193 length
= len(self
.payload
)
195 hdr
= struct
.pack("IHHII", length
+ 4*4, self
.type,
196 self
.flags
, self
.seq
, self
.pid
)
197 conn
.send(hdr
+ self
.payload
)
200 return '<netlink.Message type=%d, pid=%d, seq=%d, flags=0x%x "%s">' % (
201 self
.type, self
.pid
, self
.seq
, self
.flags
, repr(self
.payload
))
204 def __init__(self
, nltype
, groups
=0, unexpected_msg_handler
=None):
205 self
.descriptor
= socket
.socket(socket
.AF_NETLINK
,
206 socket
.SOCK_RAW
, nltype
)
207 self
.descriptor
.setsockopt(socket
.SOL_SOCKET
, socket
.SO_SNDBUF
, 65536)
208 self
.descriptor
.setsockopt(socket
.SOL_SOCKET
, socket
.SO_RCVBUF
, 65536)
209 _nl_bind(self
.descriptor
, (0, groups
))
210 self
.pid
, self
.groups
= _nl_getsockname(self
.descriptor
)
212 self
.unexpected
= unexpected_msg_handler
214 _nl_send(self
.descriptor
, msg
)
216 contents
, (nlpid
, nlgrps
) = _nl_recv(self
.descriptor
)
217 # XXX: python doesn't give us message flags, check
218 # len(contents) vs. msglen for TRUNC
219 msglen
, msg_type
, flags
, seq
, pid
= struct
.unpack("IHHII",
221 msg
= Message(msg_type
, flags
, seq
, contents
[16:])
223 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
:]