The Assimilation Project
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
frameinfo.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 '''
3 A collection of classes which provide constants for FrameTypes and FrameSetTypes
4 '''
5 
6 import re
7 #from AssimCclasses import pyFrame, pyAddrFrame, pySignFrame, pySeqnoFrame, \
8 # pyIntFrame, pyCstringFrame, pyNVpairFrame, pyIpPortFrame
9 
10 #pylint: disable=R0903
11 
12 class pyFrame(object):
13  'Placeholder bootstrapping class'
14  def __init__(self):
15  pass
16 
17 class pyAddrFrame(object):
18  'Placeholder bootstrapping class'
19  def __init__(self):
20  pass
21 
22 class pySignFrame(object):
23  'Placeholder bootstrapping class'
24  def __init__(self):
25  pass
26 
27 class pySeqnoFrame(object):
28  'Placeholder bootstrapping class'
29  def __init__(self):
30  pass
31 
32 class pyIntFrame(object):
33  'Placeholder bootstrapping class'
34  def __init__(self):
35  pass
36 
37 class pyCstringFrame(object):
38  'Placeholder bootstrapping class'
39  def __init__(self):
40  pass
41 
42 class pyNVpairFrame(object):
43  'Placeholder bootstrapping class'
44  def __init__(self):
45  pass
46 
47 class pyIpPortFrame(object):
48  'Placeholder bootstrapping class'
49  def __init__(self):
50  pass
51 
52 class pyCryptFrame(object):
53  'Placeholder bootstrapping class'
54  def __init__(self):
55  pass
56 
57 class pyCompressFrame(object):
58  'Placeholder class'
59  def __init__(self):
60  pass
61 
62 class pyCryptCurve25519(pyCryptFrame):
63  'Placeholder class'
64  def __init__(self):
65  pyCryptFrame.__init__(self)
66 
67 class FrameTypes(object):
68  'Class defining the universe of FrameSets - including code to generate a C header file'
69  fileheader = \
70 '''
71 /**
72  * @file
73  * @brief Header file defining the data layouts for our Frames.
74  * THIS FILE MECHANICALLY GENERATED by "%s". DO NOT EDIT.
75  *
76  *
77  * This file is part of the Assimilation Project.
78  *
79  * @author Copyright &copy; 2011, 2012 - Alan Robertson <alanr@unix.sh>
80  * @n
81  * The Assimilation software is free software: you can redistribute it and/or modify
82  * it under the terms of the GNU General Public License as published by
83  * the Free Software Foundation, either version 3 of the License, or
84  * (at your option) any later version.
85  *
86  * The Assimilation software is distributed in the hope that it will be useful,
87  * but WITHOUT ANY WARRANTY; without even the implied warranty of
88  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
89  * GNU General Public License for more details.
90  *
91  * You should have received a copy of the GNU General Public License
92  * along with the Assimilation Project software. If not, see http://www.gnu.org/licenses/
93  */
94 /**
95 @addtogroup FrameFormats
96 @{
97  Below is the set of frame formats and corresponding macro definitions
98  This section will document the format of the individual frame types.
99  The first frame in a frameset must be a signature frame.
100  If an encryption frame is present, it must be the frame in the frameset.
101  If a compression frame is present, it must occur after the encryption frame
102  if present, or after the signature frame, if there is no encryption frame.
103 
104  The final frame in a frameset must be an End frame (which will be
105  added automatically by the @ref FrameSet marshalling classes).
106 @}
107 */
108 /**
109 @defgroup IndividualFrameFormats Individual TLV 'Frame' data types and layouts (by TLV type)
110 @{
111 Below is the set of individual frame types and data layouts - organized by TLV type.
112 Note that a given @ref Frame subclass can appear be associated with many different TLV types.
113 This file organizes this data by the TLV type, not by the underlying @ref Frame subclass.
114 @ingroup FrameFormats
115 @ingroup DefineEnums
116 @{
117 */
118 '''
119  asciiart = {
120  'pyFrame':
121 '''
122 +----------------+-----------+------------------+
123 | frametype = %2d | f_length | frame data |
124 | (16 bits) | (24-bits) | (f_length bytes) |
125 +----------------+-----------+------------------+
126 ''',
127  'pySignFrame':
128 '''
129 +----------------+-----------+-----------------+------------+-------------------+
130 | | | major | | |
131 | frametype = %2d | f_length | signature-type | minor type | digital signature |
132 | (16 bits) | (24-bits) | (8 bits) | (8 bits) |(f_length-2 bytes) |
133 +----------------+-----------+-----------------+------------+-------------------+
134 ''',
135  'pyCompressFrame':
136 '''
137 +----------------+-----------+------------------------+
138 | frametype = %2d | f_length | compressed frames |
139 | (16 bits) | (24-bits) | (f_length bytes) |
140 +----------------+-----------+------------------------+
141 ''',
142  'pySeqnoFrame':
143 '''
144 +----------------+---------------+-------------+-----------+
145 | frametype = %2d | f_length = 8 | reply id | queue id |
146 | (16 bits) | (24-bits) | (8 bytes) | (2 bytes) |
147 +----------------+---------------+-------------+-----------+
148 ''',
149 
150  'pyIntFrame':
151 '''
152 +----------------+--------------+-------------------------+
153 | frametype = %2d | f_length = | integer value |
154 | | 1,2,3,4 or 8 | value |
155 | (16 bits) | (24-bits) | (1,2,3,4,or 8 bytes) |
156 +----------------+--------------+-------------------------+
157 ''',
158  'pyCstringFrame':
159 '''
160 +----------------+----------------+----------------+--------+
161 | frametype = %2d | f_length = 'n' | interface name | 0x00 |
162 | (16 bits) | (24-bits) | (n-1 bytes) | 1 byte |
163 +----------------+----------------+----------------+--------+
164 ''',
165  'pyAddrFrame':
166 '''
167 +----------------+----------------+---------------+--------------+
168 | frametype = %2d | f_length = n | Address Type | address |
169 | (16 bits) | (24-bits) | 2 bytes | (n-2 bytes) |
170 +----------------+----------------+---------------+--------------+
171 ''',
172  'pyIpPortFrame':
173 '''
174 +----------------+----------------+-------------+--------------+---------------+
175 | frametype = %2d | f_length = n | Port Number | Address Type | address |
176 | (16 bits) | (24-bits) | 2 bytes | 2 bytes | (n-4 bytes) |
177 +----------------+----------------+-------------+--------------+---------------+
178 ''',
179  'pyNVpairFrame':
180 '''
181 +----------------+---------------+--------+-----------------+-------+------+
182 | frametype = %2d | f_length = n | nm_len | name | NUL | | NUL |
183 | (16 bits) | (24-bits) | 1 byte | nm_len-1 | byte | value | byte |
184 | | |(8 bits)| bytes | | | |
185 +----------------+---------------+--------+-----------------+-------+------+
186 ''',
187  'pyCryptCurve25519':
188 # pylint: disable=C0301
189 '''
190 +----------------+---------------+---------+----------+----------+----------+-----------------------+---------------------+------------+
191 | | | sender | sender | receiver | receiver | | | |
192 | frametype = %2d | f_length = n | key_id | key id | key name | key id | crypto_box_NONCEBYTES | crypto_box_MACBYTES | cyphertext |
193 | (16 bits) | (24-bits) | length | | length | | (randomeness - nonce) | MAC for cyphertext | -- |
194 | | | |("length" | |("length" | | | originally |
195 | | | (1 byte)| bytes) | (1 byte) | bytes) | | | many frames|
196 +----------------+---------------+---------+----------+----------+----------+-----------------------+---------------------+------------+
197  |<---------------------------- length() value in memory -------------------------------->|
198  |<------------------------------- TLV length on the wire -------------------------------------------->|
199 For the sender: the sender key is private, and the receiver key is public
200 For the receiver: the sender key is public, and the receiver key is private
201 '''
202 
203 }
204  intframetypes = {
205  0: (pyFrame, 'END', 'Final frame in a message',
206 '''The last frame in a frameset is required to be an End frame.
207 End frames are of type zero and <b>always</b> have length zero.
208 Its corresponding class is @ref Frame.
209 This is the most basic Frame type, and is the only frame type that permits a length of zero.
210 '''),
211  1: (pySignFrame, 'SIG', 'Digital signature frame',
212 '''The signature frame is mandatory and must be the first
213 frame in the frameset - and must have frametype <b>1</b>.
214 The digital signature computed in the digital signature field is computed
215 on all the bytes in the frameset beginning with the first byte after
216 the end of this frame, extending through and including the last byte of the frameset.
217 Note that this will include the encryption frame if present.
218 The format and length of the digital signature depends on the type of signature.
219 '''),
220  2: (pyCryptCurve25519, 'CRYPTCURVE25519', '@ref CryptCurve25519 Encryption frame',
221 '''If an encryption frame is present it must be the second
222 frame in the frameset, and can only be preceded by a @ref FRAMETYPE_SIG frame.
223 When this frame is present, then all the frames following
224 are encrypted according information in the encryption information value segment.
225 '''),
226  3: (pyCompressFrame, 'COMPRESS', 'Compression frame',
227 '''If a compression frame is present (<b>frametype = 3</b>) it must be the second
228 or third frame in the frameset, and can only be preceded by a @ref FRAMETYPE_SIG
229 and encryption frames.
230 When this frame is present, then all the frames following
231 are compreseed according information in the compression information value segment.
232 The format of the compression information value segment will likely be a
233 single integer saying which compression method was used.
234 '''),
235  4: (pySeqnoFrame, 'REQID', 'Request ID - a message sequence number.',
236 '''Requests from the central authority are identified by a request id
237 (basically a sequence number) and a queue id. The combination of the two
238 is unique over a relatively long period of time - at least days.
239 Notifications from clients are sent with queue id 0, which will never be
240 used by the central authority.
241 '''),
242  6: (pyFrame, 'PKTDATA', 'Encapsulated packet data',
243 '''This frame format is normally used for a CDP or LLDP packet.
244 The data is kept exactly as it was received from the
245 network interface via libpcap.
246 '''),
247  7: (pyIntFrame, 'WALLCLOCK', '64-bit local time',
248 '''This frame provides local time on the sending system as gotten from the
249 g_get_real_time() call - which is a 64-bit time measured in microseconds.
250 In spite of the apparent variability permitted above, it is an 8-byte (64-bit) integer.
251 '''),
252  8: (pyCstringFrame, 'INTERFACE', 'Name of network interface as a C-style string',
253 '''This frame provides the name of a network interface as a
254 NUL-terminated C-style string.
255 '''),
256  9: (pyCstringFrame, 'HOSTNAME', 'Name of host as a C-style string',
257 '''This frame provides the name of a host as a NUL-terminated C-style string.
258 '''),
259  10: (pyAddrFrame, 'IPADDR', 'IP address in either IPv4 or IPv6 format.',
260 '''IPv4 addresses are address type 1 and are 4 bytes long.
261 IPv6 addresses are address type 2 and are 16 bytes long,
262 and have Address types 1 and 2 respectively.
263 '''),
264  11: (pyAddrFrame, 'MACADDR', 'MAC Address.',
265 '''This frame can be either a 6 byte (EUI-48) or an 8 byte (EUI-64) format MAC address.
266 The Address Type for a MAC address is 6.
267 '''),
268  12: (pyIntFrame, 'PORTNUM', 'Port number.',
269 '''This frame is a 16-bit IP port number.
270 '''),
271  13: (pyIpPortFrame, 'IPPORT', 'IP w/Port.',
272 '''This frame is a 16-bit IP port number along with an IPv4 or IPv6 address.
273 '''),
274  14: (pyIntFrame, 'HBINTERVAL', 'Heartbeat interval.',
275 '''This frame is a heartbeat sending interval measured in seconds.
276 '''),
277  15: (pyIntFrame, 'HBDEADTIME', 'Heartbeat deadtime.',
278 '''This frame is a heartbeat deadtime measured in seconds.
279 '''),
280  16: (pyIntFrame, 'HBWARNTIME', 'Heartbeat warntime.',
281 '''This frame is a heartbeat warning time measured in seconds.
282 '''),
283  17: (pyCstringFrame, 'PATHNAME', 'file name',
284 '''This frame contains a pathname for a file as a C string.
285 '''),
286  19: (pyCstringFrame, 'JSDISCOVER', 'JSON-formatted discovery data',
287 '''This frame contains JSON-formatted output from a discovery process.
288 The type of discovery data and program collecting it are inside.
289 '''),
290  20: (pyCstringFrame, 'CONFIGJSON', 'JSON configuration data from CMA',
291 'This frame provides the JSON for initial configuration data as a NUL-terminated C-style string.'),
292  21: (pyCstringFrame, 'CSTRINGVAL', 'Generic string value',
293 'Miscellaneous NUL-terminated C-style string.'),
294  22: (pyIntFrame, 'CINTVAL', 'Generic integer value',
295 'Miscellaneous integer value.'),
296  23: (pyIntFrame, 'ELAPSEDTIME', '64-bit elapsed time (usec)',
297 '''This frame provides elapsed time (measured locally) in microseconds.
298 In spite of the apparent variability permitted, it is an 8-byte (64-bit) integer.
299 '''),
300  24: (pyCstringFrame, 'DISCNAME', 'name of this discovery action',
301 '''This frame is a name to give this instance of a discovery action.
302 '''),
303  25: (pyIntFrame, 'DISCINTERVAL', 'Discovery interval',
304 '''This frame is a discovery repeat interval measured in seconds as an @ref IntFrame.
305 '''),
306  26: (pyCstringFrame, 'DISCJSON', 'Discovery JSON string',
307 '''This frame provides the data describing the discovery action in detail.
308  It must be preceded by a FRAMETYPE_DISCNAME.
309 '''),
310  27: (pyCstringFrame, 'RSCJSON', 'JSON resource string',
311 '''This frame provides the data describing the a resource action or cancel operation in detail.
312 '''),
313  28: (pyCstringFrame, 'RSCJSONREPLY', 'JSON operation result',
314 '''This frame provides the data describing the result of a resource action in detail.
315 '''),
316  29: (pyCstringFrame, 'KEYID', 'Key ID',
317 '''This frame provides the name of a Key ID as a C-style string.
318 '''),
319  30: (pyFrame, 'PUBKEYCURVE25519', 'A Curve25519 Public Key',
320 '''This frame provides the raw bytes of a Curve25519 Public Key.
321 It is always <b>crypto_box_PUBLICKEYBYTES</b> bytes long - no more, no less.
322 '''),
323 
324  }
325  strframetypes = dict()
326  for i in intframetypes.keys():
327  data = intframetypes[i]
328  key = data[1]
329  strframetypes[key] = (i, data[0], key, data[1], data[2])
330 
331  def __init__(self):
332  pass
333  @staticmethod
334  def get(key):
335  'Return the tuple that corresponds to this key (integer or string)'
336  if type(key) is str:
337  return FrameTypes.strframetypes[key]
338  else:
339  if FrameTypes.intframetypes.has_key(int(key)):
340  return FrameTypes.intframetypes[int(key)]
341  return (None, str(key), str(key), str(key))
342 
343  @classmethod
344  def c_defines(cls, f):
345  'Generate C #defines from our data'
346  l = FrameTypes.intframetypes.keys()
347  l.sort()
348  f.write(FrameTypes.fileheader % __file__)
349  # Create pretty ASCII art pictures and #defines of all our different packet formats
350  for i in l:
351  ourtuple = FrameTypes.intframetypes[i]
352  pyclass = ourtuple[0].__name__
353  frametype = i
354  framename = ourtuple[1]
355  #framedesc = ourtuple[1]
356  frametext = ourtuple[3]
357  Cclassname = re.sub('^py', '', pyclass)
358  f.write('/**\n FRAMETYPE_%s Frame (<b>frametype %d</b>)'
359  ' Frame subclass - @ref %s\n' % (framename, frametype, Cclassname))
360  f.write('<PRE>%s</PRE>\n%s\n */\n' % ((FrameTypes.asciiart[pyclass] % i), frametext))
361  f.write('#define FRAMETYPE_%s\t%d\t///< %s: @ref %s\n'
362  % (ourtuple[1], i, ourtuple[2], Cclassname))
363  f.write('///@}\n')
364  f.write('///@}\n')
365 
366  # Create the frame type map - mapping frame types to function names in the 'C' code.
367  f.write('#define FRAMETYPEMAP {\t\t\t\t\t\\\n')
368  for i in l:
369  tup = FrameTypes.intframetypes[i]
370  clsname = tup[0].__name__
371  Cclassname = re.sub('^py', '', clsname) + '_tlvconstructor'
372  Cfuncname = Cclassname.lower()
373  f.write(' {FRAMETYPE_%s,\t/*%d*/ %s}, \\\n' % (tup[1], i, Cfuncname))
374  f.write('}\n')
375 # Create conventional class.DEFINENAME attributes
376 for s in FrameTypes.strframetypes.keys():
377  setattr(FrameTypes, s, FrameTypes.strframetypes[s][0])
378 
379 class FrameSetTypes(object):
380  'Class defining the universe of FrameSets - including code to generate a C header file'
381  _fileheader = \
382 '''#ifndef _FRAMESETTYPES_H
383 #define _FRAMESETTYPES_H
384 /**
385  * @file
386  * @brief Header file defining all known FrameSet types
387  * THIS FILE MECHANICALLY GENERATED by "%s". DO NOT EDIT.
388  *
389  * This file is part of the Assimilation Project.
390  *
391  * @author Copyright &copy; 2011, 2012 - Alan Robertson <alanr@unix.sh>
392  * @n
393  * The Assimilation software is free software: you can redistribute it and/or modify
394  * it under the terms of the GNU General Public License as published by
395  * the Free Software Foundation, either version 3 of the License, or
396  * (at your option) any later version.
397  *
398  * The Assimilation software is distributed in the hope that it will be useful,
399  * but WITHOUT ANY WARRANTY; without even the implied warranty of
400  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
401  * GNU General Public License for more details.
402  *
403  * You should have received a copy of the GNU General Public License
404  * along with the Assimilation Project software. If not, see http://www.gnu.org/licenses/
405  */
406 
407 /**
408  * @defgroup FrameSetTypes FrameSet Types
409  *
410  * @{
411  * @ingroup DefineEnums
412  */
413 '''
414  strframetypes = {
415  # nanoprobe peer-peer FrameSets
416  'HEARTBEAT': (1, 'A heartbeat packet'),
417  'PING': (2, 'Are you alive? (can also come from the CMA)'),
418  'PONG': (3, 'I am alive (can also go to the CMA)'),
419  # nanoprobe FrameSets sent to collective management authority
420  'ACK': (16, 'Frame referred to has been acted on. (can also come from the CMA)'),
421  'CONNSHUT': (17, 'Shutting down this connection (can also come from CMA)'),
422  'CONNNAK': (18, 'Ignoring your connection start request (can also come from CMA)'),
423 
424  'STARTUP': (25, 'System originating packet looking for heartbeat configuration.'),
425  'HBDEAD': (26, 'System named in packet appears to be dead.'),
426  'HBSHUTDOWN': (27, 'System originating packet has shut down.'),
427  'HBLATE': (28, 'System named in packet sent a late heartbeat.'),
428  'HBBACKALIVE': (29, 'System named in packet sent heartbeat after being marked dead.'),
429  'HBMARTIAN': (30, 'System named in packet appears gave unexpected heartbeat.'),
430  'SWDISCOVER': (31, 'Packet encapsulates switch discovery packet'),
431  'JSDISCOVERY': (32, 'Packet contains JSON-formatted discovery data'),
432  'RSCOPREPLY': (33, 'Packet contains return result from a resource operation'),
433  # 'Privileged' FrameSets sent from the CMA to nanoprobes
434  'SENDHB': (64, 'Send Heartbeats to these addresses'),
435  'EXPECTHB': (65, 'Expect (listen for) Heartbeats from these addresses'),
436  'SENDEXPECTHB': (66, 'Send Heartbeats to these addresses, and expect them as well.'),
437  'STOPSENDHB': (67, 'Stop sending Heartbeats to these addresses'),
438  'STOPEXPECTHB': (68, 'Stop expecting (listening for) Heartbeats from these addresses'),
439  'STOPSENDEXPECTHB':(69, 'Stop sending Heartbeats to these addresses'
440  ', and stop expecting them as well.'),
441  'SETCONFIG': (70, 'Initial configuration packet'),
442  'INCRDEBUG': (71, 'Increment debug for some or all classes'),
443  'DECRDEBUG': (72, 'Increment debug for some or all classes'),
444  'DODISCOVER': (73, 'Perform (repeating) JSON discovery action'),
445  'STOPDISCOVER': (74, 'Stop a repeating JSON discovery action'),
446  'DORSCOP': (75, 'Do a (possibly-repeating) JSON resource action'),
447  'STOPRSCOP': (76, 'Stop a (possibly-repeating) JSON resource action'),
448  'RUNSCRIPT': (76, 'Run an arbitrary script (not yet implemented)'),
449  }
450  intframetypes = dict()
451  for s in strframetypes.keys():
452  i = strframetypes[s][0]
453  intframetypes[i] = (s, strframetypes[s][1])
454 
455  def __init__(self):
456  pass
457 
458  @staticmethod
459  def get(key):
460  'Return the tuple that corresponds to this key (integer or string)'
461  if type(key) is str:
462  return FrameSetTypes.strframetypes[key]
463  else:
464  if FrameSetTypes.intframetypes.has_key(int(key)):
465  return FrameSetTypes.intframetypes[int(key)]
466  return (None, str(int(key)), str(int(key)), str(int(key)))
467 
468  @classmethod
469  def c_defines(cls, f):
470  'Print out the C #defines that go with this set of definitions'
471  f.write(FrameSetTypes._fileheader % __file__)
472  l = FrameSetTypes.intframetypes.keys()
473  l.sort()
474  for i in l:
475  ourtuple = FrameSetTypes.intframetypes[i]
476  f.write('#define FRAMESETTYPE_%s\t%d\t///< %s\n' % (ourtuple[0], i, ourtuple[1]))
477  f.write('///@}\n')
478  # Don't currently want this map - probably not needed (or even a good idea...)
479  #f.write('\n#define FRAMESETTYPEMAP {\t\t\t\t\t\t\\\n')
480  #for i in l:
481  #tup = FrameSetTypes.intframetypes[i]
482  #Cobjname = "frameset_listener_" + tup[0].lower()
483  #f.write(' {FRAMESETTYPE_%s,\t/*%d*/ %s}, \\\n' % (tup[0], i, Cobjname))
484  #f.write('}\n')
485 
486  f.write('#endif /* _FRAMESETTYPES_H */\n')
487 
488 # Create conventional class.DEFINENAME attributes
489 for s in FrameSetTypes.strframetypes.keys():
490  setattr(FrameSetTypes, s, FrameSetTypes.strframetypes[s][0])
491 
492 
493 if __name__ == "__main__":
494  import sys
495  if len(sys.argv) != 3 \
496  or ( sys.argv[1] != "frametypes" and sys.argv[1] != "framesettypes"):
497  sys.stderr.write("Usage: python %s (frametypes|framesettypes) output-filename\n"
498  % sys.argv[0])
499  raise SystemExit(1)
500  fvar = open(sys.argv[2], 'w')
501  if sys.argv[1] == "frametypes":
502  FrameTypes.c_defines(fvar)
503  sys.exit(0)
504  elif sys.argv[1] == "framesettypes":
505  FrameSetTypes.c_defines(fvar)
506  sys.exit(0)
507  raise SystemExit(1)