JavaScript-Scripting

Chute unterstützt JavaScript-Scripting für erweiterte Anfrage-/Antwortmodifikation, benutzerdefinierte Regelabgleiche, DNS-Auflösung und geplante Aufgaben. Skripte verwenden die JavaScriptCore-Engine von Apple und folgen der Surge-kompatiblen Skript-API.

Skripte werden im Abschnitt [Script] der Konfigurationsdatei definiert.

Konfiguration

[Script]
MyScript = type=http-request, script-path=/path/to/script.js, pattern=^https?://example\.com, requires-body=true, max-size=262144, timeout=10, argument=myArg, debug=true
CronJob = type=cron, script-path=/path/to/cron.js, cron-expression=* * * * *, wake-system=true

Skriptparameter

Parameter Erforderlich Standard Beschreibung
type Ja http-request Skript-Trigger-Typ (siehe unten)
script-path Ja Lokaler Dateipfad oder HTTP(S)-URL zum JS-Skript
pattern Nein (alle) URL-Regex-Muster zum Filtern, wann das Skript ausgelöst wird
requires-body Nein auto-detect Erzwingt, dass das Skript den vollständigen Anfrage-/Antwort-Body erhält
max-size Nein 131072 (128KB) Maximale Body-Größe in Bytes für Body-zugreifende Skripte
timeout Nein 5,0 Sekunden Ausführungs-Timeout pro Skript
argument Nein Benutzerdefiniertes String-Argument, verfügbar als $argument in JS
debug Nein false Kompilierungs-Cache für Debugging überspringen
cron-expression Nein Cron-Zeitplan-Ausdruck (nur für Cron-Typ)
wake-system Nein false System aufwecken, um Cron-Skripte auszuführen (nur iOS)
enable Nein true Dieses Skript aktivieren oder deaktivieren
script-update-interval Nein 0 Sekunden zwischen Remote-Skript-Aktualisierungen (-1 = nie, 0 = nur beim Start)

Skripttypen

Typ-String Enum Beschreibung
http-request HTTP Request HTTP-Anfragen vor dem Upstream abfangen und ändern
http-response HTTP Response HTTP-Antworten vor dem Client abfangen und ändern
http-request-before-send HTTP Request Before Send Anfrage nach vollständiger Body-Erfassung vor dem Senden ändern
rule Rule Benutzerdefinierte Regelabgleich-Logik
dns DNS Benutzerdefinierte DNS-Auflösung
cron Cron Geplante/zeitgesteuerte Skripte
event Event Systemereignishandler (z.B. network-changed)

Body-Autoerkennung: Wenn der Skriptquelltext $request.body oder $response.body enthält, wird der Body automatisch bis zu max-size bereitgestellt. Verwenden Sie requires-body=true, um dieses Verhalten zu erzwingen.


JavaScript-API-Referenz

Skripte laufen in einer sandboxed JavaScriptCore-Umgebung mit den folgenden verfügbaren globalen Objekten.

$request (Schreibgeschützt)

Verfügbar in: http-request, http-response, http-request-before-send, rule

Eigenschaft Typ Beschreibung
.url String Vollständige Anfrage-URL
.method String HTTP-Methode (GET, POST usw.) oder QUERY für DNS
.headers Object Anfrage-Header als Schlüssel-Wert-Paare
.body String oder null Anfrage-Body (UTF-8 dekodiert)
.hostname String Ziel-Hostname
.destPort Number Zielport
.processPath String Pfad des anfragenden Prozesses (nur macOS)
.userAgent String Wert des User-Agent-Headers
.sourceIP String Quell-IP-Adresse
.listenPort Number Proxy-Lauschport
.requestId String Eindeutige Anfrage-ID
.dnsResult String Aufgelöste IP-Adresse
.srcPort Number Quellport
.protocol String Erkanntes Protokoll: http, https, tcp, dns

$response (Schreibgeschützt)

Verfügbar in: http-response

Eigenschaft Typ Beschreibung
.status Number HTTP-Statuscode
.headers Object Antwort-Header als Schlüssel-Wert-Paare
.body String oder null Antwort-Body (UTF-8 dekodiert)

$done(value) — Abschluss-Handler

Muss genau einmal am Ende des Skripts aufgerufen werden, um den Abschluss zu signalisieren. Die Skriptausführung blockiert, bis $done() aufgerufen wird oder das Timeout abläuft.

$done({})                        // Durchleitung — keine Änderungen
$done()                          // Verbindung abbrechen
$done({matched: true})           // Regelabgleich-Ergebnis (nur Regel-Skripte)
$done({address: "1.2.3.4"})      // DNS-Ergebnis (nur DNS-Skripte)

Rückgabewerte für HTTP-Request-Skripte:

$done({
    url: "https://new.example.com/path",     // URL umschreiben
    headers: {"X-Custom": "value"},           // Header ändern
    body: "new request body",                 // Body ändern
    response: {                               // Synthetische Antwort zurückgeben (Upstream überspringen)
        status: 200,
        headers: {"Content-Type": "text/html"},
        body: "<html>Blocked</html>"
    }
})

Wenn response angegeben ist, wird die Anfrage kurzgeschlossen: Chute gibt die synthetische Antwort direkt an den Client zurück, ohne den Upstream-Server zu kontaktieren. Dies ist nützlich zum Blockieren, Mocken von APIs oder Zurückgeben von zwischengespeicherten Inhalten.

Rückgabewerte für HTTP-Response-Skripte:

$done({
    status: 200,                              // Statuscode ändern
    headers: {"X-Custom": "value"},           // Antwort-Header ändern
    body: "new response body",                // Antwort-Body ändern
    url: "https://other.example.com"          // 302-Weiterleitung auslösen
})

Wenn url angegeben ist, gibt Chute eine 302-Weiterleitung zur angegebenen URL anstelle der ursprünglichen Antwort zurück.

Rückgabewerte für DNS-Skripte:

$done({address: "1.2.3.4"})                  // Einzelne IP
$done({addresses: ["1.2.3.4", "5.6.7.8"]})   // Mehrere IPs
$done({address: "10.0.0.1", ttl: 300})       // Mit benutzerdefinierter TTL (Sekunden, Standard 60)
$done({server: "8.8.8.8"})                   // An bestimmten DNS-Server weiterleiten

$httpClient — Asynchroner HTTP-Client

Führen Sie HTTP-Anfragen aus Skripten heraus aus. Alle Anfragen werden bei $done() oder Timeout abgebrochen.

$httpClient.get(url, function(error, response, data) {
    if (error) {
        console.log("Anfrage fehlgeschlagen: " + error)
    } else {
        console.log("Status: " + response.status)
        console.log("Antwort: " + data)
    }
})

$httpClient.post(url, {headers: {...}, body: "...", timeout: 5}, callback)
$httpClient.put(url, options, callback)
$httpClient.del(url, options, callback)
$httpClient.head(url, options, callback)
$httpClient.options(url, options, callback)
$httpClient.patch(url, options, callback)

Callback-Signatur: callback(error, response, data)

  • error: Fehler-String oder null
  • response: {status: Number, headers: Object} oder null
  • data: UTF-8-String-Antwort-Body oder null

$persistentStore — Schlüssel-Wert-Speicher

Persistenter Schlüssel-Wert-Speicher, der Skript- und Prozessneustarts überdauert. Unterstützt durch NSUserDefaults.

$persistentStore.write(data, key)   // Einen Wert speichern
$persistentStore.read(key)          // Einen Wert abrufen
$persistentStore.remove(key)        // Einen Wert entfernen

$notification — Lokale Benachrichtigungen

Lokale Systembenachrichtigungen senden.

$notification.post("Titel", "Untertitel", "Benachrichtigungstext")

$network — Netzwerkinformationen

Schreibgeschützte Netzwerkzustandsinformationen.

$network.dns   // Array von DNS-Server-IPs
$network.wifi  // {ssid: "WiFiName", bssid: "aa:bb:cc:dd:ee:ff"}

$environment — Laufzeitinformationen

$environment.system     // "iOS" oder "macOS"
$environment.appVersion // App-Versionsstring

$utils — Hilfsfunktionen

$utils.geoip("1.2.3.4")   // Ländercode (z.B. "US")
$utils.ipasn("1.2.3.4")   // ASN-Nummer (z.B. "13335")
$utils.ungzip(data)       // Gzip-Daten dekomprimieren

$klne — Proxy-Steuerungs-API

Steuern Sie die Proxy-Laufzeit aus Skripten.

$klne.policyGroups                    // Alle Richtliniengruppen abrufen
$klne.selectPolicy("Group", "Proxy")  // Richtlinie für eine Gruppe wechseln
$klne.getActiveConnections()          // Aktive Verbindungen auflisten
$klne.closeConnection("id")           // Eine Verbindung schließen
$klne.flushDNS()                      // DNS-Cache leeren
$klne.startURLTest("Group")           // URL-Test für eine Gruppe auslösen
$klne.reloadConfiguration()           // Gesamte Konfiguration neu laden
$klne.setOutboundMode("rule")         // Modus setzen: "global", "proxy", "direct", "rule"
$klne.setHTTPCaptureEnabled(true)     // MITM aktivieren/deaktivieren

$script — Skript-Metadaten

$script.name       // Skriptname aus der Konfiguration
$script.type       // Skripttyp-String
$script.startTime  // Epochen-Zeitstempel

Globale Variablen pro Ausführung

Die folgenden Variablen werden pro Skriptausführung injiziert und sind spezifisch für bestimmte Skripttypen.

$argument — Skript-Argument

Der String-Wert aus dem Parameter argument= in der Skriptkonfiguration. Verfügbar in: http-request, http-response, http-request-before-send, rule, dns, cron.

console.log("Argument: " + $argument)

$domain — DNS-Domain (Nur DNS-Skript)

Der abgefragte Domainname. Nur in dns-Skripten verfügbar.

var domain = $domain  // z.B. "example.com"

$cronexp — Cron-Ausdruck (Nur Cron-Skript)

Der Cron-Zeitplan-Ausdruck aus der Skriptkonfiguration. Nur in cron-Skripten verfügbar.

console.log("Zeitplan: " + $cronexp)  // z.B. "*/30 * * * *"

$event — Ereignisinformationen (Nur Event-Skript)

Informationen über das auslösende Ereignis. Derzeit wird nur network-changed unterstützt.

console.log("Ereignis: " + $event.name)  // "network-changed"

console — Protokollierung

console.log("Debug-Nachricht")    // Ausführliche Protokollierung
console.warn("Warnmeldung")  // Warnprotokoll
console.error("Fehlermeldung")   // Fehlerprotokoll mit [JS-ERROR]-Präfix

setTimeout(fn, seconds) — Timer

Plant die Ausführung einer Funktion nach einer Verzögerung.

setTimeout(function() {
    console.log("Verzögerte Ausführung")
}, 2.5)  // 2,5 Sekunden

$script(subScriptPath) — Subskript-Loader

Lädt und wertet eine andere JavaScript-Datei aus.

$script("/path/to/helper.js")
$script("https://example.com/remote-script.js")

// Daten zwischen Skripten mit $persistentStore übergeben

Details zu Skripttypen

HTTP-Request-Skript

Wird ausgeführt, wenn Anfrage-Header empfangen werden. Kann URL, Header und Body ändern, bevor die Anfrage weitergeleitet wird.

[Script]
ModifyHeaders = type=http-request, script-path=modify.js, pattern=^https://api\.example\.com

HTTP-Response-Skript

Wird ausgeführt, wenn Antwort-Header empfangen werden. Kann Status, Header und Body ändern, bevor sie an den Client zurückgegeben werden.

[Script]
ModifyResponse = type=http-response, script-path=response.js, pattern=^https://api\.example\.com

