背景:积累常见irule


1. 友好界面

背景:客户要求需要在停机更新或者系统出故障时进行页面提示【系统维护中】 F5判断系统各节点是否存活 如果全部不存活就跳到指定提示页面 如果至少一台就不用跳转到提示页面,正常进行负载。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
when HTTP_REQUEST {
if { [ active_members test_pool ]==0 } {
HTTP::respond 200 content {
<html>
<head>
<title>维护界面</title>
</head>
<body>
界面维护中!!!
</body>
</html>
}
}
}

2. 基于源地址负载均衡

背景:并配置负载均衡算法为基于源地址负载均衡算法,将192.168.11.0/24的IP地址访问分配给服务器A,将192.168.12.0/24的IP地址访问分配给服务器B。

1
2
3
4
5
6
7
8
9
10
11
when HTTP_REQUEST {
if { [IP::addr [IP::client_addr] equals 192.168.11.0/24] }{
pool pool_A member 211.136.2.11 80
} elseif { [IP::addr [IP::client_addr] equals 192.168.12.0/24] } {
pool pool_A member 211.136.2.12 80
}
}
when LB_FAILED {
log local0. "src_shibai"
LB::reselect pool pool_A
}

3. 基于URI负载均衡

示例一:配置负载均衡算法为基于http uri请求内容的负载均衡算法,将请求URL中含有“test1”的发送给服务器A,将请求URL中含有“test2”的发送给服务器B。

1
2
3
4
5
6
7
8
9
10
11
12
when HTTP_REQUEST {
set url [HTTP::uri]
if { ([string match {*test1*} $url]) & ([active_members pool_A]==1)} {
pool pool_A
log local0.info "[HTTP::uri] -- pool_A"
} elseif { ([string match {*test2*} $url]) & ([active_members pool_B]==1)} {
pool pool_B
log local0.info "[HTTP::uri] -- POOL_B"
} else {
pool pool_default
}
}

示例二:配置负载均衡算法为基于http uri请求内容的负载均衡算法,如果URI中以“test1”开始开始,则把流量发送给pool_A,如果以其他字段开头,则拒绝接受流量。

1
2
3
4
5
6
7
when HTTP_REQUEST {
if { [HTTP::uri] starts_with "/test" } {
pool pool_A
}else {
reject
}
}

4. 基于客户端浏览器负载均衡

背景:配置负载均衡算法为基于HTTP Header信息的负载均衡算法,按照HTTP请求的Header中User-Agent类型(包含终端或浏览器等信息)进行负载均衡,将匹配User-Agent类型为Chrome的发送给服务器组A,将匹配User-Agent类型Firefox发送给服务器组B,其它HTTP请求发送给服务器组C。

1
2
3
4
5
6
7
when HTTP_REQUEST {
if { [HTTP::header User-Agent] contains "Chrome" } {
pool pool_A }
elseif { [HTTP::header User-Agent] contains "Firefox" } {
pool pool_B }
else { pool pool_C }
}

5. http头部插入字段

背景:需要在http头部插入字段。

1
2
3
4
5
6
7
when HTTP_REQUEST {
HTTP::header insert "CLIENT_ORG_IP" [IP::client_addr]
if { [HTTP::header CLIENT_ORG_IP] contains [IP::client_addr] } {
log local0. "ok"
}
HTTP::header insert "CLIENT_ORG_PORT" [TCP::client_port]
}

6. 流量通过F5访问流程

背景:通过Irule查看流量地址信息

1
2
3
4
5
6
7
when SERVER_CONNECTED {
log local0.info "
client connection from [IP::client_addr]:[TCP::client_port]
access to [clientside {IP::local_addr}]:[clientside {TCP::local_port}]
Snat to [IP::local_addr]:[TCP::local_port]
TO server [IP::server_addr]:[TCP::server_port]"
}

7. DNS解析

背景:在本地GTM进行A记录域名解析,当客户端来本地访问AAAA记录信息时,则去另外的GTM进行AAAA地址解析。再把解析结果返回给客户端。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
when DNS_REQUEST {
switch [string toupper [DNS::question type]] {
"AAAA" {
pool v6_dns
}
"MX" {
pool v6_dns
}
"TXT" {
pool v6_dns
}
}
}
when DNS_RESPONSE {
if {([DNS::header rcode] equals "NXDOMAIN") or ([DNS::header rcode] equals "REFUSED") }{
DNS::header rcode NOERROR
}
}

8. 基于域名的出向选路规则

1. 当接收DNS流量时,配置出向dns请求。如果请求域名以date_group中配置的域名结尾,则去pool_dns_test去进行域名解析,否则去pool_dns_default中进行域名解析。

1
2
3
4
5
6
7
8
when DNS_REQUEST {
if {[class match [DNS::question name] ends_with data_group] } {
#log local0. "client =[IP::client_addr] NXDOMAIN111 question name: [DNS::question name]"
pool pool_dns_test
}else {
pool pool_dns_default
}
}

2. 当收到DNS响应时,如果请求的域名在domain_test中,就把A记录或者AAAA记录以及对应的域名存储在test_table表中。

