Reject connections to redirect listener
This commit is contained in:
parent
add23d4844
commit
80ea96e5b4
4 changed files with 104 additions and 7 deletions
|
|
@ -44,6 +44,24 @@ func (r *autoRedirect) setupIPTablesForFamily(iptablesPath string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if r.redirectServer != nil {
|
||||
tableNameInput := r.tableName + "-input"
|
||||
err = r.runShell(iptablesPath, "-t filter -N", tableNameInput)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = r.runShell(iptablesPath, "-t filter -A", tableNameInput,
|
||||
"-p tcp --dport", redirectPort,
|
||||
"-m conntrack ! --ctstate DNAT",
|
||||
"-j REJECT --reject-with tcp-reset")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = r.runShell(iptablesPath, "-t filter -I INPUT -j", tableNameInput)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -58,10 +76,14 @@ func (r *autoRedirect) cleanupIPTables() {
|
|||
|
||||
func (r *autoRedirect) cleanupIPTablesForFamily(iptablesPath string) {
|
||||
tableNameOutput := r.tableName + "-output"
|
||||
tableNameInput := r.tableName + "-input"
|
||||
|
||||
_ = r.runShell(iptablesPath, "-t nat -D OUTPUT -j", tableNameOutput)
|
||||
_ = r.runShell(iptablesPath, "-t nat -F", tableNameOutput)
|
||||
_ = r.runShell(iptablesPath, "-t nat -X", tableNameOutput)
|
||||
_ = r.runShell(iptablesPath, "-t filter -D INPUT -j", tableNameInput)
|
||||
_ = r.runShell(iptablesPath, "-t filter -F", tableNameInput)
|
||||
_ = r.runShell(iptablesPath, "-t filter -X", tableNameInput)
|
||||
}
|
||||
|
||||
func (r *autoRedirect) runShell(commands ...any) error {
|
||||
|
|
|
|||
|
|
@ -123,6 +123,17 @@ func (r *autoRedirect) setupNFTables() error {
|
|||
}
|
||||
}
|
||||
|
||||
if r.redirectServer != nil {
|
||||
chainInput := nft.AddChain(&nftables.Chain{
|
||||
Name: "input",
|
||||
Table: table,
|
||||
Hooknum: nftables.ChainHookInput,
|
||||
Priority: nftables.ChainPriorityFilter,
|
||||
Type: nftables.ChainTypeFilter,
|
||||
})
|
||||
r.nftablesCreateRedirectPortReject(nft, table, chainInput)
|
||||
}
|
||||
|
||||
chainPreRouting := nft.AddChain(&nftables.Chain{
|
||||
Name: "prerouting",
|
||||
Table: table,
|
||||
|
|
|
|||
|
|
@ -613,6 +613,59 @@ func (r *autoRedirect) nftablesCreateExcludeRules(nft *nftables.Conn, table *nft
|
|||
return nil
|
||||
}
|
||||
|
||||
// IPS_DST_NAT in linux/netfilter/nf_conntrack_common.h, not exported by golang.org/x/sys
|
||||
const conntrackStatusDstNAT = 1 << 5
|
||||
|
||||
func (r *autoRedirect) nftablesCreateRedirectPortReject(nft *nftables.Conn, table *nftables.Table, chain *nftables.Chain) {
|
||||
nft.AddRule(&nftables.Rule{
|
||||
Table: table,
|
||||
Chain: chain,
|
||||
Exprs: []expr.Any{
|
||||
&expr.Meta{
|
||||
Key: expr.MetaKeyL4PROTO,
|
||||
Register: 1,
|
||||
},
|
||||
&expr.Cmp{
|
||||
Op: expr.CmpOpEq,
|
||||
Register: 1,
|
||||
Data: []byte{unix.IPPROTO_TCP},
|
||||
},
|
||||
&expr.Payload{
|
||||
OperationType: expr.PayloadLoad,
|
||||
DestRegister: 1,
|
||||
Base: expr.PayloadBaseTransportHeader,
|
||||
Offset: 2,
|
||||
Len: 2,
|
||||
},
|
||||
&expr.Cmp{
|
||||
Op: expr.CmpOpEq,
|
||||
Register: 1,
|
||||
Data: binaryutil.BigEndian.PutUint16(r.redirectPort()),
|
||||
},
|
||||
&expr.Ct{
|
||||
Key: expr.CtKeySTATUS,
|
||||
Register: 1,
|
||||
},
|
||||
&expr.Bitwise{
|
||||
SourceRegister: 1,
|
||||
DestRegister: 1,
|
||||
Len: 4,
|
||||
Mask: binaryutil.NativeEndian.PutUint32(conntrackStatusDstNAT),
|
||||
Xor: make([]byte, 4),
|
||||
},
|
||||
&expr.Cmp{
|
||||
Op: expr.CmpOpEq,
|
||||
Register: 1,
|
||||
Data: make([]byte, 4),
|
||||
},
|
||||
&expr.Counter{},
|
||||
&expr.Reject{
|
||||
Type: unix.NFT_REJECT_TCP_RST,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (r *autoRedirect) nftablesCreateMark(nft *nftables.Conn, table *nftables.Table, chain *nftables.Chain) {
|
||||
nft.AddRule(&nftables.Rule{
|
||||
Table: table,
|
||||
|
|
|
|||
|
|
@ -54,22 +54,33 @@ func (s *redirectServer) Close() error {
|
|||
}
|
||||
|
||||
func (s *redirectServer) loopIn() {
|
||||
var retryDelay time.Duration
|
||||
for {
|
||||
conn, err := s.listener.AcceptTCP()
|
||||
if err != nil {
|
||||
var netError net.Error
|
||||
//nolint:staticcheck
|
||||
if errors.As(err, &netError) && netError.Temporary() {
|
||||
s.logger.Error(err)
|
||||
continue
|
||||
}
|
||||
if s.inShutdown.Load() && E.IsClosed(err) {
|
||||
return
|
||||
}
|
||||
s.listener.Close()
|
||||
s.logger.Error("serve error: ", err)
|
||||
var netError net.Error
|
||||
//nolint:staticcheck
|
||||
if errors.As(err, &netError) && netError.Temporary() {
|
||||
if retryDelay == 0 {
|
||||
retryDelay = 5 * time.Millisecond
|
||||
} else {
|
||||
retryDelay *= 2
|
||||
}
|
||||
if retryDelay > time.Second {
|
||||
retryDelay = time.Second
|
||||
}
|
||||
s.logger.Error("accept: ", err, ": retrying in ", retryDelay)
|
||||
time.Sleep(retryDelay)
|
||||
continue
|
||||
}
|
||||
s.listener.Close()
|
||||
s.logger.Error("serve error: ", err)
|
||||
return
|
||||
}
|
||||
retryDelay = 0
|
||||
source := M.SocksaddrFromNet(conn.RemoteAddr()).Unwrap()
|
||||
destination, err := control.GetOriginalDestination(conn)
|
||||
if err != nil {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue