Configurable cipher for tunnelling
authorClaudio-Daniel Freire <claudio-daniel.freire@inria.fr>
Tue, 9 Aug 2011 17:21:12 +0000 (19:21 +0200)
committerClaudio-Daniel Freire <claudio-daniel.freire@inria.fr>
Tue, 9 Aug 2011 17:21:12 +0000 (19:21 +0200)
src/nepi/core/metadata.py
src/nepi/testbeds/netns/metadata.py
src/nepi/testbeds/ns3/factories_metadata.py
src/nepi/testbeds/planetlab/interfaces.py
src/nepi/testbeds/planetlab/metadata.py
src/nepi/testbeds/planetlab/node.py
src/nepi/testbeds/planetlab/scripts/tun_connect.py
src/nepi/testbeds/planetlab/tunproto.py
src/nepi/util/tunchannel_impl.py

index 0dfc0da..7f8e781 100644 (file)
@@ -432,6 +432,21 @@ class Metadata(object):
                     Attribute.Metadata,
             "validation_function" : validation.is_integer,
             }),
+        "tun_cipher" : dict({
+            "name" : "tun_cipher", 
+            "help" : "Cryptographic cipher used for tunnelling",
+            "type" : Attribute.ENUM,
+            "value" : "AES",
+            "allowed" : [
+                "AES",
+                "Blowfish",
+                "DES3",
+                "DES",
+                "PLAIN",
+            ],
+            "flags" : Attribute.ExecImmutable,
+            "validation_function" : validation.is_enum,
+            }),
         ATTR_NEPI_TESTBED_ENVIRONMENT_SETUP : dict({
             "name" : ATTR_NEPI_TESTBED_ENVIRONMENT_SETUP,
             "help" : "Commands to set up the environment needed to run NEPI testbeds",
index d6361b3..c4ddc61 100644 (file)
@@ -535,7 +535,7 @@ factories_info = dict({
                 "other TAP interfaces supporting the NEPI tunneling protocol.",
             "connector_types": ["->fd", "udp", "tcp"],
             "allow_addresses": False,
-            "box_attributes": ["tun_proto", "tun_addr", "tun_port", "tun_key"],
+            "box_attributes": ["tun_proto", "tun_addr", "tun_port", "tun_key", "tun_cipher"],
             "tags": [tags.TUNNEL],
     }),
 })
index adda876..ace0f27 100644 (file)
@@ -1062,7 +1062,7 @@ factories_info = dict({
                 "other TAP interfaces supporting the NEPI tunneling protocol.",
         "connector_types": ["fd->", "udp", "tcp"],
         "allow_addresses": False,
-        "box_attributes": ["tun_proto", "tun_addr", "tun_port", "tun_key"],
+        "box_attributes": ["tun_proto", "tun_addr", "tun_port", "tun_key","tun_cipher"],
         "tags": [tags.TUNNEL],
  
     }),
index 4f9c69b..5b4e3a1 100644 (file)
@@ -88,10 +88,11 @@ class NodeIface(object):
     
 
 class _CrossIface(object):
-    def __init__(self, proto, addr, port):
+    def __init__(self, proto, addr, port, cipher):
         self.tun_proto = proto
         self.tun_addr = addr
         self.tun_port = port
+        self.tun_cipher = cipher
         
         # Cannot access cross peers
         self.peer_proto_impl = None
@@ -101,7 +102,8 @@ class _CrossIface(object):
             self.__class__.__name__,
             ( self.tun_proto,
               self.tun_addr,
-              self.tun_port ) 
+              self.tun_port,
+              self.tun_cipher ) 
         )
     
     __repr__ = __str__
@@ -140,6 +142,7 @@ class TunIface(object):
         # They're part of the TUN standard attribute set
         self.tun_port = None
         self.tun_addr = None
+        self.tun_cipher = "AES"
         
         # These get initialized when the iface is connected to its peer
         self.peer_iface = None
@@ -247,7 +250,8 @@ class TunIface(object):
             self.peer_iface = _CrossIface(
                 self.peer_proto,
                 self.peer_addr,
-                self.peer_port)
+                self.peer_port,
+                self.peer_cipher)
         if self.peer_iface:
             if not self.peer_proto_impl:
                 self.peer_proto_impl = self._impl_instance(home_path, listening)
