Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] 在经过 resp_ip 判断后 black_hole 无法替换 IPv4 或 IPv6 地址 #759

Open
4 tasks done
Journalist-HK opened this issue Nov 9, 2023 · 11 comments
Open
4 tasks done

Comments

@Journalist-HK
Copy link

Journalist-HK commented Nov 9, 2023

在提交之前,请确认

  • 我已经尝试搜索过 Issue ,但没有找到相关问题。
  • 我正在使用最新的 mosdns 版本(或者最新的 commit),问题依旧存在。
  • 我仔细看过 wiki 后仍然无法自行解决该问题。
  • 我非常确定这是 mosdns 核心的问题。(如果是通过第三方衍生软件使用 mosdns 核心,不确定问题源头时,请先向衍生软件开发者提交问题。)

mosdns 版本

v5.3.1

操作系统

OpenWrt

Bug 描述和复现步骤

我想要实现:对于双栈域名,经过 black_hole 后能顺带实现 prefer_ipv4 的功能。prefer_ipv4 只能在 forward 前使用,而我想要先查询再判断。

根据文档,如果某一 IP 类型未指定,则不会生成对应类型的应答,那么 black_hole 1.2.3.4black_hole 1.2.3.4 ::0 应当能够丢弃IPv6 地址。实际上并没有起作用,原始的AAAA记录将会保留,black_hole ::1 不会对结果产生任何影响。经过测试,问题只在前置判断有 resp_ip 才出现。

使用下方测试配置,测试域名 gh.api.99988866.xyz,正确 IP:

  • 2606:4700:3038::6815:eb6e
  • 2606:4700:3038::6815:eb6d
  • 104.21.235.110
  • 104.21.235.109

替换 begin 到 end 中的内容分别测试

以下 3 种均能替换 IP,说明没有 resp_ip 时 black_hole 能正常工作。

      - exec: black_hole 127.0.0.1 ::1 # a
      - exec: black_hole 127.0.0.1 # b ipv4 only
      - exec: black_hole ::1 # c ipv6 only

当两条分开写时,也能分别替换 v4/v6,返回 v4/v6 两个 IP。两条的先后顺序不影响结果。这就有点问题了,按照文档中的描述,应该以最后一条为准。

      - exec: black_hole 127.0.0.1
      - exec: black_hole ::1
      # d

加入 matches

      - matches:
          - resp_ip 0.0.0.0/0 ::/0
        exec: black_hole 127.0.0.1 ::1
      # 1 正常
      - matches:
          - resp_ip 0.0.0.0/0 ::/0
        exec: black_hole 127.0.0.1
      # 2 不会去除 v6
      - matches:
          - resp_ip 0.0.0.0/0 ::/0
        exec: black_hole ::1
      # 3 不会去除 v4

说明 resp_ip 会对 black_hole 的行为产生影响,这是意料之外的。下面进一步测试:

      - matches:
          - resp_ip 0.0.0.0/0
        exec: black_hole 127.0.0.1
      # 4 只替换 v4,v6 保留而不是删除
      - matches:
          - resp_ip 0.0.0.0/0
        exec: black_hole 127.0.0.1 ::1
      # 5 只替换 v4,v6 保留而不是替换
      - matches:
          - resp_ip 0.0.0.0/0
        exec: black_hole ::1
      # 6 什么都不会改
      - matches:
          - resp_ip ::/0
        exec: black_hole ::1
      # 7 只替换 v6,v4 保留而不是删除
      - matches:
          - resp_ip ::/0
        exec: black_hole 127.0.0.1 ::1
      # 8 能替换 v4/v6,和 5 的表现不一致
      - matches:
          - resp_ip ::/0
        exec: black_hole 127.0.0.1
      # 9 只替换 v4,v6 保留而不是删除,和 6 的表现不一致,和 4 的表现相同

4 和 7 组合能正确替换 IP,两个 matches 的先后顺序不影响结果。

      - matches:
          - resp_ip 0.0.0.0/0
        exec: black_hole 127.0.0.1
      - matches:
          - resp_ip ::/0
        exec: black_hole ::1

但是,将 5 和 c 组合,得到的结果是只能保留v6,和 d 的表现不一致。

      - matches:
          - resp_ip 0.0.0.0/0
        exec: black_hole 127.0.0.1 ::1
      - exec: black_hole ::1
      # v6 only

理想的情况是只按最后一条 black_hole 为准,并且 resp_ip 不应对结果产生任何影响。也可以考虑将 black_hole 分为 black_hole_ipv4 和 black_hole_ipv6 两种。

使用的配置文件

log:
  level: info
  file: "./mosdns.log"

api:
  http: "127.0.0.1:9091"

include: []

plugins:
  - tag: main
    type: sequence
    args:
      - exec: forward https://162.159.46.1/dns-query

      # begin
      - matches:
          - resp_ip 0.0.0.0/0
        exec: black_hole 127.0.0.1
      - matches:
          - resp_ip ::/0
        exec: black_hole ::1
      # end

      - matches:
          - has_resp
        exec: accept

  - tag: udp_server
    type: udp_server
    args:
      entry: main
      listen: ":53"

mosdns 的 log 记录

