Skip to content

تكامل Fake-IP

Fake-IP هي تقنية تُعيد فيها استعلامات DNS عناوين IP مزيفة مؤقتة من مجمع محجوز. عندما تصل حركة مرور إلى IP مزيف، يبحث النظام عن النطاق الأصلي ويوجّه بناءً على اسم النطاق بدلاً من عنوان IP (الذي لا معنى له).

لماذا Fake-IP؟

بدون Fake-IP، يواجه التوكيل الشفاف المبني على TUN معضلة:

App → DNS Query "google.com" → Real DNS → 142.250.80.14
App → Connect to 142.250.80.14 → TUN → Xray
  → Xray sees IP 142.250.80.14, but doesn't know domain "google.com"
  → Cannot do domain-based routing!

مع Fake-IP:

App → DNS Query "google.com" → Fake DNS → 198.18.0.42 (fake)
App → Connect to 198.18.0.42 → TUN → Xray
  → Xray detects 198.18.0.42 is in fake pool
  → Looks up: 198.18.0.42 → "google.com"
  → Routes based on domain "google.com"
  → Outbound resolves real IP and connects

البنية المعمارية

mermaid
flowchart TB
    App([Application]) -->|"DNS: google.com?"| DNS["Xray DNS Module"]
    DNS -->|"Return 198.18.0.42<br/>(fake IP)"| App

    App -->|"Connect to<br/>198.18.0.42"| TUN["TUN Interface"]
    TUN -->|"dest=198.18.0.42"| Handler["TUN Handler"]
    Handler -->|"DispatchLink(ctx,<br/>198.18.0.42:443)"| Dispatcher["Dispatcher"]

    Dispatcher --> Sniff["Sniffer"]
    Sniff --> FakeDNS["FakeDNS Sniffer"]
    FakeDNS -->|"198.18.0.42 in pool?<br/>→ google.com"| Override["Override dest:<br/>google.com:443"]
    Override --> Router["Router"]
    Router -->|"domain-based<br/>rule match"| Outbound["Outbound"]
    Outbound -->|"Resolve google.com<br/>→ real IP"| Server([Real Server])

FakeDNS Holder (app/dns/fakedns/fake.go)

go
type Holder struct {
    domainToIP cache.Lru       // LRU cache: domain → fake IP
    ipRange    *net.IPNet      // CIDR pool (e.g., 198.18.0.0/15)
    mu         *sync.Mutex
    config     *FakeDnsPool
}

تخصيص عناوين IP

go
func (fkdns *Holder) GetFakeIPForDomain(domain string) []net.Address {
    fkdns.mu.Lock()
    defer fkdns.mu.Unlock()

    // Check cache first
    if v, ok := fkdns.domainToIP.Get(domain); ok {
        return []net.Address{v.(net.Address)}
    }

    // Generate new fake IP based on current time
    currentTimeMillis := uint64(time.Now().UnixNano() / 1e6)
    ones, bits := fkdns.ipRange.Mask.Size()
    rooms := bits - ones
    if rooms < 64 {
        currentTimeMillis %= (uint64(1) << rooms)
    }

    bigIntIP := big.NewInt(0).SetBytes(fkdns.ipRange.IP)
    bigIntIP.Add(bigIntIP, new(big.Int).SetUint64(currentTimeMillis))

    // Handle collision: increment until unused IP found
    for {
        ip := net.IPAddress(bigIntIP.Bytes())
        if _, ok := fkdns.domainToIP.PeekKeyFromValue(ip); !ok {
            break  // IP not in use
        }
        bigIntIP.Add(bigIntIP, big.NewInt(1))
        if !fkdns.ipRange.Contains(bigIntIP.Bytes()) {
            bigIntIP = big.NewInt(0).SetBytes(fkdns.ipRange.IP)  // wrap around
        }
    }

    fkdns.domainToIP.Put(domain, ip)
    return []net.Address{ip}
}

البحث العكسي

go
func (fkdns *Holder) GetDomainFromFakeDNS(ip net.Address) string {
    if !fkdns.ipRange.Contains(ip.IP()) {
        return ""  // not a fake IP
    }
    if k, ok := fkdns.domainToIP.GetKeyFromValue(ip); ok {
        return k.(string)
    }
    return ""  // fake IP but domain expired from LRU cache
}

فحص المجمع

go
func (fkdns *Holder) IsIPInIPPool(ip net.Address) bool {
    if ip.Family().IsDomain() {
        return false
    }
    return fkdns.ipRange.Contains(ip.IP())
}

دعم المجمعات المتعددة

يدعم HolderMulti مجمعات Fake منفصلة لـ IPv4 وIPv6:

go
type HolderMulti struct {
    holders []*Holder  // e.g., [0]=198.18.0.0/15, [1]=fc00::/18
}

func (h *HolderMulti) GetFakeIPForDomain3(domain string, ipv4, ipv6 bool) []net.Address {
    var ret []net.Address
    for _, v := range h.holders {
        ret = append(ret, v.GetFakeIPForDomain3(domain, ipv4, ipv6)...)
    }
    return ret  // may return both IPv4 and IPv6 fake IPs
}

التكامل مع فحص الموزع

يتكون تكامل Fake-IP في الموزع من ثلاثة مكونات:

1. فاحص بيانات FakeDNS الوصفية

