F5 bigip自11.5.0版本后增加了socks profile的支持,即可以利用LTM提供socks4,4a以及socks5的服务。socks位于OSI模型的会话层上,可以透明的为TCP或UDP提供中转代理服务。
[title]socks profile配置项含义[/title]
protocol versions:选择需要支持的协议版本,可以为4,4a,5,默认则全部支持
DNS resolver:一个需要提前在网络部分配置好的resolver(只需配置resolver,无需配置系统级的DNS IP),以提供4a,5版本对访问目标地址为域名时的代理解析支持。即address type=domain,例如:
1 2 3 4 5 6 7 |
Socks Protocol Version: 5 Command: Connect (1) Reserved: 0 Address Type: Domain Name (3) Remote name: www.myf5.net Port: 443 |
抓包范例:立即下载
Route domain:指LTM代理发起新连接时,新连接所走网络应该处于的route domain。
Tunnel name: 指LTM发起的代理新连接处于哪个tunnel里,所以如果需要额外VS来处理LTM发起的代理新连接,则这个额外的VS应该监听在这里指定的tunnel上
Default Connect handling: 指明发起的代理新连接是否需要额外的VS来处理,勾选表示无需额外VS,不勾选表示需要额外VS。 注意:即便勾选时,如果相应tunnel有可以处理代理连接的额外VS,则这些额外VS还是会接管这些流量(即一旦tunnel有额外vs能处理这些代理连接,则是否勾选都会有一样的行为)。
利用将代理连接交给额外的VS处理,可以实现对代理连接的进一步控制和处理,例如实现代理连接走指定线路出去等。
另外,对于配置socks profile的VS,其中的目的地址和目的端口转换选项必须保持勾选状态。
[title]不同配置组合下的行为[/title]
enable Default Connect Handling + tunnel内无可转发流量vs + socks VS无snat = 无法代理访问立即下载
enable Default Connect Handling + tunnel内无可转发流量vs + socks VS有snat = 可以代理访问,访问源地址是socks vs的SNAT地址. 此时route-domain设置无效。立即下载
enable Default Connect Handling + tunnel内有可转发流量vs + socks VS无snat = 可以代理访问,访问源地址去往可转发流量vs的时候使用原始客户端地址,经过转发vs后按转发vs规则处理立即下载
enable Default Connect Handling + tunnel内有可转发流量vs + socks VS有snat = 可以代理访问,访问源地址去往可转发流量vs的时候使用SNAT后的地址,经过转发vs后按转发vs规则处理立即下载
disable Default Connect Handling + tunnel内无可转发流量vs + socks VS有snat = 无法代理访问
disable Default Connect Handling + tunnel内无可转发流量vs + socks VS无snat = 无法代理访问
disable Default Connect Handling + tunnel内有可转发流量vs + socks VS无snat = 可以代理访问,访问源地址去往可转发流量vs的时候使用原始客户端地址,经过转发vs后按转发vs规则处理
disable Default Connect Handling + tunnel内有可转发流量vs + socks VS有snat = 可以代理访问,访问源地址去往可转发流量vs的时候使用原始客户端地址,经过转发vs后按转发vs规则处理
[title]socks irule[/title]
目前支持三个socks命令:
SOCKS::allowed 返回控制状态或设置控制是否容许使用socks
SOCKS::destination 返回或设置代理连接的目标域名/IP/port,例如:
1 2 3 4 5 6 7 8 9 10 |
when SOCKS_REQUEST { log local0. "[SOCKS::destination host]" } Aug 3 15:46:30 ltm3900 info tmm[10394]: Rule /Common/socks_irule <SOCKS_REQUEST>: www.myf5.net Aug 3 15:46:30 ltm3900 info tmm3[10394]: Rule /Common/socks_irule <SOCKS_REQUEST>: s22.cnzz.com Aug 3 15:46:31 ltm3900 info tmm[10394]: Rule /Common/socks_irule <SOCKS_REQUEST>: z1.cnzz.com Aug 3 15:46:31 ltm3900 info tmm1[10394]: Rule /Common/socks_irule <SOCKS_REQUEST>: c.cnzz.com Aug 3 15:46:31 ltm3900 info tmm2[10394]: Rule /Common/socks_irule <SOCKS_REQUEST>: z1.cnzz.com Aug 3 15:46:31 ltm3900 info tmm3[10394]: Rule /Common/socks_irule <SOCKS_REQUEST>: cnzz.mmstat.co |
SOCKS::version 返回连接所用的版本
一个事件:
SOCKS_REQUEST 事件在socks连接发起到验证前被触发
[title]udp associate穿透[/title]
目前还不支持UDP的穿透(ID591610),在特定环境下,可以使用irule来模拟解决(需使用V12.1.2HF1以上版本.ID641360)
配置一个前端vs(不关联socks profile),关联以下irule。 然后该vs通过virtual 命令引导vs处理后的流量到真实的socks vs vs_proxy_real_sock上
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
when RULE_INIT { # Set your own UDP vs IP and port set static::UDP_PROXY_IP "10.*.*.*" set static::UDP_PROXY_PORT 10000 } when CLIENT_ACCEPTED { set authenticated 0 virtual vs_proxy_real_sock TCP::collect } when CLIENT_DATA { set cdata [TCP::payload] set clen [TCP::payload length] log local0. "Client payload length: ${clen}" if { ${authenticated} == 0 } { binary scan ${cdata} ccc version count method0 if { ![info exists version] || ${version} != 5 || ![info exists count] || ${count} < 1 || ![info exists method0] || ${method0} != 0 } { log local0. "Unknown first packet; bypass processing" TCP::release return } else { incr authenticated binary scan ${cdata} H* hexcdata log local0. "Authentication packet detected: ${hexcdata}" } } else { set cursor 0 binary scan ${cdata} cc version command incr cursor 2 if { ![info exists version] || ${version} != 5 || ![info exists command] || ${command} != 3 } { log local0. "Command is not UdpAssociate <${command}>; bypass processing" TCP::release return } else { binary scan ${cdata} x${cursor}cc reserved atype incr cursor 2 if { [info exists reserved] && [info exists atype] && ${atype} == 1 } { binary scan ${cdata} x${cursor}ccccS a1 a2 a3 a4 port incr cursor 6 if { [info exists a1] && [info exists a2] && [info exists a3] && [info exists a4] && [info exists port] } { set a1 [expr {${a1} & 0xff}] set a2 [expr {${a2} & 0xff}] set a3 [expr {${a3} & 0xff}] set a4 [expr {${a4} & 0xff}] set port [expr {${port} & 0xffff}] log local0. "UDP client: ${a1}.${a2}.${a3}.${a4}:${port}" TCP::payload replace 0 ${clen} "" set t1 [getfield ${static::UDP_PROXY_IP} "." 1] set t2 [getfield ${static::UDP_PROXY_IP} "." 2] set t3 [getfield ${static::UDP_PROXY_IP} "." 3] set t4 [getfield ${static::UDP_PROXY_IP} "." 4] TCP::respond [binary format ccccccccS 5 0 0 1 ${t1} ${t2} ${t3} ${t4} ${static::UDP_PROXY_PORT}] return } } TCP::payload replace 0 0 ${authprefix} TCP::release return } } TCP::release TCP::collect } when LB_SELECTED { log local0. "LB_SELECTED" } |
在UDP vs上关联:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
when CLIENT_ACCEPTED { set cdata [UDP::payload] set clen [UDP::payload length] set cursor 0 binary scan ${cdata} SccccccS reserved frag atype a1 a2 a3 a4 port incr cursor 10 if { [info exists reserved] && [info exists frag] && [info exists atype] && [info exists a1] && [info exists a2] && [info exists a3] && [info exists a4] && [info exists port] } { if { ${atype} == 1 } { # Only handle IPv4 in this iRule # Normalize the scanned numbers set a1 [expr {${a1} & 0xff}] set a2 [expr {${a2} & 0xff}] set a3 [expr {${a3} & 0xff}] set a4 [expr {${a4} & 0xff}] set port [expr {${port} & 0xffff}] log local0. "UDP destination: ${a1}.${a2}.${a3}.${a4}:${port}" binary scan ${cdata} x${cursor}a* actual_data if { [info exists actual_data] } { binary scan ${cdata} a${cursor} cheader log local0. "Actual data size: [string length ${actual_data}]" UDP::payload replace 0 0 ${actual_data} UDP::payload replace [string length ${actual_data}] ${clen} "" <<<<<<<<<<<< ${clen} should not the correct length. log local0. "UDP payload size after modification: [UDP::payload length]" <<<<<<< Look at the log messages, always the same as before modification! #node "${a1}.${a2}.${a3}.${a4}:${port}" node ${a1}.${a2}.${a3}.${a4} ${port} } else { log local0. "No data is found; packet dropped" drop } } } } when LB_SELECTED { log local0. "LB_SELECTED" } when CLIENT_DATA { log local0. "CLIENT_DATA" } when SERVER_CONNECTED { log local0. "SERVER_CONNECTED" } when SERVER_DATA { log local0. "SERVER_DATA" if { [info exists cheader] } { UDP::payload replace 0 0 ${cheader} log local0. "Response size after modification: [UDP::payload length]" } } |
需要注意,上述两个vs(关联socks profile的tcp,udp)是两个完全独立的连接,根据socks协议规范,tcp和udp两个连接是伴生关系,因此注意tcp vs的idle timeout不要过早的删除连接导致udp跟着断开.
[title]BIND连接方法[/title]
不支持,以下测试服务器未返回消息
(echo -ne "\x05\x01\x00"; sleep 1; echo -ne "\x05\x02\x00\x01\xb8\x18\x62\x62\x00\x50";sleep 1;) | nc ip 1080
[title]socks服务代理验证[/title]
待更新
文章评论