Reputation: 788
I get the following stacktrace when trying to make net.Socket()
connection to a SOCKS5-server:
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)
My code is as follows:
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());
});
});
I'm sure this is not the right way to do a connection to the socket. What would be the correct method to do it?
I took the code above out of lib/client.js
in the socksv5 package.
By the way, I do not want to use an existing package (I know there are lots of SOCKS-Client packages for NodeJS), because I would like to learn SOCKS by doing it.
Edit: Here is the output of curl -vv --socks5-hostname 115.159.155.96:1080 http://api.ipify.org?format=json
, like Quedaro suggested below:
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:~#
This means, that the proxy should work fine, doesn't it?
I also added an error-event to the socket, simply logging err
to console. This is, what I get:
{ [Error: write EPIPE] code: 'EPIPE', errno: 'EPIPE', syscall: 'write' }
Upvotes: 2
Views: 2918
Reputation: 171
Adding the working code here if someone stumbles upon this question.
As @Quedaro had mentioned, the socks5 handshake was missing.
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();
}
});
});
Upvotes: 4
Reputation: 49
Are you sure that socks server actually works? Write EPIPE
means the socket cannot be written because the connection had been dropped, hopefully closed by the server. Try it testing this command (on Linux systems):
curl -vv --socks5-hostname 115.159.155.96:1080 http://api.ipify.org?format=json
Also, before sending that data you may want to say 'hello' to the socks server, like sending these bytes: 0x05 0x02 0x00 0x01
To don't get thrown on any socket exception, try to capture the 'error'
event, like this:
socket.on('error', function(err){
console.log('error!', err);
});
Upvotes: 1