HTTP-Request-Before-Send-Skript

Wird ausgeführt, nachdem der vollständige Anfrage-Body erfasst wurde, kurz vor dem Senden an den Upstream. Nützlich zum Ändern von POST/PUT-Anfrage-Bodys.

[Script]
BeforeSend = type=http-request-before-send, script-path=before-send.js, pattern=^https://api\.example\.com, requires-body=true

Regel-Skript

Benutzerdefinierter Regelabgleich. Das Skript muss $done({matched: true}) oder $done({matched: false}) aufrufen.

[Rule]
SCRIPT,MyRuleScript,DIRECT

[Script]
MyRuleScript = type=rule, script-path=rule.js

DNS-Skript

Benutzerdefinierte DNS-Auflösung. Erhält $domain und gibt aufgelöste Adresse(n) zurück.

// dns.js
var domain = $domain
if (domain === "internal.example.com") {
    $done({address: "10.0.0.1", ttl: 300})
} else {
    $done({})  // Durchleitung zur normalen DNS-Auflösung
}

Cron-Skript

Geplante Ausführung mit Cron-Ausdrücken. Das Mindestintervall beträgt 60 Sekunden.

[Script]
HourlyTask = type=cron, script-path=hourly.js, cron-expression=0 * * * *

Vereinfachte Cron-Syntax wird unterstützt (z.B. */30 * * * * für alle 30 Minuten, durch Kommas getrennte Werte).

Event-Skript

Durch Systemereignisse ausgelöst. Unterstützt derzeit das Ereignis network-changed (wird ausgelöst, wenn sich das Wi-Fi- oder Mobilfunknetz ändert).

[Script]
NetChange = type=event, script-path=network-changed.js

Das Objekt $event ist verfügbar:

$event.name  // "network-changed"

Praxisbeispiele

Mobile Geräte umleiten

Ein http-request-Skript, das mobile Benutzer basierend auf dem User-Agent umleitet:

[Script]
MobileRedirect = type=http-request, script-path=mobile-redirect.js, pattern=^https://example\\.com
// mobile-redirect.js
var ua = $request.headers["User-Agent"] || ""
if (/Mobile|Android|iPhone/.test(ua)) {
    $done({
        response: {
            status: 302,
            headers: {"Location": "https://m.example.com" + $request.url.replace(/.*example\\.com/, "")},
            body: ""
        }
    })
} else {
    $done({})
}

Inhalte in API-Antworten blockieren

Ein http-response-Skript, das Werbung und gesponserte Inhalte aus einer JSON-API-Antwort entfernt:

[Script]
RemoveAds = type=http-response, script-path=remove-ads.js, pattern=^https://api\\.example\\.com/feed, requires-body=true
// remove-ads.js
var body = JSON.parse($response.body)
if (body.ads) {
    delete body.ads
}
if (body.recommendations) {
    body.recommendations = body.recommendations.filter(function(r) {
        return !r.sponsored
    })
}
$done({body: JSON.stringify(body)})

Anfrage-Body vor dem Senden ändern

Ein http-request-before-send-Skript, das eine POST-Nutzlast bereinigt:

[Script]
SanitizePayload = type=http-request-before-send, script-path=sanitize.js, pattern=^https://api\\.example\\.com/submit, requires-body=true
// sanitize.js
var body = JSON.parse($request.body)
body.clientSecret = "[REDACTED]"
body.timestamp = Math.floor(Date.now() / 1000)
$done({body: JSON.stringify(body)})

Benutzerdefinierte Regel: Zeitbasiertes Routing

Ein rule-Skript, das je nach Tageszeit einen anderen Proxy auswählt:

[Rule]
SCRIPT,TimeBasedRule,ProxyA

[Script]
TimeBasedRule = type=rule, script-path=time-rule.js
// time-rule.js
var hour = new Date().getHours()
if (hour >= 9 && hour < 18) {
    $done({matched: false})  // Während der Arbeitszeit zur nächsten Regel durchfallen
} else {
    $done({matched: true})   // ProxyA außerhalb der Arbeitszeit verwenden
}

Benutzerdefiniertes DNS für interne Domains

Ein dns-Skript, das interne Hostnamen zu lokalen IPs auflöst:

[Script]
InternalDNS = type=dns, script-path=internal-dns.js
// internal-dns.js
var internalHosts = {
    "gitlab.local": "10.0.0.10",
    "registry.local": "10.0.0.11",
    "monitor.local": "10.0.0.12"
}
if (internalHosts[$domain]) {
    $done({address: internalHosts[$domain], ttl: 3600})
} else {
    $done({})  // Durchleitung zur normalen DNS-Auflösung
}

Richtlinie bei Netzwerkwechsel automatisch umschalten

Ein event-Skript, das bei Mobilfunkverbindung zu einer konservativen Richtliniengruppe wechselt:

[Script]
NetSwitch = type=event, script-path=network-switch.js
// network-switch.js
if (!$network.wifi.ssid) {
    // Bei Mobilfunk — Gruppe mit niedrigem Datenverbrauch verwenden
    $klne.selectPolicy("MainGroup", "LowDataProxy")
    console.log("Auf Mobilfunkprofil umgeschaltet")
} else if ($network.wifi.ssid === "Office") {
    $klne.selectPolicy("MainGroup", "DIRECT")
    console.log("Auf Büroprofil umgeschaltet")
}

Periodische Zustandsprüfung

Ein cron-Skript, das alle 30 Minuten die Proxy-Gesundheit prüft:

[Script]
HealthCheck = type=cron, script-path=health-check.js, cron-expression=*/30 * * * *
// health-check.js
$httpClient.head("https://www.google.com/generate_204", {timeout: 10},
    function(error, response, data) {
        if (error || response.status !== 204) {
            console.error("Zustandsprüfung fehlgeschlagen: " + (error || "Status " + response.status))
            $notification.post("Chute-Alarm", "Zustandsprüfung", "Google nicht erreichbar")
        } else {
            console.log("Zustandsprüfung OK")
        }
    }
)
$done()

API-Antworten mit externen Daten anreichern

Ein http-response-Skript, das Benutzerdaten durch Aufruf einer sekundären API anreichert:

[Script]
EnrichUsers = type=http-response, script-path=enrich.js, pattern=^https://api\\.example\\.com/users, requires-body=true
// enrich.js
var users = JSON.parse($response.body)
var pending = users.length
if (pending === 0) { $done({}) }

users.forEach(function(user, index) {
    $httpClient.get("https://internal-api.example.com/avatar/" + user.id,
        function(error, resp, data) {
            if (!error && resp.status === 200) {
                users[index].avatar = JSON.parse(data).url
            }
            pending--
            if (pending === 0) {
                $done({body: JSON.stringify(users)})
            }
        }
    )
})

Ausführungsmodell

  • Alle Skripte laufen in einer dedizierten seriellen Warteschlange für Thread-Sicherheit.
  • Jede Skriptausführung hat ein pro-Skript-Timeout; wenn $done() nicht innerhalb des Timeouts aufgerufen wird, wird das Skript als Durchleitung behandelt.
  • Ein JSContext-Pool (Größe 3) wird für die Leistung verwendet; Kontexte werden über Ausführungen hinweg wiederverwendet.
  • Die Skriptkompilierung wird standardmäßig zwischengespeichert; verwenden Sie debug=true, um den Cache zu umgehen.
  • Auf iOS/tvOS unterliegen Skripte einer Speicherbegrenzung von 10 MB; auf macOS 512 MB.
  • Remote-Skripte (HTTP/HTTPS-Pfade) werden beim Start abgerufen und optional nach script-update-interval Sekunden erneut abgerufen.

Modulskript-Integration

Skripte können auch in Modul-Dateien (.sgmodule) unter dem Abschnitt [Script] definiert werden. ```

S. Smart Rabbit LLC © All Rights Reserved            updated 2026-06-28 02:09:17

results matching ""

    No results matching ""