Initial commit
commit
e79873c7b5
@ -0,0 +1,3 @@
|
|||||||
|
*.exe
|
||||||
|
*~
|
||||||
|
*bak
|
@ -0,0 +1,20 @@
|
|||||||
|
socks-go
|
||||||
|
=======
|
||||||
|
|
||||||
|
A socks server implement by golang, support socks4/4a, socks5.
|
||||||
|
|
||||||
|
|
||||||
|
usage
|
||||||
|
====
|
||||||
|
Usage example:
|
||||||
|
|
||||||
|
import "github.com/fangdingjun/socks"
|
||||||
|
|
||||||
|
fucn main(){
|
||||||
|
l, _ := net.Listen("tcp", ":1080")
|
||||||
|
for {
|
||||||
|
conn, _ := l.Accept()
|
||||||
|
s := socks.SocksConn{conn}
|
||||||
|
go s.Serve()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
socks-server
|
||||||
|
============
|
||||||
|
|
||||||
|
this is a socks server example.
|
||||||
|
|
||||||
|
run it
|
||||||
|
|
||||||
|
go run server.go
|
||||||
|
|
||||||
|
test it
|
||||||
|
|
||||||
|
curl --socks4 127.0.0.1:1080 http://www.google.com/
|
||||||
|
curl --socks4a 127.0.0.1:1080 http://www.google.com/
|
||||||
|
curl --socks5 127.0.0.1:1080 http://www.google.com/
|
||||||
|
curl --socks5-hostname 127.0.0.1:1080 http://www.google.com/
|
@ -0,0 +1,24 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/fangdingjun/socks"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
conn, err := net.Listen("tcp", ":1080")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
c, err := conn.Accept()
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
log.Printf("connected from %s", c.RemoteAddr())
|
||||||
|
s := socks.SocksConn{ClientConn: c}
|
||||||
|
go s.Serve()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
package socks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
socks4Version = 0x04
|
||||||
|
socks5Version = 0x05
|
||||||
|
cmdConnect = 0x01
|
||||||
|
addrTypeIPv4 = 0x01
|
||||||
|
addrTypeDomain = 0x03
|
||||||
|
addrTypeIPv6 = 0x04
|
||||||
|
)
|
||||||
|
|
||||||
|
type SocksConn struct {
|
||||||
|
ClientConn net.Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SocksConn) Serve() {
|
||||||
|
buf := make([]byte, 1)
|
||||||
|
|
||||||
|
// read version
|
||||||
|
io.ReadFull(s.ClientConn, buf)
|
||||||
|
|
||||||
|
switch buf[0] {
|
||||||
|
case socks4Version:
|
||||||
|
s4 := socks4Conn{client_conn: s.ClientConn}
|
||||||
|
s4.Serve()
|
||||||
|
case socks5Version:
|
||||||
|
s5 := socks5Conn{client_conn: s.ClientConn}
|
||||||
|
s5.Serve()
|
||||||
|
default:
|
||||||
|
log.Printf("error version %s", buf[0])
|
||||||
|
s.ClientConn.Close()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,104 @@
|
|||||||
|
package socks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
type socks4Conn struct {
|
||||||
|
server_conn net.Conn
|
||||||
|
client_conn net.Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s4 *socks4Conn) Serve() {
|
||||||
|
defer s4.Close()
|
||||||
|
if err := s4.processRequest(); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s4 *socks4Conn) Close() {
|
||||||
|
if s4.client_conn != nil {
|
||||||
|
s4.client_conn.Close()
|
||||||
|
}
|
||||||
|
if s4.server_conn != nil {
|
||||||
|
s4.server_conn.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s4 *socks4Conn) forward() {
|
||||||
|
go func() {
|
||||||
|
io.Copy(s4.client_conn, s4.server_conn)
|
||||||
|
}()
|
||||||
|
|
||||||
|
io.Copy(s4.server_conn, s4.client_conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s4 *socks4Conn) processRequest() error {
|
||||||
|
// version has already read out by socksConn.Serve()
|
||||||
|
// process command and target here
|
||||||
|
|
||||||
|
buf := make([]byte, 128)
|
||||||
|
n, err := io.ReadAtLeast(s4.client_conn, buf, 8)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// only support connect
|
||||||
|
if buf[0] != cmdConnect {
|
||||||
|
return fmt.Errorf("error command %s", buf[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
port := binary.BigEndian.Uint16(buf[1:3])
|
||||||
|
|
||||||
|
ip := net.IP(buf[3:7])
|
||||||
|
|
||||||
|
// NULL-terminated user string
|
||||||
|
// jump to NULL character
|
||||||
|
var j int
|
||||||
|
for j = 7; j < n; j++ {
|
||||||
|
if buf[j] == 0x00 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
host := ip.String()
|
||||||
|
|
||||||
|
// socks4a
|
||||||
|
// 0.0.0.x
|
||||||
|
if ip[0] == 0x00 && ip[1] == 0x00 && ip[2] == 0x00 && ip[3] != 0x00 {
|
||||||
|
j++
|
||||||
|
var i = j
|
||||||
|
|
||||||
|
// jump to the end of hostname
|
||||||
|
for j = i; j < n; j++ {
|
||||||
|
if buf[j] == 0x00 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
host = string(buf[i:j])
|
||||||
|
}
|
||||||
|
|
||||||
|
target := net.JoinHostPort(host, fmt.Sprintf("%d", port))
|
||||||
|
|
||||||
|
// reply user with connect success
|
||||||
|
// if dial to target failed, user will receive connection reset
|
||||||
|
s4.client_conn.Write([]byte{0x00, 0x5a, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00})
|
||||||
|
|
||||||
|
log.Printf("connecting to %s", target)
|
||||||
|
|
||||||
|
// connect to the target
|
||||||
|
s4.server_conn, err = net.Dial("tcp", target)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// enter data exchange
|
||||||
|
s4.forward()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -0,0 +1,133 @@
|
|||||||
|
package socks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
//"strconv"
|
||||||
|
"encoding/binary"
|
||||||
|
)
|
||||||
|
|
||||||
|
type socks5Conn struct {
|
||||||
|
//addr string
|
||||||
|
client_conn net.Conn
|
||||||
|
server_conn net.Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s5 *socks5Conn) Serve() {
|
||||||
|
defer s5.Close()
|
||||||
|
if err := s5.handshake(); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s5.processRequest(); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s5 *socks5Conn) handshake() error {
|
||||||
|
// version has already readed by socksConn.Serve()
|
||||||
|
// only process auth methods here
|
||||||
|
|
||||||
|
buf := make([]byte, 258)
|
||||||
|
n, err := io.ReadAtLeast(s5.client_conn, buf, 1)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
l := int(buf[0]) + 1
|
||||||
|
if n < l {
|
||||||
|
_, err := io.ReadFull(s5.client_conn, buf[n:l])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// no auth required
|
||||||
|
s5.client_conn.Write([]byte{0x05, 0x00})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s5 *socks5Conn) processRequest() error {
|
||||||
|
buf := make([]byte, 258)
|
||||||
|
n, err := io.ReadAtLeast(s5.client_conn, buf, 10)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if buf[0] != socks5Version {
|
||||||
|
return fmt.Errorf("error version %s", buf[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
// only support connect
|
||||||
|
if buf[1] != cmdConnect {
|
||||||
|
return fmt.Errorf("unsupported command %s", buf[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
hlen := 0
|
||||||
|
host := ""
|
||||||
|
msglen := 0
|
||||||
|
switch buf[3] {
|
||||||
|
case addrTypeIPv4:
|
||||||
|
hlen = 4
|
||||||
|
case addrTypeDomain:
|
||||||
|
hlen = int(buf[4]) + 1
|
||||||
|
case addrTypeIPv6:
|
||||||
|
hlen = 16
|
||||||
|
}
|
||||||
|
|
||||||
|
msglen = 6 + hlen
|
||||||
|
|
||||||
|
if n < msglen {
|
||||||
|
_, err := io.ReadFull(s5.client_conn, buf[n:msglen])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get target address
|
||||||
|
addr := buf[4 : 4+hlen]
|
||||||
|
if buf[3] == addrTypeDomain {
|
||||||
|
host = string(addr[1:])
|
||||||
|
} else {
|
||||||
|
host = net.IP(addr).String()
|
||||||
|
}
|
||||||
|
|
||||||
|
port := binary.BigEndian.Uint16(buf[msglen-2 : msglen])
|
||||||
|
|
||||||
|
target := net.JoinHostPort(host, fmt.Sprintf("%d", port))
|
||||||
|
|
||||||
|
// reply user with connect success
|
||||||
|
// if dial to target failed, user will receive connection reset
|
||||||
|
s5.client_conn.Write([]byte{0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01})
|
||||||
|
|
||||||
|
log.Printf("connecing to %s", target)
|
||||||
|
|
||||||
|
// connect to the target
|
||||||
|
s5.server_conn, err = net.Dial("tcp", target)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// enter data exchange
|
||||||
|
s5.forward()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s5 *socks5Conn) forward() {
|
||||||
|
go io.Copy(s5.client_conn, s5.server_conn)
|
||||||
|
io.Copy(s5.server_conn, s5.client_conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s5 *socks5Conn) Close() {
|
||||||
|
if s5.server_conn != nil {
|
||||||
|
s5.server_conn.Close()
|
||||||
|
}
|
||||||
|
if s5.client_conn != nil {
|
||||||
|
s5.client_conn.Close()
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue