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.
- checksums.yaml +4 -4
- data/.gitignore +6 -0
- data/CHANGELOG.md +31 -0
- data/GUIDE.md +201 -212
- data/README.md +1 -6
- data/Rakefile +1 -1
- data/bin/gen-get +144 -0
- data/bin/geo-api +40 -1
- data/bin/geo-get +18 -36
- data/bin/ngeo-get +253 -0
- data/bin/packbit +227 -0
- data/bin/probe +134 -0
- data/document/reference/DNS/346/212/200/346/234/257/346/226/207/346/241/243.md +912 -0
- data/network-infra-utility.gemspec +6 -4
- data/network.rb +19 -1
- data/service/geodb/GeoAPI.md +64 -0
- data/service/geodb/api.rb +77 -19
- data/service/geoquery/GeoQuery.md +309 -0
- data/service/geoquery/cache.rb +78 -0
- data/service/geoquery/geo_cache.rb +233 -0
- data/service/geoquery/geoquery.rb +327 -0
- data/service/geoquery/local.rb +151 -0
- data/service/geoquery/merge.rb +52 -0
- data/service/geoquery/normalize.rb +102 -0
- data/service/geoquery/online.rb +136 -0
- data/service/simlab/SimLab.md +140 -0
- data/service/simlab/bin/simctl +152 -0
- data/service/simlab/lib/simlab.rb +124 -0
- data/service/simlab/lib/simlab_engine.rb +146 -0
- data/service/simlab/lib/simlab_observer.rb +176 -0
- data/service/simlab/lib/simlab_router.rb +330 -0
- data/service/simlab/lib/simlab_scenario.rb +200 -0
- data/service/simlab/lib/simlab_switch.rb +182 -0
- data/service/simlab/lib/simlab_topology.rb +196 -0
- data/service/simlab/lib/simlab_traffic.rb +167 -0
- data/support/basic/packet.rb +167 -0
- data/support/routing/bgp.rb +279 -0
- data/support/routing/lpm_trie.rb +145 -0
- data/support/routing/ospf.rb +243 -0
- data/support/routing/prefix.rb +155 -0
- data/support/routing/rib.rb +167 -0
- data/support/routing/rip.rb +223 -0
- data/support/routing/static_route.rb +102 -0
- data/support/switching/frame_forward.rb +87 -0
- data/support/switching/mac_table.rb +127 -0
- data/support/switching/stp.rb +230 -0
- data/support/switching/vlan.rb +155 -0
- data/tool/packbit/README.md +136 -0
- data/tool/packbit/config/five-tuple.yml +25 -0
- data/tool/packbit/config/flow.yml +17 -0
- data/tool/packbit/config/packbit.yml +41 -0
- data/tool/packbit/erl/packbit.erl +588 -0
- data/tool/probe/README.md +88 -0
- data/tool/probe/lib/probe.rb +54 -0
- data/tool/probe/lib/probe_base.rb +98 -0
- data/tool/probe/lib/probe_dns.rb +64 -0
- data/tool/probe/lib/probe_icmp.rb +71 -0
- data/tool/probe/lib/probe_ntp.rb +51 -0
- data/tool/probe/lib/probe_radius.rb +58 -0
- data/tool/probe/lib/probe_registry.rb +44 -0
- data/tool/probe/lib/probe_result.rb +75 -0
- data/tool/probe/lib/probe_snmp.rb +114 -0
- data/tool/probe/lib/probe_tcp.rb +82 -0
- data/tool/probe/lib/probe_version.rb +7 -0
- data/tool/webssh/README.md +42 -0
- data/tool/webssh/app.py +788 -0
- data/tool/webssh/cli.bat +17 -0
- data/tool/webssh/config.yml.template +84 -0
- data/tool/webssh/extension//350/256/276/345/244/207/350/257/212/346/226/255.md +103 -0
- data/tool/webssh/requirements.txt +7 -0
- data/tool/webssh/ssh_cli.py +449 -0
- data/tool/webssh/ssh_worker.py +782 -0
- data/tool/webssh/static/vendor/xterm-addon-fit.min.js +8 -0
- data/tool/webssh/static/vendor/xterm.css +209 -0
- data/tool/webssh/static/vendor/xterm.min.js +8 -0
- data/tool/webssh/templates/index.html +2674 -0
- data/tool/webssh/web.bat +41 -0
- data/version.rb +1 -1
- 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__)
|