haproxy透传用户ip-方法和原理
参考URL: https://blog.csdn.net/frockee/article/details/78641188
为了透传用户ip到后端server, proxy机器需要解决两个问题:
1.在创建到后端server的套接字时, 将用户ip作为套接字的源ip,从而让后端server看到;
2.后端server在回包时, 能够将目的地为用户ip的回包,返回给proxy机器,而proxy机器能够将该包,从网卡驱动(链路层)收下来,并正确递交给应用层的haproxy进程
为了解决这两个问题,haproxy进程和所在机器需要做三个事情:
1.haproxy进程在创建到后端server的tcp套接字时,开启IP_TRANSPARENT选项, 并绑定用户ip为源ip;
2.后端server修改路由规则,将目的地为用户ip的回包,路由给proxy机器;
3.proxy机器在处理回包时, 在ip层, 由TProxy通过结合netfilter/iptables, 对该回包做一些小动作,将该回包的skb->sk = sk(sk为haproxy进程创建的对应套接字),从而让tcp层能够根据skb->sk, 将该回包递交给haroxy进程进行处理,最终返回给客户端
上传一个经典问题配置:
内网的客户机通过Linux主机连入Internet,而Linux主机与Internet连接时有两条线路,它们的网关如图所示。现要求对内网进行策略路由,所有通过TCP协议访问80端口的数据包都从ChinaNet线路出去,而所有访问UDP协议53号端口的数据包都从Cernet线路出去。
这是一个策略路由的问题,为了达到目的,在对数据包进行路由前,要先根据数据包的协议和目的端口给数据包做上一种标志,然后再指定相应规则,根据数据包的标志进行策略路由。为了给特定的数据包做上标志,需要使用mangle表,mangle表共有5条链,由于需要在路由选择前做标志,因此应该使用PREROUTING链,下面是具体的命令。
iptables -t mangle -A PREROUTING -i eth0 -p tcp --dport 80 -j MARK --set- mark 1 iptables -t mangle -A PREROUTING -i eth0 -p udp --dport 53 -j MARK --set- mark 2
ip rule add from all fwmark 1 table 10 ip rule add from all fwmark 2 table 20
以上两条命令表示所有标志是1的数据包使用路由表10进行路由,而所有标志是2的数据包使用路由表20进行路由。路由表10和20分别使用了ChinaNet和Cernet线路上的网关作为默认网关,具体设置命令如下所示
ip route add default via 10.10.1.1 dev eth1 table 10 ip route add default via 10.10.2.1 dev eth2 table 20
以上两条命令在路由表10和20上分别指定了10.10.1.1和10.10.2.1作为默认网关,它们分别位于ChinaNet和Cernet线路上。于是,使用路由表10的数据包将通过ChinaNet线路出去,而使用路由表20的数据包将通过Cernet线路出去
PS:iptables中的mangle
(修正)table 用于修改包的 IP 头。
例如,可以修改包的 TTL,增加或减少包可以经过的跳数。
这个 table 还可以对包打只在内核内有效的“标记”(internal kernel “mark”),后 续的 table 或工具处理的时候可以用到这些标记。标记不会修改包本身,只是在包的内核 表示上做标记。
上述说明了一个问题:
报文进入主机 过prerouteing的时候先过routing decide ;也就是先过netfilter框架在走路由;但是从本机发包时是先路由再走netfilter,如果走了netfilter后还需要过route
以udp 发包为例: udp 首先路由,找到出口, 然后封装ip 层报文, 执行 ip_local_out 发送报文此时会遇到LOCAL_OUTPUT netfilter 节点;最后执行dst_output 函数hook 也就是:ip_output
ip_route_output_flow->__ip_route_output_key->__mkroute_output,在__mkroute_output函数中设置rth->dst.output = ip_output;
ip_output中会执行NF_INET_POST_ROUTING(有的内核版本在POST ROUTing 前会执行一次重新路由,因为之前的LOCAL_OUT可能替换DIP,代码见nf_nat_local_fn 函数)最后到ip_finish_output 发送报文 根据arp neighbor 表项组装L2 ;然后调用dev_queue_xmit 发送到驱动;
目前遇到一个问题: 怎样直接更改内核协议栈 支持网桥模式和路由模式混合?