Skip to content

Instantly share code, notes, and snippets.

@daveio
Last active May 23, 2025 21:33
Show Gist options
  • Save daveio/2729615acf88ecad78e256e18e2e3bf2 to your computer and use it in GitHub Desktop.
Save daveio/2729615acf88ecad78e256e18e2e3bf2 to your computer and use it in GitHub Desktop.
RouterOS policy routing tutorial

RouterOS Policy-Based Routing: The Guide That Actually Makes Sense

Or: How I Learned to Stop Worrying and Love Packet Marking

Table of Contents

  1. Introduction: Why Are We Doing This to Ourselves?
  2. Policy-Based Routing: Because Normal Routing is Too Mainstream
  3. Configuration Variables: The Boring But Necessary Stuff
  4. Address Lists: Teaching Your Router to Play Favorites
  5. Routing Tables: Now We're Getting Fancy
  6. Full VRF: When VRF-Lite Isn't Extra Enough
  7. Route Configuration: Where Packets Go to Party
  8. Mangle Rules: The Dark Arts of Packet Manipulation
  9. NAT: Because Nothing Can Ever Be Simple
  10. Performance: Making It Go Brrrrr
  11. Common Pitfalls: Learn From My Pain
  12. Testing: Trust But Verify

Introduction: Why Are We Doing This to Ourselves? {#introduction}

Welcome, brave network administrator! You've decided that regular routing—where packets go from A to B like normal, well-adjusted data—is simply too boring. You want policy-based routing, where you get to micromanage every packet's life choices.

What We're Building

Imagine you're a control freak (if you're reading this, you probably are) who wants to:

  • Send your streaming traffic through a VPN because geo-restrictions are annoying
  • Keep your work traffic on the boring-but-reliable connection
  • Make your router's life complicated because... why not?
flowchart LR
    A[Your Computer] -->|Normal Traffic| B[Regular ISP]
    A -->|Special Traffic| C[VPN/Alt Route]
    B --> D[The Internet]
    C --> D

    style A fill:#800,stroke:#333,stroke-width:2px
    style C fill:#008,stroke:#333,stroke-width:2px
Loading

