network-infra-utility 0.6.0 → 1.0.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 (79) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +6 -0
  3. data/CHANGELOG.md +31 -0
  4. data/GUIDE.md +201 -212
  5. data/README.md +1 -6
  6. data/Rakefile +1 -1
  7. data/bin/gen-get +144 -0
  8. data/bin/geo-api +40 -1
  9. data/bin/geo-get +18 -36
  10. data/bin/ngeo-get +253 -0
  11. data/bin/packbit +227 -0
  12. data/bin/probe +134 -0
  13. data/document/reference/DNS/346/212/200/346/234/257/346/226/207/346/241/243.md +912 -0
  14. data/network-infra-utility.gemspec +6 -4
  15. data/network.rb +19 -1
  16. data/service/geodb/GeoAPI.md +64 -0
  17. data/service/geodb/api.rb +77 -19
  18. data/service/geoquery/GeoQuery.md +309 -0
  19. data/service/geoquery/cache.rb +78 -0
  20. data/service/geoquery/geo_cache.rb +233 -0
  21. data/service/geoquery/geoquery.rb +327 -0
  22. data/service/geoquery/local.rb +151 -0
  23. data/service/geoquery/merge.rb +52 -0
  24. data/service/geoquery/normalize.rb +102 -0
  25. data/service/geoquery/online.rb +136 -0
  26. data/service/simlab/SimLab.md +140 -0
  27. data/service/simlab/bin/simctl +152 -0
  28. data/service/simlab/lib/simlab.rb +124 -0
  29. data/service/simlab/lib/simlab_engine.rb +146 -0
  30. data/service/simlab/lib/simlab_observer.rb +176 -0
  31. data/service/simlab/lib/simlab_router.rb +330 -0
  32. data/service/simlab/lib/simlab_scenario.rb +200 -0
  33. data/service/simlab/lib/simlab_switch.rb +182 -0
  34. data/service/simlab/lib/simlab_topology.rb +196 -0
  35. data/service/simlab/lib/simlab_traffic.rb +167 -0
  36. data/support/basic/packet.rb +167 -0
  37. data/support/routing/bgp.rb +279 -0
  38. data/support/routing/lpm_trie.rb +145 -0
  39. data/support/routing/ospf.rb +243 -0
  40. data/support/routing/prefix.rb +155 -0
  41. data/support/routing/rib.rb +167 -0
  42. data/support/routing/rip.rb +223 -0
  43. data/support/routing/static_route.rb +102 -0
  44. data/support/switching/frame_forward.rb +87 -0
  45. data/support/switching/mac_table.rb +127 -0
  46. data/support/switching/stp.rb +230 -0
  47. data/support/switching/vlan.rb +155 -0
  48. data/tool/packbit/README.md +136 -0
  49. data/tool/packbit/config/five-tuple.yml +25 -0
  50. data/tool/packbit/config/flow.yml +17 -0
  51. data/tool/packbit/config/packbit.yml +41 -0
  52. data/tool/packbit/erl/packbit.erl +588 -0
  53. data/tool/probe/README.md +88 -0
  54. data/tool/probe/lib/probe.rb +54 -0
  55. data/tool/probe/lib/probe_base.rb +98 -0
  56. data/tool/probe/lib/probe_dns.rb +64 -0
  57. data/tool/probe/lib/probe_icmp.rb +71 -0
  58. data/tool/probe/lib/probe_ntp.rb +51 -0
  59. data/tool/probe/lib/probe_radius.rb +58 -0
  60. data/tool/probe/lib/probe_registry.rb +44 -0
  61. data/tool/probe/lib/probe_result.rb +75 -0
  62. data/tool/probe/lib/probe_snmp.rb +114 -0
  63. data/tool/probe/lib/probe_tcp.rb +82 -0
  64. data/tool/probe/lib/probe_version.rb +7 -0
  65. data/tool/webssh/README.md +42 -0
  66. data/tool/webssh/app.py +788 -0
  67. data/tool/webssh/cli.bat +17 -0
  68. data/tool/webssh/config.yml.template +84 -0
  69. data/tool/webssh/extension//350/256/276/345/244/207/350/257/212/346/226/255.md +103 -0
  70. data/tool/webssh/requirements.txt +7 -0
  71. data/tool/webssh/ssh_cli.py +449 -0
  72. data/tool/webssh/ssh_worker.py +782 -0
  73. data/tool/webssh/static/vendor/xterm-addon-fit.min.js +8 -0
  74. data/tool/webssh/static/vendor/xterm.css +209 -0
  75. data/tool/webssh/static/vendor/xterm.min.js +8 -0
  76. data/tool/webssh/templates/index.html +2674 -0
  77. data/tool/webssh/web.bat +41 -0
  78. data/version.rb +1 -1
  79. metadata +87 -2
