Удалось наконец-то “настроить”: Gemini 2.5 Pro Exp постарался. Ставлю на то что решение переусложнено, но уж поделюсь тем что есть, решение рабочее. Смысл как будто бы в том чтобы маркировать трафик, чтобы разделять его между sing-box и zapret.
/etc/sing-box/config
{
"inbounds": [
{
"type": "tun",
"tag": "all-in",
"domain_strategy": "prefer_ipv4",
"inet4_address": "172.16.0.1/30",
"mtu": 9000,
"stack": "system",
"auto_route": false,
"strict_route": false,
"sniff": true,
"sniff_override_destination": true
},
// ...
}
Здесь ключевое это auto_route, т.к. маршрутизацию мы будем настраивать вручную, автоматика не работает.
В /opt/zapret/config раскоментировал строки
INIT_FW_POST_UP_HOOK="/etc/firewall.zapret.hook.post_up"
INIT_FW_PRE_DOWN_HOOK="/etc/firewall.zapret.hook.pre_down"
И создал соответствующие файлы:
/etc/firewall.zapret.hook.post_up
#!/bin/sh
# --- Configuration Variables ---
SINGBOX_MARK="0x100"
SINGBOX_ROUTE_TABLE_ID="100" # Routing table ID for sing-box
SINGBOX_TUN_INTERFACE="tun0" # Your sing-box TUN interface name
NFT_ZAPRET_TABLE="inet zapret" # Standard zapret table name
NFT_PREROUTING_CHAIN="prerouting" # Standard prerouting chain in the zapret table
NFT_CUSTOM_MARK_CHAIN="singbox_fwmark_chain" # Custom chain for your marking rules
NFT_ZAPRET_IPSET_NAME="@zapret" # The nfset created by zapret for its IPs
# Define your VLESS server IP and Port if you want to exclude direct traffic to it from marking
# VLESS_SERVER_IP="your.vless.server.ip.address"
# VLESS_SERVER_PORT="your_vless_server_port"
# --- End Configuration Variables ---
# Function to log messages
log_message() {
logger -t "custom_routing" "$1"
}
log_message "Starting custom routing rules UP script."
# 1. Set up nftables custom chain and marking rule
# -------------------------------------------------
# Check if the custom chain exists in the zapret table, create if not
if ! nft list chain "$NFT_ZAPRET_TABLE" "$NFT_CUSTOM_MARK_CHAIN" > /dev/null 2>&1; then
log_message "Creating nft chain: $NFT_ZAPRET_TABLE $NFT_CUSTOM_MARK_CHAIN"
nft add chain "$NFT_ZAPRET_TABLE" "$NFT_CUSTOM_MARK_CHAIN"
else
log_message "Nft chain $NFT_ZAPRET_TABLE $NFT_CUSTOM_MARK_CHAIN already exists. Flushing."
nft flush chain "$NFT_ZAPRET_TABLE" "$NFT_CUSTOM_MARK_CHAIN"
fi
# Check if a jump rule to the custom chain exists in prerouting, add if not
# The handle number (-a) allows for easier deletion if needed.
if ! nft -a list chain "$NFT_ZAPRET_TABLE" "$NFT_PREROUTING_CHAIN" | grep -q "jump $NFT_CUSTOM_MARK_CHAIN"; then
log_message "Adding jump rule from $NFT_PREROUTING_CHAIN to $NFT_CUSTOM_MARK_CHAIN in table $NFT_ZAPRET_TABLE"
# Add the jump at the beginning of the prerouting chain; adjust if needed
nft insert rule "$NFT_ZAPRET_TABLE" "$NFT_PREROUTING_CHAIN" position 0 jump "$NFT_CUSTOM_MARK_CHAIN" comment "\"Jump to custom sing-box marking\""
else
log_message "Jump rule to $NFT_CUSTOM_MARK_CHAIN already exists in $NFT_ZAPRET_TABLE $NFT_PREROUTING_CHAIN."
fi
# Add the marking rule to your custom chain
# This rule marks traffic NOT in zapret's IP set.
log_message "Adding marking rule to $NFT_CUSTOM_MARK_CHAIN: ip daddr != $NFT_ZAPRET_IPSET_NAME mark set $SINGBOX_MARK"
nft add rule "$NFT_ZAPRET_TABLE" "$NFT_CUSTOM_MARK_CHAIN" ip daddr != "$NFT_ZAPRET_IPSET_NAME" mark set "$SINGBOX_MARK" comment "\"Mark non-NFQWS traffic for sing-box\""
# Optional: If you want to exclude traffic directly to your VLESS server from being marked (and thus from sing-box loop)
# Ensure VLESS_SERVER_IP and VLESS_SERVER_PORT are defined above
# if [ -n "$VLESS_SERVER_IP" ] && [ -n "$VLESS_SERVER_PORT" ]; then
# log_message "Adding rule to $NFT_CUSTOM_MARK_CHAIN to accept direct VLESS traffic without marking."
# nft add rule "$NFT_ZAPRET_TABLE" "$NFT_CUSTOM_MARK_CHAIN" ip daddr "$VLESS_SERVER_IP" tcp dport "$VLESS_SERVER_PORT" accept comment "\"Allow direct VLESS server traffic\""
# fi
# 2. Set up iproute2 rules
# -------------------------
# Add rule to use the custom routing table for marked packets, if it doesn't exist
if ! ip rule show | grep -q "fwmark $SINGBOX_MARK lookup $SINGBOX_ROUTE_TABLE_ID"; then
log_message "Adding ip rule: fwmark $SINGBOX_MARK lookup $SINGBOX_ROUTE_TABLE_ID"
ip rule add fwmark "$SINGBOX_MARK" lookup "$SINGBOX_ROUTE_TABLE_ID" priority 20000
else
log_message "IP rule for fwmark $SINGBOX_MARK lookup $SINGBOX_ROUTE_TABLE_ID already exists."
fi
# Add default route via sing-box TUN interface to the custom table, if it doesn't exist
# Ensure the sing-box TUN interface is up; this script runs after firewall, so it should be.
if ! ip route show table "$SINGBOX_ROUTE_TABLE_ID" | grep -q "default dev $SINGBOX_TUN_INTERFACE"; then
log_message "Adding ip route: default dev $SINGBOX_TUN_INTERFACE table $SINGBOX_ROUTE_TABLE_ID"
ip route add default dev "$SINGBOX_TUN_INTERFACE" table "$SINGBOX_ROUTE_TABLE_ID"
else
log_message "IP route default dev $SINGBOX_TUN_INTERFACE table $SINGBOX_ROUTE_TABLE_ID already exists."
fi
log_message "Custom routing rules UP script finished."
exit 0
/etc/firewall.zapret.hook.pre_down
#!/bin/sh
# --- Configuration Variables ---
SINGBOX_MARK="0x100"
SINGBOX_ROUTE_TABLE_ID="100"
SINGBOX_TUN_INTERFACE="tun0" # Your sing-box TUN interface name
NFT_ZAPRET_TABLE_FAMILY_NAME="inet zapret" # Table family and name
# !! IMPORTANT: TRY THIS SET NAME FIRST, BASED ON THE NFTABLES ERROR HINT !!
# If this doesn't work, you will need to inspect 'nft list table inet zapret'
# after zapret starts to find the actual set name.
PROPOSED_NFT_SET_NAME_IN_TABLE="zapret"
# Original attempt (if the above fails, you might revert or find the correct one):
# PROPOSED_NFT_SET_NAME_IN_TABLE="zapret_ip"
NFT_ZAPRET_IPSET_REF="@${PROPOSED_NFT_SET_NAME_IN_TABLE}" # How the set is referenced in rules
NFT_PREROUTING_CHAIN_FQN="${NFT_ZAPRET_TABLE_FAMILY_NAME} prerouting"
NFT_CUSTOM_MARK_CHAIN_NAME="singbox_fwmark_chain"
NFT_CUSTOM_MARK_CHAIN_FQN="${NFT_ZAPRET_TABLE_FAMILY_NAME} ${NFT_CUSTOM_MARK_CHAIN_NAME}"
# --- End Configuration Variables ---
# Function to log messages
log_message() {
logger -t "custom_routing_up" "$1"
}
log_message "Starting custom routing rules UP script."
# Keep a delay, as some initialization might still be asynchronous
log_message "Waiting 5 seconds for zapret to fully initialize its nftables structures..."
sleep 5
# 0. Verify that the main zapret table exists
# -------------------------------------------
if ! nft list table ${NFT_ZAPRET_TABLE_FAMILY_NAME} > /dev/null 2>&1; then
log_message "CRITICAL ERROR: Zapret nftables table '${NFT_ZAPRET_TABLE_FAMILY_NAME}' does not exist. Cannot proceed."
log_message "Please ensure zapret service has started correctly and created its main table."
exit 1
fi
log_message "Zapret nftables table '${NFT_ZAPRET_TABLE_FAMILY_NAME}' confirmed to exist."
# 1. Verify that the PROPOSED IP set DEFINITION exists in the zapret table
# -----------------------------------------------------------------------
log_message "Attempting to verify existence of IP set definition '${PROPOSED_NFT_SET_NAME_IN_TABLE}' in table '${NFT_ZAPRET_TABLE_FAMILY_NAME}'..."
if ! nft list set ${NFT_ZAPRET_TABLE_FAMILY_NAME} "${PROPOSED_NFT_SET_NAME_IN_TABLE}" > /dev/null 2>&1; then
log_message "CRITICAL ERROR: IP set definition '${PROPOSED_NFT_SET_NAME_IN_TABLE}' was NOT FOUND in table '${NFT_ZAPRET_TABLE_FAMILY_NAME}'."
log_message "The rule referencing '${NFT_ZAPRET_IPSET_REF}' will fail."
log_message "To resolve this: "
log_message " 1. After 'service zapret restart' (even if this script fails), manually run: 'nft list table ${NFT_ZAPRET_TABLE_FAMILY_NAME}'"
log_message " 2. Look for 'set <name> { ... }' definitions. Identify the correct set name that zapret uses for its IP lists."
log_message " 3. Update the 'PROPOSED_NFT_SET_NAME_IN_TABLE' variable at the top of this script (${0}) with the correct name."
log_message "Listing all currently defined sets in table '${NFT_ZAPRET_TABLE_FAMILY_NAME}' to help diagnosis:"
nft list sets ${NFT_ZAPRET_TABLE_FAMILY_NAME} 2>&1 | logger -t "custom_routing_up" # Log the list of sets
exit 1
fi
log_message "SUCCESS: IP set definition '${PROPOSED_NFT_SET_NAME_IN_TABLE}' (referenced as '${NFT_ZAPRET_IPSET_REF}') found in table '${NFT_ZAPRET_TABLE_FAMILY_NAME}'."
# 2. Set up nftables custom chain for marking rules
# -------------------------------------------------
# Check if the custom chain exists, create if not
if ! nft list chain ${NFT_CUSTOM_MARK_CHAIN_FQN} > /dev/null 2>&1; then
log_message "Creating nft chain: ${NFT_CUSTOM_MARK_CHAIN_FQN}"
nft add chain ${NFT_ZAPRET_TABLE_FAMILY_NAME} "${NFT_CUSTOM_MARK_CHAIN_NAME}"
else
log_message "Nft chain ${NFT_CUSTOM_MARK_CHAIN_FQN} already exists. Flushing its rules."
nft flush chain ${NFT_CUSTOM_MARK_CHAIN_FQN}
fi
# Add a jump rule from the main prerouting chain to your custom marking chain
# Ensure the prerouting chain exists in the zapret table (zapret itself should create this)
if ! nft -a list chain ${NFT_PREROUTING_CHAIN_FQN} | grep -q "jump ${NFT_CUSTOM_MARK_CHAIN_NAME}"; then
log_message "Adding jump rule from ${NFT_PREROUTING_CHAIN_FQN} to ${NFT_CUSTOM_MARK_CHAIN_NAME}"
# Insert at a high-priority position (e.g., 0 or adjust as needed)
nft insert rule ${NFT_PREROUTING_CHAIN_FQN} position 0 jump "${NFT_CUSTOM_MARK_CHAIN_NAME}" comment "\"Jump to custom sing-box marking\""
else
log_message "Jump rule to ${NFT_CUSTOM_MARK_CHAIN_NAME} already exists in ${NFT_PREROUTING_CHAIN_FQN}."
fi
# 3. Add the actual marking rule to your custom chain
# ---------------------------------------------------
log_message "Attempting to add marking rule to ${NFT_CUSTOM_MARK_CHAIN_FQN}: ip daddr != ${NFT_ZAPRET_IPSET_REF} mark set ${SINGBOX_MARK}"
if nft add rule ${NFT_CUSTOM_MARK_CHAIN_FQN} ip daddr != "${NFT_ZAPRET_IPSET_REF}" mark set "${SINGBOX_MARK}" comment "\"Mark non-NFQWS traffic for sing-box\""; then
log_message "SUCCESS: Marking rule added to ${NFT_CUSTOM_MARK_CHAIN_FQN}."
else
MARKING_RULE_ERROR_CODE=$?
log_message "ERROR: Failed to add marking rule to ${NFT_CUSTOM_MARK_CHAIN_FQN}. Exit code: ${MARKING_RULE_ERROR_CODE}"
log_message "This can happen if the IP set '${NFT_ZAPRET_IPSET_REF}' was not correctly identified/resolved or if there is a syntax error."
log_message "Dumping current ruleset for table ${NFT_ZAPRET_TABLE_FAMILY_NAME} for review:"
nft list table ${NFT_ZAPRET_TABLE_FAMILY_NAME} 2>&1 | logger -t "custom_routing_up"
exit 1 # Exit if this crucial rule fails
fi
# 4. Set up iproute2 rules for sing-box
# -------------------------------------
log_message "Setting up iproute2 rules..."
# Add rule to use the custom routing table for marked packets
if ! ip rule show | grep -q "fwmark ${SINGBOX_MARK} lookup ${SINGBOX_ROUTE_TABLE_ID}"; then
log_message "Adding ip rule: fwmark ${SINGBOX_MARK} lookup ${SINGBOX_ROUTE_TABLE_ID} priority 20000"
ip rule add fwmark "${SINGBOX_MARK}" lookup "${SINGBOX_ROUTE_TABLE_ID}" priority 20000
else
log_message "IP rule for fwmark ${SINGBOX_MARK} lookup ${SINGBOX_ROUTE_TABLE_ID} already exists."
fi
# Add default route via sing-box TUN interface to the custom table
if ! ip route show table "${SINGBOX_ROUTE_TABLE_ID}" | grep -q "default dev ${SINGBOX_TUN_INTERFACE}"; then
log_message "Adding ip route: default dev ${SINGBOX_TUN_INTERFACE} table ${SINGBOX_ROUTE_TABLE_ID}"
ip route add default dev "${SINGBOX_TUN_INTERFACE}" table "${SINGBOX_ROUTE_TABLE_ID}"
else
log_message "IP route default dev ${SINGBOX_TUN_INTERFACE} table ${SINGBOX_ROUTE_TABLE_ID} already exists."
fi
log_message "Custom routing rules UP script finished successfully."
exit 0