本帖最后由 江威 于 2017-3-31 17:19 编辑
1、背景介绍
Lotus Notes可以集成很多应用,在很多企业都作为办公OA系统,具有一定的普遍性,对于大型企业来说,办公OA系统会直接影响到职员的办公效率,可以部署多台Lotus Notes系统通过负载均衡的方式对外提供服务,一方面提高服务器的响应速度,另一方面可以提高扩展性,而对终端用户来说不需要修改服务器地址。
2、协议分析 Lotus Notes是IBM开发的一套办公软件,在访问其服务器时,数据包中会携带要访问的服务器IP地址,同时在数据包的头两个字节中表明此数据包的长度,服务器在收到客户端的数据包时会校验此数据包的合法性,具体可以见下图(第一张图中标记了服务器地址;第二张图中标记了数据包的长度,此图为7c):
3、解决方案 通过AD对Lotus Notes进行负载,需要对外修改为统一的VIP地址,那么必然导致服务器检查服务器IP地址这一部分不通过,因此,需要通过iPro脚本将其VIP地址修改为当前调度的节点IP地址,修改数据包之后可能造成数据包长度变化,需要一并修改,源码如下: - --[[
- Lotus Notes 应用负载,首个连接有协商,共2个数据包需要替换VIP
- --]]
- local rs = nil
- local packet = 1
- --调试
- function dbg(str)
- LOG.log(LOG.DEBUG, str)
- end
- event CLIENT_ACCEPT
- {
- dbg("CLIENT_ACCEPT")
-
- rs = pool("srv")
-
- if rs
- then
- dbg("sched ok, rs "..rs.ip..":"..rs.port)
- else
- dbg("ERROR: sched failed")
- TCP.close()
- end
-
- TCP.collect()
- }
- --处理第一个带VIP的包
- function deal_with_packet_1(data, st, ed)
- dbg("deal with packet 1")
-
- --首个字节为包总长度
- local total_len = string.byte(data, 1)
- local packet_len = total_len + 2
- --总长度差额
- local total_len_diff = 0;
-
- --新旧IP字符串长度
- local old_ip_len = ed - st + 1
- local new_ip_len = string.len(rs.ip)
- local len_diff = 0
-
- dbg("total_len: "..total_len)
- dbg("new ip len: "..new_ip_len..", old_ip_len: "..old_ip_len)
-
- len_diff = new_ip_len - old_ip_len
- total_len_diff = len_diff
- --若差额是奇数,考虑补位和总长度
- if total_len_diff % 2 ~= 0
- then
- --若最后一位是0
- if string.byte(data, packet_len) == 0
- then
- dbg("last byte == 0")
- --长度-1,去掉最后的0
- total_len_diff = total_len_diff - 1
- TCP.replace(packet_len, packet_len + 1, "")
-
- --若最后一位非0
- else
- dbg("last byte != 0")
- --长度+1,同时需要补位
- total_len_diff = total_len_diff + 1
- TCP.append(0)
- end
- end
-
- dbg("len_dif: "..len_diff..", data[5]: "..string.byte(data, 5)..", data[st - 2]: "..string.byte(data, st - 2))
- dbg("total_len_diff: "..total_len_diff)
-
- --替换为调度的服务器的IP
- TCP.replace(st, ed + 1, rs.ip)
-
- --替换data[5]和data[st - 2]位置的长度
- TCP.replace(5, 6, string.char(string.byte(data, 5) + len_diff))
- TCP.replace(st - 2, st - 1, string.char(string.byte(data, st - 2) + len_diff))
-
- --修改包总长度
- TCP.replace(1, 2, string.char(total_len + total_len_diff))
-
- dbg("deal with packet 1 finish")
- end
- --处理第二个带VIP的包
- function deal_with_packet_2(data, st, ed)
- dbg("deal with packet 2")
-
- --首个字节为包总长度
- local total_len = string.byte(data, 1)
- --总长度差额
- local total_len_diff = 0;
-
- --新旧IP字符串长度
- local old_ip_len = ed - st + 1
- local new_ip_len = string.len(rs.ip)
- local len_diff = 0
-
- dbg("total_len: "..total_len)
- dbg("new ip len: "..new_ip_len..", old_ip_len: "..old_ip_len)
- len_diff = new_ip_len - old_ip_len
- total_len_diff = len_diff
-
- dbg("len_dif: "..len_diff..", data[5]: "..string.byte(data, 5))
- dbg("total_len_diff: "..total_len_diff)
-
- --替换为调度的服务器的IP
- TCP.replace(st, ed + 1, rs.ip)
-
- --替换data[5]位置的长度
- TCP.replace(5, 6, string.char(string.byte(data, 5) + len_diff))
-
- --修改包总长度
- TCP.replace(1, 2, string.char(total_len + total_len_diff))
-
- dbg("deal with packet 2 finish")
- end
- event CLIENT_DATA
- {
- dbg("CLIENT_DATA")
-
- local data = TCP.payload()
-
- if not data
- then
- return 0
- end
-
- local st, ed = 0, 0
-
- local vip = TCP.localaddr()
-
- dbg("vip: "..vip)
-
- --查找VIP
- st, ed = string.find(data, vip, ed + 1)
-
- if not st
- then
- dbg("can't find vip "..vip)
-
- TCP.release()
- TCP.collect()
-
- return 0
- end
-
- if packet == 1
- then
- deal_with_packet_1(data, st, ed)
- --后面继续收集数据
- TCP.collect()
- elseif packet == 2
- then
- deal_with_packet_2(data, st, ed)
- --后面的包不再处理
- else
- dbg("ERROR: stop!")
- end
-
- dbg("finish, packet "..packet)
-
- packet = packet + 1
-
- TCP.release()
- }
复制代码
|