-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwebdemo.go
322 lines (274 loc) · 9.05 KB
/
webdemo.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
package main
import (
"crypto/tls"
"flag"
"fmt"
"log"
"net"
"net/http"
"os"
"strconv"
appVersion "webdemo/appinfo"
"github.com/quic-go/quic-go"
"github.com/quic-go/quic-go/http3"
)
// red := "\033[31m"
// green := "\033[32m"
// yellow := "\033[33m"
// blue := "\033[34m"
// reset := "\033[0m"
func exit_path(filename string) int {
_, err := os.Stat(filename)
if err == nil {
// fmt.Printf("文件 %s 存在\n", filename)
return 0
} else if os.IsNotExist(err) {
// fmt.Printf("文件 %s 不存在\n", filename)
return 1
} else {
// fmt.Printf("检查文件时发生错误: %v\n", err)
return 2
}
}
func basicAuth(handler http.Handler, username, password, path string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ip := r.RemoteAddr // 访问的 IP 地址
ua := r.UserAgent() //r.Header.Get("User-Agent") 获取ua头
if username != "" || password != "" { //默认空密码用户名,无需认证
user, pass, ok := r.BasicAuth()
if !ok || user != username || pass != password {
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
w.WriteHeader(http.StatusUnauthorized)
fmt.Fprintln(w, "Unauthorized") //网页端认证失败返回文字
log.Printf("\033[31m 非法访问者 %s \033[0m 使用%s 头,%s方式尝试请求文件\033[31m%s\033[0m", ip, ua, r.Method, path+r.URL.Path)
return
} else {
log.Printf("\033[32m%s \033[0m使用%s 头,%s方式请求文件%s", ip, ua, r.Method, path+r.URL.Path)
}
} else {
log.Printf("\033[33m%s \033[0m使用%s 头,%s方式请求文件%s", ip, ua, r.Method, path+r.URL.Path)
}
handler.ServeHTTP(w, r)
})
}
func quicgo_ListenAndServeTLS(addr, certFile, keyFile string, handler http.Handler) error {
//https://github.com/quic-go/quic-go/blob/master/http3/server.go#L709
//可监听tcp端口,兼容性最好
var err_certs error
certs := make([]tls.Certificate, 1)
certs[0], err_certs = tls.LoadX509KeyPair(certFile, keyFile)
if err_certs != nil {
return err_certs
}
// // 加载第二个证书密钥对
// certs = append(certs, tls.Certificate{})
// certs[2], err_certs = tls.LoadX509KeyPair(certFile, keyFile)
// if err_certs != nil {
// log.Fatal("Failed to load second certificate and key:", err)
// }
// We currently only use the cert-related stuff from tls.Config,
// so we don't need to make a full copy.
if addr == "" {
addr = ":https"
}
// Open the listeners
udpAddr, err := net.ResolveUDPAddr("udp", addr)
if err != nil {
return err
}
udpConn, err := net.ListenUDP("udp", udpAddr)
if err != nil {
return err
}
defer udpConn.Close()
if handler == nil {
handler = http.DefaultServeMux
}
quicServer := http3.Server{
Handler: handler,
TLSConfig: http3.ConfigureTLSConfig(
&tls.Config{
Certificates: certs,
MinVersion: tls.VersionTLS13,
NextProtos: []string{"h3", "h2", "http/1.1"},
PreferServerCipherSuites: true,
}),
QUICConfig: &quic.Config{
Allow0RTT: true,
EnableDatagrams: true,
},
}
hErr := make(chan error, 1)
qErr := make(chan error, 1)
go func() {
hErr <- http.ListenAndServeTLS(addr, certFile, keyFile, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
quicServer.SetQUICHeaders(w.Header())
handler.ServeHTTP(w, r)
}))
}()
go func() {
qErr <- quicServer.Serve(udpConn)
}()
select {
case err := <-hErr:
quicServer.Close()
return err
case err := <-qErr:
// Cannot close the HTTP server or wait for requests to complete properly :/
return err
}
}
// 获取本机有效的局域网IP地址(IPv4和IPv6)
func getIP() ([]net.IP, []net.IP, error) {
var ipv4Addrs []net.IP
var ipv6Addrs []net.IP
// 获取所有网络接口
interfaces, err := net.Interfaces()
if err != nil {
return nil, nil, err
}
for _, iface := range interfaces {
// 过滤无效接口(未启用或回环接口)
if iface.Flags&net.FlagUp == 0 || iface.Flags&net.FlagLoopback != 0 {
continue
}
// 获取接口地址
addrs, err := iface.Addrs()
if err != nil {
continue
}
for _, addr := range addrs {
var ip net.IP
switch v := addr.(type) {
case *net.IPNet:
ip = v.IP
case *net.IPAddr:
ip = v.IP
default:
continue
}
// 过滤回环地址
if ip.IsLoopback() {
continue
}
// 分类处理
if ipv4 := ip.To4(); ipv4 != nil {
ipv4Addrs = append(ipv4Addrs, ipv4)
} else if ipv6 := ip.To16(); ipv6 != nil {
// 过滤IPv6链路本地地址(可选)
// if ipv6.IsLinkLocalUnicast() {
// continue
// }
ipv6Addrs = append(ipv6Addrs, ipv6)
}
}
}
return ipv4Addrs, ipv6Addrs, nil
}
func main() {
var crtPath = flag.String("crt", "D:/study/ssh-key/webdemo/server.crt", "crt路径")
var keyPath = flag.String("key", "D:/study/ssh-key/webdemo/server.key", "key路径")
var username = flag.String("u", "", "用户名") //默认用户名admin
var password string
flag.StringVar(&password, "password", "", "密码") //长参数-password
flag.StringVar(&password, "p", "", "密码") //短参数-p
port := flag.Int("port", 443, "端口")
var path_show = flag.String("path", ".", "文件路径") //文件加载路径,绝对路径可以,相对路径也可以,但需要注意加引号
var showVersion bool
flag.BoolVar(&showVersion, "version", false, "-version输出版本信息")
flag.Parse()
if showVersion {
// fmt.Printf("%+v\n", appVersion.AppInfo)
fmt.Println(appVersion.BuildVersion())
os.Exit(0)
}
// result1 := exit_path(*crtPath) //crt证书是否存在
// result2 := exit_path(*keyPath) //key密钥是否存在
if exit_path(*path_show) != 0 {
log.Println("\033[31m ", *path_show, "\033[0m当前文件(文件夹)路径不存在,请重新输入")
os.Exit(1)
}
fileServer := http.FileServer(http.Dir(*path_show))
authHandler := basicAuth(fileServer, *username, password, *path_show)
log.Printf("\n用户名‘\033[32m" + *username + "\033[0m’ 密码‘\033[32m" + password + "\033[0m’")
mux := http.NewServeMux()
mux.Handle("/", authHandler) //当前目录
cert, err_tls := tls.LoadX509KeyPair(*crtPath, *keyPath)
log.Println("文件路径 \033[33m" + *path_show + "\033[0m")
if err_tls == nil {
// log.Println("文件路径 \033[33m" + *path_show + "\033[0m")
log.Printf("\033[33m%d\033[0m端口启用https", *port)
ipv4, ipv6, err := getIP()
if err != nil {
log.Println("Error:", err)
}
// fmt.Println("IPv4 Addresses:")
for _, ip := range ipv4 {
log.Printf("ipv4地址 https://%s:%d", ip, *port)
}
// log.Println("\nIPv6 Addresses:")
for _, ip := range ipv6 {
log.Printf("ipv6地址 https://[%s]:%d", ip, *port)
}
_ = cert
// srv := http.Server{ //http2
// Addr: ":" + strconv.Itoa(*port), // fmt.Sprintf(":%d", *port),
// Handler: mux,
// TLSConfig: &tls.Config{
// Certificates: []tls.Certificate{cert},
// MinVersion: tls.VersionTLS13,
// PreferServerCipherSuites: true},
// }
// err_https := srv.ListenAndServeTLS(*crtPath, *keyPath)
// err_https := http.ListenAndServeTLS(fmt.Sprintf(":%d", *port), *crtPath, *keyPath, mux) //一句话的http2
// srv3 := http3.Server{ //http3 quic协议纯粹只开放udp端口,不开放tcp端口
// Handler: mux,
// Addr: ":" + strconv.Itoa(*port),
// TLSConfig: http3.ConfigureTLSConfig(
// &tls.Config{
// Certificates: []tls.Certificate{cert},
// MinVersion: tls.VersionTLS13,
// NextProtos: []string{"h3", "h2", "http/1.1"},
// PreferServerCipherSuites: true,
// }),
// QUICConfig: &quic.Config{
// Allow0RTT: true,
// EnableDatagrams: true,
// },
// }
// err_https := srv3.ListenAndServeTLS(*crtPath, *keyPath)
// err_https := http3.ListenAndServeTLS(":"+strconv.Itoa(*port), *crtPath, *keyPath, mux) //http3支持tcp端口,兼容性最好
err_https := quicgo_ListenAndServeTLS(":"+strconv.Itoa(*port), *crtPath, *keyPath, mux) //http3.ListenAndServeTLS源代码增加了tls.config和quic.config
if err_https != nil {
log.Println(err_https.Error())
}
//可以使用crypto/tls中的generate_cert.go来生成cert.pem和key.pem
//go run $GOROOT/src/crypto/tls/generate_cert.go --host 域名/IP
//也可用https://github.com/FiloSottile/mkcert项目签发证书
//.\mkcert-v1.4.4-windows-amd64.exe -key-file ./127.0.0.1-key -cert-file ./127.0.0.1.crt 127.0.0.1
} else {
if *port == 443 {
*port = 80
}
log.Println(err_tls)
log.Printf("找不到证书和私钥,\033[33m%d\033[0m端口启用http", *port)
ipv4, ipv6, err := getIP()
if err != nil {
log.Println("Error:", err)
}
// fmt.Println("IPv4 Addresses:")
for _, ip := range ipv4 {
log.Printf("ipv4地址 https://%s:%d", ip, *port)
}
// log.Println("\nIPv6 Addresses:")
for _, ip := range ipv6 {
log.Printf("ipv6地址 https://[%s]:%d", ip, *port)
}
// http.Handle("/", authHandler) //当前目录
err_http := http.ListenAndServe(":"+strconv.Itoa(*port), mux)
//监听8080端口,外网可访问http://ip:port
if err_http != nil {
log.Println(err_http.Error())
}
}
}