Fix: nat table stack overflow
This commit is contained in:
parent
c0ea0cfd5d
commit
98fea448c1
@ -6,6 +6,7 @@ import (
|
||||
"net/netip"
|
||||
|
||||
"github.com/Dreamacro/clash/listener/tun/ipstack/system/mars/tcpip"
|
||||
"github.com/Dreamacro/clash/log"
|
||||
)
|
||||
|
||||
func Start(device io.ReadWriter, gateway, portal, broadcast netip.Addr) (*TCP, *UDP, error) {
|
||||
@ -132,7 +133,11 @@ func Start(device io.ReadWriter, gateway, portal, broadcast netip.Addr) (*TCP, *
|
||||
continue
|
||||
}
|
||||
|
||||
port = tab.newConn(tup)
|
||||
port, err = tab.newConn(tup)
|
||||
if err != nil {
|
||||
log.Warnln("[STACK] drop tcp packet by system stack: %v", err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
ip.SetSourceIP(portal)
|
||||
|
@ -1,6 +1,7 @@
|
||||
package nat
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"sync"
|
||||
|
||||
@ -31,6 +32,7 @@ type table struct {
|
||||
ports [portLength]*list.Element[*binding]
|
||||
available *list.List[*binding]
|
||||
mux sync.Mutex
|
||||
count uint16
|
||||
}
|
||||
|
||||
func (t *table) tupleOf(port uint16) tuple {
|
||||
@ -60,38 +62,50 @@ func (t *table) portOf(tuple tuple) uint16 {
|
||||
return portBegin + elm.Value.offset
|
||||
}
|
||||
|
||||
func (t *table) newConn(tuple tuple) uint16 {
|
||||
func (t *table) newConn(tuple tuple) (uint16, error) {
|
||||
t.mux.Lock()
|
||||
elm := t.availableConn()
|
||||
b := elm.Value
|
||||
t.tuples[tuple] = elm
|
||||
b.tuple = tuple
|
||||
elm, err := t.availableConn()
|
||||
if err != nil {
|
||||
t.mux.Unlock()
|
||||
|
||||
t.available.MoveToFront(elm)
|
||||
|
||||
return portBegin + b.offset
|
||||
return 0, err
|
||||
}
|
||||
|
||||
func (t *table) availableConn() *list.Element[*binding] {
|
||||
elm := t.available.Back()
|
||||
elm.Value.tuple = tuple
|
||||
t.tuples[tuple] = elm
|
||||
t.mux.Unlock()
|
||||
|
||||
return portBegin + elm.Value.offset, nil
|
||||
}
|
||||
|
||||
func (t *table) availableConn() (*list.Element[*binding], error) {
|
||||
var elm *list.Element[*binding]
|
||||
|
||||
for i := 0; i < portLength; i++ {
|
||||
elm = t.available.Back()
|
||||
t.available.MoveToFront(elm)
|
||||
|
||||
offset := elm.Value.offset
|
||||
_, ok := t.tuples[t.ports[offset].Value.tuple]
|
||||
if !ok {
|
||||
if offset != 0 && offset%portLength == 0 { // resize
|
||||
tup := t.ports[offset].Value.tuple
|
||||
if t.tuples[tup] != nil && tup.SourceAddr.IsValid() {
|
||||
continue
|
||||
}
|
||||
|
||||
if t.count == portLength { // resize
|
||||
tuples := make(map[tuple]*list.Element[*binding], portLength)
|
||||
maps.Copy(tuples, t.tuples)
|
||||
t.tuples = tuples
|
||||
t.count = 1
|
||||
}
|
||||
return elm
|
||||
return elm, nil
|
||||
}
|
||||
t.available.MoveToFront(elm)
|
||||
return t.availableConn()
|
||||
|
||||
return nil, fmt.Errorf("too many open files, limits [%d, %d]", portLength, len(t.tuples))
|
||||
}
|
||||
|
||||
func (t *table) closeConn(tuple tuple) {
|
||||
t.mux.Lock()
|
||||
delete(t.tuples, tuple)
|
||||
t.count++
|
||||
t.mux.Unlock()
|
||||
}
|
||||
|
||||
@ -100,6 +114,7 @@ func newTable() *table {
|
||||
tuples: make(map[tuple]*list.Element[*binding], portLength),
|
||||
ports: [portLength]*list.Element[*binding]{},
|
||||
available: list.New[*binding](),
|
||||
count: 1,
|
||||
}
|
||||
|
||||
for idx := range result.ports {
|
||||
|
Reference in New Issue
Block a user