go
// app/dispatcher/fakednssniffer.go
func newFakeDNSSniffer(ctx) (protocolSnifferWithMetadata, error) {
    return protocolSnifferWithMetadata{
        protocolSniffer: func(ctx, _ []byte) (SniffResult, error) {
            ob := session.OutboundsFromContext(ctx)
            dest := ob[len(ob)-1].Target

            if fkr0.IsIPInIPPool(dest.Address) {
                domain := fkr0.GetDomainFromFakeDNS(dest.Address)
                if domain != "" {
                    return &fakeDNSSniffResult{domain: domain}, nil
                }
            }
            return nil, common.ErrNoClue
        },
        metadataSniffer: true,   // No payload needed
        network:         net.Network_TCP,
    }
}

2. مُركّب FakeDNS+Others

عندما يُحلّل Fake-IP النطاق، ولكننا نريد أيضًا الكشف عن البروتوكول بناءً على المحتوى:

go
// "fakedns+others" sniffer
// Returns Fake-IP domain as the domain result
// But uses content sniffing (TLS/HTTP) for protocol detection

3. قرار التجاوز

go
func (d *DefaultDispatcher) shouldOverride(ctx, result, request, destination) bool {
    for _, p := range request.OverrideDestinationForProtocol {
        // Always override fake IPs, regardless of RouteOnly
        if fkr0.IsIPInIPPool(destination.Address) && p == "fakedns" {
            return true
        }
    }
}

في مسار التوزيع:

go
// After sniffing:
isFakeIP := fkr0.IsIPInIPPool(ob.Target.Address)
if sniffingRequest.RouteOnly && !isFakeIP {
    ob.RouteTarget = destination  // route-only: don't change target
} else {
    ob.Target = destination       // full override (always for fake IPs)
}

الإعداد

json
{
  "dns": {
    "servers": [
      {
        "address": "fakedns",
        "domains": ["geosite:cn"]
      },
      "8.8.8.8"
    ]
  },
  "fakedns": {
    "ipPool": "198.18.0.0/15",
    "poolSize": 65535
  },
  "inbounds": [{
    "tag": "tun-in",
    "protocol": "tun",
    "sniffing": {
      "enabled": true,
      "destOverride": ["fakedns+others"]
    }
  }]
}

نقاط الإعداد الرئيسية:

  • كتلة fakedns تُهيّئ مجمع IP وحجم LRU
  • خادم DNS بعنوان "fakedns" يُفعّل استجابات Fake-IP
  • فحص destOverride يتضمن "fakedns" أو "fakedns+others"

دورة حياة اتصال Fake-IP

mermaid
sequenceDiagram
    participant App
    participant DNS as Xray DNS
    participant FDH as FakeDNS Holder
    participant TUN
    participant D as Dispatcher
    participant S as Sniffer
    participant R as Router
    participant O as Outbound

    App->>DNS: Query A google.com
    DNS->>FDH: GetFakeIPForDomain("google.com")
    FDH-->>DNS: 198.18.1.42
    DNS-->>App: A 198.18.1.42

    App->>TUN: TCP SYN to 198.18.1.42:443
    TUN->>D: DispatchLink(ctx, 198.18.1.42:443)
    D->>S: SniffMetadata(ctx)
    S->>FDH: IsIPInIPPool(198.18.1.42)?
    FDH-->>S: Yes
    S->>FDH: GetDomainFromFakeDNS(198.18.1.42)
    FDH-->>S: "google.com"
    S-->>D: FakeDNS result: google.com

    D->>D: Override target: google.com:443
    D->>R: PickRoute(google.com:443)
    R-->>D: outbound-proxy

    D->>O: Dispatch(google.com:443)
    O->>O: Resolve google.com → 142.250.80.14
    O->>O: Connect to 142.250.80.14:443

ملاحظات التنفيذ

  1. إخلاء LRU: ذاكرة التخزين المؤقت لعناوين IP المزيفة مبنية على LRU. عندما تمتلئ الذاكرة، يتم إخلاء أقدم إدخال. إذا كان لدى التطبيق اتصال مفتوح لعنوان IP المزيف المُخلى، سيفشل البحث العكسي. حدد حجم LRU بشكل مناسب (65535 هو الافتراضي).

  2. توليد IP المبني على الوقت: يُشتق عنوان IP المزيف من currentTimeMillis % poolSize. هذا يوفر توزيعًا عبر المجمع لكن قد يتعارض. حلقة حل التعارضات تتعامل مع هذا.

  3. فحص البيانات الوصفية فقط: لا يحتاج فاحص Fake-IP إلى قراءة أي بايتات من الحمولة. يفحص عنوان IP الوجهة مقابل المجمع قبل وصول أي بيانات. هذا يجعله فوريًا.

  4. التجاوز الكامل دائمًا لعناوين IP المزيفة: حتى مع routeOnly: true، يجب تجاوز عناوين IP المزيفة بالكامل (وليس فقط للتوجيه). عنوان IP المزيف ليس له معنى حقيقي — الاتصال به سيفشل.

  5. مجمعات IPv4 + IPv6: استخدم HolderMulti مع مجمع IPv4 واحد ومجمع IPv6 واحد. ستُعيد وحدة DNS النوع المناسب بناءً على الاستعلام (A مقابل AAAA).

  6. يجب اعتراض DNS: لكي تعمل Fake-IP، يجب أن تصل استعلامات DNS الخاصة بالتطبيق إلى وحدة DNS في Xray. يتطلب هذا عادةً:

    • TUN مع قواعد توجيه dns.hijack
    • أو توجيه DNS النظام إلى مستمع DNS في Xray

تحليل تقني لأغراض إعادة التنفيذ.