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
63 source = os.path.join(os.path.dirname(__file__), 'scripts', 'tun_connect.py')
65 local.node.slicename, local.node.hostname,
66 os.path.join(self.home_path,'.'),)
67 (out,err),proc = server.popen_scp(
70 ident_key = local.node.ident_path,
71 server_key = local.node.server_key
75 raise RuntimeError, "Failed upload TUN connect script %r: %s %s" % (source, out,err,)
77 source = os.path.join(os.path.dirname(__file__), 'scripts', 'tunalloc.c')
78 (out,err),proc = server.popen_scp(
81 ident_key = local.node.ident_path,
82 server_key = local.node.server_key
86 raise RuntimeError, "Failed upload TUN connect script %r: %s %s" % (source, out,err,)
88 cmd = "cd %s && gcc -shared tunalloc.c -o tunalloc.so" % (server.shell_escape(self.home_path),)
89 (out,err),proc = server.popen_ssh_command(
91 host = local.node.hostname,
93 user = local.node.slicename,
95 ident_key = local.node.ident_path,
96 server_key = local.node.server_key
100 raise RuntimeError, "Failed to set up TUN forwarder: %s %s" % (out,err,)
103 def launch(self, check_proto, listen, extra_args=[]):
107 if not peer or not local:
108 raise RuntimeError, "Lost reference to peering interfaces before launching"
110 peer_port = peer.tun_port
111 peer_addr = peer.tun_addr
112 peer_proto= peer.tun_proto
114 local_port = self.port
115 local_cap = local.capture
116 local_addr = local.address
117 local_mask = local.netprefix
118 local_snat = local.snat
119 local_txq = local.txqueuelen
121 if check_proto != peer_proto:
122 raise RuntimeError, "Peering protocol mismatch: %s != %s" % (check_proto, peer_proto)
124 if not listen and (not peer_port or not peer_addr):
125 raise RuntimeError, "Misconfigured peer: %s" % (peer,)
127 if listen and (not local_port or not local_addr or not local_mask):
128 raise RuntimeError, "Misconfigured TUN: %s" % (local,)
130 args = ["python", "tun_connect.py",
131 "-m", str(self.mode),
132 "-p", str(local_port if listen else peer_port),
133 "-A", str(local_addr),
134 "-M", str(local_mask)]
139 args.extend(("-Q",str(local_txq)))
141 args.extend(map(str,extra_args))
143 args.append(str(peer_addr))
146 self._install_scripts()
148 # Start process in a "daemonized" way, using nohup and heavy
149 # stdin/out redirection to avoid connection issues
150 (out,err),proc = rspawn.remote_spawn(
154 home = self.home_path,
156 stdout = 'capture' if local_cap else '/dev/null',
157 stderr = rspawn.STDOUT,
160 host = local.node.hostname,
162 user = local.node.slicename,
164 ident_key = local.node.ident_path,
165 server_key = local.node.server_key
169 raise RuntimeError, "Failed to set up application: %s %s" % (out,err,)
177 raise RuntimeError, "Lost reference to local interface"
180 # NOTE: wait a bit for the pidfile to be created
181 if self._started and not self._pid or not self._ppid:
182 pidtuple = rspawn.remote_check_pid(
183 os.path.join(self.home_path,'pid'),
184 host = local.node.hostname,
186 user = local.node.slicename,
188 ident_key = local.node.ident_path,
189 server_key = local.node.server_key
193 self._pid, self._ppid = pidtuple
199 raise RuntimeError, "Lost reference to local interface"
202 if not self._started:
203 return rspawn.NOT_STARTED
204 elif not self._pid or not self._ppid:
205 return rspawn.NOT_STARTED
207 status = rspawn.remote_status(
208 self._pid, self._ppid,
209 host = local.node.hostname,
211 user = local.node.slicename,
213 ident_key = local.node.ident_path
221 raise RuntimeError, "Lost reference to local interface"
223 status = self.status()
224 if status == rspawn.RUNNING:
225 # kill by ppid+pid - SIGTERM first, then try SIGKILL
227 self._pid, self._ppid,
228 host = local.node.hostname,
230 user = local.node.slicename,
232 ident_key = local.node.ident_path,
233 server_key = local.node.server_key,
237 def sync_trace(self, local_dir, whichtrace):
238 if whichtrace != 'packets':
246 local_path = os.path.join(local_dir, 'capture')
248 # create parent local folders
249 proc = subprocess.Popen(
250 ["mkdir", "-p", os.path.dirname(local_path)],
251 stdout = open("/dev/null","w"),
252 stdin = open("/dev/null","r"))
255 raise RuntimeError, "Failed to synchronize trace: %s %s" % (out,err,)
258 (out,err),proc = server.popen_scp(
259 '%s@%s:%s' % (local.node.slicename, local.node.hostname,
260 os.path.join(self.home_path, 'capture')),
264 ident_key = local.node.ident_path,
265 server_key = local.node.server_key
269 raise RuntimeError, "Failed to synchronize trace: %s %s" % (out,err,)
278 eg: set up listening ports
280 raise NotImplementedError
288 raise NotImplementedError
294 raise NotImplementedError
297 class TunProtoUDP(TunProtoBase):
298 def __init__(self, local, peer, home_path, listening):
299 super(TunProtoTCP, self).__init__(local, peer, home_path)
300 self.listening = listening
306 self.launch('udp', False, ("-U",))
311 class TunProtoTCP(TunProtoBase):
312 def __init__(self, local, peer, home_path, listening):
313 super(TunProtoTCP, self).__init__(local, peer, home_path)
314 self.listening = listening
318 self.launch('tcp', True)
321 if not self.listening:
322 self.launch('tcp', False)