def need_tunnel(server): """ Reports whether a tunnel is needed to connect to the server. This needs to be able to handle fully qualified host names and IP addresses @param server : fully qualified server name or IP address """ output = search_response(['ip', 'route', 'show'], ['grep', 'default']) gateway = output[0].strip().split()[2] # This will fail if the gateway is ever not a single digit. local_domain = get_domain(gateway[:-2]) parts = server.split('.') if parts[-1].isalpha(): if re.search("fltops", server): remote_domain = "fltops" elif re.search("jpl", server): remote_domain = "jpl" else: remote_domain = "other" elif parts[0].isdigit(): remote_domain = get_domain('.'.join(parts[:-1])) module_logger.debug("need_tunnel: local domain is %s, remote domain is %s", local_domain, remote_domain) if remote_domain == "fltops" and local_domain != "fltops": need = True elif remote_domain == "jpl" and local_domain == "other": need = True else: need = False return need
def _get_child(self): """ Gets the PID of the process sustaining the tunnel @return: int """ output = search_response(["ps", "-ef"], ["grep", "xterm"]) # p1 = Popen(["ps", "-ef"], stdout=PIPE) # p2 = Popen(["grep", "xterm"], stdin=p1.stdout, stdout=PIPE) # waiting = True # while waiting: # try: # output = p2.stdout.read() # waiting = False # except IOError: # # probably an interrupted system call. Try again # continue module_logger.debug("_get_child: search_response gave\n%s", output) parts = output[0].split() pid = parts[1] user = parts[0] if pid.isdigit(): return int(pid) else: return None
def free_socket(): """ Return a free socket """ found = 1 while found: trial = random.randrange(1024, 65535) found = search_response(['netstat', '-vatn'], ['grep', str(trial)]) return trial
def do_mount(self, tunnel, remoteMP="/"): """ mount ssh source as local filesystem by calling sshfs Example: do_mount(mytunnel, "/home/me") @param tunnel : ssh tunnel to a remote host @type tunnel : Tunnel() instance @return: True on success """ self.user = tunnel.user self.port = tunnel.port self.path = remoteMP self.mp = self._get_possible_mountpoint() if not os.path.exists(self.mp): self.logger.debug( "do_mount: Creating mountpoint *s", str(self.mp)) os.mkdir(self.mp) sshfs = "%s@localhost:%s" % (self.user, self.path) # already mounted? response = search_response(['mount'], ['grep', sshfs]) if response: self.logger.debug( "do_mount: already mounted:\n%s", str(response)) self.mp = response[0].strip().split()[2] self.mountpoint = os.path.basename(self.mp) self.mountroot = os.path.dirname(self.mp) status = 0 else: command = 'sshfs -p %d -o uid=%d -o cache=no "%s" "%s"' % (self.port, self.uid, sshfs, self.mp) self.logger.debug("do_mount: login: %s", sshfs) self.logger.debug("do_mount: mount command:\n%s", command) status = os.system(command) if status == 0: self.logger.debug("do_mount: %s: %s mounted as %s in %s", self.host, self.path, self.mountpoint, self.mountroot) return True else: self.logger.warning("do_mount: Mount failed") try: os.rmdir(self.mp) except OSError as details: self.logger.error("do_mount: could not remove %s", self.mp, exc_info=True) return False
def get_user(self): """ Get the owner of the tunnel @return: owner """ self.user = '******' output = search_response(["ps", "-ef"], ["grep", str(self.pid)]) for line in output: parts = line.strip().split() if int(parts[1]) == self.pid: self.user = parts[0] break return self.user
def arbitrary_tunnel(remote_ip, relay_ip, local_port, remote_port, port=22, username='', reverse=False): """ Create an arbitrary ssh tunnel, after checking to see if a tunnel already exists. This just spawns the process that creates the tunnel, it doesn't check to see if the tunnel has successfully connected. Executes the following command: ``` ssh -p {port} -l {username} -L {local_port}:{relay_ip}:{remote_port} {remote_ip} ``` Args: remote_ip (str): The remote, or target ip address. For local port forwarding this can be localhost relay_ip (str): The relay ip address. local_port (int): The local port on which we listen remote_port (int): The remote port on which we listen Keyword Args: port (int): The -p argument for ssh username (str): The username to use for tunneling Returns: subprocess.Popen: if there isn't an existing process corresponding to tunnel: or else BasicProcess instance, the corresponds to already running tunnel command. """ #-c arcfour -o ServerAliveInterval=60 -o TCPKeepAlive=no # First thing is check to see if the remote_ip is ~/.ssh/config home_dir = os.path.expanduser("~") ssh_config = os.path.join(home_dir, ".ssh/config") with open(ssh_config, 'r') as config: contents = config.read() pattern = "host (.*)\n" hosts = [match for match in re.findall(pattern, contents)] r_option = "-L" if reverse: r_option = "-R" if remote_ip in hosts: command = "ssh -N {0} {1}:{2}:{3} {4}" command = command.format(r_option, local_port, relay_ip, remote_port, remote_ip) else: command = "ssh -N -l {0} -p {1} {2} {3}:{4}:{5} {6}" command = command.format(username, port, r_option, local_port, relay_ip, remote_port, remote_ip) command_relay = "{0} {1}:{2}:{3} {4}".format(r_option, local_port, relay_ip, remote_port, remote_ip) # module_logger.debug(command_relay) ssh_proc = search_response(['ps', 'x'], ['grep', 'ssh']) # re_pid = re.compile("\d+") # re_name = re.compile("ssh.*") for proc in ssh_proc: if command_relay in proc: module_logger.debug("Found matching process: {}".format(proc)) # proc_id = int(re_pid.findall(proc)[0]) # proc_name = re_name.findall(proc)[0] return BasicProcess(ps_line=proc, command_name='ssh') # return BasicProcess(name=proc_name, pid=proc_id) module_logger.debug("Invoking command {}".format(command)) p = invoke(command) return p