├── images ├── p5.png ├── p1@2x.png ├── p2@2x.png ├── p3@2x.png └── p4@2x.png ├── go.mod ├── go.sum ├── .gitignore ├── test.sh ├── ssl_example.md ├── test_ssl.sh ├── Makefile ├── README.md └── main.go /images/p5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiguangsdf/netcat/HEAD/images/p5.png -------------------------------------------------------------------------------- /images/p1@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiguangsdf/netcat/HEAD/images/p1@2x.png -------------------------------------------------------------------------------- /images/p2@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiguangsdf/netcat/HEAD/images/p2@2x.png -------------------------------------------------------------------------------- /images/p3@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiguangsdf/netcat/HEAD/images/p3@2x.png -------------------------------------------------------------------------------- /images/p4@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiguangsdf/netcat/HEAD/images/p4@2x.png -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/jiguangsdf/netcat 2 | 3 | go 1.23.0 4 | 5 | toolchain go1.23.2 6 | 7 | require golang.org/x/text v0.27.0 8 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= 2 | golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # mac 2 | .DS_Store 3 | 4 | # local env files 5 | .env.local 6 | .env.*.local 7 | 8 | # Editor directories and files 9 | .idea 10 | .vscode 11 | *.suo 12 | *.ntvs* 13 | *.njsproj 14 | *.sln 15 | *.sw? 16 | 17 | # build 18 | build 19 | 20 | # node_moules 21 | **/node_modules/ 22 | **/.cache 23 | **/dist 24 | 25 | # vendor 26 | **/vendor 27 | 28 | # common 29 | 30 | 31 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Netcat V2 功能测试脚本 4 | 5 | echo "=== Netcat V2 功能测试 ===" 6 | 7 | # 检查netcat是否存在 8 | if [ ! -f "./netcat" ]; then 9 | echo "错误: netcat 可执行文件不存在,请先运行 'make build'" 10 | exit 1 11 | fi 12 | 13 | echo "✓ netcat 可执行文件存在" 14 | 15 | # 1. 正向shell测试(服务端-e,客户端普通) 16 | echo -e "\n1. 正向shell测试..." 17 | ./netcat -l -p 4100 -e > shell_out.txt 2>&1 & 18 | SHELL_PID=$! 19 | sleep 1 20 | 21 | echo "whoami" | ./netcat -h 127.0.0.1 -p 4100 > shell_result.txt 22 | sleep 1 23 | kill $SHELL_PID 2>/dev/null 24 | 25 | if grep -q "$(whoami)" shell_result.txt; then 26 | echo "✓ 正向shell功能正常" 27 | else 28 | echo "✗ 正向shell功能异常" 29 | cat shell_result.txt 30 | fi 31 | rm -f shell_result.txt shell_out.txt 32 | 33 | # 2. 反向shell测试(客户端-e,服务端普通) 34 | echo -e "\n2. 反向shell测试..." 35 | ./netcat -l -p 4101 > revshell_out.txt 2>&1 & 36 | REV_PID=$! 37 | sleep 1 38 | 39 | echo "whoami" | ./netcat -h 127.0.0.1 -p 4101 -e > revshell_result.txt 40 | sleep 1 41 | kill $REV_PID 2>/dev/null 42 | 43 | if grep -q "$(whoami)" revshell_result.txt; then 44 | echo "✓ 反向shell功能正常" 45 | else 46 | echo "✗ 反向shell功能异常" 47 | cat revshell_result.txt 48 | fi 49 | rm -f revshell_result.txt revshell_out.txt 50 | 51 | echo -e "\n=== 测试完成 ===" 52 | echo "所有功能测试已完成,请检查上述结果。" 53 | 54 | # 清理可能的残留进程 55 | pkill -f "netcat -l" 2>/dev/null || true -------------------------------------------------------------------------------- /ssl_example.md: -------------------------------------------------------------------------------- 1 | # Netcat V2 SSL功能使用示例 2 | 3 | ## SSL功能概述 4 | 5 | Netcat V2 支持SSL/TLS加密连接,包括: 6 | - 自动生成自签名证书 7 | - SSL客户端连接 8 | - SSL服务器监听 9 | - HTTPS Web服务器 10 | 11 | ## 基本用法 12 | 13 | ### 1. SSL服务器监听 14 | 15 | ```bash 16 | # 启动SSL服务器监听 17 | ./netcat -l -ssl -p 8443 18 | 19 | # 客户端连接 20 | ./netcat -ssl localhost 8443 21 | ``` 22 | 23 | ### 2. HTTPS Web服务器 24 | 25 | ```bash 26 | # 创建测试目录 27 | mkdir -p public 28 | echo "

HTTPS Test

