add dns support

This commit is contained in:
p4gefau1t
2020-05-03 10:01:07 -04:00
parent e47227c141
commit e0fb9c4e7f
10 changed files with 251 additions and 20 deletions
+1 -1
View File
@@ -11,7 +11,7 @@ import (
)
const (
Version = "v0.4.3"
Version = "v0.4.4"
)
type Runnable interface {
+9
View File
@@ -18,6 +18,15 @@ const (
Relay RunType = "relay"
)
type DNSType string
const (
UDP DNSType = "udp"
DOH DNSType = "https"
DOT DNSType = "dot"
TCP DNSType = "tcp"
)
type TLSConfig struct {
Verify bool `json:"verify"`
VerifyHostname bool `json:"verify_hostname"`
+1 -1
View File
@@ -16,7 +16,7 @@ enableMissingTranslationPlaceholders = false
# Source Code repository section
description = "An unidentifiable mechanism that helps you bypass GFW. "
github_repository = "https://github.com/p4gefau1t/trojan-go"
version = "0.4.3"
version = "0.4.4"
# Documentation repository section
# documentation repository (set edit link to documentation repository)
+1
View File
@@ -4,6 +4,7 @@ go 1.14
require (
github.com/LiamHaworth/go-tproxy v0.0.0-20190726054950-ef7efd7f24ed
github.com/babolivier/go-doh-client v0.0.0-20190212214242-43780baf3561
github.com/go-acme/lego/v3 v3.5.0
github.com/go-sql-driver/mysql v1.5.0
github.com/golang/protobuf v1.4.0
+2
View File
@@ -49,6 +49,8 @@ github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190808125512-07798873deee/go.mod
github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190307165228-86c17b95fcd5/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/aws/aws-sdk-go v1.23.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/babolivier/go-doh-client v0.0.0-20190212214242-43780baf3561 h1:Zq0ikckJ47+8cG0oAYH/XC3syJ0vGgSlTGtIsqlyPFE=
github.com/babolivier/go-doh-client v0.0.0-20190212214242-43780baf3561/go.mod h1:WorCk0sF6w5RjJorPxPL80q35XcMAPew90L8WSZxobY=
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+115 -4
View File
@@ -2,11 +2,15 @@ package direct
import (
"context"
"crypto/tls"
"io"
"net"
"net/url"
"time"
"github.com/babolivier/go-doh-client"
"github.com/p4gefau1t/trojan-go/common"
"github.com/p4gefau1t/trojan-go/conf"
"github.com/p4gefau1t/trojan-go/log"
"github.com/p4gefau1t/trojan-go/protocol"
)
@@ -29,10 +33,117 @@ func (o *DirectOutboundConnSession) Close() error {
return o.conn.Close()
}
func NewOutboundConnSession(req *protocol.Request) (protocol.ConnSession, error) {
newConn, err := net.Dial(req.Network(), req.String())
if err != nil {
return nil, err
func NewOutboundConnSession(ctx context.Context, req *protocol.Request, config *conf.GlobalConfig) (protocol.ConnSession, error) {
var newConn net.Conn
//custom dns server
if req.AddressType == common.DomainName && len(config.DNS) != 0 {
//find a avaliable dns server
for _, s := range config.DNS {
var dnsType conf.DNSType
var dnsAddr string
dnsURL, err := url.Parse(s)
if err != nil {
dnsType = conf.UDP
dnsAddr = s
} else {
dnsType = conf.DNSType(dnsURL.Scheme)
dnsAddr = dnsURL.Host
}
if dnsType == conf.DOH {
resolver := doh.Resolver{
Host: dnsURL.Host,
Class: doh.IN,
}
result := []string{}
a, _, err := resolver.LookupA(req.DomainName)
if err != nil {
log.Error(err)
continue
}
if !config.TCP.PreferIPV4 {
aaaa, _, err := resolver.LookupAAAA(req.DomainName)
if err != nil {
log.Error(err)
continue
}
for _, record := range aaaa {
result = append(result, record.IP6)
}
}
for _, record := range a {
result = append(result, record.IP4)
}
if len(result) == 0 {
log.Error("a record not found for" + req.DomainName)
continue
}
for _, ip := range result {
newConn, err = net.DialTCP("tcp", nil, &net.TCPAddr{
IP: net.ParseIP(ip),
Port: req.Port,
})
if err != nil {
return nil, err
}
break
}
} else {
resolver := &net.Resolver{
PreferGo: true,
Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
switch dnsType {
case conf.UDP, conf.TCP:
d := net.Dialer{
Timeout: time.Second * time.Duration(protocol.UDPTimeout),
}
conn, err := d.DialContext(ctx, string(dnsType), dnsAddr)
if err != nil {
return nil, err
}
return conn, nil
case conf.DOT:
tlsConn, err := tls.Dial("tcp", dnsAddr, nil)
if err != nil {
return nil, err
}
return tlsConn, nil
}
return nil, common.NewError("invalid dns type" + string(dnsType))
},
}
ips, err := resolver.LookupIPAddr(ctx, req.DomainName)
if err != nil {
log.Debug("dns server " + s + " sucks")
continue
}
log.Debug("dns connected:" + s)
if len(ips) == 0 {
return nil, common.NewError("record of " + req.DomainName + " not found in dns server " + s)
}
for _, ip := range ips {
newConn, err = net.DialTCP("tcp", nil, &net.TCPAddr{
IP: ip.IP,
Port: req.Port,
})
if err != nil {
return nil, err
}
break
}
}
break
}
if newConn == nil {
return nil, common.NewError("all dns servers are down")
}
} else {
//default resolver
var err error
newConn, err = net.Dial(req.Network(), req.String())
if err != nil {
return nil, err
}
}
o := &DirectOutboundConnSession{
request: req,
+90 -10
View File
@@ -5,23 +5,31 @@ import (
"fmt"
"math/rand"
"net"
"net/http"
"testing"
"time"
"github.com/p4gefau1t/trojan-go/common"
"github.com/p4gefau1t/trojan-go/conf"
"github.com/p4gefau1t/trojan-go/protocol"
"github.com/p4gefau1t/trojan-go/test"
)
func TestDirectOutbound(t *testing.T) {
for i := 0; i < 10; i++ {
go test.RunEchoUDPServer(context.Background())
}
func TestUDPDirectOutbound(t *testing.T) {
go test.RunMultipleUDPEchoServer(context.Background())
outbound, _ := NewOutboundPacketSession(context.Background())
for i := 0; i < 30; i++ {
go func() {
for i := 0; i < 5; i++ {
req, buf, err := outbound.ReadPacket()
fmt.Println(req, string(buf), err)
}
}()
for i := 0; i < 5; i++ {
req := &protocol.Request{
Address: &common.Address{
IP: net.ParseIP("127.0.0.1"),
Port: 6543,
IP: net.ParseIP("127.0.0.1"),
Port: 6000 + rand.Intn(10),
AddressType: common.IPv4,
},
}
req.Port += rand.Intn(10)
@@ -29,8 +37,80 @@ func TestDirectOutbound(t *testing.T) {
_, err := outbound.WritePacket(req, packet)
common.Must(err)
}
for i := 0; i < 30; i++ {
req, buf, err := outbound.ReadPacket()
fmt.Println(req, string(buf), err)
time.Sleep(time.Second * 5)
}
func TestDNS(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
go test.RunEchoTCPServer(ctx)
config := &conf.GlobalConfig{
DNS: []string{"114.114.114.114:53"},
}
req := &protocol.Request{
Address: &common.Address{
DomainName: "www.baidu.com",
Port: 80,
AddressType: common.DomainName,
NetworkType: "tcp",
},
}
conn, err := NewOutboundConnSession(ctx, req, config)
common.Must(err)
httpReq, err := http.NewRequest("GET", "http://www.baidu.com", nil)
common.Must(err)
httpReq.Write(conn)
buf := [128]byte{}
conn.Read(buf[:])
fmt.Println(string(buf[:]))
cancel()
}
func TestDOT(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
go test.RunEchoTCPServer(ctx)
config := &conf.GlobalConfig{
DNS: []string{"dot://223.5.5.5:853"},
}
req := &protocol.Request{
Address: &common.Address{
DomainName: "www.baidu.com",
Port: 80,
AddressType: common.DomainName,
NetworkType: "tcp",
},
}
conn, err := NewOutboundConnSession(ctx, req, config)
common.Must(err)
httpReq, err := http.NewRequest("GET", "http://www.baidu.com", nil)
common.Must(err)
httpReq.Write(conn)
buf := [128]byte{}
conn.Read(buf[:])
fmt.Println(string(buf[:]))
cancel()
}
func TestDOH(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
go test.RunEchoTCPServer(ctx)
config := &conf.GlobalConfig{
DNS: []string{"https://223.5.5.5:443"},
}
req := &protocol.Request{
Address: &common.Address{
DomainName: "www.baidu.com",
Port: 80,
AddressType: common.DomainName,
NetworkType: "tcp",
},
}
conn, err := NewOutboundConnSession(ctx, req, config)
common.Must(err)
httpReq, err := http.NewRequest("GET", "http://www.baidu.com", nil)
common.Must(err)
httpReq.Write(conn)
buf := [128]byte{}
conn.Read(buf[:])
fmt.Println(string(buf[:]))
cancel()
}
+2 -2
View File
@@ -95,7 +95,7 @@ func (c *Client) handleSocksConn(conn io.ReadWriteCloser) {
return
}
if policy == router.Bypass {
outboundConn, err := direct.NewOutboundConnSession(req)
outboundConn, err := direct.NewOutboundConnSession(c.ctx, req, c.config)
if err != nil {
log.Error(err)
return
@@ -139,7 +139,7 @@ func (c *Client) handleHTTPConn(conn io.ReadWriteCloser) {
return
}
if policy == router.Bypass {
outboundConn, err := direct.NewOutboundConnSession(req)
outboundConn, err := direct.NewOutboundConnSession(c.ctx, req, c.config)
if err != nil {
log.Error(err)
return
+2 -2
View File
@@ -41,7 +41,7 @@ func (s *Server) handleMuxConn(stream *smux.Stream) {
}
switch req.Command {
case protocol.Connect:
outboundConn, err := direct.NewOutboundConnSession(req)
outboundConn, err := direct.NewOutboundConnSession(s.ctx, req, s.config)
if err != nil {
log.Error(err)
return
@@ -102,7 +102,7 @@ func (s *Server) handleConn(conn *tls.Conn) {
}
defer inboundConn.Close()
outboundConn, err := direct.NewOutboundConnSession(req)
outboundConn, err := direct.NewOutboundConnSession(s.ctx, req, s.config)
if err != nil {
log.Error(err)
return
+28
View File
@@ -3,6 +3,7 @@ package test
import (
"context"
"crypto/rand"
"fmt"
"io"
"io/ioutil"
"net"
@@ -35,6 +36,33 @@ func RunEchoUDPServer(ctx context.Context) {
<-ctx.Done()
}
func RunMultipleUDPEchoServer(ctx context.Context) {
for i := 0; i < 10; i++ {
go func(port int) {
conn, err := net.ListenUDP("udp", &net.UDPAddr{
IP: net.ParseIP("127.0.0.1"),
Port: port,
})
common.Must(err)
fmt.Println("udp echo:", conn.LocalAddr())
defer conn.Close()
go func() {
for {
buf := make([]byte, 2048)
n, addr, err := conn.ReadFromUDP(buf[:])
if err != nil {
return
}
log.Info("echo from", addr)
conn.WriteToUDP(buf[0:n], addr)
}
}()
<-ctx.Done()
}(6000 + i)
}
<-ctx.Done()
}
func RunEchoTCPServer(ctx context.Context) {
listener, err := net.Listen("tcp", "127.0.0.1:5000")
common.Must(err)