I would like to run an ftp server on a nixos host. I am using vsftpd, though could use something else if that would make a difference.
The ftp works fine on localhost, but the firewall is blocking me for remote usage. I have allowed TCP port 21, but that is not enough.
How should I configure the firewall to allow ftp connections (including writing to the ftp server)?
Here is the code that I currently have:
{
networking.firewall = { allowedTCPPorts = [ 20 21 ];
# connectionTrackingModules = [ "ftp" ];
};
services.vsftpd = {
enable = true;
# cannot chroot && write
# chrootlocalUser = true;
writeEnable = true;
localUsers = true;
userlist = [ "martyn" "cam" ];
userlistEnable = true;
};
}
With the above, any use of ftp from off-host fails:
ftp> put dead.letter
200 PORT command successful. Consider using PASV.
425 Failed to establish connection.
Use of passive mode (e.g., with ftp -p) doesn't seem to help here:
ftp> put dead.letter
227 Entering Passive Mode (192,168,0,7,219,202).
ftp: connect: Connection timed out
Testing on a throwaway host with the firewall disabled
networking.firewall.enable = false;
Allows ftp -p to work; though of course turning off the firewall is not an attractive option.
Thanks for any help and pointers,
In passive mode the client will connect to the server with a second connection, that is used to transfer "things" (directory listings, files). In your case:
227 Entering Passive Mode (192,168,0,7,219,202)
The server requested the client to connect to it on port 219 * 256 + 202 = 56266.
This port is choosen by vsftpd dynamically and is not open in your firewall. You have to fix vsftpd to a fixed port for the passive connection and open this connection in the firewall.
vsftpd has two configuration options to set this: pasv_max_port and pasv_min_port. You should be able to set them in services.vsftpd.extraConfig. You probably want to open a small range of ports and open these in the firewall.
To open ports in the firewall, use networking.firewall.allowedTCPPorts. For example:
networking.firewall.allowedTCPPorts = [ 21 ];
services.vsftpd.extraConfig = ''
pasv_enable=Yes
pasv_min_port=51000
pasv_max_port=51999
'';
networking.firewall.allowedTCPPortRanges = [ { from = 51000; to = 51999; } ];
Firewall configuration is not automatic in NixOS, because that would defeat the purpose of having control over what traffic is allowed.
Some services have an openFirewall option to make this easier, but the vsftpd module does not seem to provide this convenience.
Edit: 20 is for the client. Only 21 needs to be opened.
Edit: Plus a range for passive mode connections.
Related
I do not have telnet command in my system.
However my system is installed with Windows 10, so there must be a way to check whether particular port is open or not in a remote system. That particular remote system is accessible I had checked with ping command.
So here is my simple question,- how to check whether particular port is open or not using powershell.
Command netstat could brief for local system service & port and particular protocol either UDP or TCP is up & runnning. As I do not have telnet I need this to be sorted out and tackled by powershell. Any advise and suggestion are welcome.
Test-NetConnection ###.###.###.### -Port ##
You can use the following to try and open a port, if no error is returned the port is open:
$ipaddress = ""
$port = ""
$tcpClient = new-object Net.Sockets.TcpClient
$tcpClient.Connect("$ipaddress", $Port)
$tcpClient.Dispose()
Here's a more complete example, which returns true/false which is the way that Test-Path works:
function Test-Port
{
param
(
$Address,
$Port
)
$tcpClient = new-object Net.Sockets.TcpClient
try
{
$tcpClient.Connect("$Address", $Port)
$true
}
catch
{
$false
}
finally
{
$tcpClient.Dispose()
}
}
Test-Port -Address localhost -Port 80
Test-Port -Address localhost -Port 81
Depending on the version of Powershell/Windows you are using Test-NetConnection may be more appropriate.
I have 3 machines(A, B & C) connected to a Router. A,B & C are in same subnet. All these three machines are interconnected using STAF. I am using machine A as an FTP server & machine B as an FTP client. Using STAF command from machine C I am starting FTP program (TCL script) on machine B.
Now the question is, How C will know whether FTP traffic is flowing between A & B?
The ftp package allows you to specify a progress monitor callback in the ftp::Open command:
package require ftp
proc progressMessage {bytesSoFar} {
puts "Transferred $bytesSoFar; looking good..."
}
set handle [ftp::Open $A $user $pass -progress progressMessage]
# Everything after this is just standard for the ftp package
if {$handle < 0} {
error "could not connect"
}
if {![ftp::Get $handle $remoteFile $localFile]} {
ftp::Close $handle
error "could not transfer"
}
ftp::Close $handle
puts "Transfer completed"
This will print a message every time a chunk is transferred (the chunk size is configurable in the options to ftp::Open via the -blocksize option; it's 4096 by default). On modern networks, this is probably going to write messages very rapidly…
package require ftp
set handle [::ftp::Open $host $user $passwd]
if {$handle < 0} {
error "Connection refused!"
return 0
}
I am using LFTP to transfer files from a server, which unfortunately does not recognize the PORT command. I do not have control over the server (do not know in detail what server is) and I have to use the active mode.
This is the command line as:
lftp -e 'debug 10;set ftp:passive-mode off; set ftp:auto-passive-mode no; ls; bye;' -u user,password ftp://ftp.site.com
This is the debug output:
<--- 200 Using default language en_US
---> OPTS UTF8 ON
<--- 200 UTF8 set to on
---> OPTS MLST modify;perm;size;type;UNIX.group;UNIX.mode;UNIX.owner;
<--- 200 OPTS MLST modify;perm;size;type;UNIX.group;UNIX.mode;UNIX.owner;
---> USER xxxxx
<--- 331 Password required for xxxxx
---> PASS xxxxxx
<--- 230 User xxxxx logged in
---> PBSZ 0
<--- 200 PBSZ 0 successful
---> PROT P
<--- 200 Protection set to Private
---> PORT 172,16,133,11,146,168
<--- 500 Illegal PORT command
---> LIST
---> ABOR
---- Closing aborted data socket
---- Chiusura del socket di controllo
It seems that LFTP renounces to connect to data socket because the remote server does not support the PORT command. Is there a way to convince LFTP can still connect to port 20? By FTP manual obviously no problem.
The issue, I think, is not that the FTP server doesn't support the PORT command (it does), but rather, it doesn't like the IP address/port that your FTP client is sending in the PORT command.
PORT 172,16,133,11,146,168
...tells the server to connect to address 172.16.133.11, port 37544*. The interesting part here is the IP address: it's an RFC 1918 address (i.e. it's a private network address). That, in turn, suggests that your FTP client is in a LAN somewhere, and is connecting to an FTP server using a public IP address.
That remote FTP server cannot connect to a private network address; by definition, RFC 1918 address are not publicly routable.
Thus it very well could be that the FTP server is trying to make a connection to the address/port given in your PORT command, fails, thus that is why the FTP server fails the command, saying:
500 Illegal PORT command
To make a PORT command work with that FTP server, you would need to discover the public IP address that that server can connect to, to reach your client machine. Let's say that this address is 1.2.3.4. Then you would need to tell lftp to use that address in its PORT command, using the ftp:port-ipv4 option.
Chances are, though, that public IP address is the address of a NAT/router/firewall, and that that NAT/router/firewall will not allow connections, from the outside world to a high numbered port (e.g. 37544), to be routed to a machine within the LAN. This is one of the issues with active FTP data transfers, i.e. FTP data transfers which use the PORT (or EPRT) commands: they are not considered "firewall-friendly".
Hope this helps!
* - why 146,168 translates to port 37544?
According to FTP's RFC959 those parameters are:
(...) 16-bit TCP port address. This address information is broken into
8-bit fields and the value of each field is transmitted as a decimal
number (in character string representation).
146 dec = 10010010 bin = A
168 dec = 10101000 bin = B
A B
10010010 10101000 bin = 37544 dec
here is the code you can find every where on net
var net = require('net');
var server = net.createServer(function (socket) {
socket.write("Echo server\r\n");
socket.pipe(socket);
});
server.listen(1337, "127.0.0.1");
A simple tcp server will echo whatever you will send it. How to send data to it? What tools/commands I need in mac to test this server?
Use nc aka netcat. In Terminal.app, while your node app is running:
$ nc localhost 1337
Echo server
Ta-da!
I am trying to send an email from R, using the sendmailR package. The code below works fine when I run it on my PC, and I recieve the email. However, when I run it with my macbook pro, it fails with the following error:
library(sendmailR)
from <- sprintf("<sendmailR#%s>", Sys.info()[4])
to <- "<myemail#gmail.com>"
subject <- "TEST"
sendmail(from, to, subject, body,
control=list(smtpServer="ASPMX.L.GOOGLE.COM"))
Error in socketConnection(host = server, port = port, blocking = TRUE) :
cannot open the connection
In addition: Warning message:
In socketConnection(host = server, port = port, blocking = TRUE) :
ASPMX.L.GOOGLE.COM:25 cannot be opened
Any ideas as to why this would work on a PC, but not a mac? I turned the firewall off on both machines.
Are you able to send email via the command-line?
So, first of all, fire up a Terminal and then
$ echo “Test 123” | mail -s “Test” user#domain.com
Look into /var/log/mail.log, or better use
$ tail -f /var/log/mail.log
in a different window while you send your email. If you see something like
... setting up TLS connection to smtp.gmail.com[xxx.xx.xxx.xxx]:587
... Trusted TLS connection established to smtp.gmail.com[xxx.xx.xxx.xxx]:587:\
TLSv1 with cipher RC4-MD5 (128/128 bits)
then you succeeded. Otherwise, it means you have to configure you mailing system. I use postfix with Gmail for two years now, and I never had have problem with it. Basically, you need to grab the Equifax certificates, Equifax_Secure_CA.pem from here: http://www.geotrust.com/resources/root-certificates/. (They were using Thawtee certificates before but they changed last year.) Then, assuming you used Gmail,
Create relay_password in /etc/postfix and put a single line like this (with your correct login and password):
smtp.gmail.com login#gmail.com:password
then in a Terminal,
$ sudo postmap /etc/postfix/relay_password
to update Postfix lookup table.
Add the certificates in /etc/postfix/certs, or any folder you like, then
$ sudo c_rehash /etc/postfix/certs/
(i.e., rehash the certificates with Openssl).
Edit /etc/postfix/main.cf so that it includes the following lines (adjust the paths if needed):
relayhost = smtp.gmail.com:587
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/relay_password
smtp_sasl_security_options = noanonymous
smtp_tls_security_level = may
smtp_tls_CApath = /etc/postfix/certs
smtp_tls_session_cache_database = btree:/etc/postfix/smtp_scache
smtp_tls_session_cache_timeout = 3600s
smtp_tls_loglevel = 1
tls_random_source = dev:/dev/urandom
Finally, just reload the Postfix process, with e.g.
$ sudo postfix reload
(a combination of start/stop works too).
You can choose a different port for the SMTP, e.g. 465.
It’s still possible to use SASL without TLS (the above steps are basically the same), but in both case the main problem is that your login informations are available in a plan text file... Also, should you want to use your MobileMe account, just replace the Gmail SMTP server with smtp.me.com.