3-4-10-HAProxy高级功能与配置之HAProxy四七层负载

熊 0 阅读 Linux集群服务

haproxy可以通tcp-request /tcp-response 命令过滤调整四层报文。

1. tcp-request

1.1 tcp-request connection

  • 语法 : tcp-request connection <action> <options...> [ { if | unless } <condition> ] 。根据第4层的条件 , 对一个传入的连接执行一个动作

    defaults

    frontend

    listen

    backend

    yes(!)

    yes ✅

    yes ✅

    no ❌

    • <action> : 定义了在条件适用时要执行的行动。其中<action>支持以下指令

      • accept :这用于接受连接。不再评估进一步的“tcp-request connection”规则。

      • expect-netscaler-cip layer4 : 这配置了面向客户的连接 , 以便在从套接字中读取任何字节之前接收NetScaler客户IP插入协议头。 这相当于在 "bind"行上有 "accept-netscaler-cip"关键字 , 只是使用TCP规则允许只对使用ACL的某些IP地址范围接受PROXY协议。当多层负载均衡器被来自公共主机的流量通过时 , 这很方便。

      • expect-proxy layer4 : 这配置了面向客户的连接 , 以便在从套接字中读取任何字节之前接收一个PROXY协议头。这相当于在 "bind"行中使用 "accept-proxy"关键字 , 只是使用TCP规则允许PROXY协议只被接受用于使用ACL的某些IP地址范围。当多层负载均衡器被来自公共主机的流量通过时 , 这很方便。

      • reject : 这被用来拒绝该连接。没有进一步的 "tcp-request connection"规则被评估。被拒绝的连接甚至不会成为一个会话 , 这就是为什么它们在统计中作为 "被拒绝的连接 "被单独计算。它们不被考虑在会话速率限制中 , 也不被记录下来。原因是 , 这些规则应该只用于过滤极高的连接速率 , 例如在大规模DDoS攻击中遇到的连接。在这些极端条件下 ,记录每个事件的简单动作会使系统崩溃 , 并会大大降低过滤能力。如果绝对需要记录 , 那么应该使用 "tcp-request content"规则来代替 , 因为 "tcp-request session"规则也不会记录。

      • sc-inc-gpc(<idx>,<sc-id>)

      • sc-inc-gpc0(<sc-id>)

      • sc-inc-gpc1(<sc-id>)

        这些操作根据<sc-id>指定的粘性计数器来增加通用计数器。

      • sc-set-gpt(<idx>,<sc-id>) { <int> | <expr> }

      • sc-set-gpt0(<sc-id>) { <int> | <expr> }

        这些动作根据由< sc-id >指定的粘性计数器来设置32位无符号通用标签。

      • set-dst <expr>

      • set-dst-port <expr>

        这些操作用于将目的IP/端口地址设置为指定表达式的值。

      • set-mark <mark> : 在支持该操作的平台上 , 该操作用于将发送到hapaory后端服务器的所有数据包中的Netfilter/IPFW MARK设置为<mark>中传递的值。

      • set-src <expr>

      • set-src-port <expr>

        这些操作用于将源IP/端口地址设置为指定表达式的值。

      • set-tos <tos>

        在支持该功能的平台上 , 该功能用于将发送到haproxy后端服务器的数据包的TOS或DSCP字段值设置为<tos>中传递的值。

      • set-var(<var-name>[,<cond> ...]) <expr>

      • set-var-fmt(<var-name>[,<cond> ...]) <fmt>

        这是用来设置一个变量的内容。

      • silent-drop : 这将停止对规则的评估 , 并使用依赖于系统的方式使面向客户端的连接突然消失 , 该方式试图阻止通知客户端。

      • track-sc0 <key> [table <table>]

      • track-sc1 <key> [table <table>]

      • track-sc2 <key> [table <table>]

        这允许从当前连接跟踪粘性计数器。

      • unset-var(<var-name>) : 取消变量的设置

    • <condition> :是一个标准的基于第四层的ACL条件.

    在接受一个新的传入连接后 , 可以立即判断一些条件 , 以决定这个连接是否必须被接受或放弃 , 或对其计数器进行跟踪。这些条件不能利用任何数据内容 , 因为连接还没有被读取 , 缓冲区也还没有被分配。这被用来选择性地、非常快速地接受或放弃来自不同来源的连接 , 开销非常低。如果需要检查一些报文内容以作出决定 ,必须使用 "tcp-request content"语句来代替。

    “tcp-request connection"规则按其确切的声明顺序被评估。如果没有匹配的规则或没有规则 , 默认动作是接受传入的连接。对可以插入的规则的数量没有具体限制。任何规则后面都可以有一个基于ACL的条件 ,在这种情况下 , 只有当条件为真时才会被评估。

    每个实例的 "tcp-request connection"语句的数量没有限制。

    这个指令只适用于命名的defaults部分 , 而不是匿名的。在defaults部分定义的规则会在相关代理部分的规则之前被评估。为了避免歧义 , 在这种情况下 , 具有frontend功能的代理和具有backend功能的代理不能使用相同的default部分。这意味着一个listen部分不能使用定义了这种规则的default部分。

    注 : "if/unless "条件是可选的。如果没有在动作上设置条件 , 它就会无条件地执行。这对于 "track-sc*"动作 , 以及将默认动作改为拒绝。

示例

#接受来自白名单主机的所有连接 , 拒绝过快的连接而不计算在内并跟踪接受的连接。这导致连接率从滥用的来源被封顶。
tcp-request connection accept if { src -f /etc/haproxy/whitelist.lst }
tcp-request connection reject if { src_conn_rate gt 10 }
tcp-request connection track-sc0 src
​
#接受所有来自白名单主机的连接 , 计算所有其他连接 , 并拒绝速度太快的连接。这就导致了滥用程序只要不减速就会被屏蔽。
tcp-request connection accept if { src -f /etc/haproxy/whitelist.lst }
tcp-request connection track-sc0 src
tcp-request connection reject if { sc0_conn_rate gt 10 }
​
#为来自所有已知代理的流量启用代理协议。
tcp-request connection expect-proxy layer4 if { src -f proxies.lst }

1.2 tcp-request content

  • 语法 : tcp-request content <action> [{if | unless} <condition>]。根据第4-7层条件对新会话执行操作

    defaults

    frontend

    listen

    backend

    yes(!)

    yes ✅

    yes ✅

    no ❌

一个请求的内容可以在请求处理的早期阶段进行分析 , 称为 "TCP内容检查"。在这个阶段 , 每当请求内容更新时 , 基于ACL的规则就会被评估 , 直到 "accept"、"reject "或 "switch-mode"规则匹配 , 或者TCP请求检查延迟过期而没有匹配规则。

这些规则与 "tcp-request connection"规则的第一个区别是 , "tcp-request content"规则可以利用内容来进行决策。大多数情况下, 这些决定将考虑协议的识别或有效性。第二个区别是 , 基于内容的规则可以在frontend和backend使用。在HTTP与客户端保持连接的情况下 , 所有的tcp-request content规则都会被再次评估 ,所以HAProxy会记录 "tcp-request connection "与 "tcp-request content"规则分配了哪些粘性计数器 , 并在处理一个HTTP请求后刷新所有与内容相关的计数器 , 这样它们就可以被下一个请求的规则再次评估了。当规则跟踪一些L7信息或由基于L7的ACL作为条件时 , 这一点特别重要 ,因为跟踪可能在请求之间发生变化。

基于内容的规则是按照其确切的声明顺序进行评估的。如果没有匹配的规则或没有规则 , 默认动作是接受内容。对于可以插入的规则数量没有具体限制。

虽然没有任何强制规定 , 但建议在 "tcp-request connection"规则中使用track-sc0 , 在frontend的 "tcp-request content"规则中使用track-sc1 , 在backend的 "tcp-request content"规则中使用track-sc2 ,因为这使得配置更具可读性 , 更容易排除故障 , 但这只是一个指导原则 , 所有的计数器都可以到处使用。

这个指令只能从命名的defaults部分使用 , 而不是匿名的。在defaults部分定义的规则会在相关代理部分的规则之前被评估。为了避免歧义 , 在这种情况下 , 同一个defaults部分不能被具有frontend能力的代理和具有backend能力的代理所使用。这意味着一个listen部分不能使用定义这种规则的默认部分。

