Citrix ADC (NetScaler) 13: Pre-authenticating to TCP based services


photo by geralt (

last update: January 5th 2020

Recently I had to find a solution to block all connections to a TCP based service (SSH, TCP port 22), except of connections from IP addresses that pr-eauthenticated using a AAA vServer. This is something, most firewalls can do, but a Citrix ADC / NetScaler can’t.

Ok, it can do, or would you think, I’ll write a blog about me failing? (cross fingers: I never fail πŸ™‚ ) So: this is something, most firewalls can do, and a NetScaler also can do. Unfortunately it’s not a built in functionality.

The idea

There is nothing easier than dropping connection attempts: We need a responder policy, action DROP. Why drop? Because it’s silent. A reset would be something you would see doing a port scan. A drop not. You could tell me, it’s security by obscurity. My answer would be: Why not?

An other thing about drop: They don’t drop existing connections, instead they simply drop all TCP SYNC packets coming in. Therefore, an existing connection is not affected by a drop policy.

So we have a responder policy dropping all connection attempts to a certain vServer on our Citrix ADC / NetScaler. But we also need to be able to allow connections, if a user authenticated successfully. That’s a bit more difficult. I spent some time thinking about that subject. My solution: I could store the IP address of a user in a Citrix ADC / NetScaler variable. If someone connects, the responder policy would check, weather this variable contains this user’s IP address, or not.

The server used for SSH would be a Citrix ADC / NetScaler lb-vServer, the server used for authentication would be a Citrix ADC / NetScaler CS vServer with an AAA bound to it. This article is not about the AAA part, it’s just about opening the port πŸ™‚

Some built in services, like RDP, don’t allow using responder policies. You have to use TCP instead.

1st part of the solution: Seting the variable

The cs-vServer

The cs-vServer is quite simple, it may be either of type HTTP or SSL. Mine is HTTP, as it is easier to debug. I could have used a lb-vServer instead, but different to cs-vServers, lb-vServers are down if you don’t bind services to it.

add cs vserver cs_vsrv_openPort HTTP 80 -cltTimeout 180 -AuthenticationHost -Authentication ON -authnVsName aaa_vServer

Creating the Citrix ADC / NetScaler variable

add ns variable VAR_DONT_BLOCK -type ulong -expires 120
This will create the variable giving 120 seconds (2 minutes) of time to users to start the application. Of course you may change this timeout value, depending on your needs.

Assigning an IP address to this variable

add ns assignment assign_IP -variable "$VAR_DONT_BLOCK" -set CLIENT.IP.SRC

This will assign client’s IP to this variable.

The Citrix ADC / NetScaler responder policy

add responder policy res_pol_openFirewall true assign_IP
The point of this policy seems obvious: Its action is the assignment, so the variable gets assigned as soon as this policy is hit.

Binding the policy

bind lb vserver cs_vsrv_openPort -policyName res_pol_openFirewall -priority 100 -gotoPriorityExpression END -type REQUEST

The SSH vServer you want togrant access too

creating the service

add service svc_tcp_ssh TCP 22
( is the IP address of the SSL server)

creating the lb-vServer

add lb vserver lb_vsrv_tcp_ssh TCP 22
bind lb vserver lb_vsrv_tcp_ssh svc_tcp_ssh

The responder policy

add responder policy res_pol_drop_unauthenticated "CLIENT.IP.SRC.EQ($VAR_DONT_BLOCK).NOT" DROP
A Responder policy with action drop won’t kill an existing connection, instead it won’t allow new connections. Therefore we can use the built in action drop. The condition is hit, if client’s IP address is not stored in our variable.

bind lb vserver lb_vsrv_tcp_ssh -policyName res_pol_drop_unauthenticated -priority 100 -gotoPriorityExpression END -type REQUEST
binds our policy to the Citrix ADC / NetScaler vServer.

Remaining problems (Problems I didn’t have to solve)

My solution allows just 1 client to log on at a time. This was sufficient as my customer just wanted to grant administrative access from outside. (However it would allow an unlimited ammount of established connections)
Instead of using a variable I could have used an array of variables. This would have allowed to store several IPs.

An other drawack: There is no visible success message.

Feel free to post your thoughts and concerns. I’d be happy to answer your questions!

About the author

Johannes Norz

Johannes Norz is a Citrix Certified Citrix Technology Advocate (CTA), Citrix Certified Instructor (CCI) and Citrix Certified Expert on Application Delivery and Security.

He frequently works for Citrix international Consulting Services and several education centres all around the globe.


  • Hi Johannes,

    very inventive solution πŸ™‚

    I do have one question related to packet flow. If user (probably some administrator) wants to start putty towards service protected by NS. First it should probably hit CS with AAA bound to it, right? AAA and CS in your case are both HTTP 80. How do you redirect traffic from HTTP based CS to TCP based service once authenticated as you cannot have TCP LB behind HTTP CS (or there is some ‘secret magic ingredient in the recipe’?

    Thank you very much,

    • Great to see you like it! I don’t. This is something, the admin has to do himself (it’s mainly for Admins).

      So (s)he has to go to the logon point via SSL, log on, then start putty and connect. I would agree, this is not possible for Jennifer Superblond-Secretary, however, something a helpdesk guy would be able to do easily.

By Johannes Norz

Recent Posts

Recent Comments