" > public/index.html 29 | 30 | # 启动HTTPS服务器 31 | ./netcat -web -ssl -p 8443 -path public 32 | 33 | # 浏览器访问 34 | # https://localhost:8443 35 | ``` 36 | 37 | ### 3. SSL命令模式 38 | 39 | ```bash 40 | # 服务器端(SSL反向shell) 41 | ./netcat -l -e -ssl -p 8443 42 | 43 | # 客户端连接 44 | ./netcat -ssl localhost 8443 45 | ``` 46 | 47 | ## 证书信息 48 | 49 | 自签名证书包含以下信息: 50 | - **组织**: Netcat V2 Test Certificate 51 | - **国家**: CN 52 | - **有效期**: 1年 53 | - **支持的域名**: localhost, 127.0.0.1, 主机名 54 | - **支持的IP**: 127.0.0.1, ::1 55 | 56 | ## 安全注意事项 57 | 58 | 1. **自签名证书**: 仅用于测试,生产环境请使用受信任的证书 59 | 2. **证书验证**: 客户端连接时会跳过证书验证(InsecureSkipVerify) 60 | 3. **加密强度**: 使用2048位RSA密钥 61 | 4. **协议支持**: TLS 1.2及以上版本 62 | 63 | ## 测试命令 64 | 65 | ```bash 66 | # 运行SSL功能测试 67 | ./test_ssl.sh 68 | 69 | # 手动测试SSL连接 70 | ./netcat -l -ssl -p 8443 & 71 | ./netcat -ssl localhost 8443 72 | 73 | # 测试HTTPS 74 | curl -k https://localhost:8443 75 | ``` 76 | 77 | ## 故障排除 78 | 79 | ### 常见问题 80 | 81 | 1. **证书错误**: 浏览器会显示证书不受信任,这是正常的(自签名证书) 82 | 2. **连接失败**: 检查端口是否被占用 83 | 3. **SSL握手失败**: 确保客户端和服务器都使用SSL模式 84 | 85 | ### 调试方法 86 | 87 | ```bash 88 | # 启用详细日志 89 | ./netcat -v -ssl localhost 8443 90 | 91 | # 检查端口监听 92 | netstat -an | grep 8443 93 | lsof -i :8443 94 | ``` 95 | 96 | ## 生产环境建议 97 | 98 | 1. 使用受信任的CA签发的证书 99 | 2. 配置证书文件路径参数 100 | 3. 启用证书验证 101 | 4. 使用强加密套件 102 | 5. 定期更新证书 -------------------------------------------------------------------------------- /test_ssl.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # SSL功能测试脚本 4 | 5 | echo "=== Netcat V2 SSL功能测试 ===" 6 | 7 | # 检查netcat是否存在 8 | if [ ! -f "./netcat" ]; then 9 | echo "错误: netcat 可执行文件不存在,请先运行 'make build'" 10 | exit 1 11 | fi 12 | 13 | echo "✓ netcat 可执行文件存在" 14 | 15 | # 测试SSL监听模式 16 | echo -e "\n1. 测试SSL监听模式..." 17 | ./netcat -l -p 8443 -ssl & 18 | SSL_SERVER_PID=$! 19 | sleep 2 20 | 21 | # 检查进程是否在运行 22 | if kill -0 $SSL_SERVER_PID 2>/dev/null; then 23 | echo "✓ SSL服务器启动成功" 24 | 25 | # 测试SSL连接 26 | echo -e "\n2. 测试SSL客户端连接..." 27 | timeout 5s ./netcat -ssl localhost 8443 & 28 | SSL_CLIENT_PID=$! 29 | sleep 2 30 | 31 | if kill -0 $SSL_CLIENT_PID 2>/dev/null; then 32 | echo "✓ SSL客户端连接成功" 33 | kill $SSL_CLIENT_PID 2>/dev/null 34 | else 35 | echo "✗ SSL客户端连接失败" 36 | fi 37 | 38 | # 清理服务器进程 39 | kill $SSL_SERVER_PID 2>/dev/null 40 | echo "✓ SSL服务器已关闭" 41 | else 42 | echo "✗ SSL服务器启动失败" 43 | fi 44 | 45 | # 测试SSL Web服务器 46 | echo -e "\n3. 测试SSL Web服务器..." 47 | mkdir -p test_ssl_web 48 | echo "

SSL Test

" > test_ssl_web/index.html 49 | 50 | ./netcat -web -p 8444 -ssl -path test_ssl_web & 51 | SSL_WEB_PID=$! 52 | sleep 2 53 | 54 | if kill -0 $SSL_WEB_PID 2>/dev/null; then 55 | echo "✓ SSL Web服务器启动成功" 56 | 57 | # 测试HTTPS访问 58 | echo -e "\n4. 测试HTTPS访问..." 59 | curl -k -s https://localhost:8444 > /dev/null 60 | if [ $? -eq 0 ]; then 61 | echo "✓ HTTPS访问成功" 62 | else 63 | echo "✗ HTTPS访问失败" 64 | fi 65 | 66 | kill $SSL_WEB_PID 2>/dev/null 67 | echo "✓ SSL Web服务器已关闭" 68 | else 69 | echo "✗ SSL Web服务器启动失败" 70 | fi 71 | 72 | # 清理测试文件 73 | rm -rf test_ssl_web 74 | 75 | # 测试证书生成 76 | echo -e "\n5. 测试证书生成..." 77 | ./netcat -l -p 8445 -ssl & 78 | CERT_TEST_PID=$! 79 | sleep 1 80 | 81 | if kill -0 $CERT_TEST_PID 2>/dev/null; then 82 | echo "✓ 自签名证书生成成功" 83 | kill $CERT_TEST_PID 2>/dev/null 84 | else 85 | echo "✗ 自签名证书生成失败" 86 | fi 87 | 88 | echo -e "\n=== SSL测试完成 ===" 89 | echo "所有SSL功能测试已完成。" 90 | 91 | # 清理可能的残留进程 92 | pkill -f "netcat.*ssl" 2>/dev/null || true -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Netcat 增强版 Makefile 2 | 3 | # 变量定义 4 | BINARY_NAME=netcat 5 | MAIN_FILE=main.go 6 | VERSION?=2.0.1 7 | COMMIT?=$(shell git rev-parse --short HEAD 2>/dev/null || echo "unknown") 8 | BUILD_TIME=$(shell date -u '+%Y-%m-%d_%H:%M:%S') 9 | 10 | # Go 编译参数 11 | LDFLAGS=-ldflags "-X main.Version=${VERSION} -X main.Commit=${COMMIT} -X main.BuildTags=${BUILD_TIME}" 12 | 13 | # 默认目标 14 | .PHONY: all 15 | all: build 16 | 17 | # 构建 18 | .PHONY: build 19 | build: 20 | @echo "Building ${BINARY_NAME}..." 21 | go build ${LDFLAGS} -o ${BINARY_NAME} ${MAIN_FILE} 22 | @echo "Build completed: ${BINARY_NAME}" 23 | 24 | # 清理 25 | .PHONY: clean 26 | clean: 27 | @echo "Cleaning..." 28 | rm -f ${BINARY_NAME} 29 | rm -f ${BINARY_NAME}-* 30 | @echo "Clean completed" 31 | 32 | # 测试 33 | .PHONY: test 34 | test: 35 | @echo "Running tests..." 36 | go test -v ./... 37 | 38 | # 格式化代码 39 | .PHONY: fmt 40 | fmt: 41 | @echo "Formatting code..." 42 | go fmt ${MAIN_FILE} 43 | 44 | # 代码检查 45 | .PHONY: lint 46 | lint: 47 | @echo "Running linter..." 48 | golangci-lint run 49 | 50 | # 交叉编译 51 | .PHONY: cross-build 52 | cross-build: clean 53 | @echo "Cross compiling..." 54 | 55 | # Linux 56 | GOOS=linux GOARCH=amd64 go build ${LDFLAGS} -o ${BINARY_NAME}-linux-amd64 ${MAIN_FILE} 57 | GOOS=linux GOARCH=386 go build ${LDFLAGS} -o ${BINARY_NAME}-linux-386 ${MAIN_FILE} 58 | GOOS=linux GOARCH=arm64 go build ${LDFLAGS} -o ${BINARY_NAME}-linux-arm64 ${MAIN_FILE} 59 | 60 | # Windows 61 | GOOS=windows GOARCH=amd64 go build ${LDFLAGS} -o ${BINARY_NAME}-windows-amd64.exe ${MAIN_FILE} 62 | GOOS=windows GOARCH=386 go build ${LDFLAGS} -o ${BINARY_NAME}-windows-386.exe ${MAIN_FILE} 63 | 64 | # macOS 65 | GOOS=darwin GOARCH=amd64 go build ${LDFLAGS} -o ${BINARY_NAME}-darwin-amd64 ${MAIN_FILE} 66 | GOOS=darwin GOARCH=arm64 go build ${LDFLAGS} -o ${BINARY_NAME}-darwin-arm64 ${MAIN_FILE} 67 | 68 | @echo "Cross build completed" 69 | 70 | # 安装依赖 71 | .PHONY: deps 72 | deps: 73 | @echo "Installing dependencies..." 74 | go mod tidy 75 | go mod download 76 | 77 | # 运行示例 78 | .PHONY: example 79 | example: build 80 | @echo "Running example..." 81 | @echo "Starting TCP listener on port 8080..." 82 | @echo "In another terminal, run: ./netcat localhost 8080" 83 | ./netcat -l -p 8080 84 | 85 | # SSL测试 86 | .PHONY: test-ssl 87 | test-ssl: build 88 | @echo "Running SSL tests..." 89 | ./test_ssl.sh 90 | 91 | # 帮助 92 | .PHONY: help 93 | help: 94 | @echo "Available targets:" 95 | @echo " build - Build the binary" 96 | @echo " clean - Clean build artifacts" 97 | @echo " test - Run tests" 98 | @echo " fmt - Format code" 99 | @echo " lint - Run linter" 100 | @echo " cross-build - Build for multiple platforms" 101 | @echo " deps - Install dependencies" 102 | @echo " example - Run example server" 103 | @echo " test-ssl - Run SSL tests" 104 | @echo " help - Show this help" 105 | 106 | # 开发模式 107 | .PHONY: dev 108 | dev: 109 | @echo "Starting development mode..." 110 | @echo "Watching for changes..." 111 | @command -v air >/dev/null 2>&1 || { echo "Installing air..."; go install github.com/cosmtrek/air@latest; } 112 | air 113 | 114 | # 发布 115 | .PHONY: release 116 | release: clean cross-build 117 | @echo "Creating release..." 118 | tar -czf ${BINARY_NAME}-${VERSION}-linux-amd64.tar.gz ${BINARY_NAME}-linux-amd64 119 | tar -czf ${BINARY_NAME}-${VERSION}-linux-arm64.tar.gz ${BINARY_NAME}-linux-arm64 120 | zip ${BINARY_NAME}-${VERSION}-windows-amd64.zip ${BINARY_NAME}-windows-amd64.exe 121 | zip ${BINARY_NAME}-${VERSION}-darwin-amd64.zip ${BINARY_NAME}-darwin-amd64 122 | @echo "Release packages created" 123 | 124 | # 默认目标 125 | .DEFAULT_GOAL := build -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Netcat V2 2 | 3 | 一个功能增强的网络工具,支持正向shell和反向shell,详见下方用法。 4 | 5 | --- 6 | 7 | ## 主要用法 8 | 9 | ### 正向shell(服务端执行命令,客户端控制) 10 | 11 | ```bash 12 | # 服务端(被控端,执行命令) 13 | ./netcat -l -v -e 14 | # 客户端(控制端,输入命令) 15 | ./netcat -h 127.0.0.1 -p 4000 16 | ``` 17 | - 客户端输入命令,服务端执行,结果返回客户端。 18 | 19 | ### 反向shell(客户端执行命令,服务端控制) 20 | 21 | ```bash 22 | # 服务端(控制端,输入命令) 23 | ./netcat -l -v 24 | # 客户端(被控端,执行命令) 25 | ./netcat -h 127.0.0.1 -p 4000 -e 26 | ``` 27 | - 服务端输入命令,客户端执行,结果返回服务端。 28 | 29 | --- 30 | 31 | ## 其他功能 32 | 33 | - 普通数据转发:两端都不加-e 34 | - SSL/TLS、Web服务、UDP等见下文 35 | 36 | --- 37 | 38 | ## 测试 39 | 40 | 可用`make test`自动验证正向shell和反向shell功能。 41 | 42 | --- 43 | 44 | ## 主要改进(V2) 45 | 46 | ### 🛡️ 健壮性增强 47 | - **完善的错误处理**: 所有网络操作都有适当的错误处理 48 | - **资源管理**: 正确关闭连接和监听器,避免资源泄漏 49 | - **并发安全**: 使用互斥锁保护共享资源 50 | - **配置验证**: 启动前验证所有配置参数 51 | 52 | ### ⚡ 新功能 53 | - **超时控制**: 可配置连接超时时间 54 | - **重试机制**: 连接失败时自动重试 55 | - **SSL/TLS支持**: 支持加密连接 56 | - **Keep-Alive**: TCP连接保活机制 57 | - **优雅关闭**: 支持信号处理,优雅退出 58 | - **完整UDP支持**: UDP监听持续运行,不再只处理一个包 59 | 60 | ### 🔧 配置选项 61 | - `-timeout`: 连接超时时间 (默认30秒) 62 | - `-retries`: 重试次数 (默认3次) 63 | - `-ssl`: 启用SSL/TLS加密 64 | - `-keepalive`: 启用TCP保活 (默认启用) 65 | - `-buffer`: 数据传输缓冲区大小 (默认4096字节) 66 | 67 | --- 68 | 69 | ## 快速上手(V2) 70 | 71 | ### 基本用法 72 | 73 | ```bash 74 | # TCP监听模式 75 | ./netcat -l -p 8080 76 | 77 | # TCP连接模式 78 | ./netcat localhost 8080 79 | 80 | # UDP监听模式 81 | ./netcat -l -n udp -p 8080 82 | 83 | # UDP连接模式 84 | ./netcat -n udp localhost 8080 85 | ``` 86 | 87 | ### 高级功能 88 | 89 | ```bash 90 | # 带超时和重试的连接 91 | ./netcat -timeout 10s -retries 5 localhost 8080 92 | 93 | # SSL加密连接 94 | ./netcat -ssl localhost 8443 95 | 96 | # SSL监听模式 97 | ./netcat -l -ssl -p 8443 98 | 99 | # SSL Web服务器 100 | ./netcat -web -ssl -p 8443 -path ./public 101 | 102 | # 命令模式 (反向shell) 103 | ./netcat -l -e -p 8080 104 | 105 | # Web静态文件服务器 106 | ./netcat -web -p 8080 -path ./public 107 | 108 | # 自定义缓冲区大小 109 | ./netcat -buffer 8192 localhost 8080 110 | ``` 111 | 112 | --- 113 | 114 | ## 命令行选项(V2) 115 | 116 | ``` 117 | name: netcat 118 | version: 119 | commit: 120 | build_tags: 121 | go: go version go1.21.0 darwin/amd64 122 | 123 | usage: netcat [options] [host] [port] 124 | 125 | options: 126 | -p int 127 | host port to connect or listen (default 4000) 128 | -help 129 | print this help 130 | -v verbose mode (default true) 131 | -l listen mode 132 | -e shell mode 133 | -web web static server 134 | -path string 135 | web static path (default "public") 136 | -n string 137 | network protocol (default "tcp") 138 | -h string 139 | host addr to connect or listen (default "0.0.0.0") 140 | -timeout duration 141 | connection timeout (default 30s) 142 | -retries int 143 | connection retry attempts (default 3) 144 | -ssl use SSL/TLS 145 | -keepalive 146 | enable keep-alive (default true) 147 | -buffer int 148 | buffer size for data transfer (default 4096) 149 | ``` 150 | 151 | --- 152 | 153 | ## 场景演示与截图(V2) 154 | 155 | ### 1. 正向命令执行 156 | ![](images/p1@2x.png) 157 | 158 | ### 2. 反向命令执行 159 | ![](images/p2@2x.png) 160 | 161 | ### 3. 文件传输 162 | ![](images/p3@2x.png) 163 | 164 | ### 4. 标准输入输出 165 | ![](images/p4@2x.png) 166 | 167 | ### 5. Web静态服务器 168 | ![](images/p5.png) 169 | 170 | --- 171 | 172 | ## 功能特性(V2) 173 | 174 | ### 1. 网络协议支持 175 | - **TCP**: 完整的TCP客户端/服务器功能 176 | - **UDP**: 完整的UDP客户端/服务器功能 177 | - **SSL/TLS**: TCP连接支持加密传输 178 | 179 | ### 2. 监听模式 180 | - 支持多客户端连接 181 | - 优雅关闭处理 182 | - 信号处理 (Ctrl+C) 183 | - 连接日志记录 184 | 185 | ### 3. 连接模式 186 | - 自动重试机制 187 | - 超时控制 188 | - 连接保活 189 | - 错误恢复 190 | 191 | ### 4. 数据传输 192 | - 双向数据传输 193 | - 缓冲区优化 194 | - 字符编码处理 (Windows GBK支持) 195 | - 交互式和非交互式模式 196 | 197 | ### 5. 命令模式 198 | - 反向shell功能 199 | - 跨平台shell支持 200 | - 命令执行超时控制 201 | 202 | ### 6. Web服务器 203 | - 静态文件服务 204 | - HTTP请求日志 205 | - 优雅关闭 206 | - SSL/TLS支持(HTTPS) 207 | 208 | --- 209 | 210 | ## 错误处理(V2) 211 | 212 | ### 网络错误 213 | - 连接失败自动重试 214 | - 超时处理 215 | - 连接中断恢复 216 | 217 | ### 系统错误 218 | - 信号处理 219 | - 资源清理 220 | - 优雅退出 221 | 222 | ### 配置错误 223 | - 参数验证 224 | - 端口范围检查 225 | - 协议支持检查 226 | 227 | --- 228 | 229 | ## 性能优化(V2) 230 | 231 | ### 内存管理 232 | - 固定大小缓冲区 233 | - 及时释放资源 234 | - 避免内存泄漏 235 | 236 | ### 网络优化 237 | - TCP保活机制 238 | - 连接复用 239 | - 缓冲区大小可配置 240 | 241 | ### 并发处理 242 | - 多客户端支持 243 | - 线程安全 244 | - 资源竞争保护 245 | 246 | --- 247 | 248 | ## 安全特性(V2) 249 | 250 | ### SSL/TLS支持 251 | - 加密传输 252 | - 自签名证书自动生成 253 | - 证书验证 (可配置) 254 | - 安全连接 255 | - 支持HTTPS Web服务器 256 | 257 | ### 访问控制 258 | - 连接日志 259 | - 错误日志 260 | - 调试信息 261 | 262 | --- 263 | 264 | ## 常见使用场景 265 | 266 | ### 网络调试 267 | ```bash 268 | # 测试端口连通性 269 | ./netcat -timeout 5s localhost 80 270 | 271 | # 监听端口查看连接 272 | ./netcat -l -p 8080 273 | ``` 274 | 275 | ### 文件传输 276 | ```bash 277 | # 发送文件 278 | cat file.txt | ./netcat localhost 8080 279 | 280 | # 接收文件 281 | ./netcat -l -p 8080 > received.txt 282 | ``` 283 | 284 | ### 反向Shell 285 | ```bash 286 | # 服务器端 287 | ./netcat -l -e -p 8080 288 | 289 | # 客户端连接 290 | ./netcat localhost 8080 291 | ``` 292 | 293 | ### Web服务 294 | ```bash 295 | # 启动静态文件服务器 296 | ./netcat -web -p 8080 -path ./public 297 | 298 | # 启动HTTPS静态文件服务器 299 | ./netcat -web -ssl -p 8443 -path ./public 300 | ``` 301 | 302 | --- 303 | 304 | ## 构建 305 | 306 | ```bash 307 | # 编译 308 | go build -o netcat main.go 309 | 310 | # 交叉编译 311 | GOOS=linux GOARCH=amd64 go build -o netcat-linux main.go 312 | GOOS=windows GOARCH=amd64 go build -o netcat.exe main.go 313 | ``` 314 | 315 | --- 316 | 317 | ## 许可证 318 | 319 | MIT License -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "context" 6 | "crypto/rand" 7 | "crypto/rsa" 8 | "crypto/tls" 9 | "crypto/x509" 10 | "crypto/x509/pkix" 11 | "flag" 12 | "fmt" 13 | "io" 14 | "log" 15 | "math/big" 16 | "net" 17 | "net/http" 18 | "os" 19 | "os/exec" 20 | "os/signal" 21 | "runtime" 22 | "strconv" 23 | "strings" 24 | "sync" 25 | "syscall" 26 | "time" 27 | 28 | "golang.org/x/text/encoding/simplifiedchinese" 29 | "golang.org/x/text/transform" 30 | ) 31 | 32 | // 常量定义 33 | const ( 34 | udpNetwork = "udp" 35 | tcpNetwork = "tcp" 36 | udpBufSize = 64 * 1024 37 | ) 38 | 39 | // 应用信息 40 | var ( 41 | Name = "" 42 | Version = "" 43 | Commit = "" 44 | BuildTags = "" 45 | logger = log.New(os.Stderr, "", 0) 46 | ) 47 | 48 | // Config 配置结构体 49 | type Config struct { 50 | Help bool 51 | Verbose bool 52 | Listen bool 53 | Port int 54 | Network string 55 | Web bool 56 | Path string 57 | Command bool 58 | Host string 59 | Timeout time.Duration 60 | Retries int 61 | SSL bool 62 | KeepAlive bool 63 | BufferSize int 64 | } 65 | 66 | var config Config 67 | 68 | // 初始化配置 69 | func init() { 70 | flag.IntVar(&config.Port, "p", 4000, "host port to connect or listen") 71 | flag.BoolVar(&config.Help, "help", false, "print this help") 72 | flag.BoolVar(&config.Verbose, "v", true, "verbose mode") 73 | flag.BoolVar(&config.Listen, "l", false, "listen mode") 74 | flag.BoolVar(&config.Command, "e", false, "shell mode") 75 | flag.BoolVar(&config.Web, "web", false, "web static server") 76 | flag.StringVar(&config.Path, "path", "public", "web static path") 77 | flag.StringVar(&config.Network, "n", "tcp", "network protocol") 78 | flag.StringVar(&config.Host, "h", "0.0.0.0", "host addr to connect or listen") 79 | flag.DurationVar(&config.Timeout, "timeout", 30*time.Second, "connection timeout") 80 | flag.IntVar(&config.Retries, "retries", 3, "connection retry attempts") 81 | flag.BoolVar(&config.SSL, "ssl", false, "use SSL/TLS") 82 | flag.BoolVar(&config.KeepAlive, "keepalive", true, "enable keep-alive") 83 | flag.IntVar(&config.BufferSize, "buffer", 4096, "buffer size for data transfer") 84 | flag.Usage = usage 85 | flag.Parse() 86 | } 87 | 88 | // 日志函数 89 | func logf(f string, v ...interface{}) { 90 | if config.Verbose { 91 | logger.Output(2, fmt.Sprintf(f, v...)) 92 | } 93 | } 94 | 95 | // 使用说明 96 | func usage() { 97 | fmt.Fprintf(os.Stderr, fmt.Sprintf(`name: %s 98 | version: %s 99 | commit: %s 100 | build_tags: %s 101 | go: %s 102 | 103 | usage: netcat [options] [host] [port] 104 | 105 | options: 106 | `, Name, Version, Commit, BuildTags, 107 | fmt.Sprintf("go version %s %s/%s", runtime.Version(), runtime.GOOS, runtime.GOARCH)), 108 | ) 109 | flag.PrintDefaults() 110 | } 111 | 112 | // 配置验证 113 | func validateConfig() error { 114 | if config.Port < 1 || config.Port > 65535 { 115 | return fmt.Errorf("invalid port number: %d", config.Port) 116 | } 117 | 118 | if config.Network != "tcp" && config.Network != "udp" { 119 | return fmt.Errorf("unsupported network protocol: %s", config.Network) 120 | } 121 | 122 | if config.Retries < 0 { 123 | return fmt.Errorf("retries cannot be negative: %d", config.Retries) 124 | } 125 | 126 | if config.BufferSize < 1 { 127 | return fmt.Errorf("buffer size must be positive: %d", config.BufferSize) 128 | } 129 | 130 | return nil 131 | } 132 | 133 | // 参数校验 134 | func validateParameters() { 135 | // 参数互斥校验:两端不能同时加 -e 136 | if config.Command { 137 | if config.Listen { 138 | logf("[警告] 服务端已开启 -e(正向shell),请确保客户端不要同时加 -e,否则会错乱!") 139 | } else { 140 | logf("[警告] 客户端已开启 -e(反向shell),请确保服务端不要同时加 -e,否则会错乱!") 141 | } 142 | } 143 | 144 | // UDP 不支持反向 shell(客户端加 -e) 145 | if config.Network == "udp" && !config.Listen && config.Command { 146 | fmt.Fprintln(os.Stderr, "[错误] UDP 协议不支持反向 shell(客户端加 -e),请用 TCP 或服务端加 -e!") 147 | os.Exit(1) 148 | } 149 | } 150 | 151 | // 创建 TLS 配置 152 | func createTLSConfig() (*tls.Config, error) { 153 | cert, err := generateSelfSignedCert() 154 | if err != nil { 155 | return nil, fmt.Errorf("failed to generate certificate: %v", err) 156 | } 157 | 158 | return &tls.Config{ 159 | Certificates: []tls.Certificate{cert}, 160 | MinVersion: tls.VersionTLS10, 161 | MaxVersion: tls.VersionTLS13, 162 | CipherSuites: []uint16{ 163 | tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 164 | tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 165 | tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 166 | tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 167 | tls.TLS_RSA_WITH_AES_128_GCM_SHA256, 168 | tls.TLS_RSA_WITH_AES_256_GCM_SHA384, 169 | tls.TLS_RSA_WITH_AES_128_CBC_SHA, 170 | tls.TLS_RSA_WITH_AES_256_CBC_SHA, 171 | }, 172 | }, nil 173 | } 174 | 175 | // 创建客户端 TLS 配置 176 | func createClientTLSConfig() *tls.Config { 177 | return &tls.Config{ 178 | InsecureSkipVerify: true, // 注意:生产环境应该验证证书 179 | MinVersion: tls.VersionTLS10, 180 | MaxVersion: tls.VersionTLS13, 181 | CipherSuites: []uint16{ 182 | tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 183 | tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 184 | tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 185 | tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 186 | tls.TLS_RSA_WITH_AES_128_GCM_SHA256, 187 | tls.TLS_RSA_WITH_AES_256_GCM_SHA384, 188 | tls.TLS_RSA_WITH_AES_128_CBC_SHA, 189 | tls.TLS_RSA_WITH_AES_256_CBC_SHA, 190 | }, 191 | } 192 | } 193 | 194 | // 设置信号处理 195 | func setupSignalHandler(cleanup func()) { 196 | sigChan := make(chan os.Signal, 1) 197 | signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) 198 | 199 | go func() { 200 | <-sigChan 201 | logf("Received signal, shutting down...") 202 | if cleanup != nil { 203 | cleanup() 204 | } 205 | }() 206 | } 207 | 208 | // 执行命令并返回结果 209 | func executeCommand(cmdStr string) ([]byte, error) { 210 | shell, shellArgs := getShell() 211 | args := append(shellArgs, "-c", cmdStr) 212 | cmd := exec.Command(shell, args...) 213 | return cmd.CombinedOutput() 214 | } 215 | 216 | // Convert 处理字符编码转换 217 | type Convert struct { 218 | conn net.Conn 219 | mu sync.Mutex 220 | } 221 | 222 | func newConvert(c net.Conn) *Convert { 223 | return &Convert{conn: c} 224 | } 225 | 226 | func (convert *Convert) translate(p []byte, encoding string) []byte { 227 | // 使用 Go 标准库进行 GBK 到 UTF-8 的转换 228 | reader := transform.NewReader(strings.NewReader(string(p)), simplifiedchinese.GBK.NewDecoder()) 229 | result, err := io.ReadAll(reader) 230 | if err != nil { 231 | return p // 如果转换失败,返回原始数据 232 | } 233 | return result 234 | } 235 | 236 | func (convert *Convert) Write(p []byte) (n int, err error) { 237 | convert.mu.Lock() 238 | defer convert.mu.Unlock() 239 | 240 | switch runtime.GOOS { 241 | case "windows": 242 | // 在 Windows 下进行 GBK 编码转换 243 | resBytes := convert.translate(p, "gbk") 244 | m, err := convert.conn.Write(resBytes) 245 | if m != len(resBytes) { 246 | return m, err 247 | } 248 | return len(p), err 249 | default: 250 | return convert.conn.Write(p) 251 | } 252 | } 253 | 254 | func (convert *Convert) Read(p []byte) (n int, err error) { 255 | convert.mu.Lock() 256 | defer convert.mu.Unlock() 257 | return convert.conn.Read(p) 258 | } 259 | 260 | func (convert *Convert) Close() error { 261 | convert.mu.Lock() 262 | defer convert.mu.Unlock() 263 | return convert.conn.Close() 264 | } 265 | 266 | // 获取 shell 和参数 267 | func getShell() (string, []string) { 268 | switch runtime.GOOS { 269 | case "linux", "darwin": 270 | // 交互模式下不使用 -i 参数,避免 "no job control" 提示 271 | if config.Command { 272 | return "/bin/sh", []string{} 273 | } 274 | return "/bin/sh", []string{"-i"} 275 | case "freebsd": 276 | if config.Command { 277 | return "/bin/csh", []string{} 278 | } 279 | return "/bin/csh", []string{"-i"} 280 | case "windows": 281 | return "cmd.exe", []string{} 282 | default: 283 | if config.Command { 284 | return "/bin/sh", []string{} 285 | } 286 | return "/bin/sh", []string{"-i"} 287 | } 288 | } 289 | 290 | // 设置连接参数 291 | func setupConnection(conn net.Conn) { 292 | if tcpConn, ok := conn.(*net.TCPConn); ok { 293 | if config.KeepAlive { 294 | tcpConn.SetKeepAlive(true) 295 | tcpConn.SetKeepAlivePeriod(30 * time.Second) 296 | } 297 | tcpConn.SetLinger(0) 298 | } 299 | } 300 | 301 | // 处理命令模式 302 | func handleCommandMode(conn net.Conn) { 303 | defer func() { 304 | conn.Close() 305 | logf("Closed: %s", conn.RemoteAddr()) 306 | }() 307 | 308 | shell, args := getShell() 309 | cmd := exec.Command(shell, args...) 310 | convert := newConvert(conn) 311 | 312 | cmd.Stdin = convert 313 | cmd.Stdout = convert 314 | cmd.Stderr = convert 315 | 316 | // 设置超时上下文 317 | ctx, cancel := context.WithTimeout(context.Background(), config.Timeout) 318 | defer cancel() 319 | 320 | cmd = exec.CommandContext(ctx, shell, args...) 321 | cmd.Stdin = convert 322 | cmd.Stdout = convert 323 | cmd.Stderr = convert 324 | 325 | if err := cmd.Run(); err != nil { 326 | logf("Command execution failed: %v", err) 327 | } 328 | } 329 | 330 | // 处理数据传输模式 331 | func handleDataMode(conn net.Conn) { 332 | defer conn.Close() 333 | 334 | // 从连接读取数据并输出到stdout 335 | go func() { 336 | buffer := make([]byte, config.BufferSize) 337 | for { 338 | n, err := conn.Read(buffer) 339 | if err != nil { 340 | if err != io.EOF { 341 | logf("Read error: %v", err) 342 | } 343 | break 344 | } 345 | if n > 0 { 346 | os.Stdout.Write(buffer[:n]) 347 | } 348 | } 349 | }() 350 | 351 | // 从stdin读取数据并发送到连接 352 | fi, err := os.Stdin.Stat() 353 | if err != nil { 354 | logf("Stdin stat failed: %v", err) 355 | return 356 | } 357 | 358 | if (fi.Mode() & os.ModeCharDevice) == 0 { 359 | // 非交互模式,一次性读取所有数据 360 | buffer, err := io.ReadAll(os.Stdin) 361 | if err != nil { 362 | logf("Failed to read stdin: %v", err) 363 | return 364 | } 365 | _, err = conn.Write(buffer) 366 | if err != nil { 367 | logf("Failed to write to connection: %v", err) 368 | } 369 | } else { 370 | // 交互模式 371 | scanner := bufio.NewScanner(os.Stdin) 372 | for scanner.Scan() { 373 | line := scanner.Text() + "\n" 374 | _, err := conn.Write([]byte(line)) 375 | if err != nil { 376 | logf("Failed to write to connection: %v", err) 377 | break 378 | } 379 | } 380 | if err := scanner.Err(); err != nil { 381 | logf("Scanner error: %v", err) 382 | } 383 | } 384 | } 385 | 386 | // UDP 监听模式 387 | func listenUDP(host string, port int, command bool) error { 388 | listenAddr := net.JoinHostPort(host, strconv.Itoa(port)) 389 | 390 | if config.SSL { 391 | return fmt.Errorf("SSL not supported for UDP") 392 | } 393 | 394 | conn, err := net.ListenPacket("udp", listenAddr) 395 | if err != nil { 396 | return fmt.Errorf("listen failed: %v", err) 397 | } 398 | defer conn.Close() 399 | 400 | logf("Listening on: %s://%s", config.Network, listenAddr) 401 | 402 | // 处理信号 403 | setupSignalHandler(func() { 404 | logf("Shutting down UDP listener...") 405 | conn.Close() 406 | }) 407 | 408 | buf := make([]byte, udpBufSize) 409 | 410 | for { 411 | n, addr, err := conn.ReadFrom(buf) 412 | if err != nil { 413 | if strings.Contains(err.Error(), "use of closed network connection") { 414 | break 415 | } 416 | logf("Read error: %v", err) 417 | continue 418 | } 419 | 420 | if n > 0 { 421 | logf("Received %d bytes from %s", n, addr.String()) 422 | cmdStr := strings.TrimSpace(string(buf[:n])) 423 | if command { 424 | // 执行命令并返回结果 425 | output, err := executeCommand(cmdStr) 426 | if err != nil { 427 | output = append(output, []byte("\nError: "+err.Error())...) 428 | } 429 | _, err = conn.WriteTo(output, addr) 430 | if err != nil { 431 | logf("Write error: %v", err) 432 | } 433 | } else { 434 | fmt.Printf("From %s: %s", addr.String(), string(buf[:n])) 435 | _, err = conn.WriteTo(buf[:n], addr) 436 | if err != nil { 437 | logf("Write error: %v", err) 438 | } 439 | } 440 | } 441 | } 442 | 443 | return nil 444 | } 445 | 446 | // UDP 客户端命令模式处理 447 | func handleUDPClientCommand(host string, port int) error { 448 | dialAddr := net.JoinHostPort(host, strconv.Itoa(port)) 449 | 450 | // 创建UDP连接 451 | conn, err := net.Dial("udp", dialAddr) 452 | if err != nil { 453 | return fmt.Errorf("UDP dial failed: %v", err) 454 | } 455 | defer conn.Close() 456 | 457 | logf("UDP client connected to %s", dialAddr) 458 | 459 | // 处理信号 460 | setupSignalHandler(func() { 461 | logf("UDP client shutting down...") 462 | conn.Close() 463 | }) 464 | 465 | // 从stdin读取命令并发送 466 | scanner := bufio.NewScanner(os.Stdin) 467 | for scanner.Scan() { 468 | cmd := scanner.Text() 469 | if cmd == "" { 470 | continue 471 | } 472 | 473 | // 发送命令 474 | _, err := conn.Write([]byte(cmd)) 475 | if err != nil { 476 | logf("Failed to send command: %v", err) 477 | continue 478 | } 479 | 480 | // 设置读取超时 481 | conn.SetReadDeadline(time.Now().Add(5 * time.Second)) 482 | 483 | // 接收响应 484 | buffer := make([]byte, 4096) 485 | n, err := conn.Read(buffer) 486 | if err != nil { 487 | if netErr, ok := err.(net.Error); ok && netErr.Timeout() { 488 | logf("No response received (timeout)") 489 | } else { 490 | logf("Failed to read response: %v", err) 491 | } 492 | continue 493 | } 494 | 495 | // 输出响应 496 | if n > 0 { 497 | os.Stdout.Write(buffer[:n]) 498 | } 499 | } 500 | 501 | if err := scanner.Err(); err != nil { 502 | return fmt.Errorf("scanner error: %v", err) 503 | } 504 | 505 | return nil 506 | } 507 | 508 | // 带重试的连接 509 | func dialWithRetry(network, host string, port int) (net.Conn, error) { 510 | dialAddr := net.JoinHostPort(host, strconv.Itoa(port)) 511 | 512 | var conn net.Conn 513 | var err error 514 | 515 | for i := 0; i <= config.Retries; i++ { 516 | if i > 0 { 517 | logf("Retry %d/%d connecting to %s", i, config.Retries, dialAddr) 518 | time.Sleep(time.Duration(i) * time.Second) 519 | } 520 | 521 | ctx, cancel := context.WithTimeout(context.Background(), config.Timeout) 522 | 523 | if config.SSL && network == "tcp" { 524 | tlsConfig := createClientTLSConfig() 525 | conn, err = tls.Dial("tcp", dialAddr, tlsConfig) 526 | } else { 527 | var d net.Dialer 528 | conn, err = d.DialContext(ctx, network, dialAddr) 529 | } 530 | 531 | cancel() 532 | 533 | if err == nil { 534 | logf("Successfully connected to %s://%s", network, dialAddr) 535 | setupConnection(conn) 536 | return conn, nil 537 | } 538 | 539 | logf("Connection attempt %d failed: %v", i+1, err) 540 | } 541 | 542 | return nil, fmt.Errorf("failed to connect after %d attempts: %v", config.Retries+1, err) 543 | } 544 | 545 | // TCP 监听模式 546 | func listen(network, host string, port int, command bool) error { 547 | listenAddr := net.JoinHostPort(host, strconv.Itoa(port)) 548 | 549 | // 创建监听器(支持 TLS) 550 | var listener net.Listener 551 | var err error 552 | 553 | if config.SSL { 554 | tlsConfig, err := createTLSConfig() 555 | if err != nil { 556 | return err 557 | } 558 | listener, err = tls.Listen("tcp", listenAddr, tlsConfig) 559 | } else { 560 | listener, err = net.Listen("tcp", listenAddr) 561 | } 562 | 563 | if err != nil { 564 | return fmt.Errorf("Listen failed: %s", err) 565 | } 566 | defer listener.Close() 567 | 568 | logf("Listening on: %s://%s", network, listenAddr) 569 | 570 | // 处理信号,优雅关闭 571 | setupSignalHandler(func() { 572 | logf("Shutting down listener...") 573 | listener.Close() 574 | }) 575 | 576 | // 接受连接 577 | for { 578 | conn, err := listener.Accept() 579 | if err != nil { 580 | if strings.Contains(err.Error(), "use of closed network connection") { 581 | break 582 | } 583 | logf("Accept failed: %v", err) 584 | continue 585 | } 586 | 587 | logf("Connection received: %s", conn.RemoteAddr()) 588 | setupConnection(conn) 589 | 590 | // 如果是 TLS 连接,完成握手 591 | if config.SSL { 592 | if tlsConn, ok := conn.(*tls.Conn); ok { 593 | logf("[TLS] Starting handshake...") 594 | if err := tlsConn.Handshake(); err != nil { 595 | logf("TLS handshake failed: %v", err) 596 | conn.Close() 597 | continue 598 | } 599 | logf("[TLS] Handshake completed") 600 | } 601 | } 602 | 603 | if command { 604 | go handleCommandMode(conn) 605 | } else { 606 | go handleDataMode(conn) 607 | } 608 | } 609 | 610 | return nil 611 | } 612 | 613 | // Web 服务器模式 614 | func listenWeb(host string, port int, path string) error { 615 | listenAddr := net.JoinHostPort(host, strconv.Itoa(port)) 616 | 617 | // 检查静态文件目录是否存在 618 | if _, err := os.Stat(path); os.IsNotExist(err) { 619 | return fmt.Errorf("static path does not exist: %s", path) 620 | } 621 | 622 | logf("Starting web server on: %s, serving: %s", listenAddr, path) 623 | 624 | // 添加一些基本的HTTP头 625 | fileServer := http.FileServer(http.Dir(path)) 626 | handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 627 | logf("HTTP %s %s from %s", r.Method, r.URL.Path, r.RemoteAddr) 628 | fileServer.ServeHTTP(w, r) 629 | }) 630 | 631 | server := &http.Server{ 632 | Addr: listenAddr, 633 | Handler: handler, 634 | } 635 | 636 | // 如果启用SSL,配置TLS 637 | if config.SSL { 638 | tlsConfig, err := createTLSConfig() 639 | if err != nil { 640 | return err 641 | } 642 | server.TLSConfig = tlsConfig 643 | } 644 | 645 | // 优雅关闭 646 | setupSignalHandler(func() { 647 | logf("Shutting down web server...") 648 | ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 649 | defer cancel() 650 | server.Shutdown(ctx) 651 | }) 652 | 653 | if config.SSL { 654 | return server.ListenAndServeTLS("", "") 655 | } 656 | return server.ListenAndServe() 657 | } 658 | 659 | // 生成自签名证书(仅用于测试) 660 | func generateSelfSignedCert() (tls.Certificate, error) { 661 | // 生成RSA私钥 662 | privateKey, err := rsa.GenerateKey(rand.Reader, 2048) 663 | if err != nil { 664 | return tls.Certificate{}, fmt.Errorf("failed to generate private key: %v", err) 665 | } 666 | 667 | // 创建证书模板 668 | serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) 669 | serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) 670 | if err != nil { 671 | return tls.Certificate{}, fmt.Errorf("failed to generate serial number: %v", err) 672 | } 673 | 674 | // 获取主机名 675 | hostname, err := os.Hostname() 676 | if err != nil { 677 | hostname = "localhost" 678 | } 679 | 680 | // 创建证书模板 681 | template := x509.Certificate{ 682 | SerialNumber: serialNumber, 683 | Subject: pkix.Name{ 684 | Organization: []string{"Netcat V2 Test Certificate"}, 685 | Country: []string{"CN"}, 686 | Province: []string{"Test"}, 687 | Locality: []string{"Test"}, 688 | CommonName: hostname, 689 | }, 690 | NotBefore: time.Now(), 691 | NotAfter: time.Now().Add(365 * 24 * time.Hour), // 1年有效期 692 | KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, 693 | ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, 694 | BasicConstraintsValid: true, 695 | DNSNames: []string{hostname, "localhost", "127.0.0.1"}, 696 | IPAddresses: []net.IP{net.ParseIP("127.0.0.1"), net.ParseIP("::1")}, 697 | } 698 | 699 | // 创建证书 700 | derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &privateKey.PublicKey, privateKey) 701 | if err != nil { 702 | return tls.Certificate{}, fmt.Errorf("failed to create certificate: %v", err) 703 | } 704 | 705 | // 创建tls.Certificate 706 | cert := tls.Certificate{ 707 | Certificate: [][]byte{derBytes}, 708 | PrivateKey: privateKey, 709 | } 710 | 711 | return cert, nil 712 | } 713 | 714 | // 主函数 715 | func main() { 716 | if config.Help { 717 | flag.Usage() 718 | return 719 | } 720 | 721 | // 参数校验 722 | validateParameters() 723 | 724 | // 验证配置 725 | if err := validateConfig(); err != nil { 726 | logf("Configuration error: %v", err) 727 | os.Exit(1) 728 | } 729 | 730 | // 设置信号处理 731 | sigs := make(chan os.Signal, 1) 732 | signal.Notify(sigs, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) 733 | 734 | go func() { 735 | <-sigs 736 | logf("Received signal, exiting...") 737 | os.Exit(0) 738 | }() 739 | 740 | var err error 741 | 742 | // 根据模式执行相应功能 743 | if config.Web { 744 | err = listenWeb(config.Host, config.Port, config.Path) 745 | } else if config.Listen { 746 | switch config.Network { 747 | case udpNetwork: 748 | err = listenUDP(config.Host, config.Port, config.Command) 749 | case tcpNetwork: 750 | err = listen(config.Network, config.Host, config.Port, config.Command) 751 | default: 752 | err = fmt.Errorf("unsupported network protocol: %s", config.Network) 753 | } 754 | } else { 755 | if config.Network == "udp" && config.Command { 756 | // UDP 客户端命令模式:发送命令并接收响应 757 | err = handleUDPClientCommand(config.Host, config.Port) 758 | } else { 759 | conn, err := dialWithRetry(config.Network, config.Host, config.Port) 760 | if err != nil { 761 | logf("Error: %v", err) 762 | os.Exit(1) 763 | } 764 | if config.Command { 765 | handleCommandMode(conn) 766 | } else { 767 | handleDataMode(conn) 768 | } 769 | } 770 | } 771 | 772 | if err != nil { 773 | logf("Error: %v", err) 774 | os.Exit(1) 775 | } 776 | } 777 | --------------------------------------------------------------------------------