Programming Forums
User Name Password Register
 

RSS Feed
FORUM INDEX | TODAY'S POSTS | UNANSWERED THREADS | ADVANCED SEARCH

Reply
 
Thread Tools Display Modes
Old Mar 31st, 2006, 4:54 PM   #1
Sane
Programming Guru
 
Sane's Avatar
 
Join Date: Apr 2005
Location: Waterloo, Ontario
Posts: 2,086
Rep Power: 6 Sane will become famous soon enough
Send a message via MSN to Sane
FTP Server in Python

For Linux class I had to code a server FTP host in Python 2.3.4 for Knoppix. I've got quite a few commands working nicely, but something goes wrong after sending the LIST of files from the folder (right now it's a sample list for testing). The client doesn't respond to the sent item, even though it goes through. Anything more I send to it doesn't reply to, and I can't recieve anything from either ports. I'm stuck in a dead lock.

I assume it has something to do with the format of the file list. It may also have to do with what port I'm sending the file list from, although I know I send it to the connected passive port.

If you aren't familiar in detail with how the Passive FTP system works, please don't guess your way in to a simple response. It's going to be something about an incorrect address or port dealing with how the FTP server interacts with the client (from which there is very little documentation ).


import socket
import os


class ftp_server:

    def __init__(self):

        self.host = '10.174.28.135'
        self.passive_port = 7214

        self.log("""
  -------------------------------
  -- FTPy FTP Server in Python --
  -------------------------------
  
Parses raw socket connections to
    simulate the FTP environment. 

    
 Passive FTP for Knoppix Linux:
     command : client >1023 -> server 21
     data    : client >1023 -> server >1023

    
Programmed by Aaron Voelker.

Initiating server...""")

        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.bind(('', 21))
        self.sock.listen(1)

        a = self.passive_port/256
        b = self.passive_port%256
        self.tuple_port = (a, b)
        self.host_join = ','.join(self.host.split('.'))
        self.passive = False

        self.log("Server initiated.")

    def log(self, msg):
        print msg

    def get(self):
        return self.conn.recv(1024).replace('\r', '').replace('\n', '')

    def getcwd(self):
        return os.getcwd().split(chr(92))[-1]

    def put(self, ftr):
        x = {

            150:" Data connection accepted from %s:%s; transfer starting.\r\n226 Listing completed."%(self.host, self.passive_port),
            200:" Type okay.",
            220:" %s FTPy Server (Aaron Voelker) ready."%self.host,
            226:" Listing completed.",
            227:" Entering Passive Mode (%s,%s,%s)"%(self.host_join, self.tuple_port[0], self.tuple_port[1]),
            230:" User logged in, proceed.",
            250:' "/%s" is new cwd.'%self.getcwd(), 
            257:' "/%s" is cwd.'%self.getcwd(),
            331:" User name okay, need password.",
            502:" Command not implemented.",
            551:" Requested action aborted. Page type unknown." 
            
                   }[ftr]

        s = '%s%s\r\n'%(ftr, x)
        self.conn.send(s)
        return s
   
    def main(self):
        self.log("Awaiting a connection...\n")
        self.conn, addr = self.sock.accept ()
        self.log("Connection created by %s.\nEstablishing session."%addr[0])
        self.put(220)
        self.log("\nStarting Instruction Loop.")

        while 1:
            # if self.passive:
            #     try:
            #         data = self.conn2.recv(1024)
            #         print data
            #     except socket.error:
            #         pass 

                
            try: 
                data = self.get().upper()
            except socket.error:
                self.log("\n-- Connection Reset, shutting down FTP.\n ")
                self.conn.close()
                self.sock.shutdown(socket.SHUT_RDWR)
                raise socket.error
                
            self.log(" >>> %s"%data) 

            if data[:4] == 'USER':   s = 331
            elif data[:4] == 'PASS': s = 230
            elif data[:3] == 'PWD':  s = 257
            elif data[:4] == 'TYPE':
                s = 200
                # self.type = data.split(' ')[-1]
            elif data[:4] == 'PASV':
                # create passive port
                self.sock2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                self.sock2.bind(('', self.passive_port ))
                self.sock2.listen(1)
                # self.sock2.settimeout(1)
                s = self.put(227)
                self.log(" <<< %s"%s)
                self.log("     [Connecting to passive port %s]"%self.passive_port)
                self.conn2, addr = self.sock2.accept()
                self.passive = True
                self.log("     [Connected]\n") 
                s = 0 # don't routine
      
            elif data[:3] == 'CWD':
                try:
                    os.chdir('..%s'%data.split(' ')[-1])
                    s = 250
                except OSError: 
                    s = 551
            elif data[:4] == 'LIST':
                s = self.put(150)
                self.log(" <<< %s"%s)

                s = self.passive_do(1)
                self.log(" >>> %s"%s)

                # s = self.put(226)
                # self.log(" >>> %s"%s)

                # print "<<< "+ self.conn2.recv(1024)

                s = 0 # don't routine
            else:                    s = 502
    
            if s:
                s = self.put(s)
                self.log(" <<< %s"%s)

    def passive_do(self, id):

        if id == 1:
            res = """drwxr-xr-x   5 ftpuser  ftpusers       512 Jul 26  2001 bladerunner\r\ndrwxr-xr-x   5 ftpuser  ftpusers       512 Jul 26  2001 cc1\r\ndrwxr-xr-x   5 ftpuser  ftpusers       512 Jul  4  2002 ccgold\r\ndrwxr-xr-x   5 ftpuser  ftpusers       512 Jul 26  2001 dune2\r\ndrwxr-xr-x   6 ftpuser  ftpusers       512 Jul 26  2001 dune2000\r\ndrwxr-xr-x   6 ftpuser  ftpusers       512 Oct  8  2002 earthandbeyond\r\ndrwxr-xr-x   8 ftpuser  ftpusers       512 Jul  4  2002 emperor\r\ndrwxr-xr-x   3 ftpuser  ftpusers       512 Jul 26  2001 firestorm\r\ndrwxr-xr-x   4 ftpuser  ftpusers       512 Jan 29  2003 generals\r\ndrwxr-xr-x   4 ftpuser  ftpusers       512 Jul 26  2001 kyrandia1\r\ndrwxr-xr-x   4 ftpuser  ftpusers       512 Jul 26  2001 kyrandia2\r\ndrwxr-xr-x   4 ftpuser  ftpusers       512 Jul 26  2001 kyrandia3\r\ndrwxr-xr-x   4 ftpuser  ftpusers       512 Jul 26  2001 lands1\r\ndrwxr-xr-x   4 ftpuser  ftpusers       512 Jul 26  2001 lands2\r\ndrwxr-xr-x   4 ftpuser  ftpusers       512 Jul 26  2001 lands3\r\ndrwxr-xr-x   3 ftpuser  ftpusers       512 Jul 26  2001 lionking\r\ndrwxr-xr-x   3 ftpuser  ftpusers       512 Jul 26  2001 macintosh\r\ndrwxr-xr-x   7 ftpuser  ftpusers       512 Jul 26  2001 monopoly\r\ndrwxr-xr-x   7 ftpuser  ftpusers       512 Jul 26  2001 nox\r\ndrwxr-xr-x   3 ftpuser  ftpusers       512 Jun 27  2002 pirates\r\ndrwxr-xr-x   3 ftpuser  ftpusers       512 Jul 26  2001 recoil\r\ndrwxr-xr-x   6 ftpuser  ftpusers       512 Jul 26  2001 redalert\r\ndrwxr-xr-x   9 ftpuser  ftpusers       512 Apr  3  2002 redalert2\r\ndrwxr-xr-x   7 ftpuser  ftpusers       512 Jan 29  2003 renegade\r\ndrwxr-xr-x   2 ftpuser  ftpusers       512 Oct 10  2002 support\r\n-rw-r--r--   1 ftpuser  ftpusers         0 Nov 16  2004 test\r\ndrwxr-xr-x   6 ftpuser  ftpusers       512 Jul 26  2001 tiberiansun\r\n-rw-r--r--   1 ftpuser  ftpusers      2368 Sep 22  2004 version.txt\r\ndrwxr-xr-x   2 ftpuser  ftpusers       512 Mar  4  2003 wchat\r\ndrwxr-xr-x   3 ftpuser  ftpusers       512 Aug 23  2001 youngmerlin\r\nTotal of 11 Files, 10966 Blocks.\r\n"""

        self.conn2.send(res)
        # self.conn2.send('\r\n') # send blank
        return res

                
