fix: Fix firewalld range port forwarding failure issue (#11390)

This commit is contained in:
ssongliu 2025-12-18 17:21:13 +08:00 committed by GitHub
parent 863ee5c172
commit c08e83e5d4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 41 additions and 35 deletions

View file

@ -9,7 +9,6 @@ import (
"github.com/1Panel-dev/1Panel/agent/global"
"github.com/1Panel-dev/1Panel/agent/utils/cmd"
"github.com/1Panel-dev/1Panel/agent/utils/controller"
"github.com/1Panel-dev/1Panel/agent/utils/re"
)
type Firewall struct{}
@ -119,24 +118,20 @@ func (f *Firewall) ListForward() ([]FireInfo, error) {
}
var datas []FireInfo
for _, line := range strings.Split(stdout, "\n") {
line = strings.TrimFunc(line, func(r rune) bool {
return r <= 32
})
if re.GetRegex(re.FirewalldForwardPattern).MatchString(line) {
match := re.GetRegex(re.FirewalldForwardPattern).FindStringSubmatch(line)
if len(match) < 4 {
continue
}
if len(match[4]) == 0 {
match[4] = "127.0.0.1"
}
datas = append(datas, FireInfo{
Port: match[1],
Protocol: match[2],
TargetIP: match[4],
TargetPort: match[3],
})
line = strings.TrimSpace(line)
parts := strings.Split(line, ":")
if len(parts) < 4 {
continue
}
if parts[3] == "toaddr=" {
parts[3] = "127.0.0.1"
}
datas = append(datas, FireInfo{
Port: strings.TrimPrefix(parts[0], "port="),
Protocol: strings.TrimPrefix(parts[1], "proto="),
TargetIP: strings.TrimPrefix(parts[3], "toaddr="),
TargetPort: strings.TrimPrefix(parts[2], "toport="),
})
}
return datas, nil
}

View file

@ -6,8 +6,8 @@ import (
)
func AddForward(protocol, srcPort, dest, destPort, iface string, save bool) error {
// iptabels destPort 范围端口规则为:%d-%d
destPort = strings.ReplaceAll(destPort, ":", "-")
srcPort = strings.ReplaceAll(srcPort, "-", ":")
itemDstPort := strings.ReplaceAll(destPort, "-", ":")
if dest != "" && dest != "127.0.0.1" && dest != "localhost" {
iptablesArg := fmt.Sprintf("-A %s", Chain1PanelPreRouting)
if iface != "" {
@ -18,15 +18,15 @@ func AddForward(protocol, srcPort, dest, destPort, iface string, save bool) erro
return err
}
if err := Run(NatTab, fmt.Sprintf("-A %s -d %s -p %s --dport %s -j MASQUERADE", Chain1PanelPostRouting, dest, protocol, destPort)); err != nil {
if err := Run(NatTab, fmt.Sprintf("-A %s -d %s -p %s --dport %s -j MASQUERADE", Chain1PanelPostRouting, dest, protocol, itemDstPort)); err != nil {
return err
}
if err := Run(FilterTab, fmt.Sprintf("-A %s -d %s -p %s --dport %s -j ACCEPT", Chain1PanelForward, dest, protocol, destPort)); err != nil {
if err := Run(FilterTab, fmt.Sprintf("-A %s -d %s -p %s --dport %s -j ACCEPT", Chain1PanelForward, dest, protocol, itemDstPort)); err != nil {
return err
}
if err := Run(FilterTab, fmt.Sprintf("-A %s -s %s -p %s --sport %s -j ACCEPT", Chain1PanelForward, dest, protocol, destPort)); err != nil {
if err := Run(FilterTab, fmt.Sprintf("-A %s -s %s -p %s --sport %s -j ACCEPT", Chain1PanelForward, dest, protocol, itemDstPort)); err != nil {
return err
}
} else {
@ -43,20 +43,21 @@ func AddForward(protocol, srcPort, dest, destPort, iface string, save bool) erro
}
func DeleteForward(num string, protocol, srcPort, dest, destPort, iface string) error {
itemDstPort := strings.ReplaceAll(destPort, "-", ":")
if err := Run(NatTab, fmt.Sprintf("-D %s %s", Chain1PanelPreRouting, num)); err != nil {
return err
}
if dest != "" && dest != "127.0.0.1" && dest != "localhost" {
if err := Run(NatTab, fmt.Sprintf("-D %s -d %s -p %s --dport %s -j MASQUERADE", Chain1PanelPostRouting, dest, protocol, destPort)); err != nil {
if err := Run(NatTab, fmt.Sprintf("-D %s -d %s -p %s --dport %s -j MASQUERADE", Chain1PanelPostRouting, dest, protocol, itemDstPort)); err != nil {
return err
}
if err := Run(FilterTab, fmt.Sprintf("-D %s -d %s -p %s --dport %s -j ACCEPT", Chain1PanelForward, dest, protocol, destPort)); err != nil {
if err := Run(FilterTab, fmt.Sprintf("-D %s -d %s -p %s --dport %s -j ACCEPT", Chain1PanelForward, dest, protocol, itemDstPort)); err != nil {
return err
}
if err := Run(FilterTab, fmt.Sprintf("-D %s -s %s -p %s --sport %s -j ACCEPT", Chain1PanelForward, dest, protocol, destPort)); err != nil {
if err := Run(FilterTab, fmt.Sprintf("-D %s -s %s -p %s --sport %s -j ACCEPT", Chain1PanelForward, dest, protocol, itemDstPort)); err != nil {
return err
}
}

View file

@ -10,7 +10,6 @@ const (
ComposeDisallowedCharsPattern = `[^a-z0-9_-]+`
ComposeEnvVarPattern = `\$\{([^}]+)\}`
DiskKeyValuePattern = `([A-Za-z0-9_]+)=("([^"\\]|\\.)*"|[^ \t]+)`
FirewalldForwardPattern = `^port=(\d{1,5}):proto=(.+?):toport=(\d{1,5}):toaddr=(.*)$`
ValidatorNamePattern = `^[a-zA-Z\p{Han}]{1}[a-zA-Z0-9_\p{Han}]{0,30}$`
ValidatorIPPattern = `^((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3}$`
DomainPattern = `^([\w\p{Han}\-\*]{1,100}\.){1,10}([\w\p{Han}\-]{1,24}|[\w\p{Han}\-]{1,24}\.[\w\p{Han}\-]{1,24})(:\d{1,5})?$`
@ -41,7 +40,6 @@ func Init() {
ComposeDisallowedCharsPattern,
ComposeEnvVarPattern,
DiskKeyValuePattern,
FirewalldForwardPattern,
ValidatorNamePattern,
ValidatorIPPattern,
DomainPattern,

View file

@ -2964,7 +2964,7 @@ const message = {
targetPort: 'Destination port',
forwardHelper1: 'If you want to forward to the local port, the destination IP should be set to "127.0.0.1".',
forwardHelper2: 'Leave the destination IP blank to forward to the local port.',
forwardPortHelper: 'Support port range, e.g. 80:90',
forwardPortHelper: 'Supports port ranges, e.g. 8080-8089',
forwardInboundInterface: 'Forward Inbound Network Interface',
exportHelper: 'About to export {0} firewall rules. Continue?',
importSuccess: 'Successfully imported {0} rules',

View file

@ -2941,6 +2941,7 @@ const message = {
targetPort: 'Puerto de destino',
forwardHelper1: 'Si quieres reenviar al puerto local, la IP de destino debe ser "127.0.0.1".',
forwardHelper2: 'Deja en blanco la IP de destino para reenviar al puerto local.',
forwardPortHelper: 'Admite rangos de puertos, ej.: 8080-8089',
forwardInboundInterface: 'Interfaz de Red de Entrada para Reenvío',
exportHelper: 'A punto de exportar {0} reglas de firewall. ¿Continuar?',
importSuccess: 'Se importaron correctamente {0} reglas',

View file

@ -2882,6 +2882,7 @@ const message = {
targetPort: '宛先ポート',
forwardHelper1: 'ローカルポートに転送する場合は宛先IPを127.0.0.1に設定する必要があります',
forwardHelper2: '宛先IPを空白のままにしてローカルポートに転送します',
forwardPortHelper: 'ポート範囲をサポートします: 8080-8089',
forwardInboundInterface: '転送入站ネットワークインターフェース',
exportHelper: '{0} 件のファイアウォールルールをエクスポートします続行しますか',
importSuccess: '{0} 件のルールを正常にインポートしました',

View file

@ -2827,6 +2827,7 @@ const message = {
targetPort: '대상 포트',
forwardHelper1: "로컬 포트로 전달하려면, 대상 IP 를 '127.0.0.1'로 설정해야 합니다.",
forwardHelper2: '대상 IP 비워두면 로컬 포트로 전달됩니다.',
forwardPortHelper: '포트 범위를 지원합니다, : 8080-8089',
forwardInboundInterface: '포워딩 인바운드 네트워크 인터페이스',
exportHelper: '{0}개의 방화벽 규칙을 내보내려고 합니다. 계속하시겠습니까?',
importSuccess: '{0}개의 규칙을 성공적으로 가져왔습니다',

View file

@ -2944,6 +2944,7 @@ const message = {
targetPort: 'Port sasaran',
forwardHelper1: 'Jika anda ingin memajukan ke port tempatan, IP sasaran harus ditetapkan kepada "127.0.0.1".',
forwardHelper2: 'Biarkan IP sasaran kosong untuk memajukan ke port tempatan.',
forwardPortHelper: 'Menyokong julat port, cth: 8080-8089',
forwardInboundInterface: 'Antara Muka Rangkaian Masukan Penerusan',
exportHelper: 'Akan mengeksport {0} peraturan firewall. Teruskan?',
importSuccess: '{0} peraturan berjaya diimport',

View file

@ -2949,6 +2949,7 @@ const message = {
forwardHelper1:
'Se você deseja redirecionar para a porta local, o IP de destino deve ser definido como "127.0.0.1".',
forwardHelper2: 'Deixe o IP de destino em branco para redirecionar para a porta local.',
forwardPortHelper: 'Suporta intervalos de portas, ex. 8080-8089',
forwardInboundInterface: 'Interface de Rede de Entrada para Encaminhamento',
exportHelper: 'Prestes a exportar {0} regras de firewall. Continuar?',
importSuccess: '{0} regras importadas com sucesso',

View file

@ -2942,7 +2942,8 @@ const message = {
forwardHelper1:
'Если вы хотите перенаправить на локальный порт, целевой IP должен быть установлен как "127.0.0.1".',
forwardHelper2: 'Оставьте целевой IP пустым для перенаправления на локальный порт.',
forwardInboundInterface: '转发入站Сетевой интерфейс для пересылки входящего трафика网卡',
forwardPortHelper: 'Поддерживает диапазоны портов, напр. 8080-8089',
forwardInboundInterface: 'Сетевой интерфейс для пересылки входящего трафика',
exportHelper: 'Собираюсь экспортировать {0} правил брандмауэра. Продолжить?',
importSuccess: 'Успешно импортировано {0} правил',
importPartialSuccess: 'Импорт завершён: {0} успешно, {1} с ошибкой',

View file

@ -3002,6 +3002,7 @@ const message = {
targetPort: 'Hedef port',
forwardHelper1: 'Yerel porta yönlendirmek istiyorsanız, hedef IP "127.0.0.1" olarak ayarlanmalıdır.',
forwardHelper2: 'Yerel porta yönlendirmek için hedef IPyi boş bırakın.',
forwardPortHelper: 'Port aralıklarını destekler, örn.: 8080-8089',
forwardInboundInterface: 'İletme Gelen Arayüzü',
exportHelper: '{0} güvenlik duvarı kuralını dışa aktarmak üzere. Devam etmek istiyor musunuz?',
importSuccess: '{0} kural başarıyla içe aktarıldı',

View file

@ -2749,6 +2749,7 @@ const message = {
targetPort: '目標埠',
forwardHelper1: '如果是本機埠轉發目標 IP 127.0.0.1',
forwardHelper2: '如果目標 IP 不填寫預設為本機埠轉發',
forwardPortHelper: '支援端口範圍8080-8089',
forwardInboundInterface: '轉發入站網路介面',
exportHelper: '即將導出 {0} 條防火牆規則是否繼續',
importSuccess: '成功匯入 {0} 條規則',

View file

@ -497,7 +497,7 @@ const message = {
changePassword: '改密',
changeConnHelper: '此操作将修改当前数据库 {0}是否继续',
changePasswordHelper: '当前数据库已经关联应用修改密码将同步修改应用中数据库密码修改后重启生效',
recoverTimeoutHelper: ' -1 表示不限制超时时间',
recoverTimeoutHelper: '-1 表示不限制超时时间',
portHelper: '该端口为容器对外暴露端口修改需要单独保存并且重启容器',
@ -2749,7 +2749,7 @@ const message = {
targetPort: '目标端口',
forwardHelper1: '如果是本机端口转发目标IP为127.0.0.1',
forwardHelper2: '如果目标IP不填写则默认为本机端口转发',
forwardPortHelper: '支持端口范围80:90',
forwardPortHelper: '支持端口范围8080-8089',
forwardInboundInterface: '转发入站网卡',
exportHelper: '即将导出 {0} 条防火墙规则是否继续',
importSuccess: '成功导入 {0} 条规则',

View file

@ -28,7 +28,11 @@
<span class="input-help">{{ $t('firewall.forwardPortHelper') }}</span>
</el-form-item>
<el-form-item :label="$t('firewall.forwardInboundInterface')" prop="interface">
<el-form-item
v-if="dialogData.fireName !== 'firewalld'"
:label="$t('firewall.forwardInboundInterface')"
prop="interface"
>
<el-select class="w-full" v-model="dialogData.rowData!.interface">
<el-option
v-for="item in interfaceOptions"
@ -105,8 +109,8 @@ function checkPortRule(rule: any, value: string, callback: any) {
if (!value) {
return callback(new Error(i18n.global.t('firewall.portFormatError')));
}
if (value.indexOf(':') !== -1) {
const ports = value.split(':');
if (value.indexOf('-') !== -1) {
const ports = value.split('-');
if (ports.length !== 2) {
return callback(new Error(i18n.global.t('firewall.portFormatError')));
}