From 3ce69dbe2dc6d16bea5029e1377a6babaaf15efb Mon Sep 17 00:00:00 2001 From: MiaoMint <44718819+MiaoMint@users.noreply.github.com> Date: Tue, 23 Sep 2025 01:47:48 +0800 Subject: [PATCH] first commit --- .gitignore | 57 ++++++ Makefile | 100 ++++++++++ README.md | 145 ++++++++++++++ cmd/port-manager/main.go | 139 +++++++++++++ go.mod | 3 + go.sum | 0 internal/scanner/port_scanner.go | 218 +++++++++++++++++++++ internal/service/identifier.go | 180 +++++++++++++++++ internal/web/server.go | 324 +++++++++++++++++++++++++++++++ pkg/types/port.go | 31 +++ 10 files changed, 1197 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 README.md create mode 100644 cmd/port-manager/main.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 internal/scanner/port_scanner.go create mode 100644 internal/service/identifier.go create mode 100644 internal/web/server.go create mode 100644 pkg/types/port.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..deaa385 --- /dev/null +++ b/.gitignore @@ -0,0 +1,57 @@ +# 编译输出 +bin/ +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Go 测试输出 +*.test +*.out + +# Go 依赖模块 +go.work +go.work.sum + +# Go 构建缓存 +.cache/ + +# IDE 文件 +.vscode/ +.idea/ +*.swp +*.swo + +# macOS +.DS_Store + +# 日志文件 +*.log + +# 临时文件 +*.tmp +*.temp +.tmp/ + +# 环境变量文件 +.env +.env.local +.env.*.local + +# 备份文件 +*.bak +*.backup + +# 编译器输出 +*.i*86 +*.x86_64 +*.hex + +# Debug 文件 +debug +debug.test +main + +# Vendor 目录 (如果使用 vendor) +vendor/ \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..be7d0d4 --- /dev/null +++ b/Makefile @@ -0,0 +1,100 @@ +# Port Manager Makefile + +.PHONY: build run clean test help scan random install + +# 默认目标 +all: build + +# 构建可执行文件 +build: + @echo "🔨 构建 Port Manager..." + @mkdir -p bin + @go build -o bin/port-manager cmd/port-manager/main.go + @echo "✅ 构建完成: bin/port-manager" + +# 运行Web服务器(默认端口8080) +run: build + @echo "🚀 启动 Port Manager Web 界面..." + @./bin/port-manager + +# 运行Web服务器在指定端口 +run-port: build + @echo "🚀 启动 Port Manager Web 界面 (端口: $(PORT))..." + @./bin/port-manager -port $(PORT) + +# 仅扫描端口 +scan: build + @./bin/port-manager -scan + +# 生成随机端口 +random: build + @./bin/port-manager -random + +# 生成指定范围的随机端口 +random-range: build + @./bin/port-manager -random -min $(MIN) -max $(MAX) + +# 清理构建文件 +clean: + @echo "🧹 清理构建文件..." + @rm -rf bin/ + @go clean + @echo "✅ 清理完成" + +# 运行测试 +test: + @echo "🧪 运行测试..." + @go test ./... + +# 格式化代码 +fmt: + @echo "📝 格式化代码..." + @go fmt ./... + +# 代码检查 +vet: + @echo "🔍 代码检查..." + @go vet ./... + +# 更新依赖 +mod-tidy: + @echo "📦 更新依赖..." + @go mod tidy + +# 安装到系统 +install: build + @echo "📥 安装到系统..." + @sudo cp bin/port-manager /usr/local/bin/ + @echo "✅ 安装完成: /usr/local/bin/port-manager" + +# 显示帮助 +help: + @echo "Port Manager - NAS 端口管理工具" + @echo "" + @echo "可用命令:" + @echo " make build - 构建可执行文件" + @echo " make run - 运行Web界面 (默认端口8080)" + @echo " make run-port PORT=9000 - 在指定端口运行Web界面" + @echo " make scan - 扫描端口并显示结果" + @echo " make random - 生成随机可用端口" + @echo " make random-range MIN=3000 MAX=4000 - 生成指定范围随机端口" + @echo " make clean - 清理构建文件" + @echo " make test - 运行测试" + @echo " make fmt - 格式化代码" + @echo " make vet - 代码检查" + @echo " make mod-tidy - 更新依赖" + @echo " make install - 安装到系统" + @echo " make help - 显示此帮助" + @echo "" + @echo "示例:" + @echo " make run # 启动Web界面" + @echo " make run-port PORT=9000 # 在端口9000启动" + @echo " make random-range MIN=3000 MAX=4000 # 生成3000-4000范围内的随机端口" + +# 开发环境设置 +dev-setup: + @echo "🛠️ 设置开发环境..." + @go mod tidy + @go fmt ./... + @go vet ./... + @echo "✅ 开发环境设置完成" \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..0ba1998 --- /dev/null +++ b/README.md @@ -0,0 +1,145 @@ +# Port Manager + +一个用于 NAS 的端口管理工具,可以很方便的检查系统当前已经占用的端口,和识别服务。可以用作服务的快速入口(导航)也可以作为选择困难症的随机端口生成器。 + +## 主要功能 + +- 🔍 扫描本地已经占用的端口 +- 🎯 识别端口所对应的服务 +- 🚀 快速访问服务 (Web界面导航) +- 🎲 随机生成一个非占用的端口 +- 📱 现代化的Web界面 +- 💻 命令行模式支持 + +## 安装和使用 + +### 从源码构建 + +```bash +git clone https://github.com/miaomint/port-manager.git +cd port-manager +go mod tidy +go build -o bin/port-manager cmd/port-manager/main.go +``` + +### 使用方法 + +#### 1. Web界面模式(推荐) + +```bash +# 默认在8080端口启动Web界面 +./bin/port-manager + +# 指定端口启动 +./bin/port-manager -port 9000 +``` + +然后在浏览器中访问 `http://localhost:8080` + +#### 2. 命令行模式 + +```bash +# 扫描端口并在终端显示 +./bin/port-manager -scan + +# 生成随机可用端口 +./bin/port-manager -random + +# 在指定范围内生成随机端口 +./bin/port-manager -random -min 3000 -max 4000 + +# 查看帮助 +./bin/port-manager -help +``` + +## 支持的服务识别 + +本工具内置了常见服务的端口识别,包括: + +### Web服务 +- HTTP (80, 8080, 3000, 4000, 5000, 8000) +- HTTPS (443, 8443, 5001) +- 开发服务器 (React, Node.js, Flask, Django等) + +### 数据库 +- MySQL (3306) +- PostgreSQL (5432) +- MongoDB (27017) +- Redis (6379) +- Memcached (11211) + +### NAS相关 +- Synology DSM (5000, 5001) +- SMB/CIFS (445) +- AFP (548) +- NFS (2049) +- 常见下载工具 (Sonarr, Radarr, Jackett等) + +### 开发工具 +- Grafana (3001) +- Prometheus (9090) +- Elasticsearch (9200) +- Kibana (5601) +- Jupyter (8888) + +### 其他 +- SSH (22) +- FTP (21) +- DNS (53) +- 等等... + +## 项目结构 + +本项目遵循标准的 Go 项目结构: + +``` +port-manager/ +├── cmd/ +│ └── port-manager/ # 主程序入口 +│ └── main.go +├── internal/ # 内部包,不对外暴露 +│ ├── scanner/ # 端口扫描功能 +│ ├── service/ # 服务识别功能 +│ └── web/ # Web服务器 +├── pkg/ # 可被外部使用的包 +│ └── types/ # 类型定义 +├── go.mod +├── go.sum +└── README.md +``` + +## Web界面特性 + +- 📊 实时端口扫描 +- 🎨 现代化响应式设计 +- 🔗 一键访问已识别的Web服务 +- 🎲 随机端口生成器 +- 📱 移动端友好 +- ⚡ 快速加载 + +## 开发 + +### 依赖 + +- Go 1.21+ +- 仅使用标准库,无外部依赖 + +### 运行开发版本 + +```bash +go run cmd/port-manager/main.go +``` + +### 运行测试 + +```bash +go test ./... +``` + +## 贡献 + +欢迎提交 Issue 和 Pull Request! + +## 许可证 + +MIT License diff --git a/cmd/port-manager/main.go b/cmd/port-manager/main.go new file mode 100644 index 0000000..1343a3c --- /dev/null +++ b/cmd/port-manager/main.go @@ -0,0 +1,139 @@ +package main + +import ( + "flag" + "fmt" + "log" + + "github.com/miaomint/port-manager/internal/scanner" + "github.com/miaomint/port-manager/internal/service" + "github.com/miaomint/port-manager/internal/web" +) + +func main() { + var ( + webPort = flag.Int("port", 8080, "Web服务器端口") + scanOnly = flag.Bool("scan", false, "仅扫描端口并输出结果") + randomPort = flag.Bool("random", false, "生成随机可用端口") + minPort = flag.Int("min", 8000, "随机端口最小值") + maxPort = flag.Int("max", 9999, "随机端口最大值") + showHelp = flag.Bool("help", false, "显示帮助信息") + ) + + flag.Parse() + + if *showHelp { + showUsage() + return + } + + // 创建扫描器和识别器 + portScanner := scanner.NewPortScanner(true, false) + serviceIdentifier := service.NewServiceIdentifier() + + // 仅扫描模式 + if *scanOnly { + fmt.Println("🔍 正在扫描本地端口...") + result, err := portScanner.ScanPorts() + if err != nil { + log.Fatalf("扫描失败: %v", err) + } + + fmt.Printf("\n📊 扫描结果 (共发现 %d 个端口):\n", result.TotalPorts) + fmt.Println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━") + fmt.Printf("%-8s %-10s %-12s %-30s %-s\n", "端口", "协议", "状态", "服务名称", "访问地址") + fmt.Println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━") + + for _, port := range result.Ports { + identified := serviceIdentifier.IdentifyService(&port) + serviceURL := identified.ServiceURL + if serviceURL == "" { + serviceURL = "-" + } + fmt.Printf("%-8d %-10s %-12s %-30s %-s\n", + identified.Port, + identified.Protocol, + identified.State, + identified.ServiceName, + serviceURL, + ) + } + return + } + + // 随机端口生成模式 + if *randomPort { + fmt.Printf("🎲 正在生成随机可用端口 (范围: %d-%d)...\n", *minPort, *maxPort) + port, err := portScanner.GenerateRandomPort(*minPort, *maxPort) + if err != nil { + log.Fatalf("生成随机端口失败: %v", err) + } + fmt.Printf("🎯 可用端口: %d\n", port) + return + } + + // Web服务器模式(默认) + fmt.Println("🚀 启动端口管理器...") + fmt.Printf("📱 Web界面: http://localhost:%d\n", *webPort) + fmt.Println("💡 使用 --help 查看更多选项") + fmt.Println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━") + + server := web.NewServer() + if err := server.Start(*webPort); err != nil { + log.Fatalf("启动Web服务器失败: %v", err) + } +} + +func showUsage() { + fmt.Println(` +🔌 NAS 端口管理器 +================ + +一个用于NAS的端口管理工具,可以方便地检查系统当前已经占用的端口,识别服务, +提供快速访问入口,也可以作为随机端口生成器。 + +使用方法: + port-manager [选项] + +选项: + -port int + Web服务器端口 (默认: 8080) + -scan + 仅扫描端口并输出结果,不启动Web服务器 + -random + 生成一个随机可用端口 + -min int + 随机端口最小值 (默认: 8000) + -max int + 随机端口最大值 (默认: 9999) + -help + 显示此帮助信息 + +示例: + # 启动Web界面 (默认端口8080) + port-manager + + # 在指定端口启动Web界面 + port-manager -port 9000 + + # 仅扫描端口并输出到终端 + port-manager -scan + + # 生成随机可用端口 + port-manager -random + + # 在指定范围内生成随机端口 + port-manager -random -min 3000 -max 4000 + +功能特性: + ✅ 扫描本地已占用端口 + ✅ 识别端口对应的服务 + ✅ 提供Web界面快速访问服务 + ✅ 生成随机可用端口 + ✅ 支持常见NAS服务识别 + ✅ 响应式Web界面设计 + +更多信息: + 项目地址: https://github.com/miaomint/port-manager +`) +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..1e54332 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/miaomint/port-manager + +go 1.21 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..e69de29 diff --git a/internal/scanner/port_scanner.go b/internal/scanner/port_scanner.go new file mode 100644 index 0000000..5500faf --- /dev/null +++ b/internal/scanner/port_scanner.go @@ -0,0 +1,218 @@ +package scanner + +import ( + "bufio" + "fmt" + "net" + "os/exec" + "regexp" + "strconv" + "strings" + "time" + + "github.com/miaomint/port-manager/pkg/types" +) + +// PortScanner 端口扫描器 +type PortScanner struct { + includeListening bool + includeEstablished bool +} + +// NewPortScanner 创建新的端口扫描器 +func NewPortScanner(includeListening, includeEstablished bool) *PortScanner { + return &PortScanner{ + includeListening: includeListening, + includeEstablished: includeEstablished, + } +} + +// ScanPorts 扫描本地端口 +func (ps *PortScanner) ScanPorts() (*types.ScanResult, error) { + var ports []types.PortInfo + + // 获取TCP端口 + tcpPorts, err := ps.scanTCPPorts() + if err != nil { + return nil, fmt.Errorf("扫描TCP端口失败: %v", err) + } + ports = append(ports, tcpPorts...) + + // 获取UDP端口 + udpPorts, err := ps.scanUDPPorts() + if err != nil { + return nil, fmt.Errorf("扫描UDP端口失败: %v", err) + } + ports = append(ports, udpPorts...) + + return &types.ScanResult{ + Ports: ports, + Timestamp: time.Now(), + TotalPorts: len(ports), + }, nil +} + +// scanTCPPorts 扫描TCP端口(使用netstat) +func (ps *PortScanner) scanTCPPorts() ([]types.PortInfo, error) { + var args []string + args = append(args, "-an") + args = append(args, "-p", "tcp") + + cmd := exec.Command("netstat", args...) + output, err := cmd.Output() + if err != nil { + return nil, err + } + + return ps.parseNetstatOutput(string(output), "tcp") +} + +// scanUDPPorts 扫描UDP端口 +func (ps *PortScanner) scanUDPPorts() ([]types.PortInfo, error) { + var args []string + args = append(args, "-an") + args = append(args, "-p", "udp") + + cmd := exec.Command("netstat", args...) + output, err := cmd.Output() + if err != nil { + return nil, err + } + + return ps.parseNetstatOutput(string(output), "udp") +} + +// parseNetstatOutput 解析netstat输出 +func (ps *PortScanner) parseNetstatOutput(output, protocol string) ([]types.PortInfo, error) { + var ports []types.PortInfo + scanner := bufio.NewScanner(strings.NewReader(output)) + + // 跳过标题行 + for scanner.Scan() { + line := scanner.Text() + if strings.Contains(line, "Local Address") { + break + } + } + + // 解析每一行 + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) + if line == "" { + continue + } + + port, err := ps.parseNetstatLine(line, protocol) + if err != nil { + continue // 跳过解析失败的行 + } + + if port != nil { + // 过滤状态 + if ps.shouldIncludePort(port) { + ports = append(ports, *port) + } + } + } + + return ports, nil +} + +// parseNetstatLine 解析netstat的单行输出 +func (ps *PortScanner) parseNetstatLine(line, protocol string) (*types.PortInfo, error) { + fields := regexp.MustCompile(`\s+`).Split(line, -1) + if len(fields) < 3 { + return nil, fmt.Errorf("invalid line format") + } + + // 解析本地地址 + localAddr := fields[0] + parts := strings.Split(localAddr, ":") + if len(parts) < 2 { + return nil, fmt.Errorf("invalid address format") + } + + portStr := parts[len(parts)-1] + port, err := strconv.Atoi(portStr) + if err != nil { + return nil, fmt.Errorf("invalid port: %s", portStr) + } + + state := "" + if protocol == "tcp" && len(fields) >= 4 { + state = fields[3] + } + + return &types.PortInfo{ + Port: port, + Protocol: protocol, + State: state, + LastSeen: time.Now(), + }, nil +} + +// shouldIncludePort 判断是否应该包含此端口 +func (ps *PortScanner) shouldIncludePort(port *types.PortInfo) bool { + if port.Protocol == "tcp" { + if port.State == "LISTEN" { + return ps.includeListening + } + if port.State == "ESTABLISHED" { + return ps.includeEstablished + } + } + + // UDP端口默认包含 + if port.Protocol == "udp" { + return ps.includeListening + } + + return false +} + +// ScanPortRange 扫描指定端口范围 +func (ps *PortScanner) ScanPortRange(start, end int) ([]int, error) { + var openPorts []int + + for port := start; port <= end; port++ { + // TCP扫描 + conn, err := net.DialTimeout("tcp", fmt.Sprintf("localhost:%d", port), time.Millisecond*100) + if err == nil { + conn.Close() + openPorts = append(openPorts, port) + } + } + + return openPorts, nil +} + +// IsPortOpen 检查指定端口是否开放 +func (ps *PortScanner) IsPortOpen(port int, protocol string) bool { + address := fmt.Sprintf("localhost:%d", port) + conn, err := net.DialTimeout(protocol, address, time.Millisecond*100) + if err != nil { + return false + } + conn.Close() + return true +} + +// GenerateRandomPort 生成一个未被占用的随机端口 +func (ps *PortScanner) GenerateRandomPort(minPort, maxPort int) (int, error) { + if minPort <= 0 { + minPort = 8000 + } + if maxPort <= 0 || maxPort > 65535 { + maxPort = 65535 + } + + for attempts := 0; attempts < 100; attempts++ { + port := minPort + (int(time.Now().UnixNano()) % (maxPort - minPort + 1)) + + if !ps.IsPortOpen(port, "tcp") { + return port, nil + } + } + + return 0, fmt.Errorf("无法找到可用端口") +} diff --git a/internal/service/identifier.go b/internal/service/identifier.go new file mode 100644 index 0000000..ace2c43 --- /dev/null +++ b/internal/service/identifier.go @@ -0,0 +1,180 @@ +package service + +import ( + "fmt" + "net/http" + "time" + + "github.com/miaomint/port-manager/pkg/types" +) + +// ServiceIdentifier 服务识别器 +type ServiceIdentifier struct { + wellKnownPorts map[int]types.ServiceMapping +} + +// NewServiceIdentifier 创建新的服务识别器 +func NewServiceIdentifier() *ServiceIdentifier { + return &ServiceIdentifier{ + wellKnownPorts: initWellKnownPorts(), + } +} + +// IdentifyService 识别端口对应的服务 +func (si *ServiceIdentifier) IdentifyService(port *types.PortInfo) *types.PortInfo { + // 复制端口信息 + result := *port + + // 查找已知服务 + if mapping, exists := si.wellKnownPorts[port.Port]; exists { + result.ServiceName = mapping.ServiceName + + // 如果是HTTP/HTTPS服务,尝试构建访问URL + if mapping.IsHTTP || mapping.IsHTTPS { + protocol := "http" + if mapping.IsHTTPS { + protocol = "https" + } + result.ServiceURL = fmt.Sprintf("%s://localhost:%d", protocol, port.Port) + + // 验证HTTP服务是否可访问 + if si.isHTTPServiceActive(result.ServiceURL) { + result.ServiceName = fmt.Sprintf("%s (可访问)", result.ServiceName) + } + } + } else { + // 尝试探测HTTP服务 + if si.probeHTTPService(port.Port) { + result.ServiceName = "HTTP服务" + result.ServiceURL = fmt.Sprintf("http://localhost:%d", port.Port) + } else if si.probeHTTPSService(port.Port) { + result.ServiceName = "HTTPS服务" + result.ServiceURL = fmt.Sprintf("https://localhost:%d", port.Port) + } else { + result.ServiceName = "未知服务" + } + } + + return &result +} + +// probeHTTPService 探测HTTP服务 +func (si *ServiceIdentifier) probeHTTPService(port int) bool { + url := fmt.Sprintf("http://localhost:%d", port) + return si.isHTTPServiceActive(url) +} + +// probeHTTPSService 探测HTTPS服务 +func (si *ServiceIdentifier) probeHTTPSService(port int) bool { + url := fmt.Sprintf("https://localhost:%d", port) + return si.isHTTPServiceActive(url) +} + +// isHTTPServiceActive 检查HTTP服务是否活跃 +func (si *ServiceIdentifier) isHTTPServiceActive(url string) bool { + client := &http.Client{ + Timeout: 2 * time.Second, + } + + resp, err := client.Get(url) + if err != nil { + return false + } + defer resp.Body.Close() + + // 任何HTTP响应都认为是活跃的HTTP服务 + return true +} + +// initWellKnownPorts 初始化已知端口映射 +func initWellKnownPorts() map[int]types.ServiceMapping { + return map[int]types.ServiceMapping{ + // Web服务 + 80: {Port: 80, ServiceName: "HTTP", Description: "超文本传输协议", IsHTTP: true}, + 443: {Port: 443, ServiceName: "HTTPS", Description: "安全超文本传输协议", IsHTTPS: true}, + 8080: {Port: 8080, ServiceName: "HTTP代理", Description: "HTTP代理服务", IsHTTP: true}, + 8443: {Port: 8443, ServiceName: "HTTPS代理", Description: "HTTPS代理服务", IsHTTPS: true}, + 3000: {Port: 3000, ServiceName: "开发服务器", Description: "React/Node.js开发服务器", IsHTTP: true}, + 3001: {Port: 3001, ServiceName: "开发服务器", Description: "开发服务器", IsHTTP: true}, + 4000: {Port: 4000, ServiceName: "开发服务器", Description: "Jekyll/Hugo开发服务器", IsHTTP: true}, + 8000: {Port: 8000, ServiceName: "HTTP服务", Description: "Python HTTP服务器", IsHTTP: true}, + 9000: {Port: 9000, ServiceName: "PHP-FPM", Description: "PHP FastCGI Process Manager", IsHTTP: true}, + + // 数据库 + 3306: {Port: 3306, ServiceName: "MySQL", Description: "MySQL数据库服务器"}, + 5432: {Port: 5432, ServiceName: "PostgreSQL", Description: "PostgreSQL数据库服务器"}, + 27017: {Port: 27017, ServiceName: "MongoDB", Description: "MongoDB数据库服务器"}, + 6379: {Port: 6379, ServiceName: "Redis", Description: "Redis内存数据库"}, + 11211: {Port: 11211, ServiceName: "Memcached", Description: "Memcached缓存服务器"}, + + // 远程访问 + 22: {Port: 22, ServiceName: "SSH", Description: "安全外壳协议"}, + 23: {Port: 23, ServiceName: "Telnet", Description: "远程登录协议"}, + 3389: {Port: 3389, ServiceName: "RDP", Description: "远程桌面协议"}, + 5900: {Port: 5900, ServiceName: "VNC", Description: "虚拟网络计算"}, + + // 邮件服务 + 25: {Port: 25, ServiceName: "SMTP", Description: "简单邮件传输协议"}, + 110: {Port: 110, ServiceName: "POP3", Description: "邮局协议版本3"}, + 143: {Port: 143, ServiceName: "IMAP", Description: "互联网消息访问协议"}, + 465: {Port: 465, ServiceName: "SMTPS", Description: "安全SMTP"}, + 587: {Port: 587, ServiceName: "SMTP-Submission", Description: "邮件提交"}, + 993: {Port: 993, ServiceName: "IMAPS", Description: "安全IMAP"}, + 995: {Port: 995, ServiceName: "POP3S", Description: "安全POP3"}, + + // FTP + 20: {Port: 20, ServiceName: "FTP-Data", Description: "文件传输协议数据"}, + 21: {Port: 21, ServiceName: "FTP", Description: "文件传输协议"}, + + // DNS + 53: {Port: 53, ServiceName: "DNS", Description: "域名系统"}, + + // DHCP + 67: {Port: 67, ServiceName: "DHCP-Server", Description: "动态主机配置协议服务器"}, + 68: {Port: 68, ServiceName: "DHCP-Client", Description: "动态主机配置协议客户端"}, + + // NTP + 123: {Port: 123, ServiceName: "NTP", Description: "网络时间协议"}, + + // SNMP + 161: {Port: 161, ServiceName: "SNMP", Description: "简单网络管理协议"}, + 162: {Port: 162, ServiceName: "SNMP-Trap", Description: "SNMP陷阱"}, + + // LDAP + 389: {Port: 389, ServiceName: "LDAP", Description: "轻量目录访问协议"}, + 636: {Port: 636, ServiceName: "LDAPS", Description: "安全LDAP"}, + + // NAS相关服务 + 139: {Port: 139, ServiceName: "NetBIOS-SSN", Description: "NetBIOS会话服务"}, + 445: {Port: 445, ServiceName: "SMB", Description: "服务器消息块"}, + 548: {Port: 548, ServiceName: "AFP", Description: "Apple文件协议"}, + 2049: {Port: 2049, ServiceName: "NFS", Description: "网络文件系统"}, + + // 开发工具 + 9090: {Port: 9090, ServiceName: "Prometheus", Description: "Prometheus监控系统", IsHTTP: true}, + 5601: {Port: 5601, ServiceName: "Kibana", Description: "Kibana可视化平台", IsHTTP: true}, + 9200: {Port: 9200, ServiceName: "Elasticsearch", Description: "Elasticsearch搜索引擎", IsHTTP: true}, + 8888: {Port: 8888, ServiceName: "Jupyter", Description: "Jupyter Notebook", IsHTTP: true}, + 4040: {Port: 4040, ServiceName: "Spark UI", Description: "Apache Spark Web UI", IsHTTP: true}, + + // 消息队列 + 5672: {Port: 5672, ServiceName: "RabbitMQ", Description: "RabbitMQ消息队列"}, + 15672: {Port: 15672, ServiceName: "RabbitMQ管理", Description: "RabbitMQ管理界面", IsHTTP: true}, + 9092: {Port: 9092, ServiceName: "Kafka", Description: "Apache Kafka"}, + + // 容器和编排 + 2375: {Port: 2375, ServiceName: "Docker", Description: "Docker守护进程(非安全)"}, + 2376: {Port: 2376, ServiceName: "Docker", Description: "Docker守护进程(TLS)"}, + 6443: {Port: 6443, ServiceName: "Kubernetes API", Description: "Kubernetes API服务器"}, + 10250: {Port: 10250, ServiceName: "kubelet", Description: "Kubernetes kubelet"}, + + // Synology NAS特定端口 + 5000: {Port: 5000, ServiceName: "DSM", Description: "Synology DiskStation Manager", IsHTTP: true}, + 5001: {Port: 5001, ServiceName: "DSM (HTTPS)", Description: "Synology DiskStation Manager", IsHTTPS: true}, + 6690: {Port: 6690, ServiceName: "Cloud Station", Description: "Synology Cloud Station"}, + 9117: {Port: 9117, ServiceName: "Jackett", Description: "Jackett种子搜索", IsHTTP: true}, + 8989: {Port: 8989, ServiceName: "Sonarr", Description: "Sonarr自动下载", IsHTTP: true}, + 7878: {Port: 7878, ServiceName: "Radarr", Description: "Radarr电影下载", IsHTTP: true}, + 8686: {Port: 8686, ServiceName: "Lidarr", Description: "Lidarr音乐下载", IsHTTP: true}, + } +} diff --git a/internal/web/server.go b/internal/web/server.go new file mode 100644 index 0000000..f8683f8 --- /dev/null +++ b/internal/web/server.go @@ -0,0 +1,324 @@ +package web + +import ( + "encoding/json" + "fmt" + "net/http" + "strconv" + + "github.com/miaomint/port-manager/internal/scanner" + "github.com/miaomint/port-manager/internal/service" +) + +// Server Web服务器 +type Server struct { + scanner *scanner.PortScanner + identifier *service.ServiceIdentifier +} + +// NewServer 创建新的Web服务器 +func NewServer() *Server { + return &Server{ + scanner: scanner.NewPortScanner(true, false), // 只显示监听端口 + identifier: service.NewServiceIdentifier(), + } +} + +// Start 启动Web服务器 +func (s *Server) Start(port int) error { + mux := http.NewServeMux() + + // 静态文件路由 + mux.HandleFunc("/", s.indexHandler) + mux.HandleFunc("/api/ports", s.portsAPIHandler) + mux.HandleFunc("/api/random-port", s.randomPortHandler) + mux.HandleFunc("/api/scan-range", s.scanRangeHandler) + + fmt.Printf("端口管理器启动在: http://localhost:%d\n", port) + return http.ListenAndServe(fmt.Sprintf(":%d", port), mux) +} + +// indexHandler 主页处理器 +func (s *Server) indexHandler(w http.ResponseWriter, r *http.Request) { + tmpl := ` + +
+ + +