systematic use of context managers for dealing with files instead of open()/close...
[nepi.git] / src / nepi / resources / linux / scripts / linux-udp-connect.py
index 330ed17..f8f8502 100644 (file)
@@ -1,14 +1,16 @@
+import base64
 import errno
 import os
 import time
+import passfd
 import signal
 import socket
 import tunchannel
-import struct
-import fcntl
 
 from optparse import OptionParser
 
+PASSFD_MSG = "PASSFD"
+
 IFF_TUN = 0x0001
 IFF_TAP     = 0x0002
 IFF_NO_PI   = 0x1000
@@ -35,61 +37,75 @@ def _resume(sig,frame):
         SUSPEND.remove(None)
 signal.signal(signal.SIGUSR2, _resume)
 
-def open_tap(vif_name, vif_type, pi):
-    flags = 0
-    flags |= vif_type
-
-    if not pi:
-        flags |= IFF_NO_PI
-
-    fd = os.open("/dev/net/tun", os.O_RDWR)
-
-    err = fcntl.ioctl(fd, TUNSETIFF, struct.pack("16sH", vif_name, flags))
-    if err < 0:
-        os.close(fd)
-        raise RuntimeError("Could not configure device %s" % vif_name)
+def get_fd(socket_name):
+    # Socket to recive the file descriptor
+    fdsock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
+    fdsock.bind("")
+    address = fdsock.getsockname()
+
+    # Socket to connect to the pl-vif-create process 
+    # and send the PASSFD message
+    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+    sock.connect(socket_name)
+    emsg = base64.b64encode(PASSFD_MSG)
+    eargs = base64.b64encode(address)
+    encoded = "%s|%s\n" % (emsg, eargs)
+    sock.send(encoded)
+
+    # Receive fd
+    (fd, msg) = passfd.recvfd(fdsock)
+    
+    # Receive reply
+    reply = sock.recv(1024)
+    reply = base64.b64decode(reply)
 
+    sock.close()
+    fdsock.close()
     return fd
 
 def get_options():
-    usage = ("usage: %prog -N <vif_name> -t <vif-type> -p <pi> "
+    usage = ("usage: %prog -t <vif-type> -S <fd-socket-name> -n <pi> "
             "-b <bwlimit> -c <cipher> -k <cipher-key> -q <txqueuelen> " 
-            "-l <local-port-file> -r <remote-port-file> -H <remote-host> "
+            "-p <local-port-file> -P <remote-port-file> "
+            "-o <local-ip> -P <remote-ip> "
             "-R <ret-file> ")
     
     parser = OptionParser(usage = usage)
 
-    parser.add_option("-N", "--vif-name", dest="vif_name",
-        help="The name of the virtual interface", type="str")
     parser.add_option("-t", "--vif-type", dest="vif_type",
-        help="Virtual interface type. Either IFF_TAP or IFF_TUN. "
-            "Defaults to IFF_TAP. ", default=IFF_TAP, type="str")
+        help = "Virtual interface type. Either IFF_TAP or IFF_TUN. "
+            "Defaults to IFF_TAP. ", type="str")
+    parser.add_option("-S", "--fd-socket-name", dest="fd_socket_name",
+        help = "Name for the unix socket to request the TAP file descriptor", 
+        default = "tap.sock", type="str")
     parser.add_option("-n", "--pi", dest="pi", action="store_true", 
             default=False, help="Enable PI header")
 
     parser.add_option("-b", "--bwlimit", dest="bwlimit",
-        help="Specifies the interface's emulated bandwidth in bytes ",
-        default=None, type="int")
+        help = "Specifies the interface's emulated bandwidth in bytes ",
+        default = None, type="int")
     parser.add_option("-q", "--txqueuelen", dest="txqueuelen",
-        help="Specifies the interface's transmission queue length. ",
-        default=1000, type="int")
+        help = "Specifies the interface's transmission queue length. ",
+        default = 1000, type="int")
     parser.add_option("-c", "--cipher", dest="cipher",
-        help="Cipher to encript communication. "
+        help = "Cipher to encript communication. "
             "One of PLAIN, AES, Blowfish, DES, DES3. ",
-        default=None, type="str")
+        default = None, type="str")
     parser.add_option("-k", "--cipher-key", dest="cipher_key",
-        help="Specify a symmetric encryption key with which to protect "
+        help = "Specify a symmetric encryption key with which to protect "
             "packets across the tunnel. python-crypto must be installed "
             "on the system." ,
-        default=None, type="str")
+        default = None, type="str")
 
