diff --git a/Dockerfile b/Dockerfile index ef466cb..bab8015 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,7 +19,7 @@ COPY --from=builder_node /web/ui /anylink/server/ui #TODO 本地打包时使用镜像 #RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories RUN apk add --no-cache git -RUN cd /anylink/server;go build -o anylink -ldflags "-X main.COMMIT_ID=$(git rev-parse HEAD)" \ +RUN cd /anylink/server;go build -o anylink -ldflags "-X main.CommitId=$(git rev-parse HEAD)" \ && /anylink/server/anylink tool -v # anylink diff --git a/README.md b/README.md index 3e7d760..a721c50 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ AnyLink 服务端仅在CentOS 7、Ubuntu 18.04测试通过,如需要安装在 > > https://github.com/bjdgyc/anylink/releases -> 升级 go version = 1.15 +> 升级 go version = 1.16 > > 需要提前安装好 golang 和 nodejs @@ -47,11 +47,11 @@ sh build.sh # 注意使用root权限运行 cd anylink-deploy -sudo ./anylink --conf="conf/server.toml" +sudo ./anylink # 默认管理后台访问地址 # http://host:8800 -# 默认账号密码 +# 默认账号 密码 # admin 123456 ``` diff --git a/build.sh b/build.sh index 8408c92..eda8745 100644 --- a/build.sh +++ b/build.sh @@ -12,11 +12,6 @@ function RETVAL() { #当前目录 cpath=$(pwd) -echo "编译二进制文件" -cd $cpath/server -go build -v -o anylink -ldflags "-X main.COMMIT_ID=$(git rev-parse HEAD)" -RETVAL $? - echo "编译前端项目" cd $cpath/web #国内可替换源加快速度 @@ -26,21 +21,26 @@ npm run build --registry=https://registry.npm.taobao.org #npm run build RETVAL $? +echo "编译二进制文件" +cd $cpath/server +rm -rf ui +cp -rf $cpath/web/ui . +go build -v -o anylink -ldflags "-X main.CommitId=$(git rev-parse HEAD)" +RETVAL $? + cd $cpath echo "整理部署文件" deploy="anylink-deploy" -rm -rf $deploy +rm -rf $deploy ${deploy}.tar.gz mkdir $deploy -mkdir $deploy/log cp -r server/anylink $deploy -cp -r server/conf $deploy -cp -r server/files $deploy cp -r server/bridge-init.sh $deploy cp -r systemd $deploy -cp -r web/ui $deploy + +tar zcvf ${deploy}.tar.gz $deploy #注意使用root权限运行 #cd anylink-deploy diff --git a/docker_entrypoint.sh b/docker_entrypoint.sh index 3a7291a..e0393a3 100644 --- a/docker_entrypoint.sh +++ b/docker_entrypoint.sh @@ -16,7 +16,7 @@ case $var1 in *) sysctl -w net.ipv4.ip_forward=1 iptables -t nat -A POSTROUTING -s "${IPV4_CIDR}" -o eth0+ -j MASQUERADE - # iptables -nL -t nat + iptables -nL -t nat /app/anylink "$@" ;; diff --git a/question.md b/question.md index bacb417..d6542ca 100644 --- a/question.md +++ b/question.md @@ -6,10 +6,10 @@ > 添加QQ群: 567510628 ### 远程桌面连接 -> 本软件不支持远程桌面连接,请注意。 +> 本软件不支持远程桌面里面连接anyconnect,请注意。 ### 私有证书问题 > anylink 默认不支持私有证书 > -> 仅测试的话,可以通过 https://github.com/square/certstrap 生成私有的证书, 然后把CA证书放在客户端机器上即可以连接。 +> 其他使用私有证书的问题,请自行解决 diff --git a/server/admin/server.go b/server/admin/server.go index e679a99..557debc 100644 --- a/server/admin/server.go +++ b/server/admin/server.go @@ -2,6 +2,7 @@ package admin import ( + "embed" "net/http" "net/http/pprof" @@ -9,7 +10,9 @@ import ( "github.com/gorilla/mux" ) -// 开启服务 +var UiData embed.FS + +// StartAdmin 开启服务 func StartAdmin() { r := mux.NewRouter() @@ -17,7 +20,8 @@ func StartAdmin() { r.Handle("/", http.RedirectHandler("/ui/", http.StatusFound)).Name("index") r.PathPrefix("/ui/").Handler( - http.StripPrefix("/ui/", http.FileServer(http.Dir(base.Cfg.UiPath))), + // http.StripPrefix("/ui/", http.FileServer(http.Dir(base.Cfg.UiPath))), + http.FileServer(http.FS(UiData)), ).Name("static") r.HandleFunc("/base/login", Login).Name("login") diff --git a/server/base/cfg.go b/server/base/cfg.go index 4d7f79a..bfaab70 100644 --- a/server/base/cfg.go +++ b/server/base/cfg.go @@ -39,7 +39,6 @@ type ServerConfig struct { DbFile string `json:"db_file"` CertFile string `json:"cert_file"` CertKey string `json:"cert_key"` - UiPath string `json:"ui_path"` FilesPath string `json:"files_path"` LogPath string `json:"log_path"` LogLevel string `json:"log_level"` @@ -70,20 +69,20 @@ type ServerConfig struct { func initServerCfg() { - sf, _ := filepath.Abs(cfgFile) - base := filepath.Dir(sf) + // TODO 取消绝对地址转换 + // sf, _ := filepath.Abs(cfgFile) + // base := filepath.Dir(sf) // 转换成绝对路径 - Cfg.DbFile = getAbsPath(base, Cfg.DbFile) - Cfg.CertFile = getAbsPath(base, Cfg.CertFile) - Cfg.CertKey = getAbsPath(base, Cfg.CertKey) - Cfg.UiPath = getAbsPath(base, Cfg.UiPath) - Cfg.FilesPath = getAbsPath(base, Cfg.FilesPath) - Cfg.LogPath = getAbsPath(base, Cfg.LogPath) + // Cfg.DbFile = getAbsPath(base, Cfg.DbFile) + // Cfg.CertFile = getAbsPath(base, Cfg.CertFile) + // Cfg.CertKey = getAbsPath(base, Cfg.CertKey) + // Cfg.UiPath = getAbsPath(base, Cfg.UiPath) + // Cfg.FilesPath = getAbsPath(base, Cfg.FilesPath) + // Cfg.LogPath = getAbsPath(base, Cfg.LogPath) - if len(Cfg.JwtSecret) < 20 { - fmt.Println("请设置 jwt_secret 长度20位以上") - os.Exit(0) + if Cfg.JwtSecret == defaultJwt { + fmt.Fprintln(os.Stderr, "=== 使用默认的jwt_secret有安全风险,请设置新的jwt_secret ===") } fmt.Printf("ServerCfg: %+v \n", Cfg) diff --git a/server/base/cmd.go b/server/base/cmd.go index 1ea3288..baa3afb 100644 --- a/server/base/cmd.go +++ b/server/base/cmd.go @@ -1,13 +1,10 @@ package base import ( - "errors" "fmt" - "math/rand" "os" "runtime" "strings" - "time" "github.com/bjdgyc/anylink/pkg/utils" "github.com/spf13/cobra" @@ -64,13 +61,12 @@ func init() { viper.SetConfigFile(cfgFile) viper.AutomaticEnv() - _, err := os.Stat(cfgFile) - if errors.Is(err, os.ErrNotExist) { - // 文件不存在,不做处理 + if cfgFile == "" { + // 没有配置文件,不做处理 return } - err = viper.ReadInConfig() + err := viper.ReadInConfig() if err != nil { fmt.Println("Using config file:", err) } @@ -79,7 +75,7 @@ func init() { viper.SetEnvPrefix("link") // 基础配置 - rootCmd.Flags().StringVarP(&cfgFile, "conf", "c", "./conf/server.toml", "config file") + rootCmd.Flags().StringVarP(&cfgFile, "conf", "c", "", "config file") for _, v := range configs { if v.Typ == cfgStr { @@ -118,7 +114,6 @@ func initToolCmd() *cobra.Command { fmt.Printf("%s v%s build on %s [%s, %s] commit_id(%s) \n", APP_NAME, APP_VER, runtime.Version(), runtime.GOOS, runtime.GOARCH, CommitId) case secret: - rand.Seed(time.Now().UnixNano()) s, _ := utils.RandSecret(40, 60) s = strings.Trim(s, "=") fmt.Printf("Secret:%s\n", s) diff --git a/server/base/config.go b/server/base/config.go index f45d80d..8202d79 100644 --- a/server/base/config.go +++ b/server/base/config.go @@ -4,6 +4,8 @@ const ( cfgStr = iota cfgInt cfgBool + + defaultJwt = "abcdef.0123456789.abcdef" ) type config struct { @@ -24,7 +26,6 @@ var configs = []config{ {Typ: cfgStr, Name: "db_file", Usage: "数据库地址", ValStr: "./data.db"}, {Typ: cfgStr, Name: "cert_file", Usage: "证书文件", ValStr: "./vpn_cert.pem"}, {Typ: cfgStr, Name: "cert_key", Usage: "证书密钥", ValStr: "./vpn_cert.key"}, - {Typ: cfgStr, Name: "ui_path", Usage: "ui文件路径", ValStr: "./ui"}, {Typ: cfgStr, Name: "files_path", Usage: "外部下载文件路径", ValStr: "./files"}, {Typ: cfgStr, Name: "log_path", Usage: "日志文件路径", ValStr: ""}, {Typ: cfgStr, Name: "log_level", Usage: "日志等级", ValStr: "info"}, @@ -32,7 +33,7 @@ var configs = []config{ {Typ: cfgStr, Name: "issuer", Usage: "系统名称", ValStr: "XX公司VPN"}, {Typ: cfgStr, Name: "admin_user", Usage: "管理用户名", ValStr: "admin"}, {Typ: cfgStr, Name: "admin_pass", Usage: "管理用户密码", ValStr: "$2a$10$UQ7C.EoPifDeJh6d8.31TeSPQU7hM/NOM2nixmBucJpAuXDQNqNke"}, - {Typ: cfgStr, Name: "jwt_secret", Usage: "JWT密钥", ValStr: "iLmspvOiz*%ovfcs*wersdf#heR8pNU4XxBm&mW$aPCjSRMbYH#&"}, + {Typ: cfgStr, Name: "jwt_secret", Usage: "JWT密钥", ValStr: defaultJwt}, {Typ: cfgStr, Name: "link_mode", Usage: "虚拟网络类型", ValStr: "tun"}, {Typ: cfgStr, Name: "ipv4_cidr", Usage: "ip地址网段", ValStr: "192.168.10.0/24"}, {Typ: cfgStr, Name: "ipv4_gateway", Usage: "ipv4_gateway", ValStr: "192.168.10.1"}, diff --git a/server/conf/server.toml b/server/conf/server-sample.toml similarity index 87% rename from server/conf/server.toml rename to server/conf/server-sample.toml index 0cd6b76..cfd89db 100644 --- a/server/conf/server.toml +++ b/server/conf/server-sample.toml @@ -6,10 +6,9 @@ #数据文件 db_file = "./data.db" #证书文件 -cert_file = "./test_vpn_cert.pem" -cert_key = "./test_vpn_key.pem" -ui_path = "../ui" -files_path = "../files" +cert_file = "./vpn_cert.pem" +cert_key = "./vpn_cert.key" +files_path = "./files" #日志目录,为空写入标准输出 #log_path = "../log" log_path = "" @@ -22,7 +21,7 @@ issuer = "XX公司VPN" admin_user = "admin" #pass 123456 admin_pass = "$2a$10$UQ7C.EoPifDeJh6d8.31TeSPQU7hM/NOM2nixmBucJpAuXDQNqNke" -jwt_secret = "iLmspvOiz*%ovfcs*wersdf#heR8pNU4XxBm&mW$aPCjSRMbYH#&" +jwt_secret = "abcdef.0123456789.abcdef" #服务监听地址 diff --git a/server/conf/test_vpn_cert.pem b/server/conf/test_vpn_cert.pem deleted file mode 100644 index a5e002a..0000000 --- a/server/conf/test_vpn_cert.pem +++ /dev/null @@ -1,19 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDGDCCAgACCQCecQDpy/8hRTANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJD -TjELMAkGA1UECAwCQkoxCzAJBgNVBAcMAkJKMQswCQYDVQQKDAJCRDELMAkGA1UE -CwwCQkQxCzAJBgNVBAMMAkNTMB4XDTIxMDMyNjA5MTkwNloXDTMxMDMyNDA5MTkw -NlowTjELMAkGA1UEBhMCQ04xCzAJBgNVBAgMAlNIMQswCQYDVQQHDAJTSDELMAkG -A1UECgwCVE0xCzAJBgNVBAsMAlRNMQswCQYDVQQDDAJDUzCCASIwDQYJKoZIhvcN -AQEBBQADggEPADCCAQoCggEBAJtDxHduS8gjI0P6txHS+cODxKjyjNiCBa7tFgSc -d9hRrzCvK4Q4M5StKJoSczmHl0C3HVoq92Gv1vENxq4irYdCrwLeOZGyt7urUlbs -PkvEoVXxfAkPpue+JewG/CvGArJeP7UGsP5IrD0Dt5X1DP677K6qf5igzyaJqYJu -RDJ5wR84BoDvY66Zc578N9tK9XusdJ63gQ5jGcG4Dneu1UX3g8lQkJ6P0xLXTh7W -u5Sjx8axbDcFxbDLxNGL1yPgAjhIRgMfaWLwuQQg4WKFsdMljv1Flz8/h91z2xo+ -+E/B4YF0UFWTcWQ2TQ8w8noDqnnXVVQyOvuI3aajodml/f0CAwEAATANBgkqhkiG -9w0BAQsFAAOCAQEAd89n0eWXgO1lqMciWmS9xY8Sj/U840bPo/4Kclsm1vFNvIXu -I50PeaNiU2E5+CMk8AwXaJ5gDO7vsRxvLLRAUWZeuxSror2a0RkViEFW+UKcBuuB -Izl9giXUhB/P85+We1ma5jizqj7OpzgMkzkcTZL2M6Gw6IWY4jopvLQjiCooSiYF -wtLZjuFKfpLrPw5RgpWI4L8Hftbkmh6Q8nqcoQvgwm7rLrD5VqiTu7Rk1SXTFuXn -uuazXasWIWRVGFuFcYP1rwyOfp9HhCFKngi0w8IRnbOcaPdXydtbKMcKt5z9zQX5 -BqrZ3ZfPp5HeklG7L8eQrnp4ines6YDshPnaRQ== ------END CERTIFICATE----- diff --git a/server/conf/test_vpn_key.pem b/server/conf/test_vpn_key.pem deleted file mode 100644 index 74897b9..0000000 --- a/server/conf/test_vpn_key.pem +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEogIBAAKCAQEAm0PEd25LyCMjQ/q3EdL5w4PEqPKM2IIFru0WBJx32FGvMK8r -hDgzlK0omhJzOYeXQLcdWir3Ya/W8Q3GriKth0KvAt45kbK3u6tSVuw+S8ShVfF8 -CQ+m574l7Ab8K8YCsl4/tQaw/kisPQO3lfUM/rvsrqp/mKDPJompgm5EMnnBHzgG -gO9jrplznvw320r1e6x0nreBDmMZwbgOd67VRfeDyVCQno/TEtdOHta7lKPHxrFs -NwXFsMvE0YvXI+ACOEhGAx9pYvC5BCDhYoWx0yWO/UWXPz+H3XPbGj74T8HhgXRQ -VZNxZDZNDzDyegOqeddVVDI6+4jdpqOh2aX9/QIDAQABAoIBADWT2fz4g5AJiAbS -QlAVRHjSRI+kOzQPEhT93SY0NCribRjYqaSTnEEGy8b27OoCPxBm3+sYfosoGXzP -Kys17jmJqkjMFIORb1OEWAKEvS56KM42aX3a99ZqSD29X1Ffn9ibK1K1f2gP/deE -K9rEV/qjMJZJYYRyoWkEAglvMXtU/NMRoTuFYtrJPr9sFEfpBFq97WpWiyMdLKTG -MmlN+T1CXFQj/+mpv+DDSXcwLPBxAttDYE2GeqlhntId0I6cgaEGMO42D6fnqrKi -PDilA/D6zos4o/bpRGvVBdXHqOXvX2stNHK+PvEX46GRd+OZhLh0KEcrWAx8cXs9 -ZhugTyECgYEAyffRPd98acL0OhXJR9mZTgDdotl7iYq+RTZbmEvAFst3mL3LA6Ba -BTrwRLh9x8lzxoTQHHFaJL63kIrN6QAR9e3+pR0e8IX3vYCVGIlRCYB5CrE/O3Pi -B9R17tCI5dFrFXYiST38sjwrWG9+geKarbUH5AZrZEO5uw0q7+4F3TkCgYEAxM1h -Xo+xRt8RXoWZ6Cl66HhZKIvDcxkBtoNh54YLzrVpv0D+RvAWNDzRVXbbIUUpBGPN -pHrwU8G0qWr4Q/Zx+vnckqotGMTNCB7vcmB/qwF9grNW9E0rCyIYLXtJcEiclJIF -Oe406YXl7mSG1I6QjAADz8PNb4++Ct1+hVS56uUCgYAx9g/Y0nQgZY2s4L7N+1Il -LammI06gE6ZF0NCPuA1oliSbsDeMShp6uL2/AjR7O6ZcMXaZ0qCN/m/CXdPaE55d -y+X2SmHg9gL26dv4Gd/mDdXjgz01I9GCRlh2Hzf+QfPPd027+I2OObwvQEV3M+s3 -lVTCX6QpRWeokfVRLPxeYQKBgDIYPVK+rNdnbJps05JfDKQkDj3d5bBkiyUUKFWw -r0y8rOA8AP25m01MtdRVXs4HNruhU/UsPgRz6DK/wdY64ySJeXXzz2rgnXgVt8mb -eqPiyzn7wISLKAu7cAATw8vLD+BZku7+DYXryW13NULhzzVzw4SdSKu/IRbO7qet -u21pAoGAd2mBJ+PWKnUkARS8gQ3Y3cagA/qGGr094P9relglRDBv/Pm7kTUt6K8B -NnpqWydcVtcrXmNzGRx4ftm18SzmTJEohF14nF9424q4aiWoNZyG8adxaI0Yqv3G -LnH8n2fzC+pf31LijBRM8DRnepah64mLF+OM/SxgVg1nP9jVUG4= ------END RSA PRIVATE KEY----- diff --git a/server/handler/server.go b/server/handler/server.go index ffd5672..4df919b 100644 --- a/server/handler/server.go +++ b/server/handler/server.go @@ -2,27 +2,52 @@ package handler import ( "crypto/tls" + "errors" "fmt" "log" "net" "net/http" + "os" "time" "github.com/bjdgyc/anylink/base" "github.com/bjdgyc/anylink/pkg/proxyproto" "github.com/gorilla/mux" + "github.com/pion/dtls/v2/pkg/crypto/selfsign" ) func startTls() { - addr := base.Cfg.ServerAddr - certFile := base.Cfg.CertFile - keyFile := base.Cfg.CertKey + + var ( + err error + + addr = base.Cfg.ServerAddr + certFile = base.Cfg.CertFile + keyFile = base.Cfg.CertKey + certs = make([]tls.Certificate, 1) + ln net.Listener + ) + + // 判断证书文件 + _, err = os.Stat(certFile) + if errors.Is(err, os.ErrNotExist) { + // 自动生成证书 + certs[0], err = selfsign.GenerateSelfSignedWithDNS("vpn.anylink") + } else { + // 使用自定义证书 + certs[0], err = tls.LoadX509KeyPair(certFile, keyFile) + } + + if err != nil { + panic(err) + } // 设置tls信息 tlsConfig := &tls.Config{ NextProtos: []string{"http/1.1"}, MinVersion: tls.VersionTLS12, InsecureSkipVerify: true, + Certificates: certs, } srv := &http.Server{ Addr: addr, @@ -31,9 +56,7 @@ func startTls() { ErrorLog: base.GetBaseLog(), } - var ln net.Listener - - ln, err := net.Listen("tcp", addr) + ln, err = net.Listen("tcp", addr) if err != nil { log.Fatal(err) } @@ -44,7 +67,7 @@ func startTls() { } base.Info("listen server", addr) - err = srv.ServeTLS(ln, certFile, keyFile) + err = srv.ServeTLS(ln, "", "") if err != nil { base.Fatal(err) } diff --git a/server/main.go b/server/main.go index 17012db..f2efc9e 100644 --- a/server/main.go +++ b/server/main.go @@ -1,21 +1,30 @@ // AnyLink 是一个企业级远程办公vpn软件,可以支持多人同时在线使用。 +// +build !windows + package main import ( + "embed" "os" "os/signal" "syscall" + "github.com/bjdgyc/anylink/admin" + "github.com/bjdgyc/anylink/base" "github.com/bjdgyc/anylink/handler" ) +//go:embed ui +var uiData embed.FS + // 程序版本 -var COMMIT_ID string +var CommitId string func main() { - base.CommitId = COMMIT_ID + base.CommitId = CommitId + admin.UiData = uiData base.Start() handler.Start()