Jump to content
x
Upvote if you also have this question or find it interesting.
Learn more
Sign in to follow this  
Answered

Responder Policy Expressions

David Suchomel (XLS) | 0 | Members | 6 posts

Hopefully, someone can help me with this problem.  From what I thought would be a simple expression doesn't seem to work as expected, therefore I have been struggling for days trying to figure this one out. 

 

Here's my simple response policy

Obviously the names and address listed are fictitious...

 

HTTP.REQ.USER.IS_MEMBER_OF("TestDeny") && !CIP.EQUALS_ANY("allowip") || (HTTP.REQ.USER.IS_MEMBER_OF("TestDeny") && !CLIENT.IP.SRC.IN_SUBNET(10.0.0.0/24))

 

The first expression before the OR operator uses a pattern set of IP addresses "allowip" and AAA group of "TestDeny" which works without issue when the source IP has been added to the PATSET list. I would like to also check for a known allowed subnet and mask in the same response policy, but can't seem to get the next expression for CLIENT.IP.SRC.IN_SUBNET(10.0.0.0/24) to be evaluated correctly.

 

The policy action is set to show an HTML page with a JavaScript popup explaining the users access has been restricted, it then uses /cgi/logoff, and a custom logoff page to end their session.  This all works when creating separate responder policy for each of the expressions listed, or when removing one from existing expressions from the same policy. 

 

The problem begins when attempting to evaluate the second expression when combined with the or operator, it doesn't seem to want to validate the subnet. My guess is the first element returned "true" so it never looks at the next element in the expression.

 

My preference would be to have a defined subnet list such as the IP list in the same responder policy so that both are evaluated, but I can't seem to find the right get syntax to search for a subnet from a pattern list either. I tried creating an Advanced expression with the following to match on a list, that doesn't work either. 

 

CLIENT.IP.SRC.IN_SUBNET + ""

 

The ultimate end goal is to prevent members of a AAA group from connecting to the VIP when the source IP or subnet can not be found on a list, or within the policy while still allowing all other users to connect without any applied restrictions. I am sure this question has been asked and answered 1000 times over.

 

Any help or suggestions would be greatly appreciated.

 

 

Share this post


Link to post

11 answers to this question

Recommended Posts

x
Mark this reply as best answer, if it answered your question.
Learn more
x
Upvote if you found this answer helpful or interesting.
Learn more
Rhonda Rowland | Master | 1,062 | Members | 1,120 posts

David,

 

First - the logic is really tricky to get correct. Here and I kept switching between whitelist vs. blacklist and I messed it up a few times.  So, that's the first problem.  

 

Your second issue, is that this will get more and more complicated to maintain if you have to support multiple groups and or a changing list of IP whiltelists and Subnet whiltelists.  While patternsets and datasets will make these easier, for IP/Subnet whitelisting, eventually you might need to look at an HTTP Callout for the IP whitelisting or blacklisting functions. 

 

It depends on how many total entries you need to manage and how frequently it will change

 

===========

 

There are multiple expressions you can use depending on how many groups or user accounts you need to manage. 

 

First, off, lets make sure the condition you are looking for is what I think it is:

Your Original expression (with added parentheses) was this, but I don't think it did what you wanted it to do.

 

(HTTP.REQ.USER.IS_MEMBER_OF("TestDeny") && !CIP.EQUALS_ANY("allowip")) || (HTTP.REQ.USER.IS_MEMBER_OF("TestDeny") && !CLIENT.IP.SRC.IN_SUBNET(10.0.0.0/24))

 

My interpretations, is that what you are trying to do is BLOCK traffic, if a specific set of users connects from anywhere other than the allowed IP address list or the allowed subnets.  Other users should not be blocked, regardless of IP or subnet.

 

Basic clauses:

 

A:  user is in restricted list

B:  source ip is in IP White List

C:  source IP is in Subnet white List

 

The basic logic you could use, then should be: 

