mirror of
https://github.com/v2fly/v2ray-core.git
synced 2025-01-02 07:26:24 -05:00
Feature: Fake DNS support (#406)
* Add fake dns A new config object "fake" in DnsObject for toggling fake dns function Compare with sniffing, fake dns is not limited to http and tls traffic. It works across all inbounds. For example, when dns request come from one inbound, the local DNS server of v2ray will response with a unique fake IP for every unique domain name. Then later on v2ray received a request to one of the fake IP from any inbounds, it will override the request destination with the previously saved domain. By default, v2ray cache up to 65535 addresses. The old records will be discarded bases on LRU. The fake IP will be 240.x.x.x * fix an edge case when encounter a fake IP in use * Move lru to common.cache package * Added the necessary change to obtain request IP from sniffer * Refactor the code so that it may stop depending on global variables in the future. * Replace string manipulation code with more generic codes, hopefully this will work for both IPv4 and IPv6 networks. * Try to use IPv4 version of address if possible * Added Test Case for Fake Dns * Added More Test Case for Fake Dns * Stop user from creating a instance with LRU size more than subnet size, it will create a infinite loop * Move Fake DNS to a separate package * Generated Code for fakedns * Encapsulate Fake DNS as a Instance wide service * Added Support for metadata sniffer, which will be used for Fake DNS * Dependency injection for fake dns * Fake DNS As a Sniffer * Remove stub object * Remove global variable * Update generated protobuf file for metadata only sniffing * Apply Fake DNS config to session * Loading for fake dns settings * Bug fix * Include fake dns in all * Fix FakeDns Lint Condition * Fix sniffer config * Fix lint message * Fix dependency resolution * Fix fake dns not loaded as sniffer * reduce ttl for fake dns * Apply Coding Style * Apply Coding Style * Apply Coding Style * Apply Coding Style * Apply Coding Style * Fix crashed when no fake dns * Apply Coding Style * Fix Fake DNS do not apply to UDP socket * Fixed a bug prevent FakeDNS App Setting from become effective * Fixed a caveat prevent FakeDNS App Setting from become effective * Use log comparison to reduce in issue when it comes to really high value typical for ipv6 subnet * Add build tag for fakedns * Removal of FakeDNS specific logic at DNS client: making it a standard dns client * Regenerate auto generated file * Amended version of configure file * Bug fixes for fakeDNS * Bug fixes for fakeDNS * Fix test: remove reference to removed attribute * Test: fix codacy issue * Conf: Remove old field support * Test: fix codacy issue * Change test scale for TestFakeDnsHolderCreateMappingAndRollOver * Test: fix codacy issue Co-authored-by: yuhan6665 <1588741+yuhan6665@users.noreply.github.com> Co-authored-by: loyalsoldier <10487845+Loyalsoldier@users.noreply.github.com> Co-authored-by: kslr <kslrwang@gmail.com>
This commit is contained in:
parent
d8bc41e653
commit
38da831b75
@ -178,8 +178,12 @@ func (d *DefaultDispatcher) getLink(ctx context.Context) (*transport.Link, *tran
|
||||
}
|
||||
|
||||
func shouldOverride(result SniffResult, domainOverride []string) bool {
|
||||
protocolString := result.Protocol()
|
||||
if resComp, ok := result.(SnifferResultComposite); ok {
|
||||
protocolString = resComp.ProtocolForDomainResult()
|
||||
}
|
||||
for _, p := range domainOverride {
|
||||
if strings.HasPrefix(result.Protocol(), p) {
|
||||
if strings.HasPrefix(protocolString, p) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -203,15 +207,29 @@ func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destin
|
||||
ctx = session.ContextWithContent(ctx, content)
|
||||
}
|
||||
sniffingRequest := content.SniffingRequest
|
||||
if destination.Network != net.Network_TCP || !sniffingRequest.Enabled {
|
||||
switch {
|
||||
case !sniffingRequest.Enabled:
|
||||
go d.routedDispatch(ctx, outbound, destination)
|
||||
} else {
|
||||
case destination.Network != net.Network_TCP:
|
||||
// Only metadata sniff will be used for non tcp connection
|
||||
result, err := sniffer(ctx, nil, true)
|
||||
if err == nil {
|
||||
content.Protocol = result.Protocol()
|
||||
if shouldOverride(result, sniffingRequest.OverrideDestinationForProtocol) {
|
||||
domain := result.Domain()
|
||||
newError("sniffed domain: ", domain).WriteToLog(session.ExportIDToError(ctx))
|
||||
destination.Address = net.ParseAddress(domain)
|
||||
ob.Target = destination
|
||||
}
|
||||
}
|
||||
go d.routedDispatch(ctx, outbound, destination)
|
||||
default:
|
||||
go func() {
|
||||
cReader := &cachedReader{
|
||||
reader: outbound.Reader.(*pipe.Reader),
|
||||
}
|
||||
outbound.Reader = cReader
|
||||
result, err := sniffer(ctx, cReader)
|
||||
result, err := sniffer(ctx, cReader, sniffingRequest.MetadataOnly)
|
||||
if err == nil {
|
||||
content.Protocol = result.Protocol()
|
||||
}
|
||||
@ -227,34 +245,50 @@ func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destin
|
||||
return inbound, nil
|
||||
}
|
||||
|
||||
func sniffer(ctx context.Context, cReader *cachedReader) (SniffResult, error) {
|
||||
func sniffer(ctx context.Context, cReader *cachedReader, metadataOnly bool) (SniffResult, error) {
|
||||
payload := buf.New()
|
||||
defer payload.Release()
|
||||
|
||||
sniffer := NewSniffer()
|
||||
totalAttempt := 0
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
totalAttempt++
|
||||
if totalAttempt > 2 {
|
||||
return nil, errSniffingTimeout
|
||||
}
|
||||
sniffer := NewSniffer(ctx)
|
||||
|
||||
cReader.Cache(payload)
|
||||
if !payload.IsEmpty() {
|
||||
result, err := sniffer.Sniff(payload.Bytes())
|
||||
if err != common.ErrNoClue {
|
||||
return result, err
|
||||
metaresult, metadataErr := sniffer.SniffMetadata(ctx)
|
||||
|
||||
if metadataOnly {
|
||||
return metaresult, metadataErr
|
||||
}
|
||||
|
||||
contentResult, contentErr := func() (SniffResult, error) {
|
||||
totalAttempt := 0
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
totalAttempt++
|
||||
if totalAttempt > 2 {
|
||||
return nil, errSniffingTimeout
|
||||
}
|
||||
|
||||
cReader.Cache(payload)
|
||||
if !payload.IsEmpty() {
|
||||
result, err := sniffer.Sniff(ctx, payload.Bytes())
|
||||
if err != common.ErrNoClue {
|
||||
return result, err
|
||||
}
|
||||
}
|
||||
if payload.IsFull() {
|
||||
return nil, errUnknownContent
|
||||
}
|
||||
}
|
||||
if payload.IsFull() {
|
||||
return nil, errUnknownContent
|
||||
}
|
||||
}
|
||||
}()
|
||||
if contentErr != nil && metadataErr == nil {
|
||||
return metaresult, nil
|
||||
}
|
||||
if contentErr == nil && metadataErr == nil {
|
||||
return CompositeResult(metaresult, contentResult), nil
|
||||
}
|
||||
return contentResult, contentErr
|
||||
}
|
||||
|
||||
func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.Link, destination net.Destination) {
|
||||
|
51
app/dispatcher/fakednssniffer.go
Normal file
51
app/dispatcher/fakednssniffer.go
Normal file
@ -0,0 +1,51 @@
|
||||
// +build !confonly
|
||||
|
||||
package dispatcher
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"v2ray.com/core"
|
||||
"v2ray.com/core/common"
|
||||
"v2ray.com/core/common/net"
|
||||
"v2ray.com/core/common/session"
|
||||
"v2ray.com/core/features/dns"
|
||||
)
|
||||
|
||||
// newFakeDNSSniffer Create a Fake DNS metadata sniffer
|
||||
func newFakeDNSSniffer(ctx context.Context) (protocolSnifferWithMetadata, error) {
|
||||
var fakeDNSEngine dns.FakeDNSEngine
|
||||
err := core.RequireFeatures(ctx, func(fdns dns.FakeDNSEngine) {
|
||||
fakeDNSEngine = fdns
|
||||
})
|
||||
if err != nil {
|
||||
return protocolSnifferWithMetadata{}, err
|
||||
}
|
||||
if fakeDNSEngine == nil {
|
||||
errNotInit := newError("FakeDNSEngine is not initialized, but such a sniffer is used").AtError()
|
||||
return protocolSnifferWithMetadata{}, errNotInit
|
||||
}
|
||||
return protocolSnifferWithMetadata{protocolSniffer: func(ctx context.Context, bytes []byte) (SniffResult, error) {
|
||||
Target := session.OutboundFromContext(ctx).Target
|
||||
if Target.Network == net.Network_TCP || Target.Network == net.Network_UDP {
|
||||
domainFromFakeDNS := fakeDNSEngine.GetDomainFromFakeDNS(Target.Address)
|
||||
if domainFromFakeDNS != "" {
|
||||
newError("fake dns got domain: ", domainFromFakeDNS, " for ip: ", Target.Address.String()).WriteToLog(session.ExportIDToError(ctx))
|
||||
return &fakeDNSSniffResult{domainName: domainFromFakeDNS}, nil
|
||||
}
|
||||
}
|
||||
return nil, common.ErrNoClue
|
||||
}, metadataSniffer: true}, nil
|
||||
}
|
||||
|
||||
type fakeDNSSniffResult struct {
|
||||
domainName string
|
||||
}
|
||||
|
||||
func (fakeDNSSniffResult) Protocol() string {
|
||||
return "fakedns"
|
||||
}
|
||||
|
||||
func (f fakeDNSSniffResult) Domain() string {
|
||||
return f.domainName
|
||||
}
|
@ -3,6 +3,8 @@
|
||||
package dispatcher
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"v2ray.com/core/common"
|
||||
"v2ray.com/core/common/protocol/bittorrent"
|
||||
"v2ray.com/core/common/protocol/http"
|
||||
@ -14,30 +16,46 @@ type SniffResult interface {
|
||||
Domain() string
|
||||
}
|
||||
|
||||
type protocolSniffer func([]byte) (SniffResult, error)
|
||||
type protocolSniffer func(context.Context, []byte) (SniffResult, error)
|
||||
|
||||
type Sniffer struct {
|
||||
sniffer []protocolSniffer
|
||||
type protocolSnifferWithMetadata struct {
|
||||
protocolSniffer protocolSniffer
|
||||
// A Metadata sniffer will be invoked on connection establishment only, with nil body,
|
||||
// for both TCP and UDP connections
|
||||
// It will not be shown as a traffic type for routing unless there is no other successful sniffing.
|
||||
metadataSniffer bool
|
||||
}
|
||||
|
||||
func NewSniffer() *Sniffer {
|
||||
return &Sniffer{
|
||||
sniffer: []protocolSniffer{
|
||||
func(b []byte) (SniffResult, error) { return http.SniffHTTP(b) },
|
||||
func(b []byte) (SniffResult, error) { return tls.SniffTLS(b) },
|
||||
func(b []byte) (SniffResult, error) { return bittorrent.SniffBittorrent(b) },
|
||||
type Sniffer struct {
|
||||
sniffer []protocolSnifferWithMetadata
|
||||
}
|
||||
|
||||
func NewSniffer(ctx context.Context) *Sniffer {
|
||||
ret := &Sniffer{
|
||||
sniffer: []protocolSnifferWithMetadata{
|
||||
{func(c context.Context, b []byte) (SniffResult, error) { return http.SniffHTTP(b) }, false},
|
||||
{func(c context.Context, b []byte) (SniffResult, error) { return tls.SniffTLS(b) }, false},
|
||||
{func(c context.Context, b []byte) (SniffResult, error) { return bittorrent.SniffBittorrent(b) }, false},
|
||||
},
|
||||
}
|
||||
if sniffer, err := newFakeDNSSniffer(ctx); err == nil {
|
||||
ret.sniffer = append(ret.sniffer, sniffer)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
var errUnknownContent = newError("unknown content")
|
||||
|
||||
func (s *Sniffer) Sniff(payload []byte) (SniffResult, error) {
|
||||
var pendingSniffer []protocolSniffer
|
||||
for _, s := range s.sniffer {
|
||||
result, err := s(payload)
|
||||
func (s *Sniffer) Sniff(c context.Context, payload []byte) (SniffResult, error) {
|
||||
var pendingSniffer []protocolSnifferWithMetadata
|
||||
for _, si := range s.sniffer {
|
||||
s := si.protocolSniffer
|
||||
if si.metadataSniffer {
|
||||
continue
|
||||
}
|
||||
result, err := s(c, payload)
|
||||
if err == common.ErrNoClue {
|
||||
pendingSniffer = append(pendingSniffer, s)
|
||||
pendingSniffer = append(pendingSniffer, si)
|
||||
continue
|
||||
}
|
||||
|
||||
@ -53,3 +71,55 @@ func (s *Sniffer) Sniff(payload []byte) (SniffResult, error) {
|
||||
|
||||
return nil, errUnknownContent
|
||||
}
|
||||
|
||||
func (s *Sniffer) SniffMetadata(c context.Context) (SniffResult, error) {
|
||||
var pendingSniffer []protocolSnifferWithMetadata
|
||||
for _, si := range s.sniffer {
|
||||
s := si.protocolSniffer
|
||||
if !si.metadataSniffer {
|
||||
pendingSniffer = append(pendingSniffer, si)
|
||||
continue
|
||||
}
|
||||
result, err := s(c, nil)
|
||||
if err == common.ErrNoClue {
|
||||
pendingSniffer = append(pendingSniffer, si)
|
||||
continue
|
||||
}
|
||||
|
||||
if err == nil && result != nil {
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
|
||||
if len(pendingSniffer) > 0 {
|
||||
s.sniffer = pendingSniffer
|
||||
return nil, common.ErrNoClue
|
||||
}
|
||||
|
||||
return nil, errUnknownContent
|
||||
}
|
||||
|
||||
func CompositeResult(domainResult SniffResult, protocolResult SniffResult) SniffResult {
|
||||
return &compositeResult{domainResult: domainResult, protocolResult: protocolResult}
|
||||
}
|
||||
|
||||
type compositeResult struct {
|
||||
domainResult SniffResult
|
||||
protocolResult SniffResult
|
||||
}
|
||||
|
||||
func (c compositeResult) Protocol() string {
|
||||
return c.protocolResult.Protocol()
|
||||
}
|
||||
|
||||
func (c compositeResult) Domain() string {
|
||||
return c.domainResult.Domain()
|
||||
}
|
||||
|
||||
func (c compositeResult) ProtocolForDomainResult() string {
|
||||
return c.domainResult.Protocol()
|
||||
}
|
||||
|
||||
type SnifferResultComposite interface {
|
||||
ProtocolForDomainResult() string
|
||||
}
|
||||
|
@ -69,4 +69,6 @@ message Config {
|
||||
|
||||
// Tag is the inbound tag of DNS client.
|
||||
string tag = 6;
|
||||
|
||||
reserved 7;
|
||||
}
|
||||
|
@ -23,10 +23,10 @@ import (
|
||||
// DNS is a DNS rely server.
|
||||
type DNS struct {
|
||||
sync.Mutex
|
||||
tag string
|
||||
hosts *StaticHosts
|
||||
clients []*Client
|
||||
|
||||
tag string
|
||||
hosts *StaticHosts
|
||||
clients []*Client
|
||||
ctx context.Context
|
||||
domainMatcher strmatcher.IndexMatcher
|
||||
matcherInfos []DomainMatcherInfo
|
||||
}
|
||||
@ -113,6 +113,7 @@ func New(ctx context.Context, config *Config) (*DNS, error) {
|
||||
tag: tag,
|
||||
hosts: hosts,
|
||||
clients: clients,
|
||||
ctx: ctx,
|
||||
domainMatcher: domainMatcher,
|
||||
matcherInfos: matcherInfos,
|
||||
}, nil
|
||||
@ -189,7 +190,7 @@ func (s *DNS) lookupIPInternal(domain string, option IPOption) ([]net.IP, error)
|
||||
|
||||
// Name servers lookup
|
||||
errs := []error{}
|
||||
ctx := session.ContextWithInbound(context.Background(), &session.Inbound{Tag: s.tag})
|
||||
ctx := session.ContextWithInbound(s.ctx, &session.Inbound{Tag: s.tag})
|
||||
for _, client := range s.sortClients(domain) {
|
||||
ips, err := client.QueryIP(ctx, domain, option)
|
||||
if len(ips) > 0 {
|
||||
|
9
app/dns/fakedns/errors.generated.go
Normal file
9
app/dns/fakedns/errors.generated.go
Normal file
@ -0,0 +1,9 @@
|
||||
package fakedns
|
||||
|
||||
import "v2ray.com/core/common/errors"
|
||||
|
||||
type errPathObjHolder struct{}
|
||||
|
||||
func newError(values ...interface{}) *errors.Error {
|
||||
return errors.New(values...).WithPathObj(errPathObjHolder{})
|
||||
}
|
132
app/dns/fakedns/fake.go
Normal file
132
app/dns/fakedns/fake.go
Normal file
@ -0,0 +1,132 @@
|
||||
// +build !confonly
|
||||
|
||||
package fakedns
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math"
|
||||
"math/big"
|
||||
gonet "net"
|
||||
|
||||
"v2ray.com/core/common"
|
||||
"v2ray.com/core/common/cache"
|
||||
"v2ray.com/core/common/net"
|
||||
"v2ray.com/core/features/dns"
|
||||
)
|
||||
|
||||
type Holder struct {
|
||||
domainToIP cache.Lru
|
||||
nextIP *big.Int
|
||||
|
||||
ipRange *gonet.IPNet
|
||||
|
||||
config *FakeDnsPool
|
||||
}
|
||||
|
||||
func (*Holder) Type() interface{} {
|
||||
return (*dns.FakeDNSEngine)(nil)
|
||||
}
|
||||
|
||||
func (fkdns *Holder) Start() error {
|
||||
return fkdns.initializeFromConfig()
|
||||
}
|
||||
|
||||
func (fkdns *Holder) Close() error {
|
||||
fkdns.domainToIP = nil
|
||||
fkdns.nextIP = nil
|
||||
fkdns.ipRange = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewFakeDNSHolder() (*Holder, error) {
|
||||
var fkdns *Holder
|
||||
var err error
|
||||
|
||||
if fkdns, err = NewFakeDNSHolderConfigOnly(nil); err != nil {
|
||||
return nil, newError("Unable to create Fake Dns Engine").Base(err).AtError()
|
||||
}
|
||||
err = fkdns.initialize("240.0.0.0/8", 65535)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return fkdns, nil
|
||||
}
|
||||
|
||||
func NewFakeDNSHolderConfigOnly(conf *FakeDnsPool) (*Holder, error) {
|
||||
return &Holder{nil, nil, nil, conf}, nil
|
||||
}
|
||||
|
||||
func (fkdns *Holder) initializeFromConfig() error {
|
||||
return fkdns.initialize(fkdns.config.IpPool, int(fkdns.config.LruSize))
|
||||
}
|
||||
|
||||
func (fkdns *Holder) initialize(ipPoolCidr string, lruSize int) error {
|
||||
var ipRange *gonet.IPNet
|
||||
var ipaddr gonet.IP
|
||||
var currentIP *big.Int
|
||||
var err error
|
||||
|
||||
if ipaddr, ipRange, err = gonet.ParseCIDR(ipPoolCidr); err != nil {
|
||||
return newError("Unable to parse CIDR for Fake DNS IP assignment").Base(err).AtError()
|
||||
}
|
||||
|
||||
currentIP = big.NewInt(0).SetBytes(ipaddr)
|
||||
if ipaddr.To4() != nil {
|
||||
currentIP = big.NewInt(0).SetBytes(ipaddr.To4())
|
||||
}
|
||||
|
||||
ones, bits := ipRange.Mask.Size()
|
||||
rooms := bits - ones
|
||||
if math.Log2(float64(lruSize)) >= float64(rooms) {
|
||||
return newError("LRU size is bigger than subnet size").AtError()
|
||||
}
|
||||
fkdns.domainToIP = cache.NewLru(lruSize)
|
||||
fkdns.ipRange = ipRange
|
||||
fkdns.nextIP = currentIP
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetFakeIPForDomain check and generate a fake IP for a domain name
|
||||
func (fkdns *Holder) GetFakeIPForDomain(domain string) []net.Address {
|
||||
if v, ok := fkdns.domainToIP.Get(domain); ok {
|
||||
return []net.Address{v.(net.Address)}
|
||||
}
|
||||
var ip net.Address
|
||||
for {
|
||||
ip = net.IPAddress(fkdns.nextIP.Bytes())
|
||||
|
||||
fkdns.nextIP = fkdns.nextIP.Add(fkdns.nextIP, big.NewInt(1))
|
||||
if !fkdns.ipRange.Contains(fkdns.nextIP.Bytes()) {
|
||||
fkdns.nextIP = big.NewInt(0).SetBytes(fkdns.ipRange.IP)
|
||||
}
|
||||
|
||||
// if we run for a long time, we may go back to beginning and start seeing the IP in use
|
||||
if _, ok := fkdns.domainToIP.GetKeyFromValue(ip); !ok {
|
||||
break
|
||||
}
|
||||
}
|
||||
fkdns.domainToIP.Put(domain, ip)
|
||||
return []net.Address{ip}
|
||||
}
|
||||
|
||||
// GetDomainFromFakeDNS check if an IP is a fake IP and have corresponding domain name
|
||||
func (fkdns *Holder) GetDomainFromFakeDNS(ip net.Address) string {
|
||||
if !ip.Family().IsIP() || !fkdns.ipRange.Contains(ip.IP()) {
|
||||
return ""
|
||||
}
|
||||
if k, ok := fkdns.domainToIP.GetKeyFromValue(ip); ok {
|
||||
return k.(string)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func init() {
|
||||
common.Must(common.RegisterConfig((*FakeDnsPool)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
||||
var f *Holder
|
||||
var err error
|
||||
if f, err = NewFakeDNSHolderConfigOnly(config.(*FakeDnsPool)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return f, nil
|
||||
}))
|
||||
}
|
5
app/dns/fakedns/fakedns.go
Normal file
5
app/dns/fakedns/fakedns.go
Normal file
@ -0,0 +1,5 @@
|
||||
// +build !confonly
|
||||
|
||||
package fakedns
|
||||
|
||||
//go:generate go run v2ray.com/core/common/errors/errorgen
|
164
app/dns/fakedns/fakedns.pb.go
Normal file
164
app/dns/fakedns/fakedns.pb.go
Normal file
@ -0,0 +1,164 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.25.0
|
||||
// protoc v3.13.0
|
||||
// source: app/dns/fakedns/fakedns.proto
|
||||
|
||||
package fakedns
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type FakeDnsPool struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
IpPool string `protobuf:"bytes,1,opt,name=ip_pool,json=ipPool,proto3" json:"ip_pool,omitempty"` //CIDR of IP pool used as fake DNS IP
|
||||
LruSize int64 `protobuf:"varint,2,opt,name=lruSize,proto3" json:"lruSize,omitempty"` //Size of Pool for remembering relationship between domain name and IP address
|
||||
}
|
||||
|
||||
func (x *FakeDnsPool) Reset() {
|
||||
*x = FakeDnsPool{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_app_dns_fakedns_fakedns_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *FakeDnsPool) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*FakeDnsPool) ProtoMessage() {}
|
||||
|
||||
func (x *FakeDnsPool) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_app_dns_fakedns_fakedns_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use FakeDnsPool.ProtoReflect.Descriptor instead.
|
||||
func (*FakeDnsPool) Descriptor() ([]byte, []int) {
|
||||
return file_app_dns_fakedns_fakedns_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *FakeDnsPool) GetIpPool() string {
|
||||
if x != nil {
|
||||
return x.IpPool
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *FakeDnsPool) GetLruSize() int64 {
|
||||
if x != nil {
|
||||
return x.LruSize
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
var File_app_dns_fakedns_fakedns_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_app_dns_fakedns_fakedns_proto_rawDesc = []byte{
|
||||
0x0a, 0x1d, 0x61, 0x70, 0x70, 0x2f, 0x64, 0x6e, 0x73, 0x2f, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e,
|
||||
0x73, 0x2f, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
|
||||
0x1a, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e,
|
||||
0x64, 0x6e, 0x73, 0x2e, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e, 0x73, 0x22, 0x40, 0x0a, 0x0b, 0x46,
|
||||
0x61, 0x6b, 0x65, 0x44, 0x6e, 0x73, 0x50, 0x6f, 0x6f, 0x6c, 0x12, 0x17, 0x0a, 0x07, 0x69, 0x70,
|
||||
0x5f, 0x70, 0x6f, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x69, 0x70, 0x50,
|
||||
0x6f, 0x6f, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x6c, 0x72, 0x75, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6c, 0x72, 0x75, 0x53, 0x69, 0x7a, 0x65, 0x42, 0x5f, 0x0a,
|
||||
0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e, 0x73, 0x50,
|
||||
0x01, 0x5a, 0x1e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72,
|
||||
0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x64, 0x6e, 0x73, 0x2f, 0x66, 0x61, 0x6b, 0x65, 0x64, 0x6e,
|
||||
0x73, 0xaa, 0x02, 0x1a, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41,
|
||||
0x70, 0x70, 0x2e, 0x44, 0x6e, 0x73, 0x2e, 0x46, 0x61, 0x6b, 0x65, 0x64, 0x6e, 0x73, 0x62, 0x06,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_app_dns_fakedns_fakedns_proto_rawDescOnce sync.Once
|
||||
file_app_dns_fakedns_fakedns_proto_rawDescData = file_app_dns_fakedns_fakedns_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_app_dns_fakedns_fakedns_proto_rawDescGZIP() []byte {
|
||||
file_app_dns_fakedns_fakedns_proto_rawDescOnce.Do(func() {
|
||||
file_app_dns_fakedns_fakedns_proto_rawDescData = protoimpl.X.CompressGZIP(file_app_dns_fakedns_fakedns_proto_rawDescData)
|
||||
})
|
||||
return file_app_dns_fakedns_fakedns_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_app_dns_fakedns_fakedns_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_app_dns_fakedns_fakedns_proto_goTypes = []interface{}{
|
||||
(*FakeDnsPool)(nil), // 0: v2ray.core.app.dns.fakedns.FakeDnsPool
|
||||
}
|
||||
var file_app_dns_fakedns_fakedns_proto_depIdxs = []int32{
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
0, // [0:0] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_app_dns_fakedns_fakedns_proto_init() }
|
||||
func file_app_dns_fakedns_fakedns_proto_init() {
|
||||
if File_app_dns_fakedns_fakedns_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_app_dns_fakedns_fakedns_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*FakeDnsPool); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_app_dns_fakedns_fakedns_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_app_dns_fakedns_fakedns_proto_goTypes,
|
||||
DependencyIndexes: file_app_dns_fakedns_fakedns_proto_depIdxs,
|
||||
MessageInfos: file_app_dns_fakedns_fakedns_proto_msgTypes,
|
||||
}.Build()
|
||||
File_app_dns_fakedns_fakedns_proto = out.File
|
||||
file_app_dns_fakedns_fakedns_proto_rawDesc = nil
|
||||
file_app_dns_fakedns_fakedns_proto_goTypes = nil
|
||||
file_app_dns_fakedns_fakedns_proto_depIdxs = nil
|
||||
}
|
12
app/dns/fakedns/fakedns.proto
Normal file
12
app/dns/fakedns/fakedns.proto
Normal file
@ -0,0 +1,12 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package v2ray.core.app.dns.fakedns;
|
||||
option csharp_namespace = "V2Ray.Core.App.Dns.Fakedns";
|
||||
option go_package = "v2ray.com/core/app/dns/fakedns";
|
||||
option java_package = "com.v2ray.core.app.dns.fakedns";
|
||||
option java_multiple_files = true;
|
||||
|
||||
message FakeDnsPool{
|
||||
string ip_pool = 1; //CIDR of IP pool used as fake DNS IP
|
||||
int64 lruSize = 2; //Size of Pool for remembering relationship between domain name and IP address
|
||||
}
|
114
app/dns/fakedns/fakedns_test.go
Normal file
114
app/dns/fakedns/fakedns_test.go
Normal file
@ -0,0 +1,114 @@
|
||||
package fakedns
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"v2ray.com/core/common"
|
||||
"v2ray.com/core/common/net"
|
||||
"v2ray.com/core/common/uuid"
|
||||
)
|
||||
|
||||
func TestNewFakeDnsHolder(_ *testing.T) {
|
||||
_, err := NewFakeDNSHolder()
|
||||
common.Must(err)
|
||||
}
|
||||
|
||||
func TestFakeDnsHolderCreateMapping(t *testing.T) {
|
||||
fkdns, err := NewFakeDNSHolder()
|
||||
common.Must(err)
|
||||
|
||||
addr := fkdns.GetFakeIPForDomain("fakednstest.v2fly.org")
|
||||
assert.Equal(t, "240.0.0.0", addr[0].IP().String())
|
||||
}
|
||||
|
||||
func TestFakeDnsHolderCreateMappingMany(t *testing.T) {
|
||||
fkdns, err := NewFakeDNSHolder()
|
||||
common.Must(err)
|
||||
|
||||
addr := fkdns.GetFakeIPForDomain("fakednstest.v2fly.org")
|
||||
assert.Equal(t, "240.0.0.0", addr[0].IP().String())
|
||||
|
||||
addr2 := fkdns.GetFakeIPForDomain("fakednstest2.v2fly.org")
|
||||
assert.Equal(t, "240.0.0.1", addr2[0].IP().String())
|
||||
}
|
||||
|
||||
func TestFakeDnsHolderCreateMappingManyAndResolve(t *testing.T) {
|
||||
fkdns, err := NewFakeDNSHolder()
|
||||
common.Must(err)
|
||||
|
||||
{
|
||||
addr := fkdns.GetFakeIPForDomain("fakednstest.v2fly.org")
|
||||
assert.Equal(t, "240.0.0.0", addr[0].IP().String())
|
||||
}
|
||||
|
||||
{
|
||||
addr2 := fkdns.GetFakeIPForDomain("fakednstest2.v2fly.org")
|
||||
assert.Equal(t, "240.0.0.1", addr2[0].IP().String())
|
||||
}
|
||||
|
||||
{
|
||||
result := fkdns.GetDomainFromFakeDNS(net.ParseAddress("240.0.0.0"))
|
||||
assert.Equal(t, "fakednstest.v2fly.org", result)
|
||||
}
|
||||
|
||||
{
|
||||
result := fkdns.GetDomainFromFakeDNS(net.ParseAddress("240.0.0.1"))
|
||||
assert.Equal(t, "fakednstest2.v2fly.org", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFakeDnsHolderCreateMappingManySingleDomain(t *testing.T) {
|
||||
fkdns, err := NewFakeDNSHolder()
|
||||
common.Must(err)
|
||||
|
||||
addr := fkdns.GetFakeIPForDomain("fakednstest.v2fly.org")
|
||||
assert.Equal(t, "240.0.0.0", addr[0].IP().String())
|
||||
|
||||
addr2 := fkdns.GetFakeIPForDomain("fakednstest.v2fly.org")
|
||||
assert.Equal(t, "240.0.0.0", addr2[0].IP().String())
|
||||
}
|
||||
|
||||
func TestFakeDnsHolderCreateMappingAndRollOver(t *testing.T) {
|
||||
fkdns, err := NewFakeDNSHolderConfigOnly(&FakeDnsPool{
|
||||
IpPool: "240.0.0.0/12",
|
||||
LruSize: 256,
|
||||
})
|
||||
common.Must(err)
|
||||
|
||||
err = fkdns.Start()
|
||||
|
||||
common.Must(err)
|
||||
|
||||
{
|
||||
addr := fkdns.GetFakeIPForDomain("fakednstest.v2fly.org")
|
||||
assert.Equal(t, "240.0.0.0", addr[0].IP().String())
|
||||
}
|
||||
|
||||
{
|
||||
addr2 := fkdns.GetFakeIPForDomain("fakednstest2.v2fly.org")
|
||||
assert.Equal(t, "240.0.0.1", addr2[0].IP().String())
|
||||
}
|
||||
|
||||
for i := 0; i <= 8192; i++ {
|
||||
{
|
||||
result := fkdns.GetDomainFromFakeDNS(net.ParseAddress("240.0.0.0"))
|
||||
assert.Equal(t, "fakednstest.v2fly.org", result)
|
||||
}
|
||||
|
||||
{
|
||||
result := fkdns.GetDomainFromFakeDNS(net.ParseAddress("240.0.0.1"))
|
||||
assert.Equal(t, "fakednstest2.v2fly.org", result)
|
||||
}
|
||||
|
||||
{
|
||||
uuid := uuid.New()
|
||||
domain := uuid.String() + ".fakednstest.v2fly.org"
|
||||
addr := fkdns.GetFakeIPForDomain(domain)
|
||||
rsaddr := addr[0].IP().String()
|
||||
|
||||
result := fkdns.GetDomainFromFakeDNS(net.ParseAddress(rsaddr))
|
||||
assert.Equal(t, domain, result)
|
||||
}
|
||||
}
|
||||
}
|
@ -55,6 +55,8 @@ func NewServer(dest net.Destination, dispatcher routing.Dispatcher) (Server, err
|
||||
return NewDoHLocalNameServer(u), nil
|
||||
case u.Scheme == "quic+local": // DNS-over-QUIC Local mode
|
||||
return NewQUICNameServer(u)
|
||||
case u.String() == "fakedns":
|
||||
return NewFakeDNSServer(), nil
|
||||
}
|
||||
}
|
||||
if dest.Network == net.Network_Unknown {
|
||||
|
41
app/dns/nameserver_fakedns.go
Normal file
41
app/dns/nameserver_fakedns.go
Normal file
@ -0,0 +1,41 @@
|
||||
// +build !confonly
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"v2ray.com/core"
|
||||
"v2ray.com/core/common/net"
|
||||
"v2ray.com/core/features/dns"
|
||||
)
|
||||
|
||||
type FakeDNSServer struct {
|
||||
fakeDNSEngine dns.FakeDNSEngine
|
||||
}
|
||||
|
||||
func NewFakeDNSServer() *FakeDNSServer {
|
||||
return &FakeDNSServer{}
|
||||
}
|
||||
|
||||
func (FakeDNSServer) Name() string {
|
||||
return "FakeDNS"
|
||||
}
|
||||
|
||||
func (f *FakeDNSServer) QueryIP(ctx context.Context, domain string, _ net.IP, _ IPOption) ([]net.IP, error) {
|
||||
if f.fakeDNSEngine == nil {
|
||||
if err := core.RequireFeatures(ctx, func(fd dns.FakeDNSEngine) {
|
||||
f.fakeDNSEngine = fd
|
||||
}); err != nil {
|
||||
return nil, newError("Unable to locate a fake DNS Engine").Base(err).AtError()
|
||||
}
|
||||
}
|
||||
ips := f.fakeDNSEngine.GetFakeIPForDomain(domain)
|
||||
|
||||
netIP, err := toNetIP(ips)
|
||||
if err != nil {
|
||||
return nil, newError("Unable to convert IP to net ip").Base(err).AtError()
|
||||
}
|
||||
|
||||
return netIP, nil
|
||||
}
|
@ -239,8 +239,11 @@ type SniffingConfig struct {
|
||||
// Whether or not to enable content sniffing on an inbound connection.
|
||||
Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"`
|
||||
// Override target destination if sniff'ed protocol is in the given list.
|
||||
// Supported values are "http", "tls".
|
||||
// Supported values are "http", "tls", "fakedns".
|
||||
DestinationOverride []string `protobuf:"bytes,2,rep,name=destination_override,json=destinationOverride,proto3" json:"destination_override,omitempty"`
|
||||
// Whether should only try to sniff metadata without waiting for client input.
|
||||
// Can be used to support SMTP like protocol where server send the first message.
|
||||
MetadataOnly bool `protobuf:"varint,3,opt,name=metadata_only,json=metadataOnly,proto3" json:"metadata_only,omitempty"`
|
||||
}
|
||||
|
||||
func (x *SniffingConfig) Reset() {
|
||||
@ -289,6 +292,13 @@ func (x *SniffingConfig) GetDestinationOverride() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *SniffingConfig) GetMetadataOnly() bool {
|
||||
if x != nil {
|
||||
return x.MetadataOnly
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type ReceiverConfig struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@ -757,97 +767,99 @@ var file_app_proxyman_config_proto_rawDesc = []byte{
|
||||
0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22,
|
||||
0x2c, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x6c, 0x77, 0x61, 0x79,
|
||||
0x73, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x10, 0x01, 0x12,
|
||||
0x0c, 0x0a, 0x08, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x10, 0x02, 0x22, 0x5d, 0x0a,
|
||||
0x0e, 0x53, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
|
||||
0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08,
|
||||
0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x31, 0x0a, 0x14, 0x64, 0x65, 0x73,
|
||||
0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64,
|
||||
0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x22, 0xb4, 0x04, 0x0a,
|
||||
0x0e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
|
||||
0x3f, 0x0a, 0x0a, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,
|
||||
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x6f, 0x72, 0x74,
|
||||
0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65,
|
||||
0x12, 0x39, 0x0a, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x21, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f,
|
||||
0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d,
|
||||
0x61, 0x69, 0x6e, 0x52, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x12, 0x5c, 0x0a, 0x13, 0x61,
|
||||
0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65,
|
||||
0x67, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,
|
||||
0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d,
|
||||
0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72,
|
||||
0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x12, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x54, 0x0a, 0x0f, 0x73, 0x74, 0x72,
|
||||
0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,
|
||||
0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
|
||||
0x65, 0x74, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52,
|
||||
0x0e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12,
|
||||
0x40, 0x0a, 0x1c, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x5f, 0x6f, 0x72, 0x69, 0x67, 0x69,
|
||||
0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18,
|
||||
0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x4f, 0x72,
|
||||
0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x12, 0x54, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72,
|
||||
0x72, 0x69, 0x64, 0x65, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x27, 0x2e, 0x76, 0x32, 0x72,
|
||||
0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78,
|
||||
0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63,
|
||||
0x6f, 0x6c, 0x73, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4f,
|
||||
0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x54, 0x0a, 0x11, 0x73, 0x6e, 0x69, 0x66, 0x66,
|
||||
0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x08, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x27, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x53, 0x6e, 0x69,
|
||||
0x66, 0x66, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x10, 0x73, 0x6e, 0x69,
|
||||
0x66, 0x66, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x4a, 0x04, 0x08,
|
||||
0x06, 0x10, 0x07, 0x22, 0xcc, 0x01, 0x0a, 0x14, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x48,
|
||||
0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x10, 0x0a, 0x03,
|
||||
0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x53,
|
||||
0x0a, 0x11, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69,
|
||||
0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61,
|
||||
0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65,
|
||||
0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
|
||||
0x65, 0x52, 0x10, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69,
|
||||
0x6e, 0x67, 0x73, 0x12, 0x4d, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74,
|
||||
0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x76, 0x32,
|
||||
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e,
|
||||
0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73,
|
||||
0x61, 0x67, 0x65, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,
|
||||
0x67, 0x73, 0x22, 0x10, 0x0a, 0x0e, 0x4f, 0x75, 0x74, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f,
|
||||
0x6e, 0x66, 0x69, 0x67, 0x22, 0xc8, 0x02, 0x0a, 0x0c, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x43,
|
||||
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x33, 0x0a, 0x03, 0x76, 0x69, 0x61, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x21, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e,
|
||||
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44,
|
||||
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x03, 0x76, 0x69, 0x61, 0x12, 0x54, 0x0a, 0x0f, 0x73, 0x74,
|
||||
0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,
|
||||
0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72,
|
||||
0x6e, 0x65, 0x74, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||
0x52, 0x0e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
|
||||
0x12, 0x51, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e,
|
||||
0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,
|
||||
0x0c, 0x0a, 0x08, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x10, 0x02, 0x22, 0x82, 0x01,
|
||||
0x0a, 0x0e, 0x53, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||
0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x31, 0x0a, 0x14, 0x64, 0x65,
|
||||
0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69,
|
||||
0x64, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e,
|
||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x23, 0x0a,
|
||||
0x0d, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x03,
|
||||
0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x4f, 0x6e,
|
||||
0x6c, 0x79, 0x22, 0xb4, 0x04, 0x0a, 0x0e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x43,
|
||||
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x72, 0x61,
|
||||
0x6e, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x76, 0x32, 0x72, 0x61,
|
||||
0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65,
|
||||
0x74, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x09, 0x70, 0x6f, 0x72,
|
||||
0x74, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x39, 0x0a, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,
|
||||
0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x49,
|
||||
0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x06, 0x6c, 0x69, 0x73, 0x74, 0x65,
|
||||
0x6e, 0x12, 0x5c, 0x0a, 0x13, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f,
|
||||
0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b,
|
||||
0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x12, 0x61, 0x6c, 0x6c,
|
||||
0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12,
|
||||
0x54, 0x0a, 0x0f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e,
|
||||
0x67, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,
|
||||
0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e,
|
||||
0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x43, 0x6f,
|
||||
0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69,
|
||||
0x6e, 0x67, 0x73, 0x12, 0x5a, 0x0a, 0x12, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78,
|
||||
0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x2b, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70,
|
||||
0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x11, 0x6d, 0x75,
|
||||
0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22,
|
||||
0x50, 0x0a, 0x12, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43,
|
||||
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12,
|
||||
0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63,
|
||||
0x79, 0x2a, 0x23, 0x0a, 0x0e, 0x4b, 0x6e, 0x6f, 0x77, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63,
|
||||
0x6f, 0x6c, 0x73, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, 0x54, 0x50, 0x10, 0x00, 0x12, 0x07, 0x0a,
|
||||
0x03, 0x54, 0x4c, 0x53, 0x10, 0x01, 0x42, 0x56, 0x0a, 0x1b, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32,
|
||||
0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x78, 0x79, 0x6d, 0x61, 0x6e, 0x50, 0x01, 0x5a, 0x1b, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63,
|
||||
0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x72, 0x6f, 0x78,
|
||||
0x79, 0x6d, 0x61, 0x6e, 0xaa, 0x02, 0x17, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72,
|
||||
0x65, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x62, 0x06,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43,
|
||||
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65, 0x74,
|
||||
0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x40, 0x0a, 0x1c, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65,
|
||||
0x5f, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e,
|
||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x72, 0x65, 0x63,
|
||||
0x65, 0x69, 0x76, 0x65, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x44, 0x65, 0x73, 0x74,
|
||||
0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x54, 0x0a, 0x0f, 0x64, 0x6f, 0x6d, 0x61, 0x69,
|
||||
0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0e,
|
||||
0x32, 0x27, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70,
|
||||
0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e, 0x4b, 0x6e, 0x6f, 0x77, 0x6e,
|
||||
0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0e, 0x64,
|
||||
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x54, 0x0a,
|
||||
0x11, 0x73, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e,
|
||||
0x67, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,
|
||||
0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d,
|
||||
0x61, 0x6e, 0x2e, 0x53, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
||||
0x67, 0x52, 0x10, 0x73, 0x6e, 0x69, 0x66, 0x66, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69,
|
||||
0x6e, 0x67, 0x73, 0x4a, 0x04, 0x08, 0x06, 0x10, 0x07, 0x22, 0xcc, 0x01, 0x0a, 0x14, 0x49, 0x6e,
|
||||
0x62, 0x6f, 0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66,
|
||||
0x69, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x03, 0x74, 0x61, 0x67, 0x12, 0x53, 0x0a, 0x11, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72,
|
||||
0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
|
||||
0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64,
|
||||
0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x10, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65,
|
||||
0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x4d, 0x0a, 0x0e, 0x70, 0x72, 0x6f,
|
||||
0x78, 0x79, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x26, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63,
|
||||
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70,
|
||||
0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79,
|
||||
0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x10, 0x0a, 0x0e, 0x4f, 0x75, 0x74, 0x62,
|
||||
0x6f, 0x75, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0xc8, 0x02, 0x0a, 0x0c, 0x53,
|
||||
0x65, 0x6e, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x33, 0x0a, 0x03, 0x76,
|
||||
0x69, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79,
|
||||
0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x6e, 0x65, 0x74,
|
||||
0x2e, 0x49, 0x50, 0x4f, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x03, 0x76, 0x69, 0x61,
|
||||
0x12, 0x54, 0x0a, 0x0f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69,
|
||||
0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x76, 0x32, 0x72, 0x61,
|
||||
0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74,
|
||||
0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d,
|
||||
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x65,
|
||||
0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x51, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f,
|
||||
0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a,
|
||||
0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e,
|
||||
0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x50,
|
||||
0x72, 0x6f, 0x78, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x78,
|
||||
0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x5a, 0x0a, 0x12, 0x6d, 0x75, 0x6c,
|
||||
0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18,
|
||||
0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
|
||||
0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x2e,
|
||||
0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66,
|
||||
0x69, 0x67, 0x52, 0x11, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x53, 0x65, 0x74,
|
||||
0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x50, 0x0a, 0x12, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c,
|
||||
0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65,
|
||||
0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e,
|
||||
0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72,
|
||||
0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63,
|
||||
0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2a, 0x23, 0x0a, 0x0e, 0x4b, 0x6e, 0x6f, 0x77, 0x6e,
|
||||
0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x54, 0x54,
|
||||
0x50, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x54, 0x4c, 0x53, 0x10, 0x01, 0x42, 0x56, 0x0a, 0x1b,
|
||||
0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61,
|
||||
0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0x50, 0x01, 0x5a, 0x1b, 0x76,
|
||||
0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x61, 0x70,
|
||||
0x70, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x6d, 0x61, 0x6e, 0xaa, 0x02, 0x17, 0x56, 0x32, 0x52,
|
||||
0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x50, 0x72, 0x6f, 0x78,
|
||||
0x79, 0x6d, 0x61, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -54,8 +54,12 @@ message SniffingConfig {
|
||||
bool enabled = 1;
|
||||
|
||||
// Override target destination if sniff'ed protocol is in the given list.
|
||||
// Supported values are "http", "tls".
|
||||
// Supported values are "http", "tls", "fakedns".
|
||||
repeated string destination_override = 2;
|
||||
|
||||
// Whether should only try to sniff metadata without waiting for client input.
|
||||
// Can be used to support SMTP like protocol where server send the first message.
|
||||
bool metadata_only = 3;
|
||||
}
|
||||
|
||||
message ReceiverConfig {
|
||||
|
@ -128,11 +128,13 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
|
||||
|
||||
if net.HasNetwork(nl, net.Network_UDP) {
|
||||
worker := &udpWorker{
|
||||
ctx: ctx,
|
||||
tag: tag,
|
||||
proxy: p,
|
||||
address: address,
|
||||
port: net.Port(port),
|
||||
dispatcher: h.mux,
|
||||
sniffingConfig: receiverConfig.GetEffectiveSniffingSettings(),
|
||||
uplinkCounter: uplinkCounter,
|
||||
downlinkCounter: downlinkCounter,
|
||||
stream: mss,
|
||||
|
@ -148,11 +148,13 @@ func (h *DynamicInboundHandler) refresh() error {
|
||||
|
||||
if net.HasNetwork(nl, net.Network_UDP) {
|
||||
worker := &udpWorker{
|
||||
ctx: h.ctx,
|
||||
tag: h.tag,
|
||||
proxy: p,
|
||||
address: address,
|
||||
port: port,
|
||||
dispatcher: h.mux,
|
||||
sniffingConfig: h.receiverConfig.GetEffectiveSniffingSettings(),
|
||||
uplinkCounter: uplinkCounter,
|
||||
downlinkCounter: downlinkCounter,
|
||||
stream: h.streamSettings,
|
||||
|
@ -87,6 +87,7 @@ func (w *tcpWorker) callback(conn internet.Connection) {
|
||||
if w.sniffingConfig != nil {
|
||||
content.SniffingRequest.Enabled = w.sniffingConfig.Enabled
|
||||
content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride
|
||||
content.SniffingRequest.MetadataOnly = w.sniffingConfig.MetadataOnly
|
||||
}
|
||||
ctx = session.ContextWithContent(ctx, content)
|
||||
if w.uplinkCounter != nil || w.downlinkCounter != nil {
|
||||
@ -230,11 +231,14 @@ type udpWorker struct {
|
||||
tag string
|
||||
stream *internet.MemoryStreamConfig
|
||||
dispatcher routing.Dispatcher
|
||||
sniffingConfig *proxyman.SniffingConfig
|
||||
uplinkCounter stats.Counter
|
||||
downlinkCounter stats.Counter
|
||||
|
||||
checker *task.Periodic
|
||||
activeConn map[connID]*udpConn
|
||||
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
func (w *udpWorker) getConnection(id connID) (*udpConn, bool) {
|
||||
@ -286,7 +290,7 @@ func (w *udpWorker) callback(b *buf.Buffer, source net.Destination, originalDest
|
||||
common.Must(w.checker.Start())
|
||||
|
||||
go func() {
|
||||
ctx := context.Background()
|
||||
ctx := w.ctx
|
||||
sid := session.NewID()
|
||||
ctx = session.ContextWithID(ctx, sid)
|
||||
|
||||
@ -300,6 +304,13 @@ func (w *udpWorker) callback(b *buf.Buffer, source net.Destination, originalDest
|
||||
Gateway: net.UDPDestination(w.address, w.port),
|
||||
Tag: w.tag,
|
||||
})
|
||||
content := new(session.Content)
|
||||
if w.sniffingConfig != nil {
|
||||
content.SniffingRequest.Enabled = w.sniffingConfig.Enabled
|
||||
content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride
|
||||
content.SniffingRequest.MetadataOnly = w.sniffingConfig.MetadataOnly
|
||||
}
|
||||
ctx = session.ContextWithContent(ctx, content)
|
||||
if err := w.proxy.Process(ctx, net.Network_UDP, conn, w.dispatcher); err != nil {
|
||||
newError("connection ends").Base(err).WriteToLog(session.ExportIDToError(ctx))
|
||||
}
|
||||
@ -428,6 +439,7 @@ func (w *dsWorker) callback(conn internet.Connection) {
|
||||
if w.sniffingConfig != nil {
|
||||
content.SniffingRequest.Enabled = w.sniffingConfig.Enabled
|
||||
content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride
|
||||
content.SniffingRequest.MetadataOnly = w.sniffingConfig.MetadataOnly
|
||||
}
|
||||
ctx = session.ContextWithContent(ctx, content)
|
||||
if w.uplinkCounter != nil || w.downlinkCounter != nil {
|
||||
|
76
common/cache/lru.go
vendored
Normal file
76
common/cache/lru.go
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
// Lru simple, fast lru cache implementation
|
||||
type Lru interface {
|
||||
Get(key interface{}) (value interface{}, ok bool)
|
||||
GetKeyFromValue(value interface{}) (key interface{}, ok bool)
|
||||
Put(key, value interface{})
|
||||
}
|
||||
|
||||
type lru struct {
|
||||
capacity int
|
||||
doubleLinkedlist *list.List
|
||||
keyToElement *sync.Map
|
||||
valueToElement *sync.Map
|
||||
mu *sync.Mutex
|
||||
}
|
||||
|
||||
type lruElement struct {
|
||||
key interface{}
|
||||
value interface{}
|
||||
}
|
||||
|
||||
// NewLru init a lru cache
|
||||
func NewLru(cap int) Lru {
|
||||
return lru{
|
||||
capacity: cap,
|
||||
doubleLinkedlist: list.New(),
|
||||
keyToElement: new(sync.Map),
|
||||
valueToElement: new(sync.Map),
|
||||
mu: new(sync.Mutex),
|
||||
}
|
||||
}
|
||||
|
||||
func (l lru) Get(key interface{}) (value interface{}, ok bool) {
|
||||
if v, ok := l.keyToElement.Load(key); ok {
|
||||
element := v.(*list.Element)
|
||||
l.doubleLinkedlist.MoveBefore(element, l.doubleLinkedlist.Front())
|
||||
return element.Value.(lruElement).value, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (l lru) GetKeyFromValue(value interface{}) (key interface{}, ok bool) {
|
||||
if k, ok := l.valueToElement.Load(value); ok {
|
||||
element := k.(*list.Element)
|
||||
l.doubleLinkedlist.MoveBefore(element, l.doubleLinkedlist.Front())
|
||||
return element.Value.(lruElement).key, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (l lru) Put(key, value interface{}) {
|
||||
e := lruElement{key, value}
|
||||
if v, ok := l.keyToElement.Load(key); ok {
|
||||
element := v.(*list.Element)
|
||||
element.Value = e
|
||||
l.doubleLinkedlist.MoveBefore(element, l.doubleLinkedlist.Front())
|
||||
} else {
|
||||
l.mu.Lock()
|
||||
element := l.doubleLinkedlist.PushFront(e)
|
||||
l.keyToElement.Store(key, element)
|
||||
l.valueToElement.Store(value, element)
|
||||
if l.doubleLinkedlist.Len() > l.capacity {
|
||||
toBeRemove := l.doubleLinkedlist.Back()
|
||||
l.doubleLinkedlist.Remove(toBeRemove)
|
||||
l.keyToElement.Delete(toBeRemove.Value.(lruElement).key)
|
||||
l.valueToElement.Delete(toBeRemove.Value.(lruElement).value)
|
||||
}
|
||||
l.mu.Unlock()
|
||||
}
|
||||
}
|
69
common/cache/lru_test.go
vendored
Normal file
69
common/cache/lru_test.go
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
package cache_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "v2ray.com/core/common/cache"
|
||||
)
|
||||
|
||||
func TestLruReplaceValue(t *testing.T) {
|
||||
lru := NewLru(2)
|
||||
lru.Put(2, 6)
|
||||
lru.Put(1, 5)
|
||||
lru.Put(1, 2)
|
||||
v, _ := lru.Get(1)
|
||||
if v != 2 {
|
||||
t.Error("should get 2", v)
|
||||
}
|
||||
v, _ = lru.Get(2)
|
||||
if v != 6 {
|
||||
t.Error("should get 6", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLruRemoveOld(t *testing.T) {
|
||||
lru := NewLru(2)
|
||||
v, ok := lru.Get(2)
|
||||
if ok {
|
||||
t.Error("should get nil", v)
|
||||
}
|
||||
lru.Put(1, 1)
|
||||
lru.Put(2, 2)
|
||||
v, _ = lru.Get(1)
|
||||
if v != 1 {
|
||||
t.Error("should get 1", v)
|
||||
}
|
||||
lru.Put(3, 3)
|
||||
v, ok = lru.Get(2)
|
||||
if ok {
|
||||
t.Error("should get nil", v)
|
||||
}
|
||||
lru.Put(4, 4)
|
||||
v, ok = lru.Get(1)
|
||||
if ok {
|
||||
t.Error("should get nil", v)
|
||||
}
|
||||
v, _ = lru.Get(3)
|
||||
if v != 3 {
|
||||
t.Error("should get 3", v)
|
||||
}
|
||||
v, _ = lru.Get(4)
|
||||
if v != 4 {
|
||||
t.Error("should get 4", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetKeyFromValue(t *testing.T) {
|
||||
lru := NewLru(2)
|
||||
lru.Put(3, 3)
|
||||
lru.Put(2, 2)
|
||||
lru.Put(1, 1)
|
||||
v, ok := lru.GetKeyFromValue(3)
|
||||
if ok {
|
||||
t.Error("should get nil", v)
|
||||
}
|
||||
v, _ = lru.GetKeyFromValue(2)
|
||||
if v != 2 {
|
||||
t.Error("should get 2", v)
|
||||
}
|
||||
}
|
@ -57,6 +57,7 @@ type Outbound struct {
|
||||
type SniffingRequest struct {
|
||||
OverrideDestinationForProtocol []string
|
||||
Enabled bool
|
||||
MetadataOnly bool
|
||||
}
|
||||
|
||||
// Content is the metadata of the connection content.
|
||||
|
12
features/dns/fakedns.go
Normal file
12
features/dns/fakedns.go
Normal file
@ -0,0 +1,12 @@
|
||||
package dns
|
||||
|
||||
import (
|
||||
"v2ray.com/core/common/net"
|
||||
"v2ray.com/core/features"
|
||||
)
|
||||
|
||||
type FakeDNSEngine interface {
|
||||
features.Feature
|
||||
GetFakeIPForDomain(domain string) []net.Address
|
||||
GetDomainFromFakeDNS(ip net.Address) string
|
||||
}
|
9
features/dns/localdns/errors.generated.go
Normal file
9
features/dns/localdns/errors.generated.go
Normal file
@ -0,0 +1,9 @@
|
||||
package localdns
|
||||
|
||||
import "v2ray.com/core/common/errors"
|
||||
|
||||
type errPathObjHolder struct{}
|
||||
|
||||
func newError(values ...interface{}) *errors.Error {
|
||||
return errors.New(values...).WithPathObj(errPathObjHolder{})
|
||||
}
|
65
infra/conf/fakedns.go
Normal file
65
infra/conf/fakedns.go
Normal file
@ -0,0 +1,65 @@
|
||||
package conf
|
||||
|
||||
import (
|
||||
"github.com/golang/protobuf/proto"
|
||||
"v2ray.com/core/app/dns/fakedns"
|
||||
)
|
||||
|
||||
type FakeDNSConfig struct {
|
||||
IPPool string `json:"ipPool"`
|
||||
LruSize int64 `json:"poolSize"`
|
||||
}
|
||||
|
||||
func (f FakeDNSConfig) Build() (proto.Message, error) {
|
||||
return &fakedns.FakeDnsPool{
|
||||
IpPool: f.IPPool,
|
||||
LruSize: f.LruSize,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type FakeDNSPostProcessingStage struct{}
|
||||
|
||||
func (FakeDNSPostProcessingStage) Process(conf *Config) error {
|
||||
var fakeDNSInUse bool
|
||||
|
||||
if conf.DNSConfig != nil {
|
||||
for _, v := range conf.DNSConfig.Servers {
|
||||
if v.Address.Family().IsDomain() {
|
||||
if v.Address.Domain() == "fakedns" {
|
||||
fakeDNSInUse = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if fakeDNSInUse {
|
||||
if conf.FakeDNS == nil {
|
||||
// Add a Fake DNS Config if there is none
|
||||
conf.FakeDNS = &FakeDNSConfig{
|
||||
IPPool: "240.0.0.0/8",
|
||||
LruSize: 65535,
|
||||
}
|
||||
}
|
||||
found := false
|
||||
// Check if there is a Outbound with necessary sniffer on
|
||||
var inbounds []InboundDetourConfig
|
||||
|
||||
if len(conf.InboundConfigs) > 0 {
|
||||
inbounds = append(inbounds, conf.InboundConfigs...)
|
||||
}
|
||||
for _, v := range inbounds {
|
||||
if v.SniffingConfig != nil && v.SniffingConfig.Enabled && v.SniffingConfig.DestOverride != nil {
|
||||
for _, dov := range *v.SniffingConfig.DestOverride {
|
||||
if dov == "fakedns" {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
newError("Defined Fake DNS but haven't enabled fake dns sniffing at any inbound.").AtWarning().WriteToLog()
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
5
infra/conf/init.go
Normal file
5
infra/conf/init.go
Normal file
@ -0,0 +1,5 @@
|
||||
package conf
|
||||
|
||||
func init() {
|
||||
RegisterConfigureFilePostProcessingStage("FakeDNS", &FakeDNSPostProcessingStage{})
|
||||
}
|
23
infra/conf/lint.go
Normal file
23
infra/conf/lint.go
Normal file
@ -0,0 +1,23 @@
|
||||
package conf
|
||||
|
||||
type ConfigureFilePostProcessingStage interface {
|
||||
Process(conf *Config) error
|
||||
}
|
||||
|
||||
var configureFilePostProcessingStages map[string]ConfigureFilePostProcessingStage
|
||||
|
||||
func RegisterConfigureFilePostProcessingStage(name string, stage ConfigureFilePostProcessingStage) {
|
||||
if configureFilePostProcessingStages == nil {
|
||||
configureFilePostProcessingStages = make(map[string]ConfigureFilePostProcessingStage)
|
||||
}
|
||||
configureFilePostProcessingStages[name] = stage
|
||||
}
|
||||
|
||||
func PostProcessConfigureFile(conf *Config) error {
|
||||
for k, v := range configureFilePostProcessingStages {
|
||||
if err := v.Process(conf); err != nil {
|
||||
return newError("Rejected by Postprocessing Stage ", k).AtError().Base(err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
@ -59,6 +59,7 @@ func toProtocolList(s []string) ([]proxyman.KnownProtocols, error) {
|
||||
type SniffingConfig struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
DestOverride *StringList `json:"destOverride"`
|
||||
MetadataOnly bool `json:"metadataOnly"`
|
||||
}
|
||||
|
||||
// Build implements Buildable.
|
||||
@ -71,6 +72,8 @@ func (c *SniffingConfig) Build() (*proxyman.SniffingConfig, error) {
|
||||
p = append(p, "http")
|
||||
case "tls", "https", "ssl":
|
||||
p = append(p, "tls")
|
||||
case "fakedns":
|
||||
p = append(p, "fakedns")
|
||||
default:
|
||||
return nil, newError("unknown protocol: ", domainOverride)
|
||||
}
|
||||
@ -80,6 +83,7 @@ func (c *SniffingConfig) Build() (*proxyman.SniffingConfig, error) {
|
||||
return &proxyman.SniffingConfig{
|
||||
Enabled: c.Enabled,
|
||||
DestinationOverride: p,
|
||||
MetadataOnly: c.MetadataOnly,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -346,6 +350,7 @@ type Config struct {
|
||||
API *APIConfig `json:"api"`
|
||||
Stats *StatsConfig `json:"stats"`
|
||||
Reverse *ReverseConfig `json:"reverse"`
|
||||
FakeDNS *FakeDNSConfig `json:"fakeDns"`
|
||||
}
|
||||
|
||||
func (c *Config) findInboundTag(tag string) int {
|
||||
@ -399,6 +404,10 @@ func (c *Config) Override(o *Config, fn string) {
|
||||
c.Reverse = o.Reverse
|
||||
}
|
||||
|
||||
if o.FakeDNS != nil {
|
||||
c.FakeDNS = o.FakeDNS
|
||||
}
|
||||
|
||||
// deprecated attrs... keep them for now
|
||||
if o.InboundConfig != nil {
|
||||
c.InboundConfig = o.InboundConfig
|
||||
@ -470,6 +479,10 @@ func applyTransportConfig(s *StreamConfig, t *TransportConfig) {
|
||||
|
||||
// Build implements Buildable.
|
||||
func (c *Config) Build() (*core.Config, error) {
|
||||
if err := PostProcessConfigureFile(c); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config := &core.Config{
|
||||
App: []*serial.TypedMessage{
|
||||
serial.ToTypedMessage(&dispatcher.Config{}),
|
||||
@ -536,6 +549,14 @@ func (c *Config) Build() (*core.Config, error) {
|
||||
config.App = append(config.App, serial.ToTypedMessage(r))
|
||||
}
|
||||
|
||||
if c.FakeDNS != nil {
|
||||
r, err := c.FakeDNS.Build()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.App = append(config.App, serial.ToTypedMessage(r))
|
||||
}
|
||||
|
||||
var inbounds []InboundDetourConfig
|
||||
|
||||
if c.InboundConfig != nil {
|
||||
|
@ -16,6 +16,7 @@ import (
|
||||
|
||||
// Other optional features.
|
||||
_ "v2ray.com/core/app/dns"
|
||||
_ "v2ray.com/core/app/dns/fakedns"
|
||||
_ "v2ray.com/core/app/log"
|
||||
_ "v2ray.com/core/app/policy"
|
||||
_ "v2ray.com/core/app/reverse"
|
||||
|
@ -38,6 +38,7 @@ type ownLinkVerifier interface {
|
||||
}
|
||||
|
||||
type Handler struct {
|
||||
client dns.Client
|
||||
ipv4Lookup dns.IPv4Lookup
|
||||
ipv6Lookup dns.IPv6Lookup
|
||||
ownLinkVerifier ownLinkVerifier
|
||||
@ -45,6 +46,7 @@ type Handler struct {
|
||||
}
|
||||
|
||||
func (h *Handler) Init(config *Config, dnsClient dns.Client) error {
|
||||
h.client = dnsClient
|
||||
ipv4lookup, ok := dnsClient.(dns.IPv4Lookup)
|
||||
if !ok {
|
||||
return newError("dns.Client doesn't implement IPv4Lookup")
|
||||
@ -211,6 +213,8 @@ func (h *Handler) handleIPQuery(id uint16, qType dnsmessage.Type, domain string,
|
||||
var ips []net.IP
|
||||
var err error
|
||||
|
||||
var ttl uint32 = 600
|
||||
|
||||
switch qType {
|
||||
case dnsmessage.TypeA:
|
||||
ips, err = h.ipv4Lookup.LookupIPv4(domain)
|
||||
@ -243,7 +247,7 @@ func (h *Handler) handleIPQuery(id uint16, qType dnsmessage.Type, domain string,
|
||||
}))
|
||||
common.Must(builder.StartAnswers())
|
||||
|
||||
rHeader := dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName(domain), Class: dnsmessage.ClassINET, TTL: 600}
|
||||
rHeader := dnsmessage.ResourceHeader{Name: dnsmessage.MustNewName(domain), Class: dnsmessage.ClassINET, TTL: ttl}
|
||||
for _, ip := range ips {
|
||||
if len(ip) == net.IPv4len {
|
||||
var r dnsmessage.AResource
|
||||
|
Loading…
Reference in New Issue
Block a user