ATS的回环检测是通过判断本机ip是否出现在请求头中的Via头来实现。


Machine::Machine(char const* the_hostname, sockaddr const* addr):函数初始化了本机的入口ip。


如果没有配置proxy.local.incoming_ip_to_bind,这个函数第二个参数是地址存的值是一个空的sockaddr结构体。函数调用了getifaddrs,这个api可以获取系统所有的网络接口信息,存到一个ifaddrs结构体中,这个机构体是一个链表结构,每一个节点都是一个网络接口,由一个for循环依次分析么一个节点。

如果getifaddrs调用成功了,初始化一个枚举结构体,枚举包括五个变量,分别代表:无效,回环,不可分配地址,广播,全球唯一地址。顺序很重要,越靠后数值越大,优先级越高,越有可能成为incoming ip。有三个变量(spot_type,ip4_type,ip6_type),其中spot_type将被赋值为for循环中当前网络接口的类型,ip4_type和ip6_type分别代表目前出现过的最优的类型。

随后执行了一个for循环,每个循环分析一个ifaddrs结构体节点。首先会将地址和上述枚举对应上,用spot_type记录。如果是无效地址,直接continue,分析下一个节点。如果地址有效,首先判断是ipv4还是ipv6,然后判断spot_type是否大于ipv4或ipv6,如果大于,分别将spot_type赋值给ipv4或ipv6。for循环之后比较ip4_type和ip6_type,选择优先级更高的那个作为目标ip。经过一系列的转换,这个ip被转换为两个版本的字符串,点分十进制和十六进制分别保存。


HttpTransactHeaders::insert_via_header_in_request(HttpTransact::State *s, HTTPHdr *header):函数生成了Via头,并且插到回源的请求头中,ats会将Machine中的ip的十六进制字符串拼到Via头中。


HttpTransact::will_this_request_self_loop(State* s):函数判断Machine中的ip的十六进制字符串是否在Via头中存在,如果存在,判定为发生了loop,返回"400 Multi-Hop Cycle Detected"