注意 , "if/unless "条件是可选的。如果没有在动作上设置条件 , 它就会无条件地执行。 这对 "track-sc*"行动以及将默认行动改为拒绝行动很有用。

还要注意的是 , 建议使用 "tcp-request session"规则来追踪那些不依赖第7层内容的信息 , 特别是对于HTTP前端。一些HTTP处理是在会话级别进行的 , 可能会导致请求的早期拒绝。因此 , 在这种情况下 , 对内容层的跟踪可能会受到干扰。在启动过程中会发出警告 , 以尽可能地防止这种不可靠的使用。

用TCP代理的 "tcp-content "规则来匹配第7层的内容是完全可能的 , 因为HTTP特定的ACL匹配能够在提取所需数据之前初步解析缓冲区的内容。如果缓冲区的内容没有被解析为有效的HTTP消息 , 那么ACL就不匹配。 这里涉及到的解析器与所有其他的HTTP处理完全相同, 所以不存在解析出不同内容的风险。在HTTP前端或HTTP后端 , 可以保证HTTP内容在规则被评估时总是立即出现 , 因为HTTP解析是在连接处理的早期阶段 , 在会话级别进行的。但是对于这样的代理 , 使用 "http-request"规则要自然得多 , 也更值得推荐。

追踪第7层的信息也是可能的 , 前提是这些信息在规则处理时是存在的。当需要追踪的数据还没有出现时 , 规则处理引擎能够等待 , 直到检查延迟过期。

示例

tcp-request content use-service lua.deny { src -f /etc/haproxy/blacklist.lst }
​
tcp-request content set-var(sess.my_var) src
tcp-request content set-var-fmt(sess.from) %[src]:%[src_port]
tcp-request content unset-var(sess.my_var2)
​
# Accept HTTP requests containing a Host header saying "example.com"
# and reject everything else. (Only works for HTTP/1 connections)
acl is_host_com hdr(Host) -i example.com
tcp-request inspect-delay 30s
tcp-request content accept if is_host_com
tcp-request content reject
​
# Accept HTTP requests containing a Host header saying "example.com"
# and reject everything else. (works for HTTP/1 and HTTP/2 connections)
acl is_host_com hdr(Host) -i example.com
tcp-request inspect-delay 5s
tcp-request switch-mode http if HTTP
tcp-request reject   # non-HTTP traffic is implicit here
...
http-request reject unless is_host_com
​
# reject SMTP connection if client speaks first
tcp-request inspect-delay 30s
acl content_present req.len gt 0
tcp-request content reject if content_present
​
# Forward HTTPS connection only if client speaks
tcp-request inspect-delay 30s
acl content_present req.len gt 0
tcp-request content accept if content_present
tcp-request content reject
​
# Track the last IP(stick-table type string) from X-Forwarded-For
tcp-request inspect-delay 10s
tcp-request content track-sc0 hdr(x-forwarded-for,-1)
# Or track the last IP(stick-table type ip|ipv6) from X-Forwarded-For
tcp-request content track-sc0 req.hdr_ip(x-forwarded-for,-1)
​
# track request counts per "base" (concatenation of Host+URL)
tcp-request inspect-delay 10s
tcp-request content track-sc0 base table req-rate
​
#Track per-frontend and per-backend counters, block abusers at the frontend when the backend detects abuse(and marks gpc0).
frontend http
    # Use General Purpose Counter 0 in SC0 as a global abuse counter
    # protecting all our sites
    stick-table type ip size 1m expire 5m store gpc0
    tcp-request connection track-sc0 src
    tcp-request connection reject if { sc0_get_gpc0 gt 0 }
    ...
    use_backend http_dynamic if { path_end .php }
​
backend http_dynamic
    # if a source makes too fast requests to this dynamic site (tracked
    # by SC1), block it globally in the frontend.
    stick-table type ip size 1m expire 5m store http_req_rate(10s)
    acl click_too_fast sc1_http_req_rate gt 10
    acl mark_as_abuser sc0_inc_gpc0(http) gt 0
    tcp-request content track-sc1 src
    tcp-request content reject if click_too_fast mark_as_abuser
  • tcp-requsest content accept [{ if | unless} <condition>] , 这被用来接受连接。对于当前部分 , 没有进一步的 "tcp-request content"规则被评估。

  • tcp-request content capture <sample> len <length> [ { if | unless} <condition>] , 这是从请求缓冲区捕获样本表达式<sample> , 并将其转换为最多<len>个字符的字符串。产生的字符串被存储到下一个请求的 "capture "槽中 , 所以它可能会出现在一些捕获的HTTP头旁边。然后 , 它将自动出现在日志中 , 并有可能使用取样规则将其提取出来 , 送入头信息或任何东西。考虑到在整个会话过程中 , 每次捕获都会被分配到这个尺寸 , 所以长度应该是有限的。

  • tcp-request content do-resolve(<var>,<resolvers>,[ipv4,ipv6]) <expr> , 这个动作对<expr>的输出进行DNS解析 , 并将结果存储在变量<var>中。请参考 "http-request do- resolve"以获得完整的描述。

  • tcp-request content reject [{ if | unless} <condition>] , 这被用来拒绝连接。没有进一步的 "tcp-request content " 规则被评估。

  • tcp-request content sc-inc-gpc(<idx>, <sc-id>) [ { if | unless } <condition> ]

  • tcp-request content sc-inc-gpc0(<sc-id>) [ {if | unless} <condition>]

  • tcp-request content sc-inc-gpc1(<sc-id>) [ {if | unless} <condition>]

    这些操作根据<sc-id>指定的粘性计数器增加通用计数器。完整说明请参考“http-request sc-inc-gpc”、“http-request sc-inc-gpc0”和“http-request sc-inc-gpc1”。

  • tcp-request content sc-set-gpt(<idx>,<sc-id>) { <int> | <expr>} [ {if | unless} <condition>]

  • tcp-request content sc-set-gpt0(<sc-id>) { <int> | <expr>} [ {if | unless} <condition>]

    这些操作根据 指定的粘性计数器设置32位无符号通用标记<sc-id>。

  • tcp-request content set-dst <expr> [ { if | unless} <condition>]

  • tcp-request content set-dst-port <expr> [ { if | unless} <condition>]

    这些操作用于将目标IP/端口地址设置为指定表达式的值。

  • tcp-request content set-log-level <level> [ { if | unless} <condition>]

    这个动作用于设置当前会话的日志级别。

  • tcp-request content set-mark <mark> [ { if | unless } <condition> ]

    此操作用于将发送到客户端的所有数据包中的Netfilter/IPFW标记设置为在<mark>支持它的平台上传入的值。

  • tcp-request content set-src <expr> [ { if | unless} <condition> ]

  • tcp-request content set-src-port <expr> [ { if | unless} <condition> ]

    这些操作用于将源IP/端口地址设置为指定表达式的值。

  • tcp-request content silent-drop [ { if | unless} <condition> ]

    这就停止了对规则的评估 , 并使用一种依赖于系统的方式使面向客户端的连接突然消失 , 试图防止客户端被通知。

  • tcp-request content track-sc0 <key> [table <table>] [ { if | unless} <condition> ]

  • tcp-request content track-sc1 <key> [table <table>] [ { if | unless} <condition> ]

  • tcp-request content track-sc2 <key> [table <table>] [ { if | unless} <condition> ]

    这样可以跟踪来自当前连接的粘性计数器。

  • tcp-request content unset-var(<var-name>) { if | unless} <condition> ]

    这是用来解除一个变量的设置。

  • tcp-request content set-var(<var-name>[,<cond> ...]) <expr> [ { if | unless } <condition> ]

  • tcp-request content set-var-fmt(<var-name>[,<cond> ...]) <fmt> [ { if | unless } <condition> ]

    这是用来设置一个变量的内容。该变量被声明为内联。

1.3 tcp-request inspect-delay

设置在内容检查过程中允许等待数据的最长时间

  • 语法 : tcp-request inspect-delay <timeout>

    defaults

    frontend

    listen

    backend

    yes(!)

    yes ✅

    yes ✅

    yes ✅

    <timeout> : 是默认以毫秒为单位指定的超时值,但如果数字以单位为后缀, 则可以是任何其他单位。

