Learn F5 Technologies, Get Answers & Share Community Solutions Join DevCentral

Filter by:
  • Solution
  • Technology
Answers

iRule redirect via Geolocation

I'm looking to implement an iRule that leverages geolocation to redirect certain traffic from specific states. Since we leverage a CDN, I will need to use the X-Forwarded-For field for the incoming IP addresses. Below is my 1st attempt at the iRule. Will this work with the BigIP's Quova module?

when CLIENT_ACCEPTED {
  if { !(([whereis [HTTP::header values "X-Forwarded-For"] abbrev] equals "MO") or ([whereis [HTTP::header values "X-Forwarded-For"] abbrev] equals "IL")) } {
    HTTP::redirect "http://www.example.com/
  }
}
1
Rate this Question

Answers to this Question

placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
Hi zbirmingham,

There might be multiple XFF headers or multiple XFF values in a single header. And keep in mind that a client can insert any XFF value they want. With those in mind, how would you want to handle the XFF values if there are more than one?

Can you have the CDN change the name of the header they insert in their requests to something that isn't X-Forwarded-For? This would lower the chance of another proxy inserting a header with the same name (but not lower the chance that a malicious user could spoof their own header value to bypass your iRule logic).

If you move the code from the CLIENT_ACCEPTED event to the HTTP_REQUEST event, it would work if there is just one XFF value. But it would be better to use a switch statement so you're only running the whereis command once instead of twice.

Aaron
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
We are asking our CDN if they can change the name of the header. Looks like they can, so say if they change this header to "Client-IP", how would I construct this iRule using HTTP_REQUEST?

We are also not concerned with clients inserting their own values for XFF.
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
You can use an iRule like this then:

when HTTP_REQUEST {

	# Parse the client IP from the CDN header
	set client_ip [HTTP::header value "Client-IP"]
	if { $client_ip eq "" }{
		set redirect 1
	} else {
		switch [whereis $client_ip abbrev] {
			"MO" -
			"IL" {
				# Do nothing and allow the request
				set redirect 0
			}
			default {
				# Redirect all others
				set redirect 1
			}
		}
	}

	if {$redirect}{
		HTTP::redirect "http://www.example.com/
	}
}


Aaron
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
Note in the above example, I've set it so client requests without the Client-IP header will be redirected. How would you want to handle these requests? Would you want to look up the actual client IP instead? If so, you can try this:




when HTTP_REQUEST {

	# Parse the client IP from the CDN header
	set client_ip [HTTP::header value "Client-IP"]
	if { $client_ip eq "" }{
		# The header was empty/did not exist, so use the actual client IP
		set client_ip [IP::client_addr]
	}
	switch [whereis $client_ip abbrev] {
		"MO" -
		"IL" {
			# Do nothing and allow the request
		}
		default {
			# Redirect all others
			HTTP::redirect "http://www.example.com/
		}
	}
}


Aaron
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
I guess I need to test this 1st to see what I want to do with requests that don't have this header set. I have copied what you have above and changed it so it will only pick up on a certain URI. It will also display the state you are in if you are not MO or IL.

If I want it to lookup the client I and i can use this:

 when HTTP_REQUEST {
if { ([string tolower [HTTP::uri]] starts_with "/testingpage") } {
    # Parse the client IP from the CDN header
    set client_ip [HTTP::header value "Client-IP"]
    if { $client_ip eq "" }{
        # The header was empty/did not exist, so use the actual client IP
        set client_ip [IP::client_addr]
    }
    switch [whereis $client_ip abbrev] {
        "MO" -
        "IL" {
            HTTP::respond 200 content "Your IP IS from MO or IL"
        }
        default {
           set state [whereis $client_ip abbrev]
           HTTP::respond 200 content "Your IP IS NOT MO or IL you are $state"
        }
    }
}
} 


0