mirror of
https://github.com/fumiama/terasu.git
synced 2026-06-05 01:00:23 +08:00
feat: new implementations
This commit is contained in:
170
dns/dns.go
Normal file
170
dns/dns.go
Normal file
@@ -0,0 +1,170 @@
|
||||
package dns
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/fumiama/terasu"
|
||||
"github.com/fumiama/terasu/ip"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNoDNSAvailable = errors.New("no dns available")
|
||||
)
|
||||
|
||||
var DefaultDialer = net.Dialer{
|
||||
Timeout: time.Second * 8,
|
||||
}
|
||||
|
||||
type dnsstat struct {
|
||||
A string
|
||||
E bool
|
||||
}
|
||||
|
||||
type DNSList struct {
|
||||
sync.RWMutex
|
||||
m map[string][]*dnsstat
|
||||
}
|
||||
|
||||
// hasrecord no lock, use under lock
|
||||
func hasrecord(lst []*dnsstat, a string) bool {
|
||||
for _, addr := range lst {
|
||||
if addr.A == a {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (ds *DNSList) Add(m map[string][]string) {
|
||||
ds.Lock()
|
||||
defer ds.Unlock()
|
||||
addList := map[string][]*dnsstat{}
|
||||
for host, addrs := range m {
|
||||
for _, addr := range addrs {
|
||||
if !hasrecord(ds.m[host], addr) && !hasrecord(addList[host], addr) {
|
||||
addList[host] = append(addList[host], &dnsstat{addr, true})
|
||||
}
|
||||
}
|
||||
}
|
||||
for host, addrs := range addList {
|
||||
ds.m[host] = append(ds.m[host], addrs...)
|
||||
}
|
||||
}
|
||||
|
||||
func (ds *DNSList) DialContext(ctx context.Context, dialer *net.Dialer, firstFragmentLen uint8) (tlsConn *tls.Conn, err error) {
|
||||
err = ErrNoDNSAvailable
|
||||
|
||||
if dialer == nil {
|
||||
dialer = &DefaultDialer
|
||||
}
|
||||
|
||||
ds.RLock()
|
||||
defer ds.RUnlock()
|
||||
|
||||
if dialer.Timeout != 0 {
|
||||
var cancel context.CancelFunc
|
||||
ctx, cancel = context.WithTimeout(ctx, dialer.Timeout)
|
||||
defer cancel()
|
||||
}
|
||||
|
||||
if !dialer.Deadline.IsZero() {
|
||||
var cancel context.CancelFunc
|
||||
ctx, cancel = context.WithDeadline(ctx, dialer.Deadline)
|
||||
defer cancel()
|
||||
}
|
||||
|
||||
var conn net.Conn
|
||||
for host, addrs := range ds.m {
|
||||
for _, addr := range addrs {
|
||||
if !addr.E {
|
||||
continue
|
||||
}
|
||||
conn, err = dialer.DialContext(ctx, "tcp", addr.A)
|
||||
if err != nil {
|
||||
addr.E = false // no need to acquire write lock
|
||||
continue
|
||||
}
|
||||
tlsConn = tls.Client(conn, &tls.Config{ServerName: host})
|
||||
err = terasu.Use(tlsConn).HandshakeContext(ctx, firstFragmentLen)
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
_ = tlsConn.Close()
|
||||
addr.E = false // no need to acquire write lock
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var IPv6Servers = DNSList{
|
||||
m: map[string][]*dnsstat{
|
||||
"dot.sb": {
|
||||
{"[2a09::]:853", true},
|
||||
{"[2a11::]:853", true},
|
||||
},
|
||||
"dns.google": {
|
||||
{"[2001:4860:4860::8888]:853", true},
|
||||
{"[2001:4860:4860::8844]:853", true},
|
||||
},
|
||||
"cloudflare-dns.com": {
|
||||
{"[2606:4700:4700::1111]:853", true},
|
||||
{"[2606:4700:4700::1001]:853", true},
|
||||
},
|
||||
"dns.opendns.com": {
|
||||
{"[2620:119:35::35]:853", true},
|
||||
{"[2620:119:53::53]:853", true},
|
||||
},
|
||||
"dns10.quad9.net": {
|
||||
{"[2620:fe::10]:853", true},
|
||||
{"[2620:fe::fe:10]:853", true},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var IPv4Servers = DNSList{
|
||||
m: map[string][]*dnsstat{
|
||||
"dot.360.cn": {
|
||||
{"101.198.192.33:853", true},
|
||||
{"112.65.69.15:853", true},
|
||||
{"101.226.4.6:853", true},
|
||||
{"218.30.118.6:853", true},
|
||||
{"123.125.81.6:853", true},
|
||||
{"140.207.198.6:853", true},
|
||||
},
|
||||
"dot.sb": {
|
||||
{"185.222.222.222:853", true},
|
||||
{"45.11.45.11:853", true},
|
||||
},
|
||||
"dns.google": {
|
||||
{"8.8.8.8:853", true},
|
||||
{"8.8.4.4:853", true},
|
||||
},
|
||||
"cloudflare-dns.com": {
|
||||
{"1.1.1.1:853", true},
|
||||
{"1.0.0.1:853", true},
|
||||
},
|
||||
"dns.opendns.com": {
|
||||
{"208.67.222.222:853", true},
|
||||
{"208.67.220.220:853", true},
|
||||
},
|
||||
"dns10.quad9.net": {
|
||||
{"9.9.9.10:853", true},
|
||||
{"149.112.112.10:853", true},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var DefaultResolver = &net.Resolver{
|
||||
PreferGo: true,
|
||||
Dial: func(ctx context.Context, _, _ string) (net.Conn, error) {
|
||||
if ip.IsIPv6Available.Get() {
|
||||
return IPv6Servers.DialContext(ctx, nil, terasu.DefaultFirstFragmentLen)
|
||||
}
|
||||
return IPv4Servers.DialContext(ctx, nil, terasu.DefaultFirstFragmentLen)
|
||||
},
|
||||
}
|
||||
96
dns/dns_test.go
Normal file
96
dns/dns_test.go
Normal file
@@ -0,0 +1,96 @@
|
||||
package dns
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/fumiama/terasu"
|
||||
"github.com/fumiama/terasu/ip"
|
||||
)
|
||||
|
||||
func TestResolver(t *testing.T) {
|
||||
t.Log("IsIPv6Available:", ip.IsIPv6Available.Get())
|
||||
addrs, err := DefaultResolver.LookupHost(context.TODO(), "huggingface.co")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(addrs)
|
||||
if len(addrs) == 0 {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestDNS(t *testing.T) {
|
||||
if ip.IsIPv6Available.Get() {
|
||||
IPv6Servers.test()
|
||||
}
|
||||
IPv4Servers.test()
|
||||
for i := 0; i < 100; i++ {
|
||||
addrs, err := DefaultResolver.LookupHost(context.TODO(), "huggingface.co")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(addrs)
|
||||
if len(addrs) == 0 {
|
||||
t.Fail()
|
||||
}
|
||||
time.Sleep(time.Millisecond * 50)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBadDNS(t *testing.T) {
|
||||
dotv6serversbak := IPv6Servers.m
|
||||
dotv4serversbak := IPv4Servers.m
|
||||
defer func() {
|
||||
IPv6Servers.m = dotv6serversbak
|
||||
IPv4Servers.m = dotv4serversbak
|
||||
}()
|
||||
if ip.IsIPv6Available.Get() {
|
||||
IPv6Servers = DNSList{
|
||||
m: map[string][]*dnsstat{},
|
||||
}
|
||||
IPv6Servers.Add(map[string][]string{"test.bad.host": {"169.254.122.111"}})
|
||||
} else {
|
||||
IPv4Servers = DNSList{
|
||||
m: map[string][]*dnsstat{},
|
||||
}
|
||||
IPv4Servers.Add(map[string][]string{"test.bad.host": {"169.254.122.111:853"}})
|
||||
}
|
||||
for i := 0; i < 10; i++ {
|
||||
addrs, err := DefaultResolver.LookupHost(context.TODO(), "api.mangacopy.com")
|
||||
t.Log(err)
|
||||
if err == nil && len(addrs) > 0 {
|
||||
t.Fatal("unexpected")
|
||||
}
|
||||
time.Sleep(time.Millisecond * 50)
|
||||
}
|
||||
}
|
||||
|
||||
func (ds *DNSList) test() {
|
||||
ds.RLock()
|
||||
defer ds.RUnlock()
|
||||
for host, addrs := range ds.m {
|
||||
for _, addr := range addrs {
|
||||
if !addr.E {
|
||||
continue
|
||||
}
|
||||
fmt.Println("dial:", host, addr.A)
|
||||
conn, err := net.Dial("tcp", addr.A)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
tlsConn := tls.Client(conn, &tls.Config{ServerName: host})
|
||||
err = terasu.Use(tlsConn).Handshake(4)
|
||||
_ = tlsConn.Close()
|
||||
if err == nil {
|
||||
fmt.Println("succ:", host, addr.A)
|
||||
continue
|
||||
}
|
||||
fmt.Println("fail:", host, addr.A)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user