1
2
3
4
5
6
7
8
9
when DNS_RESPONSE {   	
if { ([DNS::question type] eq "A") or ([DNS::question type] eq "AAAA") } {
if {[class match [DNS::question name] contains domain_test] } {
set rrs [DNS::answer]
foreach rr $rrs {
table set -subtable "test_teble" [DNS::rdata $rr] [DNS::question name]
}
}
}

3. 配置出向选路,如果出向访问的IP在test_teble表中,则出向流量走pool_test,否则出向流量走Default_pool。注意:设备配置在出口位置,还需要把地址转换为公网地址。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
when CLIENT_ACCEPTED {
if { [table lookup -subtable "test_teble" [IP::local_addr] ] != "" } {
pool pool_test
}else {
pool Default_pool
}
}
when LB_SELECTED {
if { [IP::addr [LB::server addr] equals 1.1.1.1]} {
snatpool snat_test
}else {
snat automap
}
}

9. 清空http uri

背景:清除http uri。

1
2
3
when HTTP_REQUEST {
HTTP::uri "/"
}

10. 一个vs运行http和https

背景:客户需要使用同一个vs,接收并处理https和http业务请求。
实现方式:配置https虚拟服务并配置证书,配置irule,https用户使用特定网段正常负载转发,http用户关闭ssl profile并负载转发

1
2
3
4
5
6
7
8
when CLIENT_ACCEPTED {
if { [IP::addr [IP::client_addr] equals 192.168.10.0/24 ] } {
pool test_side_2
} else {
SSL::disable clientside
pool test_side_1
}
}

11. 多条策略使用switch命中规则案例

1
2
3
4
5
6
7
8
9
10
11
12
13
when CLIENT_ACCEPTED {
switch [string toupper [IP::client_addr]] {
"10.252.149.11" {
snatpool sp_10.252.255.11
}
"10.252.149.12" {
snatpool sp_10.252.255.12
}
"default" {
drop
}
}
}

12. irule 防止x-forwarded-for 攻击

1
2
3
4
5
6
7
8
9
10
11
12
13
when HTTP_REQUEST {
set xff 0
foreach x [HTTP::header names] {
if { [string tolower $x] equals "x-forwarded-for" } {
set xff 1
HTTP::header remove $x
HTTP::header insert X-FORWARDED-FOR [IP::client_addr]
}
}
if { $xff == 0 } {
HTTP::header insert X-FORWARDED-FOR [IP::client_addr]
}
}

13. https业务指定源地址迁移

1
2
3
4
5
6
7
8
when CLIENT_ACCEPTED {
if { [IP::addr [IP::client_addr] equals 111.20.119.234/32 ] }{
pool pool_159_443
} else {
SSL::disable serverside
pool g_KHDQ3_VSMobileJieru_01
}
}

14. http uri 替换

1
2
3
4
5
6
7
For Example:

Original HTTP Request
https://www.yourdomain.test/public/page/login.html

New HTTP Request
https://www.yourdomain.test/private/page/login.html

方式一: Using String Map : 字符串映射会将 URI 中找到的键字符串的每个实例替换为新值。

1
2
3
4
5
6
when HTTP_REQUEST {
if {[HTTP::uri] starts_with "/public/"} {
HTTP::uri [string map {"/public/" "/private/"}[HTTP::uri]]
pool pool_web
}
}

方式二:Using RegSub : (不带 -all 选项)将仅将 URI 中找到的密钥字符串的第一个实例替换为新值。

1
2
3
4
5
6
7
8
when HTTP_REQUEST {
if {[HTTP::uri] starts_with "/public/"} {
if { [regsub -nocase /public/ [HTTP::uri] /private/ new_uri] > 0 } {
HTTP::uri $new_uri
}
pool pool_web
}
}

15、允许指定Host访问vs

方式一:指定 IP

1
2
3
4
5
when HTTP_REQUEST {
if { [HTTP::host] != "192.168.10.96" } {
reject
}
}

方式二:指定域名

1
2
3
4
5
when HTTP_REQUEST {
if {not ([string tolower [HTTP::host]] starts_with "link.it.10086.cn")}{
reject
}
}

方式三:使用data group

1
2
3
4
5
when HTTP_REQUEST {
if {not [class match [HTTP::host] equals host_reject ]}{
reject
}
}

方式四:使用data group和正则匹配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
when HTTP_REQUEST {
if {[string tolower [HTTP::host]] ends_with host_reject } {
pool test_side_1
}
elseif {[string tolower [HTTP::host]] matches_regex {^ec\.it\.10086\.cn$}} {
pool test_side_1
}
elseif {[class match [HTTP::host] equals host_reject1 ]} {
pool test_side_1
}
else{
reject
}
}

16、根据edns客户端地址的最后一段奇偶性选择pool

1
2
3
4
5
6
7
8
9
10
11
when DNS_REQUEST {
if { [DNS::edns0 exists] } {
set endip [string tolower [getfield [DNS::edns0 subnet address] "." 4]]
if { [expr $endip % 2] == 0}{
pool a.com
}
else {
pool b.com
}
}
}