add
This commit is contained in:
parent
e1fb19862c
commit
15c292777f
49
client.go
49
client.go
@ -18,7 +18,7 @@ const (
|
|||||||
|
|
||||||
func NewClient(addr string, server string, target string, timeout int, key int,
|
func NewClient(addr string, server string, target string, timeout int, key int,
|
||||||
tcpmode int, tcpmode_buffersize int, tcpmode_maxwin int, tcpmode_resend_timems int, tcpmode_compress int,
|
tcpmode int, tcpmode_buffersize int, tcpmode_maxwin int, tcpmode_resend_timems int, tcpmode_compress int,
|
||||||
tcpmode_stat int) (*Client, error) {
|
tcpmode_stat int, open_sock5 int) (*Client, error) {
|
||||||
|
|
||||||
var ipaddr *net.UDPAddr
|
var ipaddr *net.UDPAddr
|
||||||
var tcpaddr *net.TCPAddr
|
var tcpaddr *net.TCPAddr
|
||||||
@ -58,6 +58,7 @@ func NewClient(addr string, server string, target string, timeout int, key int,
|
|||||||
tcpmode_resend_timems: tcpmode_resend_timems,
|
tcpmode_resend_timems: tcpmode_resend_timems,
|
||||||
tcpmode_compress: tcpmode_compress,
|
tcpmode_compress: tcpmode_compress,
|
||||||
tcpmode_stat: tcpmode_stat,
|
tcpmode_stat: tcpmode_stat,
|
||||||
|
open_sock5: open_sock5,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,6 +76,7 @@ type Client struct {
|
|||||||
tcpmode_resend_timems int
|
tcpmode_resend_timems int
|
||||||
tcpmode_compress int
|
tcpmode_compress int
|
||||||
tcpmode_stat int
|
tcpmode_stat int
|
||||||
|
open_sock5 int
|
||||||
|
|
||||||
ipaddr *net.UDPAddr
|
ipaddr *net.UDPAddr
|
||||||
tcpaddr *net.TCPAddr
|
tcpaddr *net.TCPAddr
|
||||||
@ -201,13 +203,17 @@ func (p *Client) AcceptTcp() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if conn != nil {
|
if conn != nil {
|
||||||
go p.AcceptTcpConn(conn)
|
if p.open_sock5 > 0 {
|
||||||
|
go p.AcceptSock5Conn(conn)
|
||||||
|
} else {
|
||||||
|
go p.AcceptTcpConn(conn, p.targetAddr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Client) AcceptTcpConn(conn *net.TCPConn) {
|
func (p *Client) AcceptTcpConn(conn *net.TCPConn, targetAddr string) {
|
||||||
|
|
||||||
uuid := UniqueId()
|
uuid := UniqueId()
|
||||||
tcpsrcaddr := conn.RemoteAddr().(*net.TCPAddr)
|
tcpsrcaddr := conn.RemoteAddr().(*net.TCPAddr)
|
||||||
@ -234,7 +240,7 @@ func (p *Client) AcceptTcpConn(conn *net.TCPConn) {
|
|||||||
f := e.Value.(*Frame)
|
f := e.Value.(*Frame)
|
||||||
mb, _ := proto.Marshal(f)
|
mb, _ := proto.Marshal(f)
|
||||||
p.sequence++
|
p.sequence++
|
||||||
sendICMP(p.id, p.sequence, *p.conn, p.ipaddrServer, p.targetAddr, clientConn.id, (uint32)(MyMsg_DATA), mb,
|
sendICMP(p.id, p.sequence, *p.conn, p.ipaddrServer, targetAddr, clientConn.id, (uint32)(MyMsg_DATA), mb,
|
||||||
SEND_PROTO, RECV_PROTO, p.key,
|
SEND_PROTO, RECV_PROTO, p.key,
|
||||||
p.tcpmode, p.tcpmode_buffersize, p.tcpmode_maxwin, p.tcpmode_resend_timems, p.tcpmode_compress, p.tcpmode_stat,
|
p.tcpmode, p.tcpmode_buffersize, p.tcpmode_maxwin, p.tcpmode_resend_timems, p.tcpmode_compress, p.tcpmode_stat,
|
||||||
p.timeout)
|
p.timeout)
|
||||||
@ -294,7 +300,7 @@ func (p *Client) AcceptTcpConn(conn *net.TCPConn) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
p.sequence++
|
p.sequence++
|
||||||
sendICMP(p.id, p.sequence, *p.conn, p.ipaddrServer, p.targetAddr, clientConn.id, (uint32)(MyMsg_DATA), mb,
|
sendICMP(p.id, p.sequence, *p.conn, p.ipaddrServer, targetAddr, clientConn.id, (uint32)(MyMsg_DATA), mb,
|
||||||
SEND_PROTO, RECV_PROTO, p.key,
|
SEND_PROTO, RECV_PROTO, p.key,
|
||||||
p.tcpmode, 0, 0, 0, 0, 0,
|
p.tcpmode, 0, 0, 0, 0, 0,
|
||||||
0)
|
0)
|
||||||
@ -355,7 +361,7 @@ func (p *Client) AcceptTcpConn(conn *net.TCPConn) {
|
|||||||
f := e.Value.(*Frame)
|
f := e.Value.(*Frame)
|
||||||
mb, _ := proto.Marshal(f)
|
mb, _ := proto.Marshal(f)
|
||||||
p.sequence++
|
p.sequence++
|
||||||
sendICMP(p.id, p.sequence, *p.conn, p.ipaddrServer, p.targetAddr, clientConn.id, (uint32)(MyMsg_DATA), mb,
|
sendICMP(p.id, p.sequence, *p.conn, p.ipaddrServer, targetAddr, clientConn.id, (uint32)(MyMsg_DATA), mb,
|
||||||
SEND_PROTO, RECV_PROTO, p.key,
|
SEND_PROTO, RECV_PROTO, p.key,
|
||||||
p.tcpmode, 0, 0, 0, 0, 0,
|
p.tcpmode, 0, 0, 0, 0, 0,
|
||||||
0)
|
0)
|
||||||
@ -530,7 +536,7 @@ func (p *Client) ping() {
|
|||||||
if p.sendPacket == 0 {
|
if p.sendPacket == 0 {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
b, _ := now.MarshalBinary()
|
b, _ := now.MarshalBinary()
|
||||||
sendICMP(p.id, p.sequence, *p.conn, p.ipaddrServer, p.targetAddr, "", (uint32)(MyMsg_PING), b,
|
sendICMP(p.id, p.sequence, *p.conn, p.ipaddrServer, "", "", (uint32)(MyMsg_PING), b,
|
||||||
SEND_PROTO, RECV_PROTO, p.key,
|
SEND_PROTO, RECV_PROTO, p.key,
|
||||||
0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0,
|
||||||
0)
|
0)
|
||||||
@ -547,3 +553,32 @@ func (p *Client) showNet() {
|
|||||||
p.sendPacketSize = 0
|
p.sendPacketSize = 0
|
||||||
p.recvPacketSize = 0
|
p.recvPacketSize = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Client) AcceptSock5Conn(conn *net.TCPConn) {
|
||||||
|
|
||||||
|
var err error = nil
|
||||||
|
if err = sock5Handshake(conn); err != nil {
|
||||||
|
loggo.Error("socks handshake: %s", err)
|
||||||
|
conn.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, addr, err := sock5GetRequest(conn)
|
||||||
|
if err != nil {
|
||||||
|
loggo.Error("error getting request: %s", err)
|
||||||
|
conn.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Sending connection established message immediately to client.
|
||||||
|
// This some round trip time for creating socks connection with the client.
|
||||||
|
// But if connection failed, the client will get connection reset error.
|
||||||
|
_, err = conn.Write([]byte{0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x43})
|
||||||
|
if err != nil {
|
||||||
|
loggo.Error("send connection confirmation:", err)
|
||||||
|
conn.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
loggo.Info("accept new sock5 conn: %s", addr)
|
||||||
|
|
||||||
|
p.AcceptTcpConn(conn, addr)
|
||||||
|
}
|
||||||
|
29
cmd/main.go
29
cmd/main.go
@ -14,10 +14,18 @@ var usage = `
|
|||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
|
|
||||||
|
// server
|
||||||
pingtunnel -type server
|
pingtunnel -type server
|
||||||
|
|
||||||
|
// client, Forward udp
|
||||||
|
pingtunnel -type client -l LOCAL_IP:4455 -s SERVER_IP -t SERVER_IP:4455
|
||||||
|
|
||||||
|
// client, Forward tcp
|
||||||
pingtunnel -type client -l LOCAL_IP:4455 -s SERVER_IP -t SERVER_IP:4455 -tcp 1
|
pingtunnel -type client -l LOCAL_IP:4455 -s SERVER_IP -t SERVER_IP:4455 -tcp 1
|
||||||
|
|
||||||
|
// client, Forward sock5, implicitly open tcp, so no target server is needed
|
||||||
|
pingtunnel -type client -l LOCAL_IP:4455 -s SERVER_IP -sock5 1
|
||||||
|
|
||||||
-type 服务器或者客户端
|
-type 服务器或者客户端
|
||||||
client or server
|
client or server
|
||||||
|
|
||||||
@ -59,6 +67,9 @@ Usage:
|
|||||||
|
|
||||||
-loglevel 日志文件等级,默认info
|
-loglevel 日志文件等级,默认info
|
||||||
log level, default is info
|
log level, default is info
|
||||||
|
|
||||||
|
-sock5 开启sock5转发,默认0
|
||||||
|
Turn on sock5 forwarding, default 0 is off
|
||||||
`
|
`
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -77,16 +88,30 @@ func main() {
|
|||||||
nolog := flag.Int("nolog", 0, "write log file")
|
nolog := flag.Int("nolog", 0, "write log file")
|
||||||
tcpmode_stat := flag.Int("tcp_stat", 0, "print tcp stat")
|
tcpmode_stat := flag.Int("tcp_stat", 0, "print tcp stat")
|
||||||
loglevel := flag.String("loglevel", "info", "log level")
|
loglevel := flag.String("loglevel", "info", "log level")
|
||||||
|
open_sock5 := flag.Int("sock5", 0, "sock5 mode")
|
||||||
flag.Usage = func() {
|
flag.Usage = func() {
|
||||||
fmt.Printf(usage)
|
fmt.Printf(usage)
|
||||||
}
|
}
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
if (*t != "client" && *t != "server") || (*t == "client" && (len(*listen) == 0 || len(*target) == 0 || len(*server) == 0)) {
|
if *t != "client" && *t != "server" {
|
||||||
flag.Usage()
|
flag.Usage()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if *t == "client" {
|
||||||
|
if len(*listen) == 0 || len(*server) == 0 {
|
||||||
|
flag.Usage()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if *open_sock5 == 0 && len(*target) == 0 {
|
||||||
|
flag.Usage()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if *open_sock5 != 0 {
|
||||||
|
*tcpmode = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
if *tcpmode_maxwin*10 > pingtunnel.FRAME_MAX_ID {
|
if *tcpmode_maxwin*10 > pingtunnel.FRAME_MAX_ID {
|
||||||
fmt.Println("set tcp win to big, max = " + strconv.Itoa(pingtunnel.FRAME_MAX_ID/10))
|
fmt.Println("set tcp win to big, max = " + strconv.Itoa(pingtunnel.FRAME_MAX_ID/10))
|
||||||
return
|
return
|
||||||
@ -129,7 +154,7 @@ func main() {
|
|||||||
|
|
||||||
c, err := pingtunnel.NewClient(*listen, *server, *target, *timeout, *key,
|
c, err := pingtunnel.NewClient(*listen, *server, *target, *timeout, *key,
|
||||||
*tcpmode, *tcpmode_buffersize, *tcpmode_maxwin, *tcpmode_resend_timems, *tcpmode_compress,
|
*tcpmode, *tcpmode_buffersize, *tcpmode_maxwin, *tcpmode_resend_timems, *tcpmode_compress,
|
||||||
*tcpmode_stat)
|
*tcpmode_stat, *open_sock5)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
loggo.Error("ERROR: %s", err.Error())
|
loggo.Error("ERROR: %s", err.Error())
|
||||||
return
|
return
|
||||||
|
136
sock5.go
Normal file
136
sock5.go
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
package pingtunnel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errAddrType = errors.New("socks addr type not supported")
|
||||||
|
errVer = errors.New("socks version not supported")
|
||||||
|
errMethod = errors.New("socks only support 1 method now")
|
||||||
|
errAuthExtraData = errors.New("socks authentication get extra data")
|
||||||
|
errReqExtraData = errors.New("socks request get extra data")
|
||||||
|
errCmd = errors.New("socks command not supported")
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
socksVer5 = 5
|
||||||
|
socksCmdConnect = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
func sock5Handshake(conn net.Conn) (err error) {
|
||||||
|
const (
|
||||||
|
idVer = 0
|
||||||
|
idNmethod = 1
|
||||||
|
)
|
||||||
|
// version identification and method selection message in theory can have
|
||||||
|
// at most 256 methods, plus version and nmethod field in total 258 bytes
|
||||||
|
// the current rfc defines only 3 authentication methods (plus 2 reserved),
|
||||||
|
// so it won't be such long in practice
|
||||||
|
|
||||||
|
buf := make([]byte, 258)
|
||||||
|
|
||||||
|
var n int
|
||||||
|
conn.SetReadDeadline(time.Now().Add(time.Millisecond * 100))
|
||||||
|
// make sure we get the nmethod field
|
||||||
|
if n, err = io.ReadAtLeast(conn, buf, idNmethod+1); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if buf[idVer] != socksVer5 {
|
||||||
|
return errVer
|
||||||
|
}
|
||||||
|
nmethod := int(buf[idNmethod])
|
||||||
|
msgLen := nmethod + 2
|
||||||
|
if n == msgLen { // handshake done, common case
|
||||||
|
// do nothing, jump directly to send confirmation
|
||||||
|
} else if n < msgLen { // has more methods to read, rare case
|
||||||
|
if _, err = io.ReadFull(conn, buf[n:msgLen]); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else { // error, should not get extra data
|
||||||
|
return errAuthExtraData
|
||||||
|
}
|
||||||
|
// send confirmation: version 5, no authentication required
|
||||||
|
_, err = conn.Write([]byte{socksVer5, 0})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func sock5GetRequest(conn net.Conn) (rawaddr []byte, host string, err error) {
|
||||||
|
const (
|
||||||
|
idVer = 0
|
||||||
|
idCmd = 1
|
||||||
|
idType = 3 // address type index
|
||||||
|
idIP0 = 4 // ip address start index
|
||||||
|
idDmLen = 4 // domain address length index
|
||||||
|
idDm0 = 5 // domain address start index
|
||||||
|
|
||||||
|
typeIPv4 = 1 // type is ipv4 address
|
||||||
|
typeDm = 3 // type is domain address
|
||||||
|
typeIPv6 = 4 // type is ipv6 address
|
||||||
|
|
||||||
|
lenIPv4 = 3 + 1 + net.IPv4len + 2 // 3(ver+cmd+rsv) + 1addrType + ipv4 + 2port
|
||||||
|
lenIPv6 = 3 + 1 + net.IPv6len + 2 // 3(ver+cmd+rsv) + 1addrType + ipv6 + 2port
|
||||||
|
lenDmBase = 3 + 1 + 1 + 2 // 3 + 1addrType + 1addrLen + 2port, plus addrLen
|
||||||
|
)
|
||||||
|
// refer to getRequest in server.go for why set buffer size to 263
|
||||||
|
buf := make([]byte, 263)
|
||||||
|
var n int
|
||||||
|
conn.SetReadDeadline(time.Now().Add(time.Millisecond * 100))
|
||||||
|
// read till we get possible domain length field
|
||||||
|
if n, err = io.ReadAtLeast(conn, buf, idDmLen+1); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// check version and cmd
|
||||||
|
if buf[idVer] != socksVer5 {
|
||||||
|
err = errVer
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if buf[idCmd] != socksCmdConnect {
|
||||||
|
err = errCmd
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
reqLen := -1
|
||||||
|
switch buf[idType] {
|
||||||
|
case typeIPv4:
|
||||||
|
reqLen = lenIPv4
|
||||||
|
case typeIPv6:
|
||||||
|
reqLen = lenIPv6
|
||||||
|
case typeDm:
|
||||||
|
reqLen = int(buf[idDmLen]) + lenDmBase
|
||||||
|
default:
|
||||||
|
err = errAddrType
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if n == reqLen {
|
||||||
|
// common case, do nothing
|
||||||
|
} else if n < reqLen { // rare case
|
||||||
|
if _, err = io.ReadFull(conn, buf[n:reqLen]); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = errReqExtraData
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rawaddr = buf[idType:reqLen]
|
||||||
|
|
||||||
|
switch buf[idType] {
|
||||||
|
case typeIPv4:
|
||||||
|
host = net.IP(buf[idIP0 : idIP0+net.IPv4len]).String()
|
||||||
|
case typeIPv6:
|
||||||
|
host = net.IP(buf[idIP0 : idIP0+net.IPv6len]).String()
|
||||||
|
case typeDm:
|
||||||
|
host = string(buf[idDm0 : idDm0+buf[idDmLen]])
|
||||||
|
}
|
||||||
|
port := binary.BigEndian.Uint16(buf[reqLen-2 : reqLen])
|
||||||
|
host = net.JoinHostPort(host, strconv.Itoa(int(port)))
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user