while 1:       
    try:
        ftp_server().main()
    except socket.error:
        print "Rebooting server...\n"
Sane is offline   Reply With Quote
Old Mar 31st, 2006, 11:25 PM   #2
Sane
Programming Guru
 
Sane's Avatar
 
Join Date: Apr 2005
Location: Waterloo, Ontario
Posts: 2,086
Rep Power: 6 Sane will become famous soon enough
Send a message via MSN to Sane
Here's an example log of the updated source

  -------------------------------
  -- FTPy FTP Server in Python --
  -------------------------------
  
Parses raw socket connections to
    simulate the FTP environment. 

    
 Passive FTP for Knoppix Linux:
     command : client >1023 -> server 21
     data    : client >1023 -> server >1023

    
Programmed by Aaron Voelker.

Initiating server...
Server initiated.
Awaiting a connection...

Connection created by 127.0.0.1.
Establishing session.

Starting Instruction Loop.
 >>> USER ANONYMOUS
 <<< 331 User name okay, need password.


 >>> PASS IEUSER@
 <<< 230 User logged in, proceed.


 >>> OPTS UTF8 ON
 <<< 502 Command not implemented.


 >>> PWD
 <<< 257 "/python" is cwd.


 >>> CWD /PYTHON/
 <<< 250 "/PYTHON" is new cwd.


 >>> TYPE A
 <<< 200 Type okay.


 >>> PASV
 <<< 227 Entering Passive Mode (127,0,0,1,9,227)


     [Connecting to passive port 2531]
     [Connected]

 >>> LIST
 <<< 150 Data connection accepted from 192.168.0.136:2531; transfer starting.


 <<< drwxr-xr-x   5 ftpuser  ftpusers       512 Jul 26  2001 bladerunner

drwxr-xr-x   5 ftpuser  ftpusers       512 Jul 26  2001 cc1

drwxr-xr-x   5 ftpuser  ftpusers       512 Jul  4  2002 ccgold

drwxr-xr-x   5 ftpuser  ftpusers       512 Jul 26  2001 dune2

drwxr-xr-x   6 ftpuser  ftpusers       512 Jul 26  2001 dune2000

drwxr-xr-x   6 ftpuser  ftpusers       512 Oct  8  2002 earthandbeyond

drwxr-xr-x   8 ftpuser  ftpusers       512 Jul  4  2002 emperor

drwxr-xr-x   3 ftpuser  ftpusers       512 Jul 26  2001 firestorm

drwxr-xr-x   4 ftpuser  ftpusers       512 Jan 29  2003 generals

drwxr-xr-x   4 ftpuser  ftpusers       512 Jul 26  2001 kyrandia1

drwxr-xr-x   4 ftpuser  ftpusers       512 Jul 26  2001 kyrandia2

drwxr-xr-x   4 ftpuser  ftpusers       512 Jul 26  2001 kyrandia3

drwxr-xr-x   4 ftpuser  ftpusers       512 Jul 26  2001 lands1

drwxr-xr-x   4 ftpuser  ftpusers       512 Jul 26  2001 lands2

drwxr-xr-x   4 ftpuser  ftpusers       512 Jul 26  2001 lands3

drwxr-xr-x   3 ftpuser  ftpusers       512 Jul 26  2001 lionking

drwxr-xr-x   3 ftpuser  ftpusers       512 Jul 26  2001 macintosh

drwxr-xr-x   7 ftpuser  ftpusers       512 Jul 26  2001 monopoly

drwxr-xr-x   7 ftpuser  ftpusers       512 Jul 26  2001 nox

drwxr-xr-x   3 ftpuser  ftpusers       512 Jun 27  2002 pirates

drwxr-xr-x   3 ftpuser  ftpusers       512 Jul 26  2001 recoil

drwxr-xr-x   6 ftpuser  ftpusers       512 Jul 26  2001 redalert

drwxr-xr-x   9 ftpuser  ftpusers       512 Apr  3  2002 redalert2

drwxr-xr-x   7 ftpuser  ftpusers       512 Jan 29  2003 renegade

drwxr-xr-x   2 ftpuser  ftpusers       512 Oct 10  2002 support

-rw-r--r--   1 ftpuser  ftpusers         0 Nov 16  2004 test

