Forum Discussion

Steve_Magnuson_'s avatar
Steve_Magnuson_
Icon for Nimbostratus rankNimbostratus
Nov 17, 2015

How can I force the LTM SOCKS Service to send connect requests out a specific interface?

Hello,

I've set up an LTM running 11.6 to act as an stunnel server (see stunnel.org). A client on the Internet is configured as an stunnel client. The stunnel client is listening on TCP port 1080 for SOCKS requests from other hosts on the stunnel client's local network. When a SOCKSified browser on one of those other hosts attempts to visit a web site, the request is sent to the stunnel client, which sets up an SSL connection to the stunnel server (LTM). The LTM forwards the SOCKS traffic inside the SSL connection to a SOCKS service on the same LTM, where it is subject to a whitelist implemented via an iRule and Data Group.

Network configuration is as follows:

[Host with SOCKSified browser]----[stunnel client]----[Internet]----[Outside Firewall]a----b[BigIP LTM]c-----d[Inside Firewall]----[Inside Network]

Where

  • a = 11.12.13.225 external firewall's inside IP address
  • b = 11.12.13.226 LTM's external IP address
  • c = 10.239.127.40 LTM's internal IP address
  • d = 10.239.127.33 internal firewall's outside IP address

This all works fine.

Now, I want to modify the LTM configuration such that the outbound connect requests from the LTM's SOCKS service are always sent out the LTM's internal interface through the inside firewall rather than out whatever interface the LTM's route table dictates.

Problem:

This situation seemed to me to call for an additional route domain. So, I configured a second route domain (1) and added the inside interface of the LTM to it, added a default route in that second domain with a next hop of (d), and I configured the SOCKS service to use this route domain, but outbound connect requests for external hosts still traverse the LTM's outside interface. I'd appreciate any pointers.

Configuration:
admin@(vira231g4)(cfg-sync Standalone)(Active)(/Common)(tmos) list ltm virtual vs_230_STUNNEL-self_SOCKS
ltm virtual vs_230_STUNNEL-self_SOCKS {
    description ""
    destination 11.12.13.230:9443
    ip-protocol tcp
    mask 255.255.255.255
    profiles {
        g4vip230_SSL {
            context clientside
        }
        tcp { }
    }
    rules {
        irule_log_SSL
        irule_self_SOCKS
    }
    source 0.0.0.0/0
    source-address-translation {
        type automap
    }
    vs-index 6
}
admin@(vira231g4)(cfg-sync Standalone)(Active)(/Common)(tmos) list ltm virtual vs_self_SOCKS
ltm virtual vs_self_SOCKS {
    description ""
    destination 11.12.13.130:socks
    ip-protocol tcp
    mask 255.255.255.255
    profiles {
        self_SOCKS { }
        tcp { }
    }
    rules {
        irule_whitelist_SOCKS
    }
    source 0.0.0.0/0
    source-address-translation {
        type automap
    }
    vlans-enabled
    vs-index 5
}

admin@(vira231g4)(cfg-sync Standalone)(Active)(/Common)(tmos) list ltm rule irule_whitelist_SOCKS
ltm rule irule_whitelist_SOCKS {
    when SOCKS_REQUEST {
    if { [class match [SOCKS::destination] ends_with SOCKS_whitelist] } {
        log -noname local6.notice "[virtual name]: SOCKS request from client at [IP::remote_addr] for host [SOCKS::destination] allowed"
        SOCKS::allowed 1
    } else {
        log -noname local6.warning "[virtual name]: SOCKS request from client at [IP::remote_addr] for host [SOCKS::destination] blocked"
        SOCKS::allowed 0
    }
}
}

admin@(vira231g4)(cfg-sync Standalone)(Active)(/Common)(tmos) list ltm profile socks
ltm profile socks self_SOCKS {
    app-service none
    default-connect-handling allow
    defaults-from socks
    dns-resolver self_DNS
    protocol-versions { socks4 socks4a socks5 }
    route-domain rd_internal
    tunnel-name socks-tunnel
}
ltm profile socks socks {
    app-service none
    default-connect-handling deny
    protocol-versions { socks4 socks4a socks5 }
    route-domain 0
    tunnel-name socks-tunnel
}


