Something is puzzling me about the use of ftp.nlst on a windows ftp server - ruby

So I was reading the documentation for the method nlst in the NET::FTP module (ruby-1.8.6). The source code displayed is
# File net/ftp.rb, line 602
def nlst(dir = nil)
cmd = "NLST"
if dir
cmd = cmd + " " + dir
end
files = []
retrlines(cmd) do |line|
files.push(line)
end
return files
end
So the command is written literally in the string cmd, executed via retrlines and the list of files is given back right?
The thing I don't understand is that on my windows ftp server there is no such command:
230 User logged in.
Remote system type is Windows_NT.
ftp> nlst
?Invalid command
ftp>
and yet the the method returns the file list. How is it possible? The source code doesn't appear to have an abstraction of some sort on the command and also the source code of retrlines doesn't have anything special (to me).
# File lib/net/ftp.rb, line 475
def retrlines(cmd) # :yield: line
synchronize do
with_binary(false) do
conn = transfercmd(cmd)
loop do
line = conn.gets
break if line == nil
yield(line.sub(/\r?\n\z/, ""), !line.match(/\n\z/).nil?)
end
conn.close
voidresp
end
end
end
I traced back the methods called to sendcmd inside transfercmd but I have no clue really.

The question is who is telling you ?Invalid command?
In this case it's the FTP client, not the server.
The client is just a front-end for commands that it implements, converting these front-end commands into proper FTP protocol command strings for the server.
What you're looking for is the nlist (not nlst) command in your client, which will issue the NLST FTP protocol command to the server.
ftp> help nlst
?Invalid help command nlst
ftp> help nlist
nlist nlist contents of remote directory
ftp>

Related

Can't upload file via FTP on Golang

I'm currently using github.com/jlaffaye/ftp on Go to send files.
I'm trying to connect to an FTP and upload a zipped file of about 700MB.
I connect to server properly and change the working dir but when I'm about to call the Stor function, it responds with "connection refused" and drops.
This is the code:
ftpFile="hola.txt"
fileOpen, err := os.Open(ftpFile) // For read access.
if err != nil {
fmt.Println("error "+ftpFile)
panic(err)
} else {
fmt.Println("abierto "+ftpFile)
}
reader:=bufio.NewReader(fileOpen)
err = client.Stor(ftpDir+ftpFile,reader)
if err != nil {
fmt.Println("error en stor "+ftpDir+ftpFile)
panic(err)
} else {
fmt.Println("subiendo "+ftpFile)
}
defer fileOpen.Close()
I'm opening a file with os.Open then read it with bufio.NewReader and pass it to the Stor function but it disconnects. The FTP is good as I was connected to it via FileZilla, the zipfile or txt file (in this code example) are both good and I believe I'm missing the shot when it comes to the bufio.NewReader but I can't find a working example of reading a file and using this goftp library.
Update:
Here's the logfile
220 Microsoft FTP Service
USER *user goes here*
331 Password required
PASS *plain text password goes here*
230 User logged in.
FEAT
211-Extended features supported:
LANG EN*
UTF8
AUTH TLS;TLS-C;SSL;TLS-P;
PBSZ
PROT C;P;
CCC
HOST
SIZE
MDTM
REST STREAM
211 END
TYPE I
200 Type set to I.
OPTS UTF8 ON
200 OPTS UTF8 command successful - UTF8 encoding now ON.
CWD /web-import/pre/
250 CWD command successful.
PWD
257 "/web-import/pre" is current directory.
PASV
227 Entering Passive Mode (x,x,x,x,x,x).
Update: Looks like someone had the same problem some weeks ago: goftp - 229 Entering Extended Passive Mode now I'll be looking for solutions and will post here.
Update: Changed the script to connect to a CentOS server and got the same error. Now that the FTP server is discarded then there are 2 culprits: goftp package and the script itself.
Update: Tried again with a simpler script following example at documentation and failed again at the same spot. Had to report issue on developer's Github https://github.com/jlaffaye/ftp/issues/272
Update: I connected via terminal and opened FTP from command line. I typed "ls" by mistake and got this error
227 Entering Passive Mode (x,x,x,x,x,x).
ftp: connect: Connection refused
Last Update: After coding and debugging in the end it wasn't the goftp package neither the server neither the client. It was my firewall that blocked my ftp from going PASV. I whitelisted the ip and it worked perfectly.