Policy-Based Routing: Because Normal Routing is Too Mainstream {#understanding-policy-based-routing}

Traditional Routing vs Policy-Based Routing: A Love Story

Let's start with a truth bomb: traditional routing is like a GPS that only knows one route to each destination. It's simple, reliable, and boring as watching paint dry.

graph TD
    subgraph "Traditional Routing (Boring)"
        A1[Packet arrives] --> B1{Destination?}
        B1 -->|8.8.8.8| C1[Always use ISP1]
        B1 -->|1.1.1.1| C1
        B1 -->|Anywhere| C1
    end

    subgraph "Policy-Based Routing (Fun!)"
        A2[Packet arrives] --> B2{What kind?}
        B2 -->|Streaming| C2[Use VPN]
        B2 -->|Work| D2[Use ISP1]
        B2 -->|Gaming| E2[Use ISP2]
    end
Loading

Traditional Routing thinks:

  • "Oh, you want to go to Netflix? Same route as everything else, buddy!"

Policy-Based Routing thinks:

  • "Netflix, you say? Let me check my list... Ah yes, you get the VPN treatment!"
  • "Work email? Straight through the corporate connection!"
  • "Random browsing? Dealer's choice!"

Why Would Anyone Do This?

Good question! Here are some totally reasonable scenarios:

  1. The "I'm Totally Not Pirating" Scenario: Route certain Linux ISOs through a VPN
  2. The "My Boss Thinks I'm Working" Setup: Work traffic goes through reliable connection
  3. The "I Have Two ISPs Because I'm Fancy" Configuration: Spread the load, feel important
  4. The "This One Service Hates My ISP" Workaround: Route problem children differently

Configuration Variables: The Boring But Necessary Stuff {#configuration-variables}

:local mainGatewayIPv4 "YOUR_MAIN_GATEWAY_IPv4"
:local mainGatewayIPv6 "YOUR_MAIN_GATEWAY_IPv6"
:local altGatewayIPv4 "YOUR_ALT_GATEWAY_IPv4"
:local altGatewayIPv6 "YOUR_ALT_GATEWAY_IPv6"
:local altGatewayInterface "YOUR_ALT_INTERFACE"

Look, I know variables are about as exciting as watching grass grow, but here's the thing: without them, you'll be playing find-and-replace with IP addresses at 3 AM when something breaks. And trust me, something will break.

Translation Guide for Humans:

  • mainGateway: Your ISP's router (the boring, reliable one)
  • altGateway: Your VPN/secondary connection (the fun, mysterious one)
  • altGatewayInterface: The actual port/connection name (ether2, pppoe-out1, or whatever creative name you gave it at 2 AM)

Pro tip:

Name your interfaces something meaningful. Future-you will thank present-you when you're not staring at "ether2" wondering if that's the VPN or your IoT network.

Address Lists: Teaching Your Router to Play Favorites {#address-lists}

/ip firewall address-list
add list=putio address=IPv4_ADDRESS_1 comment="Put.io - Streaming Service"
add list=putio address=IPv4_SUBNET/24 comment="Put.io - Entire subnet because I'm lazy"

Address lists are like your router's little black book—except instead of phone numbers, it's IP addresses, and instead of calling them, it routes packets differently.

flowchart TD
    subgraph "Address List: 'putio'"
        A[151.80.40.155]
        B[151.80.40.0/24]
        C[192.241.141.0/24]
        D[put.io - DNS entry]
    end

    E[Incoming Packet] -->|Is destination in list?| F{Match?}
    F -->|Yes| G[Special Treatment]
    F -->|No| H[Normal Routing]

    style G fill:#4a4,stroke:#333,stroke-width:2px
    style H fill:#a22,stroke:#333,stroke-width:2px
Loading

The Good, The Bad, and The Ugly

The Good:

  • Change IPs once, rules update everywhere
  • Named lists are self-documenting (if you're not lazy with names)
  • Can mix IPs, subnets, and even DNS names

The Bad:

  • DNS entries update on a schedule (not instantly)
  • Large lists eat RAM like Chrome eats... well, RAM

The Ugly:

  • Forgetting you have overlapping subnets and wondering why your counters are weird

Advanced Address List Wizardry

# The "I'll deal with this later" entry
add list=putio address=1.2.3.4 timeout=1h comment="Temporary - Bob's test"

# The "Follow the DNS" entry (updates automatically!)
add list=putio address=sketchy-streaming-site.com comment="Follows DNS changes"

# The "Import from file because I have 500 IPs" method
/import file=my-massive-list.txt

A Word of Warning

DNS-based entries are like that friend who's always "5 minutes away"—they update when they feel like it, not when you need them to. Plan accordingly.

Routing Tables: Now We're Getting Fancy {#routing-tables}

/routing table
add name=putio-route fib comment="Where streaming dreams come true"

Ah, routing tables—where we segregate our packets like it's network apartheid. But in a good way! Think of it as giving your special traffic its own VIP lane.

graph LR
    subgraph "RouterOS Brain"
        subgraph "Main Routing Table"
            A[Google: -> ISP1]
            B[Facebook: -> ISP1]
            C[Everything: -> ISP1]
        end

        subgraph "putio-route Table"
            D[Put.io: -> VPN]
            E[Everything else: -> VPN]
        end
    end

    F[Marked Packet] -->|Routing Mark| G{Which table?}
    G -->|main| A
    G -->|putio-route| D
Loading

Why Separate Tables?

Because sometimes you want to live in two different networking realities simultaneously. It's like having two GPS systems: one for your daily commute and one for your secret midnight food runs.

The Technical Bits That Actually Matter

  • FIB: Forwarding Information Base (fancy words for "where packets actually go")
  • Isolation: Each table is its own little universe
  • Memory: Yes, each table eats some. No, you probably won't notice unless you go crazy

Full VRF: When VRF-Lite Isn't Extra Enough {#full-vrf-implementation}

So you've been using our simple routing table approach (VRF-lite), but now you want the full VRF experience? You absolute madlad. Let's do this.

VRF-Lite vs Full VRF: The Showdown

graph TD
    subgraph "VRF-Lite (What we did)"
        A[Shared Interfaces]
        B[Separate Routing Tables]
        C[Packet Marking]
        A --> B
        B --> C
    end

    subgraph "Full VRF (Going Nuclear)"
        D[Dedicated Interfaces]
        E[Isolated Routing]
        F[Separate Everything]
        G[No Cross-Contamination]
        D --> E
        E --> F
        F --> G
    end
Loading

The Full VRF Implementation

Ready to go full network isolation? Here's how to implement proper VRF:

# Step 1: Create the VRF instance
/ip vrf
add name=streaming-vrf comment="My streaming paradise"

# Step 2: Assign interfaces to VRF (this is where it gets serious)
/interface ethernet
set ether3 vrf=streaming-vrf comment="Dedicated to VPN connection"

# Step 3: VRF-specific addresses
/ip address
add address=10.99.0.1/24 interface=ether3

# Step 4: VRF-specific DHCP (because why not complicate things further)
/ip dhcp-server
add name=streaming-dhcp interface=ether3 address-pool=streaming-pool

# Step 5: VRF-specific routes
/ip route
add dst-address=0.0.0.0/0 gateway=10.99.0.254 vrf=streaming-vrf

# Step 6: Inter-VRF routing (when you need them to talk)
/ip route
add dst-address=192.168.1.0/24 gateway=streaming-vrf@main

The Full VRF Experience: What Changes?

Isolation Level: Maximum

  • Interfaces are imprisoned in their VRF
  • No accidental packet leakage
  • Each VRF is like its own mini-router

Complexity Level: Also Maximum

  • Need separate everything (DHCP, DNS, firewall rules)
  • Inter-VRF communication requires explicit routes
  • Troubleshooting becomes "fun"
flowchart TD
    subgraph "Main VRF"
        A[LAN: 192.168.1.0/24]
        B[WAN: ISP1]
        C[Normal Services]
    end

    subgraph "Streaming VRF"
        D[LAN: 10.99.0.0/24]
        E[WAN: VPN]
        F[Streaming Services]
    end

    G[Inter-VRF Route] -.->|Explicit Permission| A
    G -.-> D

    style G fill:#660,stroke:#333,stroke-width:2px,stroke-dasharray: 5 5
Loading

When to Use Full VRF

Use VRF-Lite (our original approach) when:

  • You just want some traffic to go differently
  • You trust your firewall rules
  • You value your sanity

Use Full VRF when:

  • You need actual security isolation
  • You're running multi-tenant environments
  • You enjoy complexity
  • Your therapist says you need more stress in your life

VRF Gotchas That Will Ruin Your Day

  1. The "Why Can't I Ping?" Classic

    • Services in different VRFs can't see each other
    • Yes, this includes your management access
    • Hope you have console access!
  2. The "My DNS Broke" Surprise

    • Each VRF needs its own DNS config
    • Or explicit routes to shared DNS
  3. The "Where Did My Route Go?" Mystery

    • Routes are VRF-specific
    • Check you're in the right VRF context

Route Configuration: Where Packets Go to Party {#route-configuration}

/ip route
add dst-address=0.0.0.0/0 gateway=$mainGatewayIPv4 distance=1 comment="The boring route"
add dst-address=0.0.0.0/0 gateway=$altGatewayIPv4 distance=1 routing-table=putio-route comment="The fun route"

Routes are like giving directions to a very literal friend. You need to be specific, or they'll end up in Saskatchewan when you meant San Francisco.

graph TD
    A[I need to go to 8.8.8.8] --> B{Check Routing Table}
    B -->|Main Table| C[Gateway: 192.168.1.1 The Reliable ISP]
    B -->|putio-route Table| D[Gateway: 10.0.0.1 The VPN]

    C --> E[Destination]
    D --> E

    style C fill:#060
    style D fill:#006
Loading

Gateway Types: Choose Your Fighter

# The "I know the IP" gateway
add gateway=192.168.1.1 comment="Simple and direct"

# The "Just use that interface" gateway
add gateway=ether1 comment="For PPPoE and other weird stuff"

# The "I'm very specific" gateway
add gateway=192.168.1.1%ether1 comment="IP + Interface, because paranoia"

# The "I'll figure it out later" gateway
add gateway=pppoe-out1 comment="Dynamic interfaces"

Distance: It's Not About Geography

Distance in routing is like popularity in high school—lower is better, and it's all about preference:

add dst-address=0.0.0.0/0 gateway=192.168.1.1 distance=1 comment="Primary (favorite child)"
add dst-address=0.0.0.0/0 gateway=10.0.0.1 distance=2 comment="Backup (second favorite)"
add dst-address=0.0.0.0/0 gateway=172.16.0.1 distance=10 comment="Last resort (red-headed stepchild)"

Mangle Rules: The Dark Arts of Packet Manipulation {#mangle-rules}

Welcome to the mangle table, where we perform unspeakable acts on innocent packets. It's like packet surgery, but without the medical degree.

/ip firewall mangle
# Step 1: Mark the connection (like tagging cattle, but for data)
add chain=prerouting dst-address-list=putio action=mark-connection \
    new-connection-mark=putio-conn passthrough=yes comment="Tag, you're it!"

# Step 2: Mark the routing (the actual magic)
add chain=prerouting connection-mark=putio-conn action=mark-routing \
    new-routing-mark=putio-route passthrough=no comment="Now go that way!"

The Two-Step Tango Explained

sequenceDiagram
    participant P as Packet
    participant CM as Connection Marker
    participant RM as Routing Marker
    participant RT as Routing Table

    P->>CM: First packet arrives
    CM->>CM: Check dst-address-list
    CM->>P: Mark connection "putio-conn"
    Note over CM: Connection remembered!

    P->>RM: Continue to next rule
    RM->>RM: See connection mark
    RM->>P: Mark routing "putio-route"
    Note over RM: Stop processing (passthrough=no)

    P->>RT: Use alternate routing table

    Note over P: Future packets skip address check!
Loading

Why Two Steps? A Dramatic Reenactment

Packet #1: "Hi, I'm going to Put.io!" Rule 1: "Ah, Put.io! Let me mark your entire connection. There, you're tagged!" Rule 2: "I see you're tagged. Here's your VIP routing mark. Off you go!"

Packet #2 (same connection): "Hi, I'm also going to Put.io!" Rule 1: "No need to check the address list, your connection is already marked!" Rule 2: "Tagged connection? VIP routing for you too!"

This is why we love connection marking—it's lazy in the best way possible.

Passthrough: The Traffic Light of Packet Processing

flowchart LR
    A[Packet enters] --> B{Rule 1<br/>passthrough=yes}
    B -->|Green light| C{Rule 2<br/>passthrough=no}
    C -->|Red light| D[Stop here]
    C -.->|Would continue if yes| E{Rule 3}

    style C fill:#060
    style D fill:#c00
    style E fill:#c00,stroke-dasharray: 5 5
Loading
  • passthrough=yes: "Mark it and keep going, there might be more rules!"
  • passthrough=no: "Mark it and STOP. We're done here."

Common Mangle Mistakes That'll Make You Cry

  1. The "Wrong Chain" Classic
# WRONG - Forward chain can't do routing marks
add chain=forward action=mark-routing  # Won't work!

# RIGHT - Prerouting for routing marks
add chain=prerouting action=mark-routing  # Works!
  1. The "Order Matters" Disaster
# WRONG ORDER - Routing mark before connection mark
add chain=prerouting action=mark-routing  # How do you know what to mark?
add chain=prerouting action=mark-connection  # Too late!
  1. The "Forgotten Return Traffic" Special
# INCOMPLETE - Only marks destination
add chain=prerouting dst-address-list=putio action=mark-connection

# COMPLETE - Marks both directions
add chain=prerouting dst-address-list=putio action=mark-connection
add chain=prerouting src-address-list=putio action=mark-connection

NAT: Because Nothing Can Ever Be Simple {#nat-configuration}

/ip firewall nat
add chain=srcnat out-interface=$altGatewayInterface action=masquerade \
    comment="Hide behind the VPN like a network ninja"

NAT is like wearing a disguise to a party. Sometimes you need it, sometimes you don't, but when you need it and don't have it, you're not getting in.

sequenceDiagram
    participant L as LAN Device<br/>192.168.1.100
    participant R as Router
    participant V as VPN<br/>10.0.0.1
    participant I as Internet

    L->>R: From: 192.168.1.100<br/>To: Put.io
    Note over R: NAT Translation
    R->>V: From: 10.0.0.5<br/>To: Put.io
    V->>I: Forwarded

    I->>V: Reply to: 10.0.0.5
    V->>R: Reply to: 10.0.0.5
    Note over R: NAT Reverse Translation
    R->>L: Reply to: 192.168.1.100
Loading

When You Need NAT (The Hall of Shame)

  1. VPN Connections: They expect traffic from their assigned IP, not your LAN
  2. Mobile Internet: Your 4G provider doesn't care about your 192.168.x.x
  3. That One ISP: Who refuses to route your LAN without paying extra
  4. Cloud VPS: When you're bouncing through a remote server

Masquerade vs SNAT: The Eternal Debate

# Masquerade: The "I'm flexible" approach
action=masquerade  # Uses whatever IP the interface has

# SNAT: The "I know what I want" approach
action=src-nat to-addresses=203.0.113.1  # Always use this IP

Choose Masquerade when:

  • Your IP changes (DHCP, PPPoE)
  • You're lazy (it's okay, we all are)
  • You enjoy the mystery

Choose SNAT when:

  • You have a static IP
  • You need that 0.01% performance boost
  • You enjoy typing more

NAT Nightmares to Avoid

graph TD
    A[Common NAT Problems] --> B[Double NAT]
    A --> C[NAT Hairpinning]
    A --> D[Breaking Protocols]

    B --> E[Performance Dies]
    C --> F[LAN Can't Access Services]
    D --> G[FTP/SIP/Others Cry]

    style E fill:#c00
    style F fill:#c00
    style G fill:#c00
Loading

Performance: Making It Go Brrrrr {#performance-optimization}

/ip firewall raw
add chain=prerouting dst-address-list=putio action=notrack \
    comment="Bypass connection tracking because SPEED"

Performance optimization is like tuning a car—you can make it faster, but you might lose your air conditioning.

The Connection Tracking Dilemma

flowchart TD
    subgraph "Normal Flow (Slow but Safe)"
        A1[Packet] --> B1[Connection Tracking]
        B1 --> C1[Mangle]
        C1 --> D1[Routing]
        D1 --> E1[Filter]
        E1 --> F1[Forward]
    end

    subgraph "Notrack Flow (Fast but Reckless)"
        A2[Packet] --> B2[Raw: NOTRACK]
        B2 --> C2[Mangle]
        C2 --> D2[Routing]
        D2 --> F2[Forward]
    end

    style B1 fill:#c00
    style B2 fill:#060
Loading

When to Use Notrack (Living Dangerously)

Perfect for:

  • Netflix binges (unidirectional, high bandwidth)
  • That Linux ISO collection (definitely legitimate)
  • Any bulk transfer where you trust both ends

Terrible for:

  • Anything needing NAT
  • Stateful firewall rules
  • Connection limits
  • Accounting (unless you like mystery)

The Performance Spectrum

graph LR
    A[Slowest] --> B[Connection Tracking]
    B --> C[FastTrack]
    C --> D[Hardware Offload]
    D --> E[Notrack]
    E --> F[Fastest]

    style A fill:#c00
    style F fill:#060
Loading

Choose your fighter based on your needs:

  • Full Tracking: Maximum features, maximum overhead
  • FastTrack: Best of both worlds for established connections
  • Hardware Offload: If your hardware supports it (lucky you!)
  • Notrack: YOLO mode

Common Pitfalls: Learn From My Pain {#common-pitfalls-and-solutions}

1. The Asymmetric Routing Nightmare

graph LR
    A[Your PC] -->|Upload via VPN| B[VPN Server]
    C[Put.io] -->|Download via ISP| D[Main ISP]
    B --> C
    D --> A

    style B fill:#060
    style D fill:#c00
Loading

The Problem: Your uploads go through VPN, downloads come back through regular ISP. TCP has a mental breakdown.

The Fix: Connection marking saves the day by remembering the path.

2. DNS: The Silent Killer

The Scene: Everything's routing perfectly, except... nothing works. The Plot Twist: DNS queries are using the wrong path.

# The "Oh right, DNS exists" fix
add chain=output protocol=udp dst-port=53 dst-address-list=putio \
    action=mark-routing new-routing-mark=putio-route \
    comment="Because DNS is important, apparently"

3. The "Why Can't I Ping?" Mystery

You: "The routing works perfectly!" Also you: "But ping doesn't work..." ICMP: "Did everyone forget about me?"

# The "ICMP needs love too" solution
add chain=prerouting protocol=icmp dst-address-list=putio \
    action=mark-routing new-routing-mark=putio-route \
    comment="ICMP: The forgotten protocol"

4. The Failover That Doesn't

sequenceDiagram
    participant U as User
    participant R as Router
    participant V as VPN (Dead)
    participant I as Internet

    U->>R: Send packet to Put.io
    R->>V: Route via VPN
    Note over V: VPN is down!
    R->>V: Still trying...
    R->>V: Still trying...
    U->>U: Why is nothing working?
Loading

The Fix: Check-gateway to the rescue!

add dst-address=0.0.0.0/0 gateway=$altGatewayIPv4 \
    routing-table=putio-route check-gateway=ping \
    comment="Actually check if the gateway is alive"

Testing: Trust But Verify {#testing-and-verification}

Because "it should work" is not a valid troubleshooting step.

The Essential Testing Toolkit

# 1. The "Is my address list working?" check
/ip firewall address-list print where list=putio

# 2. The "Are packets getting marked?" investigation
/ip firewall mangle print stats where action=mark-routing

# 3. The "Where are my packets going?" tracker
/tool traceroute put.io routing-table=putio-route

# 4. The "Show me everything" debug mode
/ip firewall mangle
add chain=prerouting dst-address-list=putio \
    action=log log-prefix="PUTIO-DEBUG:" \
    comment="Temporary debugging - REMOVE ME"

The Interactive Troubleshooting Flowchart

flowchart TD
    A[Routing Not Working] --> B{Packets Marked?}
    B -->|No| C[Check Mangle Rules]
    B -->|Yes| D{Route Exists?}

    C --> E[Check Address List]
    C --> F[Check Rule Order]

    D -->|No| G[Check Routing Table]
    D -->|Yes| H{Gateway Up?}

    H -->|No| I[Check Gateway/Interface]
    H -->|Yes| J[Check NAT/Firewall]

    style A fill:#c00
    style J fill:#060
Loading

Pro Testing Tips

  1. Start Simple: Test with one IP before adding entire subnets
  2. Use Logging: But remember to remove it (your disk will thank you)
  3. Test Both Directions: Upload and download, ping and pong
  4. Document What Works: Future you will appreciate it

Best Practices: Don't Be That Person

The Commandments of Policy-Based Routing

  1. Thou Shalt Comment Everything

    # BAD
    add list=putio address=1.2.3.4
    
    # GOOD
    add list=putio address=1.2.3.4 comment="Put.io CDN - US East servers"
    
  2. Thou Shalt Not Overlap Subnets Unnecessarily

    • Having both 10.0.0.0/8 and 10.0.0.0/24 in the same list is just wasteful
  3. Thou Shalt Test Before Production

    • Your users don't appreciate being your guinea pigs
  4. Thou Shalt Have a Rollback Plan

    • Export your config before making changes
    • Know how to access your router when you break routing
  5. Thou Shalt Monitor Thy Creation

    • Set up logging during testing
    • Remove excessive logging in production
    • Keep an eye on connection counts

The Golden Rules

  • Start Simple: Get basic routing working before adding complexity
  • Document Everything: Your successor (probably you in 6 months) will thank you
  • Test Incrementally: Add one feature at a time
  • Have Console Access: Because you will lock yourself out eventually

Conclusion: You Did It!

Congratulations! You've just learned how to make your router's life significantly more complicated. You now have the power to route packets based on their hopes, dreams, and destination addresses.

Remember:

  • With great routing power comes great troubleshooting responsibility
  • Every rule you add is one more thing that can break
  • But hey, at least your streaming works through the VPN now!

Now go forth and route selectively. May your packets find their way, and may your connection marks never expire unexpectedly.

P.S. - If everything breaks, you can always reset to defaults and pretend this never happened. We won't judge.

# RouterOS Policy-Based Routing Script for putio traffic
# This script routes traffic matching address lists through alternative gateways
# === CONFIGURATION VARIABLES ===
# Replace these placeholders with your actual values
:local mainGatewayIPv4 "YOUR_MAIN_GATEWAY_IPv4"
:local mainGatewayIPv6 "YOUR_MAIN_GATEWAY_IPv6"
:local altGatewayIPv4 "YOUR_ALT_GATEWAY_IPv4"
:local altGatewayIPv6 "YOUR_ALT_GATEWAY_IPv6"
:local altGatewayInterface "YOUR_ALT_INTERFACE" # e.g., ether2, pppoe-out1
# === CREATE ADDRESS LISTS ===
# IPv4 Address List
/ip firewall address-list
add list=putio address=IPv4_ADDRESS_1 comment="Put.io IPv4"
add list=putio address=IPv4_ADDRESS_2 comment="Put.io IPv4"
add list=putio address=IPv4_SUBNET/24 comment="Put.io IPv4 subnet"
# IPv6 Address List
/ipv6 firewall address-list
add list=putio address=IPv6_ADDRESS_1 comment="Put.io IPv6"
add list=putio address=IPv6_ADDRESS_2 comment="Put.io IPv6"
add list=putio address=IPv6_PREFIX::/64 comment="Put.io IPv6 prefix"
# === CREATE ROUTING TABLES ===
/routing table
add name=putio-route fib comment="Routing table for Put.io traffic"
# === CREATE ROUTING RULES ===
# IPv4 Routes
/ip route
# Main default route (if not already exists)
add dst-address=0.0.0.0/0 gateway=$mainGatewayIPv4 distance=1 comment="Main IPv4 default route"
# Alternative route for marked traffic
add dst-address=0.0.0.0/0 gateway=$altGatewayIPv4 distance=1 routing-table=putio-route comment="Put.io IPv4 route"
# IPv6 Routes
/ipv6 route
# Main default route (if not already exists)
add dst-address=::/0 gateway=$mainGatewayIPv6 distance=1 comment="Main IPv6 default route"
# Alternative route for marked traffic
add dst-address=::/0 gateway=$altGatewayIPv6 distance=1 routing-table=putio-route comment="Put.io IPv6 route"
# === CREATE MANGLE RULES ===
# IPv4 Mangle Rules
/ip firewall mangle
# Mark connections TO putio addresses
add chain=prerouting dst-address-list=putio action=mark-connection \
new-connection-mark=putio-conn passthrough=yes comment="Mark connections TO Put.io IPv4"
# Mark connections FROM putio addresses
add chain=prerouting src-address-list=putio action=mark-connection \
new-connection-mark=putio-conn passthrough=yes comment="Mark connections FROM Put.io IPv4"
# Mark routing for putio connections
add chain=prerouting connection-mark=putio-conn action=mark-routing \
new-routing-mark=putio-route passthrough=no comment="Route Put.io IPv4 traffic"
# IPv6 Mangle Rules
/ipv6 firewall mangle
# Mark connections TO putio addresses
add chain=prerouting dst-address-list=putio action=mark-connection \
new-connection-mark=putio-conn-v6 passthrough=yes comment="Mark connections TO Put.io IPv6"
# Mark connections FROM putio addresses
add chain=prerouting src-address-list=putio action=mark-connection \
new-connection-mark=putio-conn-v6 passthrough=yes comment="Mark connections FROM Put.io IPv6"
# Mark routing for putio connections
add chain=prerouting connection-mark=putio-conn-v6 action=mark-routing \
new-routing-mark=putio-route passthrough=no comment="Route Put.io IPv6 traffic"
# === NAT RULES (if needed) ===
# If your alternative gateway requires NAT
/ip firewall nat
add chain=srcnat out-interface=$altGatewayInterface action=masquerade \
comment="NAT for Put.io traffic through alternative gateway"
# === OPTIONAL: CONNECTION TRACKING BYPASS ===
# For better performance with streaming traffic
/ip firewall raw
add chain=prerouting dst-address-list=putio action=notrack comment="Bypass conntrack for Put.io IPv4"
add chain=prerouting src-address-list=putio action=notrack comment="Bypass conntrack from Put.io IPv4"
/ipv6 firewall raw
add chain=prerouting dst-address-list=putio action=notrack comment="Bypass conntrack for Put.io IPv6"
add chain=prerouting src-address-list=putio action=notrack comment="Bypass conntrack from Put.io IPv6"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment