TPROXY 拦截后 Dnsmasq 未收到响应
Dnsmasq not receiving response after TPROXY intercept
我正在路由器上开发一种“监控流量”的应用程序,我在其中使用 TPROXY
功能来拦截 DNS 数据包并发送它到我的应用程序服务器侦听端口。处理完后,我在修改TTL后将数据包转发到实际目的地(即dnsmasq)
仅供参考,我的 TPROXY 防火墙规则将 DNS 响应数据包转发到侦听端口 2345 的应用程序服务器,如下所示:
iptables -t mangle -A PREROUTING -i <WAN-INTERFACE> -p udp --sport 53 -j TPROXY --tproxy-mark 0x3 --on-port 2345
在我的应用程序服务器上,没有错误检查:
sock_fd = socket(AF_INET, SOCK_DGRAM, 0 );
setsockopt(socket_fd, SOL_IP, IP_PKTINFO, &enabled, sizeof(int));
setsockopt(socket_fd, SOL_IP, IP_TRANSPARENT, &enabled, sizeof(int));
setsockopt(socket_fd, SOL_IP, IP_RECVORIGDSTADDR, &enabled, sizeof(int));
setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &enabled, sizeof(int));
/* client_addr points to the source IP (i.e. upstream DNS server's IP) */
bind(sock_fd, (const struct sockaddr *)client_addr, sizeof(struct sockaddr));
/* dst_addr points to the router IP on the WAN interface */
sendto(sock_fd, dns_packet_buffer, data_len, 0,
(const struct sockaddr *)dst_addr, sizeof(struct sockaddr));
这次sendto
成功,即没有报错!!!但是,dnsmasq 没有收到数据!更准确的说,dnsmasq等待数据的fd并没有变成"ready."
在dnsmasq代码里面check_dns_listeners
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
if (FD_ISSET(serverfdp->fd, set))
reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
FD_ISSET()
returns false
。如果我不拦截 DNS 响应流,那么这个 FD_ISSET()
returns 是正确的。我在这里错过了什么?
终于找到答案了!!让我把它放在这里假设它对其他人有帮助。
正如我之前提到的,我的应用程序在路由器上 运行。路由器制造商修改了现有的 dnsmasq 代码以添加一个额外的选项来限制他们从上游服务器监听的接口!换句话说,它们仅通过给定接口(如 eth2)接受来自上游服务器的响应。从代码的角度来看,他们甚至不监听 eth2 以外的其他接口!由于我的回复是通过 'lo' 发出的,他们没有在听!! :)
我在没有那个选项的情况下重新启动了 dnsmasq,viola 成功了! :)
我希望他们在 public 论坛上记录了它!这样通用的谷歌搜索就可以工作,而不是阅读 1000 行代码!!
我正在路由器上开发一种“监控流量”的应用程序,我在其中使用 TPROXY
功能来拦截 DNS 数据包并发送它到我的应用程序服务器侦听端口。处理完后,我在修改TTL后将数据包转发到实际目的地(即dnsmasq)
仅供参考,我的 TPROXY 防火墙规则将 DNS 响应数据包转发到侦听端口 2345 的应用程序服务器,如下所示:
iptables -t mangle -A PREROUTING -i <WAN-INTERFACE> -p udp --sport 53 -j TPROXY --tproxy-mark 0x3 --on-port 2345
在我的应用程序服务器上,没有错误检查:
sock_fd = socket(AF_INET, SOCK_DGRAM, 0 );
setsockopt(socket_fd, SOL_IP, IP_PKTINFO, &enabled, sizeof(int));
setsockopt(socket_fd, SOL_IP, IP_TRANSPARENT, &enabled, sizeof(int));
setsockopt(socket_fd, SOL_IP, IP_RECVORIGDSTADDR, &enabled, sizeof(int));
setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &enabled, sizeof(int));
/* client_addr points to the source IP (i.e. upstream DNS server's IP) */
bind(sock_fd, (const struct sockaddr *)client_addr, sizeof(struct sockaddr));
/* dst_addr points to the router IP on the WAN interface */
sendto(sock_fd, dns_packet_buffer, data_len, 0,
(const struct sockaddr *)dst_addr, sizeof(struct sockaddr));
这次sendto
成功,即没有报错!!!但是,dnsmasq 没有收到数据!更准确的说,dnsmasq等待数据的fd并没有变成"ready."
在dnsmasq代码里面check_dns_listeners
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
if (FD_ISSET(serverfdp->fd, set))
reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
FD_ISSET()
returns false
。如果我不拦截 DNS 响应流,那么这个 FD_ISSET()
returns 是正确的。我在这里错过了什么?
终于找到答案了!!让我把它放在这里假设它对其他人有帮助。
正如我之前提到的,我的应用程序在路由器上 运行。路由器制造商修改了现有的 dnsmasq 代码以添加一个额外的选项来限制他们从上游服务器监听的接口!换句话说,它们仅通过给定接口(如 eth2)接受来自上游服务器的响应。从代码的角度来看,他们甚至不监听 eth2 以外的其他接口!由于我的回复是通过 'lo' 发出的,他们没有在听!! :)
我在没有那个选项的情况下重新启动了 dnsmasq,viola 成功了! :)
我希望他们在 public 论坛上记录了它!这样通用的谷歌搜索就可以工作,而不是阅读 1000 行代码!!