index 203b22d..9a4a87b 100644 (file)
@@ -113,6 +113,7 @@ def crossconnect_tun_iface_peer_init(proto, testbed_instance, iface_guid, peer_i
     iface.peer_addr = peer_iface_data.get("tun_addr")
     iface.peer_proto = peer_iface_data.get("tun_proto") or proto
     iface.peer_port = peer_iface_data.get("tun_port")
+    iface.peer_cipher = peer_iface_data.get("tun_cipher")
     iface.tun_key = min(iface.tun_key, peer_iface_data.get("tun_key"))
     iface.tun_proto = proto
     
@@ -124,6 +125,7 @@ def crossconnect_tun_iface_peer_compl(proto, testbed_instance, iface_guid, peer_
     iface.peer_addr = peer_iface_data.get("tun_addr")
     iface.peer_proto = peer_iface_data.get("tun_proto") or proto
     iface.peer_port = peer_iface_data.get("tun_port")
+    iface.peer_cipher = peer_iface_data.get("tun_cipher")
     
     postconfigure_tuniface(testbed_instance, iface_guid)
 
@@ -1076,7 +1078,7 @@ factories_info = dict({
             "box_attributes": [
                 "up", "device_name", "mtu", "snat", "pointopoint",
                 "txqueuelen",
-                "tun_proto", "tun_addr", "tun_port", "tun_key"
+                "tun_proto", "tun_addr", "tun_port", "tun_key", "tun_cipher",
             ],
             "traces": ["packets", "pcap"],
             "connector_types": ["node","udp","tcp","fd->","gre"],
@@ -1092,7 +1094,7 @@ factories_info = dict({
             "box_attributes": [
                 "up", "device_name", "mtu", "snat", "pointopoint",
                 "txqueuelen",
-                "tun_proto", "tun_addr", "tun_port", "tun_key"
+                "tun_proto", "tun_addr", "tun_port", "tun_key", "tun_cipher",
             ],
             "traces": ["packets", "pcap"],
             "connector_types": ["node","udp","tcp","fd->","gre"],
index 1101bfe..8ab312f 100644 (file)
@@ -463,8 +463,10 @@ class Node(object):
 
         (out,err),proc = server.popen_ssh_command(
             # Some apps need two kills
-            "sudo -S killall -u %(slicename)s ; sudo -S killall -u root ; "
-            "sudo -S killall -u %(slicename)s ; sudo -S killall -u root" % {
+            "sudo -S killall -u %(slicename)s ; "
+            "sudo -S killall -u %(slicename)s ; "
+            "sudo -S killall -u root ; "
+            "sudo -S killall -u root " % {
                 'slicename' : self.slicename ,
             },
             host = self.hostname,
index 0eb46e3..84934ae 100644 (file)
@@ -102,6 +102,10 @@ parser.add_option(
     default = None,
     help = 
         "Specify a demultiplexing 32-bit numeric key for GRE." )
+parser.add_option(
+    "-C", "--cipher", dest="cipher", metavar="CIPHER",
+    default = 'AES',
+    help = "One of PLAIN, AES, Blowfish, DES, DES3. " )
 parser.add_option(
     "-N", "--no-capture", dest="no_capture", 
     action = "store_true",
@@ -116,6 +120,13 @@ parser.add_option(
 
 (options, remaining_args) = parser.parse_args(sys.argv[1:])
 
+options.cipher = {
+    'aes' : 'AES',
+    'des' : 'DES',
+    'des3' : 'DES3',
+    'blowfish' : 'Blowfish',
+    'plain' : None,
+}[options.cipher.lower()]
 
 ETH_P_ALL = 0x00000003
 ETH_P_IP = 0x00000800
@@ -426,7 +437,8 @@ def tun_fwd(tun, remote, reconnect = None):
         stderr = None,
         reconnect = reconnect,
         tunqueue = tunqueue,
-        tunkqueue = tunkqueue
+        tunkqueue = tunkqueue,
+        cipher = options.cipher
     )
 
 
index d3cf6b8..00bfb83 100644 (file)
@@ -162,6 +162,7 @@ class TunProtoBase(object):
         peer_port = peer.tun_port
         peer_addr = peer.tun_addr
         peer_proto= peer.tun_proto
+        peer_cipher=peer.tun_cipher
         
         local_port = self.port
         local_cap  = local.capture
@@ -170,6 +171,7 @@ class TunProtoBase(object):
         local_snat = local.snat
         local_txq  = local.txqueuelen
         local_p2p  = local.pointopoint
+        local_cipher=local.tun_cipher
         
         if not local_p2p and hasattr(peer, 'address'):
             local_p2p = peer.address
@@ -177,16 +179,23 @@ class TunProtoBase(object):
         if check_proto != peer_proto:
             raise RuntimeError, "Peering protocol mismatch: %s != %s" % (check_proto, peer_proto)
         
+        if local_cipher != peer_cipher:
+            raise RuntimeError, "Peering cipher mismatch: %s != %s" % (local_cipher, peer_cipher)
+        
         if not listen and ((peer_proto != 'fd' and not peer_port) or not peer_addr):
             raise RuntimeError, "Misconfigured peer: %s" % (peer,)
         
         if listen and ((peer_proto != 'fd' and not local_port) or not local_addr or not local_mask):
             raise RuntimeError, "Misconfigured TUN: %s" % (local,)
+
+        if check_proto == 'gre' and local_cipher.lower() != 'plain':
+            raise RuntimeError, "Misconfigured TUN: %s - GRE tunnels do not support encryption. Got %s, you MUST use PLAIN" % (local, local_cipher,)
         
         args = ["python", "tun_connect.py", 
             "-m", str(self.mode),
             "-A", str(local_addr),
-            "-M", str(local_mask)]
+            "-M", str(local_mask),
+            "-C", str(local_cipher)]
         
         if check_proto == 'fd':
             passfd_arg = str(peer_addr)
@@ -335,7 +344,7 @@ class TunProtoBase(object):
                         self._logger.debug("if_name: %r does not match expected pattern", out)
                         time.sleep(1)
                 else:
-                    pself._logger.warn("if_name: Could not get interface name")
+                    self._logger.warn("if_name: Could not get interface name")
         return self._if_name
     
     def async_launch(self, check_proto, listen, extra_args=[]):
index bfc0ce5..cecd729 100644 (file)
@@ -18,13 +18,13 @@ class TunChannel(object):
     testbed controller process. It takes several parameters that
     can be given by directly setting attributes:
     
-        tun_port/addr/proto: information about the local endpoint.
+        tun_port/addr/proto/cipher: information about the local endpoint.
             The addresses here should be externally-reachable,
             since when listening or when using the UDP protocol,
             connections to this address/port will be attempted
             by remote endpoitns.
         
-        peer_port/addr/proto: information about the remote endpoint.
+        peer_port/addr/proto/cipher: information about the remote endpoint.
             Usually, you set these when the cross connection 
             initializer/completion functions are invoked (both).
         
@@ -65,11 +65,13 @@ class TunChannel(object):
         # They're part of the TUN standard attribute set
         self.tun_port = None
         self.tun_addr = None
+        self.tun_cipher = None
         
         # These get initialized when the channel is connected to its peer
         self.peer_proto = None
         self.peer_addr = None
         self.peer_port = None
+        self.peer_cipher = None
         
         # These get initialized when the channel is connected to its iface
         self.tun_socket = None
@@ -98,12 +100,13 @@ class TunChannel(object):
         
 
     def __str__(self):
-        return "%s<%s %s:%s %s %s:%s>" % (
+        return "%s<%s %s:%s %s %s:%s %s>" % (
             self.__class__.__name__,
             self.tun_proto, 
             self.tun_addr, self.tun_port,
             self.peer_proto, 
             self.peer_addr, self.peer_port,
+            self.tun_cipher,
         )
 
     def Prepare(self):
@@ -166,10 +169,12 @@ class TunChannel(object):
         peer_port = self.peer_port
         peer_addr = self.peer_addr
         peer_proto= self.peer_proto
+        peer_cipher=self.peer_cipher
 
         local_port = self.tun_port
         local_addr = self.tun_addr
         local_proto = self.tun_proto
+        local_cipher= self.tun_cipher
         
         stderr = self.stderr
         ether_mode = self.ethernet_mode
@@ -177,6 +182,9 @@ class TunChannel(object):
         
         if local_proto != peer_proto:
             raise RuntimeError, "Peering protocol mismatch: %s != %s" % (local_proto, peer_proto)
+
+        if local_cipher != peer_cipher:
+            raise RuntimeError, "Peering cipher mismatch: %s != %s" % (local_cipher, peer_cipher)
         
         udp = local_proto == 'udp'
         listen = self.listen
@@ -249,7 +257,8 @@ class TunChannel(object):
             cipher_key = cipher_key, 
             udp = udp, 
             TERMINATE = TERMINATE,
-            stderr = stderr
+            stderr = stderr,
+            cipher = local_cipher
         )
         
         tun.close()
@@ -340,6 +349,7 @@ def crossconnect_tunchannel_peer_init(proto, testbed_instance, tun_guid, peer_da
     tun.peer_addr = peer_data.get("tun_addr")
     tun.peer_proto = peer_data.get("tun_proto") or proto
     tun.peer_port = peer_data.get("tun_port")
+    tun.peer_cipher = peer_data.get("tun_cipher")
     tun.tun_key = min(tun.tun_key, peer_data.get("tun_key"))
     tun.tun_proto = proto
     
@@ -362,6 +372,7 @@ def crossconnect_tunchannel_peer_compl(proto, testbed_instance, tun_guid, peer_d
     tun.peer_addr = peer_data.get("tun_addr")
     tun.peer_proto = peer_data.get("tun_proto") or proto
     tun.peer_port = peer_data.get("tun_port")
+    tun.peer_cipher = peer_data.get("tun_cipher")
     
     postconfigure_tunchannel(testbed_instance, tun_guid)