Skip to content

Instantly share code, notes, and snippets.

@amir
Created June 20, 2012 16:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save amir/2960672 to your computer and use it in GitHub Desktop.
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
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