2 Netlink message generation/parsing
4 Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
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
29 raise ImportError("This is neither python 2.5 nor is "
30 "the _netlink C module available!")
31 def _nl_bind(descriptor
, addr
):
32 _netlink
.bind(descriptor
.fileno(), addr
[1])
33 def _nl_getsockname(descriptor
):
34 return _netlink
.getsockname(descriptor
.fileno())
35 def _nl_send(descriptor
, msg
):
36 _netlink
.send(descriptor
.fileno(), msg
)
37 def _nl_recv(descriptor
, bufs
=16384):
38 return _netlink
.recvfrom(descriptor
.fileno(), bufs
)
54 def __init__(self
, attr_type
, data
, *values
):
57 self
.data
= struct
.pack(data
, *values
)
62 hdr
= struct
.pack("HH", len(self
.data
)+4, self
.type)
63 length
= len(self
.data
)
64 pad
= ((length
+ 4 - 1) & ~
3 ) - length
65 return hdr
+ self
.data
+ '\0' * pad
68 return '<Attr type %d, data "%s">' % (self
.type, repr(self
.data
))
71 return struct
.unpack('H', self
.data
)[0]
73 return struct
.unpack('h', self
.data
)[0]
75 return struct
.unpack('I', self
.data
)[0]
77 return struct
.unpack('i', self
.data
)[0]
81 return self
.data
.split('\0')[0]
83 return parse_attributes(self
.data
)
86 def __init__(self
, attr_type
, data
):
87 Attr
.__init
__(self
, attr_type
, "%ds" % len(data
), data
)
89 class NulStrAttr(Attr
):
90 def __init__(self
, attr_type
, data
):
91 Attr
.__init
__(self
, attr_type
, "%dsB" % len(data
), data
, 0)
94 def __init__(self
, attr_type
, val
):
95 Attr
.__init
__(self
, attr_type
, "L", val
)
98 def __init__(self
, attr_type
, val
):
99 Attr
.__init
__(self
, attr_type
, "B", val
)
102 def __init__(self
, attr_type
, attrs
):
104 self
.type = attr_type
108 for attr
in self
.attrs
:
109 contents
.append(attr
._dump
())
110 contents
= ''.join(contents
)
111 length
= len(contents
)
112 hdr
= struct
.pack("HH", length
+4, self
.type)
113 return hdr
+ contents
119 NETLINK_INET_DIAG
= 4
125 NETLINK_FIB_LOOKUP
= 10
126 NETLINK_CONNECTOR
= 11
127 NETLINK_NETFILTER
= 12
130 NETLINK_KOBJECT_UEVENT
= 15
134 def __init__(self
, msg_type
, flags
=0, seq
=-1, payload
=None):
139 payload
= payload
or []
140 if isinstance(payload
, list):
143 contents
.append(attr
._dump
())
144 self
.payload
= ''.join(contents
)
146 self
.payload
= payload
148 def send(self
, conn
):
150 self
.seq
= conn
.seq()
153 length
= len(self
.payload
)
155 hdr
= struct
.pack("IHHII", length
+ 4*4, self
.type,
156 self
.flags
, self
.seq
, self
.pid
)
157 conn
.send(hdr
+ self
.payload
)
160 return '<netlink.Message type=%d, pid=%d, seq=%d, flags=0x%x "%s">' % (
161 self
.type, self
.pid
, self
.seq
, self
.flags
, repr(self
.payload
))
164 def __init__(self
, nltype
, groups
=0, unexpected_msg_handler
=None):
165 self
.descriptor
= socket
.socket(socket
.AF_NETLINK
,
166 socket
.SOCK_RAW
, nltype
)
167 self
.descriptor
.setsockopt(socket
.SOL_SOCKET
, socket
.SO_SNDBUF
, 65536)
168 self
.descriptor
.setsockopt(socket
.SOL_SOCKET
, socket
.SO_RCVBUF
, 65536)
169 _nl_bind(self
.descriptor
, (0, groups
))
170 self
.pid
, self
.groups
= _nl_getsockname(self
.descriptor
)
172 self
.unexpected
= unexpected_msg_handler
174 _nl_send(self
.descriptor
, msg
)
176 contents
, (nlpid
, nlgrps
) = _nl_recv(self
.descriptor
)
177 # XXX: python doesn't give us message flags, check
178 # len(contents) vs. msglen for TRUNC
179 msglen
, msg_type
, flags
, seq
, pid
= struct
.unpack("IHHII",
181 msg
= Message(msg_type
, flags
, seq
, contents
[16:])
183 if msg
.type == NLMSG_ERROR
:
185 errno
= -struct
.unpack("i", msg
.payload
[:4])[0]
187 err
= OSError("Netlink error: %s (%d)" % (
188 os
.strerror(errno
), errno
))
196 def parse_attributes(data
):
199 attr_len
, attr_type
= struct
.unpack("HH", data
[:4])
200 attrs
[attr_type
] = Attr(attr_type
, data
[4:attr_len
])
201 attr_len
= ((attr_len
+ 4 - 1) & ~
3 )
202 data
= data
[attr_len
:]