From 5dce30523b2b6e38ea77381c9bf88ba0b4d0539d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=97=E5=AD=90?= Date: Fri, 25 Oct 2024 02:41:58 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E5=90=8C=E6=97=B6?= =?UTF-8?q?=E8=BE=93=E5=87=BAipv4=20v6=E5=9C=B0=E5=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/service/cli.go | 28 ++++++++++++++---- pkg/tools/tools.go | 65 ++++++++++++++++++++++++++++++++++++----- pkg/tools/tools_test.go | 22 ++++++++++++-- 3 files changed, 101 insertions(+), 14 deletions(-) diff --git a/internal/service/cli.go b/internal/service/cli.go index 71dd1b6a..e2ee5455 100644 --- a/internal/service/cli.go +++ b/internal/service/cli.go @@ -122,10 +122,7 @@ func (s *CliService) Info(ctx context.Context, cmd *cli.Command) error { if app.Conf.Bool("http.tls") { protocol = "https" } - ip, err := tools.GetPublicIP() - if err != nil { - ip = "127.0.0.1" - } + port := app.Conf.String("http.port") if port == "" { return fmt.Errorf("端口获取失败") @@ -139,7 +136,28 @@ func (s *CliService) Info(ctx context.Context, cmd *cli.Command) error { color.Greenln(fmt.Sprintf("密码: %s", password)) color.Greenln(fmt.Sprintf("端口: %s", port)) color.Greenln(fmt.Sprintf("入口: %s", entrance)) - color.Greenln(fmt.Sprintf("地址: %s://%s:%s%s", protocol, ip, port, entrance)) + + lv4, err := tools.GetLocalIPv4() + if err == nil { + color.Greenln(fmt.Sprintf("本地IPv4地址: %s://%s:%s%s", protocol, lv4, port, entrance)) + } + lv6, err := tools.GetLocalIPv6() + if err == nil { + color.Greenln(fmt.Sprintf("本地IPv6地址: %s://[%s]:%s%s", protocol, lv6, port, entrance)) + } + rv4, err := tools.GetPublicIPv4() + if err == nil { + color.Greenln(fmt.Sprintf("公网IPv4地址: %s://%s:%s%s", protocol, rv4, port, entrance)) + } + rv6, err := tools.GetPublicIPv6() + if err == nil { + color.Greenln(fmt.Sprintf("公网IPv6地址: %s://[%s]:%s%s", protocol, rv6, port, entrance)) + } + + color.Infoln(fmt.Sprintf("请根据自身网络情况自行选择合适的地址访问面板")) + color.Infoln(fmt.Sprintf("如无法访问,请检查服务器运营商安全组和防火墙是否放行%s端口", port)) + color.Infoln(fmt.Sprintf("若仍无法访问,可尝试运行 panel-cli https off 关闭面板HTTPS")) + color.Warnln(fmt.Sprintf("警告:关闭面板HTTPS后,面板安全性将大大降低,请谨慎操作")) return nil } diff --git a/pkg/tools/tools.go b/pkg/tools/tools.go index 22016e41..49959f51 100644 --- a/pkg/tools/tools.go +++ b/pkg/tools/tools.go @@ -2,7 +2,10 @@ package tools import ( + "context" "errors" + stdnet "net" + "net/http" "slices" "strings" "time" @@ -86,8 +89,8 @@ func RestartPanel() { // IsChina 是否中国大陆 func IsChina() bool { client := resty.New() - client.SetTimeout(5 * time.Second) - client.SetRetryCount(2) + client.SetTimeout(3 * time.Second) + client.SetRetryCount(3) resp, err := client.R().Get("https://www.cloudflare-cn.com/cdn-cgi/trace") if err != nil || !resp.IsSuccess() { @@ -101,16 +104,64 @@ func IsChina() bool { return false } -// GetPublicIP 获取公网IP -func GetPublicIP() (string, error) { +// GetPublicIPv4 获取公网IPv4 +func GetPublicIPv4() (string, error) { client := resty.New() - client.SetTimeout(5 * time.Second) - client.SetRetryCount(2) + client.SetTimeout(3 * time.Second) + client.SetRetryCount(3) + client.SetTransport(&http.Transport{ + DialContext: func(ctx context.Context, network string, addr string) (stdnet.Conn, error) { + return (&stdnet.Dialer{}).DialContext(ctx, "tcp4", addr) + }, + }) resp, err := client.R().Get("https://www.cloudflare-cn.com/cdn-cgi/trace") if err != nil || !resp.IsSuccess() { - return "", errors.New("获取公网IP失败") + return "", errors.New("failed to get public ipv4 address") } return strings.TrimPrefix(strings.Split(resp.String(), "\n")[2], "ip="), nil } + +// GetPublicIPv6 获取公网IPv6 +func GetPublicIPv6() (string, error) { + client := resty.New() + client.SetTimeout(3 * time.Second) + client.SetRetryCount(3) + client.SetTransport(&http.Transport{ + DialContext: func(ctx context.Context, network string, addr string) (stdnet.Conn, error) { + return (&stdnet.Dialer{}).DialContext(ctx, "tcp6", addr) + }, + }) + + resp, err := client.R().Get("https://www.cloudflare-cn.com/cdn-cgi/trace") + if err != nil || !resp.IsSuccess() { + return "", errors.New("failed to get public ipv6 address") + } + + return strings.TrimPrefix(strings.Split(resp.String(), "\n")[2], "ip="), nil +} + +// GetLocalIPv4 获取本地IPv4 +func GetLocalIPv4() (string, error) { + conn, err := stdnet.Dial("udp", "119.29.29.29:53") + if err != nil { + return "", err + } + defer conn.Close() + + local := conn.LocalAddr().(*stdnet.UDPAddr) + return local.IP.String(), nil +} + +// GetLocalIPv6 获取本地IPv6 +func GetLocalIPv6() (string, error) { + conn, err := stdnet.Dial("udp", "[2402:4e00::]:53") + if err != nil { + return "", err + } + defer conn.Close() + + local := conn.LocalAddr().(*stdnet.UDPAddr) + return local.IP.String(), nil +} diff --git a/pkg/tools/tools_test.go b/pkg/tools/tools_test.go index 0082aa23..b4d7b569 100644 --- a/pkg/tools/tools_test.go +++ b/pkg/tools/tools_test.go @@ -18,8 +18,26 @@ func (s *HelperTestSuite) TestGetMonitoringInfo() { s.NotNil(CurrentInfo(nil, nil)) } -func (s *HelperTestSuite) TestGetPublicIP() { - ip, err := GetPublicIP() +func (s *HelperTestSuite) TestGetPublicIPv4() { + ip, err := GetPublicIPv4() + s.Nil(err) + s.NotEmpty(ip) +} + +func (s *HelperTestSuite) TestGetPublicIPv6() { + ip, err := GetPublicIPv6() + s.Nil(err) + s.NotEmpty(ip) +} + +func (s *HelperTestSuite) TestGetLocalIPv4() { + ip, err := GetLocalIPv4() + s.Nil(err) + s.NotEmpty(ip) +} + +func (s *HelperTestSuite) TestGetLocalIPv6() { + ip, err := GetLocalIPv6() s.Nil(err) s.NotEmpty(ip) }