netlink.py 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. #
  2. # (Generic) Netlink message generation/parsing
  3. # Copyright (c) 2007 Johannes Berg <johannes@sipsolutions.net>
  4. # Copyright (c) 2014 Intel Corporation
  5. #
  6. # This software may be distributed under the terms of the BSD license.
  7. # See README for more details.
  8. import struct, socket
  9. # flags
  10. NLM_F_REQUEST = 1
  11. NLM_F_MULTI = 2
  12. NLM_F_ACK = 4
  13. NLM_F_ECHO = 8
  14. # types
  15. NLMSG_NOOP = 1
  16. NLMSG_ERROR = 2
  17. NLMSG_DONE = 3
  18. NLMSG_OVERRUN = 4
  19. NLMSG_MIN_TYPE = 0x10
  20. class Attr(object):
  21. def __init__(self, attr_type, data, *values):
  22. self._type = attr_type
  23. if len(values):
  24. self._data = struct.pack(data, *values)
  25. else:
  26. self._data = data
  27. def _dump(self):
  28. hdr = struct.pack("HH", len(self._data) + 4, self._type)
  29. length = len(self._data)
  30. pad = ((length + 4 - 1) & ~3 ) - length
  31. return hdr + self._data + '\0' * pad
  32. def __repr__(self):
  33. return '<Attr type %d, data "%s">' % (self._type, repr(self._data))
  34. def u16(self):
  35. return struct.unpack('H', self._data)[0]
  36. def s16(self):
  37. return struct.unpack('h', self._data)[0]
  38. def u32(self):
  39. return struct.unpack('I', self._data)[0]
  40. def s32(self):
  41. return struct.unpack('i', self._data)[0]
  42. def str(self):
  43. return self._data
  44. def nulstr(self):
  45. return self._data.split('\0')[0]
  46. def nested(self):
  47. return parse_attributes(self._data)
  48. class StrAttr(Attr):
  49. def __init__(self, attr_type, data):
  50. Attr.__init__(self, attr_type, "%ds" % len(data), data)
  51. class NulStrAttr(Attr):
  52. def __init__(self, attr_type, data):
  53. Attr.__init__(self, attr_type, "%dsB" % len(data), data, 0)
  54. class U32Attr(Attr):
  55. def __init__(self, attr_type, val):
  56. Attr.__init__(self, attr_type, "I", val)
  57. class U8Attr(Attr):
  58. def __init__(self, attr_type, val):
  59. Attr.__init__(self, attr_type, "B", val)
  60. class Nested(Attr):
  61. def __init__(self, attr_type, attrs):
  62. self.attrs = attrs
  63. self.type = attr_type
  64. def _dump(self):
  65. contents = []
  66. for attr in self.attrs:
  67. contents.append(attr._dump())
  68. contents = ''.join(contents)
  69. length = len(contents)
  70. hdr = struct.pack("HH", length+4, self.type)
  71. return hdr + contents
  72. NETLINK_ROUTE = 0
  73. NETLINK_UNUSED = 1
  74. NETLINK_USERSOCK = 2
  75. NETLINK_FIREWALL = 3
  76. NETLINK_INET_DIAG = 4
  77. NETLINK_NFLOG = 5
  78. NETLINK_XFRM = 6
  79. NETLINK_SELINUX = 7
  80. NETLINK_ISCSI = 8
  81. NETLINK_AUDIT = 9
  82. NETLINK_FIB_LOOKUP = 10
  83. NETLINK_CONNECTOR = 11
  84. NETLINK_NETFILTER = 12
  85. NETLINK_IP6_FW = 13
  86. NETLINK_DNRTMSG = 14
  87. NETLINK_KOBJECT_UEVENT = 15
  88. NETLINK_GENERIC = 16
  89. class Message(object):
  90. def __init__(self, msg_type, flags=0, seq=-1, payload=None):
  91. self.type = msg_type
  92. self.flags = flags
  93. self.seq = seq
  94. self.pid = -1
  95. payload = payload or []
  96. if isinstance(payload, list):
  97. contents = []
  98. for attr in payload:
  99. contents.append(attr._dump())
  100. self.payload = ''.join(contents)
  101. else:
  102. self.payload = payload
  103. def send(self, conn):
  104. if self.seq == -1:
  105. self.seq = conn.seq()
  106. self.pid = conn.pid
  107. length = len(self.payload)
  108. hdr = struct.pack("IHHII", length + 4*4, self.type,
  109. self.flags, self.seq, self.pid)
  110. conn.send(hdr + self.payload)
  111. def __repr__(self):
  112. return '<netlink.Message type=%d, pid=%d, seq=%d, flags=0x%x "%s">' % (
  113. self.type, self.pid, self.seq, self.flags, repr(self.payload))
  114. @property
  115. def ret(self):
  116. assert self.type == NLMSG_ERROR
  117. return struct.unpack("i", self.payload[:4])[0]
  118. def send_and_recv(self, conn):
  119. self.send(conn)
  120. while True:
  121. m = conn.recv()
  122. if m.seq == self.seq:
  123. return m
  124. class Connection(object):
  125. def __init__(self, nltype, groups=0, unexpected_msg_handler=None):
  126. self.descriptor = socket.socket(socket.AF_NETLINK,
  127. socket.SOCK_RAW, nltype)
  128. self.descriptor.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 65536)
  129. self.descriptor.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 65536)
  130. self.descriptor.bind((0, groups))
  131. self.pid, self.groups = self.descriptor.getsockname()
  132. self._seq = 0
  133. self.unexpected = unexpected_msg_handler
  134. def send(self, msg):
  135. self.descriptor.send(msg)
  136. def recv(self):
  137. contents = self.descriptor.recv(16384)
  138. # XXX: python doesn't give us message flags, check
  139. # len(contents) vs. msglen for TRUNC
  140. msglen, msg_type, flags, seq, pid = struct.unpack("IHHII",
  141. contents[:16])
  142. msg = Message(msg_type, flags, seq, contents[16:])
  143. msg.pid = pid
  144. if msg.type == NLMSG_ERROR:
  145. import os
  146. errno = msg.ret
  147. if errno < 0:
  148. err = OSError("Netlink error: %s (%d)" % (
  149. os.strerror(-errno), -errno))
  150. err.errno = -errno
  151. raise err
  152. return msg
  153. def seq(self):
  154. self._seq += 1
  155. return self._seq
  156. def parse_attributes(data):
  157. attrs = {}
  158. while len(data):
  159. attr_len, attr_type = struct.unpack("HH", data[:4])
  160. attrs[attr_type] = Attr(attr_type, data[4:attr_len])
  161. attr_len = ((attr_len + 4 - 1) & ~3 )
  162. data = data[attr_len:]
  163. return attrs
  164. CTRL_CMD_UNSPEC = 0
  165. CTRL_CMD_NEWFAMILY = 1
  166. CTRL_CMD_DELFAMILY = 2
  167. CTRL_CMD_GETFAMILY = 3
  168. CTRL_CMD_NEWOPS = 4
  169. CTRL_CMD_DELOPS = 5
  170. CTRL_CMD_GETOPS = 6
  171. CTRL_ATTR_UNSPEC = 0
  172. CTRL_ATTR_FAMILY_ID = 1
  173. CTRL_ATTR_FAMILY_NAME = 2
  174. CTRL_ATTR_VERSION = 3
  175. CTRL_ATTR_HDRSIZE = 4
  176. CTRL_ATTR_MAXATTR = 5
  177. CTRL_ATTR_OPS = 6
  178. class GenlHdr(object):
  179. def __init__(self, cmd, version = 0):
  180. self.cmd = cmd
  181. self.version = version
  182. def _dump(self):
  183. return struct.pack("BBxx", self.cmd, self.version)
  184. def _genl_hdr_parse(data):
  185. return GenlHdr(*struct.unpack("BBxx", data))
  186. GENL_ID_CTRL = NLMSG_MIN_TYPE
  187. class GenlMessage(Message):
  188. def __init__(self, family, cmd, attrs=[], flags=0):
  189. Message.__init__(self, family, flags=flags, payload=[GenlHdr(cmd)] + attrs)
  190. class GenlController(object):
  191. def __init__(self, conn):
  192. self.conn = conn
  193. def get_family_id(self, family):
  194. a = NulStrAttr(CTRL_ATTR_FAMILY_NAME, family)
  195. m = GenlMessage(GENL_ID_CTRL, CTRL_CMD_GETFAMILY, flags=NLM_F_REQUEST, attrs=[a])
  196. m.send(self.conn)
  197. m = self.conn.recv()
  198. gh = _genl_hdr_parse(m.payload[:4])
  199. attrs = parse_attributes(m.payload[4:])
  200. return attrs[CTRL_ATTR_FAMILY_ID].u16()
  201. genl_controller = GenlController(Connection(NETLINK_GENERIC))