A && !(B && C)   (this is also the same as:  A && (!B || !C). 

So: if a good user logs in (A is False) and there is no need to look at the IP or subnet; policy never applies.

      If a bad user logs in (A is True), now it depends on their IP or Subnet.

      If the source IP is in either the IP whitelist or the subnet whitelist, then the second phrase !(B && C) is false; policy won't block.

     If the source IP is in neither whitelist, then the second phrase is TRUE and the policy will block (for badusers only).

 

If I misinterpreted your logic, you would need to adjust.

 

Next, For the A, B, and C statements above there are multiple ways you can do this.

Converting to text to use Patternsets or Datasets will make it easier if you need to match multiple user groups, IP Addresses, or Subnets. If you have a long list of IPs and Subnets that will constantly change, you might be better of with HTTP callouts.  But here are some expressions that should work:

 

Below syntax is using 11.1.51.26

 

For each clause, try the following:

A:  user is in restricted list aka "BadUsers"

Option 1:  (if just a single group):  http.req.user.is_member_of("BadGroup")

Option 2:  (use this to use a patternset, based on user login names instead of group memberships):  http.req.user.login_name.set_text_mode(ignorecase).equals_any("ps_users_denied")

 

 

B:  source ip is in IP White List.  

For multiple IP Addresses a Data Set can be a lot easier to support. But data set comparisons can only be used with strings:

client.ip.src.typecast_text_t.equals_any("data_iplist_allow")

 

 

C:  source IP is in Subnet white List

For Subnets, same trick, convert to text and then use a subnet data set:
client.IP.SRC.SUBNET(24).TYPECAST_TEXT_T.EQUALS_ANY("data_ipsubnet_allow")

 

Final Expression:

For my test contractor is a member BadUsers.

 

Option 1:

http.REQ.USER.IS_MEMBER_OF("BadUsers") && !(client.IP.SRC.TYPECAST_TEXT_T.EQUALS_ANY("data_iplist_allow") || client.IP.SRC.SUBNET(24).TYPECAST_TEXT_T.EQUALS_ANY("data_ipsubnet_allow"))

 

Option 2:

http.REQ.USER.LOGIN_NAME.SET_TEXT_MODE(ignorecase).EQUALS_ANY("ps_deniedusers") && !(client.IP.SRC.TYPECAST_TEXT_T.EQUALS_ANY("data_iplist_allow") || client.IP.SRC.SUBNET(24).TYPECAST_TEXT_T.EQUALS_ANY("data_ipsubnet_denied"))

 

 

Example Pattern and DataSets:

 

# User Login Name patternset, instead of Group comparison

add policy patset ps_deniedusers
bind policy patset ps_deniedusers contractor

 

# IP Whitelist dataset

add policy dataset data_iplist_allow ipv4
bind policy dataset data_iplist_allow 192.168.10.10
bind policy dataset data_iplist_allow 192.168.10.11
 

 

# Subnet Whitelist dataset
add policy dataset data_ipsubnet_allow ipv4
bind policy dataset data_ipsubnet_allow 192.168.10.0
bind policy dataset data_ipsubnet_allow 192.168.20.0
 

 

My test workstation had a 192.168.10.10 address. Contractor appeared in my BadUsers group or as a login in the denied users list.  I then tested, by removing the "good ip" and 'good subnet" from the whitelists and confirmed various combinations.

 

Example:

testadmin is not in bad list, and so was never blocked by the responder policy regardless of IP or Subnet.

Contractor is a member of the bad group, and therefore could only connect if the IP was in the allow list, subnet in allow list, or both were valid.  If neither the IP or subnet matched, the responder policy would block access.

Share this post


Link to post
x
Mark this reply as best answer, if it answered your question.
Learn more
x
Upvote if you found this answer helpful or interesting.
Learn more
Paul_Blitz | Virtuoso | 2,619 | Members | 4,378 posts

Netscaler policies do use shortcut evaluation:

 

- A or B : if A is TRUE, then it doesn't bother to evaluate B

- A and B : if A id FALSE, then it doesn't bother to evaluate B

 

If you want to use "pattern sets" but for IP's, take a look at DATA SETS

Share this post


Link to post
x
Mark this reply as best answer, if it answered your question.
Learn more
x
Upvote if you found this answer helpful or interesting.
Learn more
Rhonda Rowland | Master | 1,062 | Members | 1,120 posts

Try Paul's suggestion with the data set, but you may also be missing a set of parentheses for this to evaluate:

Original expression:

HTTP.REQ.USER.IS_MEMBER_OF("TestDeny") && !CIP.EQUALS_ANY("allowip") || (HTTP.REQ.USER.IS_MEMBER_OF("TestDeny") && !CLIENT.IP.SRC.IN_SUBNET(10.0.0.0/24))

 

Probably needs to be:

(HTTP.REQ.USER.IS_MEMBER_OF("TestDeny") && !CIP.EQUALS_ANY("allowip")) || (HTTP.REQ.USER.IS_MEMBER_OF("TestDeny") && !CLIENT.IP.SRC.IN_SUBNET(10.0.0.0/24))

 

So you can get an (A && !b ) || (C && !D) clause.  If the first phrase is true (A && !b ), then there will be no attempt to evaluate the second phrase (C && !D).  

Share this post


Link to post
x
Mark this reply as best answer, if it answered your question.
Learn more
x
Upvote if you found this answer helpful or interesting.
Learn more
David Suchomel (XLS) | 0 | Members | 6 posts

Thanks Paul, and Rhonda for your quick responses.

 

To be honest, I tried so many variations in an attempt to get this working, I can't remember if the expression was tested with the additional parentheses, but will certainly test it again this evening.

 

-Dave

Share this post


Link to post
x
Mark this reply as best answer, if it answered your question.
Learn more
x
Upvote if you found this answer helpful or interesting.
Learn more
David Suchomel (XLS) | 0 | Members | 6 posts

Paul,

 

Data Sets may provide more flexibility for what I'm looking for, would you mind showing me an example of the expression to pull from a pattern list that includes both IP and subnet addresses? I need to allow and block client networks when requested so adding from a list would be a better solution instead of pending a responder policy each time a change needs to be made.

 

 

List Example:

 

1.1.1.1.2 

17.30.0.0/17

2.2.2.5/24

2.2.2.2

3.3.3.3

10.0.0.10/24

Share this post


Link to post
x
Mark this reply as best answer, if it answered your question.
Learn more
x
Upvote if you found this answer helpful or interesting.
Learn more
David Suchomel (XLS) | 0 | Members | 6 posts

Rhonda,

 

This is absolutely what I was looking for, your interpretation is spot on and achieves the desired results. I'm sure others have run into this exact issue, so hopefully your efforts in solving my dilemma will also assist them with their troubleshooting.

 

I am responsible for multiple Citrix farms across geographic locations, along with managing and supporting several SDX appliances, so everyday is a new learning experience and challenge trying to keep up with our ever changing client requirements, thanks again for spending so much of your time on this problem.

 

-David

Share this post


Link to post
x
Mark this reply as best answer, if it answered your question.
Learn more
x
Upvote if you found this answer helpful or interesting.
Learn more
Rhonda Rowland | Master | 1,062 | Members | 1,120 posts

Watch out that if you do the user logins by patternset, it will be a case-sensitive comparison based on how they logon, so absolutely use the ignorecase flag, if not relying on the is_member_of method.

Share this post


Link to post
x
Mark this reply as best answer, if it answered your question.
Learn more
x
Upvote if you found this answer helpful or interesting.
Learn more
x
Mark this reply as best answer, if it answered your question.
Learn more
x
Upvote if you found this answer helpful or interesting.
Learn more
David Suchomel (XLS) | 0 | Members | 6 posts

Rhonda

 

Everything works perfectly now,  I ended up using DataSets instead of the Patterns. I think the missing piece of the responder syntax puzzle for me was converting to text which I should have tried from the beginning.

 

Thanks again for taking the time to review my issue, as well as the detailed explanation on how to resolve it.

Share this post


Link to post
x
Mark this reply as best answer, if it answered your question.
Learn more
x
Upvote if you found this answer helpful or interesting.
Learn more
skleine506 | 0 | CTP Member | 2 posts

Hi Rhonda, 

 

Great Insight, thanks so much for taking the time to get into detail on whitelisting with datasets/subnets above.  I am actually digging into this now and doing some testing. Hoping you could provide some additional guidance. 

 

Scenario: Whitelist with multiple IP blocks , all with different CIDR masks. 30 total.  would like to drop all  IPs NOT  specified in the whitelist.  This will be for an external facing VIP, so looking at responder policies. 

 

I see two ways to accomplish this, if there is a better way, or tweaking would love to know: 

 

1. Responder policy /w datasets - as you noted above this is a nice option, the difference in my scenario is 9 different CIDR masks across these IP Blocks. With that said, datasets don't let you apply the mask, seems this is done at the policy level as you noted above. So the solution from what I can see would be to group the datasets by subnet, so total of 9 datasets. Expression would be: CLIENT.IP.SRC.SUBNET(24).TYPECAST_TEXT_T.EQUALS_ANY("testing_IPSub24").NOT of course all others would swap out the 24, for additional CIDR masks.

 

2. Responder policy /w policy expressions - client.ip.src.in_subnet(172.16.5.0/25).NOT || client.ip.src.in_subnet(192.16.5.0/29).NOT-- Would be upwards of 30 expressions here, because they are all listed separate. 

 

As you noted as well, I have requests in to look at seeing if the list can be provided in a programatic way to allow for HTTP call out functionality to help with maintaining the whitelist.

 

Based on the information above - which option 1 or 2 would be more efficient, I personally feel the dataset route is more manageable. 

 

Any insight would be greatly appreciated! 

 

Thanks in advance! 

 

 

 

David,

 

First - the logic is really tricky to get correct. Here and I kept switching between whitelist vs. blacklist and I messed it up a few times.  So, that's the first problem.  

 

Your second issue, is that this will get more and more complicated to maintain if you have to support multiple groups and or a changing list of IP whiltelists and Subnet whiltelists.  While patternsets and datasets will make these easier, for IP/Subnet whitelisting, eventually you might need to look at an HTTP Callout for the IP whitelisting or blacklisting functions. 

 

It depends on how many total entries you need to manage and how frequently it will change

 

===========

 

There are multiple expressions you can use depending on how many groups or user accounts you need to manage. 

 

First, off, lets make sure the condition you are looking for is what I think it is:

Your Original expression (with added parentheses) was this, but I don't think it did what you wanted it to do.

 

(HTTP.REQ.USER.IS_MEMBER_OF("TestDeny") && !CIP.EQUALS_ANY("allowip")) || (HTTP.REQ.USER.IS_MEMBER_OF("TestDeny") && !CLIENT.IP.SRC.IN_SUBNET(10.0.0.0/24))

 

My interpretations, is that what you are trying to do is BLOCK traffic, if a specific set of users connects from anywhere other than the allowed IP address list or the allowed subnets.  Other users should not be blocked, regardless of IP or subnet.

 

Basic clauses:

 

A:  user is in restricted list

B:  source ip is in IP White List

C:  source IP is in Subnet white List

 

The basic logic you could use, then should be: 

A && !(B && C)   (this is also the same as:  A && (!B || !C). 

So: if a good user logs in (A is False) and there is no need to look at the IP or subnet; policy never applies.

      If a bad user logs in (A is True), now it depends on their IP or Subnet.

      If the source IP is in either the IP whitelist or the subnet whitelist, then the second phrase !(B && C) is false; policy won't block.

     If the source IP is in neither whitelist, then the second phrase is TRUE and the policy will block (for badusers only).

 

If I misinterpreted your logic, you would need to adjust.

 

Next, For the A, B, and C statements above there are multiple ways you can do this.

Converting to text to use Patternsets or Datasets will make it easier if you need to match multiple user groups, IP Addresses, or Subnets. If you have a long list of IPs and Subnets that will constantly change, you might be better of with HTTP callouts.  But here are some expressions that should work:

 

Below syntax is using 11.1.51.26

 

For each clause, try the following:

A:  user is in restricted list aka "BadUsers"

Option 1:  (if just a single group):  http.req.user.is_member_of("BadGroup")

Option 2:  (use this to use a patternset, based on user login names instead of group memberships):  http.req.user.login_name.set_text_mode(ignorecase).equals_any("ps_users_denied")

 

 

B:  source ip is in IP White List.  

For multiple IP Addresses a Data Set can be a lot easier to support. But data set comparisons can only be used with strings:

client.ip.src.typecast_text_t.equals_any("data_iplist_allow")

 

 

C:  source IP is in Subnet white List

For Subnets, same trick, convert to text and then use a subnet data set:
client.IP.SRC.SUBNET(24).TYPECAST_TEXT_T.EQUALS_ANY("data_ipsubnet_allow")

 

Final Expression:

For my test contractor is a member BadUsers.

 

Option 1:

http.REQ.USER.IS_MEMBER_OF("BadUsers") && !(client.IP.SRC.TYPECAST_TEXT_T.EQUALS_ANY("data_iplist_allow") || client.IP.SRC.SUBNET(24).TYPECAST_TEXT_T.EQUALS_ANY("data_ipsubnet_allow"))

 

Option 2:

http.REQ.USER.LOGIN_NAME.SET_TEXT_MODE(ignorecase).EQUALS_ANY("ps_deniedusers") && !(client.IP.SRC.TYPECAST_TEXT_T.EQUALS_ANY("data_iplist_allow") || client.IP.SRC.SUBNET(24).TYPECAST_TEXT_T.EQUALS_ANY("data_ipsubnet_denied"))

 

 

Example Pattern and DataSets:

 

# User Login Name patternset, instead of Group comparison

add policy patset ps_deniedusers
bind policy patset ps_deniedusers contractor

 

# IP Whitelist dataset

add policy dataset data_iplist_allow ipv4
bind policy dataset data_iplist_allow 192.168.10.10
bind policy dataset data_iplist_allow 192.168.10.11
 

 

# Subnet Whitelist dataset
add policy dataset data_ipsubnet_allow ipv4
bind policy dataset data_ipsubnet_allow 192.168.10.0
bind policy dataset data_ipsubnet_allow 192.168.20.0
 

 

My test workstation had a 192.168.10.10 address. Contractor appeared in my BadUsers group or as a login in the denied users list.  I then tested, by removing the "good ip" and 'good subnet" from the whitelists and confirmed various combinations.

 

Example:

testadmin is not in bad list, and so was never blocked by the responder policy regardless of IP or Subnet.

Contractor is a member of the bad group, and therefore could only connect if the IP was in the allow list, subnet in allow list, or both were valid.  If neither the IP or subnet matched, the responder policy would block access.

 

Share this post


Link to post

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
Sign in to follow this  
TOP
×
×
  • Create New...