feat: Support checking proxy server connection availability (#10502)

Refs #9843
This commit is contained in:
ssongliu 2025-09-26 17:24:12 +08:00 committed by GitHub
parent 34b39f6eb8
commit 3f141346fa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 78 additions and 1 deletions

View file

@ -2,6 +2,7 @@ package service
import (
"bytes"
"context"
"crypto/rand"
"crypto/rsa"
"crypto/tls"
@ -9,8 +10,10 @@ import (
"encoding/json"
"encoding/pem"
"fmt"
"io"
"net"
"net/http"
"net/url"
"os"
"path"
"strconv"
@ -30,6 +33,7 @@ import (
"github.com/1Panel-dev/1Panel/core/utils/req_helper/proxy_local"
"github.com/1Panel-dev/1Panel/core/utils/xpack"
"github.com/gin-gonic/gin"
"golang.org/x/net/proxy"
)
type SettingService struct{}
@ -38,7 +42,6 @@ type ISettingService interface {
GetSettingInfo() (*dto.SettingInfo, error)
LoadInterfaceAddr() ([]string, error)
Update(key, value string) error
UpdateProxy(req dto.ProxyUpdate) error
UpdatePassword(c *gin.Context, old, new string) error
UpdatePort(port uint) error
UpdateBindInfo(req dto.BindInfo) error
@ -48,6 +51,8 @@ type ISettingService interface {
GenerateApiKey() (string, error)
UpdateApiConfig(req dto.ApiInterfaceConfig) error
UpdateProxy(req dto.ProxyUpdate) error
GetTerminalInfo() (*dto.TerminalInfo, error)
UpdateTerminal(req dto.TerminalInfo) error
@ -192,6 +197,10 @@ func (u *SettingService) UpdateProxy(req dto.ProxyUpdate) error {
proxyUrl := req.ProxyUrl
if req.ProxyType == "https" || req.ProxyType == "http" {
proxyUrl = req.ProxyType + "://" + req.ProxyUrl
req.ProxyUrl = proxyUrl
}
if err := checkProxy(req); err != nil {
return err
}
if err := settingRepo.Update("ProxyUrl", proxyUrl); err != nil {
return err
@ -691,3 +700,61 @@ func loadDockerProxy(req dto.ProxyUpdate) string {
return fmt.Sprintf("%s://%s%s:%s", req.ProxyType, account, req.ProxyUrl, req.ProxyPort)
}
func checkProxy(req dto.ProxyUpdate) error {
var transport http.Transport
proxyItem := net.JoinHostPort(req.ProxyUrl, req.ProxyPort)
switch req.ProxyType {
case "http", "https":
proxyURL, err := url.Parse(proxyItem)
if err != nil {
return buserr.WithErr("ErrProxySetting", fmt.Errorf("parse url %s failed, err: %v", proxyItem, err))
}
if len(req.ProxyUser) != 0 {
proxyURL.User = url.UserPassword(req.ProxyUser, req.ProxyPasswd)
}
transport = http.Transport{Proxy: http.ProxyURL(proxyURL)}
case "socks5":
var auth *proxy.Auth
if len(req.ProxyUser) == 0 {
auth = nil
} else {
auth = &proxy.Auth{User: req.ProxyUser, Password: req.ProxyPasswd}
}
dialer, err := proxy.SOCKS5("tcp", proxyItem, auth, proxy.Direct)
if err != nil {
return buserr.WithErr("ErrProxySetting", fmt.Errorf("new socks5 proxy failed, err: %v", err))
}
dialContext := func(ctx context.Context, network, addr string) (net.Conn, error) {
return dialer.Dial(network, addr)
}
transport = http.Transport{DialContext: dialContext}
case "", "close":
default:
return buserr.WithDetail("ErrNotSupportType", req.ProxyType, nil)
}
defer func() {
if r := recover(); r != nil {
global.LOG.Errorf("handle request failed, error message: %v", r)
return
}
}()
client := http.Client{Timeout: 3 * time.Second, Transport: &transport}
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
request, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://1panel.cn/", nil)
if err != nil {
return buserr.WithErr("ErrProxySetting", err)
}
request.Header.Set("Content-Type", "application/json")
resp, err := client.Do(request)
if err != nil {
return buserr.WithErr("ErrProxySetting", err)
}
if _, err := io.ReadAll(resp.Body); err != nil {
return buserr.WithErr("ErrProxySetting", err)
}
defer resp.Body.Close()
return nil
}

View file

@ -21,6 +21,7 @@ ErrHttpReqNotFound: "Unable to find the requested resource {{ .err }}"
ErrHttpReqFailed: "Request failed {{ .err }}"
ErrHttpReqTimeOut: "Request timed out {{ .err }}"
ErrCreateHttpClient: "Failed to create request {{ .err }}"
ErrProxySetting: "Proxy server information unavailable {{ .err }}, please check and try again!"
# common
ErrDemoEnvironment: "Demo server, this operation is prohibited!"

View file

@ -21,6 +21,7 @@ ErrHttpReqNotFound: "No se pudo encontrar el recurso solicitado {{ .err }}"
ErrHttpReqFailed: "Solicitud fallida {{ .err }}"
ErrHttpReqTimeOut: "La solicitud ha expirado {{ .err }}"
ErrCreateHttpClient: "Error al crear la solicitud {{ .err }}"
ErrProxySetting: "Información del servidor proxy no disponible {{ .err }}, ¡compruebe e inténtelo de nuevo!"
# common
ErrDemoEnvironment: "Servidor de demostración, ¡esta operación está prohibida!"

View file

@ -21,6 +21,7 @@ ErrHttpReqNotFound: "要求されたリソースが見つかりません {{ .err
ErrHttpReqFailed: "リクエスト失敗 {{ .err }}"
ErrHttpReqTimeOut: "リクエストタイムアウト {{ .err }}"
ErrCreateHttpClient: "リクエストの作成に失敗しました {{ .err }}"
ErrProxySetting: "プロキシサーバー情報が利用できません {{ .err }}、確認して再試行してください!"
# common
ErrDemoEnvironment: "デモサーバーではこの操作は許可されていません!"

View file

@ -21,6 +21,7 @@ ErrHttpReqNotFound: "요청한 리소스를 찾을 수 없습니다 {{ .err }}"
ErrHttpReqFailed: "요청 실패 {{ .err }}"
ErrHttpReqTimeOut: "요청 시간이 초과되었습니다 {{ .err }}"
ErrCreateHttpClient: "요청 생성 실패 {{ .err }}"
ErrProxySetting: "프록시 서버 정보를 사용할 수 없음 {{ .err }}, 확인 후 다시 시도하세요!"
# common
ErrDemoEnvironment: "데모 서버에서는 이 작업이 금지되어 있습니다!"

View file

@ -21,6 +21,7 @@ ErrHttpReqNotFound: "Sumber yang diminta tidak dapat ditemui {{ .err }}"
ErrHttpReqFailed: "Permintaan gagal {{ .err }}"
ErrHttpReqTimeOut: "Permintaan telah tamat masa {{ .err }}"
ErrCreateHttpClient: "Gagal mencipta permintaan {{ .err }}"
ErrProxySetting: "Maklumat pelayan proksi tidak tersedia {{ .err }}, sila periksa dan cuba lagi!"
# common
ErrDemoEnvironment: "Pelayan demo, operasi ini dilarang!"

View file

@ -21,6 +21,7 @@ ErrHttpReqNotFound: "Recurso solicitado não encontrado {{ .err }}"
ErrHttpReqFailed: "Falha na requisição {{ .err }}"
ErrHttpReqTimeOut: "Tempo de requisição esgotado {{ .err }}"
ErrCreateHttpClient: "Falha ao criar a requisição {{ .err }}"
ErrProxySetting: "Informação do servidor proxy indisponível {{ .err }}, verifique e tente novamente!"
# common
ErrDemoEnvironment: "Servidor de demonstração, essa operação é proibida!"

View file

@ -21,6 +21,7 @@ ErrHttpReqNotFound: "Не удалось найти запрашиваемый
ErrHttpReqFailed: "Ошибка запроса {{ .err }}"
ErrHttpReqTimeOut: "Время ожидания запроса истекло {{ .err }}"
ErrCreateHttpClient: "Ошибка создания запроса {{ .err }}"
ErrProxySetting: "Информация о прокси-сервере недоступна {{ .err }}, проверьте и повторите попытку!"
# common
ErrDemoEnvironment: "Демонстрационный сервер, эта операция запрещена!"

View file

@ -21,6 +21,7 @@ ErrHttpReqNotFound: "İstenen kaynak bulunamıyor {{ .err }}"
ErrHttpReqFailed: "İstek başarısız {{ .err }}"
ErrHttpReqTimeOut: "İstek zaman aşımına uğradı {{ .err }}"
ErrCreateHttpClient: "İstek oluşturma başarısız {{ .err }}"
ErrProxySetting: "Proxy sunucu bilgisi kullanılamıyor {{ .err }}, lütfen kontrol edip tekrar deneyin!"
# common
ErrDemoEnvironment: "Demo sunucu, bu işlem yasak!"

View file

@ -21,6 +21,7 @@ ErrHttpReqNotFound: "無法找到請求的資源 {{ .err }}"
ErrHttpReqFailed: "請求失敗 {{ .err }}"
ErrHttpReqTimeOut: "請求逾時 {{ .err }}"
ErrCreateHttpClient: "建立請求失敗 {{ .err }}"
ErrProxySetting: "代理伺服器資訊不可用 {{ .err }},請檢查後重試!"
#common
ErrDemoEnvironment: "示範伺服器,禁止此操作!"

View file

@ -21,6 +21,7 @@ ErrHttpReqNotFound: "无法找到请求的资源 {{ .err }}"
ErrHttpReqFailed: "请求失败 {{ .err }}"
ErrHttpReqTimeOut: "请求超时 {{ .err }}"
ErrCreateHttpClient: "创建请求失败 {{ .err }}"
ErrProxySetting: "代理服务器信息不可用 {{ .err }},请检查后重试!"
#common
ErrDemoEnvironment: "演示服务器,禁止此操作!"