This module defines the Ftp proxy interface as implemented by the Ftp proxy module.
from Plug import PlugProxy
from Proxy import Proxy, Proxy
Module defining classes encapsulating native proxies.
from Session import StackedSession
Module defining session related classes and functions.
from SockAddr import SockAddrInet, SockAddrInetRange
Module implementing SockAddr handling functions.
from Stream import Stream
Module exporting an interface to the Zorp.Stream component.
from Zorp import *
Module defining global constants, and interface entry points to the Zorp core.
This class ensures one way data connections by setting the appropriate copy_to_* variable in Plug.
By default deny everything, but data connection establishment. You should dervice your customized Ftp proxy classes in order to do something useful.
This section contains basic usage patterns, you as an administrator may need to do.
All requests are denied in the low level proxy implementation by default. To enable different commands and answers you'll need to extend the low-level proxy in Python. To see how this is done, see the next two sections.
Changing the default behaviour of commands can be done using the hash named "command". This hash is indexed by the command name (e.g: USER or PWD), and each item in this hash is an action tuple, defining proxy behaviour for the given command.
The first item in this tuple is an integer value, determining the action to take, and also the interpretation of the remaining items in the tuple.
Possible values for the first item:
Example 4-3. Sample for anonymous only sessions in FTP
class AnonFtp(FtpProxy):
def config(self):
self.fw_server_data.ip_s="192.168.0.1"
self.fw_client_data.ip_s="10.0.0.1"
self.commands["USER"] = (Ftp.FTP_CMD_POLICY, self.pUser)
self.commands["*"] = (Ftp.FTP_CMD_ACCEPT)
def pUser(self,command):
if self.request_parameter == "ftp" or self.request_parameter == "anonymous":
return Z_ACCEPT
return Z_DENY
Like with commands, we have a hash for answers as well. This hash indexed by command concatenated with answer, and contains an action tuple in each item. A special wildcard character * matches every command. Another feature is that you don't need to write the full answer code, it's possible to write only the first, or the first two digits.
For example, all three index below is valid:
Table 4-35. Untitled
PWD200 | Match exactly the answer 200 coming in reply to a PWD command. |
PWD2 | Match every answer starting with 2 in reply to a PWD command. |
*20 | Match every answer between 200 and 209 in reply to any command. |
All answers are "denied" default. It's changed to "500 Error parsing answer", because dropping an answer is not permitted by RFC959. You may enable all answers with "*".
The precedence in processing hashtable entries is the following:
1. Exact match. (PWD200)
2. Exact command match, partial answer matches (PWD20, PWD2, PWD)
3. Wildcard command, with answer codes repeated as above. (*200, *20, *2, *)
Possible values for the first item in the action tuple:
Table 4-36. Untitled
FTP_ANS_ACCEPT | allow answer without modification. |
FTP_ANS_CHANGE | change answer code and message. (default) Second parameter contains a string, which will be sent back to client. |
FTP_ANS_POLICY | call a Python function to decide what to do. this value uses an additional parameter, which must be a callable Python function. The function takes three parameters: self, command, answer |
FTP_ANS_ABORT | deny request, and drop conection. |
Table 4-37. Attributes for class FtpProxy
data_connect | Object for the data connection |
data_proxy | proxy to use for data connections |
data_port_min | ports should be allocated above this variable |
data_port_max | ports should be allocated below this variable |
data_mode | FTP_DATA_KEEP, FTP_DATA_PASSIVE or FTP_DATA_ACTIVE can be used to force a connection type in server side. (default: FTP_DATA_KEEP) |
transparent_mode | (logical) TRUE for transparent proxy, FALSE otherwise (default: TRUE) |
fw_server_data | (ZorpSocket) Firewall address in server side. By default it contains the IP address of the interface towards the server. |
fw_client_data | (ZorpSocket) Firewall address in client side. By default it contains the IP address of the interface towards the client. |
permit_unknown_command | (boolean) Enable commands not understood (and not handled) by proxy. (Default: FALSE) |
permit_empty_command | (boolean) Enable lines without commands. (Default: FALSE) |
max_line_length | (integer) Maximum line lenght, what a proxy may transfer. (Default: 255) |
max_username_length | (integer) Maximum length of usernames. (Default: 32) |
max_password_length | (integer) Maximum length of passwords. (Default: 64) |
commands | (hash) normative policy hash, directing the proxy to do something with requests, without the need to call Python. indexed by the command (e.g. "USER", "PWD" etc) (default: empty) |
answers | (hash) normative policy hash directing the proxy to do something with answers. Indexed by the command, and the answer (e.g. "USER331", "PWD200" etc) (default: empty) |
request_command | (string) When a command goes up to policy level, you may change it with this. FIXME: Not yet used. |
request_parameter | (string) When a command goes up to policy level, this variable contains command parameters. |
answer_code | (string) When an answer goes up to policy level, this variable contains answer code. |
answer_parameter | (string) When an answer go up to policy level, this variable contain answer parameters. |
restrict_client_connect | (boolean) Restricting data connection in client side. Accept data connection only if it's coming from IP number equal with command channel endpoint. (Default: TRUE) |
restrict_server_connect | (boolean) Restricting data connection in server side. Accept data connection only if it's coming from IP number equal with command channel endpoint. (Default: FALSE) |
Table 4-38. Untitled
state | connection state 0 is initial, 1 one of the connections were established, 2 both connections established ready to start data proxy. |
modes | array indexed by side, L for Listen or C for connect |
listens | listen objects created by us, array indexed by side |
connects | connect objects created by us, array indexed by side |
sides | determines the order in which sides must be processed (first listen/connect on sides[0] then on sides[1]) |
fds | array indexed by side, containing the side specific fd |
localsesa | local socket adress in server side. Used when data connections port is in a range. |
localclsa | local socket adress in client side. Used when data connecion port is in range. |
Deinitializes an FtpProxy class
__destroy__ ( self ) |
Calls resetState() to destroy bound listeners and connectors. It destroys running data connection.
Table 4-39. Arguments for FtpProxy.__destroy__()
self | this instance |
Initialize an FtpProxy instance
__init__ ( self, session ) |
This constructor initializes an FtpProxy instance by calling the inherited __init__ constructor with appropriate parameters, and setting up local attributes based on arguments.
Table 4-40. Arguments for FtpProxy.__init__()
self | this instance |
session | The session object |
Callback called when a connection was accepted on either side.
acceptedCallback ( self, client, fd, ) |
This callback is called if any of the sides was in L mode, and a connection was accepted on the listening socket.
Table 4-41. Arguments for FtpProxy.acceptedCallback()
self | this instance |
client | the client address which has connected |
fd | the file descriptor for the connection |
InternalError
stores the parameters, increases the state and continues with the state machine
Callback called when a connection was established.
connectedCallback ( self, fd ) |
This function is similar to [acceptedCallback], but used if we were in C (connect) mode.
.. [acceptedCallback] FtpDataConnect.acceptedCallback
Table 4-42. Arguments for FtpProxy.connectedCallback()
self | this instance |
fd | the file descriptor for the connection |
InternalError
stores the parameter, increases the state and continues with the state machine
This function can be called by derived classes to initialize internal hashtables.
loadAnswers ( self ) |
This function fills in the self.answers hash so that commonly used request/answer combinations are enabled.
Table 4-43. Arguments for FtpProxy.loadAnswers()
self | this instance |
Prepares the data channel on side side using mode mode.
prepareData ( self, side, mode, ) |
This function prepares the given side of the data connection. This means either to listen for connections (like passive mode on the client side) or to start establishing a connection (passive mode on the server side).
Table 4-44. Arguments for FtpProxy.prepareData()
self | this instance |
side | FTP_SIDE_CLIENT or FTP_SIDE_SERVER representing either the client or the server |
mode | L or C for Listen or Connect |
Reset data connection state.
resetData ( self ) |
Sets the initial state of everything, and destroy pending listeners.
Table 4-45. Arguments for FtpProxy.resetData()
self | this instance |
Start the data connection procedure as prepared by earlier prepare calls.
startData ( self, side1, side2, way, ) |
Previous calls to prepare determines how the data connection should be built. This function starts the state machine whose final state is to start a proxy on the established data connection.
Table 4-46. Arguments for FtpProxy.startData()
side1 | connect/listen on this side first |
side2 | connect/listen on this side after the first one succeeded |
way | direction |
InternalError
Do the processing as required by the current state.
stepData ( self ) |
This function is called each time after processing the current state finishes. This means that if the data connection on the server side is established we are ready to step one further and start accepting connections on the client side.
Table 4-47. Arguments for FtpProxy.stepData()
self | this instance |
InternalError
If state == 2, stacks in the proxy and starts it with a session stacked out from self.session
In state 0 and 1 it either listens or connects, based on the type field of parms[state]
Callback called by the data proxy to indicate the end of the data connection.
stopDataConnection ( self ) |
This callback is registered with the data proxy ([FtpDataProxy], see below), and is called when the data connection was terminated. It's task is to signal this condition to the Ftp proxy core.
.. [FtpDataProxy] FtpDataProxy
Table 4-48. Arguments for FtpProxy.stopDataConnection()
self | this instance |
We defined two example classes derived from the default FtpProxy class, enabling some additional commands/answers from the FTP protocol. FtpProxyAllow as the name suggests allows any FTP command to pass through the proxy, and allows any answer in reply to them.
Default config for FtpProxyAllow.
config ( self ) |
Enables all commands by setting permit_unknown_commands to TRUE and adding two wildcard entries to the commands and answers hash.
Table 4-49. Arguments for FtpProxyAllow.config()
self | this instance |
This proxy enables the minimal required protocol elements required by daily usage.
Configuration for FtpProxyMinimal
config ( self ) |
It enables a minimal set of commands for a working FTP proxy, and sets permit_unknown_commands to FALSE.
Table 4-50. Arguments for FtpProxyMinimal.config()
self | this instance |
Test function to log answers not enabled in config
test ( self, command, answer, ) |
This function is used to gather still useful answers not enabled in FtpProxyMinimal by default. It accepts any answers but sends a log message about it.
Table 4-51. Arguments for FtpProxyMinimal.test()
self | this instance |
command | command |
answer | answer |