mirror of
https://github.com/SagerNet/sing-box.git
synced 2024-11-10 11:03:13 +00:00
96 lines
2.2 KiB
Go
96 lines
2.2 KiB
Go
|
package dns
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"context"
|
||
|
"net"
|
||
|
"net/http"
|
||
|
"net/netip"
|
||
|
"os"
|
||
|
|
||
|
"github.com/sagernet/sing/common"
|
||
|
"github.com/sagernet/sing/common/buf"
|
||
|
M "github.com/sagernet/sing/common/metadata"
|
||
|
N "github.com/sagernet/sing/common/network"
|
||
|
|
||
|
C "github.com/sagernet/sing-box/constant"
|
||
|
|
||
|
"golang.org/x/net/dns/dnsmessage"
|
||
|
)
|
||
|
|
||
|
const dnsMimeType = "application/dns-message"
|
||
|
|
||
|
var _ Transport = (*HTTPSTransport)(nil)
|
||
|
|
||
|
type HTTPSTransport struct {
|
||
|
destination string
|
||
|
transport *http.Transport
|
||
|
}
|
||
|
|
||
|
func NewHTTPSTransport(dialer N.Dialer, destination string) *HTTPSTransport {
|
||
|
return &HTTPSTransport{
|
||
|
destination: destination,
|
||
|
transport: &http.Transport{
|
||
|
ForceAttemptHTTP2: true,
|
||
|
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||
|
return dialer.DialContext(ctx, network, M.ParseSocksaddr(addr))
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (t *HTTPSTransport) Start() error {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (t *HTTPSTransport) Close() error {
|
||
|
t.transport.CloseIdleConnections()
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (t *HTTPSTransport) Raw() bool {
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
func (t *HTTPSTransport) Exchange(ctx context.Context, message *dnsmessage.Message) (*dnsmessage.Message, error) {
|
||
|
message.ID = 0
|
||
|
_buffer := buf.StackNewSize(1024)
|
||
|
defer common.KeepAlive(_buffer)
|
||
|
buffer := common.Dup(_buffer)
|
||
|
defer buffer.Release()
|
||
|
rawMessage, err := message.AppendPack(buffer.Index(0))
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
buffer.Truncate(len(rawMessage))
|
||
|
request, err := http.NewRequest(http.MethodPost, t.destination, bytes.NewReader(buffer.Bytes()))
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
request.WithContext(ctx)
|
||
|
request.Header.Set("content-type", dnsMimeType)
|
||
|
request.Header.Set("accept", dnsMimeType)
|
||
|
|
||
|
client := &http.Client{Transport: t.transport}
|
||
|
response, err := client.Do(request)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
defer response.Body.Close()
|
||
|
buffer.FullReset()
|
||
|
_, err = buffer.ReadAllFrom(response.Body)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
var responseMessage dnsmessage.Message
|
||
|
err = responseMessage.Unpack(buffer.Bytes())
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return &responseMessage, nil
|
||
|
}
|
||
|
|
||
|
func (t *HTTPSTransport) Lookup(ctx context.Context, domain string, strategy C.DomainStrategy) ([]netip.Addr, error) {
|
||
|
return nil, os.ErrInvalid
|
||
|
}
|