为啥我的 SOCKS5 UDP 实现不起作用?
Posted
技术标签:
【中文标题】为啥我的 SOCKS5 UDP 实现不起作用?【英文标题】:Why is my SOCKS5 UDP implementation not working?为什么我的 SOCKS5 UDP 实现不起作用? 【发布时间】:2018-06-11 10:05:31 【问题描述】:我在这个废话上花了 50 多个小时,为什么我的 UDP 实现不起作用?问题是服务器没有收到UDP数据包。我制作了服务器应用程序以在控制台中记录事件,但我发现它没有收到任何东西。这是我遵循的 SOCKS5 文档:https://www.ietf.org/rfc/rfc1928.txt
byte[] response = new byte[256];
int responseLength;
Socket socket = new Socket(proxyHost, proxyPort);
DatagramSocket clientSocket = new DatagramSocket();
DataOutputStream writer = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
DataInputStream reader = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
// connect/authorization request
writer.writeByte(0x05); // VER
writer.writeByte(1); // NMETHODS
writer.writeByte(0); // METHODS
writer.flush();
// connect/authorization response
responseLength = reader.read(response); // RESPONSE IS: 5 0
// udp associate request
writer.writeByte(0x05); // VER
writer.writeByte(0x03); // CMD - UDP ASSOCIATE
writer.writeByte(0x00); // RSV
writer.writeByte(0x01); // ATYP
// is what I'm sending here as DST.ADDR & DST.PORT okay?
writer.write(clientSocket.getLocalAddress().getAddress()); // DST.ADDR
writer.writeShort(clientSocket.getLocalPort()); // DST.PORT
//writer.write(InetAddress.getByName(trackerHost).getAddress());
//writer.writeShort(trackerPort);
writer.flush();
// udp associate response
reader.skipBytes(4); // skip VER, REP, RSV, ATYP bytes
relayAddress = reader.readInt();
InetAddress relayInetAddress = InetAddress.getByAddress(ByteBuffer.allocate(4).putInt(relayAddress).array());
relayPort = reader.readUnsignedShort(); // server returns some random port
// connect to relay server via datagramsocket
clientSocket.connect(relayInetAddress, relayPort);
// send package to destination server
ByteBuffer byteBuffer = ByteBuffer.allocate(16 + 10);
//header - 10 bytes
byteBuffer.putShort((short) 0); // RSV
byteBuffer.put((byte) 0); // FRAG
byteBuffer.put((byte) 1); // ATYP
byteBuffer.put(trackerInetAddress.getAddress()); // DST.ADDR
byteBuffer.putShort((short) targetPort); // DST.PORT
//packet data
byteBuffer.putLong(1);
byteBuffer.putInt(0);
byteBuffer.putInt(1);
// send packet
packet = byteBuffer.array();
DatagramPacket sendPacket = new DatagramPacket(packet, packet.length);//, relayInetAddress, relayPort);
clientSocket.send(sendPacket); // SERVER DOES NOT RECEIVE THIS
验证目标主机在没有代理的情况下可以 100% 正常工作。使用来自https://blazingseollc.com/proxy/ 的支持 SOCKS5 的半专用代理
【问题讨论】:
你为什么用Reader
读取字节?你为什么同时滥用Reader.ready()
和InputStream.available()
?
@EJP 请详细说明,这有什么问题? InputStream.available() 返回可供读取的字节数。我正在使用 ready() 以等待响应数据包到达。它适用于这部分,我收到身份验证和 udp 关联响应很好。读取(或更类似于接收)的问题仅出现在 DatagramSocket 部分。当然,在那部分之前可能已经犯了错误。任何可能的解决方案线索都是金,所以让我知道
1. Reader
读取 char
,而不是 byte
。 2. while (!inputStreamReader.ready());
除了抽你的 CPU 之外什么也没做,因为下面的读取无论如何都会阻塞。 3.有一个具体的警告,不要像你一样使用available()
。这都在 Javadoc 中。您也完全忽略了响应的内容;您还假设有响应而不是断开连接,并且响应表明成功。您需要解析它,并且这样做作为字节。你会发现DataInputStream
的方法很有用。而不是所有这些废话。
@EJP 好的,我用 DataInputStream 和 DataOutputStream 更新了代码;但这不是问题的代码之美,所以它没有解决任何问题
我不是在谈论“美”,我是在谈论正确性。 编写与 Javadoc 不一致的代码是不正确的。我发表了我的评论作为评论,而不是作为答案。我现在要问你为什么不对响应进行错误检查。
【参考方案1】:
原来代理提供商不支持 SOCKS5 的 UDP ASSOCIATE。事实证明大多数代理提供商不支持它。
【讨论】:
代理的响应在REP
字段中有一个状态码,指示请求是被接受还是被拒绝,如果被拒绝,那么为什么(例如0x07
表示“命令不支持”)。您的代码忽略了该字段(它也忽略了 ATYP
字段并假设响应始终包含 IPv4 地址,但这不是保证)。
我在调试器中检查和错误检查这些字段的响应,这些代理提供者甚至没有费心回复 0x07 或任何指示不支持的命令
他们必须用 something 来回应。 REP
字段中除0x00
之外的任何值都是请求失败。如果他们只是忽略请求而不发送响应,那么他们不符合协议。
那么他们不合规或配置错误
SOCKS 很容易实现,所以我非常怀疑任何代理制造商都不会遵循 complete 规范,即使不是所有命令都实现了。我强烈建议您使用像 Wireshark 这样的数据包嗅探器来验证您实际上以正确的格式传输 SOCKS 请求,并确保代理根本没有真正响应。也许是这样,只是你没有正确阅读。以上是关于为啥我的 SOCKS5 UDP 实现不起作用?的主要内容,如果未能解决你的问题,请参考以下文章