admin@(vira231g4)(cfg-sync Standalone)(Active)(/Common)(tmos) list ltm rule irule_log_SSL
ltm rule irule_log_SSL {
    when CLIENTSSL_CLIENTCERT {
    This event is triggered when LTM requests/requires a cert, even if the client doesn't present a cert.
    Check if client presented a cert after it was requested/required
   if {[SSL::cert count] > 0}{
       Client presented at least one cert.  The actual client cert should always be first.
       Loop through each cert and log the cert subject, issuer and serial number
      for {set i 0} {$i < [SSL::cert count]} {incr i}{
         log -noname local6.notice "[virtual name]: Client [IP::client_addr]:[TCP::client_port] SSL handshake: Received cert [expr {1 + $i}] of [SSL::cert count] - Subject: [X509::subject [SSL::cert $i]];\
         Issuer: [X509::issuer [SSL::cert $i]]; Serial: [X509::serial_number [SSL::cert $i]];"
      }
      set cert_error [X509::verify_cert_error_string [SSL::verify_result]]
      if { [info exists cert_error] } {
         if { not ([string tolower $cert_error] ends_with "ok") } {
            log -noname local6.error "[virtual name]: Client [IP::client_addr]:[TCP::client_port] SSL handshake failed: $cert_error"
         }
      }
   } else {
      log -noname local6.error "[virtual name]: Client [IP::client_addr]:[TCP::client_port] SSL handshake failed: Client did not provide a certificate"
   }
}
when CLIENTSSL_HANDSHAKE {
   log -noname local6.notice "[virtual name]: Client [IP::client_addr]:[TCP::client_port] SSL handshake successful: Session ID [SSL::sessionid]"
}
}

admin@(vira231g4)(cfg-sync Standalone)(Active)(/Common)(tmos) list ltm rule irule_self_SOCKS
ltm rule irule_self_SOCKS {
    when CLIENT_ACCEPTED {
   virtual /Common/vs_self_SOCKS
}
}

admin@(vira231g4)(cfg-sync Standalone)(Active)(/Common)(tmos) list net route-domain
net route-domain 0 {
    id 0
    vlans {
        http-tunnel
        socks-tunnel
        external
    }
}
net route-domain rd_internal {
    id 1
    strict disabled
    vlans {
        internal
    }
}

admin@(vira231g4)(cfg-sync Standalone)(Active)(/Common)(tmos) list net route
net route external_default_gateway {
    gw 11.12.13.225
    network default
}
net route internal_default_gateway {
    gw 10.239.127.33%1
    network default%1
}

admin@(vira231g4)(cfg-sync Standalone)(Active)(/Common)(tmos) list net self
net self 10.239.127.40 {
    address 10.239.127.40%1/27
    traffic-group traffic-group-local-only
    vlan internal
}
net self 11.12.13.226 {
    address 11.12.13.226/28
    traffic-group traffic-group-local-only
    vlan external
}

