Routing Hook
The core calls the global HandleRoute function in routing.script when selecting an outbound. See the Routing Scripts guide for configuration and complete examples.
API Index
| Category | Member | Description |
|---|---|---|
| Hook | HandleRoute(...) | Select an outbound for a request |
| Object | routing.Context | The current request's routing context |
| Method | ctx:GetSourceIPs() | Get source IPs |
| Method | ctx:GetTargetIPs() | Get target IPs |
| Method | ctx:GetLocalIPs() | Get local IPs |
| Method | ctx:GetAttributes() | Get request attributes |
Hook Interface
HandleRoute(...)
function HandleRoute(ctx, inboundTag, sourcePort, targetPort,
localPort, targetDomain, network, protocol, user,
vlessRoute, skipDNSResolve)
return outboundTag, ruleTag, err
end2
3
4
5
Selects an outbound for the current request, optionally returning a rule name or an error.
Parameters
The core always passes all 11 parameters in the order shown above, and none is nil. You can omit unused trailing parameters from the function definition; this does not change the values passed by the core.
| Parameter | Type | Description | Empty and Default Values |
|---|---|---|---|
ctx | routing.Context | Current request context | Always valid userdata |
inboundTag | string | Inbound tag | "" if the inbound has no tag or inbound information is unavailable |
sourcePort | number | Source port, 0 .. 65535 | 0 if no valid source address is available |
targetPort | number | Target port, 0 .. 65535 | 0 if no valid target address is available |
localPort | number | Local port of the inbound connection, 0 .. 65535 | 0 if no valid local address is available |
targetDomain | string | The effective sniffed domain takes precedence over the connection's target domain; converted to lowercase | "" if the target is an IP without an effective sniffed domain, or target information is unavailable |
network | number | Network type; compare with constants such as router.NetworkTCP | NetworkUnknown (0) if outbound information is unavailable or the network type is unknown |
protocol | string | Sniffed protocol | "" if sniffed protocol information is unavailable |
user | string | User email | "" if inbound or user information is unavailable, or no email is set |
vlessRoute | number | Routing value formed from bytes 7 and 8 of the VLESS UUID, 0 .. 65535 | 0 if unavailable; the value itself may also be 0 |
skipDNSResolve | boolean | When true, DNS queries must be skipped to avoid loops | false if the flag or additional request information is unavailable |
Return Values
| Return value | Type | Description |
|---|---|---|
outboundTag | string or nil | Outbound tag; nil or "" means no outbound was selected |
ruleTag | string or nil | Optional rule name; nil, omission, or "" means no name |
err | error, string, or nil | Only nil means no error |
Behavior
The core validates err, outboundTag, and ruleTag in that order, stopping at the first error. When err is non-nil, the first two values are ignored. When no outbound is selected, ruleTag is ignored.
On success, trailing ruleTag and err values may be omitted, for example return "direct". An error must be in the third position, for example return nil, nil, "routing failed"; return nil, "routing failed" does not report an error.
| Script result | Core behavior |
|---|---|
Validation succeeds and outboundTag is non-empty | Uses the corresponding outbound; closes the connection if the tag does not exist |
| No outbound selected | Uses the default outbound |
| Returned error, invalid return-value type, or execution exception | Logs the error and tries the default outbound |
The default outbound is the first outbound in the configuration; the connection is closed if no default outbound is available. To block traffic, explicitly return a configured blackhole outbound tag instead of relying on this behavior with a nonexistent tag.
Related Objects
routing.Context
routing.Context represents the current request's routing context, accessed through the ctx parameter in HandleRoute.
| Property | Description |
|---|---|
| Underlying Go type | The routing.Context interface in features/routing |
| Lua representation | userdata |
| Obtained from | The first argument passed by the core to HandleRoute |
All methods below take no additional parameters. See Data Types for IP and slice operations.
GetSourceIPs
local ips = ctx:GetSourceIPs()Gets the request's source IPs.
Parameters
No additional parameters.
Return Values
| Return value | Type | Description |
|---|---|---|
ips | []net.IP or nil | IP list for the corresponding address |
Behavior
Returns nil if there is no inbound, the source address is invalid, or it is not an IP address.
GetTargetIPs
local ips = ctx:GetTargetIPs()Gets the request's target IPs.
Parameters
No additional parameters.
Return Values
| Return value | Type | Description |
|---|---|---|
ips | []net.IP or nil | IP list for the corresponding address |
Behavior
Returns nil if there is no outbound, the target address is invalid, or it is a domain name.
GetLocalIPs
local ips = ctx:GetLocalIPs()Gets the local IPs of the inbound connection.
Parameters
No additional parameters.
Return Values
| Return value | Type | Description |
|---|---|---|
ips | []net.IP or nil | IP list for the corresponding address |
Behavior
Returns nil if there is no inbound, the local address is invalid, or it is not an IP address.
GetAttributes
local attributes = ctx:GetAttributes()Gets the current request's attributes.
Parameters
No additional parameters.
Return Values
| Return value | Type | Description |
|---|---|---|
attributes | map[string]string | Always userdata; never nil |
Behavior
Read attributes with attributes[key], where key must be a string. An existing key returns a string (possibly ""); a missing key returns nil.
See the attrs field in the routing configuration for the meaning and use of attributes.
Example
local attributes = ctx:GetAttributes()
if attributes[":method"] == "GET" then
return "direct", "lua-get"
end2
3
4