使用HAProxy主要作为TCP 负载均衡软件的人常常担心不经任何分析就把任何类型的协议传给服务器的风险。为了能够分析请求的内容 , 我们必须先扣留数据 , 然后再分析它们。这条语法只是实现了最多在指定时间内扣留数据。

当一个连接到达frontend时 , TCP内容检查很早就适用了, 然后当连接转发到backend时也很早就适用了。这意味着 , 如果一个连接都有tcp-request规则 , 它可能在frontend经历第一次延迟 , 在backend经历第二次延迟。

请注意 , 在执行内容检查时 , HAProxy将为每一个进入的新块评估整个规则 , 并考虑到这些数据是部分的事实。如果在上述延迟之前没有规则匹配 , 则在到期时进行最后一次检查 , 这次要考虑到内容是确定的。如果没有设置延迟 , HAProxy将根本不等待 , 而是立即根据现有的信息进行裁决。显然 , 这不太可能是非常有用的 , 甚至可能是饶舌的 , 所以不推荐这种设置。

一旦有规则匹配 , 请求就会被释放 , 并照常进行。如果达到超时且没有规则匹配 , 默认策略是让它不受影响地通过。

对于大多数协议来说 , 将其设置为几秒钟就足够了 , 因为大多数客户端在连接后立即发送全部请求。增加3秒或更多的时间来覆盖TCP重传 , 但这就是全部。对于某些协议 , 使用大的数值可能是有意义的 , 例如 , 确保客户机永远不会在服务器之前说话(如SMTP) ,或者等待客户机说话后再将数据传给服务器(如SSL)。

注意 , 客户端超时必须至少涵盖检查延迟 , 否则它将首先过期。如果客户端关闭了连接或者缓冲区满了 , 延迟就会立即过期 . 因为内容将无法再改变。

这个指令只在命名的defaults部分可用 ,而不是匿名的。代理从其默认值部分继承此值。

1.4 tcp-request session

根据第5层条件对已验证的会话执行操作

defaults

frontend

listen

backend

yes(!)

no ❌

yes ✅

no ❌

  • 语法 : tcp-request session <action> [{if | unless} <condition>]

    • <action> : 定义了在条件适用时要执行的行动, 需要的动作均和connection 中类似

    • <condition> : 是一个标准的基于5层的ACL条件, 主要是查看5.9.1.1章节中5层的筛选条件

这个指令只能从命名的defaults部分使用 , 而不是匿名的。在defaults部分定义的规则会在相关代理部分的规则之前被评估。为了避免歧义 , 在这种情况下 , 同一个defaults部分不能被具有frontend能力的代理和具有backend能力的代理所使用。这意味着一个listen部分不能使用定义这种规则的默认部分。

注意 , "if/unless "条件是可选的。如果没有在动作上设置条件 , 它就会无条件地执行。 这对 "track-sc*"行动以及将默认行动改为拒绝行动很有用。

tcp-request session accept if { src -f /etc/haproxy/whitelist.lst }
tcp-request session track-sc0 src
tcp-request session reject if { sc0_sess_rate gt 10 }

2. tcp-response

2.1 tcp-response content

根据第4-7层的条件 , 对会话响应执行一个动作

  • 语法 : tcp-response content <action> [{if | unless} <condition>]

    • <action> : 定义了在条件适用时要执行的行动,

    • <condition> : 是一个标准的基于4-7层的ACL条件, 主要是查看5.9.1.1章节中5层的筛选条件

defaults

frontend

listen

backend

yes(!)

no ❌

yes ✅

yes ✅

响应内容可以在响应处理的早期阶段进行分析 , 称为 "TCP内容检查"。在这个阶段 , 每次更新响应内容时都会评估基于ACL的规则 , 直到 "accept"、"close "或 "reject"规则匹配 , 或者TCP响应检查延迟被设置并在没有匹配规则的情况下过期。

大多数情况下 , 这些决定将考虑协议的识别或有效性。

基于内容的规则是按照其确切的声明顺序进行评估的。如果没有匹配的规则或没有规则 , 默认动作是接受内容。对可以插入的规则数量没有具体限制。

这个指令只能从命名的defaults部分使用 , 而不是匿名的。在defaults部分定义的规则会在相关代理部分的规则之前被评估。为了避免歧义 , 在这种情况下 , 同一个defaults部分不能被具有frontend能力的代理和具有backend能力的代理所使用。这意味着一个listen部分不能使用定义这种规则的默认部分。

注意 , "if/unless "条件是可选的。如果没有在动作上设置条件 , 它就会无条件地执行。 这对 "track-sc*"行动以及将默认行动改为拒绝行动很有用。

有几种类型的动作被支持。

用 "tcp-response content"规则来匹配第7层的内容是完全可能的 , 但重要的是要确保完整的响应已经被缓冲 , 否则没有内容会被匹配。为了实现这一点 , 最好的解决方案是在检查期间检测HTTP协议。

  • tcp-response content accept [ { if | unless } <condition> ], 这用于接受响应。不评估进一步的“tcp-response content”规则。

  • tcp-response content close [ { if | unless } <condition> ] , 这被用来立即关闭与服务器的连接。没有进一步的 "tcp-response content"规则被评估。这个动作的主要目的是强迫客户端和服务器之间的连接在交换后结束 , 此时应用进程协议预计会先经过一些长时间的超时。其目的是消除空闲的连接 , 这些连接在使用某些协议的服务器上占用大量资源。

  • tcp-response content reject [ { if | unless } <condition> ] , 这用于拒绝响应。不评估进一步的“tcp-response content reject”规则。

  • tcp-response content sc-inc-gpc(<idx>,<sc-id>) [ { if | unless } <condition> ]

  • tcp-response content sc-inc-gpc0(<sc-id>) [ { if | unless } <condition> ]

  • tcp-response content sc-inc-gpc1(<sc-id>) [ { if | unless } <condition> ]

    这些操作根据<sc-id>指定的粘性计数器来增加通用计数器。

  • tcp-response content sc-set-gpt(<idx>,<sc-id>) [ { if | unless } <condition> ]

  • tcp-response content sc-set-gpt0(<sc-id>) [ { if | unless } <condition> ]

    这些操作根据<sc-id>指定的粘性计数器设置32位无符号通用标签。

  • tcp-response content set-log-level <level> [ { if | unless } <condition> ]

    这个动作用于设置当前会话的日志级别。

  • tcp-response content set-mark <mark> [ { if | unless } <condition> ]

    在支持该操作的平台上 , 该操作用于将发送到客户端的所有数据包中的Netfilter/IPFW MARK设置为<mark>中传递的值。

  • tcp-response content set-var(<var-name>[,<cond>...]) <expr> [ { if | unless } <condition> ]

  • tcp-response content set-var-fmt(<var-name>[,<cond>...]) <fmt> [ { if | unless } <condition> ]

    这是用来设置一个变量的内容。该变量是内联声明的。

  • tcp-response content silent-drop [ { if | unless } <condition> ]

    这将停止对规则的评估 , 并使面向客户端的连接突然消失 , 使用依赖于系统的方式 , 该方式试图阻止客户端收到通知。

  • tcp-response content unset-var(<var-name>) [ { if | unless } <condition> ]

    这是用来解除一个变量的设置。

2.2 tcp-response inspect-delay

设置在内容检查期间等待响应的最大允许时间

defaults

frontend

listen

backend

yes(!)

no ❌

yes ✅

yes ✅

  • 语法 : tcp-response inspect-delay <timeout>

    • timeout : 是默认以毫秒为单位的超时值 , 但如果数字以单位为后缀 , 则可以是任何其他单位。

此指令仅从命名的默认值部分可用 , 而不能从匿名部分获得。代理从其默认值部分继承此值。

3. http-request

  • 语法 : http-request <action> [options...] [ { if | unless } <condition> ]

    第7层请求的访问控制

    defaults

    frontend

    listen

    backend

    yes(!)

    yes ✅

    yes ✅

    yes ✅

http-request语句定义了一组适用于第7层处理的规则。当这些规则在frontend、listen或backend部分得到满足时 , 将按照其声明顺序进行评估。任何规则后面都可以有一个基于ACL的条件 , 在这种情况下 , 只有当条件为真时才会被评估。