drwxr-xr-x   6 ftpuser  ftpusers       512 Jul 26  2001 tiberiansun

-rw-r--r--   1 ftpuser  ftpusers      2368 Sep 22  2004 version.txt

drwxr-xr-x   2 ftpuser  ftpusers       512 Mar  4  2003 wchat

drwxr-xr-x   3 ftpuser  ftpusers       512 Aug 23  2001 youngmerlin


 <<< 226 Listing completed.

And here's the updated source:

import socket
import os


class ftp_server:

    def __init__(self):

        self.host = '192.168.0.136'
        self.passive_port = 2531

        self.log("""
  -------------------------------
  -- FTPy FTP Server in Python --
  -------------------------------
  
Parses raw socket connections to
    simulate the FTP environment. 

    
 Passive FTP for Knoppix Linux:
     command : client >1023 -> server 21
     data    : client >1023 -> server >1023

    
Programmed by Aaron Voelker.

Initiating server...""")

        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.bind(('', 21))
        self.sock.listen(1)

        a = self.passive_port/256
        b = self.passive_port%256
        self.tuple_port = (a, b)
        self.host_join = ','.join(self.host.split('.'))
        self.passive = False

        self.log("Server initiated.")

    def log(self, msg):
        f = open("logs.txt", "a")
        f.write(msg+'\n')
        f.close()

    def get(self):
        return self.conn.recv(1024).replace('\r', '').replace('\n', '')

    def getcwd(self):
        return os.getcwd().split(chr(92))[-1]

    def put(self, ftr):
        x = {

            150:" Data connection accepted from %s:%s; transfer starting."%(self.host, self.passive_port),
            200:" Type okay.",
            220:" %s FTPy Server (Aaron Voelker) ready."%self.host,
            226:" Listing completed.",
            227:" Entering Passive Mode (%s,%s,%s)"%(self.addr_join, self.tuple_port[0], self.tuple_port[1]),
            230:" User logged in, proceed.",
            250:' "/%s" is new cwd.'%self.getcwd(), 
            257:' "/%s" is cwd.'%self.getcwd(),
            331:" User name okay, need password.",
            502:" Command not implemented.",
            551:" Requested action aborted. Page type unknown." 
            
                   }[ftr]

        s = '%s%s\r\n'%(ftr, x)
        self.conn.send(s)
        return s
   
    def main(self):
        self.log("Awaiting a connection...\n")
        self.conn, self.addr = self.sock.accept ()
        self.addr_join = ','.join(self.addr[0].split('.'))
        
        self.log("Connection created by %s.\nEstablishing session."%self.addr[0])
        self.put(220)
        self.log("\nStarting Instruction Loop.")

        while 1:
            # if self.passive:
            #     try:
            #         data = self.conn2.recv(1024)
            #         print data
            #     except socket.error:
            #         pass 

                
            try: 
                data = self.get().upper()
            except socket.error:
                self.log("\n-- Connection Reset, shutting down FTP.\n ")
                self.conn.close()
                self.sock.shutdown(socket.SHUT_RDWR)
                if self.passive:
                    self.conn2.close()
                    self.sock2.shutdown(socket.SHUT_RDWR)                    
                raise socket.error
                
            self.log(" >>> %s"%data) 

            if data[:4] == 'USER':   s = 331
            elif data[:4] == 'PASS': s = 230
            elif data[:3] == 'PWD':  s = 257
            elif data[:4] == 'TYPE':
                s = 200
                # self.type = data.split(' ')[-1]
            elif data[:4] == 'PASV':
                # create passive port
                self.sock2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                self.sock2.bind((self.addr[0], self.passive_port))
                self.sock2.listen(1)
                # self.sock2.settimeout(1)
                s = self.put(227)
                self.log(" <<< %s"%s)
                self.log("     [Connecting to passive port %s]"%self.passive_port)
                self.conn2, addr = self.sock2.accept()
                self.passive = True
                self.log("     [Connected]\n") 
                s = 0 # don't routine
      
            elif data[:3] == 'CWD':
                try:
                    os.chdir('..%s'%data.split(' ')[-1])
                    s = 250
                except OSError: 
                    s = 551
            elif data[:4] == 'LIST':
                s = self.put(150)
                self.log(" <<< %s"%s)

                s = self.passive_do(1)
                self.log(" <<< %s"%s)

                s = self.put(226)
                self.log(" <<< %s"%s)

                # print "<<< "+ self.conn2.recv(1024)

                s = 0 # don't routine
            else:                    s = 502
    
            if s:
                s = self.put(s)
                self.log(" <<< %s"%s)

    def passive_do(self, id):

        if id == 1:
            res = """drwxr-xr-x   5 ftpuser  ftpusers       512 Jul 26  2001 bladerunner\r\ndrwxr-xr-x   5 ftpuser  ftpusers       512 Jul 26  2001 cc1\r\ndrwxr-xr-x   5 ftpuser  ftpusers       512 Jul  4  2002 ccgold\r\ndrwxr-xr-x   5 ftpuser  ftpusers       512 Jul 26  2001 dune2\r\ndrwxr-xr-x   6 ftpuser  ftpusers       512 Jul 26  2001 dune2000\r\ndrwxr-xr-x   6 ftpuser  ftpusers       512 Oct  8  2002 earthandbeyond\r\ndrwxr-xr-x   8 ftpuser  ftpusers       512 Jul  4  2002 emperor\r\ndrwxr-xr-x   3 ftpuser  ftpusers       512 Jul 26  2001 firestorm\r\ndrwxr-xr-x   4 ftpuser  ftpusers       512 Jan 29  2003 generals\r\ndrwxr-xr-x   4 ftpuser  ftpusers       512 Jul 26  2001 kyrandia1\r\ndrwxr-xr-x   4 ftpuser  ftpusers       512 Jul 26  2001 kyrandia2\r\ndrwxr-xr-x   4 ftpuser  ftpusers       512 Jul 26  2001 kyrandia3\r\ndrwxr-xr-x   4 ftpuser  ftpusers       512 Jul 26  2001 lands1\r\ndrwxr-xr-x   4 ftpuser  ftpusers       512 Jul 26  2001 lands2\r\ndrwxr-xr-x   4 ftpuser  ftpusers       512 Jul 26  2001 lands3\r\ndrwxr-xr-x   3 ftpuser  ftpusers       512 Jul 26  2001 lionking\r\ndrwxr-xr-x   3 ftpuser  ftpusers       512 Jul 26  2001 macintosh\r\ndrwxr-xr-x   7 ftpuser  ftpusers       512 Jul 26  2001 monopoly\r\ndrwxr-xr-x   7 ftpuser  ftpusers       512 Jul 26  2001 nox\r\ndrwxr-xr-x   3 ftpuser  ftpusers       512 Jun 27  2002 pirates\r\ndrwxr-xr-x   3 ftpuser  ftpusers       512 Jul 26  2001 recoil\r\ndrwxr-xr-x   6 ftpuser  ftpusers       512 Jul 26  2001 redalert\r\ndrwxr-xr-x   9 ftpuser  ftpusers       512 Apr  3  2002 redalert2\r\ndrwxr-xr-x   7 ftpuser  ftpusers       512 Jan 29  2003 renegade\r\ndrwxr-xr-x   2 ftpuser  ftpusers       512 Oct 10  2002 support\r\n-rw-r--r--   1 ftpuser  ftpusers         0 Nov 16  2004 test\r\ndrwxr-xr-x   6 ftpuser  ftpusers       512 Jul 26  2001 tiberiansun\r\n-rw-r--r--   1 ftpuser  ftpusers      2368 Sep 22  2004 version.txt\r\ndrwxr-xr-x   2 ftpuser  ftpusers       512 Mar  4  2003 wchat\r\ndrwxr-xr-x   3 ftpuser  ftpusers       512 Aug 23  2001 youngmerlin\r\n"""

        self.conn2.send(res)
        # self.conn2.send('\r\n') # send blank
        return res

                
while 1:       
    try:
        ftp_server().main()
    except socket.error:
        print "Rebooting server...\n"

But I still can't quite get it to work. It must be something about the wrong ports. Yes, the file list is sent through the passive port after attaining a connection.
Sane is offline   Reply With Quote
Reply

Bookmarks

« Previous Thread in Forum | Next Thread in Forum »

Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump




DaniWeb IT Discussion Community
All times are GMT -5. The time now is 1:13 AM.

Powered by vBulletin® Version 3.7.0, Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Copyright ©2007 DaniWeb® LLC