network-infra-utility 0.2.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +21 -0
  3. data/CHANGELOG.md +31 -4
  4. data/Gemfile +2 -0
  5. data/Gemfile.lock +70 -0
  6. data/Rakefile +1 -1
  7. data/bin/dns-query +834 -0
  8. data/bin/geo-doc +135 -0
  9. data/bin/geo-get +1 -1
  10. data/document/ASNum/346/250/241/345/235/227/345/212/237/350/203/275/350/257/264/346/230/216.md +242 -0
  11. data/document/DNSQuery/345/267/245/345/205/267/344/275/277/347/224/250/346/226/271/346/263/225.md +248 -0
  12. data/document/Geo/345/221/275/344/273/244/345/267/245/345/205/267/344/275/277/347/224/250/346/226/271/346/263/225.md +441 -0
  13. data/document/IP/346/250/241/345/235/227/345/212/237/350/203/275/350/257/264/346/230/216.md +297 -0
  14. data/document/MAC/346/250/241/345/235/227/345/212/237/350/203/275/350/257/264/346/230/216.md +296 -0
  15. data/document/SSH/350/277/236/346/216/245/345/256/242/346/210/267/347/253/257/344/275/277/347/224/250/346/226/271/346/263/225.md +764 -0
  16. data/network-infra-utility.gemspec +4 -2
  17. data/network.rb +3 -1
  18. data/service/geodb/GeoAPI.md +1 -0
  19. data/service/geodb/geodb.rb +278 -1
  20. data/service/ssh/README.md +942 -0
  21. data/service/ssh/bin/ssh-client +198 -0
  22. data/service/ssh/design/SSH/350/277/236/346/216/245/345/256/242/346/210/267/347/253/257/345/212/237/350/203/275/351/234/200/346/261/202/346/226/207/346/241/243.md +292 -0
  23. data/service/ssh/design/SSH/350/277/236/346/216/245/345/256/242/346/210/267/347/253/257/350/257/246/347/273/206/350/256/276/350/256/241/346/226/207/346/241/243.md +1521 -0
  24. data/service/ssh/design/SSH/350/277/236/346/216/245/345/256/242/346/210/267/347/253/257/350/275/257/344/273/266/350/256/276/350/256/241/346/226/207/346/241/243.md +2493 -0
  25. data/service/ssh/ext/ssh_core/bin/ssh_core.cmd +28 -0
  26. data/service/ssh/ext/ssh_core/config/sys.config +0 -0
  27. data/service/ssh/ext/ssh_core/config/vm.args +0 -0
  28. data/service/ssh/ext/ssh_core/local_deps/jsx/CHECKSUM +1 -0
  29. data/service/ssh/ext/ssh_core/local_deps/jsx/LICENSE +21 -0
  30. data/service/ssh/ext/ssh_core/local_deps/jsx/README.md +696 -0
  31. data/service/ssh/ext/ssh_core/local_deps/jsx/VERSION +1 -0
  32. data/service/ssh/ext/ssh_core/local_deps/jsx/contents.tar.gz +0 -0
  33. data/service/ssh/ext/ssh_core/local_deps/jsx/metadata.config +15 -0
  34. data/service/ssh/ext/ssh_core/local_deps/jsx/rebar.config +17 -0
  35. data/service/ssh/ext/ssh_core/local_deps/jsx/rebar.lock +1 -0
  36. data/service/ssh/ext/ssh_core/local_deps/jsx/src/jsx.app.src +10 -0
  37. data/service/ssh/ext/ssh_core/local_deps/jsx/src/jsx.erl +506 -0
  38. data/service/ssh/ext/ssh_core/local_deps/jsx/src/jsx_config.erl +393 -0
  39. data/service/ssh/ext/ssh_core/local_deps/jsx/src/jsx_config.hrl +18 -0
  40. data/service/ssh/ext/ssh_core/local_deps/jsx/src/jsx_consult.erl +81 -0
  41. data/service/ssh/ext/ssh_core/local_deps/jsx/src/jsx_decoder.erl +1909 -0
  42. data/service/ssh/ext/ssh_core/local_deps/jsx/src/jsx_encoder.erl +116 -0
  43. data/service/ssh/ext/ssh_core/local_deps/jsx/src/jsx_parser.erl +1214 -0
  44. data/service/ssh/ext/ssh_core/local_deps/jsx/src/jsx_to_json.erl +408 -0
  45. data/service/ssh/ext/ssh_core/local_deps/jsx/src/jsx_to_term.erl +389 -0
  46. data/service/ssh/ext/ssh_core/local_deps/jsx/src/jsx_verify.erl +121 -0
  47. data/service/ssh/ext/ssh_core/local_deps/jsx/src/src/jsx.erl +506 -0
  48. data/service/ssh/ext/ssh_core/local_deps/jsx/src/src/jsx_config.erl +393 -0
  49. data/service/ssh/ext/ssh_core/local_deps/jsx/src/src/jsx_config.hrl +18 -0
  50. data/service/ssh/ext/ssh_core/local_deps/jsx/src/src/jsx_consult.erl +81 -0
  51. data/service/ssh/ext/ssh_core/local_deps/jsx/src/src/jsx_decoder.erl +1909 -0
  52. data/service/ssh/ext/ssh_core/local_deps/jsx/src/src/jsx_encoder.erl +116 -0
  53. data/service/ssh/ext/ssh_core/local_deps/jsx/src/src/jsx_parser.erl +1214 -0
  54. data/service/ssh/ext/ssh_core/local_deps/jsx/src/src/jsx_to_json.erl +408 -0
  55. data/service/ssh/ext/ssh_core/local_deps/jsx/src/src/jsx_to_term.erl +389 -0
  56. data/service/ssh/ext/ssh_core/local_deps/jsx/src/src/jsx_verify.erl +121 -0
  57. data/service/ssh/ext/ssh_core/rebar.config +24 -0
  58. data/service/ssh/ext/ssh_core/rebar.lock +1 -0
  59. data/service/ssh/ext/ssh_core/src/ssh_auth_engine.erl +156 -0
  60. data/service/ssh/ext/ssh_core/src/ssh_channel_stm.erl +232 -0
  61. data/service/ssh/ext/ssh_core/src/ssh_codec.erl +83 -0
  62. data/service/ssh/ext/ssh_core/src/ssh_conn_sup.erl +48 -0
  63. data/service/ssh/ext/ssh_core/src/ssh_conn_worker.erl +535 -0
  64. data/service/ssh/ext/ssh_core/src/ssh_core.app.src +36 -0
  65. data/service/ssh/ext/ssh_core/src/ssh_core_app.erl +11 -0
  66. data/service/ssh/ext/ssh_core/src/ssh_core_sup.erl +46 -0
  67. data/service/ssh/ext/ssh_core/src/ssh_infra_sup.erl +104 -0
  68. data/service/ssh/ext/ssh_core/src/ssh_ipc.hrl +80 -0
  69. data/service/ssh/ext/ssh_core/src/ssh_ipc_coalesce.erl +94 -0
  70. data/service/ssh/ext/ssh_core/src/ssh_ipc_gateway.erl +467 -0
  71. data/service/ssh/ext/ssh_core/src/ssh_ipc_proto.erl +95 -0
  72. data/service/ssh/ext/ssh_core/src/ssh_jump_chain.erl +101 -0
  73. data/service/ssh/ext/ssh_core/src/ssh_keepalive_mgr.erl +222 -0
  74. data/service/ssh/ext/ssh_core/src/ssh_known_hosts_proxy.erl +67 -0
  75. data/service/ssh/ext/ssh_core/src/ssh_port_fwd.erl +225 -0
  76. data/service/ssh/ext/ssh_core/src/ssh_sftp_session.erl +250 -0
  77. data/service/ssh/ext/ssh_core/src/ssh_sftp_sup.erl +62 -0
  78. data/service/ssh/ext/ssh_core_rs/Cargo.lock +2345 -0
  79. data/service/ssh/ext/ssh_core_rs/Cargo.toml +30 -0
  80. data/service/ssh/ext/ssh_core_rs/bin/ssh_core_rs +34 -0
  81. data/service/ssh/ext/ssh_core_rs/bin/ssh_core_rs.cmd +40 -0
  82. data/service/ssh/ext/ssh_core_rs/src/channel.rs +296 -0
  83. data/service/ssh/ext/ssh_core_rs/src/coalesce.rs +143 -0
  84. data/service/ssh/ext/ssh_core_rs/src/codec.rs +71 -0
  85. data/service/ssh/ext/ssh_core_rs/src/conn.rs +628 -0
  86. data/service/ssh/ext/ssh_core_rs/src/gateway.rs +389 -0
  87. data/service/ssh/ext/ssh_core_rs/src/handler.rs +293 -0
  88. data/service/ssh/ext/ssh_core_rs/src/keepalive.rs +194 -0
  89. data/service/ssh/ext/ssh_core_rs/src/main.rs +351 -0
  90. data/service/ssh/ext/ssh_core_rs/src/portfwd.rs +378 -0
  91. data/service/ssh/ext/ssh_core_rs/src/proto.rs +198 -0
  92. data/service/ssh/ext/ssh_core_rs/src/sftp.rs +294 -0
  93. data/service/ssh/lib/network_infra_utility/ssh/automation/macro_engine.rb +213 -0
  94. data/service/ssh/lib/network_infra_utility/ssh/client.rb +257 -0
  95. data/service/ssh/lib/network_infra_utility/ssh/config/schema.rb +90 -0
  96. data/service/ssh/lib/network_infra_utility/ssh/config/settings.rb +103 -0
  97. data/service/ssh/lib/network_infra_utility/ssh/config/store.rb +90 -0
  98. data/service/ssh/lib/network_infra_utility/ssh/ipc/coalesce.rb +83 -0
  99. data/service/ssh/lib/network_infra_utility/ssh/ipc/errors.rb +36 -0
  100. data/service/ssh/lib/network_infra_utility/ssh/ipc/router.rb +212 -0
  101. data/service/ssh/lib/network_infra_utility/ssh/ipc/transport.rb +81 -0
  102. data/service/ssh/lib/network_infra_utility/ssh/security/host_key.rb +211 -0
  103. data/service/ssh/lib/network_infra_utility/ssh/security/vault.rb +211 -0
  104. data/service/ssh/lib/network_infra_utility/ssh/session/history.rb +56 -0
  105. data/service/ssh/lib/network_infra_utility/ssh/session/manager.rb +92 -0
  106. data/service/ssh/lib/network_infra_utility/ssh/session/session.rb +109 -0
  107. data/service/ssh/lib/network_infra_utility/ssh/session/tree.rb +95 -0
  108. data/service/ssh/lib/network_infra_utility/ssh/terminal/ansi_parser.rb +435 -0
  109. data/service/ssh/lib/network_infra_utility/ssh/terminal/buffer.rb +78 -0
  110. data/service/ssh/lib/network_infra_utility/ssh/terminal/emulator.rb +159 -0
  111. data/service/ssh/lib/network_infra_utility/ssh/terminal/logger.rb +195 -0
  112. data/service/ssh/lib/network_infra_utility/ssh/terminal/screen.rb +212 -0
  113. data/service/ssh/lib/network_infra_utility/ssh/terminal/theme.rb +127 -0
  114. data/service/ssh/lib/network_infra_utility/ssh/version.rb +7 -0
  115. data/service/ssh/lib/network_infra_utility/ssh.rb +44 -0
  116. data/support/basic/as_num.rb +221 -0
  117. data/support/basic/mac_address.rb +281 -0
  118. data/version.rb +1 -1
  119. metadata +138 -1
data/bin/geo-doc ADDED
@@ -0,0 +1,135 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+ # coding: utf-8
4
+ #
5
+ # geo-doc — network-infra-utility 的 GeoLite2 JSON → 大表导出工具
6
+ #
7
+ # 把 geo-load 生成的 JSON 数据文件(city-IPv4/IPv6、country-IPv4/IPv6、
8
+ # asn、geo-city、geo-country)拼接成一张完整大表,按 IPv4 / IPv6 分别
9
+ # 输出为 CSV 和/或 TXT 文件。
10
+ #
11
+ # 用法:
12
+ # geo-doc # 从 ./geodb/ 读取, 输出到 ./geodb/
13
+ # geo-doc -d /data/geodb # 指定数据目录
14
+ # geo-doc -d /data/geodb -o /output # 指定数据目录 + 输出目录
15
+ # geo-doc -d /data/geodb --format csv # 仅输出 CSV
16
+ # geo-doc -d /data/geodb --format txt # 仅输出 TXT
17
+ # geo-doc -d /data/geodb -o /out -f csv # 指定输出目录 + 仅 CSV
18
+ #
19
+ # 参数规则:
20
+ # -d, --data-dir DIR 数据文件目录(含 JSON),默认 ./geodb/
21
+ # -o, --output-dir DIR 输出目录,默认与数据目录相同
22
+ # -f, --format FORMAT 输出格式: csv / txt / both(默认 both)
23
+ # -h, --help 显示帮助
24
+ # -v, --version 显示版本
25
+
26
+ require "optparse"
27
+
28
+ # ---- 命令行解析 -------------------------------------------------------------
29
+ options = { data_dir: nil, output_dir: nil, format: :both }
30
+ parser = OptionParser.new do |opts|
31
+ opts.banner = <<~BAN
32
+ geo-doc — GeoLite2 JSON → 大表导出工具 (network-infra-utility)
33
+
34
+ 将 geo-load 生成的 JSON 拼接为完整 IP 归属大表,按 IPv4/IPv6 分别输出。
35
+
36
+ 用法:
37
+ geo-doc # 从 ./geodb/ 读取并输出
38
+ geo-doc -d /data/geodb # 指定数据目录
39
+ geo-doc -d /data/geodb -o /output # 指定数据目录 + 输出目录
40
+ geo-doc -d /data/geodb -f csv # 仅输出 CSV
41
+ geo-doc -d /data/geodb -f txt # 仅输出 TXT
42
+
43
+ 参数:
44
+ -d, --data-dir DIR 数据文件目录 (含 JSON),默认 ./geodb/
45
+ -o, --output-dir DIR 输出目录,默认与数据目录相同
46
+ -f, --format FORMAT 输出格式: csv / txt / both (默认 both)
47
+
48
+ 选项:
49
+ BAN
50
+ opts.on("-d", "--data-dir DIR", "数据文件目录,默认 ./geodb/") { |v| options[:data_dir] = v }
51
+ opts.on("-o", "--output-dir DIR", "输出目录,默认与数据目录相同") { |v| options[:output_dir] = v }
52
+ opts.on("-f", "--format FORMAT", %w[csv txt both], "输出格式: csv / txt / both (默认 both)") { |v| options[:format] = v.to_sym }
53
+ opts.on("-v", "--version", "显示版本") do
54
+ require_relative "../version"
55
+ puts "geo-doc #{NetworkInfraUtility::VERSION}"
56
+ exit 0
57
+ end
58
+ opts.on("-h", "--help", "显示帮助") do
59
+ puts opts
60
+ exit 0
61
+ end
62
+ end
63
+ parser.parse!
64
+
65
+ # ---- 确定数据目录 -----------------------------------------------------------
66
+ data_dir = options[:data_dir] || ENV["GEODB_DATA_DIR"] || "geodb"
67
+ data_dir = File.expand_path(data_dir)
68
+
69
+ unless File.directory?(data_dir)
70
+ warn "✗ 数据目录不存在: #{data_dir}"
71
+ warn " 请用 -d/--data-dir 指定包含 JSON 数据文件的目录。"
72
+ warn " 期望目录下含: asn.json / city-IPv4.json / city-IPv6.json /"
73
+ warn " country-IPv4.json / country-IPv6.json /"
74
+ warn " geo-city.json / geo-country.json"
75
+ exit 1
76
+ end
77
+
78
+ required = %w[asn.json geo-city.json geo-country.json]
79
+ missing = required.reject { |f| File.exist?(File.join(data_dir, f)) }
80
+ unless missing.empty?
81
+ warn "✗ 数据目录 #{data_dir} 缺少必要文件: #{missing.join(', ')}"
82
+ warn " 请先运行 geo-load 生成 JSON 数据文件。"
83
+ exit 1
84
+ end
85
+
86
+ # ---- 确定输出目录 -----------------------------------------------------------
87
+ if options[:output_dir]
88
+ output_dir = File.expand_path(options[:output_dir])
89
+ unless File.directory?(output_dir)
90
+ begin
91
+ require "fileutils"
92
+ FileUtils.mkdir_p(output_dir)
93
+ rescue SystemCallError => e
94
+ abort "✗ 无法创建输出目录 #{output_dir}: #{e.message}"
95
+ end
96
+ end
97
+ else
98
+ output_dir = nil # nil → 与数据目录相同
99
+ end
100
+
101
+ # ---- 解析 format 参数 -------------------------------------------------------
102
+ case options[:format]
103
+ when :csv then format = [:csv]
104
+ when :txt then format = [:txt]
105
+ when :both then format = [:csv, :txt]
106
+ else
107
+ abort "✗ 不支持的格式: #{options[:format]} (可选: csv / txt / both)"
108
+ end
109
+
110
+ # ---- 加载 GeoDB 模块 --------------------------------------------------------
111
+ ROOT = File.expand_path("..", __dir__)
112
+ $LOAD_PATH.unshift File.join(ROOT, "service", "geodb")
113
+
114
+ require "cc"
115
+ require "network"
116
+ CC.use "file", "enum", "shell-tools"
117
+ require "geodb"
118
+
119
+ # ---- 执行导出 ---------------------------------------------------------------
120
+ require_relative "../version"
121
+ puts "╭─ geo-doc #{NetworkInfraUtility::VERSION} ───────────────────────────────"
122
+ puts "│ 数据目录: #{data_dir}"
123
+ puts "│ 输出目录: #{output_dir || data_dir}"
124
+ puts "│ 输出格式: #{format.join(' + ')}"
125
+ puts "╰─ 开始导出 ─────────────────────────────────────"
126
+ $stdout.flush
127
+
128
+ GeoDB.output(data_dir + "/", format: format, output_path: output_dir ? output_dir + "/" : nil)
129
+
130
+ puts "╭─ 完成 ───────────────────────────────────────"
131
+ out_target = output_dir || data_dir
132
+ puts "│ 大表文件已生成到: #{out_target}"
133
+ puts "│ 文件列表:"
134
+ Dir.glob(File.join(out_target, "output-*.{csv,txt}")).each { |f| puts "│ #{File.basename(f)}" }
135
+ puts "╰─ 可用 geo-get 查询单个 IP 归属信息 ──────────"
data/bin/geo-get CHANGED
@@ -82,7 +82,7 @@ def fetch(base, path, params)
82
82
  res = Net::HTTP.get_response(uri)
