Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 35 additions & 2 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ ftpmult - a simple FTP multiplexer / reverse proxy written in Node.JS
Welcome
----

THIS IS A FORK OF https://github.com/peter-x/ftpmult
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not a fork anymore, if this pull request is accepted ;-)


IMPROVED BY https://github.com/djpimp2010/ftpmult

This piece of software provides a reverse proxy for FTP which can select the
target server based on the username. This is for example useful in a hosting
environment where you have many virtual servers but only a single IP address and
Expand All @@ -15,10 +19,39 @@ all or only based on some suffix ("`@hostname`") of the username. Furthermore,
ftpmult is an extremely simple piece of software (less than 300 lines) and can
thus be easily adapted to your needs.

THIS SERVICE INIT SCRIPT HAS BEEN DESIGNED ON THE PRETENSE THAT NODE JS ONLY RUNS FOR THIS PROGRAM
IF YOU HAVE OTHER PROGRAMS RUNNING NODE.JS YOU WILL NEED TO IMPROVE THE SERVICE INIT SCRIPT


How to use
----

See `test.js` for an example and adjust the callback `getHostFromUsername` to your
needs.
(THIS GUIDE IS BASED ON CentOS/Fedora)

1. Once the repo is cloned into your node.js modules directory, you will need to copy 'ftpproxy.initscript' to /etc/init.d
(Or your 'service' script location, for other distros)

2. Edit ftpproxy.initscript and set the two variables at the top:
NODE_EXECUTABLE_PATH=/usr/local/bin/node
NODE_MODULES_PATH=/usr/local/bin/lib/node_modules/npm/node_modules

3. Rename file from ftpproxy.initscript to ftpproxy, and chmod with executable permissions for root.

4. Decide if you are going to be using a database to manage users/hosts.
If you are, the database must have these fields:
'increment_name' (primary key, auto increment) *name can vary*
'username' (varchar)
'host' (varchar)

You can have other fields too, as long as each row is unique, and the fields username and host are present.
This could be linked into a pre-existent user management database.

5. If you are using a database to manage users, and your database is set up, you should be ready to test the script.
# service ftpproxy start

If there are any errors, they will be listed in the console window.
If you see the message "FTP multiplexer up and ready for connections." then your server is listening.

If you decided not to use mysql to manage users, please rename 'ftp_proxy.js' to 'ftp_proxy.js.old',
And then rename 'ftp_proxy_blank.js' to 'ftp_proxy.js'
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be great if you could unify both files and just add configuration switches like

var useMysql = 1;
if (useMyysql) {
...
} else {
...
}

This is a template file for creating a proxy server, although this has no function written for getting hostname from username.
4 changes: 0 additions & 4 deletions README.md

This file was deleted.

71 changes: 71 additions & 0 deletions ftp_proxy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
var ftpd = require('./ftpmult.js');

/*function to check associative array for username, and return host*/
/*if username is not in array, return bad host, so that connection is refused*/
/*array example:
users = [
{ record_id: "1", username: "testuser1", host: "192.168.0.11" },
{ record_id: "2", username: "testuser2", host: "192.168.0.12" },
{ record_id: "3", username: "testuser3", host: "192.168.0.13" }
];*/
Array.prototype.contains = function ( needle ) {
for (i in this) {
if (this[i]['username'] === needle) return this[i]['host'];
}
return '10.32.0.1'; /*set this to an IP address not in your network*/
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, what about returning "undefined" or false something like that and just close the connection in this case?
Apart from that, I don't think it's a good idea to change the general array object for this special purpose...

}

/*node.js mysql library required*/
/*npm install mysql*/
var mysql = require('mysql');
var connection = mysql.createConnection({
host : '192.168.0.10',
user : 'ftpproxy',
password: 'P4ssw0rd',
database: 'ftpproxy'
});

/*connect once on service start, and run query to get users*/
connection.connect(function(err){
if(err){
console.log(err);
return;
}
});

/*this query fetches all users from the table ftpproxy.users*/
connection.query('SELECT * from users', function(err, rows, fields) {
if (err) {
console.log(err);
return;
} else {
/*store array in global scope, without declaring it as a 'var'*/
users = rows;
}
});

/*close mysql connection, as we now have array of users*/
connection.end();

/*create server on ftp login attempt*/
var server = new ftpd.FtpServer({
getHostFromUsername: function(username) {
var host = users.contains(username);
return {hostname: host, port: 21}
}
});

server.logLevel = 4;
/*listen on port 21 (command issued as root)*/
server.listen(21);
try {
/*change uid/gid to non-root user*/
process.setuid(65534);
process.setgid(65534);
} catch (e) {
}
server.server.on("error", function() {
/* better exit so that someone can restart us */
process.exit(1);
});

44 changes: 24 additions & 20 deletions test.js → ftp_proxy_blank.js
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
var ftpd = require('./ftpmult.js');

try {
process.setuid(65534);
process.setgid(65534);
} catch (e) {
}

var server = new ftpd.FtpServer({
getHostFromUsername: function(username) {
return {hostname: 'ftp.kernel.org', port: 21};
}
});

server.logLevel = 4;
server.listen(7002);
server.server.on("error", function() {
/* better exit so that someone can restart us */
process.exit(1);
});
var ftpd = require('./ftpmult.js');

/*create server on ftp login attempt*/
var server = new ftpd.FtpServer({
getHostFromUsername: function(username) {
/*insert code here to determine hostname from username*/
return {hostname: "192.168.0.20", port: 21}
}
});

server.logLevel = 4;
/*listen on port 21 (command issued as root)*/
server.listen(21);
try {
/*change uid/gid to non-root user*/
process.setuid(65534);
process.setgid(65534);
} catch (e) {
}
server.server.on("error", function() {
/* better exit so that someone can restart us */
process.exit(1);
});

2 changes: 1 addition & 1 deletion ftpmult.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ function FtpServer(options) {
return new FtpServer(options);
}

this.myHost = options.host || '127.0.0.1';
this.myHost = options.host || '127.0.0.1'; // I had to change this to my FTP Proxy server IP of 192.168.0.100
this.server = net.createServer();
this.getHostFromUsername = options.getHostFromUsername || function(username) { return null; };
this.logLevel = options.logLevel || 0;
Expand Down
69 changes: 69 additions & 0 deletions ftpproxy.initscript
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#!/bin/sh

# chkconfig: 345 70 30
# description: ftpproxy
# processname: ftpproxy

NODE_EXECUTABLE_PATH=/usr/local/bin/node
NODE_MODULES_PATH=/usr/local/bin/lib/node_modules/npm/node_modules

check () {
if pidof -x "node" >/dev/null; then
return 0
else
return 1
fi
}

chk_status () {
if check; then
echo "FTP Proxy is running"
echo
else
echo "FTP Proxy is stopped"
echo
fi
}

start () {
if check; then
echo "FTP Proxy is already running"
echo
else
echo "Starting FTP Proxy"
$NODE_EXECUTABLE_PATH $NODE_MODULES_PATH/ftpmult/ftp_proxy.js &
chk_status
touch /var/lock/subsys/ftpproxy
fi
}

stop () {
if check; then
echo "Stopping FTP Proxy"
pkill -9 node
rm -rf /var/lock/subsys/ftpproxy
chk_status
else
echo "FTP Proxy is not running"
echo
fi
}

case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
status)
chk_status
;;
*)
echo $"Usage: $0 {start|stop|restart|status}"
esac