├── 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 | 
157 |
158 | ### 2. 反向命令执行
159 | 
160 |
161 | ### 3. 文件传输
162 | 
163 |
164 | ### 4. 标准输入输出
165 | 
166 |
167 | ### 5. Web静态服务器
168 | 
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 |
--------------------------------------------------------------------------------