这条指令只适用于命名的defaults部分 , 而不是匿名的部分。在defaults部分定义的规则会在相关代理部分的规则之前被评估。为了避免歧义 , 在这种情况下 , 同一个defaults部分不能被具有frontend功能的代理和具有backend功能的代理所使用。这意味着一个listen部分不能使用定义了这种规则的default部分。

  • http-request add-acl (<file-name>) <key fmt> [ { if | unless } <condition> ]

    这是用来在ACL中添加一个新条目。ACL必须从一个文件(甚至是一个假的空文件)加载。要更新的ACL的文件名在括号中传递。它需要一个参数。<key fmt> ,它遵循日志格式规则 ,以收集新条目的内容。在插入之前, 它在ACL中进行查找 ,以避免重复(或更多)的值。这种查找是通过线性搜索来完成的 , 对于大的列表来说 , 这种查找可能是很昂贵的。它相当于统计套接字中的 "add acl"命令 , 但可以由一个HTTP请求触发。

  • http-request add-header <name> <fmt> [ { if | unless } <condition> ]

    这将附加一个HTTP header域中 , 其名称由<name>指定 , 其值由<fmt>定义 ,它遵循日志格式规则。这对于向服务器传递特定的连接信息(如客户端的SSL证书),或将几个头信息合并为一个头信息特别有用。这个规则不是最终的 ,所以可以添加其他类似的规则。请注意 ,头的添加是立即进行的 , 所以一个规则可能会重复使用前一个规则产生的头。

  • http-request allow [ { if | unless } <condition> ]

    这就停止了对规则的评估 , 让请求通过检查。

  • http-request auth [realm <realm>] [ { if | unless } <condition> ]

    这将停止对规则的评估 , 并立即响应HTTP 401或407错误代码 , 邀请用户出示有效的用户名和密码。没有进一步的 "http-request"规则被评估。支持一个可选的 "realm"参数 , 它设置了与响应一起返回的认证范围(通常是应用程序的名称)。

    相应的代理的错误信息被使用。它可以使用 "errorfile"或 "http-error "指令来定制。对于401响应 , 所有出现的WWW-Authenticate头都会被删除 , 并由一个新的头部信息取代 , 该头带有对域"<realm>"的基本认证挑战。对于407响应 , 对Proxy-Authenticate头也做同样的处理。如果错误信息必须不被改变 , 可以考虑使用 "http-request return"规则来代替。

    acl auth_ok http_auth_group(L1) G1
    http-request auth unless auth_ok
  • http-request capture <sample> [ len <length> | id <id> ] [ { if | unless } <condition> ]

    这是从请求缓冲区捕获样本表达式 , 并将其转换为最多个字符的字符串。产生的字符串被存储到下一个请求的 "capture "槽中 , 所以它可能会出现在一些捕获的HTTP头旁边。然后 , 它将自动出现在日志中 , 并有可能使用取样规则将其提取出来 , 送入头信息或任何东西。考虑到在整个会话过程中每次捕获都会分配到这个大小 , 所以长度应该是有限的。

    如果使用关键字 "id"而不是 "len" , 该动作会尝试将捕获的字符串存储在一个先前声明的捕获槽中。这对于在backend运行捕获是很有用的。槽的id可以由之前的指令 "http-request capture "或 "declaration capture"关键字来声明。

    当在backend使用这个动作时 , 请仔细检查相关的frontend是否有所需的capture槽 , 否则 , 这个规则在运行时将被忽略。由于HAProxy能够在运行时动态解析后端名称 , 这在配置解析时无法检测到。

  • http-request del-acl (<file-name>) <key fmt> [ { if | unless } <condition>]

    这是用来从一个ACL中删除一个条目。ACL必须从一个文件(甚至是一个假的空文件)加载。要更新的ACL的文件名在括号中传递。它需要一个参数 : <key fmt> , 它遵循日志格式规则 ,收集要删除的条目的内容。它相当于统计套接字中的 "del acl"命令 , 但可以由一个HTTP请求触发。

  • http-request del-header <name> [ -m <meth>] [ { if | unless } <condition>]

    这将删除所有HTTP头域 , 其名称在<name>中指定。<meth>是匹配方法 , 适用于头名称。支持的匹配方法有 "str"(精确匹配)、"beg"(前缀匹配)、"end"(后缀匹配)、"sub"(子串匹配)和 "reg"(正则匹配)。如果没有指定 , 则使用精确匹配方法。

  • http-request del-map(<file-name>) <key fmt> [ { if | unless } <condition> ]

    这是用来从一个MAP中删除一个条目。该MAP必须从一个文件(甚至是一个假的空文件)加载。要更新的MAP的文件名在括号中传递。

    <key fmt> , 它遵循日志格式规则 , 收集要删除的条目的内容。

    <file-name>, 它相当于统计套接字的 "del map"命令 , 但可以由HTTP请求触发。

  • http-request deny [deny_status <status>] [ { if | unless } <condition> ]

http-request deny [ { status | deny_status } <code>] [content-type <type>]          [ { default-errorfiles | errorfile <file> | errorfiles <name> |              file <file> | lf-file <file> | string <str> | lf-string <fmt> } ]          [ hdr <name> <fmt> ]*          [ { if | unless } <condition> ]