No response

@qingtian110
Copy link

可以在 GitHub 搜索下 openwrt mosdns luci 的配置文件,resp_ip + black_hole 它是工作的

image
image

@Journalist-HK
Copy link
Author

可以在 GitHub 搜索下 openwrt mosdns luci 的配置文件,resp_ip + black_hole 它是工作的

如过你指的是这个
https://github.com/sbwml/luci-app-mosdns/blob/3ba579cf805795c407852d77607efa5fa1ac0e51/luci-app-mosdns/root/usr/share/mosdns/default.yaml#L141

那你可以尝试将图片中的“Cloudflare IP 范围”设置为只有 IPv4 或 IPv6 再试一试。

@qingtian110
Copy link

图片
图片

匹配范围 ipv4 only,这测试结果应该是对的吧。因为匹配 resp_ip 的 ipv4 地址,那么理所当然的也是更替应答结果的 ipv4 地址。

如果它连同 ipv6 也被更替了,我会觉得它是一个 bug。@IrineSistiana @sbwml 大佬们是不是这样的?

@Journalist-HK
Copy link
Author

匹配范围 ipv4 only,这测试结果应该是对的吧。因为匹配 resp_ip 的 ipv4 地址,那么理所当然的也是更替应答结果的 ipv4 地址。

如果它连同 ipv6 也被更替了,我会觉得它是一个 bug。

按照你的说法,如果我只匹配 IPv6 地址,是不是应该只替换 IPv6 地址,而不替换 IPv4 地址?但是 mosdns 并没有这样工作,你可以再试一试。

@kkkgo
Copy link

kkkgo commented Nov 12, 2023

1、A记录和AAAA记录是不同的qtype,他们的查询并不在同一个请求里面。
2、// Response returns a response with given ips if query has corresponding qtypes.
// Otherwise, it returns nil.
如果提供了blackhole的地址,就会替换,否则不替换。

@kkkgo
Copy link

kkkgo commented Nov 12, 2023

3、如果说可能的bug的话,在Match方法里面,::/0是包含了0.0.0.0/0,0.0.0.0/0不包含::/0。
而Contains是先把IP统一转换成IPv6格式再匹配:

// Contains reports whether the list includes the given netip.Addr.
func (list *List) Contains(addr netip.Addr) bool {
	if !list.sorted {
		panic("list is not sorted")
	}
	if !addr.IsValid() {
		return false
	}

	addr = to6(addr)

	i, j := 0, len(list.e)
	for i < j {
		h := int(uint(i+j) >> 1) // avoid overflow when computing h
		if list.e[h].Addr().Compare(addr) <= 0 {
			i = h + 1
		} else {
			j = h
		}
	}

	if i == 0 {
		return false
	}

	return list.e[i-1].Contains(addr)
}

所以这也算不上bug,如果你想匹配全部AAAA记录,应该用qtype 28更高效。

@Journalist-HK
Copy link
Author

所以这也算不上bug,如果你想匹配全部AAAA记录,应该用qtype 28更高效。

      - matches:
          - qtype 1
          - has_wanted_ans
          - resp_ip $cloudflare_ip
        exec: jump blackhole_cloudflare
      - matches:
          - qtype 28
          - has_wanted_ans
          - resp_ip $cloudflare_ipv6
        exec: jump blackhole_cloudflare_ipv6

这样写的话,能实现如果原来是 IPv4 only / IPv4 only / dual stack,替换后也是。

但是如何实现 prefer_ipv4?因为我希望只对命中规则的域名(在这里就是使用 CF CDN 的域名)实施 prefer_ipv4,其他的保留 IPv6。而 prefer_ipv4 只能放在 forward 之前,还没有请求上游前并不知道它是不是用了Cloudflare CDN。

@kkkgo
Copy link

kkkgo commented Nov 24, 2023

“使用 CF CDN 的域名实施 prefer_ipv4",那你直接把解析结果命中 CF V6 CDN 的请求reject掉不就好了……

1、A记录和AAAA记录是不同的qtype,他们的查询并不在同一个请求里面。

@Journalist-HK
Copy link
Author

这样会影响只返回 AAAA 而没有 A 记录的域名,虽然这样的域名应该不多。正因为不是同一个请求,才不好实现。

@kkkgo
Copy link

kkkgo commented Nov 24, 2023

纯v6 cf cdn的域名。不能说不多,只能说除非是故意的。

@ryanfys
Copy link

ryanfys commented Mar 16, 2024

我在尝试cf cdn优选ip时候发现了同样的问题

在没有'resp_ip'的情况下,'black_hole'是无视ipv4 ipv6完整替换的

但在'resp_ip'后,'black_hole'只会根据'resp_ip'匹配的ip类型,进行替换,'resp_ip'未匹配到的ip类型,保持不变。

感觉这种现象很割裂,按正常的想法,matchs只是条件筛选,而不应该影响后续的操作

而且不仅'black_hole'如此,'redirect'也会受到resp_ip的影响。

当然对于优选cf ip,不影响使用,cf cdn基本都是双栈

但还是希望能统一'black_hole'、'redirect'等的行为,不受'resp_ip'的影响

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants