diff options
author | Tamir Duberstein <tamird@google.com> | 2018-09-17 20:42:48 -0700 |
---|---|---|
committer | Shentubot <shentubot@google.com> | 2018-09-17 20:44:04 -0700 |
commit | d6409b6564d6f908a217709010df2276497b264b (patch) | |
tree | eef606f06646507d0fbfdba60d48ffc3ff46b715 /pkg/tcpip/ports | |
parent | bb88c187c5457df14fa78e5e6b6f48cbc90fb489 (diff) |
Prevent TCP connect from picking bound ports
PiperOrigin-RevId: 213387851
Change-Id: Icc6850761bc11afd0525f34863acd77584155140
Diffstat (limited to 'pkg/tcpip/ports')
-rw-r--r-- | pkg/tcpip/ports/ports.go | 46 | ||||
-rw-r--r-- | pkg/tcpip/ports/ports_test.go | 10 |
2 files changed, 35 insertions, 21 deletions
diff --git a/pkg/tcpip/ports/ports.go b/pkg/tcpip/ports/ports.go index db7371efb..4e24efddb 100644 --- a/pkg/tcpip/ports/ports.go +++ b/pkg/tcpip/ports/ports.go @@ -24,8 +24,8 @@ import ( ) const ( - // firstEphemeral is the first ephemeral port. - firstEphemeral uint16 = 16000 + // FirstEphemeral is the first ephemeral port. + FirstEphemeral = 16000 anyIPAddress tcpip.Address = "" ) @@ -73,11 +73,11 @@ func NewPortManager() *PortManager { // is suitable for its needs, and stopping when a port is found or an error // occurs. func (s *PortManager) PickEphemeralPort(testPort func(p uint16) (bool, *tcpip.Error)) (port uint16, err *tcpip.Error) { - count := uint16(math.MaxUint16 - firstEphemeral + 1) + count := uint16(math.MaxUint16 - FirstEphemeral + 1) offset := uint16(rand.Int31n(int32(count))) for i := uint16(0); i < count; i++ { - port = firstEphemeral + (offset+i)%count + port = FirstEphemeral + (offset+i)%count ok, err := testPort(port) if err != nil { return 0, err @@ -91,6 +91,25 @@ func (s *PortManager) PickEphemeralPort(testPort func(p uint16) (bool, *tcpip.Er return 0, tcpip.ErrNoPortAvailable } +// IsPortAvailable tests if the given port is available on all given protocols. +func (s *PortManager) IsPortAvailable(networks []tcpip.NetworkProtocolNumber, transport tcpip.TransportProtocolNumber, addr tcpip.Address, port uint16) bool { + s.mu.Lock() + defer s.mu.Unlock() + return s.isPortAvailableLocked(networks, transport, addr, port) +} + +func (s *PortManager) isPortAvailableLocked(networks []tcpip.NetworkProtocolNumber, transport tcpip.TransportProtocolNumber, addr tcpip.Address, port uint16) bool { + for _, network := range networks { + desc := portDescriptor{network, transport, port} + if addrs, ok := s.allocatedPorts[desc]; ok { + if !addrs.isAvailable(addr) { + return false + } + } + } + return true +} + // ReservePort marks a port/IP combination as reserved so that it cannot be // reserved by another endpoint. If port is zero, ReservePort will search for // an unreserved ephemeral port and reserve it, returning its value in the @@ -116,14 +135,8 @@ func (s *PortManager) ReservePort(networks []tcpip.NetworkProtocolNumber, transp // reserveSpecificPort tries to reserve the given port on all given protocols. func (s *PortManager) reserveSpecificPort(networks []tcpip.NetworkProtocolNumber, transport tcpip.TransportProtocolNumber, addr tcpip.Address, port uint16) bool { - // Check that the port is available on all network protocols. - for _, network := range networks { - desc := portDescriptor{network, transport, port} - if addrs, ok := s.allocatedPorts[desc]; ok { - if !addrs.isAvailable(addr) { - return false - } - } + if !s.isPortAvailableLocked(networks, transport, addr, port) { + return false } // Reserve port on all network protocols. @@ -148,10 +161,11 @@ func (s *PortManager) ReleasePort(networks []tcpip.NetworkProtocolNumber, transp for _, network := range networks { desc := portDescriptor{network, transport, port} - m := s.allocatedPorts[desc] - delete(m, addr) - if len(m) == 0 { - delete(s.allocatedPorts, desc) + if m, ok := s.allocatedPorts[desc]; ok { + delete(m, addr) + if len(m) == 0 { + delete(s.allocatedPorts, desc) + } } } } diff --git a/pkg/tcpip/ports/ports_test.go b/pkg/tcpip/ports/ports_test.go index 825d5d314..4ab6a1fa2 100644 --- a/pkg/tcpip/ports/ports_test.go +++ b/pkg/tcpip/ports/ports_test.go @@ -78,8 +78,8 @@ func TestPortReservation(t *testing.T) { if err != test.want { t.Fatalf("ReservePort(.., .., %s, %d) = %v, want %v", test.ip, test.port, err, test.want) } - if test.port == 0 && (gotPort == 0 || gotPort < firstEphemeral) { - t.Fatalf("ReservePort(.., .., .., 0) = %d, want port number >= %d to be picked", gotPort, firstEphemeral) + if test.port == 0 && (gotPort == 0 || gotPort < FirstEphemeral) { + t.Fatalf("ReservePort(.., .., .., 0) = %d, want port number >= %d to be picked", gotPort, FirstEphemeral) } } @@ -118,17 +118,17 @@ func TestPickEphemeralPort(t *testing.T) { { name: "only-port-16042-available", f: func(port uint16) (bool, *tcpip.Error) { - if port == firstEphemeral+42 { + if port == FirstEphemeral+42 { return true, nil } return false, nil }, - wantPort: firstEphemeral + 42, + wantPort: FirstEphemeral + 42, }, { name: "only-port-under-16000-available", f: func(port uint16) (bool, *tcpip.Error) { - if port < firstEphemeral { + if port < FirstEphemeral { return true, nil } return false, nil |