10 Replies

    • Brad_Parker_139's avatar
      Brad_Parker_139
      Icon for Nacreous rankNacreous
      You could try setting a variable and use that to set the nexthop in SERVER_CONNECTED. when SOCKS_REQUEST { if { [class match [SOCKS::destination] ends_with SOCKS_whitelist] } { log -noname local6.notice "[virtual name]: SOCKS request from client at [IP::remote_addr] for host [SOCKS::destination] allowed" set socksAllowed 1 SOCKS::allowed 1 } else { log -noname local6.warning "[virtual name]: SOCKS request from client at [IP::remote_addr] for host [SOCKS::destination] blocked" set socksAllowed 1 SOCKS::allowed 0 } } when SERVER_CONNECTED { if { $socksAllowed }{ nexthop destination } }
    • Brad_Parker's avatar
      Brad_Parker
      Icon for Cirrus rankCirrus
      You could try setting a variable and use that to set the nexthop in SERVER_CONNECTED. when SOCKS_REQUEST { if { [class match [SOCKS::destination] ends_with SOCKS_whitelist] } { log -noname local6.notice "[virtual name]: SOCKS request from client at [IP::remote_addr] for host [SOCKS::destination] allowed" set socksAllowed 1 SOCKS::allowed 1 } else { log -noname local6.warning "[virtual name]: SOCKS request from client at [IP::remote_addr] for host [SOCKS::destination] blocked" set socksAllowed 1 SOCKS::allowed 0 } } when SERVER_CONNECTED { if { $socksAllowed }{ nexthop destination } }
  • Thanks for the quick reply, Brad.

    I couldn't see a way to configure the next hop in my irule_whitelist_SOCKS iRule because

    nexthop
    isn't allowed inside a
    SOCKS_REQUEST
    event. Since I only want the
    nexthop
    to apply for connection requests from the SOCKS server, where would I apply it?

    Regards,

    Steve

  • Hi Brad,

    I removed the route domain I added earlier and restored all the other settings accordingly and confirmed the SOCKS function still worked as before. Then I tried your suggestion and a couple of variations including using the MAC address of my inside firewall's outside interface and including and excluding the vlan name with the IP address of the inside firewall's external interface, but the LTM always ignores the

    nexthop
    setting. I added some logging to see what's going on.

    when SOCKS_REQUEST {
    
        if { [class match [SOCKS::destination] ends_with SOCKS_whitelist] } {
            log -noname local6.notice "[virtual name]: SOCKS request from client at [IP::remote_addr] for host [SOCKS::destination] allowed"
            set socksAllowed 1
            SOCKS::allowed 1
        } else {
            log -noname local6.warning "[virtual name]: SOCKS request from client at [IP::remote_addr] for host [SOCKS::destination] blocked"
            set socksAllowed 1
            SOCKS::allowed 0
        }
        log -noname local6.warning "[virtual name]: In SOCKS_REQUEST event; nexthop = [LINK::nexthop name]; [LINK::nexthop]"
    }
    
    when SERVER_CONNECTED { 
        if { $socksAllowed }{ 
            nexthop internal 10.239.127.33 
            log -noname local6.warning "[virtual name]: In SERVER_CONNECTED event; nexthop = [LINK::nexthop name]; [LINK::nexthop]"
        } 
    }
    

    When inside the SOCKS_REQUEST event, the log shows (as I'd expect):

    /Common/vs_self_SOCKS: In SOCKS_REQUEST event; nexthop = unknown; ff:ff:ff:ff:ff:ff

    When inside the SERVER_CONNECTED event, after setting

    nexthop
    , the log shows:

    /Common/vs_self_SOCKS: In SERVER_CONNECTED event; nexthop = loopback; 00:01:4c:4f:4f:50

    The LTM still routes the traffic according to the routing table. In the case of a request for google.com, for example, that's out the external interface and the connection is successful.

    There seems to be something special about using the SOCKS service that disallows the use of

    nexthop
    .

    Regards,

    Steve

    • Brad_Parker's avatar
      Brad_Parker
      Icon for Cirrus rankCirrus
      Well that's a pain. Yeah the SOCKS events and command are very new and don't have much documentation at this time. You may want to try to open a case with support.
    • Steve_Magnuson_'s avatar
      Steve_Magnuson_
      Icon for Nimbostratus rankNimbostratus
      OK, will do. I'll add another comment if I'm able to come up with a solution with help from support. Regards, Steve
  • I think you need disable the "Default Connect Handling" (dont check) and create a vs that listening on the tunnel to handle the proxy connections, and then steer traffic on this listening vs.

     

  • Hi Steve, Can you please guide in SOCKS_Destination are you using destination IP address or dest domain names?