現象
--subnet の prefix 長が検証されていない。負の値がそのまま EDNS Client Subnet オプションの source_prefix になる。
$ # Tdig.CLI.parse_subnet_option/1 の実測
192.0.2.1/24: source_prefix: 24
192.0.2.1/-5: source_prefix: -5 ← 負値がそのまま通る
192.0.2.1/999: source_prefix: 32 ← 上限だけは効く
2001:db8::1/-1: source_prefix: -1
原因
lib/tdig/cli.ex の parse_subnet_option/1 が
prefix = String.to_integer(prefix_str)
...
source_bits = min(prefix, 32) # IPv6 側は min(prefix, 128)
としており、min/2 は上限しか抑えない。下限のチェックが無く、String.to_integer/1 は "-5" を素直に -5 にする。
RFC 7871 の SOURCE PREFIX-LENGTH は 8 bit の符号なし整数なので、負値は表現できない。
影響
パケット組み立て側の扱い次第だが、いずれにせよ利用者の意図しないクエリが送られる。dig は +subnet=192.0.2.1/-5 を invalid prefix length で拒否する。
検討事項
挙動の変更を伴うため、方針を決める必要がある。
- 範囲外をエラーにする(
dig に合わせる。既存の Invalid subnet format と同じく stderr + System.halt(1))
- 0 にクランプする
dig 互換を掲げているので 1 が素直だと考える。
あわせて String.to_integer/1 は "abc" で ArgumentError を投げるため、--subnet 192.0.2.1/abc がスタックトレースを出す点も同時に見るとよい。
経緯
PR #85(Dialyzer の contract_supertype 解消)のレビューで source_prefix を non_neg_integer() にできないかという指摘があり、実測したところ実装が負値を返し得ることが分かった。spec は実装に忠実な integer() に据え置き、入力検証の欠落は挙動変更を伴うため本 issue に分離した。
https://claude.ai/code/session_01YAjSJR67tWTvYDJLcQThbQ
現象
--subnetの prefix 長が検証されていない。負の値がそのまま EDNS Client Subnet オプションのsource_prefixになる。原因
lib/tdig/cli.exのparse_subnet_option/1がとしており、
min/2は上限しか抑えない。下限のチェックが無く、String.to_integer/1は"-5"を素直に-5にする。RFC 7871 の SOURCE PREFIX-LENGTH は 8 bit の符号なし整数なので、負値は表現できない。
影響
パケット組み立て側の扱い次第だが、いずれにせよ利用者の意図しないクエリが送られる。
digは+subnet=192.0.2.1/-5をinvalid prefix lengthで拒否する。検討事項
挙動の変更を伴うため、方針を決める必要がある。
digに合わせる。既存のInvalid subnet formatと同じく stderr +System.halt(1))dig互換を掲げているので 1 が素直だと考える。あわせて
String.to_integer/1は"abc"でArgumentErrorを投げるため、--subnet 192.0.2.1/abcがスタックトレースを出す点も同時に見るとよい。経緯
PR #85(Dialyzer の
contract_supertype解消)のレビューでsource_prefixをnon_neg_integer()にできないかという指摘があり、実測したところ実装が負値を返し得ることが分かった。spec は実装に忠実なinteger()に据え置き、入力検証の欠落は挙動変更を伴うため本 issue に分離した。https://claude.ai/code/session_01YAjSJR67tWTvYDJLcQThbQ