copy contents of a remote location to a local file in ruby script

I want to copy the contents of a remote location file to some local file after an ssh connection has been made.
begin
ssh = Net::SSH.start("localhost", "user")
logger.info "conn successful!"
results = conn.exec!('ruby somefile "#{arguments}"')
#code to copy the contents of a.txt in remote location to local file
#IO.copy_stream (localfile, remotefile)
rescue
logger.info "error - cannot connect to host"
end
I tried using IO.copy_stream but that doesn't work. How do I go about this?
Use Net::SCP (which requires Net::SSH) to transfer files:
Net::SCP.download!("remote.host.com", "username",
"/remote/path", "/local/path",
:password => password)
More info here: https://rubygems.org/gems/net-scp

Ruby FTP server "halts"

I am trying to implement the FTP protocol in Ruby. The problem is that when the user enters the bye command my program doesn't respond (the other commands work fine). Here is some of my code (the socket parts are omitted). Can anyone tell me what is going wrong? (I know that when bye is entered the standard windows FTP program sends "QUIT".)
user_on = true
while user_on
cmd = client.recv(2000)
# THIS IS WHERE IT FREEZES
if cmd.contains? 'QUIT'
client.puts("221 Goodbye.")
client.close
user_on = false
else
puts("500 UNRECOGNIZED COMMAND")
cmd = client.recv(2000)
end
end

Ruby Telnet Lib - Weird Response

I am trying to execute cmds on a remote CPU through telnet. While some commands sent (through Ruby's stdlib for telnet) are successful, others are giving me a weird response:
*===============================================================
Welcome to Microsoft Telnet Server.
*===============================================================
C:\Documents and Settings\UserJW>ls
Desktop
Favorites
My Documents
Start Menu
Sti_Trace.log
C:\Documents and Settings\UserJW>cd\
More?
Why is telnet giving me this "More?" response, as if expecting something?
In the code, I am simply connecting to remote CPU, logging in, and sending commands:
#connection = Net::Telnet.new(...)
#connection.login( user, pwd )
#connection.cmd(...)
Any help would be appreciated.
Thanks,
J
**EDIT:
#connection = Net::Telnet.new(
"Host" => machine,
"Prompt" => /[A-Za-z]:\\.*>\z/n,
"Timeout" => 3,
"Output_log" => output )
#connection.login( user, pwd )
#connection.cmd( 'ls' )
#connection.cmd( 'ls' )
output...
C:\Documents and Settings\UserJW>
ls
Desktop
Favorites
My Documents
Start Menu
Sti_Trace.log
C:\Documents and Settings\UserJW>
ls
More?
I can't even send more than one command, apparently. Is my Prompt regex wrong? I'm trying to allow..
C:[anything...]>
I meet a same problem with you ( ruby telnet to windows 2008 ,execute command error ).I solved it. the reason is ruby net/telnet library use error newline seperator. Must be EOL(CR+LF) but CR+NULL . But I don't know who make the bug,windows or ruby? I write a monkey patch as below:
class Net::Telnet
def print(string)
string = string.gsub(/#{IAC}/no, IAC + IAC) if #options["Telnetmode"]
if #options["Binmode"]
self.write(string)
else
if #telnet_option["BINARY"] and #telnet_option["SGA"]
self.write(string.gsub(/\n/n, CR))
elsif #telnet_option["SGA"]
self.write(string.gsub(/\n/n, EOL)) ### fix here. reaplce CR+NULL bY EOL
else
self.write(string.gsub(/\n/n, EOL))
end
end
end
end

How to fetch a binary file from a remote embeded system using telnet?

I have a remote embedded system and it is telnet-able. How can I fetch a binary file from it using ruby? If it were a text file, I could have used:
con = Net::Telnet::new("Host"=>ip,"Timeout"=>200) #Host not host
File.open("fetched_file","w+") do |f|
con.cmd("cat /ect/file") {|data| f.write(data)}
end
But this wouldn't work for binary file you won't get desirable data by cating it.
establish your telnet connection then
send the command:
uuencode filename -
to the remote host, replacing filename with the filename
take the data you are sent and pass it to uudecode on your system
If the device has uuencode installed, you could use that to 'wrap' the binary into printable characters. Other possibility is to run dd if=/etc/file 2>/dev/null to dump the data (however I am not completely certain this will word any better...)

Resources