Commit 60567f9cf7ffe3c4fcbbd78b24480db385dd7f5f

  • avatar
  • Giovanni Misitano <gialmisi @stu…nt.jyu.fi> (Committer)
  • Wed Jan 16 03:32:54 EET 2019
  • avatar
  • Giovanni Misitano <gialmisi @stu…nt.jyu.fi> (Author)
  • Wed Jan 16 03:32:54 EET 2019
FTP client almost ready. Switched to bftpd ftp-server for testing due to strange behavior of LIST when using vsftpd.
file/ftpclient.py
(157 / 1)
  
1111import socket
1212import re
1313import threading
14import getpass
1415
1516
17def control_connection(ip, port, bsize):
18 control = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
19
20 try:
21 control.connect((ip, port))
22 except:
23 print("Could not connect to the ftp-server on {}:{}".format(ip, port))
24 return "Connection refused on {}:{}".format(ip, port)
25
26 states = ["AUTHORIZATION_1", "AUTHORIZATION_2", "LOGGED_IN"]
27
28 # Check initial connection to be ok
29 response = get_response_array(control, bsize)
30 if response is not None and len(response) > 1 and response[0] == "220":
31 print("Connection successful!")
32 else:
33 print("Could not connect to the ftp-server on {}:{}".format(ip, port))
34 return "FTP service not available!"
35
36 state = "AUTHORIZATION_1"
37
38 # Main loop
39 while True:
40 if state == "AUTHORIZATION_1":
41 username = input("Username:")
42
43 send_to_socket(control, "USER {}\r\n".format(username))
44 response = get_response_array(control, bsize)
45
46 if response and len(response) > 1 and response[0] == "331":
47 print("Username ok. Give password.")
48 state = "AUTHORIZATION_2"
49 else:
50 print("Username {} not valid.".format(username))
51
52 elif state == "AUTHORIZATION_2":
53 password = getpass.getpass()
54
55 send_to_socket(control, "PASS {}\r\n".format(password))
56 response = get_response_array(control, bsize)
57
58 if response and len(response) > 1 and response[0] == "230":
59 print("Login successful.")
60 print_help()
61 state = "LOGGED_IN"
62 else:
63 print("Login incorrect!".format(username))
64 state = "AUTHORIZATION_1"
65
66 elif state == "LOGGED_IN":
67 query = parse_query(input(">"))
68
69 if not query:
70 print("Bad command.")
71
72 elif query[0] in ['q', 'quit']:
73 print("Quitting...")
74 break
75
76 elif query[0] in ['h', 'help']:
77 print_help()
78
79 elif query[0] in ['l', 'list']:
80 print("Requesting directory list.")
81
82 send_to_socket(control, "PASV\r\n")
83 response = get_response_array(control, bsize)
84 print(response)
85
86 if response and response[0] == '227':
87 # foramt of response '(ip,ip,ip,ip,port,port)'
88 ip_and_port = eval(response[-1])
89 dataport = bit_decimals_to_port(ip_and_port[-2], ip_and_port[-1])
90
91 print("Server is listening on port {}".format(dataport))
92
93 data = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
94
95 try:
96 data.connect((ip, dataport))
97 except:
98 print("Could not connect to the ftp-server on {}:{}".format(ip, port))
99 data = None
100
101 if data:
102 send_to_socket(control, "LIST\r\n")
103 response = get_response_array(control, bsize)
104 print(response)
105
106 response = get_response_array(data, bsize)
107
108 print(response)
109
110 response = get_response_array(control, bsize)
111
112 print(response)
113
114
115
116
117
118
119 control.close()
120 return "All fine"
121
122
123def port_to_bit_decimals(port):
124 whole = '{0:016b}'.format(port)
125 upper = int(whole[0:8], 2)
126 lower = int(whole[8:], 2)
127
128 return upper, lower
129
130
131def bit_decimals_to_port(upper, lower):
132 whole = '{0:08b}'.format(upper) + '{0:08b}'.format(lower)
133 whole = int(whole, 2)
134
135 return whole
136
137
138def get_response_array(sock, bsize):
139 """Splits a response into a string array."""
140 data = sock.recv(bsize)
141
142 if data == b'':
143 return None
144
145 data_s = (str(data.strip(), 'utf-8'))
146 data_s = data_s.split()
147
148 return data_s
149
150
151def send_to_socket(sock, string):
152 sock.send(bytes(string, 'utf-8'))
153 return
154
155def parse_query(query):
156 if not query:
157 return None
158
159 return query.lower().split()
160
161def print_help():
162 print("FTP ready!")
163 print("Supported commands:")
164 print("\tl, pasv \t\t Request directory listing.")
165 print("\th, help \t\t Print this help message.")
166 print("\tq, quit \t\t Close the connection to the server and quit.")
167
16168def main(ip, port):
17 print("{}:{}".format(ip, port))
169 bsize = 1024
170 print(bit_decimals_to_port(125, 99))
171 print("{}:{}".format(ip, port, bsize))
172
173 control_connection(ip, port, bsize)
18174 return
19175
20176