github.com/Asutorufa/yuhaiin@v0.3.6-0.20240502055049-7984da7023a0/pkg/components/resolver/hosts.go (about)

     1  package resolver
     2  
     3  import (
     4  	"context"
     5  	"net"
     6  	"strings"
     7  
     8  	"github.com/Asutorufa/yuhaiin/pkg/net/netapi"
     9  	"github.com/Asutorufa/yuhaiin/pkg/protos/config"
    10  	"github.com/Asutorufa/yuhaiin/pkg/utils/yerror"
    11  	"golang.org/x/net/dns/dnsmessage"
    12  )
    13  
    14  type Hosts struct {
    15  	hosts    map[string]*hostsEntry
    16  	dialer   netapi.Proxy
    17  	resolver netapi.Resolver
    18  }
    19  
    20  type hostsEntry struct {
    21  	V       netapi.Address
    22  	portMap map[uint16]netapi.Address
    23  }
    24  
    25  func NewHosts(dialer netapi.Proxy, resolver netapi.Resolver) *Hosts {
    26  	return &Hosts{dialer: dialer, resolver: resolver, hosts: map[string]*hostsEntry{}}
    27  }
    28  
    29  func (h *Hosts) Update(c *config.Setting) {
    30  	store := map[string]*hostsEntry{}
    31  
    32  	for k, v := range c.Dns.Hosts {
    33  		_, _, e1 := net.SplitHostPort(k)
    34  		_, _, e2 := net.SplitHostPort(v)
    35  
    36  		if e1 == nil && e2 == nil {
    37  			kaddr, err1 := netapi.ParseAddress(0, k)
    38  			addr, err2 := netapi.ParseAddress(0, v)
    39  			if err1 == nil && err2 == nil && kaddr.Port().Port() != 0 && addr.Port().Port() != 0 {
    40  				v, ok := store[kaddr.Hostname()]
    41  				if !ok {
    42  					v = &hostsEntry{}
    43  					store[kaddr.Hostname()] = v
    44  				}
    45  
    46  				if v.portMap == nil {
    47  					v.portMap = map[uint16]netapi.Address{}
    48  				}
    49  
    50  				v.portMap[kaddr.Port().Port()] = addr
    51  			}
    52  		}
    53  
    54  		if e1 != nil && e2 != nil {
    55  			he, ok := store[k]
    56  			if !ok {
    57  				he = &hostsEntry{}
    58  				store[k] = he
    59  			}
    60  
    61  			he.V = netapi.ParseAddressPort(0, v, netapi.EmptyPort)
    62  		}
    63  	}
    64  
    65  	h.hosts = store
    66  }
    67  
    68  func (h *Hosts) Dispatch(ctx context.Context, addr netapi.Address) (netapi.Address, error) {
    69  	haddr := h.dispatchAddr(ctx, addr)
    70  	return h.dialer.Dispatch(ctx, haddr)
    71  }
    72  
    73  func (h *Hosts) Conn(ctx context.Context, addr netapi.Address) (net.Conn, error) {
    74  	return h.dialer.Conn(ctx, h.dispatchAddr(ctx, addr))
    75  }
    76  
    77  func (h *Hosts) PacketConn(ctx context.Context, addr netapi.Address) (net.PacketConn, error) {
    78  	c, err := h.dialer.PacketConn(ctx, h.dispatchAddr(ctx, addr))
    79  	if err != nil {
    80  		return nil, err
    81  	}
    82  	return &dispatchPacketConn{c, h.dispatchAddr}, nil
    83  }
    84  
    85  func (h *Hosts) dispatchAddr(ctx context.Context, addr netapi.Address) netapi.Address {
    86  	v, ok := h.hosts[addr.Hostname()]
    87  	if !ok {
    88  		return addr
    89  	}
    90  
    91  	if v.portMap != nil {
    92  		z, ok := v.portMap[addr.Port().Port()]
    93  		if ok {
    94  			store := netapi.StoreFromContext(ctx)
    95  			store.Add("Hosts", addr.String())
    96  			addr = addr.OverrideHostname(z.Hostname()).OverridePort(z.Port())
    97  			store.Add(netapi.CurrentKey{}, addr)
    98  			return addr
    99  		}
   100  	}
   101  
   102  	if v.V == nil {
   103  		return addr
   104  	}
   105  
   106  	netapi.StoreFromContext(ctx).
   107  		Add("Hosts", addr.Hostname()).
   108  		Add(netapi.CurrentKey{}, addr)
   109  	return addr.OverrideHostname(v.V.Hostname())
   110  
   111  }
   112  
   113  func (h *Hosts) LookupIP(ctx context.Context, domain string, opts ...func(*netapi.LookupIPOption)) ([]net.IP, error) {
   114  	addr := h.dispatchAddr(ctx, netapi.ParseAddressPort(0, domain, netapi.EmptyPort))
   115  	if addr.Type() == netapi.IP {
   116  		return []net.IP{yerror.Ignore(addr.IP(ctx))}, nil
   117  	}
   118  
   119  	return h.resolver.LookupIP(ctx, addr.Hostname(), opts...)
   120  }
   121  
   122  func (h *Hosts) Raw(ctx context.Context, req dnsmessage.Question) (dnsmessage.Message, error) {
   123  	addr := h.dispatchAddr(ctx, netapi.ParseAddressPort(0, strings.TrimSuffix(req.Name.String(), "."), netapi.EmptyPort))
   124  	if req.Type != dnsmessage.TypeAAAA && req.Type != dnsmessage.TypeA {
   125  		return h.resolver.Raw(ctx, req)
   126  	}
   127  
   128  	if addr.Type() != netapi.IP {
   129  		name, err := dnsmessage.NewName(addr.Hostname() + ".")
   130  		if err != nil {
   131  			return dnsmessage.Message{}, err
   132  		}
   133  		req.Name = name
   134  		return h.resolver.Raw(ctx, req)
   135  	}
   136  
   137  	msg := dnsmessage.Message{
   138  		Header: dnsmessage.Header{
   139  			ID:                 0,
   140  			Response:           true,
   141  			Authoritative:      false,
   142  			RecursionDesired:   false,
   143  			RCode:              dnsmessage.RCodeSuccess,
   144  			RecursionAvailable: false,
   145  		},
   146  		Questions: []dnsmessage.Question{
   147  			{
   148  				Name:  req.Name,
   149  				Type:  req.Type,
   150  				Class: dnsmessage.ClassINET,
   151  			},
   152  		},
   153  	}
   154  
   155  	if req.Type == dnsmessage.TypeAAAA {
   156  		msg.Answers = []dnsmessage.Resource{
   157  			{
   158  				Header: dnsmessage.ResourceHeader{
   159  					Name:  req.Name,
   160  					Class: dnsmessage.ClassINET,
   161  					TTL:   600,
   162  					Type:  dnsmessage.TypeAAAA,
   163  				},
   164  				Body: &dnsmessage.AAAAResource{AAAA: [16]byte(yerror.Ignore(addr.IP(ctx)).To16())},
   165  			},
   166  		}
   167  	}
   168  
   169  	if req.Type == dnsmessage.TypeA {
   170  		msg.Answers = []dnsmessage.Resource{
   171  			{
   172  				Header: dnsmessage.ResourceHeader{
   173  					Name:  req.Name,
   174  					Class: dnsmessage.ClassINET,
   175  					TTL:   600,
   176  					Type:  dnsmessage.TypeA,
   177  				},
   178  				Body: &dnsmessage.AResource{A: [4]byte(yerror.Ignore(addr.IP(ctx)).To4())},
   179  			},
   180  		}
   181  	}
   182  
   183  	return msg, nil
   184  }
   185  
   186  func (h *Hosts) Close() error { return nil }