The Assimilation Project  based on Assimilation version 1.1.6.1462601511
AssimCclasses.py
Go to the documentation of this file.
1 # pylint: disable=C0302
2 # vim: smartindent tabstop=4 shiftwidth=4 expandtab number colorcolumn=100
3 #C0302: too many lines in module
4 #
5 #
6 # This file is part of the Assimilation Project.
7 #
8 # Copyright (C) 2011, 2012 - Alan Robertson <alanr@unix.sh>
9 #
10 # The Assimilation software is free software: you can redistribute it and/or modify
11 # it under the terms of the GNU General Public License as published by
12 # the Free Software Foundation, either version 3 of the License, or
13 # (at your option) any later version.
14 #
15 # The Assimilation software is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU General Public License for more details.
19 #
20 # You should have received a copy of the GNU General Public License
21 # along with the Assimilation Project software. If not, see http://www.gnu.org/licenses/
22 #
23 #
24 #pylint: disable=C0302,W0212
25 '''
26 A collection of classes which wrap our @ref C-Classes and provide Pythonic interfaces
27 to these C-classes.
28 '''
29 import AssimCtypes
30 from AssimCtypes import POINTER, cast, addressof, pointer, string_at, create_string_buffer, \
31  c_char_p, byref, memmove, c_int, badfree, \
32  g_free, GSList, GDestroyNotify, g_slist_length, g_slist_next, struct__GSList, \
33  g_slist_free, \
34  MALLOC, memmove, \
35  FRAMETYPE_SIG, \
36  Frame, AssimObj, NetAddr, SeqnoFrame, ReliableUDP, \
37  frame_new, addrframe_new, \
38  nvpairframe_new, frameset_new, frameset_append_frame, frameset_prepend_frame, \
39  seqnoframe_new, cstringframe_new, unknownframe_new, \
40  ipportframe_netaddr_new, ipportframe_ipv4_new, ipportframe_ipv6_new, \
41  frameset_construct_packet, frameset_get_flags, frameset_set_flags, frameset_clear_flags, \
42  frameset_dump, frameset_sender_key_id, frameset_sender_identity, \
43  LLDP_TLV_END, LLDP_TLV_CHID, LLDP_TLV_PID, LLDP_TLV_TTL, LLDP_TLV_PORT_DESCR, \
44  LLDP_TLV_SYS_NAME, LLDP_TLV_SYS_DESCR, LLDP_TLV_SYS_CAPS, LLDP_TLV_MGMT_ADDR, \
45  LLDP_TLV_ORG_SPECIFIC, \
46  LLDP_ORG802_1_VLAN_PVID, LLDP_ORG802_1_VLAN_PORTPROTO, LLDP_ORG802_1_VLAN_NAME, \
47  LLDP_ORG802_1_VLAN_PROTOID, LLDP_ORG802_3_PHY_CONFIG, LLDP_ORG802_3_POWERVIAMDI, \
48  LLDP_ORG802_3_LINKAGG, LLDP_ORG802_3_MTU, \
49  LLDP_PIDTYPE_ALIAS, LLDP_PIDTYPE_IFNAME, LLDP_PIDTYPE_LOCAL, LLDP_CHIDTYPE_ALIAS, \
50  LLDP_CHIDTYPE_IFNAME, LLDP_CHIDTYPE_LOCAL, LLDP_CHIDTYPE_MACADDR, \
51  LLDP_CHIDTYPE_COMPONENT, LLDP_CHIDTYPE_NETADDR, \
52  CDP_TLV_DEVID, CDP_TLV_ADDRESS, CDP_TLV_PORTID, CDP_TLV_CAPS, CDP_TLV_VERS, CDP_TLV_POWER, \
53  CDP_TLV_PLATFORM, CDP_TLV_MTU, CDP_TLV_SYSTEM_NAME, CDP_TLV_MANAGEMENT_ADDR, CDP_TLV_DUPLEX, \
54  CDP_TLV_LOCATION, CDP_TLV_EXT_PORTID, CDP_TLV_NATIVEVLAN, CDP_TLV_VLREPLY, CDP_TLV_VLQUERY, \
55  CDP_TLV_VTPDOMAIN, CDP_TLV_TRUST_BITMAP, CDP_TLV_UNTRUSTED_COS, CDP_TLV_HELLO, \
56  ADDR_FAMILY_IPV4, ADDR_FAMILY_IPV6, ADDR_FAMILY_802, \
57  is_valid_lldp_packet, is_valid_cdp_packet, \
58  netaddr_ipv4_new, netaddr_ipv6_new, netaddr_dns_new, netaddr_mac48_new, netaddr_mac64_new, \
59  proj_class_classname, \
60  assimobj_new, intframe_new, signframe_glib_new, packetdecoder_new, configcontext_new, \
61  configcontext_new_JSON_string, netio_new, netioudp_new, reliableudp_new,\
62  netio_is_dual_ipv4v6_stack, create_setconfig, create_sendexpecthb, \
63  get_lldptlv_first, \
64  get_lldptlv_next, \
65  get_lldptlv_type, \
66  get_lldptlv_len, \
67  get_lldptlv_body, \
68  get_lldptlv_next, \
69  get_cdptlv_first, \
70  get_cdptlv_next, \
71  get_cdptlv_type, \
72  get_cdptlv_len, \
73  get_cdptlv_body, \
74  pcap_capture_iter_new, pcap_capture_iter_del, pcap_capture_iter_next, \
75  tlv_get_guint8, tlv_get_guint16, tlv_get_guint24, tlv_get_guint32, tlv_get_guint64, \
76  CFG_EEXIST, CFG_CFGCTX, CFG_CFGCTX, CFG_STRING, CFG_NETADDR, CFG_FRAME, CFG_INT64, CFG_ARRAY, \
77  CFG_FLOAT, CFG_BOOL, DEFAULT_FSP_QID, CFG_NULL, CMA_IDENTITY_NAME, \
78  COMPRESS_ZLIB, FRAMETYPE_COMPRESS, compressframe_new_string, \
79  cryptframe_associate_identity, cryptframe_set_dest_key_id, cryptframe_whois_key_id, \
80  cryptframe_get_dest_key_id, \
81  cryptframe_new_by_destaddr, cryptframe_get_key_ids, cryptframe_set_signing_key_id, \
82  cryptframe_private_key_by_id, cryptcurve25519_set_encryption_method, \
83  cryptcurve25519_cache_all_keypairs, CMA_KEY_PREFIX, curve25519_key_id_to_filename, \
84  cryptcurve25519_gen_persistent_keypair, cryptcurve25519_new, FRAMETYPE_CRYPTCURVE25519, \
85  proj_class_live_object_count, proj_class_dump_live_objects
86 from consts import CMAconsts
87 from frameinfo import FrameTypes, FrameSetTypes
88 import collections
89 import traceback, types
90 import sys, gc
91 
92 
93 #pylint: disable=R0903
94 class cClass (object):
95  'Just a handy collection of POINTER() objects'
96  def __init__(self):
97  pass
98  NetAddr = POINTER(AssimCtypes.NetAddr)
99  Frame = POINTER(AssimCtypes.Frame)
100  AddrFrame = POINTER(AssimCtypes.AddrFrame)
101  IntFrame = POINTER(AssimCtypes.IntFrame)
102  SeqnoFrame = POINTER(AssimCtypes.SeqnoFrame)
103  CstringFrame = POINTER(AssimCtypes.CstringFrame)
104  UnknownFrame = POINTER(AssimCtypes.UnknownFrame)
105  SignFrame = POINTER(AssimCtypes.SignFrame)
106  FrameSet = POINTER(AssimCtypes.FrameSet)
107  ConfigContext = POINTER(AssimCtypes.ConfigContext)
108  ConfigValue = POINTER(AssimCtypes.ConfigValue)
109  IpPortFrame = POINTER(AssimCtypes.IpPortFrame)
110  CompressFrame = POINTER(AssimCtypes.CompressFrame)
111  guint8 = POINTER(AssimCtypes.guint8)
112  GSList = POINTER(AssimCtypes.GSList)
113  CryptCurve25519 = POINTER(AssimCtypes.CryptCurve25519)
114 
115 #
116 def not_this_exact_type(obj, cls):
117  '''Do return True if this is NOT the given type.
118  This is necessary for dealing with Ctypes, but pylint hates this construct
119  so we ignore its warning.
120  '''
121  return type(obj) is not cls
122 
123 def CCref(obj):
124  '''
125  Increment the reference count to an AssimObj (_not_ a pyAssimObj)
126  Need to call CCref under the following circumstances:
127  When we are creating an object that points to another underlying C-class object
128  which already has a permanent reference to it somewhere else
129  For example, if we're returning a pyNetAddr object that points to a NetAddr object
130  that's in a ConfigContext object. If we don't, then when our pyNetAddr object goes
131  out of scope, then the underlying NetAddr object will be freed, even though there's
132  a reference to it in the ConfigContext object. Conversely, if the ConfigContext
133  object goes out of scope first, then the our pyNetAddr object could become invalid.
134 
135  Do not call it when you've constructed a new object that there were no previous pointers
136  to.
137  '''
138  base = obj[0]
139  while (not_this_exact_type(base, AssimObj)):
140  base = base.baseclass
141  base.ref(obj)
142 
143 def CCunref(obj):
144  'Unref an AssimObj object (or subclass)'
145  base = obj[0]
146  # This 'hasattr' construct only works because we are the base C-class
147  while (hasattr(base, 'baseclass')):
148  base = base.baseclass
149  base.unref(obj)
150 
151 class pySwitchDiscovery(object):
152  '''
153  Class for interpreting switch discovery data via LLDP or CDP
154  Currently only LLDP is fully implemented.
155  '''
156  lldpnames = {
157  LLDP_TLV_END: ('END', True),
158  LLDP_TLV_CHID: ('ChassisId', True),
159  LLDP_TLV_PID: ('PortId', True),
160  LLDP_TLV_TTL: ('TTL', True),
161  LLDP_TLV_PORT_DESCR: ('PortDescription', False),
162  LLDP_TLV_SYS_NAME: ('SystemName', True),
163  LLDP_TLV_SYS_DESCR: ('SystemDescription', True),
164  LLDP_TLV_SYS_CAPS: ('SystemCapabilities', True),
165  LLDP_TLV_MGMT_ADDR: ('ManagementAddress', True),
166  LLDP_TLV_ORG_SPECIFIC: ('(OrgSpecific)', True),
167  }
168  lldp802_1names = {
169  LLDP_ORG802_1_VLAN_PVID: ('VlanPvId', False),
170  LLDP_ORG802_1_VLAN_PORTPROTO: ('VlanPortProtocol', False),
171  LLDP_ORG802_1_VLAN_NAME: ('VlanName', False),
172  LLDP_ORG802_1_VLAN_PROTOID: ('VlanProtocolId', False),
173  }
174  lldp802_3names = {
175  LLDP_ORG802_3_PHY_CONFIG: ('PhysicalConfiguration', False),
176  LLDP_ORG802_3_POWERVIAMDI: ('PowerViaMDI', False),
177  LLDP_ORG802_3_LINKAGG: ('LinkAggregation', False),
178 
179  }
180 
181  cdpnames = {
182  # System-wide capabilities
183  CDP_TLV_DEVID: ('ChassisId', True),
184  CDP_TLV_CAPS: ('SystemCapabilities', True),
185  CDP_TLV_VERS: ('SystemVersion', True),
186  CDP_TLV_PLATFORM: ('SystemPlatform', True),
187  CDP_TLV_VTPDOMAIN: ('VLANManagementDomain', True),
188  CDP_TLV_ADDRESS: ('SystemAddress', True),
189  CDP_TLV_MANAGEMENT_ADDR: ('ManagementAddress', True),
190  CDP_TLV_SYSTEM_NAME: ('SystemName', True),
191  CDP_TLV_LOCATION: ('SystemDescription', True),
192  CDP_TLV_HELLO: ('CiscoHello', True),
193  # Per-port capabilities follow
194  CDP_TLV_TRUST_BITMAP: ('CiscoTrustBitMap', False),
195  CDP_TLV_UNTRUSTED_COS: ('CiscoUnTrustedPortCOS', False),
196  CDP_TLV_NATIVEVLAN: ('VlanId', False),
197  CDP_TLV_VLQUERY: ('VlanQuery', False),
198  CDP_TLV_VLREPLY: ('VlanReply', False),
199  CDP_TLV_PORTID: ('PortId', False),
200  CDP_TLV_EXT_PORTID: ('PortDescription', False),
201  CDP_TLV_DUPLEX: ('duplex', False),
202  CDP_TLV_MTU: ('mtu', False),
203  CDP_TLV_POWER: ('PortPower', False),
204  }
205 
206  def __init__(self):
207  pass
208 
209  @staticmethod
210  def _byte0(pktstart):
211  'Return the first (zeroth) byte from a memory blob'
212  return int(cast(pktstart, cClass.guint8)[0])
213 
214  @staticmethod
215  def _byte1addr(pktstart):
216  'Return the address of byte 1 in a memory blob'
217  addr = addressof(pktstart.contents) + 1
218  return pointer(type(pktstart.contents).from_address(addr))
219 
220  @staticmethod
221  def _byteN(pktstart, n):
222  'Return the Nth byte from a memory blob'
223  return int(cast(pktstart, cClass.guint8)[n])
224 
225  @staticmethod
226  def _byteNaddr(pktstart, n):
227  'Return the address of the Nth byte in a memory blob'
228  addr = addressof(pktstart.contents) + n
229  return pointer(type(pktstart.contents).from_address(addr))
230 
231  @staticmethod
232  def _decode_netaddr(addrstart, addrlen):
233  'Return an appropriate pyNetAddr object corresponding to the given memory blob'
234  byte0 = pySwitchDiscovery._byte0(addrstart)
235  byte1addr = pySwitchDiscovery._byte1addr(addrstart)
236  Cnetaddr = None
237  if byte0 == ADDR_FAMILY_IPV6:
238  if addrlen != 17:
239  return None
240  Cnetaddr = netaddr_ipv6_new(byte1addr, 0)
241  elif byte0 == ADDR_FAMILY_IPV4:
242  if addrlen != 5:
243  return None
244  Cnetaddr = netaddr_ipv4_new(byte1addr, 0)
245  elif byte0 == ADDR_FAMILY_802:
246  if addrlen == 7:
247  Cnetaddr = netaddr_mac48_new(byte1addr)
248  elif addrlen == 9:
249  Cnetaddr = netaddr_mac64_new(byte1addr)
250  if Cnetaddr is not None:
251  return str(pyNetAddr(None, Cstruct=Cnetaddr))
252  return None
253 
254  @staticmethod
255  def decode_discovery(host, interface, instance, wallclock, pktstart, pktend):
256  'Return a JSON packet corresponding to the given switch discovery packet'
257 
258  if is_valid_lldp_packet(pktstart, pktend):
259  #print >> sys.stderr, '>>>>>>>>>>>>>>>LLDP PACKET'
260  return pySwitchDiscovery._decode_lldp(host, interface, instance,
261  wallclock, pktstart, pktend)
262 
263  if is_valid_cdp_packet(pktstart, pktend):
264  #print >> sys.stderr, '>>>>>>>>>>>>>>>CDP PACKET'
265  return pySwitchDiscovery._decode_cdp(host, interface, instance,
266  wallclock, pktstart, pktend)
267  raise ValueError('Malformed Switch Discovery Packet')
268 
269  @staticmethod
270  def _decode_lldp_chid(tlvptr, tlvlen):
271  'Decode the LLDP CHID field, and return an appropriate value'
272  chidtype = pySwitchDiscovery._byte0(tlvptr)
273 
274  if (chidtype == LLDP_CHIDTYPE_COMPONENT or chidtype == LLDP_CHIDTYPE_ALIAS
275  or chidtype == LLDP_CHIDTYPE_IFNAME or chidtype == LLDP_CHIDTYPE_LOCAL):
276  sloc = pySwitchDiscovery._byte1addr(tlvptr)
277  value = string_at(sloc, tlvlen-1)
278  elif chidtype == LLDP_CHIDTYPE_MACADDR:
279  byte1addr = pySwitchDiscovery._byte1addr(tlvptr)
280  Cmacaddr = None
281  if tlvlen == 7:
282  Cmacaddr = netaddr_mac48_new(byte1addr)
283  elif tlvlen == 9:
284  Cmacaddr = netaddr_mac64_new(byte1addr)
285  if Cmacaddr is not None:
286  value = pyNetAddr(None, Cstruct=Cmacaddr)
287  elif chidtype == LLDP_CHIDTYPE_NETADDR:
288  byte1addr = pySwitchDiscovery._byte1addr(tlvptr)
289  value = pySwitchDiscovery._decode_netaddr(byte1addr, tlvlen-1)
290  return value
291 
292  #pylint: disable=R0914,R0912
293  @staticmethod
294  def _decode_lldp(host, interface, instance, wallclock, pktstart, pktend):
295  'Decode LLDP packet into a JSON discovery packet'
296  #print >> sys.stderr, 'DECODING LLDP PACKET!<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<'
297  thisportinfo = pyConfigContext(init={
298  'ConnectsToHost': host,
299  'ConnectsToInterface': interface,
300  }
301  )
302  switchinfo = pyConfigContext(init = {'ports': pyConfigContext()})
303  metadata = pyConfigContext(init={
304  'discovertype': '__LinkDiscovery',
305  'description': 'Link Level Switch Discovery (lldp)',
306  'source': '_decode_lldp()',
307  'host': host,
308  'instance': instance,
309  'localtime': str(wallclock),
310  'data': switchinfo,
311  }
312  )
313  capnames = [ None, CMAconsts.ROLE_repeater
314  , CMAconsts.ROLE_bridge, CMAconsts.ROLE_AccessPoint
315  , CMAconsts.ROLE_router, CMAconsts.ROLE_phone
316  , CMAconsts.ROLE_DOCSIS, CMAconsts.ROLE_Station
317  ]
318 
319  sourcemacptr = pySwitchDiscovery._byteNaddr(cast(pktstart, cClass.guint8), 6)
320  if not sourcemacptr:
321  return metadata
322  Cmacaddr = netaddr_mac48_new(sourcemacptr)
323  sourcemac = pyNetAddr(None, Cstruct=Cmacaddr)
324 
325 
326  this = get_lldptlv_first(pktstart, pktend)
327  while this and this < pktend:
328  tlvtype = get_lldptlv_type(this, pktend)
329  tlvlen = get_lldptlv_len(this, pktend)
330  tlvptr = cast(get_lldptlv_body(this, pktend), cClass.guint8)
331  value = None
332  if tlvtype not in pySwitchDiscovery.lldpnames:
333  print >> sys.stderr, 'Cannot find tlvtype %d' % tlvtype
334  tlvtype = None
335  else:
336  (tlvname, isswitchinfo) = pySwitchDiscovery.lldpnames[tlvtype]
337 
338  if (tlvtype == LLDP_TLV_PORT_DESCR or tlvtype == LLDP_TLV_SYS_NAME or
339  tlvtype == LLDP_TLV_SYS_DESCR): #########################################
340  value = string_at(tlvptr, tlvlen)
341 
342  elif tlvtype == LLDP_TLV_PID: ###############################################
343  pidtype = pySwitchDiscovery._byte0(tlvptr)
344  if (pidtype == LLDP_PIDTYPE_ALIAS or pidtype == LLDP_PIDTYPE_IFNAME
345  or pidtype == LLDP_PIDTYPE_LOCAL):
346  sloc = pySwitchDiscovery._byte1addr(tlvptr)
347  value = string_at(sloc, tlvlen-1)
348 
349  elif tlvtype == LLDP_TLV_CHID: #############################################
350  value = pySwitchDiscovery._decode_lldp_chid(tlvptr, tlvlen)
351 
352  elif tlvtype == LLDP_TLV_MGMT_ADDR: #########################################
353  addrlen = pySwitchDiscovery._byte0(tlvptr)
354  byte1addr = pySwitchDiscovery._byte1addr(tlvptr)
355  value = pySwitchDiscovery._decode_netaddr(byte1addr, addrlen)
356 
357  elif tlvtype == LLDP_TLV_SYS_CAPS: #########################################
358  byte0 = pySwitchDiscovery._byte0(tlvptr)
359  byte1 = pySwitchDiscovery._byteN(tlvptr, 1)
360  byte2 = pySwitchDiscovery._byteN(tlvptr, 2)
361  byte3 = pySwitchDiscovery._byteN(tlvptr, 3)
362  caps0 = (byte0 << 8 | byte1)
363  caps1 = (byte2 << 8 | byte3)
364  value = pyConfigContext()
365  mask = 2
366  for j in range(1, 7):
367  if (caps0 & mask):
368  value[capnames[j]] = ((caps1 & mask) != 0)
369  mask <<= 1
370 
371 
372  elif tlvtype == LLDP_TLV_ORG_SPECIFIC: ######################################
373  pySwitchDiscovery._decode_lldp_org_specific(switchinfo, thisportinfo,
374  tlvptr, tlvlen, pktend)
375 
376  if value is not None:
377  if tlvtype == LLDP_TLV_PID:
378  switchinfo['ports'][value] = thisportinfo
379  thisportinfo['PortId'] = value
380  numericpart = value
381  while len(numericpart) > 0 and not numericpart.isdigit():
382  numericpart = numericpart[1:]
383  #if len > 0 and numericpart.isdigit():
384  # thisportinfo['PORTNUM'] = int(numericpart)
385  else:
386  if isswitchinfo:
387  switchinfo[tlvname] = value
388  else:
389  thisportinfo[tlvname] = value
390  this = get_lldptlv_next(this, pktend)
391  thisportinfo['sourceMAC'] = sourcemac
392  return metadata
393  @staticmethod
394  def _dump_c_bytes(prefix, tlvstart, tlvlen):
395  '''Dump out data from a given C-style address'''
396  dump = "%s: DUMP (%d bytes):" % (prefix, tlvlen)
397  for offset in range(0, tlvlen):
398  dump += ' %02x' % pySwitchDiscovery._byteN(tlvstart, offset)
399  print >> sys.stderr, dump
400 
401  @staticmethod
402  def _decode_lldp_org_specific(switchinfo, thisportinfo, tlvptr, tlvlen, pktend):
403  '''Decode LLDP org-specific TLV sets (or not...)'''
404  oui = tlv_get_guint24(tlvptr, pktend)
405  #print >> sys.stderr, 'ORG_OUI: 0x%06x' % oui
406  tlv3ptr = pySwitchDiscovery._byteNaddr(tlvptr, 3)
407  if oui == 0x0080c2:
408  pySwitchDiscovery._decode_lldp_802_1(switchinfo, thisportinfo,
409  tlv3ptr, tlvlen-3, pktend)
410  elif oui == 0x00120f:
411  pySwitchDiscovery._decode_lldp_802_3(switchinfo, thisportinfo,
412  tlv3ptr, tlvlen-3, pktend)
413  elif oui == 0x0012bb:
414  pySwitchDiscovery._decode_lldp_med(switchinfo, thisportinfo,
415  tlv3ptr, tlvlen-3, pktend)
416  elif oui == 0x00ceff:
417  pySwitchDiscovery._decode_lldp_profibus(switchinfo, thisportinfo,
418  tlv3ptr, tlvlen-3, pktend)
419  elif oui == 0x00cecf:
420  pySwitchDiscovery._decode_lldp_hytec(switchinfo, thisportinfo,
421  tlv3ptr, tlvlen-3, pktend)
422  else:
423  print >> sys.stderr, (
424  'Ignored %d bytes of unknown LLDP org-specific extensions. OUI: %06x.'
425  % (tlvlen, oui))
426 
427  @staticmethod
428  def _decode_lldp_802_1(_switchinfo, thisportinfo, tlvptr, tlvlen, pktend):
429  '''Decode 802.1 LLDP org-specific TLV sets (or not...)'''
430  subtype = pySwitchDiscovery._byte0(tlvptr)
431  tlvstart = pySwitchDiscovery._byte1addr(tlvptr)
432  if subtype == 1:
433  thisportinfo['pvid'] = tlv_get_guint16(tlvstart, pktend)
434  elif subtype == 2:
435  ppstatus = pySwitchDiscovery._byte0(tlvstart)
436  thisportinfo['pp_vlan_capable'] = ((ppstatus & 2) == 2)
437  thisportinfo['pp_vlan_enabled'] = ((ppstatus & 4) == 4)
438  thisportinfo['ppvid'] = tlv_get_guint16(
439  pySwitchDiscovery._byte1addr(tlvstart), pktend)
440  elif subtype == 3:
441  vlannameaddr = pySwitchDiscovery._byteNaddr(tlvptr, 3)
442  namelen = pySwitchDiscovery._byte0(vlannameaddr)
443  if namelen != tlvlen - 4:
444  print >> sys.stderr, 'F.4: invalid name length %s out of total of %s' % (namelen,
445  tlvlen)
446  pySwitchDiscovery._dump_c_bytes('PACKET:' , tlvptr, tlvlen)
447  else:
448  thisportinfo['vid'] = tlv_get_guint16(tlvstart, pktend)
449  thisportinfo['vlan_name'] = string_at(pySwitchDiscovery._byte1addr(vlannameaddr),
450  namelen).strip()
451  else:
452  print >> sys.stderr, (
453  'Ignored %d bytes of LLDP 802.1 extensions (Annex F, subtype %d).'
454  % (tlvlen, subtype))
455 
456  @staticmethod
457  def _decode_lldp_802_3(switchinfo, thisportinfo, tlvptr, tlvlen, pktend):
458  '''Decode 802.3 LLDP org-specific TLV sets (or not...)'''
459  subtype = pySwitchDiscovery._byte0(tlvptr)
460  if subtype == 1:
461  pySwitchDiscovery._decode_lldp_802_3_mac_phy(switchinfo, thisportinfo,
462  pySwitchDiscovery._byte1addr(tlvptr), tlvlen-1, pktend)
463  return
464  if subtype == LLDP_ORG802_3_MTU: # G.5: Maximum Frame Size TLV (4)
465  mtuaddr = pySwitchDiscovery._byte1addr(tlvptr)
466  thisportinfo['mtu'] = tlv_get_guint16(mtuaddr, pktend)
467  return
468  print >> sys.stderr, (
469  'Ignored %d bytes of LLDP 802.3 extensions (Annex G, subtype %d).'
470  % (tlvlen, subtype))
471 
472  @staticmethod
473  def dot3MauTypes(mautype):
474  '''MAU types and characteristics from RFC 3636 - starting at page 9
475  The LLDP spec says that MAU types returned by G2.3 MAU type are to be
476  the same as dot3MauType information in RFC 3636.
477  This is my take on that information.
478  '''
479  mautypes = {
480  1: {'speed':10, 'duplex':'half', 'media': 'thick coax'},
481  2: {'speed':10, 'duplex':'half', 'media': 'FOIRL'},
482  3: {'speed':10, 'duplex':'half', 'media': 'thick coax'},
483  4: {'speed':10, 'duplex':'half', 'media': 'thin coax'},
484  5: {'speed':10, 'media': 'UTP'},
485 
486  6: {'speed':10, 'media': 'passive fiber'},
487  7: {'speed':10, 'media': 'sync fiber'},
488  8: {'speed':10, 'media': 'async fiber'},
489  9: {'speed':10, 'media': 'broadband DTE'},
490  10: {'speed':10, 'duplex':'half', 'media': 'UTP'},
491 
492  11: {'speed':10, 'duplex':'full', 'media': 'UTP'},
493  12: {'speed':10, 'duplex':'half', 'media': 'async fiber'},
494  13: {'speed':10, 'duplex':'full', 'media': 'async fiber'},
495  14: {'speed':100, 'media': '4 pair category 3 UTP'},
496  15: {'speed':100, 'duplex':'half', 'media': '2 pair category 5 UTP'},
497 
498  16: {'speed':100, 'duplex':'half', 'media': '2 pair category 5 UTP'},
499  17: {'speed':100, 'duplex':'half', 'media': 'X fiber over PMT'},
500  18: {'speed':100, 'duplex':'full', 'media': 'X fiber over PMT'},
501  19: {'speed':100, 'duplex':'half', 'media': '2 pair category 3 UTP'},
502  20: {'speed':100, 'duplex':'full', 'media': '2 pair category 3 UTP'},
503 
504  21: {'speed':1000, 'duplex':'half', 'media': 'PCS/PMA, unknown PMD'},
505  22: {'speed':1000, 'duplex':'full', 'media': 'PCS/PMA, unknown PMD'},
506  23: {'speed':1000, 'duplex':'half', 'media':
507  'fiber over long-wavelength laser'},
508  24: {'speed':1000, 'duplex':'full', 'media':
509  'fiber over long-wavelength laser'},
510  25: {'speed':1000, 'duplex':'half', 'media':
511  'fiber over short-wavelength laser'},
512 
513  26: {'speed':1000, 'duplex':'full', 'media':
514  'fiber over short-wavelength laser'},
515  27: {'speed':1000, 'duplex':'half', 'media':
516  'copper over 150-ohm balanced cable'},
517  28: {'speed':1000, 'duplex':'full', 'media':
518  'copper over 150-ohm balanced cable'},
519  29: {'speed':1000, 'duplex':'half', 'media': 'Four-pair Category 5 UTP'},
520  30: {'speed':1000, 'duplex':'full', 'media': 'Four-pair Category 5 UTP'},
521 
522  31: {'speed':10000, 'media': 'X PCS/PMA, unknown MD'},
523  32: {'speed':10000, 'media': 'X fiber over WWDM optics'},
524  33: {'speed':10000, 'media': 'R PCS/PMA, unknown PMD'},
525  34: {'speed':10000, 'media': 'R fiber over 1550 nm optics'},
526  35: {'speed':10000, 'media': 'R fiber over 1310 nm optics'},
527 
528  36: {'speed':10000, 'media': 'R fiber over 850 nm optics'},
529  37: {'speed':10000, 'media': 'W PCS/PMA, unknown PMD'},
530  38: {'speed':10000, 'media': 'W fiber over 1550 nm optics'},
531  39: {'speed':10000, 'media': 'R fiber over 1310 nm optics'},
532  40: {'speed':10000, 'media': 'R fiber over 850 nm optics'},
533  }
534  return mautypes[mautype] if mautype in mautypes else {}
535 
536  @staticmethod
537  def _decode_lldp_802_3_mac_phy(_switchinfo, thisportinfo,
538  tlvptr, tlvlen, pktend):
539  '''Decode 802.3 MAC/PHY TLV org-specific TLV (or not...)'''
540  if tlvlen != 5:
541  print >> sys.stderr, (
542  'Invalid %d byte LLDP 802.3 MAC/PHY information (Annex G.2).' % tlvlen)
543  return
544  autoneg_status = pySwitchDiscovery._byte0(tlvptr)
545  thisportinfo['autoneg_supported'] = (autoneg_status & 0x01) == 0x01
546  thisportinfo['autoneg_enabled'] = (autoneg_status & 0x10) == 0x10
547  #@TODO: Need to add info about autonegotiation speeds/duplexes supported (pmd_autoneg)
548  # I'm ignoring the PMD_AUTONEG field because it's not horribly important
549  # and it's incorrect on the switches in my test lab - and it's kinda
550  # complicated to decode and figure out ;-)
551  #
552  # It has one bit for each speed/duplex it is _capable_ of autonegotiating.
553  # PMD auto-negotiation advertised capability is described as the field
554  # ifMauAutoNegCapAdvertisedBits in RFC 3636 (page 42)
555  # pmd_autoneg_addr = pySwitchDiscovery._byte1addr(tlvptr)
556  # pmd_autoneg = tlv_get_guint16(pmd_autoneg_addr, pktend)
557  mau_addr = pySwitchDiscovery._byteNaddr(tlvptr, 3)
558  mau_type = tlv_get_guint16(mau_addr, pktend)
559  mauinfo = pySwitchDiscovery.dot3MauTypes(mau_type)
560  for key in mauinfo:
561  thisportinfo[key] = mauinfo[key]
562  #print >> sys.stderr, ("Autoneg_status: 0x%02x" % autoneg_status)
563  #print >> sys.stderr, ("pmd_autoneg: %d" % pmd_autoneg)
564  #print >> sys.stderr, ("MAU type: %d" % mau_type)
565 
566  @staticmethod
567  def _decode_lldp_med(switchinfo, _thisportinfo, tlvptr, tlvlen, _pktend):
568  '''Decode LLDP-MED org-specific TLV (or not...)'''
569  subtype = pySwitchDiscovery._byte0(tlvptr)
570  # for Location Identification (0x03) see https://tools.ietf.org/html/rfc4776#page-7
571  # Co-ordinate LCI
572  # Coordinate-based location data format uses geospatial data, that is, latitude,
573  # longitude, and altitude (height or floors), including indications of resolution, with
574  # reference to a particular datum: WGS 84, NAD83-North American Vertical Datum of 1988
575  # (NAVD88), or NAD83-Mean Lower Low Water (MLLW). For more information, see RFC 3825,
576  # Dynamic Host Configuration Protocol Option for Coordinate-based Location
577  # Configuration Information.
578 
579  # ELIN LCI
580  # Emergency Location Identification Number (ELIN) location data format provides a unique
581  # number for each location for Emergency Call Services (ECS). In North America, ELINs
582  # are typically 10 digits long; ELINs up to 25 digits are supported.
583 
584  # Civic Address LCI
585  # The Civic Address location data format uses common street address format, as described
586  # in RFC4776.
587  if subtype == 5:
588  pySwitchDiscovery._get_med_string(switchinfo, 'hardware-revision', tlvptr, tlvlen)
589  elif subtype == 6:
590  pySwitchDiscovery._get_med_string(switchinfo, 'firmware-revision', tlvptr, tlvlen)
591  elif subtype == 7:
592  pySwitchDiscovery._get_med_string(switchinfo, 'software-revision', tlvptr, tlvlen)
593  elif subtype == 8:
594  pySwitchDiscovery._get_med_string(switchinfo, 'serial-number', tlvptr, tlvlen)
595  elif subtype == 9:
596  pySwitchDiscovery._get_med_string(switchinfo, 'manufacturer', tlvptr, tlvlen)
597  elif subtype == 10:
598  pySwitchDiscovery._get_med_string(switchinfo, 'model', tlvptr, tlvlen)
599  elif subtype == 11:
600  pySwitchDiscovery._get_med_string(switchinfo, 'asset-id', tlvptr, tlvlen)
601  else:
602  print >> sys.stderr, (
603  'Ignored %d bytes of LLDP-MED extensions (subtype %d).' % (tlvlen, subtype))
604 
605  @staticmethod
606  def _get_med_string(info, name, tlvptr, tlvlen):
607  '''Decode LLDP-MED string value - trim off extra white space at end'''
608  strptr = cast(pySwitchDiscovery._byte1addr(tlvptr), c_char_p)
609  info[name] = string_at(strptr, tlvlen-1).strip()
610 
611  @staticmethod
612  def _decode_lldp_profibus(_switchinfo, _thisportinfo, _tlvptr, tlvlen, _pktend):
613  '''Decode LLDP Profibus org-specific TLV (or not...)'''
614  print >> sys.stderr, (
615  'Ignored %d bytes of Profibus International LLDP extensions.' % tlvlen)
616 
617  @staticmethod
618  def _decode_lldp_hytec(_switchinfo, _thisportinfo, _tlvptr, tlvlen, _pktend):
619  '''Decode LLDP Hytec org-specific TLV (or not...)'''
620  print >> sys.stderr, (
621  'Ignored %d bytes of Hytec Geraetebau GmbH LLDP extensions.' % tlvlen)
622 
623  @staticmethod
624  def _decode_cdp(host, interface, instance, wallclock, pktstart, pktend):
625  'Decode CDP packet into a JSON discovery packet'
626  thisportinfo = pyConfigContext(init={
627  'ConnectsToHost': host,
628  'ConnectsToInterface': interface,
629  }
630  )
631  switchinfo = pyConfigContext(init = {'ports': pyConfigContext()})
632  metadata = pyConfigContext(init={
633  'discovertype': '__LinkDiscovery',
634  'description': 'Link Level Switch Discovery (cdp)',
635  'source': '_decode_cdp()',
636  'host': host,
637  'instance': instance,
638  'localtime': str(wallclock),
639  'data': switchinfo,
640  }
641  )
642  sourcemacptr = pySwitchDiscovery._byteNaddr(cast(pktstart, cClass.guint8), 6)
643  if not sourcemacptr:
644  return metadata
645  Cmacaddr = netaddr_mac48_new(sourcemacptr)
646  sourcemac = pyNetAddr(None, Cstruct=Cmacaddr)
647  this = get_cdptlv_first(pktstart, pktend)
648  while this and this < pktend:
649  tlvtype = get_cdptlv_type(this, pktend)
650  tlvlen = get_cdptlv_len(this, pktend)
651  tlvptr = cast(get_cdptlv_body(this, pktend), cClass.guint8)
652  this = get_cdptlv_next(this, pktend)
653  value = None
654  if tlvtype not in pySwitchDiscovery.cdpnames:
655  tlvname = ('TLV_0x%02x' % tlvtype)
656  isswitchinfo = True # Gotta do _something_...
657  else:
658  (tlvname, isswitchinfo) = pySwitchDiscovery.cdpnames[tlvtype]
659  if tlvtype == CDP_TLV_DEVID:
660  value = string_at(tlvptr, tlvlen-4)
661  elif tlvtype == CDP_TLV_ADDRESS:
662  # 4 byte count + 'count' addresses
663  value = pySwitchDiscovery.getcdpaddresses(tlvlen, tlvptr, pktend)
664  elif tlvtype == CDP_TLV_PORTID:
665  value = string_at(tlvptr, tlvlen-4)
666  elif tlvtype == CDP_TLV_CAPS:
667  #bytez = [ '%02x' % pySwitchDiscovery._byteN(tlvptr, j) for j in range(0, tlvlen)]
668  #print >> sys.stderr, 'CAPBYTES = ', bytez
669  caps = pySwitchDiscovery.getNint(tlvptr, 4, pktend)
670  #print >> sys.stderr, ('CAPS IS: 0x%08x (%d bytes)' % (caps, tlvlen))
671  value = pySwitchDiscovery.construct_cdp_caps(caps)
672  elif tlvtype == CDP_TLV_VERS:
673  value = string_at(tlvptr, tlvlen-4)
674  elif tlvtype == CDP_TLV_PLATFORM:
675  value = string_at(tlvptr, tlvlen-4)
676  elif tlvtype == CDP_TLV_POWER:
677  tlen = tlvlen if tlvlen <= 2 else 2
678  value = pySwitchDiscovery.getNint(tlvptr, tlen, pktend)
679  elif tlvtype == CDP_TLV_MTU:
680  value = pySwitchDiscovery.getNint(tlvptr, tlvlen, pktend)
681  elif tlvtype == CDP_TLV_SYSTEM_NAME:
682  value = string_at(tlvptr, tlvlen-4)
683  elif tlvtype == CDP_TLV_MANAGEMENT_ADDR:
684  # 4 byte count + 'count' addresses
685  value = pySwitchDiscovery.getcdpaddresses(tlvlen, tlvptr, pktend)
686  elif tlvtype == CDP_TLV_VTPDOMAIN:
687  value = string_at(tlvptr, tlvlen-4)
688  elif tlvtype == CDP_TLV_NATIVEVLAN:
689  value = tlv_get_guint16(tlvptr, pktend)
690  elif tlvtype == CDP_TLV_UNTRUSTED_COS:
691  value = pySwitchDiscovery._byte0(tlvptr)
692  elif tlvtype == CDP_TLV_DUPLEX:
693  value = 'half' if pySwitchDiscovery._byte0(tlvptr) == 0 else 'full'
694  elif tlvtype == CDP_TLV_LOCATION:
695  value = string_at(tlvptr, tlvlen-4)
696  elif tlvtype == CDP_TLV_EXT_PORTID:
697  value = string_at(tlvptr, tlvlen-4)
698  else:
699  value='0x'
700  for offset in range(0, tlvlen):
701  value += ('%02x' % pySwitchDiscovery._byteN(tlvptr, offset))
702  #print >> sys.stderr, 'Ignoring CDP field %s: %s' % (tlvname, value)
703  value = None
704 
705  if value is None:
706  print >> sys.stderr, ('Ignored %d bytes for %s field [0x%02x]'
707  % (tlvlen, tlvname, tlvtype))
708  else:
709  if tlvtype == CDP_TLV_PORTID:
710  switchinfo['ports'][value] = thisportinfo
711  thisportinfo['PortId'] = value
712  numericpart = value
713  while len(numericpart) > 0 and not numericpart.isdigit():
714  numericpart = numericpart[1:]
715  #if len > 0 and numericpart.isdigit():
716  # thisportinfo['PORTNUM'] = int(numericpart)
717  else:
718  if isswitchinfo:
719  switchinfo[tlvname] = value
720  else:
721  thisportinfo[tlvname] = value
722  #print >> sys.stderr, ('TLVNAME[%s] %s has value "%s" -- len: %d'
723  #% (tlvtype, tlvname, value, len(str(value))))
724  thisportinfo['sourceMAC'] = sourcemac
725  return metadata
726 
727 
728  @staticmethod
729  def getNint(tlvptr, tlvlen, pktend):
730  'Return an integer of any size that we support...'
731  intptr = tlvptr
732  if tlvlen == 1:
733  return tlv_get_guint8(intptr, pktend)
734  if tlvlen == 2:
735  return tlv_get_guint16(intptr, pktend)
736  if tlvlen == 3:
737  return tlv_get_guint24(intptr, pktend)
738  if tlvlen == 4:
739  return tlv_get_guint32(intptr, pktend)
740  if tlvlen == 8:
741  return tlv_get_guint64(intptr, pktend)
742  return None
743 
744  @staticmethod
745  def construct_cdp_caps(capval):
746  'Construct Capability value from the CDP capability integer'
747  capnames = [ CMAconsts.ROLE_router
748  , CMAconsts.ROLE_tb_bridge, CMAconsts.ROLE_srcbridge
749  , CMAconsts.ROLE_bridge, CMAconsts.ROLE_host
750  , CMAconsts.ROLE_igmp, CMAconsts.ROLE_repeater
751  ]
752  mask = 1
753  value = []
754  for j in range(0, len(capnames)):
755  if (capval & mask):
756  #value[capnames[j]] = ((capval & mask) != 0)
757  value.append(capnames[j])
758  mask <<= 1
759  return value
760 
761 
762  @staticmethod
763  def getcdpaddresses(tlvlen, tlvstart, pktend):
764  '''
765  Decode utterly bizarre CDP-specific address list format
766  4 bytes address count
767  'count' addresses in this form:
768  one bytes protocol length
769  'protocol length' bytes of protocol type
770  two bytes address length
771  'address length' bytes of address
772  IPv4:
773  protocol length = 1, protocol type = 0xCC
774  IPv6:
775  protocol length = 8 and address length = 16
776  protocol type == 0xAAAA0300000086DD ??
777  +-------+--------------------+----------+-----------------+
778  |Proto |Protocol Type | address | Actual address |
779  |Length |(protolength bytes) | length | (addresslength |
780  |1 byte |(1-255 bytes) | (2 bytes)| bytes) |
781  +-------+--------------------+----------+-----------------+
782 
783  Min length for an IPV4 address is 8 bytes
784  '''
785  minlength=8
786  retlist = []
787  offset = 0
788  count = pySwitchDiscovery.getNint(tlvstart, 4, pktend)
789  offset += 4
790  for j in range(0, count):
791  addr = None
792  if (offset+minlength) > tlvlen:
793  break
794  protolen = pySwitchDiscovery.getNint(pySwitchDiscovery._byteNaddr
795  ( cast(tlvstart, cClass.guint8), offset), 1, pktend)
796  offset += 2
797  if protolen < 1:
798  break
799  if offset >= tlvlen:
800  break
801  if protolen == 1:
802  prototype = pySwitchDiscovery._byteN(tlvstart, offset+protolen-1)
803  elif protolen == 16:
804  prototype = pySwitchDiscovery.getNint(
805  pySwitchDiscovery._byteNaddr(cast(tlvstart, cClass.guint8), offset+protolen-2)
806  , 2, pktend)
807  else:
808  prototype = 0xdeadbeef
809  offset += protolen
810  if offset > tlvlen:
811  break
812  addrlen = pySwitchDiscovery.getNint(pySwitchDiscovery._byteNaddr
813  ( cast(tlvstart, cClass.guint8), offset), 2, pktend)
814  if protolen == 1 and addrlen == 4 and prototype == 0xCC:
815  addrstr=''
816  for j in (offset+2, offset+3, offset, offset+1):
817  addrstr += chr(pySwitchDiscovery._byteN(tlvstart, j))
818  addr = netaddr_ipv4_new(c_char_p(addrstr), 0)
819  elif protolen == 8 and addrlen == 16 and prototype == 0x86DD:
820  # protocol type == 0xAAAA0300000086DD
821  addr = netaddr_ipv6_new(pySwitchDiscovery._byteNaddr(cast(tlvstart, cClass.guint8)
822  , offset), 0)
823  if addr is not None:
824  pyaddr = pyNetAddr(Cstruct=addr, addrstring=None)
825  retlist.append(pyaddr)
826  offset += addrlen
827 
828  if len(retlist) == 0:
829  return None
830  if len(retlist) == 1:
831  return retlist[0]
832  return retlist
833 
834 
835 
836 
837 class pyAssimObj(object):
838  'The base object for all the C-class objects'
839  def __init__(self, Cstruct=None):
840  'Create a base pyAssimObj object'
841  self._Cstruct = None
842  if (Cstruct is not None):
843  assert not isinstance(Cstruct, (int, long))
844  self._Cstruct = Cstruct
845  else:
846  self._Cstruct = assimobj_new(0)
847  #print 'ASSIMOBJ:init: %s' % (Cstruct)
848 
849  def cclassname(self):
850  "Return the 'C' class name for this object"
851  return proj_class_classname(self._Cstruct)
852 
853  def __str__(self):
854  'Convert this AssimObj into a printable string'
855  if not self._Cstruct:
856  return "[None]"
857  base = self._Cstruct[0]
858  while (not_this_exact_type(base, AssimObj)):
859  base = base.baseclass
860  cstringret = cast(base.toString(self._Cstruct), c_char_p)
861  ret = string_at(cstringret)
862  g_free(cstringret)
863  return ret
864 
865  #pylint: disable=W0603
866  def __del__(self):
867  'Free up the underlying Cstruct for this pyAssimObj object.'
868  if not self._Cstruct or self._Cstruct is None:
869  return
870  global badfree
871  badfree = 0
872  CCunref(self._Cstruct)
873  if badfree != 0:
874  print >> sys.stderr, "Attempt to free something already freed(%s)" % str(self._Cstruct)
875  traceback.print_stack()
876  badfree = 0
877  self._Cstruct = None
878 
879  def refcount(self):
880  'Return the reference count for this object'
881  base = self._Cstruct[0]
882  while (hasattr(base, 'baseclass')):
883  base = base.baseclass
884  return base._refcount
885 
887  '''This class represents the Python version of our C-class @ref NetAddr
888  - represented by the struct _NetAddr.
889  '''
890  def __init__(self, addrstring, port=None, Cstruct=None):
891  '''This constructor needs a list of integers of the right length as its first argument.
892  The length of the list determines the type of address generated.
893  4 bytes == ipv4
894  6 bytes == MAC address
895  8 bytes == MAC address
896  16 bytes == ipv6 address
897  This is slightly sleazy but it should work for the forseeable future.
898  '''
899 
900  self._Cstruct = None # Silence error messages in failure cases
901 
902  if (Cstruct is not None):
903  assert (not isinstance(Cstruct, (int, long))) and Cstruct
904  pyAssimObj.__init__(self, Cstruct=Cstruct)
905  if port is not None:
906  self.setport(port)
907  assert self._Cstruct
908  return
909 
910  if port is None:
911  port = 0
912 
913  if isinstance(addrstring, unicode) or isinstance(addrstring, pyNetAddr):
914  addrstring = str(addrstring)
915  if isinstance(addrstring, str):
916  cs = netaddr_dns_new(addrstring)
917  if not cs:
918  raise ValueError('Illegal NetAddr initial value: "%s"' % addrstring)
919  if port != 0:
920  cs[0].setport(cs, port)
921  pyAssimObj.__init__(self, Cstruct=cs)
922  assert self._Cstruct
923  return
924 
925  self._init_from_binary(addrstring, port)
926  assert self._Cstruct
927 
928  def _init_from_binary(self, addrstring, port):
929  'Initialize an addrstring from a binary argument'
930  alen = len(addrstring)
931  addr = create_string_buffer(alen)
932  #print >> sys.stderr, "ADDRTYPE:", type(addr)
933  #print >> sys.stderr, "ADDRSTRINGTYPE:", type(addrstring)
934  for i in range(0, alen):
935  asi = addrstring[i]
936  #print >> sys.stderr, "ASI_TYPE: (%s,%s)" % (type(asi), asi)
937  if isinstance(asi, (str, unicode)):
938  addr[i] = str(asi)
939  else:
940  addr[i] = chr(asi)
941  #print >> sys.stderr, 'ADDR = %s' % addr
942  if alen == 4: # ipv4
943  NA = netaddr_ipv4_new(addr, port)
944  pyAssimObj.__init__(self, Cstruct=NA)
945  elif alen == 16: # ipv6
946  pyAssimObj.__init__(self, netaddr_ipv6_new(addr, port))
947  elif alen == 6: # "Normal" 48-bit MAC address
948  assert port == 0
949  pyAssimObj.__init__(self, netaddr_mac48_new(addr, port))
950  elif alen == 8: # Extended 64-bit MAC address
951  assert port == 0
952  pyAssimObj.__init__(self, netaddr_mac64_new(addr, port))
953  else:
954  raise ValueError('Invalid address length - not 4, 6, 8, or 16')
955 
956  def port(self):
957  'Return the port (if any) for this pyNetAddr object'
958  base = self._Cstruct[0]
959  while (not_this_exact_type(base, NetAddr)):
960  base = base.baseclass
961  return base.port(self._Cstruct)
962 
963  def setport(self, port):
964  'Return the port (if any) for this pyNetAddr object'
965  base = self._Cstruct[0]
966  while (not_this_exact_type(base, NetAddr)):
967  base = base.baseclass
968  base.setport(self._Cstruct, port)
969 
970  def addrtype(self):
971  'Return the type of address for this pyNetAddr object'
972  base = self._Cstruct[0]
973  while (not_this_exact_type(base, NetAddr)):
974  base = base.baseclass
975  return base.addrtype(self._Cstruct)
976 
977  def addrlen(self):
978  "Return the number of bytes necessary to represent this pyNetAddr object on the wire."
979  base = self._Cstruct[0]
980  while (not_this_exact_type(base, NetAddr)):
981  base = base.baseclass
982  return base._addrlen
983 
984  def islocal(self):
985  'Return True if this address is a local address'
986  base = self._Cstruct[0]
987  while (not_this_exact_type(base, NetAddr)):
988  base = base.baseclass
989  return base.islocal(self._Cstruct)
990 
991  def isanyaddr(self):
992  '''Return True if this address is the 'ANY' address'''
993  base = self._Cstruct[0]
994  while (not_this_exact_type(base, NetAddr)):
995  base = base.baseclass
996  return base.isanyaddr(self._Cstruct)
997 
998  def toIPv6(self, port=None):
999  'Return an equivalent IPv6 address to the one that was given. Guaranteed to be a copy'
1000  base = self._Cstruct[0]
1001  while (not_this_exact_type(base, NetAddr)):
1002  base = base.baseclass
1003  newcs = cast(base.toIPv6(self._Cstruct), cClass.NetAddr)
1004  return pyNetAddr(None, Cstruct=newcs, port=port)
1005 
1006  def toIPv4(self, port=None):
1007  '''Return an equivalent IPv4 address to the one that was given - if possible.
1008  Guaranteed to be a copy'''
1009  base = self._Cstruct[0]
1010  while (not_this_exact_type(base, NetAddr)):
1011  base = base.baseclass
1012  newcs = cast(base.toIPv4(self._Cstruct), cClass.NetAddr)
1013  if not newcs:
1014  raise ValueError('Could not be converted to IPv4: %s' % (str(self)))
1015  return pyNetAddr(None, Cstruct=newcs, port=port)
1016 
1017  def __repr__(self):
1018  'Return a canonical representation of this NetAddr'
1019  assert self._Cstruct
1020  base = self._Cstruct[0]
1021  while (not_this_exact_type(base, NetAddr)):
1022  base = base.baseclass
1023  cstringret = base.canonStr(self._Cstruct)
1024  ret = string_at(cstringret)
1025  g_free(cstringret)
1026  return ret
1027 
1028 
1029  def __eq__(self, other):
1030  "Return True if the two pyNetAddrs are equal"
1031  if not other._Cstruct or not self._Cstruct:
1032  return False
1033  base = self._Cstruct[0]
1034  while (not_this_exact_type(base, NetAddr)):
1035  base = base.baseclass
1036  return True if base.equal(self._Cstruct, other._Cstruct) else False
1037 
1038  def __hash__(self):
1039  'Return a hash value for the given pyNetAddr'
1040  if not self._Cstruct:
1041  return 0
1042  base = self._Cstruct[0]
1043  while (not_this_exact_type(base, NetAddr)):
1044  base = base.baseclass
1045  return base.hash(self._Cstruct)
1046 
1047 
1049  '''This class represents the Python version of our C-class @ref Frame
1050  - represented by the struct _Frame.
1051  This class is a base class for several different pyFrame subclasses.
1052  Each of these various pyFrame subclasses have a corresponding C-class @ref Frame subclass.
1053  The purpose of these pyFrames and their subclasses is to talk on the wire with our C code in our
1054  nanoprobes.
1055 
1056  Deliberately leaving out the updatedata() C-class member function - at least for now.
1057  I suspect that the Python code will only need the corresponding calls in a @ref FrameSet
1058  - which would then update the corresponding @ref Frame member functions...
1059  '''
1060  #
1061  # Our subclasses need to implement these methods:
1062  # __init__ - subclass initializer
1063  # from_Cstruct classmethod - call the corresponding xxxframe_tlvconstructor() function
1064  # to act as a pseudo-constructor. This method/constructor is used to create
1065  # Python objects from incoming packet data.
1066  #
1067  def __init__(self, initval, Cstruct=None):
1068  "Initializer for the pyFrame object."
1069  if Cstruct is None:
1070  try:
1071  frametype = initval.tlvtype
1072  except(AttributeError):
1073  frametype = int(initval)
1074  # If we don't do this, then a subclass __init__ function must do it instead...
1075  pyAssimObj.__init__(self, Cstruct=frame_new(frametype, 0))
1076  else:
1077  pyAssimObj.__init__(self, Cstruct=Cstruct)
1078 
1079  def frametype(self):
1080  "Return the TLV type for the pyFrame object."
1081  base = self._Cstruct[0]
1082  while (not_this_exact_type(base, Frame)):
1083  base = base.baseclass
1084  return base.type
1085 
1086  def framelen(self):
1087  "Return the length of this frame in bytes (TLV length)."
1088  base = self._Cstruct[0]
1089  while (not_this_exact_type(base, Frame)):
1090  base = base.baseclass
1091  return base.length
1092 
1093  def framevalue(self):
1094  'Return a C-style pointer to the underlying raw TLV data (if any)'
1095  base = self._Cstruct[0]
1096  while (not_this_exact_type(base, Frame)):
1097  base = base.baseclass
1098  return cast(base.value, c_char_p)
1099 
1100  def frameend(self):
1101  'Return a C-style pointer to the underlying raw TLV data (if any)'
1102  base = self._Cstruct[0]
1103  while (not_this_exact_type(base, Frame)):
1104  base = base.baseclass
1105  return cast(base.value+base.length, c_char_p)
1106 
1107  def dataspace(self):
1108  'Return the amount of space this frame needs - including type and length'
1109  base = self._Cstruct[0]
1110  while (not_this_exact_type(base, Frame)):
1111  base = base.baseclass
1112  return base.dataspace(self._Cstruct)
1113 
1114  def isvalid(self):
1115  "Return True if this Frame is valid"
1116  base = self._Cstruct[0]
1117  while (not_this_exact_type(base, Frame)):
1118  base = base.baseclass
1119 # pstart = pointer(cast(base.value, c_char_p))
1120 # if pstart[0] is None:
1121 # return False
1122  return (int(base.isvalid(self._Cstruct, None, None)) != 0)
1123 
1124  def setvalue(self, value):
1125  'Assign a chunk of memory to the Value portion of this Frame'
1126  vlen = len(value)
1127  if isinstance(value, (str, unicode)):
1128  valbuf = create_string_buffer(vlen+1)
1129  for i in range(0, vlen):
1130  vi = value[i]
1131  valbuf[i] = vi
1132  valbuf[vlen] = chr(0)
1133  vlen += 1
1134  else:
1135  valbuf = create_string_buffer(vlen)
1136  for i in range(0, vlen):
1137  vi = value[i]
1138  valbuf[i] = int(vi)
1139  base = self._Cstruct[0]
1140  valptr = MALLOC(vlen)
1141  memmove(valptr, valbuf, vlen)
1142  while (not_this_exact_type(base, Frame)):
1143  base = base.baseclass
1144  base.setvalue(self._Cstruct, valptr, vlen, cast(None, GDestroyNotify))
1145 
1146  def dump(self, prefix):
1147  'Dump out this Frame (using C-class "dump" member function)'
1148  base = self._Cstruct[0]
1149  while (not_this_exact_type(base, Frame)):
1150  base = base.baseclass
1151  base.dump(self._Cstruct, cast(prefix, c_char_p))
1152 
1153  def __str__(self):
1154  'Convert this Frame to a string'
1155  base = self._Cstruct[0]
1156  while (not_this_exact_type(base, AssimObj)):
1157  base = base.baseclass
1158  cstringret = cast(base.toString(self._Cstruct), c_char_p)
1159  ret = string_at(cstringret)
1160  g_free(cstringret)
1161  return '%s: %s' % (FrameTypes.get(self.frametype())[1] , ret)
1162 
1163  @staticmethod
1164  def Cstruct2Frame(frameptr):
1165  'Unmarshalls a binary blob (Cstruct) into a Frame'
1166  frameptr = cast(frameptr, cClass.Frame)
1167  CCref(frameptr)
1168  frametype = frameptr[0].type
1169  Cclassname = proj_class_classname(frameptr)
1170  pyclassname = "py" + Cclassname
1171  if Cclassname == 'NetAddr':
1172  statement = "%s(%d, None, Cstruct=cast(frameptr, cClass.%s))" \
1173  % (pyclassname, frametype, Cclassname)
1174  elif Cclassname == Cclassname == 'IpPortFrame':
1175  statement = "%s(%d, None, None, Cstruct=cast(frameptr, cClass.%s))" \
1176  % (pyclassname, frametype, Cclassname)
1177  else:
1178  statement = "%s(%d, Cstruct=cast(frameptr, cClass.%s))" \
1179  % (pyclassname, frametype, Cclassname)
1180  #print >> sys.stderr, "EVAL:", statement
1181  # We construct the string from our data, so it's trusted data...
1182  # pylint: disable=W0123
1183  return eval(statement)
1184 
1186  '''This class represents the Python version of our C-class CompressFrame
1187  - represented by the struct _CompressFrame. It is used to tell us that
1188  what kind of compression we want in our communication stream.
1189  '''
1190  def __init__(self, frametype=FRAMETYPE_COMPRESS, compression_method=COMPRESS_ZLIB
1191  , Cstruct=None):
1192  self._Cstruct = None # Keep error legs from complaining.
1193  if Cstruct is None:
1194  Cstruct = compressframe_new_string(frametype, compression_method)
1195  else:
1196  Cstruct = Cstruct
1197  pyFrame.__init__(self, frametype, Cstruct=Cstruct)
1198 
1199 
1201  '''This class represents the Python version of our C-class AddrFrame
1202  - represented by the struct _AddrFrame.
1203  '''
1204  def __init__(self, frametype, addrstring=None, port=None, Cstruct=None):
1205  "Initializer for the pyAddrFrame object."
1206  self._Cstruct = None # Keep error legs from complaining.
1207  if Cstruct is None:
1208  if isinstance(addrstring, pyNetAddr):
1209  self._pyNetAddr = addrstring
1210  else:
1211  self._pyNetAddr = pyNetAddr(addrstring, port=port)
1212  Cstruct = addrframe_new(frametype, 0)
1213  if addrstring is not None:
1214  Cstruct[0].setnetaddr(Cstruct, self._pyNetAddr._Cstruct)
1215  else:
1216  assert port is None
1217  assert addrstring is None
1218  # Allow for prefixed address type - two bytes
1219  addrlen = Cstruct[0].baseclass.length - 2
1220  assert addrlen == 4 or addrlen == 6 or addrlen == 8 or addrlen == 16 \
1221  , ("addrlen is %d" % addrlen)
1222  addrstr = Cstruct[0].baseclass.value+2
1223  addrstring = create_string_buffer(addrlen)
1224  memmove(addrstring, addrstr, addrlen)
1225  self._pyNetAddr = pyNetAddr(addrstring, port=None)
1226  pyFrame.__init__(self, frametype, Cstruct=Cstruct)
1227 
1228  def addrtype(self):
1229  'Return the Address type for this AddrFrame'
1230  return self._pyNetAddr.addrtype()
1231 
1232  def getnetaddr(self):
1233  'Return the pyNetAddr for this AddrFrame'
1234  return self._pyNetAddr
1235 
1236  def __str__(self):
1237  return ("pyAddrFrame(%s, (%s))" \
1238  % (FrameTypes.get(self.frametype())[1], str(self._pyNetAddr)))
1239 
1241  '''This class represents the Python version of our C-class IpPortFrame
1242  - represented by the struct _IpPortFrame.
1243  '''
1244  def __init__(self, frametype, addrstring, port=None, Cstruct=None):
1245  "Initializer for the pyIpPortFrame object."
1246  self._Cstruct = None # Keep error legs from complaining.
1247  if Cstruct is None:
1248  if isinstance(addrstring, pyNetAddr):
1249  self._pyNetAddr = addrstring
1250  Cstruct = ipportframe_netaddr_new(frametype, addrstring._Cstruct)
1251  if not Cstruct:
1252  raise ValueError("invalid initializer")
1253  self.port = addrstring.port()
1254  else:
1255  Cstruct = self._init_from_binary(frametype, addrstring, port)
1256  else:
1257  assert port is None
1258  assert addrstring is None
1259  addrlen = Cstruct[0].baseclass.length - 4 # Allow for prefixed port and address type
1260  if addrlen != 4 and addrlen != 16:
1261  raise ValueError("Bad addrlen: %d" % addrlen)
1262  port = Cstruct[0].port
1263  self.port = port
1264  addrstr = Cstruct[0].baseclass.value+4
1265  addrstring = create_string_buffer(addrlen)
1266  memmove(addrstring, addrstr, addrlen)
1267  self._pyNetAddr = pyNetAddr(addrstring, port=port)
1268  pyFrame.__init__(self, frametype, Cstruct=Cstruct)
1269 
1270  def _init_from_binary(self, frametype, addrstring, port):
1271  'Initialize a pyIpAddrFrame from a binary argument'
1272  addrlen = len(addrstring)
1273  self._pyNetAddr = pyNetAddr(addrstring, port=port)
1274  if self._pyNetAddr is None:
1275  raise ValueError("Invalid initializer.")
1276  addrstr = create_string_buffer(addrlen)
1277  for j in range(0, addrlen):
1278  addrstr[j] = chr(addrstring[j])
1279  if addrlen == 4:
1280  Cstruct = ipportframe_ipv4_new(frametype, port, addrstr)
1281  elif addrlen == 16:
1282  Cstruct = ipportframe_ipv6_new(frametype, port, addrstr)
1283  else:
1284  raise ValueError('Bad address length: %d' % addrlen)
1285  self.port = port
1286  if port == 0:
1287  raise ValueError("zero port")
1288  if not Cstruct:
1289  raise ValueError("invalid initializer")
1290  return Cstruct
1291 
1292  def addrtype(self):
1293  'Return the Address type of this pyIpPortFrame'
1294  return self._pyNetAddr.addrtype()
1295 
1296  def getnetaddr(self):
1297  'Return the NetAddr of this pyIpPortFrame'
1298  return self._pyNetAddr
1299 
1300  def getport(self):
1301  'Return the port of this pyIpPortFrame'
1302  return self._pyNetAddr.port()
1303 
1304 
1306  '''This class represents the Python version of our C-class CstringFrame
1307  - represented by the struct _CstringFrame.
1308  This class represents a Frame standard NUL-terminated C string.
1309  '''
1310  def __init__(self, frametype, initval=None, Cstruct=None):
1311  '''Constructor for pyCstringFrame object - initial value should be something
1312  that looks a lot like a Python string'''
1313  if Cstruct is None:
1314  Cstruct = cstringframe_new(frametype, 0)
1315  pyFrame.__init__(self, frametype, Cstruct)
1316  if initval is not None:
1317  self.setvalue(initval)
1318 
1319  def getstr(self):
1320  'Return the String part of this pyCstringFrame'
1321  base = self._Cstruct[0]
1322  while (not hasattr(base, 'value')):
1323  base = base.baseclass
1324  return string_at(base.value)
1325 
1327  '''This class represents the Python version of our IntFrame C-class
1328  - represented by the struct _IntFrame.
1329  This class represents an integer of 1, 2, 3, 4 or 8 bytes.
1330  '''
1331  def __init__(self, frametype, initval=None, intbytes=4, Cstruct=None):
1332  '''Constructor for pyIntFrame object
1333  - initial value should be something that looks a lot like an integer'''
1334  self._Cstruct = None
1335  if Cstruct is None:
1336  Cstruct = intframe_new(frametype, intbytes)
1337  if not Cstruct:
1338  raise ValueError("Invalid integer size (%d) in pyIntFrame constructor" % intbytes)
1339  pyFrame.__init__(self, frametype, Cstruct=Cstruct)
1340  if initval is not None:
1341  self.setint(initval)
1342 
1343  def __int__(self):
1344  '''Return the integer value of this pyIntFrame. (implemented by the
1345  underlying IntFrame object)'''
1346  return self._Cstruct[0].getint(self._Cstruct)
1347 
1348  def __str__(self):
1349  'Return a string representation of this pyIntFrame (the integer value).'
1350  return ("pyIntFrame(%s, (%d))" % (FrameTypes.get(self.frametype())[1], int(self)))
1351 
1352  def getint(self):
1353  'Return the integer value of this pyIntFrame - same as __int__.'
1354  return int(self)
1355 
1356  def setint(self, intval):
1357  '''Set the value of this pyIntFrame to the given integer value.
1358  Note that this value is range checked by the underlying IntFrame implementation.
1359  '''
1360  self._Cstruct[0].setint(self._Cstruct, int(intval))
1361 
1362  def intlength(self):
1363  '''Return the number of bytes in the integer underlying this pyIntFrame object.
1364  (implemented by underlying IntFrame object)'''
1365  return self._Cstruct[0].intlength(self._Cstruct)
1366 
1368  "Class for a Frame type we don't recognize"
1369  def __init__(self, frametype, Cstruct=None):
1370  'Initializer for pyUnknownFrame'
1371  if Cstruct is None:
1372  Cstruct = unknownframe_new(frametype)
1373  pyFrame.__init__(self, frametype, Cstruct)
1374 
1376  'Class for a Sequence Number Frame - for reliable UDP packet transmission.'
1377  def __init__(self, frametype, initval=None, Cstruct=None):
1378  'Initializer for pySeqnoFrame'
1379  self._Cstruct = None
1380  # TODO(?): Need to allow for initialization of seqno frames.
1381  if Cstruct is None:
1382  Cstruct = seqnoframe_new(frametype, 0)
1383  if not Cstruct:
1384  raise ValueError("Constructor error for PySeqnoFrame()")
1385  pyFrame.__init__(self, frametype, Cstruct=Cstruct)
1386  if initval is not None:
1387  self.setqid(initval[0])
1388  self.setreqid(initval[1])
1389 
1390  def setreqid(self, reqid):
1391  'Set the request ID portion of this SeqnoFrame'
1392  self._Cstruct[0].setreqid(self._Cstruct, reqid)
1393 
1394  def setqid(self, qid):
1395  'Set the Queue ID portion of this SeqnoFrame'
1396  self._Cstruct[0].setqid(self._Cstruct, qid)
1397 
1398  def getreqid(self):
1399  'Get the request ID portion of this SeqnoFrame'
1400  return self._Cstruct[0].getreqid(self._Cstruct)
1401 
1402  def getqid(self):
1403  'Get the Queue ID portion of this SeqnoFrame'
1404  return self._Cstruct[0].getqid(self._Cstruct)
1405 
1406  def __eq__(self, rhs):
1407  'Compare this pySeqnoFrame to another pySeqnoFrame'
1408  lhsbase = self._Cstruct[0]
1409  while (not_this_exact_type(lhsbase, SeqnoFrame)):
1410  lhsbase = lhsbase.baseclass
1411  return True if lhsbase.equal(self._Cstruct, rhs._Cstruct) else False
1412 
1413  def __str__(self):
1414  'Convert this pySeqnoFrame to a String'
1415  return ("pySeqNo(%s: (%d, %d))" \
1416  % (FrameTypes.get(self.frametype())[1], self.getqid(), self.getreqid()))
1417 
1419  '''Class for Digital Signature Frames
1420  - for authenticating data (subclasses will authenticate senders)'''
1421  def __init__(self, gchecksumtype, Cstruct=None):
1422  'Initializer for pySignFrame'
1423  self._Cstruct = None
1424  if Cstruct is None:
1425  Cstruct = signframe_glib_new(gchecksumtype, 0)
1426  if not Cstruct:
1427  raise ValueError("Invalid checksum type (%s) for PySignFrame()" % gchecksumtype)
1428  pyFrame.__init__(self, initval=FRAMETYPE_SIG, Cstruct=Cstruct)
1429 
1431  'Class for a Frame containing a single name/value pair'
1432  def __init__(self, frametype, name, value, Cstruct=None):
1433  'Initializer for pyNVpairFrame'
1434  self._Cstruct = None
1435  if Cstruct is None:
1436  Cstruct = nvpairframe_new(frametype, name, value, 0)
1437  if not Cstruct:
1438  raise ValueError("Invalid NVpair initializer for pyNVPairFrame()")
1439  pyFrame.__init__(self, initval=frametype, Cstruct=Cstruct)
1440 
1441  def name(self):
1442  'Return the name portion of a pyNVpairFrame'
1443  return string_at(self._Cstruct[0].name)
1444 
1445  def value(self):
1446  'Return the name portion of a pyNVpairFrame'
1447  return string_at(self._Cstruct[0].value)
1448 
1450  '''Abstract class for a generalized encryption frame
1451  Our main importance is for our static methods which allow us
1452  to map key ids to identities, and IP addresses to key ids.
1453  The underlying C code then automatically creates the correct
1454  CryptFrame objects for outgoing packets.
1455  '''
1456  NOTAKEY = AssimCtypes.NOTAKEY
1457  PUBLICKEY = AssimCtypes.PUBLICKEY
1458  PRIVATEKEY = AssimCtypes.PRIVATEKEY
1459  def __init__(self, destaddr=None, Cstruct=None):
1460  self._Cstruct = None
1461  if Cstruct is None and destaddr is None:
1462  raise ValueError('pyCryptFrame requires destaddr or Cstruct')
1463  if Cstruct is None:
1464  Cstruct = cryptframe_new_by_destaddr(destaddr._Cstruct)
1465  pyFrame.__init__(self, None, Cstruct=Cstruct)
1466 
1467  def receiver_id(self):
1468  'Return the key_id of the receiver key'
1469  return string_at(self._Cstruct[0].receiver_key_id)
1470 
1471  @staticmethod
1473  'Returns the set of key ids that we know about'
1474  keyidlist_int = cryptframe_get_key_ids()
1475  keyid_gslist = cast(keyidlist_int, cClass.GSList)
1476  keyid_list = []
1477  curkeyid = keyid_gslist
1478  while curkeyid:
1479  keyid_list.append(string_at(curkeyid[0].data))
1480  curkeyid = g_slist_next(curkeyid)
1481  g_slist_free(keyid_gslist)
1482  return keyid_list
1483 
1484  @staticmethod
1486  'Return the set of CMA key ids we know about'
1487  ret = []
1488  for keyid in pyCryptFrame.get_key_ids():
1489  if keyid.startswith(CMA_KEY_PREFIX):
1490  ret.append(keyid)
1491  return ret
1492 
1493  @staticmethod
1494  def associate_identity(identityname, key_id):
1495  '''Associate the given identity name with the given key id
1496  This allows many keys to be associated with a single identity, but
1497  does not support a key being associated with multiple identities
1498  (which doesn't make sense anyway).
1499  '''
1500  assert identityname is not None
1501  assert key_id is not None
1502  if not cryptframe_associate_identity(str(identityname), str(key_id)):
1503  raise ValueError("Problem with key id %s or identity %s" % (key_id, identityname))
1504 
1505  @staticmethod
1506  def get_identity(key_id):
1507  'Return the identity associated with the given key id'
1508  assert key_id is not None
1509  cret = cryptframe_whois_key_id(str(key_id))
1510  if not cret:
1511  return None
1512  return str(cret)
1513 
1514  @staticmethod
1515  def get_dest_identity(destaddr):
1516  'Return the identity associated with this pyNetAddr'
1517  key_id = pyCryptFrame.get_dest_key_id(destaddr)
1518  if key_id is None:
1519  return None
1520  return pyCryptFrame.get_identity(key_id)
1521 
1522  @staticmethod
1523  def get_dest_key_id(destaddr):
1524  'Return the key_id associated with this pyNetAddr'
1525  cret = cryptframe_get_dest_key_id(destaddr._Cstruct)
1526  if not cret:
1527  return None
1528  return str(cret)
1529 
1530  @staticmethod
1531  def dest_set_key_id(destaddr, key_id):
1532  '''Set the public key we should use when talking to the given destination
1533  address (including port).
1534  '''
1535  if not destaddr._Cstruct or key_id is None:
1536  raise ValueError('illegal parameters')
1537  if not cryptframe_set_dest_key_id(destaddr._Cstruct, str(key_id)):
1538  raise ValueError("Inappropriate key_id %s" % key_id)
1539 
1540 
1541 #This is a bizarre and buggy complaint...
1542 #AssimCclasses.py:1283: [R0904:pyCryptCurve25519] Too many public methods (21/20)
1543 #pylint: disable=R0904
1545  '''Encryption Frame based on Libsodium - Curve25519 public key encryption.
1546  Strangely enough, we may not actually use objects of this class - because it's
1547  effectively hidden by the C code from us having to know about it.
1548 
1549  Instead we just manage public keys, and map IP addresses to public keys
1550  and the C code under us takes care of the rest in terms of creating these objects.
1551  '''
1552  def __init__(self, publickey_id=None, privatekey_id=None, Cstruct=None):
1553  self._Cstruct = None
1554  if Cstruct is None:
1555  Cstruct = cryptcurve25519_new(FRAMETYPE_CRYPTCURVE25519, publickey_id, privatekey_id, 0)
1556  pyCryptFrame.__init__(self, Cstruct=Cstruct)
1557 
1558  @staticmethod
1559  def key_id_to_filename(key_id, keytype):
1560  'Translate a key_id to a filename'
1561  ret = curve25519_key_id_to_filename(key_id, keytype)
1562  pyret = string_at(ret.raw)
1563  g_free(ret)
1564  return pyret
1565 
1566  @staticmethod
1567  def initkeys():
1568  '''Initialize our set of persistent public keys / keypairs and get ready to encrypt.
1569  This involves several steps:
1570  1) Read in all available public and private keys
1571  2) If we have no CMA keys, then generate two keypairs and give instructions
1572  on hiding the second one...
1573  2) Figure out which private keys are ours and select which one (oldest) to use
1574  as our preferred signing key
1575  3) set the default signing method
1576 
1577  Note that there are still two issues that this doesn't deal with:
1578  Persisting the association between nanoprobe keys ids and (domain, hostname) pairs
1579  Assigning default IP addresses with nanoprobe key ids.
1580  '''
1581  warnings = []
1583  cma_ids = pyCryptFrame.get_cma_key_ids()
1584  cma_ids.sort()
1585  if len(cma_ids) == 0:
1586  warnings.append('No CMA keys found. Generating two CMA key-pairs to start.')
1587  for keyid in (0, 1):
1588  print >> sys.stderr, "Generating key id", keyid
1589  cryptcurve25519_gen_persistent_keypair('%s%05d' % (CMA_KEY_PREFIX, keyid))
1591  cma_ids = pyCryptFrame.get_cma_key_ids()
1592  elif len(cma_ids) == 1:
1593  lastkey = cma_ids[0]
1594  lastseqno = int(lastkey[len(CMA_KEY_PREFIX):])
1595  newkeyid = ('%s%05d' % (CMA_KEY_PREFIX, lastseqno + 1))
1596  warnings.append('Generating an additional CMA key-pair.')
1599  cma_ids = pyCryptFrame.get_cma_key_ids()
1600  if len(cma_ids) != 2:
1601  warnings.append('Unexpected number of CMA keys. Expecting 2, but got %d.'
1602  % len(cma_ids))
1603  # We want to use the lowest-numbered private key we have access to.
1604  privatecount = 0
1605  extras = []
1606  cma_ids.sort()
1607  for keyid in cma_ids:
1608  pyCryptFrame.associate_identity(CMA_IDENTITY_NAME, keyid)
1609  if cryptframe_private_key_by_id(keyid):
1610  privatecount += 1
1611  if privatecount == 1:
1613  else:
1614  extras.append(keyid)
1615  if privatecount < 1:
1616  raise RuntimeError('FATAL: No CMA private keys to sign with!')
1617  if privatecount != 1:
1618  warnings.append('Incorrect number of Private CMA keys. Expecting 1, but got %d.'
1619  % len(cma_ids))
1620  warnings.append('YOU MUST SECURELY HIDE all but one private CMA key.')
1621  for keyid in extras:
1622  warnings.append('SECURELY HIDE *private* key %s' %
1623  pyCryptCurve25519.key_id_to_filename(keyid, pyCryptFrame.PRIVATEKEY))
1625  return warnings
1626 
1627 
1628 #pylint: disable=R0921
1630  'Class for Frame Sets - for collections of Frames making up a logical packet'
1631  def __init__(self, framesettype, Cstruct=None):
1632  'Initializer for pyFrameSet'
1633  if Cstruct is None:
1634  Cstruct = frameset_new(framesettype)
1635  pyAssimObj.__init__(self, Cstruct=Cstruct)
1636 
1637  def append(self, frame):
1638  'Append a frame to the end of a @ref FrameSet'
1639  frameset_append_frame(self._Cstruct, frame._Cstruct)
1640 
1641  def prepend(self, frame):
1642  'Prepend a frame before the first frame in a @ref FrameSet'
1643  frameset_prepend_frame(self._Cstruct, frame._Cstruct)
1644 
1645  def construct_packet(self, signframe, cryptframe=None, compressframe=None):
1646  'Construct packet from curent frameset + special prefix frames'
1647  cf = None
1648  cmpf = None
1649  if cryptframe is not None:
1650  cf = cryptframe._Cstruct
1651  if compressframe is not None:
1652  cmpf = compressframe._Cstruct
1653  frameset_construct_packet(self._Cstruct, signframe._Cstruct, cf, cmpf)
1654 
1655  def get_framesettype(self):
1656  'Return frameset type of this FrameSet'
1657  return self._Cstruct[0].fstype
1658 
1659  def get_flags(self):
1660  'Return current flags for this FrameSet'
1661  return frameset_get_flags(self._Cstruct)
1662 
1663  def set_flags(self, flags):
1664  "'OR' the given flags into the set of flags for this FrameSet"
1665  return frameset_set_flags(self._Cstruct, int(flags))
1666 
1667  def clear_flags(self, flags):
1668  "Clear the given flags for this FrameSet"
1669  return frameset_clear_flags(self._Cstruct, int(flags))
1670 
1671  def sender_key_id(self):
1672  'Return the key_id of the cryptographic sender of this FrameSet'
1673  #print >> sys.stderr, 'TYPE(self)', type(self), 'str(self)', str(self), type(self._Cstruct)
1674  ret = frameset_sender_key_id(self._Cstruct)
1675  #print >> sys.stderr, 'sender_key_id: TYPE(ret)', type(ret), 'ret', ret, \
1676  # 'raw', ret.raw, 'data', ret.data
1677  #print >> sys.stderr, 'sender_key_id: str(ret)', str(ret), type(str(ret)), not ret
1678  #print type(ret.raw), ret.raw
1679  if not ret:
1680  #print >> sys.stderr, 'Returning None(!)', self.get_framesettype()
1681  return None
1682  pyret = string_at(ret.raw)
1683  #print >> sys.stderr, 'PYRET:', type(pyret), 'pyret:', pyret
1684  return pyret
1685 
1686  def sender_identity(self):
1687  'Return the identity of the cryptographic sender of this FrameSet'
1688  cret = frameset_sender_identity(self._Cstruct)
1689  if not cret:
1690  return None
1691  return str(cret)
1692 
1693  def dump(self):
1694  'Dump out the given frameset'
1695  frameset_dump(self._Cstruct)
1696 
1697  def getpacket(self):
1698  'Return the constructed packet for this pyFrameSet'
1699  if not self._Cstruct[0].packet:
1700  raise ValueError("No packet constructed for frameset")
1701  return (self._Cstruct[0].packet, self._Cstruct[0].pktend)
1702 
1703  def __len__(self):
1704  'Return the number of Frames in this pyFrameSet'
1705  # This next statement OUGHT to work - and indeed it returns the right value
1706  # But somehow, 'self' doesn't get freed like it ought to :-(
1707  # BUG??
1708  #return g_slist_length(self._Cstruct[0].framelist)
1709  # So, let's do this instead...
1710  curframe = self._Cstruct[0].framelist
1711  count = 0
1712  while curframe:
1713  count += 1
1714  curframe = g_slist_next(curframe)
1715  return int(count)
1716 
1717  def __delitem__(self, key):
1718  "Fail - we don't implement this"
1719  raise NotImplementedError("FrameSet does not implement __delitem__()")
1720 
1721  def __getitem__(self, key):
1722  "Fail - we don't implement this"
1723  raise NotImplementedError("FrameSet does not implement __getitem__()")
1724 
1725  def __setitem__(self, key, value):
1726  "Fail - we don't implement this"
1727  raise NotImplementedError("FrameSet does not implement __setitem__()")
1728 
1729  def iter(self):
1730  'Generator yielding the set of pyFrames in this pyFrameSet'
1731  curframe = self._Cstruct[0].framelist
1732  while curframe:
1733  cast(curframe[0].data, struct__GSList._fields_[0][1])
1734  yieldval = pyFrame.Cstruct2Frame(cast(curframe[0].data, cClass.Frame))
1735  #print >> sys.stderr, ("Constructed frame IS [%s]" % str(yieldval))
1736  if not yieldval.isvalid():
1737  print >> sys.stderr \
1738  , "OOPS! Constructed %d byte frame from iter() is not valid [%s]" \
1739  % (yieldval.framelen(), str(yieldval))
1740  raise ValueError("Constructed %d byte frame from iter() is not valid [%s]"
1741  % (yieldval.framelen(), str(yieldval)))
1742  #print "Yielding:", str(yieldval), "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
1743  yield yieldval
1744  curframe = g_slist_next(curframe)
1745 
1746  def fstypestr(self):
1747  'Return the frameset type name as a string'
1748  return FrameSetTypes.get(self.get_framesettype())[0]
1749 
1750  def __str__(self):
1751  'Convert this pyFrameSet to a String'
1752  result = '%s:{' % self.fstypestr()
1753  comma = ''
1754  for frame in self.iter():
1755  result += '%s[%d]%s' % (comma, frame.framelen(), str(frame))
1756  comma = ', '
1757  result += "}"
1758  return result
1759 
1760 
1761 
1763  'Class for Decoding packets - for returning an array of FrameSets from a physical packet.'
1764  def __init__(self, Cstruct=None):
1765  'Initializer for pyPacketDecoder'
1766  if Cstruct is None:
1767  Cstruct = packetdecoder_new(0, None, 0)
1768  pyAssimObj.__init__(self, Cstruct=Cstruct)
1769 
1770  def fslist_from_pktdata(self, pktlocation):
1771  'Make a list of FrameSets out of a packet.'
1772  base = self._Cstruct[0]
1773  while (not_this_exact_type(base, AssimCtypes.PacketDecoder)):
1774  base = base.baseclass
1775  fs_gslistint = base.pktdata_to_framesetlist(self._Cstruct, pktlocation[0], pktlocation[1])
1776  return pyPacketDecoder.fslist_to_pyfs_array(fs_gslistint)
1777 
1778  @staticmethod
1779  def fslist_to_pyfs_array(listheadint):
1780  'Converts a GSList of FrameSets to a python array of pyFrameSets'
1781  fs_gslist = cast(listheadint, cClass.GSList)
1782  frameset_list = []
1783  curfs = fs_gslist
1784  while curfs:
1785  cfs = cast(curfs[0].data, cClass.FrameSet)
1786  fs = pyFrameSet(None, Cstruct=cfs)
1787  frameset_list.append(fs)
1788  curfs = g_slist_next(curfs)
1789  g_slist_free(fs_gslist)
1790  return frameset_list
1791 
1792 # R0904: Too many public methods
1793 #pylint: disable=R0904
1795  'Class for Holding configuration information - now a general JSON-compatible data bag'
1796  #pylint: disable=R0921
1797 
1798  def __init__(self, init=None, filename=None, Cstruct=None):
1799  'Initializer for pyConfigContext'
1800  self._Cstruct = None # Keep error legs from complaining.
1801  if not Cstruct:
1802  # Cstruct overrides init and filename
1803  if filename is not None:
1804  f = open(filename, 'r')
1805  # filename overrides init
1806  init = f.read()
1807  f.close()
1808  if (isinstance(init, str) or isinstance(init, unicode)):
1809  Cstruct = configcontext_new_JSON_string(str(init))
1810  if not Cstruct:
1811  raise ValueError('Bad JSON [%s]' % str(init))
1812  init = None
1813  else:
1814  Cstruct = configcontext_new(0)
1815  pyAssimObj.__init__(self, Cstruct=Cstruct)
1816  if init is not None:
1817  for key in init.keys():
1818  self[key] = init[key]
1819 
1820 
1821  def getint(self, name):
1822  'Return the integer associated with "name"'
1823  return self._Cstruct[0].getint(self._Cstruct, name)
1824 
1825  def setint(self, name, value):
1826  'Set the integer associated with "name"'
1827  self._Cstruct[0].setint(self._Cstruct, name, value)
1828 
1829  def getbool(self, name):
1830  'Return the boolean associated with "name"'
1831  return self._Cstruct[0].getbool(self._Cstruct, name) != 0
1832 
1833  def setbool(self, name, value):
1834  'Set the boolean associated with "name"'
1835  self._Cstruct[0].setbool(self._Cstruct, name, bool(value))
1836 
1837  def getfloat(self, name):
1838  'Return the floating point value associated with "name"'
1839  return self._Cstruct[0].getdouble(self._Cstruct, name)
1840 
1841  def setfloat(self, name, value):
1842  'Set the floating point value associated with "name"'
1843  self._Cstruct[0].setdouble(self._Cstruct, name, float(value))
1844 
1845  def getaddr(self, name):
1846  'Return the NetAddr associated with "name"'
1847  naddr = self._Cstruct[0].getaddr(self._Cstruct, name)
1848  if naddr:
1849  naddr = cast(naddr, cClass.NetAddr)
1850  # We're creating a new reference to the pre-existing NetAddr
1851  CCref(naddr)
1852  return pyNetAddr(None, Cstruct=naddr)
1853  raise IndexError("No such NetAddr value [%s]" % name)
1854 
1855  def setaddr(self, name, value):
1856  'Set the @ref NetAddr associated with "name"'
1857  self._Cstruct[0].setaddr(self._Cstruct, name, value._Cstruct)
1858 
1859  def getframe(self, name):
1860  'Return the Frame associated with "name"'
1861  faddr = self._Cstruct[0].getframe(self._Cstruct, name)
1862  if faddr:
1863  # Cstruct2Frame already calls CCref()
1864  return pyFrame.Cstruct2Frame(faddr)
1865  raise IndexError("No such Frame value [%s]" % name)
1866 
1867  def setframe(self, name, value):
1868  'Set the @ref Frame associated with "name"'
1869  self._Cstruct[0].setframe(self._Cstruct, name, value._Cstruct)
1870 
1871  def getconfig(self, name):
1872  'Return the pyConfigContext object associated with "name"'
1873  caddr = self._Cstruct[0].getconfig(self._Cstruct, name)
1874  if caddr:
1875  caddr = cast(caddr, cClass.ConfigContext)
1876  # We're creating a new reference to the pre-existing NetAddr
1877  CCref(caddr)
1878  return pyConfigContext(Cstruct=caddr)
1879  raise IndexError("No such ConfigContext value [%s]" % name)
1880 
1881  def setconfig(self, name, value):
1882  'Set the @ref ConfigContext associated with "name"'
1883  self._Cstruct[0].setconfig(self._Cstruct, name, value._Cstruct)
1884 
1885  def getstring(self, name):
1886  'Return the string associated with "name"'
1887  ret = self._Cstruct[0].getstring(self._Cstruct, name)
1888  if ret:
1889  return string_at(ret)
1890  raise IndexError("No such String value [%s]" % name)
1891 
1892  def setstring(self, name, value):
1893  'Set the string associated with "name"'
1894  self._Cstruct[0].setstring(self._Cstruct, name, value)
1895 
1896  def getarray(self, name):
1897  'Return the array value associated with "name"'
1898  curlist = cast(self._Cstruct[0].getarray(self._Cstruct, name), cClass.GSList)
1899  #print >> sys.stderr, "CURLIST(initial) = %s" % curlist
1900  ret = []
1901  while curlist:
1902  #print >> sys.stderr, "CURLIST = %s" % curlist
1903  #cfgval = pyConfigValue(cast(cClass.ConfigValue, curlist[0].data).get())
1904  data = cast(curlist[0].data, cClass.ConfigValue)
1905  #print >> sys.stderr, "CURLIST->data = %s" % data
1906  CCref(data)
1907  cfgval = pyConfigValue(data).get()
1908  #print >> sys.stderr, "CURLIST->data->get() = %s" % cfgval
1909  ret.append(cfgval)
1910  curlist = g_slist_next(curlist)
1911  return ret
1912 
1913  def setarray(self, name, value):
1914  'Set a ConfigContext key value to be a sequence of values from an iterable'
1915  self._Cstruct[0].setarray(self._Cstruct, name, None)
1916  for elem in value:
1917  if isinstance(elem, bool):
1918  self._Cstruct[0].appendbool(self._Cstruct, name, elem)
1919  continue
1920  if isinstance(elem, (int, long)):
1921  self._Cstruct[0].appendint(self._Cstruct, name, elem)
1922  continue
1923  if isinstance(elem, float):
1924  self._Cstruct[0].appendfloat(self._Cstruct, name, elem)
1925  continue
1926  if isinstance(elem, str):
1927  self._Cstruct[0].appendstring(self._Cstruct, name, elem)
1928  continue
1929  if isinstance(elem, pyNetAddr):
1930  self._Cstruct[0].appendaddr(self._Cstruct, name, elem)
1931  continue
1932  if isinstance(elem, pyConfigContext):
1933  self._Cstruct[0].appendconfig(self._Cstruct, name, elem._Cstruct)
1934  continue
1935  if isinstance(elem, dict):
1936  cfgctx = pyConfigContext.from_dict(elem)
1937  self._Cstruct[0].appendconfig(self._Cstruct, name, cfgctx._Cstruct)
1938  continue
1939  raise ValueError("Cannot append/include array elements of type %s" % type(elem))
1940 
1941  @staticmethod
1942  def from_dict(dictval):
1943  'Construct a pyConfigContext from a dict-like object'
1944  newobj = pyConfigContext()
1945  for key in dictval.keys():
1946  keyval = dictval[key]
1947  if hasattr(keyval, 'keys'):
1948  keyval = pyConfigContext.from_dict(dictval[key])
1949  newobj[key] = dictval[key]
1950  return newobj
1951 
1952  def keys(self):
1953  'Return the set of keys for this object'
1954  l = []
1955  keylist = cast(self._Cstruct[0].keys(self._Cstruct), POINTER(GSList))
1956  curkey = keylist
1957  while curkey:
1958  l.append(string_at(curkey[0].data))
1959  curkey = g_slist_next(curkey)
1960  g_slist_free(keylist)
1961  return l
1962 
1963  def __iter__(self):
1964  'Iterate over self.keys()'
1965  for key in self.keys():
1966  yield key
1967 
1968  def gettype(self, name):
1969  '''Return the enumeration type of this particular key
1970  @todo Convert these enums to python types'''
1971  #print >> sys.stderr, 'gettype(%s)' % str(name)
1972  return self._Cstruct[0].gettype(self._Cstruct, str(name))
1973 
1974  def get(self, key, alternative=None):
1975  '''return value if object contains the given key - 'alternative' if not'''
1976  if self._Cstruct[0].gettype(self._Cstruct, str(key)) == CFG_EEXIST:
1977  return alternative
1978  return self[key]
1979 
1980  # pylint R0911: too many returns (9)
1981  # pylint: disable=R0911
1982  def deepget(self, key, alternative=None):
1983  '''return value if object contains the given *structured* key - 'alternative' if not'''
1984  try:
1985  (prefix, suffix) = key.split('.', 1)
1986  except ValueError:
1987  suffix = None
1988  prefix = key
1989  if prefix not in self:
1990  # Note that very similar code exists in GraphNodes get member function
1991  if not prefix.endswith(']'):
1992  return alternative
1993  else:
1994  # Looks like we have an array index
1995  proper = prefix[0:len(prefix)-1]
1996  try:
1997  (preprefix, idx) = proper.split('[', 1)
1998  except ValueError:
1999  return alternative
2000  if preprefix not in self:
2001  return alternative
2002  try:
2003  array = self[preprefix]
2004  idx = int(idx) # Possible ValueError
2005  value = array[idx] # possible IndexError or TypeError
2006  if suffix is None:
2007  return value
2008  except (TypeError, IndexError, ValueError):
2009  return alternative
2010  return value.deepget(suffix, alternative)
2011 
2012  prefixvalue = self[prefix]
2013  if suffix is None:
2014  return prefixvalue
2015  if not isinstance(prefixvalue, pyConfigContext):
2016  return alternative
2017  gotten = prefixvalue.deepget(suffix, alternative)
2018  return gotten
2019 
2020  def has_key(self, key):
2021  'return True if it has the given key'
2022  return self.__contains__(key)
2023 
2024  def __contains__(self, key):
2025  'return True if our object contains the given key'
2026  ktype = self._Cstruct[0].gettype(self._Cstruct, str(key))
2027  return ktype != CFG_EEXIST
2028 
2029  def __len__(self):
2030  'Return the number of items in this pyConfigContext'
2031  keylist = cast(self._Cstruct[0].keys(self._Cstruct), POINTER(GSList))
2032  llen = g_slist_length(keylist)
2033  g_slist_free(keylist)
2034  return llen
2035 
2036  def __delitem__(self, key):
2037  "Delete the given item"
2038  self._Cstruct[0].delkey(self._Cstruct, str(key))
2039 
2040  def __getitem__(self, name):
2041  'Return a value associated with "name"'
2042  name = str(name)
2043  ktype = self.gettype(name)
2044  ret = None
2045  #print >> sys.stderr, '************ GETITEM[%s] => %d *********************' % (name, ktype)
2046  if ktype == CFG_EEXIST:
2047  traceback.print_stack()
2048  raise IndexError("No such value [%s] in [%s]" % (name, str(self)))
2049  elif ktype == CFG_CFGCTX:
2050  ret = self.getconfig(name)
2051  elif ktype == CFG_STRING:
2052  ret = self.getstring(name)
2053  elif ktype == CFG_NETADDR:
2054  ret = self.getaddr(name)
2055  elif ktype == CFG_FRAME:
2056  ret = self.getframe(name)
2057  elif ktype == CFG_INT64:
2058  ret = self.getint(name)
2059  elif ktype == CFG_FLOAT:
2060  ret = self.getfloat(name)
2061  elif ktype == CFG_BOOL:
2062  ret = self.getbool(name)
2063  elif ktype == CFG_ARRAY:
2064  #print >> sys.stderr, '************ GETITEM[%s] => getarray(%s) *********************' \
2065  # % (name, name)
2066  ret = self.getarray(name)
2067  return ret
2068 
2069  def __setitem__(self, name, value):
2070  'Set a value associated with "name" - in the appropriate table'
2071  if isinstance(value, str):
2072  return self.setstring(name, value)
2073  if isinstance(value, pyNetAddr):
2074  return self.setaddr(name, value)
2075  if isinstance(value, pyFrame):
2076  return self.setframe(name, value)
2077  if isinstance(value, pyConfigContext):
2078  return self.setconfig(name, value)
2079  if isinstance(value, dict):
2080  return self.setconfig(name, pyConfigContext(value))
2081  if isinstance(value, (list, tuple)) or hasattr(value, '__iter__'):
2082  return self.setarray(name, value)
2083  if isinstance(value, float):
2084  return self.setfloat(name, value)
2085  if isinstance(value, dict):
2086  return self.setconfig(name, pyConfigContext.from_dict(value))
2087  if isinstance(value, bool):
2088  return self.setbool(name, value)
2089  self.setint(name, int(value))
2090 
2092  'A Python wrapper for a C implementation of something like a Python Dictionary'
2093  def __init__(self, Cstruct):
2094  'Initializer for pyConfigValue - now a subclass of pyAssimObj'
2095  pyAssimObj.__init__(self, Cstruct=Cstruct)
2096 
2097  def __str__(self):
2098  'Convert the given pyConfigValue to a String'
2099  str(self.get())
2100 
2101  def get(self):
2102  'Return the value of this object'
2103  ret = None
2104  vtype = self._Cstruct[0].valtype
2105  if vtype == CFG_BOOL:
2106  ret = self._Cstruct[0].u.intvalue != 0
2107  elif vtype == CFG_INT64:
2108  ret = int(self._Cstruct[0].u.intvalue)
2109  elif vtype == CFG_STRING:
2110  ret = str(self._Cstruct[0].u.strvalue)
2111  elif vtype == CFG_FLOAT:
2112  ret = float(self._Cstruct[0].u.floatvalue)
2113  elif vtype == CFG_CFGCTX:
2114  # We're creating a new reference to the pre-existing NetAddr
2115  CCref(self._Cstruct[0].u.cfgctxvalue)
2116  ret = pyConfigContext(Cstruct=self._Cstruct[0].u.cfgctxvalue)
2117  elif vtype == CFG_NETADDR:
2118  ret = pyNetAddr(None, Cstruct=self._Cstruct[0].u.addrvalue)
2119  # We're creating a new reference to the pre-existing NetAddr
2120  CCref(ret._Cstruct)
2121  elif vtype == CFG_FRAME:
2122  # Cstruct2Frame calls CCref() - so we don't need to
2123  ret = pyFrame.Cstruct2Frame(self._Cstruct[0].u.framevalue)
2124  elif vtype == CFG_ARRAY:
2125  # An Array is a linked list (GSList) of ConfigValue objects...
2126  ret = []
2127  this = self._Cstruct[0].u.arrayvalue
2128  while this:
2129  dataptr = cast(this[0].data, struct__GSList._fields_[0][1])
2130  dataptr = cast(dataptr, cClass.ConfigValue)
2131  CCref(dataptr)
2132  thisobj = pyConfigValue(cast(dataptr, cClass.ConfigValue)).get()
2133  ret.append(thisobj)
2134  this = g_slist_next(this)
2135  elif vtype == CFG_NULL:
2136  return None
2137  if ret is None:
2138  raise ValueError('Invalid valtype (%s)in pyConfigValue object' % self._Cstruct.valtype)
2139  return ret
2140 
2142  'A Network I/O object - with a variety of subclasses'
2143  CONN_NONE = 0 # FSPR_NONE -- Apparently ctypesgen doesn't do enum values...
2144  CONN_INIT = 1 # FSPR_INIT
2145  CONN_UP = 2 # FSPR_UP
2146  CONN_SHUT1 = 3 # FSPR_SHUT1
2147  CONN_SHUT2 = 4 # FSPR_SHUT2
2148  CONN_SHUT3 = 5 # FSPR_SHUT3
2149 
2150  def __init__(self, configobj, packetdecoder, Cstruct=None):
2151  'Initializer for pyNetIO'
2152  self._Cstruct = None # Keep error legs from complaining.
2153  if Cstruct is None:
2154  Cstruct = netio_new(0, configobj._Cstruct, packetdecoder._Cstruct)
2155  self.config = configobj
2156  else:
2157  self._Cstruct = Cstruct
2158  base = self._Cstruct[0]
2159  while (not hasattr(base, '_configinfo')):
2160  base = base.baseclass
2161  self.config = pyConfigContext(Cstruct=base._configinfo)
2162  CCref(base._configinfo)
2163  pyAssimObj.__init__(self, Cstruct=Cstruct)
2164 
2165  def setblockio(self, mode):
2166  'Set this NetIO object to blocking IO mode'
2167  base = self._Cstruct[0]
2168  while (not hasattr(base, 'setblockio')):
2169  base = base.baseclass
2170  return base.setblockio(self._Cstruct, int(mode))
2171 
2172  def fileno(self):
2173  'Return the file descriptor for this pyNetIO object'
2174  base = self._Cstruct[0]
2175  while (not hasattr(base, 'getfd')):
2176  base = base.baseclass
2177  return base.getfd(self._Cstruct)
2178 
2179  def bindaddr(self, addr, silent=False):
2180  'Bind the socket underneath this NetIO object to the given address'
2181  base = self._Cstruct[0]
2182  while (not hasattr(base, 'bindaddr')):
2183  base = base.baseclass
2184  return base.bindaddr(self._Cstruct, addr._Cstruct, silent)
2185 
2186  def boundaddr(self):
2187  'Return the socket underlying this NetIO object'
2188  base = self._Cstruct[0]
2189  while (not hasattr(base, 'bindaddr')):
2190  base = base.baseclass
2191  boundaddr = base.boundaddr(self._Cstruct)
2192  # We're creating a new reference to the pre-existing NetAddr
2193  ret = pyNetAddr(None, Cstruct=boundaddr)
2194  CCref(boundaddr)
2195  return ret
2196 
2197  def getrcvbufsize(self):
2198  'Return the receive buffer size for this socket'
2199  base = self._Cstruct[0]
2200  while (not hasattr(base, 'getsockbufsize')):
2201  base = base.baseclass
2202  return base.getsockbufsize(self._Cstruct, True)
2203 
2204  def setrcvbufsize(self, bufsize):
2205  'Set and return the receive buffer size for this socket'
2206  base = self._Cstruct[0]
2207  while (not hasattr(base, 'setsockbufsize')):
2208  base = base.baseclass
2209  return base.setsockbufsize(self._Cstruct, True, bufsize)
2210 
2211  def getsendbufsize(self):
2212  'Return the output buffer size for this socket'
2213  base = self._Cstruct[0]
2214  while (not hasattr(base, 'getsockbufsize')):
2215  base = base.baseclass
2216  return base.getsockbufsize(self._Cstruct, False)
2217 
2218  def setsendbufsize(self, bufsize):
2219  'Return the output buffer size for this socket'
2220  base = self._Cstruct[0]
2221  while (not hasattr(base, 'setsockbufsize')):
2222  base = base.baseclass
2223  return base.setsockbufsize(self._Cstruct, False, bufsize)
2224 
2225  def mcastjoin(self, addr):
2226  'Join the underlying socket to the given multicast address'
2227  base = self._Cstruct[0]
2228  while (not hasattr(base, 'mcastjoin')):
2229  base = base.baseclass
2230  return base.mcastjoin(self._Cstruct, addr._Cstruct, None)
2231 
2232  def getmaxpktsize(self):
2233  'Return the max packet size for this pyNetIO'
2234  base = self._Cstruct[0]
2235  while (not hasattr(base, 'getmaxpktsize')):
2236  base = base.baseclass
2237  return base.getmaxpktsize(self._Cstruct)
2238 
2239  def setmaxpktsize(self, size):
2240  'Set the max packet size for this pyNetIO'
2241  base = self._Cstruct[0]
2242  while (not hasattr(base, 'setmaxpktsize')):
2243  base = base.baseclass
2244  return base.setmaxpktsize(self._Cstruct, int(size))
2245 
2246  def compressframe(self):
2247  'Return the compression frame for this pyNetIO - may be None'
2248  # Doesn't make a py class object out of it yet...
2249  base = self._Cstruct[0]
2250  while (not hasattr(base, 'compressframe')):
2251  base = base.baseclass
2252  return base.compressframe(self._Cstruct)
2253 
2254  def signframe(self):
2255  'Return the digital signature frame for this pyNetIO'
2256  base = self._Cstruct[0]
2257  while (not hasattr(base, 'signframe')):
2258  base = base.baseclass
2259  return pySignFrame(0, Cstruct=cast(base.signframe(self._Cstruct), cClass.SignFrame))
2260 
2261  def connstate(self, peeraddr, qid=DEFAULT_FSP_QID):
2262  'Return the state of this connection - return value is one of the pyNetIO constants'
2263  fsproto = self._Cstruct[0]._protocol
2264  return fsproto[0].connstate(fsproto, qid, peeraddr._Cstruct)
2265 
2266  def connactive(self, peeraddr, qid=DEFAULT_FSP_QID):
2267  '''Return TRUE if this connection is active.
2268  That is, if it's established and not in shutdown.
2269  Note that the presence of timeouts doesn't make a connection inactive.
2270  We can time out for days and still think the connection is active.
2271  '''
2272  connstate = self.connstate(peeraddr, qid)
2273  return connstate == pyNetIO.CONN_INIT or connstate == pyNetIO.CONN_UP
2274 
2275  def sendframesets(self, destaddr, framesetlist):
2276  'Send the (collection of) frameset(s) out on this pyNetIO'
2277  if destaddr.port() == 0:
2278  raise ValueError("Zero Port in sendframesets: destaddr=%s" % str(destaddr))
2279  if not isinstance(framesetlist, collections.Sequence):
2280  framesetlist = (framesetlist, )
2281  base = self._Cstruct[0]
2282  while (not hasattr(base, 'sendaframeset')):
2283  base = base.baseclass
2284  # We ought to eventually construct a GSList of them and then call sendframesets
2285  # But this is easy for now...
2286  for frameset in framesetlist:
2287  base.sendaframeset(self._Cstruct, destaddr._Cstruct, frameset._Cstruct)
2288 
2289  def sendreliablefs(self, destaddr, framesetlist, qid=DEFAULT_FSP_QID):
2290  'Reliably send the (collection of) frameset(s) out on this pyNetIO (if possible)'
2291  if destaddr.port() == 0:
2292  raise ValueError("Zero Port in sendreliablefs: destaddr=%s" % str(destaddr))
2293  if not isinstance(framesetlist, collections.Sequence):
2294  framesetlist = (framesetlist, )
2295  base = self._Cstruct[0]
2296  while (not hasattr(base, 'sendaframeset')):
2297  base = base.baseclass
2298  for frameset in framesetlist:
2299  success = base.sendareliablefs(self._Cstruct, destaddr._Cstruct, qid, frameset._Cstruct)
2300  if not success:
2301  raise IOError("sendareliablefs(%s, %s) failed." % (destaddr, frameset))
2302 
2303  def ackmessage(self, destaddr, frameset):
2304  'ACK (acknowledge) this frameset - (presumably sent reliably).'
2305 
2306  base = self._Cstruct[0]
2307  while (not hasattr(base, 'ackmessage')):
2308  base = base.baseclass
2309  base.ackmessage(self._Cstruct, destaddr._Cstruct, frameset._Cstruct)
2310 
2311  def closeconn(self, qid, destaddr):
2312  'Close (reset) our connection to this address'
2313  base = self._Cstruct[0]
2314  while (not hasattr(base, 'closeconn')):
2315  base = base.baseclass
2316  print >> sys.stderr, ('RESETTING CONNECTION (closeconn) TO %s' % str(destaddr))
2317  base.closeconn(self._Cstruct, qid, destaddr._Cstruct)
2318 
2319  def addalias(self, fromaddr, toaddr):
2320  'Close (reset) our connection to this address'
2321 
2322  base = self._Cstruct[0]
2323  while (not hasattr(base, 'addalias')):
2324  base = base.baseclass
2325  base.addalias(self._Cstruct, fromaddr._Cstruct, toaddr._Cstruct)
2326 
2327  def recvframesets(self):
2328  '''Receive a collection of framesets read from this pyNetIO - all from the same Address.
2329  @return The return value is a tuple (address, framesetlist). '''
2330  #GSList * _netio_recvframesets (NetIO *self,NetAddr **src)
2331 
2332  base = self._Cstruct[0]
2333  while (not hasattr(base, 'recvframesets')):
2334  base = base.baseclass
2335  netaddrint = netaddr_ipv4_new(create_string_buffer(4), 101)
2336  netaddr = cast(netaddrint, cClass.NetAddr)
2337  netaddr[0].baseclass.unref(netaddr) # We're about to replace it...
2338  # Basically we needed a pointer to pass, and this seemed like a good way to do it...
2339  # Maybe it was -- maybe it wasn't... It's a pretty expensive way to get this effect...
2340  fs_gslistint = base.recvframesets(self._Cstruct, byref(netaddr))
2341  fslist = pyPacketDecoder.fslist_to_pyfs_array(fs_gslistint)
2342  if netaddr and len(fslist) > 0:
2343  # recvframesets gave us that 'netaddr' for us to dispose of - there are no other refs
2344  # to it so we should NOT 'CCref' it. It's a new object - not a pointer to an old one.
2345  address = pyNetAddr(None, Cstruct=netaddr)
2346  else:
2347  address = None
2348  return (address, fslist)
2349 
2350  @staticmethod
2352  'Return True if our OS supports a dual IPv4/IPv6 stack'
2354 
2356  'UDP version of the pyNetIO abstract base class'
2357  def __init__(self, config, packetdecoder, Cstruct=None):
2358  'Initializer for pyNetIOudp'
2359  self._Cstruct = None # Keep error legs from complaining.
2360  if Cstruct is None:
2361  Cstruct = netioudp_new(0, config._Cstruct, packetdecoder._Cstruct)
2362  if not Cstruct:
2363  raise ValueError("Invalid parameters to pyNetIOudp constructor")
2364  pyNetIO.__init__(self, config, packetdecoder, Cstruct=Cstruct)
2365 
2367  'Reliable UDP version of the pyNetIOudp abstract base class'
2368  def __init__(self, config, packetdecoder, rexmit_timer_uS=0, Cstruct=None):
2369  'Initializer for pyReliableUDP'
2370  self._Cstruct = None # Keep error legs from complaining.
2371  if Cstruct is None:
2372  Cstruct = reliableudp_new(0, config._Cstruct, packetdecoder._Cstruct, rexmit_timer_uS)
2373  if not Cstruct:
2374  raise ValueError("Invalid parameters to pyReliableUDP constructor")
2375  pyNetIOudp.__init__(self, config, packetdecoder, Cstruct=Cstruct)
2376 
2377  def log_conn(self, destaddr, qid=DEFAULT_FSP_QID):
2378  'Log connection status/info to system logs'
2379  base = self._Cstruct[0]
2380  while (not_this_exact_type(base, ReliableUDP)):
2381  base = base.baseclass
2382  base.log_conn(self._Cstruct, qid, destaddr._Cstruct)
2383 
2384 class CMAlib(object):
2385  'Miscellaneous functions to create certain useful pyFrameSets'
2386 
2387  def __init__(self):
2388  'Do-nothing init function'
2389  pass
2390 
2391  @staticmethod
2393  'Create a setconfig FrameSet'
2394  fs = cast(create_setconfig(cfg._Cstruct), cClass.FrameSet)
2395  return pyFrameSet(None, Cstruct=fs)
2396 
2397  @staticmethod
2398  def create_sendexpecthb(cfg, msgtype, address):
2399  'Create a Send/Expect heartbeat FrameSet'
2400  ucfs = create_sendexpecthb(cfg._Cstruct, int(msgtype)
2401  , address._Cstruct, 1)
2402  fs = cast(ucfs, cClass.FrameSet)
2403  return pyFrameSet(None, Cstruct=fs)
2404 
2405 class pyPcapCapture(object):
2406  'Class to read binary packets from pcap packet capture files'
2407  def __init__(self, filename):
2408  self._Cstruct = pcap_capture_iter_new(filename)
2409  if not self._Cstruct:
2410  raise ValueError('Invalid parameters to pyPcapCapture constructor')
2411  # I'm saving this here because for some unclear reason it goes to None...
2412  self.destructor = pcap_capture_iter_del
2413 
2414  def __del__(self):
2415  'Clean up our pcap capture file descriptor'
2416  if self._Cstruct:
2417  self.destructor(self._Cstruct)
2418  self._Cstruct = None
2419 
2420  def __iter__(self):
2421  pktlen = c_int()
2422  pktend = cClass.guint8()
2423  ret = pcap_capture_iter_next(self._Cstruct, byref(pktend), byref(pktlen))
2424  if not ret:
2425  self.destructor(self._Cstruct)
2426  self._Cstruct = None
2427  return
2428  yield (cast(ret, cClass.guint8), pktend, int(pktlen.value))
2429 
2431  'Dump out live objects to help locate memory leaks'
2432  print >> sys.stderr, 'GC Garbage: [%s]' % str(gc.garbage)
2433  print >> sys.stderr, '***************LOOKING FOR pyAssimObjs***********'
2434  get_referrers = True
2435  cobjcount = 0
2436  gc.collect()
2437  for obj in gc.get_objects():
2438  if isinstance(obj, (pyAssimObj, pyCstringFrame)):
2439  cobjcount += 1
2440  cobj = 'None'
2441  if hasattr(obj, '_Cstruct') and obj._Cstruct is not None:
2442  cobj = ('0x%x' % addressof(getattr(obj, '_Cstruct')[0]))
2443  print >> sys.stderr, ('FOUND C object class(%s): %s -> %s'
2444  % (obj.__class__.__name__, str(obj)[:512], cobj))
2445  if get_referrers:
2447 
2448  print >> sys.stderr, ('%d python wrappers referring to %d C-objects'
2449  % (cobjcount, proj_class_live_object_count()))
2451 
2452 def follow_referrer_back(obj, level=0, maxlevel=4):
2453  'Follow and print object referrer chains back through "maxlevel" levels'
2454  print >> sys.stderr, ('++++%sREFERRERS' % (level * '**'))
2455  for referrer in gc.get_referrers(obj):
2456  if isinstance(referrer, (list, types.FrameType)):
2457  continue
2458  print >> sys.stderr, ('++++%sReferred to by(%s): %s'
2459  % (level * '**', type(referrer), str(referrer)[:512]))
2460  if level < maxlevel:
2461  follow_referrer_back(referrer, level+1)
2462 
2463 if __name__ == '__main__':
2465  'Code to minimally exercise the pyPcapCapture class'
2466  for f in ('../pcap/cdp_v2.pcap', '../pcap/lldp.detailed.pcap'):
2467  print 'Capture file: %s' % f
2468  capture = pyPcapCapture(f)
2469  for results in capture:
2470  (pkt, pktend, pktlen) = results
2471  print 'Pkt', pkt, 'pktend', pktend, 'pktlen', pktlen
WINEXPORT gboolean cryptframe_set_dest_key_id(NetAddr *destaddr, const char *key_id)
Set the encryption key to use when sending to destaddr Set destkey to NULL to stop encrypting to that...
Definition: cryptframe.c:470
guint16 frameset_set_flags(FrameSet *fs, guint16 flagbits)
Set (OR in) the given set of FrameSet flags.
Definition: frameset.c:319
WINEXPORT const void * get_cdptlv_next(const void *tlv_vp, const void *tlv_vpend)
Locate the next CDP TLV triple (iterator).
Definition: cdp_min.c:271
void frameset_dump(const FrameSet *fs)
Dump out a FrameSet.
Definition: frameset.c:365
ConfigContext * configcontext_new_JSON_string(const char *jsontext)
Construct a ConfigContext object from the given JSON string.
WINEXPORT GList * cryptframe_get_key_ids(void)
Return a GList of strings of all known key ids.
Definition: cryptframe.c:397
WINEXPORT guint16 get_cdptlv_type(const void *tlv_vp, const void *pktend)
Return type from the given TLV triplet in a CDP packet.
Definition: cdp_min.c:196
WINEXPORT void cryptcurve25519_set_encryption_method(void)
Function just to make setting the encryption method simpler from Python.
SeqnoFrame * seqnoframe_new(guint16 frametype, int objsize)
Construct new SeqnoFrame object.
Definition: seqnoframe.c:211
WINEXPORT AddrFrame * addrframe_new(guint16 frame_type, gsize framesize)
Construct a new AddrFrame class - allowing for "derived" frame types...
Definition: addrframe.c:201
def setconfig(self, name, value)
guint16 frameset_get_flags(FrameSet *fs)
Return the flags currently set on this FrameSet.
Definition: frameset.c:311
CryptCurve25519 * cryptcurve25519_new(guint16 frame_type, const char *sender_key_id, const char *receiver_key_id, gboolean forsending, gsize objsize)
Construct a new CryptCurve25519 object (frame).
WINEXPORT char * cryptcurve25519_gen_persistent_keypair(const char *giveitaname)
Create a persistent keypair and write it to disk Returns a MALLOCed string with the key id for the ke...
guint16 frameset_clear_flags(FrameSet *fs, guint16 flagbits)
Clear the given set of FrameSet flags (& ~flagbits)
Definition: frameset.c:329
WINEXPORT gboolean is_valid_cdp_packet(const void *packet, const void *pktend)
Check to see if this is a valid CDP packet.
Definition: cdp_min.c:94
NetIOudp * netioudp_new(gsize objsize, ConfigContext *config, PacketDecoder *decoder)
Construct new UDP NetIO object (and its socket, etc)
Definition: netioudp.c:52
guint8 tlv_get_guint8(const void *vitem, const void *bufend)
Retrieve an unsigned 8 bit integer from the given location with error checking.
Definition: tlvhelper.c:31
WINEXPORT IpPortFrame * ipportframe_ipv6_new(guint16 frame_type, guint16 port, gconstpointer addr)
Construct and initialize an IPv6 IpPortFrame class.
Definition: ipportframe.c:217
def __setitem__(self, key, value)
WINEXPORT SignFrame * signframe_glib_new(GChecksumType sigtype, gsize framesize)
Construct a new SignFrame - allowing for "derived" frame types...
Definition: signframe.c:334
WINEXPORT IpPortFrame * ipportframe_netaddr_new(guint16 frame_type, NetAddr *addr)
Construct and initialize an IpPortFrame class from a IP NetAddr class.
Definition: ipportframe.c:234
guint64 tlv_get_guint64(const void *vitem, const void *bufend)
Retrieve an unsigned 64 bit integer from the given location with error checking and without caring ab...
Definition: tlvhelper.c:108
NetAddr * netaddr_dns_new(const char *sysname_or_addr)
Create a NetAddr from a DNS name or an ipv4 or ipv6 constant string.
Definition: netaddr.c:1004
IntFrame * intframe_new(guint16 frametype, int intbytes)
Construct new IntFrame object.
Definition: intframe.c:179
NetAddr * netaddr_mac64_new(gconstpointer macbuf)
Create new NetAddr from a MAC64 address.
Definition: netaddr.c:1078
def decode_discovery(host, interface, instance, wallclock, pktstart, pktend)
WINEXPORT gboolean cryptframe_associate_identity(const char *identity, const char *key_id)
Associate the given key id with the given identity Note that it is OK to associate multiple key ids w...
Definition: cryptframe.c:293
def fslist_from_pktdata(self, pktlocation)
FrameSet * frameset_new(guint16 frameset_type)
Construct a new frameset of the given type.
Definition: frameset.c:110
NetAddr * netaddr_ipv4_new(gconstpointer ipbuf, guint16 port)
Create new NetAddr from a IPv4 address.
Definition: netaddr.c:1085
WINEXPORT const char * frameset_sender_identity(const FrameSet *self)
Return the identity of this Frameset's CryptFrame sender – NULL if None or Unknown.
Definition: frameset.c:451
UnknownFrame * unknownframe_new(guint16 frame_type)
Construct a new UnknownFrame - disallowing for "derived" frame types...
Definition: unknownframe.c:55
WINEXPORT const void * get_cdptlv_first(const void *pkt, const void *pktend)
Return the first CDP TLV triple in a CDP packet.
Definition: cdp_min.c:240
PacketDecoder * packetdecoder_new(guint objsize, const FrameTypeToFrame *framemap, gint mapsize)
Initialize our frame type map.
Definition: packetdecoder.c:77
def setaddr(self, name, value)
WINEXPORT CryptFrame * cryptframe_new_by_destaddr(const NetAddr *destaddr)
Construct a CryptFrame class appropriate for encrypting messages to destaddr
Definition: cryptframe.c:488
NetAddr * netaddr_mac48_new(gconstpointer macbuf)
Create new NetAddr from a MAC48 address.
Definition: netaddr.c:1071
def setbool(self, name, value)
WINEXPORT const char * cryptframe_whois_key_id(const char *key_id)
Return the identity associated with the given key id.
Definition: cryptframe.c:371
WINEXPORT const char * cryptframe_get_dest_key_id(const NetAddr *destaddr)
Return the key_id associated with the given destination address.
Definition: cryptframe.c:504
def setint(self, name, value)
void frameset_append_frame(FrameSet *fs, Frame *f)
Append frame to the front of the end of the frame list.
Definition: frameset.c:143
guint8 get_lldptlv_type(const void *tlv_vp, const void *pktend)
Return the 'Type' of the given LLDP TLV entry The Type is the high order 7 bits from the zeroth byte ...
Definition: lldp_min.c:83
WINEXPORT gsize get_cdptlv_len(const void *tlv_vp, const void *pktend)
Return size of the given TLV triplet.
Definition: cdp_min.c:206
def associate_identity(identityname, key_id)
guint32 tlv_get_guint32(const void *vitem, const void *bufend)
Retrieve an unsigned 32 bit integer from the given location with error checking and without caring ab...
Definition: tlvhelper.c:81
Frame * frame_new(guint16 frame_type, gsize framesize)
Construct a new frame - allowing for "derived" frame types...
Definition: frame.c:125
def _init_from_binary(self, addrstring, port)
def setarray(self, name, value)
gboolean netio_is_dual_ipv4v6_stack(void)
Definition: netio.c:954
NetAddr * netaddr_ipv6_new(gconstpointer ipbuf, guint16 port)
Create new NetAddr from a IPv6 address.
Definition: netaddr.c:1093
def setvalue(self, value)
FSTATIC CryptFramePrivateKey * cryptframe_private_key_by_id(const char *key_id)
Return the non-const private key with the given id.
Definition: cryptframe.c:279
guint32 tlv_get_guint24(const void *vitem, const void *bufend)
Retrieve an unsigned 24 bit (3-byte) integer from the given location with error checking and without ...
Definition: tlvhelper.c:133
def setsendbufsize(self, bufsize)
def getcdpaddresses(tlvlen, tlvstart, pktend)
WINEXPORT char * curve25519_key_id_to_filename(const char *key_id, enum keytype ktype)
WINEXPORT struct pcap_capture_iter * pcap_capture_iter_new(const char *capture_filename)
Definition: pcap_min.c:254
guint32 proj_class_live_object_count(void)
Return the count of live C class objects.
Definition: proj_classes.c:406
WINEXPORT const char * frameset_sender_key_id(const FrameSet *self)
Return the key_id of this Frameset's CryptFrame sender – NULL if None.
Definition: frameset.c:434
def __setitem__(self, name, value)
def ackmessage(self, destaddr, frameset)
def dest_set_key_id(destaddr, key_id)
def key_id_to_filename(key_id, keytype)
ReliableUDP * reliableudp_new(gsize objsize, ConfigContext *config, PacketDecoder *decoder, guint rexmit_timer_uS)
Construct new UDP NetIO object (and its socket, etc)
Definition: reliableudp.c:69
def setblockio(self, mode)
AssimObj * assimobj_new(guint objsize)
Definition: assimobj.c:74
const char * proj_class_classname(gconstpointer object)
Return the class name of one of our managed objects.
Definition: proj_classes.c:324
NVpairFrame * nvpairframe_new(guint16 frame_type, gchar *name, gchar *value, gsize framesize)
Construct a new NVpairFrame - allowing for "derived" frame types...
Definition: nvpairframe.c:101
const void * get_lldptlv_first(const void *packet, const void *pktend)
Definition: lldp_min.c:195
def getNint(tlvptr, tlvlen, pktend)
def setfloat(self, name, value)
void frameset_prepend_frame(FrameSet *fs, Frame *f)
Prepend frame to the front of the frame list.
Definition: frameset.c:132
def closeconn(self, qid, destaddr)
#define MALLOC(nbytes)
should it just call g_malloc?
Definition: projectcommon.h:26
def sendframesets(self, destaddr, framesetlist)
void frameset_construct_packet(FrameSet *fs, SignFrame *sigframe, CryptFrame *cryptframe, CompressFrame *compressframe)
Construct packet to go correspond to this frameset.
Definition: frameset.c:159
def _init_from_binary(self, frametype, addrstring, port)
WINEXPORT const void * get_cdptlv_body(const void *tlv_vp, const void *pktend)
Return the body (value) blob of a CDP TLV triplet.
Definition: cdp_min.c:229
gboolean is_valid_lldp_packet(const void *tlv_vp, const void *pktend)
Definition: lldp_min.c:116
WINEXPORT IpPortFrame * ipportframe_ipv4_new(guint16 frame_type, guint16 port, gconstpointer addr)
Construct and initialize an IPv4 IpPortFrame class.
Definition: ipportframe.c:199
def addalias(self, fromaddr, toaddr)
NetIO * netio_new(gsize objsize, ConfigContext *config, PacketDecoder *decoder)
NetIO constructor.
Definition: netio.c:488
def not_this_exact_type(obj, cls)
def dump(self, prefix)
def create_sendexpecthb(cfg, msgtype, address)
WINEXPORT void cryptframe_set_signing_key_id(const char *key_id)
Set the default signing key.
Definition: cryptframe.c:416
const void * get_lldptlv_next(const void *tlv_vp, const void *pktend)
Return pointer to the next LLDP TLV entry after the current location.
Definition: lldp_min.c:209
gsize get_lldptlv_len(const void *tlv_vp, const void *pktend)
Return the 'Length' of the given LLDP TLV entry.
Definition: lldp_min.c:93
void proj_class_dump_live_objects(void)
Dump all live C class objects (address and Class)
Definition: proj_classes.c:356
ConfigContext * configcontext_new(gsize objsize)
Construct a new ConfigContext object - with no values defaulted.
CompressFrame * compressframe_new_string(guint16 frame_type, const char *compression_name)
def setframe(self, name, value)
def setmaxpktsize(self, size)
WINEXPORT void cryptcurve25519_cache_all_keypairs(void)
We read in and cache all the key pairs (or public keys) that we find in CRYPTKEYDIR.
def setrcvbufsize(self, bufsize)
guint16 tlv_get_guint16(const void *vitem, const void *bufend)
Retrieve an unsigned 16 bit integer from the given location with error checking and without caring ab...
Definition: tlvhelper.c:55
WINEXPORT const guint8 * pcap_capture_iter_next(struct pcap_capture_iter *iter, const guint8 **pktend, guint *pktlen)
Definition: pcap_min.c:285
def setstring(self, name, value)
WINEXPORT CstringFrame * cstringframe_new(guint16 frame_type, gsize framesize)
Construct a new CstringFrame - allowing for "derived" frame types...
Definition: cstringframe.c:101
const void * get_lldptlv_body(const void *tlv_vp, const void *pktend)
Return the 'Value' of the given LLDP TLV entry.
Definition: lldp_min.c:106