-    parser.add_option("-l", "--local-port-file", dest="local_port_file",
+    parser.add_option("-p", "--local-port-file", dest="local_port_file",
         help = "File where to store the local binded UDP port number ", 
         default = "local_port_file", type="str")
-    parser.add_option("-r", "--remote-port-file", dest="remote_port_file",
+    parser.add_option("-P", "--remote-port-file", dest="remote_port_file",
         help = "File where to read the remote UDP port number to connect to", 
         default = "remote_port_file", type="str")
-    parser.add_option("-H", "--remote-host", dest="remote_host",
+    parser.add_option("-o", "--local-ip", dest="local_ip",
+        help = "Local host IP", default = "local_host", type="str")
+    parser.add_option("-O", "--remote-ip", dest="remote_ip",
         help = "Remote host IP", default = "remote_host", type="str")
     parser.add_option("-R", "--ret-file", dest="ret_file",
         help = "File where to store return code (success of connection) ", 
@@ -101,31 +117,30 @@ def get_options():
     if options.vif_type and options.vif_type == "IFF_TUN":
         vif_type = IFF_TUN
 
-    return ( options.vif_name, vif_type, options.pi
+    return (vif_type, options.pi, options.fd_socket_name
             options.local_port_file, options.remote_port_file, 
-            options.remote_host, options.ret_file, options.bwlimit, 
-            options.cipher, options.cipher_key, options.txqueuelen )
+            options.local_ip, options.remote_ip, options.ret_file, 
+            options.bwlimit, options.cipher, options.cipher_key,
+            options.txqueuelen )
 
 if __name__ == '__main__':
+    ( vif_type, pi, socket_name, local_port_file, remote_port_file,
+            local_ip, remote_ip, ret_file, bwlimit, cipher, cipher_key, 
+            txqueuelen ) = get_options()
 
-    ( vif_name, vif_type, pi, local_port_file, remote_port_file,
-      remote_host, ret_file, bwlimit, cipher, cipher_key, txqueuelen 
-         ) = get_options()
-   
     # Get the file descriptor of the TAP device from the process
     # that created it
-    fd = open_tap(vif_name, vif_type, pi)
+    fd = get_fd(socket_name)
+    tun = os.fdopen(fd, 'r+b', 0)
 
     # Create a local socket to stablish the tunnel connection
-    hostaddr = socket.gethostbyname(socket.gethostname())
     sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
-    sock.bind((hostaddr, 0))
+    sock.bind((local_ip, 0))
     (local_host, local_port) = sock.getsockname()
 
     # Save local port information to file
-    f = open(local_port_file, 'w')
-    f.write("%d\n" % local_port)
-    f.close()
+    with open(local_port_file, 'w') as f:
+        f.write("%d\n" % local_port)
 
     # Wait until remote port information is available
     while not os.path.exists(remote_port_file):
@@ -139,9 +154,8 @@ if __name__ == '__main__':
     #       the read operation returns empty string!
     #       Maybe a race condition?
     for i in xrange(10):
-        f = open(remote_port_file, 'r')
-        remote_port = f.read()
-        f.close()
+        with open(remote_port_file, 'r') as f:
+            remote_port = f.read()
 
         if remote_port:
             break
@@ -152,15 +166,14 @@ if __name__ == '__main__':
     remote_port = int(remote_port)
 
     # Connect local socket to remote port
-    sock.connect((remote_host, remote_port))
+    sock.connect((remote_ip, remote_port))
     remote = os.fdopen(sock.fileno(), 'r+b', 0)
 
     # TODO: Test connectivity!    
 
     # Create a ret_file to indicate success
-    f = open(ret_file, 'w')
-    f.write("0")
-    f.close()
+    with open(ret_file, 'w') as f:
+        f.write("0")
 
     # Establish tunnel
     tunchannel.tun_fwd(tun, remote,