Created
June 20, 2012 16:04
-
-
Save amir/2960672 to your computer and use it in GitHub Desktop.
net.Dial alike Dial for SOCKS4a, and SOCKS5, or how to use http.Client's Transport element to proxy HTTP calls
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bytes" | |
"encoding/binary" | |
"io/ioutil" | |
"log" | |
"net" | |
"net/http" | |
"strconv" | |
) | |
func main() { | |
tr := &http.Transport{ | |
Dial: DialSOCKS5, // or DialSOCKS4a | |
} | |
c := &http.Client{ | |
Transport: tr, | |
} | |
res, err := c.Get("http://echoip.com") | |
if err != nil { | |
log.Fatalf("%s", err) | |
} | |
body, err := ioutil.ReadAll(res.Body) | |
if err != nil { | |
log.Fatalf("%s", err) | |
} | |
log.Print(string(body)) | |
} | |
func DialSOCKS4a(network, addr string) (c net.Conn, err error) { | |
laddr, _ := net.ResolveTCPAddr("tcp", "127.0.0.1") | |
raddr, _ := net.ResolveTCPAddr("tcp", "127.0.0.1:9999") // SOCKS4a server | |
host, p, err := net.SplitHostPort(addr) | |
if err != nil { | |
return | |
} | |
port, err := strconv.Atoi(p) | |
if err != nil { | |
return | |
} | |
c, err = net.DialTCP("tcp", laddr, raddr) | |
buffer := bytes.NewBuffer([]byte{}) | |
// SOCKS version number | |
binary.Write(buffer, binary.BigEndian, []byte{0x04}) | |
// Command code. 0x01 to establish a TCP/IP stream connection | |
binary.Write(buffer, binary.BigEndian, []byte{0x01}) | |
// Network byte order port number | |
binary.Write(buffer, binary.BigEndian, uint16(port)) | |
// Deliberate invalid IP address | |
binary.Write(buffer, binary.BigEndian, []byte{0x00, 0x00, 0x00, 0x01}) | |
// User ID | |
binary.Write(buffer, binary.BigEndian, []byte{0x00}) | |
// Domain name of the host we want to contact | |
binary.Write(buffer, binary.BigEndian, []byte(host)) | |
// Since domain name is variable lengthm terminate it with a null | |
binary.Write(buffer, binary.BigEndian, []byte{0x00}) | |
binary.Write(c, binary.BigEndian, buffer.Bytes()) | |
data := make([]byte, 8) | |
_, err = c.Read(data) | |
if err != nil { | |
return | |
} | |
return | |
} | |
func DialSOCKS5(network, addr string) (c net.Conn, err error) { | |
laddr, _ := net.ResolveTCPAddr("tcp", "127.0.0.1") | |
raddr, _ := net.ResolveTCPAddr("tcp", "127.0.0.1:9999") // SOCKS5 server | |
host, p, err := net.SplitHostPort(addr) | |
if err != nil { | |
return | |
} | |
port, err := strconv.Atoi(p) | |
if err != nil { | |
return | |
} | |
c, err = net.DialTCP("tcp", laddr, raddr) | |
version := []byte{0x05} | |
buffer := bytes.NewBuffer([]byte{}) | |
// SOCKS version number | |
binary.Write(buffer, binary.BigEndian, version) | |
// In SOCKS5 initial handshake is different | |
// A greeting which includes a list of authentication methods supported | |
// Only one authentication method is supported | |
binary.Write(buffer, binary.BigEndian, []byte{0x01}) | |
// Supported authentication method is "No authentication" | |
binary.Write(buffer, binary.BigEndian, []byte{0x00}) | |
binary.Write(c, binary.BigEndian, buffer.Bytes()) | |
data := make([]byte, 8) | |
_, err = c.Read(data) | |
if err != nil { | |
return | |
} | |
buffer = bytes.NewBuffer([]byte{}) | |
// SOCKS version number | |
binary.Write(buffer, binary.BigEndian, version) | |
// Command code. 0x01 to establish a TCP/IP stream connection | |
binary.Write(buffer, binary.BigEndian, []byte{0x01}) | |
// Reserved, must be 0x00 | |
binary.Write(buffer, binary.BigEndian, []byte{0x00}) | |
// Address type. 0x03 is for domain name | |
binary.Write(buffer, binary.BigEndian, []byte{0x03}) | |
// Length of domain name | |
binary.Write(buffer, binary.BigEndian, []byte{byte(len(host))}) | |
// Domain name | |
binary.Write(buffer, binary.BigEndian, []byte(host)) | |
// Network byte order port number | |
binary.Write(buffer, binary.BigEndian, uint16(port)) | |
binary.Write(c, binary.BigEndian, buffer.Bytes()) | |
data = make([]byte, 16) | |
_, err = c.Read(data) | |
if err != nil { | |
return | |
} | |
return | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment