ping: Fix unprivileged conn leak
This commit is contained in:
parent
e5d2fab035
commit
47ac4d08b1
4 changed files with 20 additions and 12 deletions
|
|
@ -51,11 +51,11 @@ func ConnectDestination(
|
||||||
)
|
)
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
case "darwin", "ios", "windows":
|
case "darwin", "ios", "windows":
|
||||||
conn, err = Connect(ctx, false, controlFunc, destination)
|
conn, err = Connect(ctx, false, controlFunc, destination, timeout)
|
||||||
default:
|
default:
|
||||||
conn, err = Connect(ctx, true, controlFunc, destination)
|
conn, err = Connect(ctx, true, controlFunc, destination, timeout)
|
||||||
if errors.Is(err, os.ErrPermission) {
|
if errors.Is(err, os.ErrPermission) {
|
||||||
conn, err = Connect(ctx, false, controlFunc, destination)
|
conn, err = Connect(ctx, false, controlFunc, destination, timeout)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -30,22 +30,22 @@ type Conn struct {
|
||||||
readMsg func(b, oob []byte) (n, oobn int, addr netip.Addr, err error)
|
readMsg func(b, oob []byte) (n, oobn int, addr netip.Addr, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Connect(ctx context.Context, privileged bool, controlFunc control.Func, destination netip.Addr) (*Conn, error) {
|
func Connect(ctx context.Context, privileged bool, controlFunc control.Func, destination netip.Addr, idleTimeout time.Duration) (*Conn, error) {
|
||||||
c := &Conn{
|
c := &Conn{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
privileged: privileged,
|
privileged: privileged,
|
||||||
destination: destination,
|
destination: destination,
|
||||||
}
|
}
|
||||||
err := c.connect(controlFunc)
|
err := c.connect(controlFunc, idleTimeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Conn) connect(controlFunc control.Func) (err error) {
|
func (c *Conn) connect(controlFunc control.Func, idleTimeout time.Duration) (err error) {
|
||||||
if c.isLinuxUnprivileged() {
|
if c.isLinuxUnprivileged() {
|
||||||
c.conn, err = newUnprivilegedConn(c.ctx, controlFunc, c.destination)
|
c.conn, err = newUnprivilegedConn(c.ctx, controlFunc, c.destination, idleTimeout)
|
||||||
} else {
|
} else {
|
||||||
c.conn, err = connect(c.privileged, controlFunc, c.destination)
|
c.conn, err = connect(c.privileged, controlFunc, c.destination)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ func TestPing(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testPingIPv4ReadIP(t *testing.T, privileged bool, addr string) {
|
func testPingIPv4ReadIP(t *testing.T, privileged bool, addr string) {
|
||||||
conn, err := ping.Connect(context.Background(), privileged, nil, netip.MustParseAddr(addr))
|
conn, err := ping.Connect(context.Background(), privileged, nil, netip.MustParseAddr(addr), 0)
|
||||||
if runtime.GOOS == "linux" && err != nil && err.Error() == "socket(): permission denied" {
|
if runtime.GOOS == "linux" && err != nil && err.Error() == "socket(): permission denied" {
|
||||||
t.SkipNow()
|
t.SkipNow()
|
||||||
}
|
}
|
||||||
|
|
@ -105,7 +105,7 @@ func testPingIPv4ReadIP(t *testing.T, privileged bool, addr string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testPingIPv4ReadICMP(t *testing.T, privileged bool, addr string) {
|
func testPingIPv4ReadICMP(t *testing.T, privileged bool, addr string) {
|
||||||
conn, err := ping.Connect(context.Background(), privileged, nil, netip.MustParseAddr(addr))
|
conn, err := ping.Connect(context.Background(), privileged, nil, netip.MustParseAddr(addr), 0)
|
||||||
if runtime.GOOS == "linux" && err != nil && err.Error() == "socket(): permission denied" {
|
if runtime.GOOS == "linux" && err != nil && err.Error() == "socket(): permission denied" {
|
||||||
t.SkipNow()
|
t.SkipNow()
|
||||||
}
|
}
|
||||||
|
|
@ -137,7 +137,7 @@ func testPingIPv4ReadICMP(t *testing.T, privileged bool, addr string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testPingIPv6ReadIP(t *testing.T, privileged bool, addr string) {
|
func testPingIPv6ReadIP(t *testing.T, privileged bool, addr string) {
|
||||||
conn, err := ping.Connect(context.Background(), privileged, nil, netip.MustParseAddr(addr))
|
conn, err := ping.Connect(context.Background(), privileged, nil, netip.MustParseAddr(addr), 0)
|
||||||
if runtime.GOOS == "linux" && err != nil && err.Error() == "socket(): permission denied" {
|
if runtime.GOOS == "linux" && err != nil && err.Error() == "socket(): permission denied" {
|
||||||
t.SkipNow()
|
t.SkipNow()
|
||||||
}
|
}
|
||||||
|
|
@ -169,7 +169,7 @@ func testPingIPv6ReadIP(t *testing.T, privileged bool, addr string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testPingIPv6ReadICMP(t *testing.T, privileged bool, addr string) {
|
func testPingIPv6ReadICMP(t *testing.T, privileged bool, addr string) {
|
||||||
conn, err := ping.Connect(context.Background(), privileged, nil, netip.MustParseAddr(addr))
|
conn, err := ping.Connect(context.Background(), privileged, nil, netip.MustParseAddr(addr), 0)
|
||||||
if runtime.GOOS == "linux" && err != nil && err.Error() == "socket(): permission denied" {
|
if runtime.GOOS == "linux" && err != nil && err.Error() == "socket(): permission denied" {
|
||||||
t.SkipNow()
|
t.SkipNow()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ type UnprivilegedConn struct {
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
controlFunc control.Func
|
controlFunc control.Func
|
||||||
destination netip.Addr
|
destination netip.Addr
|
||||||
|
idleTimeout time.Duration
|
||||||
receiveChan chan *unprivilegedResponse
|
receiveChan chan *unprivilegedResponse
|
||||||
readDeadline pipe.Deadline
|
readDeadline pipe.Deadline
|
||||||
mappingAccess sync.Mutex
|
mappingAccess sync.Mutex
|
||||||
|
|
@ -33,7 +34,7 @@ type unprivilegedResponse struct {
|
||||||
Addr netip.Addr
|
Addr netip.Addr
|
||||||
}
|
}
|
||||||
|
|
||||||
func newUnprivilegedConn(ctx context.Context, controlFunc control.Func, destination netip.Addr) (net.Conn, error) {
|
func newUnprivilegedConn(ctx context.Context, controlFunc control.Func, destination netip.Addr, idleTimeout time.Duration) (net.Conn, error) {
|
||||||
conn, err := connect(false, controlFunc, destination)
|
conn, err := connect(false, controlFunc, destination)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -45,6 +46,7 @@ func newUnprivilegedConn(ctx context.Context, controlFunc control.Func, destinat
|
||||||
cancel: cancel,
|
cancel: cancel,
|
||||||
controlFunc: controlFunc,
|
controlFunc: controlFunc,
|
||||||
destination: destination,
|
destination: destination,
|
||||||
|
idleTimeout: idleTimeout,
|
||||||
receiveChan: make(chan *unprivilegedResponse),
|
receiveChan: make(chan *unprivilegedResponse),
|
||||||
readDeadline: pipe.MakeDeadline(),
|
readDeadline: pipe.MakeDeadline(),
|
||||||
mapping: make(map[uint16]net.Conn),
|
mapping: make(map[uint16]net.Conn),
|
||||||
|
|
@ -116,6 +118,12 @@ func (c *UnprivilegedConn) Write(b []byte) (n int, err error) {
|
||||||
func (c *UnprivilegedConn) fetchResponse(conn *net.UDPConn, identifier uint16) {
|
func (c *UnprivilegedConn) fetchResponse(conn *net.UDPConn, identifier uint16) {
|
||||||
defer c.removeConn(conn, identifier)
|
defer c.removeConn(conn, identifier)
|
||||||
for {
|
for {
|
||||||
|
if c.idleTimeout > 0 {
|
||||||
|
err := conn.SetReadDeadline(time.Now().Add(c.idleTimeout))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
buffer := buf.NewPacket()
|
buffer := buf.NewPacket()
|
||||||
cmsgBuffer := buf.NewSize(1024)
|
cmsgBuffer := buf.NewSize(1024)
|
||||||
n, oobN, _, addr, err := conn.ReadMsgUDPAddrPort(buffer.FreeBytes(), cmsgBuffer.FreeBytes())
|
n, oobN, _, addr, err := conn.ReadMsgUDPAddrPort(buffer.FreeBytes(), cmsgBuffer.FreeBytes())
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue