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,
|
||||
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 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_compress: tcpmode_compress,
|
||||
tcpmode_stat: tcpmode_stat,
|
||||
open_sock5: open_sock5,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -75,6 +76,7 @@ type Client struct {
|
||||
tcpmode_resend_timems int
|
||||
tcpmode_compress int
|
||||
tcpmode_stat int
|
||||
open_sock5 int
|
||||
|
||||
ipaddr *net.UDPAddr
|
||||
tcpaddr *net.TCPAddr
|
||||
@ -201,13 +203,17 @@ func (p *Client) AcceptTcp() error {
|
||||
}
|
||||
|
||||
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()
|
||||
tcpsrcaddr := conn.RemoteAddr().(*net.TCPAddr)
|
||||
@ -234,7 +240,7 @@ func (p *Client) AcceptTcpConn(conn *net.TCPConn) {
|
||||
f := e.Value.(*Frame)
|
||||
mb, _ := proto.Marshal(f)
|
||||
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,
|
||||
p.tcpmode, p.tcpmode_buffersize, p.tcpmode_maxwin, p.tcpmode_resend_timems, p.tcpmode_compress, p.tcpmode_stat,
|
||||
p.timeout)
|
||||
@ -294,7 +300,7 @@ func (p *Client) AcceptTcpConn(conn *net.TCPConn) {
|
||||
continue
|
||||
}
|
||||
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,
|
||||
p.tcpmode, 0, 0, 0, 0, 0,
|
||||
0)
|
||||
@ -355,7 +361,7 @@ func (p *Client) AcceptTcpConn(conn *net.TCPConn) {
|
||||
f := e.Value.(*Frame)
|
||||
mb, _ := proto.Marshal(f)
|
||||
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,
|
||||
p.tcpmode, 0, 0, 0, 0, 0,
|
||||
0)
|
||||
@ -530,7 +536,7 @@ func (p *Client) ping() {
|
||||
if p.sendPacket == 0 {
|
||||
now := time.Now()
|
||||
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,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0)
|
||||
@ -547,3 +553,32 @@ func (p *Client) showNet() {
|
||||
p.sendPacketSize = 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:
|
||||
|
||||
// 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
|
||||
|
||||
// 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 服务器或者客户端
|
||||
client or server
|
||||
|
||||
@ -59,6 +67,9 @@ Usage:
|
||||
|
||||
-loglevel 日志文件等级,默认info
|
||||
log level, default is info
|
||||
|
||||
-sock5 开启sock5转发,默认0
|
||||
Turn on sock5 forwarding, default 0 is off
|
||||
`
|
||||
|
||||
func main() {
|
||||
@ -77,16 +88,30 @@ func main() {
|
||||
nolog := flag.Int("nolog", 0, "write log file")
|
||||
tcpmode_stat := flag.Int("tcp_stat", 0, "print tcp stat")
|
||||
loglevel := flag.String("loglevel", "info", "log level")
|
||||
open_sock5 := flag.Int("sock5", 0, "sock5 mode")
|
||||
flag.Usage = func() {
|
||||
fmt.Printf(usage)
|
||||
}
|
||||
|
||||
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()
|
||||
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 {
|
||||
fmt.Println("set tcp win to big, max = " + strconv.Itoa(pingtunnel.FRAME_MAX_ID/10))
|
||||
return
|
||||
@ -129,7 +154,7 @@ func main() {
|
||||
|
||||
c, err := pingtunnel.NewClient(*listen, *server, *target, *timeout, *key,
|
||||
*tcpmode, *tcpmode_buffersize, *tcpmode_maxwin, *tcpmode_resend_timems, *tcpmode_compress,
|
||||
*tcpmode_stat)
|
||||
*tcpmode_stat, *open_sock5)
|
||||
if err != nil {
|
||||
loggo.Error("ERROR: %s", err.Error())
|
||||
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