这将停止对规则的评估 , 并立即拒绝该请求。默认情况下 , 会返回一个HTTP 403错误。但可以使用与 "http-request return"规则相同的语法来定制响应。为兼容起见 , 当没有定义参数 , 或者只有 "deny_status"时 , 参数 "default-errorfiles"是隐含的。这意味着 "http-request deny [deny_status <status>]"是 "http-request deny [status <status>] default-errorfiles "的一个别名。没有进一步的 "http-request"规则被评估。

  • http-request disable-l7-retry [ { if | unless } <condition> ]

    如果请求因任何其他原因而失败 , 这将禁用任何重试请求的尝试 , 而不是连接失败。例如 , 这对于确保POST请求在失败时不被重试很有用。

  • http-request do-resolve (<var>,<resolvers>,[ipv4,ipv6]) <expr> [ { if | unless } <condition> ]

    此操作将执行 输出的 DNS 解析<expr> , 并将结果存储在变量<var>中。它使用 所指向的 DNS 解析进程部分<resolvers>。可以使用可选参数“ipv4”或“ipv6”来选择分辨率首选项。执行DNS解析时 ,客户端连接处于暂停状态 , 等待解析结束。如果可以找到IP地址 , 则会将其存储在<var>中。如果发生任何类型的错误 ,<var>则不设置。可以使用此操作在运行时根据在请求中找到的信息(即Host标头)发现服务器IP地址。如果此操作用于查找服务器的IP地址(使用“set-dst”操作) , 则后端中的服务器IP地址必须设置为0.0.0.0。do-resolve 操作采用仅主机参数 , 必须从字符串中删除任何端口。

  • http-request early-hint <name> <fmt> [ { if | unless } <condition> ]

    这用于在任何其他响应之前建立一个HTTP 103早期提示响应。这将在这个响应中附加一个HTTP头域 , 其名称由<name>指定 , 其值由<fmt>定义。这对于向客户端传递一些链接头以预加载渲染HTML文档所需的资源特别有用。

  • http-request normalize-uri <normalizer> [ { if | unless } <condition> ]

  • http-request normalize-uri fragment-encode [ { if | unless } <condition> ]

  • http-request normalize-uri fragment-strip [ { if | unless } <condition> ]

  • http-request normalize-uri path-merge-slashes [ { if | unless } <condition> ]

  • http-request normalize-uri path-strip-dot [ { if | unless } <condition> ]

  • http-request normalize-uri path-strip-dotdot [ full ][ { if | unless } <condition> ]

  • http-request normalize-uri percent-decode-unreserved [ strict ] [ { if | unless } <condition> ]

  • http-request normalize-uri percent-to-uppercase [ strict ] [ { if | unless } <condition> ]

  • http-request normalize-uri query-sort-by-name [ { if | unless } <condition> ]

    对请求的URI进行规范化处理。

    HAProxy 2.4中的URI规范化目前是作为一个实验性的技术预览。因此 , 它需要首先使用全局指令 "expose-experimental-directives"才能调用它。你应该做好准备 , 规范化器的行为可能会改变 , 以修复可能出现的问题 , 可能会破坏你的基础设施中正确的请求处理。

    每个规范化器都处理单一的规范化类型 , 以允许细粒度地选择适合于支持的后端的规范化水平。

    例如 , "path-strip-dotdot"规范化器可能对静态文件服务器很有用 , 它直接将请求的URI映射到本地文件系统中的路径。然而 , 它可能会破坏一个期望在路径中有特定数量段的API的路由。

    需要注意的是 , 一些规范化程序可能会导致不安全的URI转换。还有一种情况是 ,如果规范化器本身是安全的 , 那么在不适当的组合下 , 可能会导致不安全的转换。

    以下是可用的规范器。

    • fragment-encode :将 #编码为%23

      fragment-strip 是首选的。除非已知中断的客户端未能在在路径组件中正确编码“#”。

      - /#foo  -> /%23foo
    • fragment-strip : 删除uri中的fragment组件

      根据RFC 3986#3.5 , URI的 "fragment "部分不应该被发送 , 而是由用户代理在检索资源后处理。

      该规范化器应首先应用 , 以确保该片段不被解释为请求的路径组件的一部分。

      - /#foo  -> /
    • path-strip-dot : 删除 "path"组件中的"/./"段。

      包括百分比编码的点.("%2E")的片段将不会被检测到。如果不希望出现这种情况 , 请先使用 "percent-decode-unreserved"规范器。

      - /.            -> /
      - /./bar/       -> /bar/
      - /a/./a        -> /a/a
      - /.well-known/ -> /.well-known/ (no change)
    • path-strip-dotdot : 将 "path"组件中的"/.../"段规范化。

      这将试图访问父目录的段与它们前面的段合并。

      空的片段不会得到特殊处理。如果不希望这样 , 请先使用 "merge-slashes"规范化程序。

      包括百分比编码的点.("%2E")的片段将不会被检测到。如果不希望这样 , 请先使用 "percent-decode-unreserved "规范器。

      - /foo/../     -> /
      - /foo/../bar/ -> /bar/
      - /foo/bar/../ -> /foo/
      - /../bar/     -> /../bar/
      - /bar/../../  -> /../
      - /foo//../    -> /foo/
      - /foo/%2E%2E/ -> /foo/%2E%2E/

      如果指定了 "full "选项 , 那么开头的"../"也将被删除。

      - /../bar/     -> /bar/
      - /bar/../../  -> /
    • path-merge-slashes : 将 "path"组件中相邻的斜线合并为一条斜线。

      - //        -> /
      - /foo//bar -> /foo/bar
    • percent-decode-unreserved : 对未保留的百分比编码字符进行解码 , 使其作为常规字符表示

      未保留的字符集包括所有字母、所有数字、"-"、"."、"_"和"~"。

      - /%61dmin       -> /admin
      - /foo%3Fbar=baz -> /foo%3Fbar=baz (no change)
      - /%%36%36       -> /%66           (unsafe)
      - /%ZZ           -> /%ZZ

      如果指定了 "strict"选项 ,那么无效的序列将导致返回HTTP 400坏请求。

      - /%%36%36 -> HTTP 400
      - /%ZZ     -> HTTP 400
    • percent-to-uppercase : 百分比编码序列中的大写字母

      - /%6f -> /%6F
      - /%zz -> /%zz

      如果指定了 "strict"选项 ,那么无效的序列将导致返回HTTP 400坏请求。

      - /%zz -> HTTP 400
    • query-sort-by-name : 按参数名称对查询字符串的参数进行排序。假设参数以'&'为界。较短的名称在较长的名称之前排序 , 相同的参数名称保持其相对顺序。

      - /?c=3&a=1&b=2         -> /?a=1&b=2&c=3
      - /?aaa=3&a=1&aa=2      -> /?a=1&aa=2&aaa=3
      - /?a=3&b=4&a=1&b=5&a=2 -> /?a=3&a=1&a=2&b=4&b=5
  • http-request redirect <rule> [ { if | unless } <condition> ]

    这是基于重定向规则执行HTTP重定向。这与 "redirect"语句完全相同 , 只是它插入了一个可以在其他 "http-request"规则中间处理的重定向规则, 这些规则使用 "log-format"字符串。

  • http-request reject [ { if | unless} <condition> ]

    这将停止对规则的评估 , 并立即关闭连接而不发送任何响应。它的作用类似于 "tcp-request content reject"规则。在HTTP/2连接上强制立即关闭连接可能很有用。

  • http-request replace-header <name> <match-regex> <replace-fmt> [ { if | unless } <condition> ]

    这与<match-regex>匹配头域<name>的所有出现的值。匹配是在区分大小写的情况下进行的。匹配的值被<replace-fmt>完全替换。格式化字符在<replace-fmt>中是允许的 , 并且像"http-request add-header " 中的<fmt>参数一样工作。支持使用反斜杠('\')和数字的标准反向引用。

    这个动作作用于整个头文件行 , 不管它们可能包含多少个值。因此 , 它非常适用于处理在其值中自然包含逗号的头文件 , 如If-Modified-Since。包含逗号分隔的值列表的头文件 , 如Accept , 应该使用 "http-request replace-value" 来处理。

    http-request replace-header Cookie foo=([^;]*);(.*) foo=\1;ip=%bi;\2
    ​
    # applied to:
    Cookie: foo=foobar; expires=Tue, 14-Jun-2016 01:40:45 GMT;
    ​
    # outputs:
    Cookie: foo=foobar;ip=192.168.1.20; expires=Tue, 14-Jun-2016 01:40:45 GMT;
    ​
    # assuming the backend IP is 192.168.1.20
    ​
    http-request replace-header User-Agent curl foo
    ​
    # applied to:
    User-Agent: curl/7.47.0
    ​
    # outputs:
    User-Agent: foo
  • http-request replace-path <match-regex> <replace-fmt> [ { if | unless } <condition> ]

    它的工作原理与 "replace-header "类似 ,只是它对请求的path组件而不是header起作用。path组件从可选scheme+authority后的第一个'/'开始 , 在?前结束。因此 ,替换并不修改方案、授权和查询字符串。

    值得注意的是 , 正则表达式的评估损耗可能比某些ACL要高 , 所以罕见的替换可能得益于一个条件 , 即如果不匹配 , 就根本不执行评估。

    # prefix /foo : turn /bar?q=1 into /foo/bar?q=1 :
    http-request replace-path (.*) /foo\1
    ​
    # strip /foo : turn /foo/bar?q=1 into /bar?q=1
    http-request replace-path /foo/(.*) /\1
    # or more efficient if only some requests match :
    http-request replace-path /foo/(.*) /\1 if { url_beg /foo/ }
  • http-request replace-pathq <match-regex> <replace-fmt> [ { if | unless } <condition> ]

    这与 "http-request replace-path"的作用相同 , 只是path包含查询字符串(如果有的话)。因此 , path和query-string均会被替换。

    # suffix /foo : turn /bar?q=1 into /bar/foo?q=1 :
    http-request replace-pathq ([^?]*)(\?(.*))? \1/foo\2
  • http-request replace-uri <match-regex> <replace-fmt> [ { if | unless } <condition> ] `

    这与 "replace-header"的工作原理类似 , 只是它对请求的URI部分而不是header的部分起作用。URI部分可以包含一个可选的scheme、authority或query string。这些被认为是被匹配的值的一部分。

    值得注意的是 , 正则表达式的评估损耗可能比某些ACL要高 , 所以少见的替换可能会受益于一个条件 , 如果它不匹配 , 就根本不会执行评估。

    重要提示 : 在HTTP/1.x中 , 绝大多数浏览器发送的请求都使用 "origin form",这与 "absolute form" 不同 , 因为它们在URI部分不包含scheme或authority。大多数情况下 ,只有发送到代理机构的请求、手工伪造的请求和某些应用程序发出的请求使用绝对形式。因此 , 在HTTP/1.x中 , "replace-uri"通常在大多数时候都能正常工作 , 规则以"/"开头。但在HTTP/2中 鼓励客户只发送绝对URI , 这看起来像HTTP/1客户用来与代理对话的URI。这样的部分replace-uri规则在HTTP/2 中可能会失败 , 而在HTTP/1中是有效的。

    # rewrite all "http" absolute requests to "https":
    http-request replace-uri ^http://(.*) https://\1
    ​
    # prefix /foo : turn /bar?q=1 into /foo/bar?q=1 :
    http-request replace-uri ([^/:]*://[^/]*)?(.*) \1/foo\2
  • http-request replace-value <name> <match-regex> <replace-fmt> [ { if | unless } <condition> ]

    这与 "replace-header"的工作原理类似 , 只是它与标头字段 <name>的每一个逗号分隔的值而不是整个标头匹配。这适用于所有允许携带一个以上的值的头部信息。一个例子是Accept头。

    http-request replace-value X-Forwarded-For ^192\.168\.(.*)$ 172.16.\1
    ​
    # applied to:
    X-Forwarded-For: 192.168.10.1, 192.168.13.24, 10.0.0.37
    ​
    # outputs:
    X-Forwarded-For: 172.16.10.1, 172.16.13.24, 10.0.0.37
http-request return [status <code>] [content-type <type>]
          [ { default-errorfiles | errorfile <file> | errorfiles <name> |
              file <file> | lf-file <file> | string <str> | lf-string <fmt> } ]
          [ hdr <name> <fmt> ]*
          [ { if | unless } <condition> ]

这将停止对规则的评估 , 并立即返回一个响应。响应的默认状态代码是200。响应所使用的默认状态码是200。它可以作为 "status"的一个参数来指定。响应的内容类型也可以作为 "content-type"的一个参数来指定。最后 , 响应本身可以被定义。它可以是一个完整的HTTP响应 , 指定要使用的errorfile , 或者指定要使用的文件或字符串的响应有效载荷。这些规则是用来创建响应的。

  • 如果既没有定义errorfile , 也没有定义要使用的payload , 则返回一个虚拟响应。只有 "status" 参数被考虑。它可以是[200, 599]范围内的任何代码。如果有 "content-type " 参数 , 则被忽略。

  • 如果 "default-errorfiles"参数被设置 , 代理的errorfiles就被考虑。 如果定义了 "status "参数 , 它必须是HAProxy处理的状态代码之一(200, 400, 403, 404, 405, 408, 410, 413, 425, 429, 500, 501, 502, 503, 和 504)。如果有 "content-type "参数 , 则被忽略。

  • 如果使用“errorfile”参数定义了特定的错误文件 , 则返回包含完整 HTTP 响应的相应文件。仅考虑status参数。它必须是HAProxy处理的状态代码之一(200, 400, 403, 404, 405, 408,410, 413, 425, 429, 500, 501, 502, 503和 504)。如果有 "content-type"参数 , 则被忽略。

  • 如果定义了http-errors部分 , 并有 "errorfiles"参数 , 则返回指定的http-errors部分中的相应文件 , 包含完整的HTTP响应。只有 "status"参数被考虑。它必须是HAProxy处理的状态代码之一(200, 400, 403, 404, 405, 408,410, 413, 425, 429, 500, 501, 502, 503和 504)。如果有 "content-type"参数 , 则被忽略。

  • 如果指定了 "file"或 "lf-file"参数 , 该文件的内容被用作响应的有效载荷。如果文件不是空的 , 其内容类型必须作为参数设置为 "content-type"。否则 , 任何 "content-type"参数都被忽略。有了 "lf-file"参数 , 文件的内容被评估为一个日志格式的字符串。有了 "file "参数 , 它就被看作是一个原始内容。

  • 如果指定了 "string"或 "lf-string"参数 , 定义的字符串被用作响应的有效载荷。内容类型必须始终作为参数设置为 "content-type"。如果有 "lf-string"参数 , 则该字符串被评估为日志格式的字符串。有了 "string"参数, 它就被视为一个原始字符串。

当响应不是基于错误文件时 , 可以使用“hdr”参数将HTTP标头字段附加到响应中。否则 , 所有 "hdr "参数都会被忽略。对于每一个 , 标头名称在<name>中指定 ,其值由<fmt>定义 , 它遵循日志格式规则。

请注意 , 生成的响应必须小于缓冲区。并且为了避免任何警告 , 当加载错误文件或原始文件时 , 为标题重写保留的缓冲区空间也应该是空闲的。

http-request return errorfile /etc/haproxy/errorfiles/200.http \
    if { path /ping }
​
http-request return content-type image/x-icon file /var/www/favicon.ico  \
    if { path /favicon.ico }
​
http-request return status 403 content-type text/plain    \
    lf-string "Access denied. IP %[src] is blacklisted."  \
    if { src -f /etc/haproxy/blacklist.lst }
  • http-request sc-inc-gpc (<idx>,<sc-id>) [ { if | unless } <condition> ]

    这个动作使与<sc-id>指定的粘性计数器相关的数组的索引<idx>的通用计数器增加。如果发生错误 , 这个动作会默默地失败 , 然后继续进行动作评估。<idx>是0到99之间的整数 , <sc-id>是0到2之间的整数。如果在这个索引中没有存储GPC , 它也会默默地失败。

    这个动作只适用于'gpc'和'gpc_rate'数组数据类型(而不适用于传统的 'gpc0' 、'gpc1' 、'gpc0_rate' 或'gpc1_rate'数据类型)。

  • http-request sc-inc-gpc0(<sc-id>) [ { if | unless } <condition> ]

  • http-request sc-inc-gpc1(<sc-id>) [ { if | unless } <condition> ]

    这个动作根据<sc-id>指定的粘性计数器来增加GPC0或GPC1计数器。如果发生错误 ,这个动作会默默地失败 , 然后继续进行动作评估。

  • http-request sc-get-gpt (<idx>,<sc-id>) { <int> | <expr> } [ { if | unless } <condition> ]

    这个动作将与<sc-id>指定的粘性计数器相关的数组的索引<idx>处的32位无符号GPT设置为<int>/<expr>的值。预期结果是一个布尔值。

    如果发生错误 , 这个动作就会默默地失败 , 然后继续进行动作评估。<idx>是0到99之间的一个整数 , <sc-id>是0到2之间的一个整数。如果在这个索引中没有存储GPT , 它也会默默地失败。

    这个动作只适用于'gpt'阵列数据类型(而不是传统的'gpt0'数据类型)。

  • http-request sc-get-gpt0 (<sc-id>) { <int> | <expr> } [ { if | unless } <condition> ]

    此操作根据<sc-id>指定的粘性计数器和<int>/<expr>的值设置32位无符号GPT0标签。预期结果是一个布尔值。如果发生错误 , 这个动作就会默默地失败 , 动作评估继续进行。

  • http-requet set-dst <expr> [ { if | unless } <condition> ]

    这是用来将目标IP地址设置为指定表达式的值。当HAProxy前面的代理重写目标IP , 但在HTTP头中提供正确的IP时 ,或者你想掩盖IP以保护隐私时 , 这很有用。如果你想连接到新的地址/端口 , 在后端使用'0.0.0.0:0'作为服务器地址。

    • <expr> : 是一个标准的HAProxy表达式 , 由一个取样器和一些转换器组成。

    http-request set-dst hdr(x-dst)
    http-request set-dst dst,ipmask(24)

    在可能的情况下 , 只要地址族允许 , set-dst会保留原来的目的端口 , 否则目的端口会被设置为0。

  • http-request set-dst-port <expr> [ { if | unless } <condition> ]

    这用于将目标端口地址设置为指定表达式的值。如果你想连接到新的地址/端口 , 在后端使用'0.0.0.0:0'作为服务器地址。

    • <expr> : 是一个标准的HAProxy表达式 , 由一个取样器和一些转换器组成。

    http-request set-dst-port hdr(x-port)
    http-request set-dst-port int(4000)

    在可能的情况下 , 只要地址族支持端口 , set-dst-port就会保留原来的目的地址 , 否则就会在重写端口之前将目的地址强制为IPv4"0.0.0.0"。

  • http-request set-header <name> <fmt> [ { if | unless } <condition> ]

    这与 "http-request add-header"的作用相同 , 只是如果标头的名字存在的话 , 会首先将其删除。这在向服务器传递安全信息时非常有用 , 其中标头信息不能被外部用户操作。请注意 , 新的值是在删除之前计算的 , 所以有可能将一个值连接到一个现有的标头。

    http-request set-header X-Haproxy-Current-Date %T
    http-request set-header X-SSL                  %[ssl_fc]
    http-request set-header X-SSL-Session_ID       %[ssl_fc_session_id,hex]
    http-request set-header X-SSL-Client-Verify    %[ssl_c_verify]
    http-request set-header X-SSL-Client-DN        %{+Q}[ssl_c_s_dn]
    http-request set-header X-SSL-Client-CN        %{+Q}[ssl_c_s_dn(cn)]
    http-request set-header X-SSL-Issuer           %{+Q}[ssl_c_i_dn]
    http-request set-header X-SSL-Client-NotBefore %{+Q}[ssl_c_notbefore]
    http-request set-header X-SSL-Client-NotAfter  %{+Q}[ssl_c_notafter]
  • http-request set-log-level <level> [ { if | unless } <condition> ]

    这是用来改变当前请求的日志级别 , 当满足某个条件的时候。有效的级别是8个syslog级别(见 "log"关键字) , 加上特殊级别 "silent" , 它可以禁用此请求的日志记录。这个规则不是最终的 , 所以最后匹配的规则获胜。这个规则对于禁用来自另一个设备的健康检查很有用。

  • http-request set-map(<file-name>) <key fmt> <value fmt> [ { if | unless } <condition> ]

    这用于将新条目添加到MAP中。必须从文件(甚至是虚拟的空文件)加载MAP。要更新的MAP的文件名在括号之间传递。

    它需要2个参数: <key fmt> , 它遵循日志格式规则 , 用于收集MAP键 ; <value fmt> , 它遵循日志格式规则 ,用于收集新条目的内容。

    在插入之前 , 它在MAP中进行查找 , 以避免重复(或更多)的值。这种查找是通过线性搜索完成的 , 对于大的列表来说 ,这种查找可能损耗很大。它相当于来自stats套接字的“set map”命令 , 但可以由HTTP请求触发。

  • http-request set-mark <mark> [ { if | unless } <condition> ]

    这用于在支持的平台上将发送到客户端的所有数据包上的Netfilter/IPFW MARK设置为<mark>中传递的值。这个值是一个无符号的32位值, 可以被netfilter/ipfw和路由表匹配 , 或者通过DTrace监控数据包。它可以用十进制或十六进制格式表示(前缀为 "0x")。

    这对于强制某些数据包采用不同的路由是很有用的(例如批量下载时采用更便宜的网络路径)。这适用于Linux内核2.6.32及更高版本 , 并且需要管理员权限 , 在FreeBSD和OpenBSD上也是如此。

  • http-request set-path <fmt> [ { if | unless } <condition> ]

    这将用格式字符串<fmt>的评估结果重写请求路径。查询字符串(如果有)保持不变。如果在路径前发现了scheme和authority , 它们也会被保留下来。如果请求中没有路径("*") ,这个路径将被替换成格式。例如 , 这可以用来在路径前面预置一个目录组件。另见 "http-request set-query"和 "http-request set-uri"。

    # prepend the host name before the path
    http-request set-path /%[hdr(host)]%[path]
  • http-request set-pahtq <fmt> [ { if | unless } <condition> ]

    这与 "http-request set-path"的作用相同 , 只是query-string也被重写了。它可以用来删除查询字符串 , 包括问号(无法使用“http-request set-query”)。

  • http-request set-query <fmt> [ { if | unless } <condition> ]

    这将重写请求中出现在第一个问号("?")之后的查询字符串 ,其结果是对格式字符串<fmt>的评估。问号之前的部分保持原样。如果请求不包含问号 , 并且新值不是空的 , 那么就在URI的末尾添加一个问号 ,后面是新值。如果有一个问号 , 即使值是空的 , 也不会被删除。这可以用来从查询字符串中添加或删除参数。

    # replace "%3D" with "=" in the query string
    http-request set-query %[query,regsub(%3D,=,g)]

  • http-request set-src <expr> [ { if | unless } <condition> ]

    这是用来设置源IP地址到指定的表达式的值。当HAProxy前面的代理重写了源IP , 但在HTTP头中提供了正确的IP ;或者你想掩盖源IP以保护隐私时 , 这很有用。所有后续对 "src"取值的调用将返回这个值

    http-request set-src hdr(x-forwarded-for)
    http-request set-src src,ipmask(24)
    ​
    # 屏蔽后 , 这将根据IP地址跟踪连接 , 最后一个字节被清零。
    http-request track-sc0 src

    在可能的情况下 , 只要地址族允许 , set-src会保留原来的源端口 ,否则源端口会被设置为0。

  • http-request set-src-port <expr> [ { if | unless } <condition> ]

    这用于将源端口地址设置为指定表达式的值。

    http-request set-src-port hdr(x-port)
    http-request set-src-port int(4000)

    在可能的情况下 , 只要地址族支持端口 , set-src-port就会保留原始的源地址 , 否则就会在重写端口之前将源地址强制为IPv4 "0.0.0.0"。

  • http-request set-uri <fmt> [ { if | unless } <condition> ]

    这将用格式字符串<fmt>的评估结果重写请求URI。scheme, authority, pathandquery string都被一次性替换。这可用于重写代理前面的主机 , 或对URI执行复杂的修改 , 如移动路径和查询字符串之间的部分。

  • http-request silent-drop [ { if | unless } <condition> ]

    这就停止了对规则的评估 , 并使面向客户的连接突然消失 , 用一种依赖于系统的方式 , 试图防止客户被通知。

  • http-request strict-mode { on | off} [ { if | unless } <condition> ]

    这将启用或禁用以下规则的严格重写模式。它不影响在它之前声明的规则 , 它只适用于对请求进行重写的规则。当严格模式被启用时 , 任何重写失败都会触发一个内部错误。否则 , 这种错误会被默默地忽略。严格重写模式的目的是使某些重写成为可有可无的 , 而其他重写必须执行以继续处理请求。

    默认情况下 , 严格重写模式是启用的。当一个规则集的评估结束时 , 它的值也会被重置。因此 , 举例来说 , 如果你在前端改变了模式 , 当HAProxy开始后端规则评估时 , 就会恢复默认模式。

  • http-request tarpit [deny_status <status>] [ { if | unless } <condition> ]

http-request tarpit [ { status | deny_status } <code>] [content-type <type>]
          [ { default-errorfiles | errorfile <file> | errorfiles <name> |
              file <file> | lf-file <file> | string <str> | lf-string <fmt> } ]
          [ hdr <name> <fmt> ]*
          [ { if | unless } <condition> ]

这将停止对规则的评估 , 并立即阻止请求而不作出响应 , 延迟时间由 "timeout tarpit"或 "timeout connect"指定 , 如果前者未被设置。在该延迟之后 , 如果客户端仍在连接 , 就会返回一个响应 , 这样客户端就不会怀疑它已经被tarpitted了。

  • http-request track-sc0 <key> [table <table>] [ { if | unless } <condition> ]

  • http-request track-sc1 <key> [table <table>] [ { if | unless } <condition> ]

  • http-request track-sc2 <key> [table <table>] [ { if | unless } <condition> ]

    这可以跟踪来自当前请求的粘性计数器。这些规则不会停止评估 , 也不会更改默认操作。同一连接可同时追踪的计数器数量在构建时设置为MAX_SESS_STKCTR(在haproxy -vv中报告) , 默认为3, 所以track-sc数量在0和(MAX_SESS_STKCTR-1)之间。sc0计数器用于frontend部分 , 而sc1用于backend部分。

    • <key> : 是强制性的 , 是5.9.1.1节中描述的表达式规则样本。它描述了传入请求或连接的哪些元素将被分析、提取、组合 , 并用于选择更新计数器的表项。

    • <table> : 是一个可选的表 , 用来代替默认的表 , 也就是当前代理中声明的stick-table。然后 , 所有匹配的计数器和键的更新都将在该表中进行 , 直到会话结束。

    一旦执行了“track-sc*”规则 , 就会在表中查找键 , 如果找不到 , 则为其分配一个条目。然后 , 该条目的指针会在整个会话期间被保留下来, 并且该条目的计数器会尽可能频繁地被更新 , 每次会话的计数器被更新时 , 以及会话结束时都会系统地更新。计数器只对跟踪开始后发生的事件进行更新。作为一个例外 , 连接计数器和请求计数器会被系统地更新 , 以便它们反映有用的信息。

    如果条目跟踪并发连接计数器 , 则只要条目被跟踪 , 就会计算一个连接 , 并且该条目在此期间不会过期。与仅检查键相比 , 跟踪计数器还提供了性能优势 , 因为使用它的所有 ACL 检查只执行一次表查找。

  • http-request wait-for-handshake [ { if | unless } <condition> ]

    这将延迟请求的处理 , 直到 SSL 握手发生。这对于延迟处理早期数据非常有用 , 直到我们确定它们是有效的。

4. http-response

第7层响应的访问控制

defaults

frontend

listen

backend

yes(!)

yes ✅

yes ✅

yes ✅

  • 语法 : http-respons <action> <options...> [ { if | unless } <condition> ]

http-response语句定义了一组适用于第7层处理的规则。当这些规则在frontend、listen或backend部分得到满足时 , 将按照其声明顺序进行评估。任何规则后面都可以有一个基于ACL的条件 , 在这种情况下 , 只有当条件为真时才会被评估。由于这些规则适用于响应 , backend规则首先被应用 ,然后是frontend的规则。

这条指令只适用于命名的defaults部分 , 而不是匿名的部分。在defaults部分定义的规则会在相关代理部分的规则之前被评估。为了避免歧义 , 在这种情况下 , 同一个defaults部分不能被具有frontend功能的代理和具有backend功能的代理所使用。这意味着一个listen部分不能使用定义了这种规则的default部分。

  • http-response add-acl(<file-name>) <key fmt> [ { if | unless } <condition> ]

    这是用来在ACL中添加一个新条目。

  • http-response add-header <name> <fmt> [ { if | unless } <condition> ]

    这会附加一个HTTP标头字段。其名称由<name>指定 , 其值由<fmt>定义。

  • http-response allow [ { if | unless } <condition> ]

    这就停止了对规则的评估 , 让响应通过检查。

  • http-response capture <sample> id <id> [ { if | unless } <condition> ]

    这是从响应缓冲区中捕获样本表达式<sample> ,并将其转换为一个字符串。产生的字符串被存储到下一个请求的 "capture "槽中 , 所以它可能会出现在一些捕获的HTTP头旁边。然后 , 它将自动出现在日志中 , 并有可能使用样本获取规则将其提取出来 ,送入头信息或任何东西。请查看第5.9.1.1节(取样)和 "捕获响应头 "以了解更多信息。

    关键字 "id"是用于存储字符串的捕获槽的id。capture槽必须在一个相关的frontend中定义。这对于在backend运行捕获是很有用的。槽的id可以通过之前的指令 "http-response capture "或 "declaration capture"关键字来声明。

    当在backend使用这个动作时 ,请仔细检查相关的frontend是否有所需的捕获槽 , 否则 , 这个规则在运行时将被忽略。由于HAProxy能够在运行时动态解析backend名称 , 这在配置解析时无法检测到。

  • http-response del-acl(<file-name>) <key fmt> [ { if | unless } <condition> ]

    这是用来从ACL中删除一个条目。

  • http-response del-header <name> [ -m <meth> ] [ { if | unless } <condition> ]

    这将删除所有HTTP头域 , 其名称在<name>中指定。

  • http-response del-map(<file-name>) <key fmt> [ { if | unless } <condition> ]

    这用于从MAP 中删除条目。

  • http-response deny [deny_status <status> ] [ { if | unless } <condition> ]

http-response deny [ { status | deny_status } <code>] [content-type <type>]
          [ { default-errorfiles | errorfile <file> | errorfiles <name> |
              file <file> | lf-file <file> | string <str> | lf-string <fmt> } ]
          [ hdr <name> <fmt> ]*
          [ { if | unless } <condition> ]

这将停止对规则的评估 , 并立即拒绝响应。默认情况下 , 会返回一个HTTP 502错误。但可以使用与 "http-response return"规则相同的语法来定制响应。为兼容起见 , 当没有定义参数 , 或者只有 "deny_status"时 ,参数 "default-errorfiles"是隐含的。这意味着 "http-response deny [deny_status <status>]"是 "http-response deny [status <status>] default-errorfiles"的一个别名。没有进一步的 "http-response"规则被评估。

  • http-response redirect <rule> [ { if | unless } <condition> ]

    这将根据重定向规则执行HTTP重定向。这支持类似于“http-request redirect”规则的格式字符串 , 但响应中只有“location”类型的重定向是可能的。有关规则的语法 , 请参见“redirect”关键字。在响应期间应用重定向规则时 , 与服务器的连接将关闭 , 因此无法将数据从服务器转发到客户端。

  • http-response replace-header <name> <regex-match> <replace-fmt> [ { if | unless } <condition> ]

    这与 "http-request replace-header"的工作原理类似 ,只是它对服务器的响应而不是客户端的请求起作用。

    http-response replace-header Set-Cookie (C=[^;]*);(.*) \1;ip=%bi;\2
    ​
    # applied to:
    Set-Cookie: C=1; expires=Tue, 14-Jun-2016 01:40:45 GMT
    ​
    # outputs:
    Set-Cookie: C=1;ip=192.168.1.20; expires=Tue, 14-Jun-2016 01:40:45 GMT
    ​
    # assuming the backend IP is 192.168.1.20.

  • http-response replace-value <name> <regex-match> <replace-fmt> [ { if | unless } <condition> ]

    这与 "http-request replace-value"的工作原理类似 , 只是它对服务器的响应而不是客户端的请求起作用。

http-response return [status <code>] [content-type <type>]
          [ { default-errorfiles | errorfile <file> | errorfiles <name> |
              file <file> | lf-file <file> | string <str> | lf-string <fmt> } ]
          [ hdr <name> <value> ]*
          [ { if | unless } <condition> ]

这将停止对规则的评估 , 并立即返回一个响应。请参考 "http-request return"以获得完整的描述。没有进一步的 "http-response"规则被评估。

  • http-response sc-inc-gpc(<idx>,<sc-id>) [ { if | unless } <condition> ]

  • http-response sc-inc-gpc0(<sc-id>) [ { if | unless } <condition> ]

  • http-response sc-inc-gpc1(<sc-id>) [ { if | unless } <condition> ]

    这些操作根据 指定的粘性计数器增加通用计数器

  • http-response sc-set-gpt(<idx>,<sc-id>) { <int> | <expr> } [ { if | unless } <condition> ]

  • http-response sc-set-gpt0(<sc-id>) { <int> | <expr> } [ { if | unless } <condition> ]

  • http-response sc-set-gpt1(<sc-id>) { <int> | <expr> } [ { if | unless } <condition> ]

    这些操作根据<sc-id>指定的粘性计数器设置32位无符号通用标签。

  • http-response set-header <name> <fmt> [ { if | unless } <condition> ]

    这与“http-response add-header”的作用相同 , 只是如果标头名称存在 , 则首先将其删除。这在将安全信息传递给服务器时非常有用 , 其中标头不能被外部用户操作。

  • http-response set-log-level <level> [ { if | unless } <condition> ]

    这用于更改当前响应的日志级别。

  • http-response set-map (<file-name>) <key fmt> <value fmt>

    这用于将新条目添加到MAP中。完整描述请参考“http-request set-map”。

  • http-response set-mark <mark> [ { if | unless } <condition> ]

    这用于将新条目添加到MAP中。完整描述请参考“http-request set-map”。

  • http-response set-status <status> [reason <str>] [ { if | unless } <condition> ]

    这将用<status>替换响应状态代码 , 必须是100到999之间的整数。可以选择提供一个由<str>定义的自定义原因文本 , 或者使用指定代码的默认原因作为后备。

  • http-response silent-drop [ { if | unless } <condition> ]

    这就停止了对规则的评估 , 并使用一种依赖于系统的方式使面向客户端的连接突然消失, 试图防止客户端被通知。请参考 "http-request silent-drop"以获得完整的描述。

  • http-response strict-mode { on | off } [ { if | unless } <condition> ]

    这将启用或禁用以下规则的严格重写模式。

  • http-response track-sc0 <key> [table <table> ] [ { if | unless } <condition> ]

  • http-response track-sc1 <key> [table <table> ] [ { if | unless } <condition> ]

  • http-response track-sc2 <key> [table <table> ] [ { if | unless } <condition> ]

    这可以实现对当前连接的粘性计数器的跟踪。请参考 "http-request track-sc0"、"http-request track-sc1"和 "http-request track-sc2"的完整描述。