hi, i would like to ask how could i connect to my udp server with an udp client if my isp is a proxy and seems to block incoming connections.
if you try to send to your server the fact it block incoming packets is not important.
it depend on what kind of proxy it is : if it is an http only proxy forget you wont be able to send anything then tcp packets (and maybe/sometimes only to port 80)
if it is a socks proxy you have to embed your packets into proxy packet using
new Socket(Proxy)
http://www.j2ee.me/j2se/1.5.0/docs/api/java/net/Proxy.html
http://www.j2ee.me/j2se/1.5.0/docs/api/java/net/Proxy.Type.html
seems that you can also configure your JRE to use your proxy with a runtime argument:
complete guide here : http://java.sun.com/javase/6/docs/technotes/guides/net/proxies.html
Hi, i don’t seem to understand how to set the connection up and the documentations don’t seem to give any hints either.
My current code, don’t know if it is even correct:
Server:
public class Server {
public static void main(String[] args) {
new ServerThread().start();
}
}
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
public class ServerThread extends Thread {
ServerSocket server;
Socket incoming, outgoing = null;
InetSocketAddress dest;
PrintWriter out = null;
BufferedReader in = null;
boolean error = false;
public ServerThread() {
try {
server = new ServerSocket(5556);
incoming = server.accept();
} catch (Exception e) {
e.printStackTrace();
}
}
public void run() {
while (!error) {
try {
in = new BufferedReader(new InputStreamReader(incoming
.getInputStream()));
String input;
while ((input = in.readLine()) != null) {
System.out.println("server got: " + input);
}
SocketAddress local = new InetSocketAddress(InetAddress.getLocalHost(), 5556);
SocketAddress dest = new InetSocketAddress(incoming.getInetAddress(),incoming.getPort());
Proxy proxy = new Proxy(Proxy.Type.SOCKS, local);
outgoing = new Socket(proxy);
outgoing.connect(dest);
out = new PrintWriter(outgoing.getOutputStream(), true);
out.write("From server "+System.currentTimeMillis()%1000);
} catch (IOException e) {
e.printStackTrace();
} finally {
error = true;
}
}
try {
incoming.close();
outgoing.close();
out.close();
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public synchronized void start() {
super.start();
}
}
Client:
public class Client {
public static void main(String[] args) {
new ClientThread().start();
}
}
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.Socket;
import java.net.SocketAddress;
public class ClientThread extends Thread {
Proxy proxy;
Socket socket;
InetSocketAddress dest;
PrintWriter out = null;
BufferedReader in = null;
boolean error = false;
public ClientThread() {
try {
byte[] d = { (byte) MY, (byte) EXTERNAL, (byte) IP, (byte) ADDRESS };
SocketAddress local = new InetSocketAddress(InetAddress.getLocalHost(), 3000);
SocketAddress dest = new InetSocketAddress(InetAddress.getByAddress(d),5556);
proxy = new Proxy(Proxy.Type.SOCKS, local);
socket = new Socket(proxy);
socket.connect(dest);
} catch (Exception e) {
e.printStackTrace();
}
}
public void run() {
while (!error) {
try {
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(socket
.getInputStream()));
String input;
while ((input = in.readLine()) != null) {
System.out.println("client got: " + input);
}
out.write("From client "+System.currentTimeMillis()%1000);
} catch (IOException e) {
e.printStackTrace();
} finally {
error = true;
}
}
try {
socket.close();
out.close();
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public synchronized void start() {
super.start();
}
}
Hope anybody can help. Currently it says in client thread: Connection refused: connect
Excuse me, this is way offtopic but… I browsed through java.net.SocksSocketImpl.class
byte[] data = new byte[8];
int n = readSocksReply(in, data);
if (n != 8)
throw new SocketException("Reply from SOCKS server has bad length: " + n);
private int readSocksReply(InputStream in, byte[] data) throws IOException {
int len = data.length;
int received = 0;
for (int attempts = 0; received < len && attempts < 3; attempts++) {
int count = in.read(data, received, len - received);
if (count < 0)
throw new SocketException("Malformed reply from SOCKS server");
received += count;
}
return received;
}
So if it takes more than 3 socket reads to receive 8 bytes, you’re screwed! Shame on you Sun!
To make up for the offtopic-ness, I wrote some code. This is all from the specs, not even compiled, so use as a reference:
To create a relay server:
Serversocket ss = ...;
while(true)
{
Socket s = ss.accept();
// create new thread
}
// on another thread
InputStream in = s.getInputStream();
int mustBe4 = in.read(); // SOCKS4
int mustBe1 = in.read(); // stream
int port = 0;
port |= (in.read() & 0xFF << 8);
port |= (in.read() & 0xFF << 0);
byte[] addr = new byte[4];
for(int i=0; i<4; i++) addr[i] = (byte)in.read();
byte[] userid = new byte[128];
int len = -1;
for(int i=0; i<userid.length; i++)
{
int b = in.read();
if(b == 0x00) { len = i; break;}
userid[i] = (byte)b;
}
if(len==-1) throw new ISE("userid too long");
char[] username = new char[len];
for(int i=0; i<len; i++)
username[i] = (char)userid[i];
System.out.println(new String(username));
out.write(0x00);
out.write(0x5a); // request granted
for(int i=0; i<2; i++) out.write(0x13); // 2 arbitrary bytes, that should be ignored
for(int i=0; i<4; i++) out.write(0x14); // 4 arbitrary bytes, that should be ignored
out.flush();
InetAddress iaddr = InetAddress.getByAddress(addr);
Socket dest = new Socket(iaddr, port);
// launch 2 threads that pump IN and OUT bytes between both endpoints.
This messy code actually works!
Setup Firefox to use a proxy (SOCKS4, not SOCKS5) using 127.0.0.1@1080, and watch the STDOUT fly by.
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class SOCKS4
{
public static void main(String[] args) throws IOException
{
ServerSocket ss = new ServerSocket(1080, 50, InetAddress.getByName("127.0.0.1"));
while (true)
{
Socket s = ss.accept();
new Thread(new Stream(s)).start();
}
}
static class Stream implements Runnable
{
private final Socket src;
public Stream(Socket src)
{
this.src = src;
}
public void run()
{
try
{
InputStream in = this.src.getInputStream();
OutputStream out = this.src.getOutputStream();
int mustBe4 = in.read(); // SOCKS4
int mustBe1 = in.read(); // stream
if ((mustBe4 | mustBe1) < 0)
throw new EOFException();
if (mustBe4 != 4)
throw new IllegalStateException("mustBe4=" + mustBe4);
if (mustBe1 != 1)
throw new IllegalStateException("mustBe1=" + mustBe1);
int port = 0;
port |= (in.read() << 8);
port |= (in.read() << 0);
if (port < 0)
throw new EOFException();
System.out.println("port:" + port);
byte[] addr = new byte[4];
for (int i = 0; i < 4; i++)
addr[i] = (byte) in.read();
InetAddress iaddr = InetAddress.getByAddress(addr);
System.out.println("addr:" + iaddr.getHostAddress() + " => " + iaddr.getHostName());
byte[] userid = new byte[128];
int len = -1;
for (int i = 0; i < userid.length; i++)
{
int b = in.read();
if (b == -1)
{
throw new EOFException();
}
if (b != 0x00)
{
userid[i] = (byte) b;
}
else
{
len = i;
break;
}
}
if (len == -1)
throw new IllegalStateException("userid too long");
char[] username = new char[len];
for (int i = 0; i < len; i++)
username[i] = (char) userid[i];
System.out.println("user:" + new String(username));
out.write(0x00);
out.write(0x5a); // request granted
for (int i = 0; i < 2; i++)
out.write(0x13); // 2 arbitrary bytes, that should be ignored
for (int i = 0; i < 4; i++)
out.write(0x14); // 4 arbitrary bytes, that should be ignored
out.flush();
Socket dst = new Socket(iaddr, port);
src.setSoTimeout(30 * 1000);
dst.setSoTimeout(30 * 1000);
Thread t1 = new Thread(new Pump(dst.getInputStream(), out));
Thread t2 = new Thread(new Pump(in, dst.getOutputStream()));
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("closing:" + src + " <=> " + dst);
src.close();
dst.close();
}
catch (InterruptedException exc)
{
exc.printStackTrace();
}
catch (IOException exc)
{
exc.printStackTrace();
}
finally
{
try
{
this.src.close();
}
catch (IOException exc)
{
// ignore
}
}
}
}
static class Pump implements Runnable
{
private final InputStream in;
private final OutputStream out;
public Pump(InputStream in, OutputStream out)
{
this.in = in;
this.out = out;
}
@Override
public void run()
{
try
{
byte[] buf = new byte[8 * 1024];
while (true)
{
int b = this.in.read(buf);
if (b == -1)
break;
this.out.write(buf, 0, b);
this.out.flush();
}
}
catch (IOException exc)
{
// ignore
}
finally
{
try
{
this.in.close();
}
catch (IOException exc)
{
// ignore
}
try
{
this.out.close();
}
catch (IOException exc)
{
// ignore
}
}
}
}
}
Using the above code, I saw how MSIE makes a connection to Microsoft on port 443, for every regular hit. :persecutioncomplex:
addr=65.55.157.60,port=443
love that feeling;) !
so if my isp uses a proxy then there’s no way i can make a low level connection from outside to my custom program?
You’d have to have a publicly reachable server, that you can connect to from your home (this shouldn’t be a problem), and listen on that server for connections, using some custom protocol to send all incoming bytes over that single connection back to your home system, and back ofcource.
In that situation, you’d probably use that server anyway, instead of your home PC…
okay thanks, those private servers where u can run anything cost a lot so first u have to complete a huge game and then u can try if it even works correctly over open internet.
very nice code source snipet , what about cleaning it (or no ) a little and put it into shared section ?
Nobody needs this. Unless you are building spyware maybe, or you’re debugging your… pop3/smtp/http/whatever-server. Now… who is doing that??
On a technical note: it desperately needs a thread pool, to get rid of the initial delay on each new connection. That, and with a few minor changes, it can run on my Priobit (NIO) API – much better than spawning 3 (!) threads per TCP connection.
no this is just nice and can be usefull, yes for debugging mostly but also for doing & understanding a socks4 proxy
SOCKS4 is … easy! It’s laughable. There is nothing to learn!
Having said that, I’m going to write a nice NIO implementation
Improved Priobit a bit, to make to possible to use:
- fixed-length packets (SOCKS4 header)
- null-terminated-strings (SOCKS4 userid)
- direct streaming (SOCKS4 transfering received bytes)
in the same TCP-stream.
And the very convenient client.disconnectOnSent();
to ensure the last outbound bytes are sent, before disconnecting.
http://code.google.com/p/priobit/source/browse/trunk/%20priobit/test/jawnae/priobit/SOCKS4.java
// fixed length packet
ByteFilter header = new ByteFilterLength(8)
{
@Override
public void onReady(ByteBuffer buffer)
{
...
}
};
// null-terminated-string
ByteFilter userid = new ByteFilterEndsWith(new byte[] { (byte) 0x00 }, 256)
{
@Override
public void onReady(ByteBuffer buffer)
{
...
// start streaming (direct handling) of bytes
client.applyReadStrategy(ReadStrategy.PASS_COPIED_BUFFER);
}
};
src.applyReadStrategy(ReadStrategy.USE_BYTE_FILTER);
src.enqueueByteFilter(header); // onReady will be invoked when done, it will continue with the userid
src.enqueueByteFilter(userid); // onReady will be invoked when done, it will continue with plain streaming of bytes
// result of PASS_COPIED_BUFFER
@Override
public void receivedData(NioClient client, ByteBuffer data)
{
NioClient other = (NioClient) client.attachment();
// just send to the other client what we received
other.enqueue(data);
}