Fix: nat table stack overflow
This commit is contained in:
parent
c0ea0cfd5d
commit
98fea448c1
@ -6,6 +6,7 @@ import (
|
|||||||
"net/netip"
|
"net/netip"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/listener/tun/ipstack/system/mars/tcpip"
|
"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) {
|
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
|
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)
|
ip.SetSourceIP(portal)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package nat
|
package nat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
@ -31,6 +32,7 @@ type table struct {
|
|||||||
ports [portLength]*list.Element[*binding]
|
ports [portLength]*list.Element[*binding]
|
||||||
available *list.List[*binding]
|
available *list.List[*binding]
|
||||||
mux sync.Mutex
|
mux sync.Mutex
|
||||||
|
count uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *table) tupleOf(port uint16) tuple {
|
func (t *table) tupleOf(port uint16) tuple {
|
||||||
@ -60,38 +62,50 @@ func (t *table) portOf(tuple tuple) uint16 {
|
|||||||
return portBegin + elm.Value.offset
|
return portBegin + elm.Value.offset
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *table) newConn(tuple tuple) uint16 {
|
func (t *table) newConn(tuple tuple) (uint16, error) {
|
||||||
t.mux.Lock()
|
t.mux.Lock()
|
||||||
elm := t.availableConn()
|
elm, err := t.availableConn()
|
||||||
b := elm.Value
|
if err != nil {
|
||||||
|
t.mux.Unlock()
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
elm.Value.tuple = tuple
|
||||||
t.tuples[tuple] = elm
|
t.tuples[tuple] = elm
|
||||||
b.tuple = tuple
|
|
||||||
t.mux.Unlock()
|
t.mux.Unlock()
|
||||||
|
|
||||||
t.available.MoveToFront(elm)
|
return portBegin + elm.Value.offset, nil
|
||||||
|
|
||||||
return portBegin + b.offset
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *table) availableConn() *list.Element[*binding] {
|
func (t *table) availableConn() (*list.Element[*binding], error) {
|
||||||
elm := t.available.Back()
|
var elm *list.Element[*binding]
|
||||||
offset := elm.Value.offset
|
|
||||||
_, ok := t.tuples[t.ports[offset].Value.tuple]
|
for i := 0; i < portLength; i++ {
|
||||||
if !ok {
|
elm = t.available.Back()
|
||||||
if offset != 0 && offset%portLength == 0 { // resize
|
t.available.MoveToFront(elm)
|
||||||
|
|
||||||
|
offset := elm.Value.offset
|
||||||
|
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)
|
tuples := make(map[tuple]*list.Element[*binding], portLength)
|
||||||
maps.Copy(tuples, t.tuples)
|
maps.Copy(tuples, t.tuples)
|
||||||
t.tuples = 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) {
|
func (t *table) closeConn(tuple tuple) {
|
||||||
t.mux.Lock()
|
t.mux.Lock()
|
||||||
delete(t.tuples, tuple)
|
delete(t.tuples, tuple)
|
||||||
|
t.count++
|
||||||
t.mux.Unlock()
|
t.mux.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,6 +114,7 @@ func newTable() *table {
|
|||||||
tuples: make(map[tuple]*list.Element[*binding], portLength),
|
tuples: make(map[tuple]*list.Element[*binding], portLength),
|
||||||
ports: [portLength]*list.Element[*binding]{},
|
ports: [portLength]*list.Element[*binding]{},
|
||||||
available: list.New[*binding](),
|
available: list.New[*binding](),
|
||||||
|
count: 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
for idx := range result.ports {
|
for idx := range result.ports {
|
||||||
|
Reference in New Issue
Block a user