ssh tunneling vs dynamic dns

Nick Demou ndemou at gmail.com
Wed Oct 26 16:47:32 EEST 2011


2011/10/26 Antonis Christofides <anthony at itia.ntua.gr>:
> Γεια σας,
>
> θυμάμαι ότι παλιά είχα φτιάξει ένα μηχάνημα (A) πίσω από adsl να
> διατηρεί ανοιχτή μια σύνδεση ssh με ένα server (B) και να την
> ξανασηκώνει αν πέσει, η οποία σύνδεση προσέφερε κι ένα τουνελάκι για
> μπορώ να κάνω ssh στο A μέσω του Β. Η λύση αυτή δούλευε ωραία και
> αξιόπιστα.
>
> Σε σχέση με το dynamic dns τι σας λέει;

dynamic dns
  μειονέκτημα: πρέπει να ανοίξεις πόρτες στο adsl modem
  μειονέκτημα: από τις ανοιχτές πόρτες θα προσπαθούν να μπουν και άλλοι
  πλεονέκτημα: εκτός από το να ανοίξεις πόρτες δεν έχεις να κάνεις τίποτα άλλο

Πριν ~2 χρόνια είχα γράψει ένα python script  για τη λύση χωρίς
dynamic dns. Σε ένα pc έπαιζε σταθερά επί πολλούς μήνες. Here it is
(απαιτεί το pexpet[1]):

#! /usr/bin/python
# This program allows someone else to access the ssh daemon (or any
other TCP service)
# running on your PC even if it is behind a firewall
# THAT SOMEONE ELSE CAN DO NASTY THINGS WITH YOUR PC - you've been warned
# see 'Usage' below (or run it without parameters) for more info
#
#
# # This is how I install it in my friends (I paste the commands
bellow in pastebin.com for them):
#   SERVER=x.y.z
#   ls ~/.ssh/known_hosts > /dev/null && grep -v $SERVER
~/.ssh/known_hosts > /tmp/foo3029 && cat /tmp/foo3029 >
~/.ssh/known_hosts && rm -f /tmp/foo3029 && echo "OK 1"
#   wget -q -O pexpect.py www.enlogic.gr/other/pexpect.py && wget -q
-O remote.py  www.enlogic.gr/other/remote.py && echo "OK 2"
#   PORT=ssh_port_of_the_server
#   USER=user_name
#   PASWD=the_password
#   kill -9 `ps ax | grep ssh.*$USER@$SERVER | grep -v grep | cut -d\  -f1`
#   python remote.py 22225 $SERVER $PORT "" $USER $PASWD 22 2
#
# and if there is any problem I replace 2 with 3
#
# # and some ubuntu/debian tips:
# # ...to install both the ssh client and the ssh server
# sudo apt-get install ssh
# # ...to install only the ssh client
# sudo apt-get install openssh-client


import pexpect,time,sys,re,commands

#=============================CONFIGURATION================================

# various timeouts
ConnectTimeout=20
NormalTimeout=5
ResponseTimeOut=0.5

#===========================================================================


def debug(s,level=2):
    global Verbosity
    if level<=Verbosity:
        print "***INFO : %s"%(s)

def errmsg(s):
    sys.stderr.write( "***ERROR: %s\n"%(s) )

def wait(t,msg):
    debug(msg)
    time.sleep(t)

# todo: maybe kill leftover ssh connections to the remotehost that may
block this port forwarding
#       e.g. take the output of "ps ax" and find lines with
"%s:localhost:%s"%(MhFreePort,FhSshdPort)
#            these are processes you MOST LIKELY must kill

def main():
    global Verbosity
    if len(sys.argv)<>9 and len(sys.argv)<>1:
        print "ERROR: not enough parameters (run me with no parameters
