core.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793
  1. #
  2. # Netlink interface based on libnl
  3. #
  4. # Copyright (c) 2011 Thomas Graf <tgraf@suug.ch>
  5. #
  6. """netlink library based on libnl
  7. This module provides an interface to netlink sockets
  8. The module contains the following public classes:
  9. - Socket -- The netlink socket
  10. - Message -- The netlink message
  11. - Callback -- The netlink callback handler
  12. - Object -- Abstract object (based on struct nl_obect in libnl) used as
  13. base class for all object types which can be put into a Cache
  14. - Cache -- A collection of objects which are derived from the base
  15. class Object. Used for netlink protocols which maintain a list
  16. or tree of objects.
  17. - DumpParams --
  18. The following exceptions are defined:
  19. - NetlinkError -- Base exception for all general purpose exceptions raised.
  20. - KernelError -- Raised when the kernel returns an error as response to a
  21. request.
  22. All other classes or functions in this module are considered implementation
  23. details.
  24. """
  25. from __future__ import absolute_import
  26. from . import capi
  27. import sys
  28. import socket
  29. __all__ = [
  30. 'Socket',
  31. 'Message',
  32. 'Callback',
  33. 'DumpParams',
  34. 'Object',
  35. 'Cache',
  36. 'KernelError',
  37. 'NetlinkError',
  38. ]
  39. __version__ = '0.1'
  40. # netlink protocols
  41. NETLINK_ROUTE = 0
  42. # NETLINK_UNUSED = 1
  43. NETLINK_USERSOCK = 2
  44. NETLINK_FIREWALL = 3
  45. NETLINK_INET_DIAG = 4
  46. NETLINK_NFLOG = 5
  47. NETLINK_XFRM = 6
  48. NETLINK_SELINUX = 7
  49. NETLINK_ISCSI = 8
  50. NETLINK_AUDIT = 9
  51. NETLINK_FIB_LOOKUP = 10
  52. NETLINK_CONNECTOR = 11
  53. NETLINK_NETFILTER = 12
  54. NETLINK_IP6_FW = 13
  55. NETLINK_DNRTMSG = 14
  56. NETLINK_KOBJECT_UEVENT = 15
  57. NETLINK_GENERIC = 16
  58. NETLINK_SCSITRANSPORT = 18
  59. NETLINK_ECRYPTFS = 19
  60. NL_DONTPAD = 0
  61. NL_AUTO_PORT = 0
  62. NL_AUTO_SEQ = 0
  63. NL_DUMP_LINE = 0
  64. NL_DUMP_DETAILS = 1
  65. NL_DUMP_STATS = 2
  66. NLM_F_REQUEST = 1
  67. NLM_F_MULTI = 2
  68. NLM_F_ACK = 4
  69. NLM_F_ECHO = 8
  70. NLM_F_ROOT = 0x100
  71. NLM_F_MATCH = 0x200
  72. NLM_F_ATOMIC = 0x400
  73. NLM_F_DUMP = NLM_F_ROOT | NLM_F_MATCH
  74. NLM_F_REPLACE = 0x100
  75. NLM_F_EXCL = 0x200
  76. NLM_F_CREATE = 0x400
  77. NLM_F_APPEND = 0x800
  78. class NetlinkError(Exception):
  79. def __init__(self, error):
  80. self._error = error
  81. self._msg = capi.nl_geterror(error)
  82. def __str__(self):
  83. return self._msg
  84. class KernelError(NetlinkError):
  85. def __str__(self):
  86. return 'Kernel returned: {0}'.format(self._msg)
  87. class ImmutableError(NetlinkError):
  88. def __init__(self, msg):
  89. self._msg = msg
  90. def __str__(self):
  91. return 'Immutable attribute: {0}'.format(self._msg)
  92. class Message(object):
  93. """Netlink message"""
  94. def __init__(self, size=0):
  95. if size == 0:
  96. self._msg = capi.nlmsg_alloc()
  97. else:
  98. self._msg = capi.nlmsg_alloc_size(size)
  99. if self._msg is None:
  100. raise Exception('Message allocation returned NULL')
  101. def __del__(self):
  102. capi.nlmsg_free(self._msg)
  103. def __len__(self):
  104. return capi.nlmsg_len(nlmsg_hdr(self._msg))
  105. @property
  106. def protocol(self):
  107. return capi.nlmsg_get_proto(self._msg)
  108. @protocol.setter
  109. def protocol(self, value):
  110. capi.nlmsg_set_proto(self._msg, value)
  111. @property
  112. def maxSize(self):
  113. return capi.nlmsg_get_max_size(self._msg)
  114. @property
  115. def hdr(self):
  116. return capi.nlmsg_hdr(self._msg)
  117. @property
  118. def data(self):
  119. return capi.nlmsg_data(self._msg)
  120. @property
  121. def attrs(self):
  122. return capi.nlmsg_attrdata(self._msg)
  123. def send(self, sock):
  124. sock.send(self)
  125. class Callback(object):
  126. """Netlink callback"""
  127. def __init__(self, kind=capi.NL_CB_DEFAULT):
  128. if isinstance(kind, Callback):
  129. self._cb = capi.py_nl_cb_clone(kind._cb)
  130. else:
  131. self._cb = capi.nl_cb_alloc(kind)
  132. def __del__(self):
  133. capi.py_nl_cb_put(self._cb)
  134. def set_type(self, t, k, handler, obj):
  135. return capi.py_nl_cb_set(self._cb, t, k, handler, obj)
  136. def set_all(self, k, handler, obj):
  137. return capi.py_nl_cb_set_all(self._cb, k, handler, obj)
  138. def set_err(self, k, handler, obj):
  139. return capi.py_nl_cb_err(self._cb, k, handler, obj)
  140. def clone(self):
  141. return Callback(self)
  142. class Socket(object):
  143. """Netlink socket"""
  144. def __init__(self, cb=None):
  145. if isinstance(cb, Callback):
  146. self._sock = capi.nl_socket_alloc_cb(cb._cb)
  147. elif cb == None:
  148. self._sock = capi.nl_socket_alloc()
  149. else:
  150. raise Exception('\'cb\' parameter has wrong type')
  151. if self._sock is None:
  152. raise Exception('NULL pointer returned while allocating socket')
  153. def __del__(self):
  154. capi.nl_socket_free(self._sock)
  155. def __str__(self):
  156. return 'nlsock<{0}>'.format(self.local_port)
  157. @property
  158. def local_port(self):
  159. return capi.nl_socket_get_local_port(self._sock)
  160. @local_port.setter
  161. def local_port(self, value):
  162. capi.nl_socket_set_local_port(self._sock, int(value))
  163. @property
  164. def peer_port(self):
  165. return capi.nl_socket_get_peer_port(self._sock)
  166. @peer_port.setter
  167. def peer_port(self, value):
  168. capi.nl_socket_set_peer_port(self._sock, int(value))
  169. @property
  170. def peer_groups(self):
  171. return capi.nl_socket_get_peer_groups(self._sock)
  172. @peer_groups.setter
  173. def peer_groups(self, value):
  174. capi.nl_socket_set_peer_groups(self._sock, value)
  175. def set_bufsize(self, rx, tx):
  176. capi.nl_socket_set_buffer_size(self._sock, rx, tx)
  177. def connect(self, proto):
  178. capi.nl_connect(self._sock, proto)
  179. return self
  180. def disconnect(self):
  181. capi.nl_close(self._sock)
  182. def sendto(self, buf):
  183. ret = capi.nl_sendto(self._sock, buf, len(buf))
  184. if ret < 0:
  185. raise Exception('Failed to send')
  186. else:
  187. return ret
  188. def send_auto_complete(self, msg):
  189. if not isinstance(msg, Message):
  190. raise Exception('must provide Message instance')
  191. ret = capi.nl_send_auto_complete(self._sock, msg._msg)
  192. if ret < 0:
  193. raise Exception('send_auto_complete failed: ret=%d' % ret)
  194. return ret
  195. def recvmsgs(self, recv_cb):
  196. if not isinstance(recv_cb, Callback):
  197. raise Exception('must provide Callback instance')
  198. ret = capi.nl_recvmsgs(self._sock, recv_cb._cb)
  199. if ret < 0:
  200. raise Exception('recvmsg failed: ret=%d' % ret)
  201. _sockets = {}
  202. def lookup_socket(protocol):
  203. try:
  204. sock = _sockets[protocol]
  205. except KeyError:
  206. sock = Socket()
  207. sock.connect(protocol)
  208. _sockets[protocol] = sock
  209. return sock
  210. class DumpParams(object):
  211. """Dumping parameters"""
  212. def __init__(self, type_=NL_DUMP_LINE):
  213. self._dp = capi.alloc_dump_params()
  214. if not self._dp:
  215. raise Exception('Unable to allocate struct nl_dump_params')
  216. self._dp.dp_type = type_
  217. def __del__(self):
  218. capi.free_dump_params(self._dp)
  219. @property
  220. def type(self):
  221. return self._dp.dp_type
  222. @type.setter
  223. def type(self, value):
  224. self._dp.dp_type = value
  225. @property
  226. def prefix(self):
  227. return self._dp.dp_prefix
  228. @prefix.setter
  229. def prefix(self, value):
  230. self._dp.dp_prefix = value
  231. # underscore this to make sure it is deleted first upon module deletion
  232. _defaultDumpParams = DumpParams(NL_DUMP_LINE)
  233. class Object(object):
  234. """Cacheable object (base class)"""
  235. def __init__(self, obj_name, name, obj=None):
  236. self._obj_name = obj_name
  237. self._name = name
  238. self._modules = []
  239. if not obj:
  240. obj = capi.object_alloc_name(self._obj_name)
  241. self._nl_object = obj
  242. # Create a clone which stores the original state to notice
  243. # modifications
  244. clone_obj = capi.nl_object_clone(self._nl_object)
  245. self._orig = self._obj2type(clone_obj)
  246. def __del__(self):
  247. if not self._nl_object:
  248. raise ValueError()
  249. capi.nl_object_put(self._nl_object)
  250. def __str__(self):
  251. if hasattr(self, 'format'):
  252. return self.format()
  253. else:
  254. return capi.nl_object_dump_buf(self._nl_object, 4096).rstrip()
  255. def _new_instance(self):
  256. raise NotImplementedError()
  257. def clone(self):
  258. """Clone object"""
  259. return self._new_instance(capi.nl_object_clone(self._nl_object))
  260. def _module_lookup(self, path, constructor=None):
  261. """Lookup object specific module and load it
  262. Object implementations consisting of multiple types may
  263. offload some type specific code to separate modules which
  264. are loadable on demand, e.g. a VLAN link or a specific
  265. queueing discipline implementation.
  266. Loads the module `path` and calls the constructor if
  267. supplied or `module`.init()
  268. The constructor/init function typically assigns a new
  269. object covering the type specific implementation aspects
  270. to the new object, e.g. link.vlan = VLANLink()
  271. """
  272. try:
  273. __import__(path)
  274. except ImportError:
  275. return
  276. module = sys.modules[path]
  277. if constructor:
  278. ret = getattr(module, constructor)(self)
  279. else:
  280. ret = module.init(self)
  281. if ret:
  282. self._modules.append(ret)
  283. def _module_brief(self):
  284. ret = ''
  285. for module in self._modules:
  286. if hasattr(module, 'brief'):
  287. ret += module.brief()
  288. return ret
  289. def dump(self, params=None):
  290. """Dump object as human readable text"""
  291. if params is None:
  292. params = _defaultDumpParams
  293. capi.nl_object_dump(self._nl_object, params._dp)
  294. @property
  295. def mark(self):
  296. return bool(capi.nl_object_is_marked(self._nl_object))
  297. @mark.setter
  298. def mark(self, value):
  299. if value:
  300. capi.nl_object_mark(self._nl_object)
  301. else:
  302. capi.nl_object_unmark(self._nl_object)
  303. @property
  304. def shared(self):
  305. return capi.nl_object_shared(self._nl_object) != 0
  306. @property
  307. def attrs(self):
  308. attr_list = capi.nl_object_attr_list(self._nl_object, 1024)
  309. return attr_list[0].split()
  310. @property
  311. def refcnt(self):
  312. return capi.nl_object_get_refcnt(self._nl_object)
  313. # this method resolves multiple levels of sub types to allow
  314. # accessing properties of subclass/subtypes (e.g. link.vlan.id)
  315. def _resolve(self, attr):
  316. obj = self
  317. l = attr.split('.')
  318. while len(l) > 1:
  319. obj = getattr(obj, l.pop(0))
  320. return (obj, l.pop(0))
  321. def _setattr(self, attr, val):
  322. obj, attr = self._resolve(attr)
  323. return setattr(obj, attr, val)
  324. def _hasattr(self, attr):
  325. obj, attr = self._resolve(attr)
  326. return hasattr(obj, attr)
  327. class ObjIterator(object):
  328. def __init__(self, cache, obj):
  329. self._cache = cache
  330. self._nl_object = None
  331. if not obj:
  332. self._end = 1
  333. else:
  334. capi.nl_object_get(obj)
  335. self._nl_object = obj
  336. self._first = 1
  337. self._end = 0
  338. def __del__(self):
  339. if self._nl_object:
  340. capi.nl_object_put(self._nl_object)
  341. def __iter__(self):
  342. return self
  343. def get_next(self):
  344. return capi.nl_cache_get_next(self._nl_object)
  345. def next(self):
  346. return self.__next__()
  347. def __next__(self):
  348. if self._end:
  349. raise StopIteration()
  350. if self._first:
  351. ret = self._nl_object
  352. self._first = 0
  353. else:
  354. ret = self.get_next()
  355. if not ret:
  356. self._end = 1
  357. raise StopIteration()
  358. # return ref of previous element and acquire ref of current
  359. # element to have object stay around until we fetched the
  360. # next ptr
  361. capi.nl_object_put(self._nl_object)
  362. capi.nl_object_get(ret)
  363. self._nl_object = ret
  364. # reference used inside object
  365. capi.nl_object_get(ret)
  366. return self._cache._new_object(ret)
  367. class ReverseObjIterator(ObjIterator):
  368. def get_next(self):
  369. return capi.nl_cache_get_prev(self._nl_object)
  370. class Cache(object):
  371. """Collection of netlink objects"""
  372. def __init__(self):
  373. if self.__class__ is Cache:
  374. raise NotImplementedError()
  375. self.arg1 = None
  376. self.arg2 = None
  377. def __del__(self):
  378. capi.nl_cache_free(self._nl_cache)
  379. def __len__(self):
  380. return capi.nl_cache_nitems(self._nl_cache)
  381. def __iter__(self):
  382. obj = capi.nl_cache_get_first(self._nl_cache)
  383. return ObjIterator(self, obj)
  384. def __reversed__(self):
  385. obj = capi.nl_cache_get_last(self._nl_cache)
  386. return ReverseObjIterator(self, obj)
  387. def __contains__(self, item):
  388. obj = capi.nl_cache_search(self._nl_cache, item._nl_object)
  389. if obj is None:
  390. return False
  391. else:
  392. capi.nl_object_put(obj)
  393. return True
  394. # called by sub classes to allocate type specific caches by name
  395. @staticmethod
  396. def _alloc_cache_name(name):
  397. return capi.alloc_cache_name(name)
  398. # implemented by sub classes, must return new instasnce of cacheable
  399. # object
  400. @staticmethod
  401. def _new_object(obj):
  402. raise NotImplementedError()
  403. # implemented by sub classes, must return instance of sub class
  404. def _new_cache(self, cache):
  405. raise NotImplementedError()
  406. def subset(self, filter_):
  407. """Return new cache containing subset of cache
  408. Cretes a new cache containing all objects which match the
  409. specified filter.
  410. """
  411. if not filter_:
  412. raise ValueError()
  413. c = capi.nl_cache_subset(self._nl_cache, filter_._nl_object)
  414. return self._new_cache(cache=c)
  415. def dump(self, params=None, filter_=None):
  416. """Dump (print) cache as human readable text"""
  417. if not params:
  418. params = _defaultDumpParams
  419. if filter_:
  420. filter_ = filter_._nl_object
  421. capi.nl_cache_dump_filter(self._nl_cache, params._dp, filter_)
  422. def clear(self):
  423. """Remove all cache entries"""
  424. capi.nl_cache_clear(self._nl_cache)
  425. # Called by sub classes to set first cache argument
  426. def _set_arg1(self, arg):
  427. self.arg1 = arg
  428. capi.nl_cache_set_arg1(self._nl_cache, arg)
  429. # Called by sub classes to set second cache argument
  430. def _set_arg2(self, arg):
  431. self.arg2 = arg
  432. capi.nl_cache_set_arg2(self._nl_cache, arg)
  433. def refill(self, socket=None):
  434. """Clear cache and refill it"""
  435. if socket is None:
  436. socket = lookup_socket(self._protocol)
  437. capi.nl_cache_refill(socket._sock, self._nl_cache)
  438. return self
  439. def resync(self, socket=None, cb=None, args=None):
  440. """Synchronize cache with content in kernel"""
  441. if socket is None:
  442. socket = lookup_socket(self._protocol)
  443. capi.nl_cache_resync(socket._sock, self._nl_cache, cb, args)
  444. def provide(self):
  445. """Provide this cache to others
  446. Caches which have been "provided" are made available
  447. to other users (of the same application context) which
  448. "require" it. F.e. a link cache is generally provided
  449. to allow others to translate interface indexes to
  450. link names
  451. """
  452. capi.nl_cache_mngt_provide(self._nl_cache)
  453. def unprovide(self):
  454. """Unprovide this cache
  455. No longer make the cache available to others. If the cache
  456. has been handed out already, that reference will still
  457. be valid.
  458. """
  459. capi.nl_cache_mngt_unprovide(self._nl_cache)
  460. # Cache Manager (Work in Progress)
  461. NL_AUTO_PROVIDE = 1
  462. class CacheManager(object):
  463. def __init__(self, protocol, flags=None):
  464. self._sock = Socket()
  465. self._sock.connect(protocol)
  466. if not flags:
  467. flags = NL_AUTO_PROVIDE
  468. self._mngr = capi.cache_mngr_alloc(self._sock._sock, protocol, flags)
  469. def __del__(self):
  470. if self._sock:
  471. self._sock.disconnect()
  472. if self._mngr:
  473. capi.nl_cache_mngr_free(self._mngr)
  474. def add(self, name):
  475. capi.cache_mngr_add(self._mngr, name, None, None)
  476. class AddressFamily(object):
  477. """Address family representation
  478. af = AddressFamily('inet6')
  479. # raises:
  480. # - ValueError if family name is not known
  481. # - TypeError if invalid type is specified for family
  482. print af # => 'inet6' (string representation)
  483. print int(af) # => 10 (numeric representation)
  484. print repr(af) # => AddressFamily('inet6')
  485. """
  486. def __init__(self, family=socket.AF_UNSPEC):
  487. if isinstance(family, str):
  488. family = capi.nl_str2af(family)
  489. if family < 0:
  490. raise ValueError('Unknown family name')
  491. elif not isinstance(family, int):
  492. raise TypeError()
  493. self._family = family
  494. def __str__(self):
  495. return capi.nl_af2str(self._family, 32)[0]
  496. def __int__(self):
  497. return self._family
  498. def __repr__(self):
  499. return 'AddressFamily({0!r})'.format(str(self))
  500. class AbstractAddress(object):
  501. """Abstract address object
  502. addr = AbstractAddress('127.0.0.1/8')
  503. print addr # => '127.0.0.1/8'
  504. print addr.prefixlen # => '8'
  505. print addr.family # => 'inet'
  506. print len(addr) # => '4' (32bit ipv4 address)
  507. a = AbstractAddress('10.0.0.1/24')
  508. b = AbstractAddress('10.0.0.2/24')
  509. print a == b # => False
  510. """
  511. def __init__(self, addr):
  512. self._nl_addr = None
  513. if isinstance(addr, str):
  514. # returns None on success I guess
  515. # TO CORRECT
  516. addr = capi.addr_parse(addr, socket.AF_UNSPEC)
  517. if addr is None:
  518. raise ValueError('Invalid address format')
  519. elif addr:
  520. capi.nl_addr_get(addr)
  521. self._nl_addr = addr
  522. def __del__(self):
  523. if self._nl_addr:
  524. capi.nl_addr_put(self._nl_addr)
  525. def __cmp__(self, other):
  526. if isinstance(other, str):
  527. other = AbstractAddress(other)
  528. diff = self.prefixlen - other.prefixlen
  529. if diff == 0:
  530. diff = capi.nl_addr_cmp(self._nl_addr, other._nl_addr)
  531. return diff
  532. def contains(self, item):
  533. diff = int(self.family) - int(item.family)
  534. if diff:
  535. return False
  536. if item.prefixlen < self.prefixlen:
  537. return False
  538. diff = capi.nl_addr_cmp_prefix(self._nl_addr, item._nl_addr)
  539. return diff == 0
  540. def __nonzero__(self):
  541. if self._nl_addr:
  542. return not capi.nl_addr_iszero(self._nl_addr)
  543. else:
  544. return False
  545. def __len__(self):
  546. if self._nl_addr:
  547. return capi.nl_addr_get_len(self._nl_addr)
  548. else:
  549. return 0
  550. def __str__(self):
  551. if self._nl_addr:
  552. return capi.nl_addr2str(self._nl_addr, 64)[0]
  553. else:
  554. return 'none'
  555. @property
  556. def shared(self):
  557. """True if address is shared (multiple users)"""
  558. if self._nl_addr:
  559. return capi.nl_addr_shared(self._nl_addr) != 0
  560. else:
  561. return False
  562. @property
  563. def prefixlen(self):
  564. """Length of prefix (number of bits)"""
  565. if self._nl_addr:
  566. return capi.nl_addr_get_prefixlen(self._nl_addr)
  567. else:
  568. return 0
  569. @prefixlen.setter
  570. def prefixlen(self, value):
  571. if not self._nl_addr:
  572. raise TypeError()
  573. capi.nl_addr_set_prefixlen(self._nl_addr, int(value))
  574. @property
  575. def family(self):
  576. """Address family"""
  577. f = 0
  578. if self._nl_addr:
  579. f = capi.nl_addr_get_family(self._nl_addr)
  580. return AddressFamily(f)
  581. @family.setter
  582. def family(self, value):
  583. if not self._nl_addr:
  584. raise TypeError()
  585. if not isinstance(value, AddressFamily):
  586. value = AddressFamily(value)
  587. capi.nl_addr_set_family(self._nl_addr, int(value))
  588. # keyword:
  589. # type = { int | str }
  590. # immutable = { True | False }
  591. # fmt = func (formatting function)
  592. # title = string
  593. def nlattr(**kwds):
  594. """netlink object attribute decorator
  595. decorator used to mark mutable and immutable properties
  596. of netlink objects. All properties marked as such are
  597. regarded to be accessable.
  598. @property
  599. @netlink.nlattr(type=int)
  600. def my_attr(self):
  601. return self._my_attr
  602. """
  603. def wrap_fn(func):
  604. func.formatinfo = kwds
  605. return func
  606. return wrap_fn