החייגן החכם מחפש אסטרטגיה שתבטל את החסימה של DNS ו-TLS עבור רשימה נתונה של דומיינים לבדיקה. הוא מקבל הגדרה שמתארת כמה אסטרטגיות לבחירה.
קובץ הגדרות YAML לחיוג חכם
ההגדרה שמקבלת החייגן החכם היא בפורמט YAML. לדוגמה:
dns:
- system: {}
- https:
name: 8.8.8.8
- https:
name: 9.9.9.9
tls:
- ""
- split:2
- tlsfrag:1
fallback:
- ss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTprSzdEdHQ0MkJLOE9hRjBKYjdpWGFK@1.2.3.4:9999/?outline=1
הגדרת DNS
- השדה
dnsמציין רשימה של מקודדי DNS לבדיקה. - כל פותר DNS יכול להיות אחד מהסוגים הבאים:
-
system: שימוש בפתרון הבעיות של המערכת. מציינים באמצעות אובייקט ריק. -
https: שימוש במפענח DNS מוצפן על גבי HTTPS (DoH). -
tls: שימוש במקודד DNS מוצפן באמצעות TLS (DoT). -
udp: שימוש ב-UDP resolver. -
tcp: שימוש ב-TCP resolver.
-
מקודד DNS-over-HTTPS (DoH)
https:
name: dns.google
address: 8.8.8.8
-
name: שם הדומיין של שרת DoH. -
address: המארח:היציאה של שרת ה-DoH. ברירת המחדל היאname:443.
מקודד DNS-over-TLS (DoT)
tls:
name: dns.google
address: 8.8.8.8
-
name: שם הדומיין של שרת DoT. -
address: המארח:היציאה של שרת ה-DoT. ברירת המחדל היאname:853.
UDP Resolver
udp:
address: 8.8.8.8
-
address: המארח:היציאה של פותר ה-UDP.
TCP Resolver
tcp:
address: 8.8.8.8
-
address: המארח:היציאה של פותר ה-TCP.
הגדרת TLS
- השדה
tlsמציין רשימה של פרוטוקולי TLS לתעבורה שצריך לבדוק. - כל העברה באמצעות TLS היא מחרוזת שמציינת את ההעברה שבה יש להשתמש.
- לדוגמה,
override:host=cloudflare.net|tlsfrag:1מציין תעבורה שמשתמשת בהסתרת דומיין עם Cloudflare ובפיצול TLS. פרטים נוספים מופיעים במסמכי התיעוד בנושא הגדרות.
הגדרת חזרה למצב ראשוני
הגדרה חלופית משמשת אם אף אחת מהאסטרטגיות ללא שרת proxy לא מצליחה להתחבר. לדוגמה, אפשר לציין שרת proxy לגיבוי כדי לנסות להתחבר למשתמש. השימוש בגיבוי יהיה איטי יותר בהתחלה, כי קודם האסטרטגיות האחרות של DNS/TLS צריכות להיכשל או להגיע לזמן קצוב לתפוגה.
מחרוזות הגיבוי צריכות להיות:
- מחרוזת הגדרה תקינה
StreamDialerכמוגדר ב-configurl. - אובייקט הגדרה תקין של Psiphon כצאצא של שדה
psiphon.
דוגמה לשרת Shadowsocks
fallback:
- ss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTprSzdEdHQ0MkJLOE9hRjBKYjdpWGFK@1.2.3.4:9999/?outline=1
דוגמה לשרת SOCKS5
fallback:
- socks5://[USERINFO]@[HOST]:[PORT]
דוגמה להגדרת Psiphon
כדי להשתמש ברשת Psiphon, צריך:
- כדי לקבל גישה לרשת שלהם, צריך לפנות לצוות של Psiphon כדי לקבל הגדרה. יכול להיות שיהיה צורך בחוזה.
- מוסיפים את הגדרות Psiphon שקיבלתם לקטע
fallbackבהגדרות של Smart Dialer. מכיוון ש-JSON תואם ל-YAML, אפשר להעתיק ולהדביק את ההגדרה של Psiphon ישירות לקטעfallback, כך:
fallback:
- psiphon: {
"PropagationChannelId": "FFFFFFFFFFFFFFFF",
"SponsorId": "FFFFFFFFFFFFFFFF",
"DisableLocalSocksProxy" : true,
"DisableLocalHTTPProxy" : true,
...
}
איך משתמשים בחייגן החכם
כדי להשתמש בחייגן החכם, יוצרים אובייקט StrategyFinder ומפעילים את השיטה NewDialer, ומעבירים את רשימת הדומיינים לבדיקה ואת הגדרת ה-YAML.
השיטה NewDialer תחזיר transport.StreamDialer שאפשר להשתמש בו כדי ליצור חיבורים באמצעות האסטרטגיה שנמצאה. לדוגמה:
finder := &smart.StrategyFinder{
TestTimeout: 5 * time.Second,
LogWriter: os.Stdout,
StreamDialer: &transport.TCPDialer{},
PacketDialer: &transport.UDPDialer{},
}
configBytes := []byte(`
dns:
- system: {}
- https:
name: 8.8.8.8
- https:
name: 9.9.9.9
tls:
- ""
- split:2
- tlsfrag:1
fallback:
- ss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTprSzdEdHQ0MkJLOE9hRjBKYjdpWGFK@1.2.3.4:9999/?outline=1
`)
dialer, err := finder.NewDialer(
context.Background(),
[]string{"www.google.com"},
configBytes
)
if err != nil {
// Handle error.
}
// Use dialer to create connections.
זוהי דוגמה בסיסית, ויכול להיות שתצטרכו להתאים אותה לתרחיש השימוש הספציפי שלכם.
הוספת שיטת חלופה חדשה
המערכת משתמשת באסטרטגיות חלופיות אם אף אחת מהאסטרטגיות ללא שרת proxy לא מצליחה. בדרך כלל מדובר בשרתי proxy שאמורים להיות אמינים יותר.
כדי להוסיף אסטרטגיית גיבוי חדשה:
- יוצרים פונקציית
FallbackParser. הפונקציה הזו מקבלתYAMLNodeומחזירהtransport.StreamDialerוחתימת הגדרה. - רושמים את
FallbackParserבאמצעות השיטהmobileproxy.SmartDialerOptions.RegisterFallbackParser.
לדוגמה, כך אפשר לרשום חלופה שמוגדרת עם {error: "my error message"} שתמיד מחזירה שגיאה בחיוג:
func RegisterErrorConfig(opt *mobileproxy.SmartDialerOptions, name string) {
opt.RegisterFallbackParser(name, func(ctx context.Context, yamlNode smart.YAMLNode) (transport.StreamDialer, string, error) {
switch typed := yamlNode.(type) {
case string:
dialer := transport.FuncStreamDialer(func(ctx context.Context, addr string) (transport.StreamConn, error) {
return nil, errors.New(typed)
})
return dialer, typed, nil
default:
return nil, "", fmt.Errorf("invalid error dialer config")
}
})
}
func main() {
// ...
opts := mobileproxy.NewSmartDialerOptions(mobileproxy.NewListFromLines(*testDomainsFlag), *configFlag)
opts.SetLogWriter(mobileproxy.NewStderrLogWriter())
RegisterErrorConfig(opts, "error")
//...
}