data/bin/packbit ADDED
@@ -0,0 +1,227 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+ # coding: utf-8
4
+ #
5
+ # packbit — pcap 抓包解析命令行工具 (Ruby CLI + Erlang 引擎)
6
+ #
7
+ # Ruby 负责命令行参数解析与用户交互,核心解析由 Erlang escript 实现。
8
+ # 通过读取 YAML 配置文件决定筛选、统计、展示数据包的内容。
9
+ #
10
+ # 用法:
11
+ # packbit -f <pcap> # 全量逐字段解析
12
+ # packbit -f <pcap> -d # 摘要: 统计表 + 每包一行
13
+ # packbit -f <pcap> -c packbit.yml # 按配置文件筛选/统计/展示
14
+ # packbit -f <pcap> -p 80 tcp # 按端口+协议筛选
15
+ # packbit -f <pcap> -c flow.yml -d # flow 分组统计
16
+ # packbit -f <pcap -c packbit.yml -d # 配置 + 摘要模式
17
+ # packbit -h # 帮助
18
+ # packbit -v # 版本
19
+ #
20
+ # 选项:
21
+ # -f, --file FILE pcap 文件路径
22
+ # -c, --config FILE YAML 配置文件 (筛选/统计/展示)
23
+ # -d, --summary 摘要模式 (统计表 + 每包一行)
24
+ # -p, --port PORT PROTO 按端口+协议筛选 (如 -p 80 tcp)
25
+ # -h, --help 显示帮助
26
+ # -v, --version 显示版本
27
+ #
28
+ # 退出码: 0 成功, 1 参数错误/Erlang 未安装
29
+
30
+ require "optparse"
31
+ require "rbconfig"
32
+ require "shellwords"
33
+ require_relative "../version"
34
+
35
+ module Packbit
36
+ ERL_DIR = File.expand_path("../tool/packbit/erl", __dir__)
37
+ ESCRIPT = File.join(ERL_DIR, "packbit.erl")
38
+ DEFAULT_CFG = File.expand_path("../tool/packbit/config/packbit.yml", __dir__)
39
+
40
+ module Platform
41
+ def self.erlang?
42
+ @has_erlang ||= begin
43
+ if windows?
44
+ system("where escript >NUL 2>&1")
45
+ else
46
+ system("command -v escript >/dev/null 2>&1")
47
+ end
48
+ end
49
+ end
50
+
51
+ def self.windows?
52
+ RbConfig::CONFIG["host_os"] =~ /mswin|mingw|cygwin|windows/
53
+ end
54
+
55
+ def self.escript_path
56
+ @escript_path ||= begin
57
+ if windows?
58
+ `where escript`.strip.lines.first&.strip
59
+ else
60
+ `command -v escript`.strip
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ module CLI
67
+ def self.run(argv)
68
+ options = { file: nil, config: nil, summary: false, port: nil, proto: nil,
69
+ help: false, version: false }
70
+
71
+ parser = build_parser(options)
72
+ begin
73
+ parser.parse!(argv)
74
+ rescue OptionParser::ParseError => e
75
+ warn "错误: #{e.message}"
76
+ warn "用法: packbit -f <pcap> [选项] (用 -h 查看完整帮助)"
77
+ return 1
78
+ end
79
+
80
+ return print_help(parser) if options[:help]
81
+ return print_version if options[:version]
82
+
83
+ if options[:file].nil?
84
+ warn "错误: 缺少 pcap 文件路径 (-f)"
85
+ warn "用法: packbit -f <pcap> [选项] (用 -h 查看完整帮助)"
86
+ return 1
87
+ end
88
+
89
+ unless File.exist?(options[:file])
90
+ warn "错误: 文件不存在: #{options[:file]}"
91
+ return 1
92
+ end
93
+
94
+ unless Platform.erlang?
95
+ warn "错误: 未检测到 Erlang escript"
96
+ warn " 请安装 Erlang/OTP:"
97
+ warn " Windows: choco install erlang 或 下载 https://www.erlang.org/downloads"
98
+ warn " Linux: apt install erlang / yum install erlang"
99
+ warn " macOS: brew install erlang"
100
+ return 1
101
+ end
102
+
103
+ invoke_escript(options)
104
+ end
105
+
106
+ def self.invoke_escript(options)
107
+ if Platform.windows?
108
+ q = ->(s) { "\"#{s}\"" }
109
+ else
110
+ q = ->(s) { Shellwords.shellescape(s) }
111
+ end
112
+
113
+ args = ["-f", q.call(options[:file])]
114
+
115
+ cfg = options[:config]
116
+ args += ["-c", q.call(cfg)] if cfg && !cfg.empty? && File.exist?(cfg)
117
+
118
+ args << "-d" if options[:summary]
119
+
120
+ if options[:port] && options[:proto]
121
+ args += ["-p", options[:port].to_s, options[:proto]]
122
+ end
123
+
124
+ escript = Platform.escript_path || "escript"
125
+ cmd = "#{q.call(escript)} #{q.call(ESCRIPT)} #{args.join(' ')}"
126
+
127
+ output = `#{cmd} 2>&1`
128
+ code = $?.exitstatus
129
+
130
+ # Windows 下 Erlang 输出可能为 Latin-1,统一转 UTF-8
131
+ if Platform.windows? && !output.valid_encoding?
132
+ output = output.force_encoding(Encoding::ISO_8859_1)
133
+ .encode(Encoding::UTF_8, invalid: :replace, undef: :replace)
134
+ end
135
+
136
+ puts output
137
+ code
138
+ end
139
+
140
+ def self.build_parser(options)
141
+ OptionParser.new do |opts|
142
+ opts.banner = <<~BAN
143
+ packbit — pcap 抓包解析工具 (Ruby CLI + Erlang 引擎)
144
+
145
+ 通过 YAML 配置文件决定筛选、统计、展示数据包的内容。
146
+ 核心解析由 Erlang 实现,Ruby 负责命令行交互。
147
+
148
+ 用法:
149
+ packbit -f <pcap> # 全量逐字段解析
150
+ packbit -f <pcap> -d # 摘要: 统计表 + 每包一行
151
+ packbit -f <pcap> -c packbit.yml # 按配置文件筛选/统计/展示
152
+ packbit -f <pcap> -p 80 tcp # 按端口+协议筛选
153
+ packbit -f <pcap> -c flow.yml -d # flow 分组统计
154
+ packbit -h # 帮助
155
+
156
+ 选项:
157
+ BAN
158
+ opts.on("-f", "--file FILE", "pcap 文件路径") do |v|
159
+ options[:file] = v
160
+ end
161
+ opts.on("-c", "--config FILE", "YAML 配置文件 (筛选/统计/展示)") do |v|
162
+ options[:config] = v
163
+ end
164
+ opts.on("-d", "--summary", "摘要模式 (统计表 + 每包一行)") do
165
+ options[:summary] = true
166
+ end
167
+ opts.on("-p", "--port PORT", "按端口+协议筛选 (如 -p 80,tcp 或 -p \"80 tcp\")") do |v|
168
+ parts = v.split(/[\s,]+/)
169
+ if parts.size == 2
170
+ options[:port] = parts[0]
171
+ options[:proto] = parts[1]
172
+ else
173
+ warn "错误: -p 需要端口和协议 (如 -p 80,tcp)"
174
+ exit 1
175
+ end
176
+ end
177
+ opts.on("-v", "--version", "显示版本") do
178
+ options[:version] = true
179
+ end
180
+ opts.on("-h", "--help", "显示帮助") do
181
+ options[:help] = true
182
+ end
183
+ end
184
+ end
185
+
186
+ def self.print_help(parser)
187
+ puts parser
188
+ puts ""
189
+ puts "配置文件格式 (packbit.yml):"
190
+ puts " filter:"
191
+ puts " protocol: [tcp, udp] # 按协议筛选"
192
+ puts " port: 80 # 按端口筛选"
193
+ puts " ip: 10.0.0.1 # 按 IP 筛选"
194
+ puts " stats:"
195
+ puts " group_by: stack # stack | protocol | flow | 字段列表"
196
+ puts " # group_by: # 字段列表写法 (多行 - item):"
197
+ puts " # - src_ip"
198
+ puts " # - dst_ip"
199
+ puts " # - src_port"
200
+ puts " # - protocol"
201
+ puts " sort_by: count # count | bytes (按包数或流量排序)"
202
+ puts " top: 10 # 前 N 条, 0=全部"
203
+ puts " sort: desc # desc | asc"
204
+ puts " display:"
205
+ puts " mode: detail # detail | summary"
206
+ puts " fields: [src_ip, dst_ip] # 紧凑模式字段"
207
+ puts " payload: true # 显示载荷"
208
+ puts " color: false # 彩色输出"
209
+ puts ""
210
+ puts "group_by 取值:"
211
+ puts " stack 按协议栈分组 (Ethernet/IPv4/TCP... -> "
212
+ puts " protocol 按顶层协议分组 (TCP/UDP/ARP... )"
213
+ puts " flow 源IP->目的IP 组合 (= [src_ip, dst_ip])"
214
+ puts " 字段列表 任意字段组合, 每行一个 - field_name"
215
+ puts " 可用字段: src_ip dst_ip src_port dst_port"
216
+ puts " protocol ttl header_len ..."
217
+ 0
218
+ end
219
+
220
+ def self.print_version
221
+ puts "packbit #{NetworkInfraUtility::VERSION}"
222
+ 0
223
+ end
224
+ end
225
+ end
226
+
227
+ exit Packbit::CLI.run(ARGV) if File.basename($PROGRAM_NAME) == File.basename(__FILE__)
data/bin/probe ADDED
@@ -0,0 +1,134 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+ # coding: utf-8
4
+ #
5
+ # probe — 网络服务连通性探测命令行工具 (network-infra-utility)
6
+ #
7
+ # 用法:
8
+ # probe <host> [协议...] [选项]
9
+ # probe 10.0.0.1 ssh snmp dns # 探测指定协议
10
+ # probe 10.0.0.1 --all # 探测全部协议
11
+ # probe 10.0.0.1 ssh --timeout 5 # 自定义超时
12
+ # probe 10.0.0.1 snmp --community RO # SNMP 团体名
13
+ # probe 10.0.0.1 --all --json # JSON 输出
14
+ #
15
+ # 选项:
16
+ # -p, --port PORT 覆盖默认端口
17
+ # -t, --timeout SEC 超时(秒), 默认 3
18
+ # --all 探测全部协议
19
+ # --json JSON 输出
20
+ # --community NAME SNMP 团体名 (默认 public)
21
+ # --list 列出全部可用协议
22
+ # -v, --version 显示版本
23
+ # -h, --help 显示帮助
24
+ #
25
+ # 退出码: 0 全部可达, 1 存在失败, 2 参数错误
26
+
27
+ require "optparse"
28
+ require "json"
29
+
30
+ begin
31
+ require "probe"
32
+ rescue LoadError
33
+ $LOAD_PATH.unshift(File.expand_path("../tool/probe/lib", __dir__))
34
+ require "probe"
35
+ end
36
+
37
+ require_relative "../version"
38
+
39
+ module ProbeCLI
40
+ module_function
41
+
42
+ def run(argv)
43
+ options = { timeout: 3, all: false, json: false, port: nil, community: "public", list: false }
44
+ parser = build_parser(options)
45
+
46
+ begin
47
+ parser.parse!(argv)
48
+ rescue OptionParser::ParseError => e
49
+ warn "错误: #{e.message}"
50
+ return 2
51
+ end
52
+
53
+ return print_help(parser) if options[:help]
54
+ return print_version if options[:version]
55
+ return print_protocols if options[:list]
56
+
57
+ if argv.empty?
58
+ warn "错误: 缺少目标主机"
59
+ warn "用法: probe <host> [协议...] [选项] (用 -h 查看完整帮助)"
60
+ return 2
61
+ end
62
+
63
+ host = argv.shift
64
+ protocols = options[:all] ? nil : argv.map(&:to_sym)
65
+ return 2 if protocols && protocols.empty?
66
+
67
+ run_probes(host, protocols, options)
68
+ end
69
+
70
+ def run_probes(host, protocols, options)
71
+ opts = { timeout: options[:timeout].to_f }
72
+ opts[:port] = options[:port].to_i if options[:port]
73
+ opts[:community] = options[:community] if options[:community]
74
+
75
+ results = NetworkInfraUtility::Probe.check(host, protocols: protocols, **opts)
76
+
77
+ if options[:json]
78
+ puts JSON.pretty_generate(results.map(&:to_h))
79
+ else
80
+ results.each { |r| puts r.to_s }
81
+ failed = results.reject(&:ok?)
82
+ puts ""
83
+ puts "结果: #{results.size - failed.size}/#{results.size} 可达"
84
+ end
85
+
86
+ results.any? { |r| !r.ok? } ? 1 : 0
87
+ rescue ArgumentError => e
88
+ warn "错误: #{e.message}"
89
+ 2
90
+ end
91
+
92
+ def build_parser(options)
93
+ OptionParser.new do |opts|
94
+ opts.banner = <<~BAN
95
+ probe — 网络服务连通性探测工具
96
+
97
+ 用法:
98
+ probe <host> [协议...] [选项]
99
+ probe 10.0.0.1 ssh snmp dns
100
+ probe 10.0.0.1 --all
101
+ probe 10.0.0.1 --all --json
102
+
103
+ 可用协议: #{NetworkInfraUtility::Probe.protocols.join(', ')}
104
+
105
+ 选项:
106
+ BAN
107
+ opts.on("-p", "--port PORT", Integer, "覆盖默认端口") { |v| options[:port] = v }
108
+ opts.on("-t", "--timeout SEC", Float, "超时(秒), 默认 3") { |v| options[:timeout] = v }
109
+ opts.on("--all", "探测全部协议") { options[:all] = true }
110
+ opts.on("--json", "JSON 输出") { options[:json] = true }
111
+ opts.on("--community NAME", "SNMP 团体名 (默认 public)") { |v| options[:community] = v }
112
+ opts.on("--list", "列出全部可用协议") { options[:list] = true }
113
+ opts.on("-v", "--version", "显示版本") { options[:version] = true }
114
+ opts.on("-h", "--help", "显示帮助") { options[:help] = true }
115
+ end
116
+ end
117
+
118
+ def print_help(parser)
119
+ puts parser
120
+ 0
121
+ end
122
+
123
+ def print_version
124
+ puts "probe #{NetworkInfraUtility::VERSION}"
125
+ 0
126
+ end
127
+
128
+ def print_protocols
129
+ puts NetworkInfraUtility::Probe.protocols.join(" ")
130
+ 0
131
+ end
132
+ end
133
+
134
+ exit ProbeCLI.run(ARGV) if File.basename($PROGRAM_NAME) == File.basename(__FILE__)