尝试将net.Socket()
连接到SOCKS5服务器时,我得到以下stacktrace:
events.js:141
throw er; // Unhandled 'error' event
^
Error: write EPIPE
at exports._errnoException (util.js:870:11)
at WriteWrap.afterWrite (net.js:769:14)
我的代码如下:
var net = require('net');
var proxy = {
host: '115.159.155.96',
port: 1080,
dstHost: 'www.google.com',
dstPort: 80
};
var socket = new net.connect({
host: proxy.host,
port: proxy.port
}, function() {
console.log('connected!');
var addrlen = Buffer.byteLength(proxy.dstHost);
var reqbuf = new Buffer(7 + addrlen);
var p;
reqbuf[0] = 0x05;
reqbuf[1] = 0x01;
reqbuf[2] = 0x00;
reqbuf[3] = 0x03;
reqbuf[4] = addrlen;
reqbuf.write(proxy.dstHost, 5, addrlen);
p = 5 + addrlen;
reqbuf.writeUInt16BE(proxy.dstPort, p, true);
socket.write(reqbuf);
socket.on('data', function(data) {
if(data.toString('hex') == '0500') { // This means 0x05 for version 5 and 0x00 for 'succeeded', right?
var bfr = new Buffer('GET / HTTP/1.1\r\nHost: www.google.com');
socket.write(bfr);
// I also tried "socket.write('GET / HTTP/1.1\r\nHost: www.google.com');",
// but I got the same error.
}
console.log(data.toString());
});
});
我确定这不是连接套接字的正确方法。正确的方法是什么?
我从socksv5包中的
lib/client.js
中取出了上面的代码。顺便说一句,我不想使用现有的程序包(我知道有很多NodeJS的SOCKS-Client程序包),因为我想通过学习它来学习SOCKS。
编辑:这是
curl -vv --socks5-hostname 115.159.155.96:1080 http://api.ipify.org?format=json
的输出,类似于下面建议的Quedaro:root@mymachine:~# curl -vv --socks5-hostname 115.159.155.96:1080
http://api.ipify.org?format=json
* Rebuilt URL to: http://api.ipify.org/?format=json
* Hostname was NOT found in DNS cache
* Trying 115.159.155.96...
* Connected to 115.159.155.96 (115.159.155.96) port 1080 (#0)
> GET /?format=json HTTP/1.1
> User-Agent: curl/7.38.0
> Host: api.ipify.org
> Accept: */*
>
< HTTP/1.1 200 OK
* Server Cowboy is not blacklisted
< Server: Cowboy
< Connection: keep-alive
< Content-Type: application/json
< Date: Wed, 06 Apr 2016 18:15:59 GMT
< Content-Length: 23
< Via: 1.1 vegur
<
* Connection #0 to host api.ipify.org left intact
{"ip":"115.159.155.96"}
root@mymachine:~#
这意味着代理应该可以正常工作,不是吗?
我还向套接字添加了一个错误事件,只需将
err
记录到控制台即可。这就是我得到的:{ [Error: write EPIPE] code: 'EPIPE', errno: 'EPIPE', syscall: 'write' }
最佳答案
如果有人偶然发现此问题,请在此处添加工作代码。
就像@Quedaro提到的那样,socks5握手丢失了。
var net = require('net');
var proxy = {
host: 'localhost', // You can create a socks5 server by running `ssh -D 8001 xyz.com`
port: 8001,
destinationHost: 'www.google.com',
destinationPort: 80,
destinationPath: '/'
};
var socks5Handshake = new Buffer(3);
socks5Handshake[0] = 0x05; // SOCKS version number (must be 0x05 for this version)
socks5Handshake[1] = 0x01; // Number of authentication methods supported.
socks5Handshake[2] = 0x00; // 0x00: No authentication
var serverHandshakeResponse = "0500"; // SOCKS version number followed by chosen authentication method, 1 byte, or 0xFF if no acceptable methods were offered.
var serverConnectionResponse = "05000001000000000000";
var socket = new net.connect({
host: proxy.host,
port: proxy.port
}, function() {
// Socket connect done. Initiating Socks5 handshake
socket.write(socks5Handshake);
// Error event handler to handle error in case of ECONNRESET, ECONNREFUSED etc.
socket.on('error', function(err){
console.log('error!', err);
});
socket.once('data', function(data) {
if(data.toString('hex') == serverHandshakeResponse) {
var addressLength = Buffer.byteLength(proxy.destinationHost);
var requestBuffer = new Buffer(7 + addressLength);
var portOffset;
requestBuffer[0] = 0x05; // SOCKS version number (must be 0x05 for this version)
requestBuffer[1] = 0x01; // establish a TCP/IP stream connection
requestBuffer[2] = 0x00; // reserved, must be 0x00
requestBuffer[3] = 0x03; // address type, 1 byte. 0x03 = Domain name
requestBuffer[4] = addressLength; // 1 byte of name length followed by the name for domain name
requestBuffer.write(proxy.destinationHost, 5, addressLength);
portOffset = 5 + addressLength;
requestBuffer.writeUInt16BE(proxy.destinationPort, portOffset, true);
socket.write(requestBuffer);
socket.once('data', function(data){
if(data.toString('hex') == serverConnectionResponse) {
var requestBuffer = new Buffer("GET " + proxy.destinationPath + " HTTP/1.1\r\nHost: " + proxy.destinationHost + ":" + proxy.destinationPort + "\r\n\r\n");
socket.write(requestBuffer);
socket.once('data', function(data){
console.log("Response for the url:", proxy.destinationHost + ":" + proxy.destinationPort, "=>", data.toString().match(/^HTTP\/1\.. \d+/i)[0]);
socket.end();
});
}
else {
console.log("Socks5 connection request failed. Closing the socket");
socket.end();
}
});
}
else {
console.log("Socks5 handshake failed. Closing the socket");
socket.end();
}
});
});