mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-06-06 21:24:10 +00:00
fix
This commit is contained in:
parent
44ec6cf04c
commit
1bafa1fc37
2 changed files with 44 additions and 50 deletions
|
|
@ -6,6 +6,7 @@ package iptables
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
@ -48,10 +49,23 @@ func FlushChain() error {
|
||||||
|
|
||||||
// BlockIP inserts a DROP rule for the given source IP on the given TCP destination
|
// BlockIP inserts a DROP rule for the given source IP on the given TCP destination
|
||||||
// port into the custom chain. The comment embeds the current Unix timestamp so
|
// port into the custom chain. The comment embeds the current Unix timestamp so
|
||||||
// the rule can be age-checked later.
|
// the rule can be age-checked later. Duplicate rules are skipped.
|
||||||
func BlockIP(ip string, port int) error {
|
func BlockIP(ip string, port int) error {
|
||||||
|
if net.ParseIP(ip) == nil {
|
||||||
|
return fmt.Errorf("invalid IP address: %s", ip)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip if an identical rule already exists
|
||||||
|
_, err := run("iptables", "-C", chain,
|
||||||
|
"-s", ip,
|
||||||
|
"-p", "tcp", "--dport", strconv.Itoa(port),
|
||||||
|
"-j", "DROP")
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
comment := fmt.Sprintf("3xui:block:%d", time.Now().Unix())
|
comment := fmt.Sprintf("3xui:block:%d", time.Now().Unix())
|
||||||
_, err := run("iptables", "-I", chain,
|
_, err = run("iptables", "-I", chain,
|
||||||
"-s", ip,
|
"-s", ip,
|
||||||
"-p", "tcp", "--dport", strconv.Itoa(port),
|
"-p", "tcp", "--dport", strconv.Itoa(port),
|
||||||
"-m", "comment", "--comment", comment,
|
"-m", "comment", "--comment", comment,
|
||||||
|
|
@ -64,6 +78,9 @@ func BlockIP(ip string, port int) error {
|
||||||
|
|
||||||
// UnblockIP removes the DROP rule for the given source IP and TCP destination port.
|
// UnblockIP removes the DROP rule for the given source IP and TCP destination port.
|
||||||
func UnblockIP(ip string, port int) error {
|
func UnblockIP(ip string, port int) error {
|
||||||
|
if net.ParseIP(ip) == nil {
|
||||||
|
return fmt.Errorf("invalid IP address: %s", ip)
|
||||||
|
}
|
||||||
_, err := run("iptables", "-D", chain,
|
_, err := run("iptables", "-D", chain,
|
||||||
"-s", ip,
|
"-s", ip,
|
||||||
"-p", "tcp", "--dport", strconv.Itoa(port),
|
"-p", "tcp", "--dport", strconv.Itoa(port),
|
||||||
|
|
@ -154,7 +171,7 @@ func findComment(ip string, port int) string {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
needle := fmt.Sprintf("-s %s", ip)
|
needle := fmt.Sprintf("-s %s/32", ip)
|
||||||
dport := fmt.Sprintf("--dport %d", port)
|
dport := fmt.Sprintf("--dport %d", port)
|
||||||
for _, line := range strings.Split(out, "\n") {
|
for _, line := range strings.Split(out, "\n") {
|
||||||
if strings.Contains(line, needle) && strings.Contains(line, dport) {
|
if strings.Contains(line, needle) && strings.Contains(line, dport) {
|
||||||
|
|
|
||||||
|
|
@ -2532,19 +2532,16 @@ func (s *InboundService) DelInboundClientByEmail(inboundId int, email string) (b
|
||||||
return needRestart, db.Save(oldInbound).Error
|
return needRestart, db.Save(oldInbound).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// blockClientIPs inserts iptables DROP rules for all known IPs of the given client.
|
// clientIPsForFirewall returns the list of known IP addresses and the inbound port for a client.
|
||||||
// Failures are logged as warnings so a missing iptables binary does not break the
|
func (s *InboundService) clientIPsForFirewall(email string) ([]string, int) {
|
||||||
// normal disable flow.
|
|
||||||
func (s *InboundService) blockClientIPs(email string) {
|
|
||||||
ipsJSON, err := s.GetInboundClientIps(email)
|
ipsJSON, err := s.GetInboundClientIps(email)
|
||||||
if err != nil || ipsJSON == "" {
|
if err != nil || ipsJSON == "" {
|
||||||
return
|
return nil, 0
|
||||||
}
|
}
|
||||||
_, inbound, err := s.GetClientInboundByEmail(email)
|
_, inbound, err := s.GetClientInboundByEmail(email)
|
||||||
if err != nil || inbound == nil {
|
if err != nil || inbound == nil {
|
||||||
return
|
return nil, 0
|
||||||
}
|
}
|
||||||
port := inbound.Port
|
|
||||||
|
|
||||||
type IPWithTimestamp struct {
|
type IPWithTimestamp struct {
|
||||||
IP string `json:"ip"`
|
IP string `json:"ip"`
|
||||||
|
|
@ -2552,57 +2549,37 @@ func (s *InboundService) blockClientIPs(email string) {
|
||||||
}
|
}
|
||||||
var ipsWithTime []IPWithTimestamp
|
var ipsWithTime []IPWithTimestamp
|
||||||
if err := json.Unmarshal([]byte(ipsJSON), &ipsWithTime); err != nil {
|
if err := json.Unmarshal([]byte(ipsJSON), &ipsWithTime); err != nil {
|
||||||
// Try simple string-array format
|
|
||||||
var simpleIPs []string
|
var simpleIPs []string
|
||||||
if err2 := json.Unmarshal([]byte(ipsJSON), &simpleIPs); err2 != nil {
|
if err2 := json.Unmarshal([]byte(ipsJSON), &simpleIPs); err2 != nil {
|
||||||
return
|
return nil, 0
|
||||||
}
|
}
|
||||||
for _, ip := range simpleIPs {
|
return simpleIPs, inbound.Port
|
||||||
if berr := iptables.BlockIP(ip, port); berr != nil {
|
|
||||||
logger.Warning("blockClientIPs: failed to block", ip, berr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
ips := make([]string, 0, len(ipsWithTime))
|
||||||
for _, entry := range ipsWithTime {
|
for _, entry := range ipsWithTime {
|
||||||
if berr := iptables.BlockIP(entry.IP, port); berr != nil {
|
ips = append(ips, entry.IP)
|
||||||
logger.Warning("blockClientIPs: failed to block", entry.IP, berr)
|
}
|
||||||
|
return ips, inbound.Port
|
||||||
|
}
|
||||||
|
|
||||||
|
// blockClientIPs inserts iptables DROP rules for all known IPs of the given client.
|
||||||
|
// Failures are logged as warnings so a missing iptables binary does not break the
|
||||||
|
// normal disable flow.
|
||||||
|
func (s *InboundService) blockClientIPs(email string) {
|
||||||
|
ips, port := s.clientIPsForFirewall(email)
|
||||||
|
for _, ip := range ips {
|
||||||
|
if err := iptables.BlockIP(ip, port); err != nil {
|
||||||
|
logger.Warning("blockClientIPs: failed to block", ip, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// unblockClientIPs removes iptables DROP rules for all known IPs of the given client.
|
// unblockClientIPs removes iptables DROP rules for all known IPs of the given client.
|
||||||
func (s *InboundService) unblockClientIPs(email string) {
|
func (s *InboundService) unblockClientIPs(email string) {
|
||||||
ipsJSON, err := s.GetInboundClientIps(email)
|
ips, port := s.clientIPsForFirewall(email)
|
||||||
if err != nil || ipsJSON == "" {
|
for _, ip := range ips {
|
||||||
return
|
if err := iptables.UnblockIP(ip, port); err != nil {
|
||||||
}
|
logger.Debug("unblockClientIPs: failed to unblock", ip, err)
|
||||||
_, inbound, err := s.GetClientInboundByEmail(email)
|
|
||||||
if err != nil || inbound == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
port := inbound.Port
|
|
||||||
|
|
||||||
type IPWithTimestamp struct {
|
|
||||||
IP string `json:"ip"`
|
|
||||||
Timestamp int64 `json:"timestamp"`
|
|
||||||
}
|
|
||||||
var ipsWithTime []IPWithTimestamp
|
|
||||||
if err := json.Unmarshal([]byte(ipsJSON), &ipsWithTime); err != nil {
|
|
||||||
var simpleIPs []string
|
|
||||||
if err2 := json.Unmarshal([]byte(ipsJSON), &simpleIPs); err2 != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, ip := range simpleIPs {
|
|
||||||
if uerr := iptables.UnblockIP(ip, port); uerr != nil {
|
|
||||||
logger.Debug("unblockClientIPs: failed to unblock", ip, uerr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, entry := range ipsWithTime {
|
|
||||||
if uerr := iptables.UnblockIP(entry.IP, port); uerr != nil {
|
|
||||||
logger.Debug("unblockClientIPs: failed to unblock", entry.IP, uerr)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue