Skip to content

Commit

Permalink
fix geoip path, websocket plaintext mode
Browse files Browse the repository at this point in the history
  • Loading branch information
p4gefau1t committed Jun 12, 2020
1 parent dab329c commit ed9cbc1
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 61 deletions.
72 changes: 72 additions & 0 deletions tunnel/raw/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@ package raw

import (
"context"
"crypto/tls"
"github.com/p4gefau1t/trojan-go/common"
"github.com/p4gefau1t/trojan-go/config"
"github.com/p4gefau1t/trojan-go/log"
"net"
"net/url"
"strconv"
"time"

"github.com/p4gefau1t/trojan-go/tunnel"
)
Expand All @@ -12,6 +18,71 @@ type Client struct {
preferIPv4 bool
noDelay bool
keepAlive bool
dns []string
ctx context.Context
}

func (c *Client) resolveIP(addr *tunnel.Address) ([]net.IPAddr, error) {
for _, s := range c.dns {
var dnsAddr string
var dnsHost, dnsType string
var err error

dnsURL, err := url.Parse(s)
if err != nil || dnsURL.Scheme == "" {
dnsType = "udp"
dnsAddr = s
} else {
dnsType = dnsURL.Scheme
dnsAddr = dnsURL.Host
}

dnsHost, tmp, err := net.SplitHostPort(dnsAddr)
dnsPort, err := strconv.ParseInt(tmp, 10, 32)
common.Must(err)

if err != nil {
dnsHost = dnsAddr
switch dnsType {
case "dot":
dnsPort = 853
case "tcp", "udp":
dnsPort = 53
}
}

resolver := &net.Resolver{
PreferGo: true,
Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
dnsAddress := tunnel.NewAddressFromHostPort("tcp", dnsHost, int(dnsPort))
switch dnsType {
case "udp", "tcp":
d := net.Dialer{
Timeout: time.Second * 5,
}
conn, err := d.DialContext(ctx, dnsType, dnsAddress.String())
if err != nil {
return nil, err
}
return conn, nil
case "dot":
tlsConn, err := tls.Dial("tcp", dnsAddress.String(), nil)
if err != nil {
return nil, err
}
return tlsConn, nil
}
return nil, common.NewError("invalid dns type:" + dnsType)
},
}
ip, err := resolver.LookupIPAddr(c.ctx, addr.String())
if err != nil {
log.Error(err)
continue
}
return ip, nil
}
return nil, common.NewError("address not found")
}

