diff --git a/dnstt-client/dns.go b/dnstt-client/lib/dns.go similarity index 94% rename from dnstt-client/dns.go rename to dnstt-client/lib/dns.go index af1ad88..c610d0f 100644 --- a/dnstt-client/dns.go +++ b/dnstt-client/lib/dns.go @@ -1,4 +1,4 @@ -package main +package dnstt_client import ( "bytes" @@ -16,8 +16,8 @@ import ( ) const ( - // How many bytes of random padding to insert into queries. - numPadding = 3 + // NumPadding How many bytes of random padding to insert into queries. + NumPadding = 3 // In an otherwise empty polling query, insert even more random padding, // to reduce the chance of a cache hit. Cannot be greater than 31, // because the prefix codes indicating padding start at 224. @@ -39,8 +39,8 @@ const ( pollLimit = 16 ) -// base32Encoding is a base32 encoding without padding. -var base32Encoding = base32.StdEncoding.WithPadding(base32.NoPadding) +// Base32Encoding is a base32 encoding without padding. +var Base32Encoding = base32.StdEncoding.WithPadding(base32.NoPadding) // DNSPacketConn provides a packet-sending and -receiving interface over various // forms of DNS. It handles the details of how packets and padding are encoded @@ -187,6 +187,7 @@ func (c *DNSPacketConn) recvLoop(transport net.PacketConn) error { var buf [4096]byte n, addr, err := transport.ReadFrom(buf[:]) if err != nil { + //goland:noinspection GoDeprecation if err, ok := err.(net.Error); ok && err.Temporary() { log.Printf("ReadFrom temporary error: %v", err) continue @@ -205,13 +206,13 @@ func (c *DNSPacketConn) recvLoop(transport net.PacketConn) error { // Pull out the packets contained in the payload. r := bytes.NewReader(payload) - any := false + anyPacket := false for { p, err := nextPacket(r) if err != nil { break } - any = true + anyPacket = true c.QueuePacketConn.QueueIncoming(p, addr) } @@ -219,7 +220,7 @@ func (c *DNSPacketConn) recvLoop(transport net.PacketConn) error { // to poll immediately. ACKs on received data will effectively // serve as another stream of polls whose rate is proportional // to the rate of incoming packets. - if any { + if anyPacket { select { case c.pollChan <- struct{}{}: default: @@ -228,9 +229,9 @@ func (c *DNSPacketConn) recvLoop(transport net.PacketConn) error { } } -// chunks breaks p into non-empty subslices of at most n bytes, greedily so that +// Chunks breaks p into non-empty subslices of at most n bytes, greedily so that // only final subslice has length < n. -func chunks(p []byte, n int) [][]byte { +func Chunks(p []byte, n int) [][]byte { var result [][]byte for len(p) > 0 { sz := len(p) @@ -274,13 +275,13 @@ func (c *DNSPacketConn) send(transport net.PacketConn, p []byte, addr net.Addr) var buf bytes.Buffer // ClientID buf.Write(c.clientID[:]) - n := numPadding + n := NumPadding if len(p) == 0 { n = numPaddingForPoll } // Padding / cache inhibition buf.WriteByte(byte(224 + n)) - io.CopyN(&buf, rand.Reader, int64(n)) + _, _ = io.CopyN(&buf, rand.Reader, int64(n)) // Packet contents if len(p) > 0 { buf.WriteByte(byte(len(p))) @@ -289,10 +290,10 @@ func (c *DNSPacketConn) send(transport net.PacketConn, p []byte, addr net.Addr) decoded = buf.Bytes() } - encoded := make([]byte, base32Encoding.EncodedLen(len(decoded))) - base32Encoding.Encode(encoded, decoded) + encoded := make([]byte, Base32Encoding.EncodedLen(len(decoded))) + Base32Encoding.Encode(encoded, decoded) encoded = bytes.ToLower(encoded) - labels := chunks(encoded, 63) + labels := Chunks(encoded, 63) labels = append(labels, c.domain...) name, err := dns.NewName(labels) if err != nil { @@ -300,7 +301,7 @@ func (c *DNSPacketConn) send(transport net.PacketConn, p []byte, addr net.Addr) } var id uint16 - binary.Read(rand.Reader, binary.BigEndian, &id) + _ = binary.Read(rand.Reader, binary.BigEndian, &id) query := &dns.Message{ ID: id, Flags: 0x0100, // QR = 0, RD = 1 diff --git a/dnstt-client/dns_test.go b/dnstt-client/lib/dns_test.go similarity index 98% rename from dnstt-client/dns_test.go rename to dnstt-client/lib/dns_test.go index e09ccc2..08af7df 100644 --- a/dnstt-client/dns_test.go +++ b/dnstt-client/lib/dns_test.go @@ -1,4 +1,4 @@ -package main +package dnstt_client import ( "bytes" diff --git a/dnstt-client/http.go b/dnstt-client/lib/http.go similarity index 98% rename from dnstt-client/http.go rename to dnstt-client/lib/http.go index 560735a..1711725 100644 --- a/dnstt-client/http.go +++ b/dnstt-client/lib/http.go @@ -1,4 +1,4 @@ -package main +package dnstt_client import ( "bytes" @@ -88,7 +88,9 @@ func (c *HTTPPacketConn) send(p []byte) error { if err != nil { return err } - defer resp.Body.Close() + defer func() { + _ = resp.Body.Close() + }() switch resp.StatusCode { case http.StatusOK: diff --git a/dnstt-client/http_test.go b/dnstt-client/lib/http_test.go similarity index 98% rename from dnstt-client/http_test.go rename to dnstt-client/lib/http_test.go index 1b18bc3..ed6633b 100644 --- a/dnstt-client/http_test.go +++ b/dnstt-client/lib/http_test.go @@ -1,4 +1,4 @@ -package main +package dnstt_client import ( "testing" diff --git a/dnstt-client/tls.go b/dnstt-client/lib/tls.go similarity index 97% rename from dnstt-client/tls.go rename to dnstt-client/lib/tls.go index 8897237..6f26654 100644 --- a/dnstt-client/tls.go +++ b/dnstt-client/lib/tls.go @@ -1,4 +1,4 @@ -package main +package dnstt_client import ( "bufio" @@ -54,7 +54,9 @@ func NewTLSPacketConn(addr string, dialTLSContext func(ctx context.Context, netw QueuePacketConn: turbotunnel.NewQueuePacketConn(turbotunnel.DummyAddr{}, 0), } go func() { - defer c.Close() + defer func() { + _ = c.Close() + }() for { var wg sync.WaitGroup wg.Add(2) @@ -73,7 +75,7 @@ func NewTLSPacketConn(addr string, dialTLSContext func(ctx context.Context, netw wg.Done() }() wg.Wait() - conn.Close() + _ = conn.Close() // Whenever the TLS connection dies, redial a new one. conn, err = dial() diff --git a/dnstt-client/utls.go b/dnstt-client/lib/utls.go similarity index 93% rename from dnstt-client/utls.go rename to dnstt-client/lib/utls.go index 7a6af56..ff1647e 100644 --- a/dnstt-client/utls.go +++ b/dnstt-client/lib/utls.go @@ -1,4 +1,4 @@ -package main +package dnstt_client // Support code for TLS camouflage using uTLS. @@ -16,9 +16,9 @@ import ( "golang.org/x/net/http2" ) -// utlsClientHelloIDMap is a correspondence between human-readable labels and +// UtlsClientHelloIDMap is a correspondence between human-readable labels and // supported utls.ClientHelloIDs. -var utlsClientHelloIDMap = []struct { +var UtlsClientHelloIDMap = []struct { Label string ID *utls.ClientHelloID }{ @@ -38,10 +38,10 @@ var utlsClientHelloIDMap = []struct { {"iOS_12_1", &utls.HelloIOS_12_1}, } -// utlsLookup returns a *utls.ClientHelloID from utlsClientHelloIDMap by a +// UtlsLookup returns a *utls.ClientHelloID from utlsClientHelloIDMap by a // case-insensitive label match, or nil if there is no match. -func utlsLookup(label string) *utls.ClientHelloID { - for _, entry := range utlsClientHelloIDMap { +func UtlsLookup(label string) *utls.ClientHelloID { + for _, entry := range UtlsClientHelloIDMap { if strings.ToLower(label) == strings.ToLower(entry.Label) { return entry.ID } @@ -49,10 +49,10 @@ func utlsLookup(label string) *utls.ClientHelloID { return nil } -// utlsDialContext connects to the given network address and initiates a TLS +// UtlsDialContext connects to the given network address and initiates a TLS // handshake with the provided ClientHelloID, and returns the resulting TLS // connection. -func utlsDialContext(ctx context.Context, network, addr string, config *utls.Config, id *utls.ClientHelloID) (*utls.UConn, error) { +func UtlsDialContext(ctx context.Context, network, addr string, config *utls.Config, id *utls.ClientHelloID) (*utls.UConn, error) { // Set the SNI from addr, if not already set. if config == nil { config = &utls.Config{} @@ -76,7 +76,7 @@ func utlsDialContext(ctx context.Context, network, addr string, config *utls.Con if net.ParseIP(config.ServerName) != nil { err := uconn.RemoveSNIExtension() if err != nil { - uconn.Close() + _ = uconn.Close() return nil, err } } @@ -88,7 +88,7 @@ func utlsDialContext(ctx context.Context, network, addr string, config *utls.Con // https://github.com/refraction-networking/utls/issues/75 err = uconn.Handshake() if err != nil { - uconn.Close() + _ = uconn.Close() return nil, err } return uconn, nil @@ -186,7 +186,7 @@ func makeRoundTripper(req *http.Request, config *utls.Config, id *utls.ClientHel return nil, err } - bootstrapConn, err := utlsDialContext(req.Context(), "tcp", addr, config, id) + bootstrapConn, err := UtlsDialContext(req.Context(), "tcp", addr, config, id) if err != nil { return nil, err } @@ -210,7 +210,7 @@ func makeRoundTripper(req *http.Request, config *utls.Config, id *utls.ClientHel } // Later dials make a new connection. - uconn, err := utlsDialContext(ctx, "tcp", addr, config, id) + uconn, err := UtlsDialContext(ctx, "tcp", addr, config, id) if err != nil { return nil, err } diff --git a/dnstt-client/weightedlist.go b/dnstt-client/lib/weightedlist.go similarity index 94% rename from dnstt-client/weightedlist.go rename to dnstt-client/lib/weightedlist.go index 6ff599a..9445f3f 100644 --- a/dnstt-client/weightedlist.go +++ b/dnstt-client/lib/weightedlist.go @@ -1,4 +1,4 @@ -package main +package dnstt_client // Random selection from weighted distributions, and strings for specifying such // distributions. @@ -12,7 +12,7 @@ import ( "strings" ) -// parseWeightedList parses a list of text labels with optional numeric weights, +// ParseWeightedList parses a list of text labels with optional numeric weights, // and returns parallel slices of weights and labels. If a weight is omitted for // a label, the weight is 1. // @@ -22,7 +22,7 @@ import ( // // list ::= entry ("," entry)* // entry ::= (weight "*")? label -func parseWeightedList(s string) ([]uint32, []string, error) { +func ParseWeightedList(s string) ([]uint32, []string, error) { const ( kindEOF = iota kindComma @@ -176,10 +176,10 @@ func (s cryptoSource) Int63() int64 { return n } -// sampleWeighted returns the index of a randomly selected element of the +// SampleWeighted returns the index of a randomly selected element of the // weights slice, weighted by the values stored in the slice. Panics if // the sum of the weights is zero or does not fit in an int64. -func sampleWeighted(weights []uint32) int { +func SampleWeighted(weights []uint32) int { var sum int64 = 0 for _, w := range weights { sum += int64(w) diff --git a/dnstt-client/weightedlist_test.go b/dnstt-client/lib/weightedlist_test.go similarity index 92% rename from dnstt-client/weightedlist_test.go rename to dnstt-client/lib/weightedlist_test.go index 56dd6fc..aa58734 100644 --- a/dnstt-client/weightedlist_test.go +++ b/dnstt-client/lib/weightedlist_test.go @@ -1,4 +1,4 @@ -package main +package dnstt_client import ( "testing" @@ -20,7 +20,7 @@ func TestParseWeightedList(t *testing.T) { {"\\,", []uint32{1}, []string{","}}, {"3\\*apple\\,car\\rot,100*orange", []uint32{1, 100}, []string{"3*apple,carrot", "orange"}}, } { - weights, labels, err := parseWeightedList(test.input) + weights, labels, err := ParseWeightedList(test.input) if err != nil { t.Errorf("%+q resulted in error: %v", test.input, err) continue @@ -55,7 +55,7 @@ func TestParseWeightedList(t *testing.T) { "-5*apple", "5.5*apple", } { - _, _, err := parseWeightedList(input) + _, _, err := ParseWeightedList(input) if err == nil { t.Errorf("%+q resulted in no error", input) continue @@ -77,7 +77,7 @@ func TestSampleWeighted(t *testing.T) { t.Errorf("%v: expected panic", weights) } }() - sampleWeighted(weights) + SampleWeighted(weights) }() } @@ -92,7 +92,7 @@ func TestSampleWeighted(t *testing.T) { {[]uint32{0, 0, 0xffffffff, 0, 1}, 2}, } { for i := 0; i < 100; i++ { - index := sampleWeighted(test.weights) + index := SampleWeighted(test.weights) if index != test.index { t.Errorf("%v: expected %d, got %d", test.weights, test.index, index) } diff --git a/dnstt-client/main.go b/dnstt-client/main.go index f96b2ed..f9ad749 100644 --- a/dnstt-client/main.go +++ b/dnstt-client/main.go @@ -48,6 +48,7 @@ import ( "sync" "syscall" "time" + dc "www.bamsoftware.com/git/dnstt.git/dnstt-client/lib" utls "github.com/refraction-networking/utls" "github.com/xtaci/kcp-go/v5" @@ -99,7 +100,7 @@ func readKeyFromFile(filename string) ([]byte, error) { // utls.ClientHelloID from utlsClientHelloIDMap, and randomly samples one // utls.ClientHelloID from the distribution. func sampleUTLSDistribution(spec string) (*utls.ClientHelloID, error) { - weights, labels, err := parseWeightedList(spec) + weights, labels, err := dc.ParseWeightedList(spec) if err != nil { return nil, err } @@ -109,14 +110,14 @@ func sampleUTLSDistribution(spec string) (*utls.ClientHelloID, error) { if label == "none" { id = nil } else { - id = utlsLookup(label) + id = dc.UtlsLookup(label) if id == nil { return nil, fmt.Errorf("unknown TLS fingerprint %q", label) } } ids = append(ids, id) } - return ids[sampleWeighted(weights)], nil + return ids[dc.SampleWeighted(weights)], nil } func handle(local *net.TCPConn, sess *smux.Session, conv uint32) error { @@ -170,7 +171,7 @@ func listen(pubkey []byte, domain dns.Name, remoteAddr net.Addr, pconn net.Packe return nil, nil, nil, fmt.Errorf("opening local listener: %v", err) } - mtu := dnsNameCapacity(domain) - 8 - 1 - numPadding - 1 // clientid + padding length prefix + padding + data length prefix + mtu := dnsNameCapacity(domain) - 8 - 1 - dc.NumPadding - 1 // clientid + padding length prefix + padding + data length prefix if mtu < 80 { _ = pconn.Close() _ = ln.Close() @@ -244,6 +245,7 @@ func acceptLoop(ln *pt.SocksListener, pconn net.PacketConn, conn *kcp.UDPSession for { local, err := ln.AcceptSocks() if err != nil { + //goland:noinspection GoDeprecation if err, ok := err.(net.Error); ok && err.Temporary() { continue } @@ -308,9 +310,9 @@ Examples: `, os.Args[0]) flag.PrintDefaults() - labels := make([]string, 0, len(utlsClientHelloIDMap)) + labels := make([]string, 0, len(dc.UtlsClientHelloIDMap)) labels = append(labels, "none") - for _, entry := range utlsClientHelloIDMap { + for _, entry := range dc.UtlsClientHelloIDMap { labels = append(labels, entry.Label) } _, _ = fmt.Fprintf(flag.CommandLine.Output(), ` @@ -407,9 +409,9 @@ Known TLS fingerprints for -utls are: transport.Proxy = nil rt = transport } else { - rt = NewUTLSRoundTripper(nil, utlsClientHelloID) + rt = dc.NewUTLSRoundTripper(nil, utlsClientHelloID) } - pconn, err := NewHTTPPacketConn(rt, dohURL, 32) + pconn, err := dc.NewHTTPPacketConn(rt, dohURL, 32) return addr, pconn, err }}, // -dot @@ -420,10 +422,10 @@ Known TLS fingerprints for -utls are: dialTLSContext = (&tls.Dialer{}).DialContext } else { dialTLSContext = func(ctx context.Context, network, addr string) (net.Conn, error) { - return utlsDialContext(ctx, network, addr, nil, utlsClientHelloID) + return dc.UtlsDialContext(ctx, network, addr, nil, utlsClientHelloID) } } - pconn, err := NewTLSPacketConn(dotAddr, dialTLSContext) + pconn, err := dc.NewTLSPacketConn(dotAddr, dialTLSContext) return addr, pconn, err }}, // -udp @@ -473,7 +475,7 @@ Known TLS fingerprints for -utls are: for _, methodName := range ptInfo.MethodNames { switch methodName { case "dnstt": - pconn = NewDNSPacketConn(pconn, remoteAddr, domain) + pconn = dc.NewDNSPacketConn(pconn, remoteAddr, domain) ln, conn, sess, err := listen(pubkey, domain, remoteAddr, pconn) if err != nil { _ = pt.CmethodError(methodName, err.Error()) diff --git a/dnstt-client/main_test.go b/dnstt-client/main_test.go index 071fc50..dc065fc 100644 --- a/dnstt-client/main_test.go +++ b/dnstt-client/main_test.go @@ -3,13 +3,14 @@ package main import ( "bytes" "testing" + dc "www.bamsoftware.com/git/dnstt.git/dnstt-client/lib" "www.bamsoftware.com/git/dnstt.git/dns" ) func TestDNSNameCapacity(t *testing.T) { for domainLen := 0; domainLen < 255; domainLen++ { - domain, err := dns.NewName(chunks(bytes.Repeat([]byte{'x'}, domainLen), 63)) + domain, err := dns.NewName(dc.Chunks(bytes.Repeat([]byte{'x'}, domainLen), 63)) if err != nil { continue } @@ -17,8 +18,8 @@ func TestDNSNameCapacity(t *testing.T) { if capacity <= 0 { continue } - prefix := []byte(base32Encoding.EncodeToString(bytes.Repeat([]byte{'y'}, capacity))) - labels := append(chunks(prefix, 63), domain...) + prefix := []byte(dc.Base32Encoding.EncodeToString(bytes.Repeat([]byte{'y'}, capacity))) + labels := append(dc.Chunks(prefix, 63), domain...) _, err = dns.NewName(labels) if err != nil { t.Errorf("length %v capacity %v %v", domainLen, capacity, err)