to get help on usage)"
        print len(sys.argv)
        return

    if len(sys.argv)==1:
        print """Usage:
%s MasterHost MhSshdPort Fh2MhSshOptions MhUserName MhPassword
MhFreePort FhSshdPort Verbosity

    This program allows someone else to ssh to your PC even if it is
behind a firewall

    Here is a typical case:
    You have a host behind a firewall that allows NO incoming
connection (Firewalled Host -- FH)
    and you have a Master Host (MH) from where you want to connect to
the Firewalled Host
    and the Master Host CAN ACCEPT SSH CONNECTIONS
    You arange for this script to be running in FH and you can connect
from MH by issuing
    this command:
       ssh -p MhFreePort user at localhost

    You should have a user with a dummy shell setup in MH just to
accept the ssh connection.
    Here is a bash script for the dummy shell. This shell prints a
line containing the magic
    word 'quit' that this script expects to recieve whenever you type anything:

        #!/bin/bash
        while read BUFFER; do
            echo "echo type quit[ENTER] to quit"
            if [ "$BUFFER" = "quit" ]; then break; fi
        done

    So in MH create a user and set his shell to be the bash script above.
    (here is an example from my /etc/passwd
        remote:x:520:520::/home/remote:/opt/dummyshell.sh
    )

    This script strives to keep an open ssh connection from FH to MH.

    The Firewalled Host should run ssh listening to localhost:FhSshdPort
    On Master Host, TCP Port locahost:MhFreePort should by free (not
bind to something else)

    LIST OF PARAMETERS IN ORDER OF APEARENCE
    ----------------------------------------
    (regarding master host)
        MhFreePort   (picking a random port from 30000-65000 is usualy OK)

    (regarding the ssh conection from FH 2 MH)
        MasterHost
        MhSshdPort (typicaly 22)
        Fh2MhSshOptions
        MhUserName
        MhPassword

    (regarding free host)
        FhSshdPort (typicaly 22)

    (verbosity see bellow for info)
        Verbosity

    MORE DETAILS
    ------------
    Regarding the verbosity option:
       0=only errors
       1=errors and some important messages (started/connected/disconnected)
       2=most debug messages (i.e. everything except row output from
ssh session)
       3=all messages
"""%(sys.argv[0]).split("/")[-1]
        return
    else:
        try:
            # regarding master host
            MhFreePort=int(sys.argv[1])

            # regarding the ssh conection from FH --> MH
            MasterHost=sys.argv[2]
            MhSshdPort=int(sys.argv[3])
            Fh2MhSshOptions=sys.argv[4]
            MhUserName=sys.argv[5]
            MhPassword=sys.argv[6]

            # regarding free host
            FhSshdPort=int(sys.argv[7])

            # verbosity:
            Verbosity=int(sys.argv[8])
        except:
            errmsg("Invalid value in parameter")


    # build the ssh command
    sshcmd="ssh -p %s -o'RSAAuthentication=no'
-o'PubkeyAuthentication=no' %s -R %s:localhost:%s
%s@%s"%(MhSshdPort,Fh2MhSshOptions,MhFreePort,FhSshdPort,MhUserName,MasterHost)

    # start an endless loop of ssh connection attempts
    while 1:

        debug("Trying to connect with command: "+sshcmd)

        # first try to spawn an ssh command
        try:
            child = pexpect.spawn (sshcmd)
            if Verbosity>=3: child.logfile = sys.stdout
        except  KeyboardInterrupt:
            debug("ABORTING due to KeyboardInterrupt")
            break
        except:
            errmsg("failed to spawn ssh")
            wait(5,"waiting before retrying")
        else:

            debug("ssh started (but we're not yet connected)",1)

            # ssh spawned, wait for MhPassword
            try:
                i = child.expect(['assword:', 'yes/no', 'Offending key
in'],ConnectTimeout)
            except  KeyboardInterrupt:
                debug("ABORTING due to KeyboardInterrupt")
                break
            except:
                errmsg("failed expecting Password or accept key")
            else:
                if i==0:
                    debug("sending Password")
                    child.sendline(MhPassword)
                elif i==1:
                    debug("sending a 'yes' answer")
                    child.sendline("yes")
                    debug("sending Password")
                    child.expect("assword:", NormalTimeout)
                    child.sendline(MhPassword)
                elif i==2:
                    errmsg("Please fix your known_hosts file to get
rid of the following error: \n\n%s" % child.before)
                    break

                # MhPassword sent, wait for prompt
                try:
                    i = child.expect(['Last login'],NormalTimeout)
                except  KeyboardInterrupt:
                    debug("ABORTING due to KeyboardInterrupt")
                    break
                except:
                    errmsg("failed expecting 'last login' prompt")
                else:

                    # all done, start an endless ping
                    debug("Connected to Firewalled Host",1)

                    while child.isalive()==1:
                        child.sendline('ping')
                        debug("sent command")

                        # expect a standard response
                        ExpectedResponse='quit'
                        try:
                            child.expect(ExpectedResponse,ResponseTimeOut)
                            response=child.after
                        except  KeyboardInterrupt:
                            debug("ABORTING due to KeyboardInterrupt")
                            break
                        except:
                            response=0

                        if response==ExpectedResponse:
                            debug("got proper answer")
                            wait(10,"waiting 10secs before next ping")
                        elif response==0:
                            errmsg("Ping timed out (no response from
remote machine)")
                            break
                        else:
                            errmsg("bad response from remote
machine:%s"%(response))
                            break

                    # either a bad response or a time out

                    # close the connection if needed
                    if child.isalive():
                        debug("ABORTING SESSION (stoping ssh)",1)
                        child.close()
                    else:
                        debug("ABORTING SESSION (ssh process has terminated)",1)

                    # wait before retrying to connect
                    wait(10,"Waiting 10secs before retrying ssh")

    errmsg("Terminated")

main()





____________
[1] Pexpect is a Python module for spawning child applications and
controlling them automatically...



More information about the Linux-greek-users mailing list