func (c *Client) DialConn(addr *tunnel.Address, t tunnel.Tunnel) (tunnel.Conn, error) {
Expand Down Expand Up @@ -53,6 +124,7 @@ func NewClient(ctx context.Context, client tunnel.Client) (*Client, error) {
// TODO implement dns
cfg := config.FromContext(ctx, Name).(*Config)
return &Client{
dns: cfg.DNS,
noDelay: cfg.TCP.NoDelay,
keepAlive: cfg.TCP.KeepAlive,
preferIPv4: cfg.TCP.PreferIPV4,
Expand Down
6 changes: 3 additions & 3 deletions tunnel/router/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,11 +265,11 @@ func NewClient(ctx context.Context, underlay tunnel.Client) (*Client, error) {
cancel: cancel,
}
switch cfg.Router.DomainStrategy {
case "as_is":
case "as_is", "as-is":
client.domainStrategy = AsIs
case "ip_if_non_match":
case "ip_if_non_match", "ip-if-non-match":
client.domainStrategy = IPIfNonMatch
case "ip_on_demand":
case "ip_on_demand", "ip-on-demand":
client.domainStrategy = IPOnDemand
default:
return nil, common.NewError("unknown strategy: " + cfg.Router.DomainStrategy)
Expand Down
9 changes: 5 additions & 4 deletions tunnel/router/config.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package router

import (
"github.com/p4gefau1t/trojan-go/common"
"github.com/p4gefau1t/trojan-go/config"
"os"
)
Expand All @@ -26,13 +27,13 @@ func init() {
Router: RouterConfig{
DefaultPolicy: "proxy",
DomainStrategy: "as_is",
GeoIPFilename: "geoip.dat",
GeoSiteFilename: "geosite.dat",
GeoIPFilename: common.GetProgramDir() + "/geoip.dat",
GeoSiteFilename: common.GetProgramDir() + "/geosite.dat",
},
}
if path := os.Getenv("TROJAN_GO_LOCATION_ASSET"); path != "" {
cfg.Router.GeoIPFilename = path + "geoip.dat"
cfg.Router.GeoSiteFilename = path + "geosite.dat"
cfg.Router.GeoIPFilename = path + "/geoip.dat"
cfg.Router.GeoSiteFilename = path + "/geosite.dat"
}
return cfg
})
Expand Down
110 changes: 56 additions & 54 deletions tunnel/transport/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,71 +71,73 @@ func (s *Server) acceptLoop() {
return
}
go func(tcpConn net.Conn) {
var transportConn net.Conn
if s.plugin {
s.connChan <- &Conn{
Conn: tcpConn,
// plain text mode
transportConn = tcpConn
} else {
// default tls
sniVerified := true
tlsConfig := &tls.Config{
Certificates: s.keyPair,
CipherSuites: s.cipherSuite,
PreferServerCipherSuites: s.PreferServerCipher,
SessionTicketsDisabled: !s.sessionTicket,
NextProtos: s.alpn,
KeyLogWriter: s.keyLogger,
GetCertificate: func(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
if s.verifySNI && hello.ServerName != s.sni {
sniVerified = false
return nil, common.NewError("sni mismatched: " + hello.ServerName + ", expected: " + s.sni)
}
return &s.keyPair[0], nil
},
}
return
}
sniVerified := true
tlsConfig := &tls.Config{
Certificates: s.keyPair,
CipherSuites: s.cipherSuite,
PreferServerCipherSuites: s.PreferServerCipher,
SessionTicketsDisabled: !s.sessionTicket,
NextProtos: s.alpn,
KeyLogWriter: s.keyLogger,
GetCertificate: func(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
if s.verifySNI && hello.ServerName != s.sni {
sniVerified = false
return nil, common.NewError("sni mismatched: " + hello.ServerName + ", expected: " + s.sni)
}
return &s.keyPair[0], nil
},
}

// ------------------------ WAR ZONE ----------------------------
// ------------------------ WAR ZONE ----------------------------

rewindConn := common.NewRewindConn(tcpConn)
rewindConn.SetBufferSize(2048)
rewindConn := common.NewRewindConn(tcpConn)
rewindConn.SetBufferSize(2048)

tlsConn := tls.Server(rewindConn, tlsConfig)
err = tlsConn.Handshake()
rewindConn.StopBuffering()
tlsConn := tls.Server(rewindConn, tlsConfig)
err = tlsConn.Handshake()
rewindConn.StopBuffering()

if err != nil {
if !sniVerified {
// close tls conn immediately if the sni is invalid
tlsConn.Close()
log.Error(common.NewError("tls client hello with wrong sni").Base(err))
} else if strings.Contains(err.Error(), "first record does not look like a TLS handshake") {
// not a valid tls client hello
rewindConn.Rewind()
log.Error(common.NewError("failed to perform tls handshake with " + tlsConn.RemoteAddr().String() + ", redirecting").Base(err))
if s.fallbackAddress != nil {
s.redir.Redirect(&redirector.Redirection{
InboundConn: rewindConn,
RedirectTo: s.fallbackAddress,
})
} else if s.httpResp != nil {
rewindConn.Write(s.httpResp)
rewindConn.Close()
if err != nil {
if !sniVerified {
// close tls conn immediately if the sni is invalid
tlsConn.Close()
log.Error(common.NewError("tls client hello with wrong sni").Base(err))
} else if strings.Contains(err.Error(), "first record does not look like a TLS handshake") {
// not a valid tls client hello
rewindConn.Rewind()
log.Error(common.NewError("failed to perform tls handshake with " + tlsConn.RemoteAddr().String() + ", redirecting").Base(err))
if s.fallbackAddress != nil {
s.redir.Redirect(&redirector.Redirection{
InboundConn: rewindConn,
RedirectTo: s.fallbackAddress,
})
} else if s.httpResp != nil {
rewindConn.Write(s.httpResp)
rewindConn.Close()
} else {
rewindConn.Close()
}
} else {
rewindConn.Close()
// other cases, simply close it
tlsConn.Close()
log.Error(common.NewError("tls handshake failed").Base(err))
}
} else {
// other cases, simply close it
tlsConn.Close()
log.Error(common.NewError("tls handshake failed").Base(err))
return
}
return
}

state := tlsConn.ConnectionState()
log.Trace("tls handshake", tls.CipherSuiteName(state.CipherSuite), state.DidResume, state.NegotiatedProtocol)
state := tlsConn.ConnectionState()
log.Trace("tls handshake", tls.CipherSuiteName(state.CipherSuite), state.DidResume, state.NegotiatedProtocol)
transportConn = tlsConn
}

// we use a real http header parser to mimic a real http server
tlsRewindConn := common.NewRewindConn(tlsConn)
// we use real http header parser to mimic a real http server
tlsRewindConn := common.NewRewindConn(transportConn)
tlsRewindConn.SetBufferSize(512)
defer tlsRewindConn.StopBuffering()
r := bufio.NewReader(tlsRewindConn)
Expand Down

0 comments on commit ed9cbc1

Please sign in to comment.