2 # -*- coding: utf-8 -*-
10 from nepi.util import server
12 class TunProtoBase(object):
13 def __init__(self, local, peer, home_path):
14 # Weak references, since ifaces do have a reference to the
15 # tunneling protocol implementation - we don't want strong
16 # circular references.
17 self.peer = weakref.ref(peer)
18 self.local = weakref.ref(local)
23 self.home_path = home_path
33 raise RuntimeError, "Lost reference to peering interfaces before launching"
35 raise RuntimeError, "Unconnected TUN - missing node"
37 # Make sure all the paths are created where
38 # they have to be created for deployment
39 cmd = "mkdir -p %s" % (server.shell_escape(self.home_path),)
40 (out,err),proc = server.popen_ssh_command(
42 host = local.node.hostname,
44 user = local.node.slicename,
46 ident_key = local.node.ident_path,
47 server_key = local.node.server_key
51 raise RuntimeError, "Failed to set up TUN forwarder: %s %s" % (out,err,)
54 def _install_scripts(self):
58 raise RuntimeError, "Lost reference to peering interfaces before launching"
60 raise RuntimeError, "Unconnected TUN - missing node"
62 # Install the tun_connect script and tunalloc utility
64 os.path.join(os.path.dirname(__file__), 'scripts', 'tun_connect.py'),
65 os.path.join(os.path.dirname(__file__), 'scripts', 'tunalloc.c'),
68 local.node.slicename, local.node.hostname,
69 os.path.join(self.home_path,'.'),)
70 (out,err),proc = server.popen_scp(
73 ident_key = local.node.ident_path,
74 server_key = local.node.server_key
78 raise RuntimeError, "Failed upload TUN connect script %r: %s %s" % (source, out,err,)
80 cmd = "cd %s && gcc -shared tunalloc.c -o tunalloc.so" % (server.shell_escape(self.home_path),)
81 (out,err),proc = server.popen_ssh_command(
83 host = local.node.hostname,
85 user = local.node.slicename,
87 ident_key = local.node.ident_path,
88 server_key = local.node.server_key
92 raise RuntimeError, "Failed to set up TUN forwarder: %s %s" % (out,err,)
95 def launch(self, check_proto, listen, extra_args=[]):
99 if not peer or not local:
100 raise RuntimeError, "Lost reference to peering interfaces before launching"
102 peer_port = peer.tun_port
103 peer_addr = peer.tun_addr
104 peer_proto= peer.tun_proto
106 local_port = self.port
107 local_cap = local.capture
108 local_addr = local.address
109 local_mask = local.netprefix
110 local_snat = local.snat
111 local_txq = local.txqueuelen
113 if check_proto != peer_proto:
114 raise RuntimeError, "Peering protocol mismatch: %s != %s" % (check_proto, peer_proto)
116 if not listen and (not peer_port or not peer_addr):
117 raise RuntimeError, "Misconfigured peer: %s" % (peer,)
119 if listen and (not local_port or not local_addr or not local_mask):
120 raise RuntimeError, "Misconfigured TUN: %s" % (local,)
122 args = ["python", "tun_connect.py",
123 "-m", str(self.mode),
124 "-p", str(local_port if listen else peer_port),
125 "-A", str(local_addr),
126 "-M", str(local_mask)]
131 args.extend(("-Q",str(local_txq)))
133 args.extend(map(str,extra_args))
135 args.append(str(peer_addr))
138 self._install_scripts()
140 # Start process in a "daemonized" way, using nohup and heavy
141 # stdin/out redirection to avoid connection issues
142 (out,err),proc = rspawn.remote_spawn(
146 home = self.home_path,
148 stdout = 'capture' if local_cap else '/dev/null',
149 stderr = rspawn.STDOUT,
152 host = local.node.hostname,
154 user = local.node.slicename,
156 ident_key = local.node.ident_path,
157 server_key = local.node.server_key
161 raise RuntimeError, "Failed to set up application: %s %s" % (out,err,)
169 raise RuntimeError, "Lost reference to local interface"
172 # NOTE: wait a bit for the pidfile to be created
173 if self._started and not self._pid or not self._ppid:
174 pidtuple = rspawn.remote_check_pid(
175 os.path.join(self.home_path,'pid'),
176 host = local.node.hostname,
178 user = local.node.slicename,
180 ident_key = local.node.ident_path,
181 server_key = local.node.server_key
185 self._pid, self._ppid = pidtuple
191 raise RuntimeError, "Lost reference to local interface"
194 if not self._started:
195 return rspawn.NOT_STARTED
196 elif not self._pid or not self._ppid:
197 return rspawn.NOT_STARTED
199 status = rspawn.remote_status(
200 self._pid, self._ppid,
201 host = local.node.hostname,
203 user = local.node.slicename,
205 ident_key = local.node.ident_path
213 raise RuntimeError, "Lost reference to local interface"
215 status = self.status()
216 if status == rspawn.RUNNING:
217 # kill by ppid+pid - SIGTERM first, then try SIGKILL
219 self._pid, self._ppid,
220 host = local.node.hostname,
222 user = local.node.slicename,
224 ident_key = local.node.ident_path,
225 server_key = local.node.server_key,
229 def sync_trace(self, local_dir, whichtrace):
230 if whichtrace != 'packets':
238 local_path = os.path.join(local_dir, 'capture')
240 # create parent local folders
241 proc = subprocess.Popen(
242 ["mkdir", "-p", os.path.dirname(local_path)],
243 stdout = open("/dev/null","w"),
244 stdin = open("/dev/null","r"))
247 raise RuntimeError, "Failed to synchronize trace: %s %s" % (out,err,)
250 (out,err),proc = server.popen_scp(
251 '%s@%s:%s' % (local.node.slicename, local.node.hostname,
252 os.path.join(self.home_path, 'capture')),
256 ident_key = local.node.ident_path,
257 server_key = local.node.server_key
261 raise RuntimeError, "Failed to synchronize trace: %s %s" % (out,err,)
270 eg: set up listening ports
272 raise NotImplementedError
280 raise NotImplementedError
286 raise NotImplementedError
289 class TunProtoUDP(TunProtoBase):
290 def __init__(self, local, peer, home_path, listening):
291 super(TunProtoTCP, self).__init__(local, peer, home_path)
292 self.listening = listening
298 self.launch('udp', False, ("-U",))
303 class TunProtoTCP(TunProtoBase):
304 def __init__(self, local, peer, home_path, listening):
305 super(TunProtoTCP, self).__init__(local, peer, home_path)
306 self.listening = listening
310 self.launch('tcp', True)
313 if not self.listening:
314 self.launch('tcp', False)