SKILL.md
只读
名称
network-config-validation
描述
路由器与交换机上线前的配置检查工具,涵盖高危命令检测、IP 地址重复、子网重叠、失效引用、管理平面风险以及 IOS 风格的安全规范校验。
Network Config Validation
在变更窗口期前或自动化脚本操作生产设备之前,使用此 Skill 对网络配置进行审查。
使用场景
- 在上线前审查 Cisco IOS 或 IOS-XE 风格的配置片段。
- 审计由脚本或模板自动生成的配置。
- 排查高危命令、重复 IP 地址或子网重叠问题。
- 检查 ACL、route-map、prefix-list 或 line policy 是否存在“引用了但未定义”的情况。
- 为网络自动化构建轻量级的上线前检查(pre-flight)脚本。
工作原理
应将配置校验视为多维度的参考依据,而非完备的语法解析器。正则检查适合用于上线前的预警提示,但最终审定仍需网络工程师亲自核查变更意图、平台特定语法以及回滚步骤。
建议按以下顺序依次校验:
- 破坏性命令。
- 凭据泄露与管理平面暴露风险。
- 地址重复与子网重叠。
- 对 ACL、route-map、prefix-list 和接口的失效引用。
- 运维规范(如 NTP、时间戳、远程日志和登录 Banner)。
高危命令检测
import re
DANGEROUS_PATTERNS: list[tuple[re.Pattern[str], str]] = [
(re.compile(r"\breload\b", re.I), "reload causes downtime"),
(re.compile(r"\berase\s+(startup|nvram|flash)", re.I), "erases persistent storage"),
(re.compile(r"\bformat\b", re.I), "formats a device filesystem"),
(re.compile(r"\bno\s+router\s+(bgp|ospf|eigrp)\b", re.I), "removes a routing process"),
(re.compile(r"\bno\s+interface\s+\S+", re.I), "removes interface configuration"),
(re.compile(r"\baaa\s+new-model\b", re.I), "changes authentication behavior"),
(re.compile(r"\bcrypto\s+key\s+(zeroize|generate)\b", re.I), "changes device SSH keys"),
]
def find_dangerous_commands(lines: list[str]) -> list[dict[str, str | int]]:
findings = []
for line_number, line in enumerate(lines, start=1):
stripped = line.strip()
for pattern, reason in DANGEROUS_PATTERNS:
if pattern.search(stripped):
findings.append({
"line": line_number,
"command": stripped,
"reason": reason,
})
return findings
IP 地址重复与子网重叠检测
import ipaddress
import re
from collections import Counter
IP_ADDRESS_RE = re.compile(
r"^\s*ip address\s+"
r"(?P<ip>\d{1,3}(?:\.\d{1,3}){3})\s+"
r"(?P<mask>\d{1,3}(?:\.\d{1,3}){3})\b",
re.I | re.M,
)
def extract_interfaces(config: str) -> list[dict[str, str]]:
results = []
current = None
for line in config.splitlines():
if line.startswith("interface "):
current = line.split(maxsplit=1)[1]
continue
match = IP_ADDRESS_RE.match(line)
if current and match:
ip = match.group("ip")
mask = match.group("mask")
network = ipaddress.ip_interface(f"{ip}/{mask}").network
results.append({"interface": current, "ip": ip, "network": str(network)})
return results
def find_duplicate_ips(config: str) -> list[str]:
ips = [entry["ip"] for entry in extract_interfaces(config)]
counts = Counter(ips)
return sorted(ip for ip, count in counts.items() if count > 1)
def find_subnet_overlaps(config: str) -> list[tuple[str, str]]:
networks = [ipaddress.ip_network(entry["network"]) for entry in extract_interfaces(config)]
overlaps = []
for index, left in enumerate(networks):
for right in networks[index + 1:]:
if left.overlaps(right):
overlaps.append((str(left), str(right)))
return overlaps
管理平面检查
按 Section 逐块解析 VTY 配置,避免 access-class 检查逻辑误跨到无关行。
import re
def iter_blocks(config: str, starts_with: str) -> list[str]:
blocks = []
current: list[str] = []
for line in config.splitlines():
if line.startswith(starts_with):
if current:
blocks.append("\n".join(current))
current = [line]
continue
if current:
if line and not line.startswith(" "):
blocks.append("\n".join(current))
current = []
else:
current.append(line)
if current:
blocks.append("\n".join(current))
return blocks
def check_vty_blocks(config: str) -> list[str]:
issues = []
for block in iter_blocks(config, "line vty"):
if re.search(r"transport\s+input\s+.*telnet", block, re.I):
issues.append("VTY allows Telnet; require SSH only.")
if not re.search(r"\baccess-class\s+\S+\s+in\b", block, re.I):
issues.append("VTY block has no inbound access-class source restriction.")
if not re.search(r"\bexec-timeout\s+\d+\s+\d+\b", block, re.I):
issues.append("VTY block has no explicit exec-timeout.")
return issues
安全规范检查
SECURITY_PATTERNS = [
(re.compile(r"\bsnmp-server community\s+(public|private)\b", re.I),
"default SNMP community configured"),
(re.compile(r"\bsnmp-server community\s+\S+", re.I),
"SNMPv2 community string configured; prefer SNMPv3 authPriv"),
(re.compile(r"\bip ssh version 1\b", re.I),
"SSH version 1 enabled"),
(re.compile(r"\benable password\b", re.I),
"enable password is present; use enable secret"),
(re.compile(r"\busername\s+\S+\s+password\b", re.I),
"local username uses password instead of secret"),
]
BEST_PRACTICE_PATTERNS = [
(re.compile(r"\bntp server\b", re.I), "NTP server"),
(re.compile(r"\bservice timestamps\b", re.I), "log timestamps"),
(re.compile(r"\blogging\s+\S+", re.I), "logging destination or buffer"),
(re.compile(r"\bsnmp-server group\s+\S+\s+v3\s+priv\b", re.I), "SNMPv3 authPriv group"),
(re.compile(r"\bbanner\s+(login|motd)\b", re.I), "login banner"),
]
def check_security(config: str) -> list[str]:
return [message for pattern, message in SECURITY_PATTERNS if pattern.search(config)]
def check_missing_hygiene(config: str) -> list[str]:
return [
f"Missing {description}"
for pattern, description in BEST_PRACTICE_PATTERNS
if not pattern.search(config)
]
常用示例
变更窗口前置检查
- 对即将粘贴入设备的配置片段进行高危命令检查。
- 对完整的拟上线配置进行 IP 地址重复及子网重叠检查。
- 确认所引用的每个 ACL、route-map 和 prefix-list 均已定义。
- 在对管理平面进行任何变更前,务必确认回滚命令及带外管理通道正常可用。
自动化上线前置检查
在 Netmiko、NAPALM、Ansible 或厂商 API 自动化工具推送生成的配置之前,将此校验作为阻断式关卡(blocking gate)。凡触及高危命令或明文凭据风险时直接挂断阻断;对于不在本次变更范围内的最佳实践缺失,提示警告即可。
反模式(避坑指南)
- 把正则校验当成完整的设备语法解析器使用。
- 未经 dry-run 对比 diff 就直接下发生成的配置。
- 将 SNMPv2 Community String 作为监控的硬性推荐方案。
- 使用可能意外跨越无关 Section 的正则表达式去匹配 VTY 配置块。
- 靠禁用 ACL 而不是查看计数器/日志来排查防火墙行为。
参见
- Agent:
network-config-reviewer - Agent:
network-troubleshooter - Skill:
network-interface-health






