mirror of
https://github.com/p4gefau1t/trojan-go.git
synced 2024-04-21 12:21:34 +00:00
add dns support
This commit is contained in:
+1
-1
@@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
Version = "v0.4.3"
|
||||
Version = "v0.4.4"
|
||||
)
|
||||
|
||||
type Runnable interface {
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user