Alright, so I'm given a Java FtpClient class that I am supposed to finish/modify so that the finished product will serve as a WebServer.
The following is a method that lets me interact with the server through command lines.
/*
* Send ftp command
* #param command: the full command line to send to the ftp server
* #param expected_code: the expected response code from the ftp server
* #return the response line from the ftp server after sending the command
*/
private String sendCommand(String command, int expected_response_code){
String response = "";
try {
// send command to the ftp server
controlWriter.writeBytes(command);
// get response from ftp server
response = controlReader.readLine();
if (DEBUG) {
System.out.println("Current FTP response: " + response);
}
// check validity of response
if (!response.startsWith(String.valueOf(expected_response_code)))
{
throw new IOException(
"Bad response: " + response);
}
} catch (IOException ex) {
System.out.println("IOException: " + ex);
}
return response;
}
However, when I invoke the GET command, i.e.
sendCommand("get " + __file__name__ + "\r\l", 200);),
I get the following response:
500 Unknown command.
I am almost 100% sure this issue has nothing to do with the method I've posted above, but I only posted it so you'll know what I am referring to by the sendCommand method).
Has anyone had a similar issue with this command before? If so, how did you work around it?
I've done a very similar side project to the one you're doing here, and I've encountered the same problem you've discussed here. I still haven't figured out why I wasn't able to simly invoke GET and read off the data stream, but here's my get-around.
First, you'll need to use RETR instead of GET. If you're not familiar with what RETR does, it basically lets you send a file as a packet of bytes through a temporary port you'll generate for data transmission.
To instantiate a temporary port, you will need to be im Passive Mode. So, type in:
quote pasv
Your output would look something like the following:
227 Entering Passive Mode (127,0,0,1,143,155).
A quick glance at the numbers shown between the two parentheses will probably not mean anything to you, however, two details can be derived from there.
The first 3 numbers represent your localhost which is always 127.0.0.1, an the other two are referred to p1 and p2. In this case, we have p1 = 143 and p2 = 155. These two numbers can be used to figure out which port has been assigned to us for data transfer.
Fire up your command line interface
To find out the port number, plug in the numbers in the following formula:
PORT = p1 * 256 + p2
So, our port number in this case is (143 * 256) + 155 ==> (36763).
Now that we have a transfer port open for us and ready for data transfer, you can go ahead and instantiate a new Socket with the port number derived from the formula mentioned above (please note that the numbers will be different every time you run the quote pasv, so don't assume these are constants).
The next step here is to send the file from yourself to the client. Note that you're not directing the data packet to a specific client, rather, any client that's currently connected will be receiving the packets.
To send the file, type in the following command:
quote retr
now you can use the DataInputStream class from your Socket to read all the bytes, display them, then them into an identical copy of the original file, or do whatever you're planning to do with them.
Note.. Note... Note... : the commands listed above were meant to be entered from the command line But since you want your application to handle all the job (I assume), the same commands can be passed from your Java application with a little bit of tweaking around. You will basically only need to take the word quote out of all the commands we've used them in.
I think I've typed enough tonight. I am headed to bed now. Let me know if you need further help in a comment below and I will try to respond as soon as possible. Also, let me know if anything I have said is not making sense to you.
Related
I'm working on an Android app (Java 8, target API=27) that downloads files from an FTP server (using Apache Common's FTPClient) but I'm experiencing a big problem with missing bytes with the retrieveFile and retrieveFileStream methods.
That's why I want to try the alternative of sending the actual commands:
//login
String path = remoteFolder + "/" + filename;
if(ftpClient.isConnected()) {
ftpClient.enterLocalPassiveMode();
ftpClient.setFileType(FTP.BINARY_FILE_TYPE); //For images,...
ftpClient.retr(path); //sends the "RETR" command
String reply = ftpClient.getReplyString();
Log.d(TAG,reply);
}
This prints:
150 Opening BINARY mode data connection.
But what now?
ftpClient.getReplyStrings().length is 1 and it's the same text. Usually I'd send the RETR command on the command socket, then read the data socket's reply (= the contents of the e.g. txt file) but there don't seem to be different, openly accesible sockets in this library.
Question: How do I get the contents of the file "manually" - so using the FTP commands but without using the retrieveFile... methods (if possible)?
Before sending RETR, you need to send PASV, EPSV, PORT or EPRT and parse its response. Typically you would use PASV, for which there's FTP.pasv method.
The next would to be open the data connection, based on the response to the PASV (and only then you send RETR).
But implementing the data connection is lot of work. And the FTPClient implementation of the data connection is hidden in a protected _openDataConnection_ method. So you cannot reuse the standard implementation. You will have to use generic Socket class.
And only then you can call FTP.retr (which does not do much on its own).
This is all a bad idea. But if you want to do it, check the implementation of FTPClient.retrieveFile – It's all there.
The FTPClient.retrieveFile and FTPClient.retrieveFileStream methods work perfectly – They are being used by thousands – It's probably the most widely used FTP library for Java. If it does not work for you, it's either because you are using them incorrectly or because there's something wrong with your network or servers.
i want to read the DNS requests made by the browser, then extract the name of website from the DNS UDP datagram.
I can capture the datagram, then i used getData() to find the labels of the website, but i don't get clear data.
public static void main(String args[]) throws Exception
{
DatagramSocket serverSocket = new DatagramSocket(53);
byte[] receiveData = new byte[512];
while(true)
{
DatagramPacket receivePacket = new DatagramPacket(receiveData,
receiveData.length);
serverSocket.receive(receivePacket);
byte telegramContent[] = receivePacket.getData();
String sentence = new String( telegramContent);
System.out.println("RECEIVED: " + sentence);
the result i had for www.google.com
my question is how to get the full name of the website clear like www.google.com
You will need to read RFC1034 and 1035. The DNS protocol is far more complicated than that, you will need far more code to parse it.
First, why not using a specific Java DNS library that surely exists and which can both generate and parse DNS packets? Even if you do not want to use it, reading its source may help you understand how the parse is happening.
Second, and if you really want to to it yourself, you will have to understand the generic format of a DNS packet (with a structure separating the question, the authority part, the answer part, the additional part), see section 4 for DNS packet structure, and then for names specifically, you need to understand "DNS compression", see section 4.1.4 of same RFC.
A name does not appear like this in a DNS packet. Each label (the string between two dots) is encoded on the wire with its length and then the label EXCEPT in some cases where pointers are used to point inside another part of the DNS packet in order never to repeat the same label or sequence of labels.
Finally you will need to not just try to grab any string in the DNS packet. A reply can have a lot of other content, like if you get a CNAME reply you will get two "strings", that is two domain names, the owner of the record and the associated RDATA. You will need to follow these CNAME records (if you want to find out the first name requested) and then parse replies of A and AAAA requests. You obviously also need to take into account negative replies (NXDOMAIN) that can happen for any name queried.
As for
i want to read the DNS requests made by the browser
, there is a far easier solution.
Install a recursive nameserver, like unbound and make sure your browser is pointed to it. Then you will easily see all hostnames in the nameserver logfile.
Also another solution with recent browser versions implementing DoH (DNS over HTTPS): again install a nameserver speaking DoH and configure your browser to point to it (see https://www.internetsociety.org/blog/2018/12/dns-privacy-support-in-mozilla-firefox/ for example for Firefox).
The code below works to two other sites I've tried, but will not work with my domain hosted by 1and1. The return code is always 500 - Permanent Negative Completion reply.
I know I'm connecting because FTPReply.isPositiveCompletion(reply) returns true. I tried it with both reading file off phone storage and sending it from a byte array populated early in the code. This is the byte array. Both return 500. Both work on the other sites.
If I don't use enterLocalPassiveMode() the code stops executing on the storeFile call. No exception, no socket time-out. It just ends there and the async task will not call again in that session. The code does not do that on the other sites.
I've tried both ASCII and BINARY file types. Both return 500. 1and1 site says to use my domain and port 21. I can connect with CoreFTP and read and write using both of the accounts I've set up.
I also tired ftp4j and had the same response with all scenarios so went back to Apache because the code was already written with robust error trapping.
I've tried both mydomain.com and ftp.mydomian.com. 500 on both. I also tried the dot quad I can see in the CoreFTP window, but i get "cannot resolve host name" with the Apache Java code. Maybe not a static IP?
This is what CoreFTP does. It connects on port 21 and then goes in to passive mode and an ASCII data connection.
It's a long shot, but has anyone else ever FTPed to their 1and1 domain using Java in Android Studio?
Greg
Resolving mydomain.com...
Connect socket #5684 to xx.xx.xx.xxx, port 21...
220 Microsoft FTP Service
USER ftp79815757-0
331 Password required for ftp79815757-0.
PASS **********
230 User logged in.
SYST
215 Windows_NT
Keep alive off...
PWD
257 "/ftp79815757-0" is current directory.
PASV
227 Entering Passive Mode (xx,xxx,xx,xxx,xxx,xxx).
LIST
Connect socket #5700 to xx.xx.xx.xx, port 62894...
150 Opening ASCII mode data connection.
226 Transfer complete.
Transferred 51 bytes in 0.094 seconds
FTPClient mFtpClient = new FTPClient();
String ip = "my domain dot com";
String userName = "ftp79815757-0";
String pass = "password";
mFtpClient.connect(InetAddress.getByName(ip));
mFtpClient.login(userName, pass);
int reply = mFtpClient.getReplyCode();
if (FTPReply.isPositiveCompletion(reply)) {
mFtpClient.setFileType(FTP.BINARY_FILE_TYPE);
//one thread said this would do the trick
mFtpClient.enterLocalPassiveMode();
mFtpClient.enterRemotePassiveMode();
InputStream stream = new ByteArrayInputStream(imageData);
//I have two accounts. One points to images_in
/*if (!mFtpClient.changeWorkingDirectory("images_in")) {
Log.e("ChangeDir", String.valueOf(mFtpClient.getReplyCode()));
}*/
if (!mFtpClient.storeFile("remoteName.jpg", stream)) {
Log.e("FTPUpload", String.valueOf(mFtpClient.getReplyCode()));
}
stream.close();
mFtpClient.disconnect();
}
Finally got it. The main problem was that I was using an old version of the Apache library. The Jar I was using was commons-net-1.4.jar. Someone in another thread pointed me to commons-net-3.3.jar.
I commented out both mFtpClient.enterLocalPassiveMode() and mFtpClient.enterRemotePassiveMode(), and with some trail and error it worked with FTP.BINARY_FILE_TYPE and not ASCII_FILE_TYPE. ASCII got the file there, but it was garbage.
I just want to create echo server/client using protobuf and java.
I tested with protobuf-java-2.4.1 and jdk1.7.
I wrote echo server code like below
// create server socket and accept for client connection.
// ...
link = servSock.accept();
Person person = Person.parseFrom(link.getInputStream()); // blocking position
person.writeTo(link.getOutputStream());
I think it is not necessary to note Person.proto.
The client code is only send Person object using socket input stream and receive echo Person object.
// socket connect code was omitted.
Person person = Person.newBuilder().setId(1).setName("zotiger").build();
person.writeTo(echoSocket.getOutputStream());
person = Person.parseFrom(echoSocket.getInputStream());
But server was blocked in parseFrom function when the server and client both run.
I found if i use writeDelimitedTo() and parseDelimitedFrom(), then that is ok. I don't understand why the writeTo() and parseFrom() function does not working.
Why did the server blocking in there?
Is it necessary to send some end signal from client side?
The reason you have to use writeDelimitedTo()/parseDelimitedFrom() is that otherwise protocol buffers may have no idea how much data it needs to read from the socket. That presents a problem (I say may because you could of course create a message with only fixed length fields that wouldn't require this ... but protocol buffers has to deal with both cases)
The writeDelimitedTo() method writes the length of the message to the OutputStream then the message itself. Its counterpart parseDelimitedFrom() reads the length, then the message.
You can use writeTo() and pasrseFrom() with streams but only if you want to write/read a single message and are closing the stream after writing. The reader will then get an EOF to indicate the end of the message (also the case when reading from a file that contains only a single message).
Don't write your own Client/Server, ie. RPC solution. There is one here......https://code.google.com/p/protobuf-rpc-pro/ which has some nice features already for java.
I want to connect to a number of different sockets/webservices on the command line and send data back and forth in the standard output/input.
I have been doing this using a variety of different languages and approaches so far: System.Net.Sockets in C#, flash.net.sockets in Flash and java.net.sockets in Java, depending on the protocol being used by the socket and the language being used in the client example given by the companies who've written the sockets. I've had enough of moving from language to language to do this (using the provided client socket example in each case), and will probably all the clients to java.
In the meantime, I want a way to connect to a socket on the command line in windows, see what's return in the standard output, send text to the socket on the command line (or a very, very simple GUI) and see what's returned back. I don't need any extra functionality like a periodic ping to keep the socket alive or anything.
What tools can I do this on Windows with? I've tried opening a telnet session to the socket i.e. push.domain.com 1234, and also tried using Putty to connect also, to no avail.
I'm trying to emulate the way a flash client connects to this socket and sends and receives data:
theSocket.addEventListener(Event.CONNECT, connectHandler);
theSocket.connect(theHost, thePort);
* * *
private function connectHandler(event:Event) : void
{
if (theSocket.connected)
{
bytes = new ByteArray();
bytes.writeByte(35);
bytes.writeByte(1);
bytes.writeByte(23);
bytes.writeByte(7);
bytes.writeUTFBytes(theTopic);
bytes.writeByte(0);
theSocket.writeBytes(bytes);
theSocket.flush();
theSocket.addEventListener(ProgressEvent.SOCKET_DATA, handshakeHandler);
* * *
private function handshakeHandler(event:ProgressEvent) : void
{
var zero:int = 0;
theSocket.removeEventListener(ProgressEvent.SOCKET_DATA, handshakeHandler);
theConnectionTimer.stop();
var bytes:* = new ByteArray();
var counter:int = 0;
theSocket.readUTFBytes(theSocket.bytesAvailable));
var a:* = theSocket.readByte();
var b:* = theSocket.readByte(); // the second byte should be 1????
var response:* = theSocket.readByte(); // this is the reponse identifier. . . ???
theMessageSize = theSocket.readByte(); // is this byte the size??????
switch(response)
{
case 100:
{
while ((zero = theSocket.readByte()) != 0)
{
var temp = counter++;
bytes[temp] = _loc_5;
};
theClientID = bytes.toString();
trace("The client ID is: " + theClientID);
How can I send the bytes values of 35, 1, 23, 7 and 0, as well as the value of the variable, Topic, to the socket using Hercules (or any other tool). Ideally, I'd like to connect with Hercules, send those bytes and the topic, and get something back containing the clientID like in the code. Although, I don't know if hercules will render the bytes in the response into text for me.
I'd appreciate any pointers at all on this.
Thanks.
I was thinking in Hercules and searching for the website I found out that there's already an answer here in stackoverflow.
I think it does what you need and more.
Uhm, I'm nost sure I understood completely what you are asking, but I don't see why telnet could not help you in this case.