Skip to content

Commit

Permalink
VNet: Refuse conn if local port doesn't match app spec
Browse files Browse the repository at this point in the history
  • Loading branch information
ravicious committed Dec 17, 2024
1 parent 670a34a commit 7fd6be8
Show file tree
Hide file tree
Showing 17 changed files with 2,554 additions and 1,981 deletions.
2 changes: 2 additions & 0 deletions api/proto/teleport/legacy/types/types.proto
Original file line number Diff line number Diff line change
Expand Up @@ -1071,6 +1071,8 @@ message Header {
// PortRange can be used to describe a single port in which case the Port field is the port and the
// EndPort field is 0.
message PortRange {
option (gogoproto.goproto_stringer) = false;
option (gogoproto.stringer) = false;
// Port describes the start of the range. It must be between 1 and 65535.
uint32 Port = 1 [(gogoproto.jsontag) = "port"];
// EndPort describes the end of the range, inclusive. If set, it must be between 2 and 65535 and
Expand Down
37 changes: 35 additions & 2 deletions api/types/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ package types
import (
"fmt"
"net/url"
"slices"
"strconv"
"strings"
"time"

Expand Down Expand Up @@ -88,7 +90,7 @@ type Application interface {
// GetCORS returns the CORS configuration for the app.
GetCORS() *CORSPolicy
// GetTCPPorts returns port ranges supported by the app to which connections can be forwarded to.
GetTCPPorts() []*PortRange
GetTCPPorts() PortRanges
// SetTCPPorts sets port ranges to which connections can be forwarded to.
SetTCPPorts([]*PortRange)
// GetIdentityCenter fetches identity center info for the app, if any.
Expand Down Expand Up @@ -314,7 +316,7 @@ func (a *AppV3) SetUserGroups(userGroups []string) {
}

// GetTCPPorts returns port ranges supported by the app to which connections can be forwarded to.
func (a *AppV3) GetTCPPorts() []*PortRange {
func (a *AppV3) GetTCPPorts() PortRanges {
return a.Spec.TCPPorts
}

Expand Down Expand Up @@ -537,3 +539,34 @@ func (a *AppIdentityCenter) GetPermissionSets() []*IdentityCenterPermissionSet {
}
return a.PermissionSets
}

// PortRanges is a list of port ranges.
type PortRanges []*PortRange

// Contains checks if targetPort is within any of the port ranges.
func (p PortRanges) Contains(targetPort int) bool {
return slices.ContainsFunc(p, func(portRange *PortRange) bool {
return netutils.IsPortInRange(int(portRange.Port), int(portRange.EndPort), targetPort)
})
}

// String returns a string representation of port ranges.
func (p PortRanges) String() string {
var builder strings.Builder
for i, portRange := range p {
if i > 0 {
builder.WriteString(", ")
}
builder.WriteString(portRange.String())
}
return builder.String()
}

// String returns a string representation of a port range.
func (p *PortRange) String() string {
if p.EndPort == 0 {
return strconv.Itoa(int(p.Port))
} else {
return fmt.Sprintf("%d-%d", p.Port, p.EndPort)
}
}
26 changes: 26 additions & 0 deletions api/types/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package types

import (
"fmt"
"strconv"
"testing"

"github.com/gravitational/trace"
Expand Down Expand Up @@ -563,6 +564,31 @@ func TestNewAppV3(t *testing.T) {
}
}

func TestPortRangesContains(t *testing.T) {
portRanges := PortRanges([]*PortRange{
&PortRange{Port: 10, EndPort: 20},
&PortRange{Port: 42},
})

tests := []struct {
port int
want require.BoolAssertionFunc
}{
{port: 10, want: require.True},
{port: 20, want: require.True},
{port: 15, want: require.True},
{port: 42, want: require.True},
{port: 30, want: require.False},
{port: 0, want: require.False},
}

for _, tt := range tests {
t.Run(strconv.Itoa(tt.port), func(t *testing.T) {
tt.want(t, portRanges.Contains(tt.port))
})
}
}

func hasNoErr(t require.TestingT, err error, msgAndArgs ...interface{}) {
require.NoError(t, err, msgAndArgs...)
}
Expand Down
3,153 changes: 1,576 additions & 1,577 deletions api/types/types.pb.go

Large diffs are not rendered by default.

Loading

0 comments on commit 7fd6be8

Please sign in to comment.