83
83
  { code: res.code.to_i, body: (JSON.parse(res.body) rescue res.body) }
84
84
  rescue Errno::ECONNREFUSED
85
- abort "✗ 无法连接 #{base} —— geo-api 服务未启动。\n 启动命令: geo-api -d E:/workspace/momentum/twinklite/data/geodb"
85
+ abort "✗ 无法连接 #{base} —— geo-api 服务未启动。\n 启动命令: geo-api -d ./geodb"
86
86
  rescue => e
87
87
  abort "✗ 请求失败: #{e.class}: #{e.message}"
88
88
  end
@@ -0,0 +1,242 @@
1
+
2
+ # ASNum 模块功能说明
3
+
4
+ > 源码位置:`support/basic/as_num.rb`
5
+ > 加载方式:`require 'network'` 自动加载,或单独 `require_relative 'support/basic/as_num'`
6
+
7
+ ## AS 号背景
8
+
9
+ AS(自治系统)号是 BGP 路由中标识独立路由域的编号,分 16 位传统号和 32 位扩展号两个区间,每个区间内再分公有、私有、保留三类。
10
+
11
+ ### 号段一览
12
+
13
+ | 位宽 | 类型 | 范围 | 说明 |
14
+ | -------- | ------ | --------------------------------- | ------------------------ |
15
+ | 16 位 | 公有 | 1 – 64511 | 全球可路由,需向 RIR 申请 |
16
+ | 16 位 | 私有 | 64512 – 65534 | 内部网络,不可通告公网 |
17
+ | 16 位 | 保留 | 0, 23456, 65535 | AS 0 / AS_TRANS / 文档 |
18
+ | 32 位 | 公有 | 65536 – 4,199,999,999 | 全球可路由 |
19
+ | 32 位 | 私有 | 4,200,000,000 – 4,294,967,294 | 内部使用 |
20
+ | 32 位 | 保留 | 4,294,967,295 | 32 位全 1 |
21
+
22
+ > AS_TRANS(23456)用于 16 位与 32 位 BGP 互通过渡,归类为保留,不归公有。
23
+
24
+ ### 两种记法
25
+
26
+ | 记法 | 示例 | 说明 |
27
+ | ---------- | ----------- | ------------------------------- |
28
+ | **asplain** | `65546` | 纯十进制整数 |
29
+ | **asdot** | `1.10` | 高 16 位 . 低 16 位,各 0–65535 |
30
+
31
+ 转换关系:`plain = high * 65536 + low`
32
+
33
+ ---
34
+
35
+ ## 创建
36
+
37
+ `ASNum.new` 接受 String(asplain 或 asdot)或 Integer:
38
+
39
+ ```ruby
40
+ require 'network'
41
+
42
+ ASNum.new("65546") # asplain 字符串
43
+ ASNum.new("1.10") # asdot 字符串
44
+ ASNum.new(65546) # Integer
45
+ ASNum.new(" 65546 ") # 自动去除前后空白
46
+ ```
47
+
48
+ 非法输入抛 `ArgumentError`:
49
+
50
+ ```ruby
51
+ ASNum.new("abc") # → ArgumentError (Invalid AS number)
52
+ ASNum.new("70000.1") # → ArgumentError (asdot 段超 65535)
53
+ ASNum.new(4294967296) # → ArgumentError (超 32 位范围)
54
+ ASNum.new(-1) # → ArgumentError (负数)
55
+ ```
56
+
57
+ ---
58
+
59
+ ## 属性
60
+
61
+ ```ruby
62
+ as = ASNum.new("1.10")
63
+
64
+ as.number # => 65546 32 位整数
65
+ as.high # => 1 高 16 位
66
+ as.low # => 10 低 16 位
67
+ ```
68
+
69
+ ---
70
+
71
+ ## 输出格式
72
+
73
+ ```ruby
74
+ as = ASNum.new("1.10")
75
+
76
+ as.to_i # => 65546 十进制整数
77
+ as.to_plain # => "65546" asplain 字符串
78
+ as.to_dot # => "1.10" asdot 字符串(16 位范围内无点)
79
+ as.to_s # => "1.10" 同 to_dot
80
+ as.inspect # => "1.10" 同 to_dot
81
+ ```
82
+
83
+ 16 位号 `to_dot` 回退为纯数字:
84
+
85
+ ```ruby
86
+ ASNum.new("100").to_dot # => "100"
87
+ ASNum.new("65535").to_dot # => "65535"
88
+ ASNum.new("65536").to_dot # => "1.0"
89
+ ```
90
+
91
+ ### asplain ↔ asdot 互换
92
+
93
+ ```ruby
94
+ ASNum.new("1.10").to_plain # => "65546"
95
+ ASNum.new("65546").to_dot # => "1.10"
96
+ ASNum.new("65000.20001").to_plain # => "4259860001"
97
+ ASNum.new("4259860001").to_dot # => "65000.20001"
98
+ ```
99
+
100
+ ---
101
+
102
+ ## 类型判定
103
+
104
+ ```ruby
105
+ # 公有
106
+ ASNum.new("100").public? # => true (1 – 64511)
107
+ ASNum.new("65536").public? # => true (65536 – 4199999999)
108
+
109
+ # 私有
110
+ ASNum.new("64512").private? # => true (64512 – 65534)
111
+ ASNum.new("4200000000").private? # => true (4200000000 – 4294967294)
112
+
113
+ # 保留
114
+ ASNum.new("0").reserved? # => true AS 0
115
+ ASNum.new("23456").reserved? # => true AS_TRANS
116
+ ASNum.new("65535").reserved? # => true 16 位文档保留
117
+ ASNum.new("4294967295").reserved? # => true 32 位全 1
118
+
119
+ # 一次性获取类型符号
120
+ ASNum.new("100").type # => :public
121
+ ASNum.new("64512").type # => :private
122
+ ASNum.new("23456").type # => :reserved
123
+ ```
124
+
125
+ > 三类互斥:同一 AS 号只属于一类。AS_TRANS(23456) 虽落在 1–64511 范围内,但因属保留号,`public?` 返回 false。
126
+
127
+ ### 兼容原接口别名
128
+
129
+ ```ruby
130
+ as = ASNum.new("100")
131
+ as.is_public_as? # => true 等价 public?
132
+ as.is_private_as? # => false 等价 private?
133
+ as.is_reserved_as? # => false 等价 reserved?
134
+ ```
135
+
136
+ ---
137
+
138
+ ## 位宽判定
139
+
140
+ ```ruby
141
+ ASNum.new("100").as2? # => true 16 位传统号 (0 – 65535)
142
+ ASNum.new("65536").as4? # => true 32 位扩展号 (≥ 65536)
143
+
144
+ ASNum.new("65535").as4? # => false
145
+ ASNum.new("65536").as2? # => false
146
+ ```
147
+
148
+ ---
149
+
150
+ ## 排序比较
151
+
152
+ `ASNum` 包含 `Comparable`,按 32 位整数排序:
153
+
154
+ ```ruby
155
+ ASNum.new("100") < ASNum.new("200") # => true
156
+ ASNum.new("1.10") == ASNum.new("65546") # => true(不同记法等价)
157
+ ASNum.new("1.10") == ASNum.new(65546) # => true
158
+
159
+ arr = [ASNum.new("300"), ASNum.new("100"), ASNum.new("200")]
160
+ arr.sort.map(&:to_i) # => [100, 200, 300]
161
+ arr.min.to_i # => 100
162
+ ```
163
+
164
+ ### 作为 Hash key
165
+
166
+ ```ruby
167
+ h = { ASNum.new("100") => "AS100", ASNum.new("200") => "AS200" }
168
+ h[ASNum.new("100")] # => "AS100"
169
+
170
+ # 不同记法、相同值 → hash 一致
171
+ ASNum.new("1.10").hash == ASNum.new("65546").hash # => true
172
+ ```
173
+
174
+ ---
175
+
176
+ ## 典型业务场景
177
+
178
+ ### 1. 批量判断 AS 号归属
179
+
180
+ ```ruby
181
+ as_list = ["100", "64512", "23456", "4294967295", "65536"]
182
+ as_list.each do |s|
183
+ as = ASNum.new(s)
184
+ puts "#{s} → #{as.type}"
185
+ end
186
+ # 100 → public
187
+ # 64512 → private
188
+ # 23456 → reserved
189
+ # 4294967295 → reserved
190
+ # 65536 → public
191
+ ```
192
+
193
+ ### 2. BGP 路由表 AS 号去重排序
194
+
195
+ ```ruby
196
+ # 从 BGP 表中收集的 AS 号(asdot 与 asplain 混用)
197
+ raw = ["1.10", "65546", "100", "65000.20001", "100"]
198
+
199
+ unique_sorted = raw.map { |s| ASNum.new(s) }.uniq.sort
200
+ unique_sorted.map(&:to_plain)
201
+ # => ["100", "65546", "4259860001"]
202
+ ```
203
+
204
+ ### 3. asdot ↔ asplain 批量转换
205
+
206
+ ```ruby
207
+ # Cisco 设备导出 asdot,需转为 asplain 做入库
208
+ ["1.10", "65000.20001", "0.100"].map { |s| ASNum.new(s).to_plain }
209
+ # => ["65546", "4259860001", "100"]
210
+
211
+ # 反过来,asplain 转 asdot
212
+ ["65546", "4259860001", "100"].map { |s| ASNum.new(s).to_dot }
213
+ # => ["1.10", "65000.20001", "100"]
214
+ ```
215
+
216
+ ### 4. 过滤私有和保留 AS 号
217
+
218
+ ```ruby
219
+ as_paths = [100, 64512, 23456, 65536, 65000, 0]
220
+
221
+ announcable = as_paths.reject { |n| ASNum.new(n).private? || ASNum.new(n).reserved? }
222
+ # => [100, 65536]
223
+ ```
224
+
225
+ ---
226
+
227
+ ## 内部常量
228
+
229
+ | 常量 | 值 | 说明 |
230
+ | ------------- | --------------- | --------------- |
231
+ | `AS2_MAX` | 65535 | 16 位上限 |
232
+ | `AS4_MAX` | 4294967295 | 32 位上限 |
233
+ | `PUB_16_MIN` | 1 | 16 位公有下限 |
234
+ | `PUB_16_MAX` | 64511 | 16 位公台上限 |
235
+ | `PRIV_16_MIN` | 64512 | 16 位私有下限 |
236
+ | `PRIV_16_MAX` | 65534 | 16 位私台上限 |
237
+ | `PUB_32_MIN` | 65536 | 32 位公有下限 |
238
+ | `PUB_32_MAX` | 4199999999 | 32 位公台上限 |
239
+ | `PRIV_32_MIN` | 4200000000 | 32 位私有下限 |
240
+ | `PRIV_32_MAX` | 4294967294 | 32 位私台上限 |
241
+ | `RESERVED_16` | [0, 23456, 65535] | 16 位保留号列表 |
242
+ | `RESERVED_32` | 4294967295 | 32 位保留号 |
@@ -0,0 +1,248 @@
1
+ 
2
+ # DNS Query 命令工具使用方法
3
+
4
+ > 命令文件:`bin/dns-query`
5
+ > 运行方式:`ruby bin/dns-query`
6
+
7
+ 跨平台统一域名查询工具:自动检测当前系统所有可用的 DNS 查询工具(dig / nslookup / host / Resolve-DnsName / ping -a 等),默认使用优先级最高的工具执行查询。用户无需关心底层工具差异,也不需要记住各家工具的参数差异。
8
+
9
+ ---
10
+
11
+ ## 一、命令行用法
12
+
13
+ **用法:**
14
+
15
+ ```
16
+ ruby bin/dns-query <目标> [选项]
17
+ ```
18
+
19
+ **位置参数:**
20
+
21
+ | 参数 | 说明 |
22
+ |------|------|
23
+ | `<目标>` | 域名(正查)或 IP 地址(反查 PTR)。目标为 IP 地址时自动切换为 PTR 反查 |
24
+
25
+ **选项:**
26
+
27
+ | 选项 | 说明 |
28
+ |------|------|
29
+ | `-t, --type TYPE` | DNS 记录类型,默认 `A`。支持 `A` / `AAAA` / `CNAME` / `MX` / `NS` / `PTR` / `SOA` / `TXT` / `SRV` / `ANY` |
30
+ | `-s, --server SERVER` | 指定 DNS 服务器(IP 或域名),默认用系统 DNS |
31
+ | `-a, --all` | 使用当前平台所有可用工具交叉查询 |
32
+ | `--tools` | 列出当前平台可用工具及优先级 |
33
+ | `--matrix` | 显示 10 个查询工具的全平台支持矩阵 |
34
+ | `--no-color` | 禁用 ANSI 颜色输出(适合重定向到文件或管道) |
35
+ | `-v, --version` | 显示版本号 |
36
+ | `-h, --help` | 显示帮助 |
37
+
38
+ **示例:**
39
+
40
+ ```bash
41
+ # 正查 A 记录(默认)
42
+ ruby bin/dns-query www.baidu.com
43
+
44
+ # 反查 PTR 记录(自动识别 IP)
45
+ ruby bin/dns-query 8.8.8.8
46
+
47
+ # 指定记录类型
48
+ ruby bin/dns-query www.baidu.com -t MX
49
+ ruby bin/dns-query baidu.com -t NS
50
+
51
+ # 指定 DNS 服务器
52
+ ruby bin/dns-query www.baidu.com -s 8.8.8.8
53
+ ruby bin/dns-query www.baidu.com -s 114.114.114.114 -t AAAA
54
+
55
+ # 用所有可用工具交叉查询
56
+ ruby bin/dns-query www.baidu.com -a
57
+
58
+ # 查看当前平台可用工具
59
+ ruby bin/dns-query --tools
60
+
61
+ # 查看全平台工具矩阵
62
+ ruby bin/dns-query --matrix
63
+
64
+ # 无颜色输出(重定向到文件时不带 ANSI 转义码)
65
+ ruby bin/dns-query www.baidu.com --no-color > result.txt
66
+ ```
67
+
68
+ **退出码:**
69
+
70
+ | 退出码 | 含义 |
71
+ |--------|------|
72
+ | `0` | 查询成功 |
73
+ | `1` | 参数错误 / 当前平台无可用工具 / 查询全部失败 |
74
+
75
+ ---
76
+
77
+ ## 二、自动行为说明
78
+
79
+ ### 1. 工具自动选择
80
+
81
+ 每次查询前会做运行时检测(命令是否存在),按优先级自动选择:
82
+
83
+ - **Linux**:`dig` → `host` → `nslookup` → `drill` → `kdig` → `dog` → `getent` → `resolvectl`
84
+ - **Windows**:`dig`(若安装)→ `nslookup` → `Resolve-DnsName` → `ping -a`
85
+
86
+ 可通过 `--tools` 查看当前平台实际可用工具。
87
+
88
+ ### 2. IP 自动反查 PTR
89
+
90
+ 目标为合法 IPv4 / IPv6 地址时,若未显式指定 `-t`,自动把记录类型切换为 `PTR`,并统一转换成反向域名(`in-addr.arpa` / `ip6.arpa`)再查询,保证 dig / drill / kdig 等工具行为一致。
91
+
92
+ ```bash
93
+ ruby bin/dns-query 8.8.8.8
94
+ # 等效于: ruby bin/dns-query 8.8.8.8 -t PTR
95
+ # 实际查询: nslookup -type=PTR 8.8.8.8.in-addr.arpa
96
+ ```
97
+
98
+ ### 3. 记录类型与工具能力对照
99
+
100
+ 各工具支持能力不同(可用 `--matrix` 查看完整矩阵),摘要如下:
101
+
102
+ | 记录类型 | dig | nslookup | host | drill | kdig | dog | Resolve-DnsName |
103
+ |----------|-----|----------|------|-------|------|-----|-----------------|
104
+ | A / AAAA / CNAME / MX / NS / PTR / SOA / TXT / SRV | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
105
+ | ANY | ✅ | – | – | – | – | – | – |
106
+ | AXFR / DNSSEC / trace | ✅ | – | – | ✅ | ✅ | – | – |
107
+ | DoH / DoT | – | – | – | – | ✅ | – | – |
108
+
109
+ 部分工具(如 `getent hosts`)只支持 A / AAAA,`ping -a` 仅支持 PTR。`--all` 模式下查询失败的工具会显示 `[查询失败或不可用]`,不影响其他工具结果。
110
+
111
+ ---
112
+
113
+ ## 三、全平台工具矩阵(--matrix)
114
+
115
+ `--matrix` 输出 10 个 DNS 工具的跨平台支持情况:
116
+
117
+ - **dig**(DNS 查询瑞士军刀):Linux 各发行版可用;Windows 需手动安装 ISC BIND
118
+ - **nslookup**(经典工具):全平台内置(Linux 需 bind 工具包)
119
+ - **host**:仅 Linux(bind 工具包)
120
+ - **drill**(ldns,支持 DNSSEC):Linux 各发行版;Windows 需手动安装
121
+ - **kdig**(Knot DNS,支持 DNSSEC / DoH / DoT):Linux 各发行版
122
+ - **dog**(Rust 彩色工具):Linux 各发行版(部分需 cargo 安装)
123
+ - **Resolve-DnsName**(PowerShell):仅 Windows(PS 4.0+)
124
+ - **ping -a**(反查主机名):仅 Windows,仅支持 PTR
125
+ - **getent hosts**:仅 Linux
126
+ - **resolvectl query**:仅 Linux(systemd-resolved,Alpine 无)
127
+
128
+ **缺失工具的安装命令**(Linux):
129
+
130
+ | 工具 | Ubuntu / Debian | Alpine | RHEL/CentOS |
131
+ |------|-----------------|--------|-------------|
132
+ | dig / host / nslookup | `sudo apt install -y dnsutils` | `sudo apk add bind-tools` | `sudo yum install -y bind-utils` |
133
+ | drill | `sudo apt install -y ldnsutils` | `sudo apk add drill` | `sudo yum install -y ldns` |
134
+ | kdig | `sudo apt install -y knot-dnsutils` | `sudo apk add knot` | `sudo yum install -y knot-utils` |
135
+
136
+ ---
137
+
138
+ ## 四、典型使用场景
139
+
140
+ ### 1. 正查域名 A 记录
141
+
142
+ ```bash
143
+ $ ruby bin/dns-query www.baidu.com
144
+ === 使用 nslookup 查询 www.baidu.com (A) ===
145
+
146
+ 非权威应答:
147
+
148
+ 服务器: UnKnown
149
+ Address: 10.140.209.68
150
+
151
+ 名称: www.a.shifen.com
152
+ Addresses: 39.156.70.46
153
+ 39.156.70.239
154
+ Aliases: www.baidu.com
155
+ ```
156
+
157
+ ### 2. 反查 IP 归属域名
158
+
159
+ ```bash
160
+ $ ruby bin/dns-query 8.8.8.8
161
+ === 使用 nslookup 查询 8.8.8.8 (PTR) ===
162
+
163
+ 非权威应答:
164
+
165
+ 服务器: UnKnown
166
+ Address: 10.140.209.68
167
+
168
+ 8.8.8.8.in-addr.arpa name = dns.google
169
+ ```
170
+
171
+ ### 3. 指定公网 DNS 服务器校验解析结果
172
+
173
+ ```bash
174
+ # 对比系统 DNS 与公共 DNS 的解析差异(排查 DNS 污染/劫持)
175
+ ruby bin/dns-query www.baidu.com
176
+ ruby bin/dns-query www.baidu.com -s 8.8.8.8
177
+ ruby bin/dns-query www.baidu.com -s 114.114.114.114
178
+ ```
179
+
180
+ ### 4. 多工具交叉验证(--all)
181
+
182
+ ```bash
183
+ $ ruby bin/dns-query www.baidu.com -a
184
+ === 使用所有可用工具查询 www.baidu.com (A) ===
185
+
186
+ --- nslookup ---
187
+ 非权威应答: ...
188
+ --- Resolve-DnsName ---
189
+ Name : www.baidu.com
190
+ QueryType : A
191
+ ...
192
+ --- ping -a ---
193
+ 正在 Ping www.a.shifen.com [2409:8c00:...] 具有 32 字节的数据:
194
+ ...
195
+ ```
196
+
197
+ ### 5. 检查邮件服务器(MX)
198
+
199
+ ```bash
200
+ $ ruby bin/dns-query qq.com -t MX
201
+ === 使用 nslookup 查询 qq.com (MX) ===
202
+ 非权威应答:
203
+ qq.com MX preference = 30, mail exchanger = mx3.qq.com
204
+ ...
205
+ ```
206
+
207
+ ---
208
+
209
+ ## 五、代码级用法
210
+
211
+ 脚本同时提供可复用的模块能力(`load` 后不自动执行 CLI;文件无 `.rb` 扩展名,需用 `load` 而非 `require`):
212
+
213
+ ```ruby
214
+ load File.expand_path("bin/dns-query", __dir__)
215
+
216
+ # 查询对象:自动判断 IP / 域名,IP 自动反查 PTR
217
+ query = DnsQuery::Query.new("www.baidu.com", qtype: "A", server: "8.8.8.8")
218
+
219
+ # 默认最佳工具查询 → [stdout, exit_code]
220
+ stdout, code = query.execute
221
+
222
+ # 全部工具交叉查询 → [汇总状态, exit_code]
223
+ DnsQuery::Query.new("8.8.8.8").execute_all
224
+
225
+ # 平台与工具检测
226
+ DnsQuery::Platform.os # => :windows / :linux
227
+ DnsQuery::Platform.wsl? # => true / false
228
+ DnsQuery::ToolDetector.detect # => [{key:, name:, priority:}, ...]
229
+ ```
230
+
231
+ **模块结构:**
232
+
233
+ | 模块 | 职责 |
234
+ |------|------|
235
+ | `DnsQuery::Platform` | 操作系统 / 发行版 / Windows 版本 / PowerShell 版本检测 |
236
+ | `DnsQuery::ToolDetector` | 运行时检测当前平台可用工具(`which`/`where` 按平台分流) |
237
+ | `DnsQuery::Executor` | 10 个工具的调用逻辑统一入口,PTR 自动转反向域名,Windows 输出自动转 UTF-8 |
238
+ | `DnsQuery::Query` | 查询编排:最佳工具单查 / 全部工具交叉查 |
239
+ | `DnsQuery::CLI` | 参数解析、校验、分发,返回进程退出码 |
240
+
241
+ ---
242
+
243
+ ## 六、注意事项
244
+
245
+ - Windows 下 `ver` / PowerShell 命令输出为 GBK 编码,脚本已统一转换为 UTF-8,无需手动设置代码页
246
+ - 指定 `-s` 服务器时接受 IP 或域名;非法格式会在查询前报错
247
+ - `ping -a` 会实际发起一次 ICMP 探测,离线环境 `--all` 模式会超时,可单独用 `--tools` 确认后避免使用该工具
248
+ - 输出重定向到文件时建议加 `--no-color`,避免 ANSI 转义码进入文件