netlink.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  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 FlagAttr(Attr):
  61. def __init__(self, attr_type):
  62. Attr.__init__(self, attr_type, "")
  63. class Nested(Attr):
  64. def __init__(self, attr_type, attrs):
  65. self.attrs = attrs
  66. self.type = attr_type
  67. def _dump(self):
  68. contents = []
  69. for attr in self.attrs:
  70. contents.append(attr._dump())
  71. contents = ''.join(contents)
  72. length = len(contents)
  73. hdr = struct.pack("HH", length+4, self.type)
  74. return hdr + contents
  75. NETLINK_ROUTE = 0
  76. NETLINK_UNUSED = 1
  77. NETLINK_USERSOCK = 2
  78. NETLINK_FIREWALL = 3
  79. NETLINK_INET_DIAG = 4
  80. NETLINK_NFLOG = 5
  81. NETLINK_XFRM = 6
  82. NETLINK_SELINUX = 7
  83. NETLINK_ISCSI = 8
  84. NETLINK_AUDIT = 9
  85. NETLINK_FIB_LOOKUP = 10
  86. NETLINK_CONNECTOR = 11
  87. NETLINK_NETFILTER = 12
  88. NETLINK_IP6_FW = 13
  89. NETLINK_DNRTMSG = 14
  90. NETLINK_KOBJECT_UEVENT = 15
  91. NETLINK_GENERIC = 16
  92. class Message(object):
  93. def __init__(self, msg_type, flags=0, seq=-1, payload=None):
  94. self.type = msg_type
  95. self.flags = flags
  96. self.seq = seq
  97. self.pid = -1
  98. payload = payload or []
  99. if isinstance(payload, list):
  100. contents = []
  101. for attr in payload:
  102. contents.append(attr._dump())
  103. self.payload = ''.join(contents)
  104. else:
  105. self.payload = payload
  106. def send(self, conn):
  107. if self.seq == -1:
  108. self.seq = conn.seq()
  109. self.pid = conn.pid
  110. length = len(self.payload)
  111. hdr = struct.pack("IHHII", length + 4*4, self.type,
  112. self.flags, self.seq, self.pid)
  113. conn.send(hdr + self.payload)
  114. def __repr__(self):
  115. return '<netlink.Message type=%d, pid=%d, seq=%d, flags=0x%x "%s">' % (
  116. self.type, self.pid, self.seq, self.flags, repr(self.payload))
  117. @property
  118. def ret(self):
  119. assert self.type == NLMSG_ERROR
  120. return struct.unpack("i", self.payload[:4])[0]
  121. def send_and_recv(self, conn):
  122. self.send(conn)
  123. while True:
  124. m = conn.recv()
  125. if m.seq == self.seq:
  126. return m
  127. class Connection(object):
  128. def __init__(self, nltype, groups=0, unexpected_msg_handler=None):
  129. self.descriptor = socket.socket(socket.AF_NETLINK,
  130. socket.SOCK_RAW, nltype)
  131. self.descriptor.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 65536)
  132. self.descriptor.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 65536)
  133. self.descriptor.bind((0, groups))
  134. self.pid, self.groups = self.descriptor.getsockname()
  135. self._seq = 0
  136. self.unexpected = unexpected_msg_handler
  137. def send(self, msg):
  138. self.descriptor.send(msg)
  139. def recv(self):
  140. contents = self.descriptor.recv(16384)
  141. # XXX: python doesn't give us message flags, check
  142. # len(contents) vs. msglen for TRUNC
  143. msglen, msg_type, flags, seq, pid = struct.unpack("IHHII",
  144. contents[:16])
  145. msg = Message(msg_type, flags, seq, contents[16:])
  146. msg.pid = pid
  147. if msg.type == NLMSG_ERROR:
  148. import os
  149. errno = msg.ret
  150. if errno < 0:
  151. err = OSError("Netlink error: %s (%d)" % (
  152. os.strerror(-errno), -errno))
  153. err.errno = -errno
  154. raise err
  155. return msg
  156. def seq(self):
  157. self._seq += 1
  158. return self._seq
  159. def parse_attributes(data):
  160. attrs = {}
  161. while len(data):
  162. attr_len, attr_type = struct.unpack("HH", data[:4])
  163. attrs[attr_type] = Attr(attr_type, data[4:attr_len])
  164. attr_len = ((attr_len + 4 - 1) & ~3 )
  165. data = data[attr_len:]
  166. return attrs
  167. CTRL_CMD_UNSPEC = 0
  168. CTRL_CMD_NEWFAMILY = 1
  169. CTRL_CMD_DELFAMILY = 2
  170. CTRL_CMD_GETFAMILY = 3
  171. CTRL_CMD_NEWOPS = 4
  172. CTRL_CMD_DELOPS = 5
  173. CTRL_CMD_GETOPS = 6
  174. CTRL_ATTR_UNSPEC = 0
  175. CTRL_ATTR_FAMILY_ID = 1
  176. CTRL_ATTR_FAMILY_NAME = 2
  177. CTRL_ATTR_VERSION = 3
  178. CTRL_ATTR_HDRSIZE = 4
  179. CTRL_ATTR_MAXATTR = 5
  180. CTRL_ATTR_OPS = 6
  181. class GenlHdr(object):
  182. def __init__(self, cmd, version = 0):
  183. self.cmd = cmd
  184. self.version = version
  185. def _dump(self):
  186. return struct.pack("BBxx", self.cmd, self.version)
  187. def _genl_hdr_parse(data):
  188. return GenlHdr(*struct.unpack("BBxx", data))
  189. GENL_ID_CTRL = NLMSG_MIN_TYPE
  190. class GenlMessage(Message):
  191. def __init__(self, family, cmd, attrs=[], flags=0):
  192. Message.__init__(self, family, flags=flags, payload=[GenlHdr(cmd)] + attrs)
  193. class GenlController(object):
  194. def __init__(self, conn):
  195. self.conn = conn
  196. def get_family_id(self, family):
  197. a = NulStrAttr(CTRL_ATTR_FAMILY_NAME, family)
  198. m = GenlMessage(GENL_ID_CTRL, CTRL_CMD_GETFAMILY, flags=NLM_F_REQUEST, attrs=[a])
  199. m.send(self.conn)
  200. m = self.conn.recv()
  201. gh = _genl_hdr_parse(m.payload[:4])
  202. attrs = parse_attributes(m.payload[4:])
  203. return attrs[CTRL_ATTR_FAMILY_ID].u16()
  204. genl_controller = GenlController(Connection(NETLINK_GENERIC))