[tor-commits] [stem/master] Cell attribute for unused padding

atagar at torproject.org atagar at torproject.org
Mon Jun 18 20:10:28 UTC 2018


commit 84e4e657b4785e4888e567fbc04c8ea29fd43cc4
Author: Damian Johnson <atagar at torproject.org>
Date:   Mon Jun 18 13:02:47 2018 -0700

    Cell attribute for unused padding
    
    I love our prior commit's effort to be more explicit when Cell data is
    explicitly ignored. Rather than a commment making this an 'unused' attribute of
    the base Cell class. This way our callers will have all the information
    necessary to reconstruct cells if they so desire.
---
 stem/client/cell.py      | 67 ++++++++++++++++++++++++++++++++++--------------
 test/unit/client/cell.py |  6 +++++
 2 files changed, 54 insertions(+), 19 deletions(-)

diff --git a/stem/client/cell.py b/stem/client/cell.py
index 1b30db6c..788c4c41 100644
--- a/stem/client/cell.py
+++ b/stem/client/cell.py
@@ -75,12 +75,18 @@ STREAM_ID_DISALLOWED = (
 class Cell(object):
   """
   Metadata for ORPort cells.
+
+  :var bytes unused: unused filler that padded the cell to the expected size
   """
 
   NAME = 'UNKNOWN'
   VALUE = -1
   IS_FIXED_SIZE = False
 
+  def __init__(self, unused = b''):
+    super(Cell, self).__init__()
+    self.unused = unused
+
   @staticmethod
   def by_name(name):
     """
@@ -240,7 +246,8 @@ class CircuitCell(Cell):
   :var int circ_id: circuit id
   """
 
-  def __init__(self, circ_id):
+  def __init__(self, circ_id, unused = b''):
+    super(CircuitCell, self).__init__(unused)
     self.circ_id = circ_id
 
 
@@ -261,6 +268,7 @@ class PaddingCell(Cell):
     elif len(payload) != FIXED_PAYLOAD_LEN:
       raise ValueError('Padding payload should be %i bytes, but was %i' % (FIXED_PAYLOAD_LEN, len(payload)))
 
+    super(PaddingCell, self).__init__()
     self.payload = payload
 
   def pack(self, link_protocol):
@@ -279,12 +287,18 @@ class CreateCell(CircuitCell):
   VALUE = 1
   IS_FIXED_SIZE = True
 
+  def __init__(self):
+    super(CreateCell, self).__init__()  # TODO: implement
+
 
 class CreatedCell(CircuitCell):
   NAME = 'CREATED'
   VALUE = 2
   IS_FIXED_SIZE = True
 
+  def __init__(self):
+    super(CreatedCell, self).__init__()  # TODO: implement
+
 
 class RelayCell(CircuitCell):
   """
@@ -302,7 +316,7 @@ class RelayCell(CircuitCell):
   VALUE = 3
   IS_FIXED_SIZE = True
 
-  def __init__(self, circ_id, command, data, digest = 0, stream_id = 0, recognized = 0):
+  def __init__(self, circ_id, command, data, digest = 0, stream_id = 0, recognized = 0, unused = b''):
     if 'HASH' in str(type(digest)):
       # Unfortunately hashlib generates from a dynamic private class so
       # isinstance() isn't such a great option. With python2/python3 the
@@ -316,7 +330,7 @@ class RelayCell(CircuitCell):
     else:
       raise ValueError('RELAY cell digest must be a hash, string, or int but was a %s' % type(digest).__name__)
 
-    super(RelayCell, self).__init__(circ_id)
+    super(RelayCell, self).__init__(circ_id, unused)
     self.command, self.command_int = RelayCommand.get(command)
     self.data = str_tools._to_bytes(data)
     self.recognized = recognized
@@ -347,11 +361,9 @@ class RelayCell(CircuitCell):
     stream_id, content = Size.SHORT.pop(content)
     digest, content = Size.LONG.pop(content)
     data_len, content = Size.SHORT.pop(content)
-    data, _ = split(content, data_len)
+    data, unused = split(content, data_len)
 
-    # remaining content (if any) is thrown out (ignored)
-
-    return RelayCell(circ_id, command, data, digest, stream_id, recognized)
+    return RelayCell(circ_id, command, data, digest, stream_id, recognized, unused)
 
   def __hash__(self):
     return _hash_attr(self, 'command_int', 'stream_id', 'digest', 'data')
@@ -481,6 +493,7 @@ class VersionsCell(Cell):
   IS_FIXED_SIZE = False
 
   def __init__(self, versions):
+    super(VersionsCell, self).__init__()
     self.versions = versions
 
   def pack(self, link_protocol = None):
@@ -517,7 +530,8 @@ class NetinfoCell(Cell):
   VALUE = 8
   IS_FIXED_SIZE = True
 
-  def __init__(self, receiver_address, sender_addresses, timestamp = None):
+  def __init__(self, receiver_address, sender_addresses, timestamp = None, unused = b''):
+    super(NetinfoCell, self).__init__(unused)
     self.timestamp = timestamp if timestamp else datetime.datetime.now()
     self.receiver_address = receiver_address
     self.sender_addresses = sender_addresses
@@ -548,9 +562,7 @@ class NetinfoCell(Cell):
       addr, content = Address.pop(content)
       sender_addresses.append(addr)
 
-    # remaining content (if any) is thrown out (ignored)
-
-    return NetinfoCell(receiver_address, sender_addresses, datetime.datetime.utcfromtimestamp(timestamp))
+    return NetinfoCell(receiver_address, sender_addresses, datetime.datetime.utcfromtimestamp(timestamp), unused = b'')
 
   def __hash__(self):
     return _hash_attr(self, 'timestamp', 'receiver_address', 'sender_addresses')
@@ -561,24 +573,36 @@ class RelayEarlyCell(CircuitCell):
   VALUE = 9
   IS_FIXED_SIZE = True
 
+  def __init__(self):
+    super(RelayEarlyCell, self).__init__()  # TODO: implement
+
 
 class Create2Cell(CircuitCell):
   NAME = 'CREATE2'
   VALUE = 10
   IS_FIXED_SIZE = True
 
+  def __init__(self):
+    super(Create2Cell, self).__init__()  # TODO: implement
+
 
 class Created2Cell(Cell):
   NAME = 'CREATED2'
   VALUE = 11
   IS_FIXED_SIZE = True
 
+  def __init__(self):
+    super(Created2Cell, self).__init__()  # TODO: implement
+
 
 class PaddingNegotiateCell(Cell):
   NAME = 'PADDING_NEGOTIATE'
   VALUE = 12
   IS_FIXED_SIZE = True
 
+  def __init__(self):
+    super(PaddingNegotiateCell, self).__init__()  # TODO: implement
+
 
 class VPaddingCell(Cell):
   """
@@ -599,6 +623,7 @@ class VPaddingCell(Cell):
     elif size is not None and payload is not None and size != len(payload):
       raise ValueError('VPaddingCell constructor specified both a size of %i bytes and payload of %i bytes' % (size, len(payload)))
 
+    super(VPaddingCell, self).__init__()
     self.payload = payload if payload is not None else os.urandom(size)
 
   def pack(self, link_protocol):
@@ -623,7 +648,8 @@ class CertsCell(Cell):
   VALUE = 129
   IS_FIXED_SIZE = False
 
-  def __init__(self, certs):
+  def __init__(self, certs, unused = b''):
+    super(CertsCell, self).__init__(unused)
     self.certificates = certs
 
   def pack(self, link_protocol):
@@ -641,9 +667,7 @@ class CertsCell(Cell):
       cert, content = Certificate.pop(content)
       certs.append(cert)
 
-    # remaining content (if any) is thrown out (ignored)
-
-    return CertsCell(certs)
+    return CertsCell(certs, unused = content)
 
   def __hash__(self):
     return _hash_attr(self, 'certificates')
@@ -662,12 +686,13 @@ class AuthChallengeCell(Cell):
   VALUE = 130
   IS_FIXED_SIZE = False
 
-  def __init__(self, methods, challenge = None):
+  def __init__(self, methods, challenge = None, unused = b''):
     if not challenge:
       challenge = os.urandom(AUTH_CHALLENGE_SIZE)
     elif len(challenge) != AUTH_CHALLENGE_SIZE:
       raise ValueError('AUTH_CHALLENGE must be %i bytes, but was %i' % (AUTH_CHALLENGE_SIZE, len(challenge)))
 
+    super(AuthChallengeCell, self).__init__(unused)
     self.challenge = challenge
     self.methods = methods
 
@@ -698,9 +723,7 @@ class AuthChallengeCell(Cell):
       method, content = Size.SHORT.pop(content)
       methods.append(method)
 
-    # remaining content (if any) is thrown out (ignored)
-
-    return AuthChallengeCell(methods, challenge)
+    return AuthChallengeCell(methods, challenge, unused = content)
 
   def __hash__(self):
     return _hash_attr(self, 'challenge', 'methods')
@@ -711,8 +734,14 @@ class AuthenticateCell(Cell):
   VALUE = 131
   IS_FIXED_SIZE = False
 
+  def __init__(self):
+    super(AuthenticateCell, self).__init__()  # TODO: implement
+
 
 class AuthorizeCell(Cell):
   NAME = 'AUTHORIZE'
   VALUE = 132
   IS_FIXED_SIZE = False
+
+  def __init__(self):
+    super(AuthorizeCell, self).__init__()  # TODO: implement
diff --git a/test/unit/client/cell.py b/test/unit/client/cell.py
index 3d054757..b6734fe7 100644
--- a/test/unit/client/cell.py
+++ b/test/unit/client/cell.py
@@ -173,6 +173,7 @@ class TestCell(unittest.TestCase):
       self.assertEqual(data, cell.data)
       self.assertEqual(digest, cell.digest)
       self.assertEqual(stream_id, cell.stream_id)
+      self.assertEqual(b'\x00' * (498 - len(cell.data)), cell.unused)
 
     digest = hashlib.sha1(b'hi')
     self.assertEqual(3257622417, RelayCell(5, 'RELAY_BEGIN_DIR', '', digest, 564346860).digest)
@@ -190,6 +191,7 @@ class TestCell(unittest.TestCase):
       self.assertEqual(circ_id, cell.circ_id)
       self.assertEqual(reason, cell.reason)
       self.assertEqual(reason_int, cell.reason_int)
+      self.assertEqual(b'', cell.unused)
 
     self.assertRaisesRegexp(ValueError, 'Circuit closure reason should be a single byte, but was 2', Cell.pop, b'\x80\x00\x00\x00\x04\x01\x01' + ZERO * 507, 5)
 
@@ -200,6 +202,7 @@ class TestCell(unittest.TestCase):
       cell = Cell.pop(cell_bytes, 5)[0]
       self.assertEqual(circ_id, cell.circ_id)
       self.assertEqual(key_material, cell.key_material)
+      self.assertEqual(b'', cell.unused)
 
     self.assertRaisesRegexp(ValueError, 'Key material should be 20 bytes, but was 3', CreateFastCell, 5, 'boo')
 
@@ -211,6 +214,7 @@ class TestCell(unittest.TestCase):
       self.assertEqual(circ_id, cell.circ_id)
       self.assertEqual(key_material, cell.key_material)
       self.assertEqual(derivative_key, cell.derivative_key)
+      self.assertEqual(b'', cell.unused)
 
     self.assertRaisesRegexp(ValueError, 'Key material should be 20 bytes, but was 3', CreateFastCell, 5, 'boo')
 
@@ -227,6 +231,7 @@ class TestCell(unittest.TestCase):
       self.assertEqual(timestamp, cell.timestamp)
       self.assertEqual(receiver_address, cell.receiver_address)
       self.assertEqual(sender_addresses, cell.sender_addresses)
+      self.assertEqual(b'', cell.unused)
 
   def test_vpadding_cell(self):
     for cell_bytes, payload in VPADDING_CELLS.items():
@@ -262,6 +267,7 @@ class TestCell(unittest.TestCase):
       cell = Cell.pop(cell_bytes, 2)[0]
       self.assertEqual(challenge, cell.challenge)
       self.assertEqual(methods, cell.methods)
+      self.assertEqual(b'', cell.unused)
 
     self.assertRaisesRegexp(ValueError, 'AUTH_CHALLENGE cell should have a payload of 38 bytes, but only had 16', Cell.pop, b'\x00\x00\x82\x00&' + CHALLENGE[:10] + b'\x00\x02\x00\x01\x00\x03', 2)
     self.assertRaisesRegexp(ValueError, 'AUTH_CHALLENGE should have 3 methods, but only had 4 bytes for it', Cell.pop, b'\x00\x00\x82\x00&' + CHALLENGE + b'\x00\x03\x00\x01\x00\x03', 2)





More information about the tor-commits mailing list