From 2a22fc40806543071260e2f5e0c28eba2bea1d2b Mon Sep 17 00:00:00 2001 From: Nishad Musthafa Date: Sun, 8 Jun 2025 23:22:30 -0700 Subject: [PATCH] Strong Number filter for Trunks Added logic to fail calls when calls 'to' number on the inbound trunk did not match any trunk --- pkg/service/ioservice_sip.go | 6 +- pkg/service/ioservice_sip_test.go | 111 +++++++++++++++++++++++++++++- 2 files changed, 112 insertions(+), 5 deletions(-) diff --git a/pkg/service/ioservice_sip.go b/pkg/service/ioservice_sip.go index 5892a4c47..32bc6219b 100644 --- a/pkg/service/ioservice_sip.go +++ b/pkg/service/ioservice_sip.go @@ -17,6 +17,7 @@ package service import ( "context" "errors" + "fmt" "net/netip" "github.com/dennwc/iters" @@ -145,8 +146,9 @@ func (s *IOInfoService) GetSIPTrunkAuthentication(ctx context.Context, req *rpc. return nil, err } if trunk == nil { - log.Debugw("No SIP trunk matched for auth", "sipTrunk", "") - return &rpc.GetSIPTrunkAuthenticationResponse{}, nil + err := twirp.NotFoundError(fmt.Sprintf("sip trunk not found for destination %q", req.Call.To)) + log.Errorw("No SIP trunk matched for auth", err, "sipTrunk", "", "to", req.Call.To) + return nil, err } log.Debugw("SIP trunk matched for auth", "sipTrunk", trunk.SipTrunkId) return &rpc.GetSIPTrunkAuthenticationResponse{ diff --git a/pkg/service/ioservice_sip_test.go b/pkg/service/ioservice_sip_test.go index 2a8b75288..4aca9c5be 100644 --- a/pkg/service/ioservice_sip_test.go +++ b/pkg/service/ioservice_sip_test.go @@ -16,13 +16,15 @@ package service_test import ( "context" - "github.com/dennwc/iters" - "github.com/livekit/livekit-server/pkg/service" - "github.com/livekit/psrpc" "slices" "testing" + "github.com/dennwc/iters" + "github.com/livekit/livekit-server/pkg/service" + "github.com/livekit/psrpc" + "github.com/livekit/protocol/livekit" + "github.com/livekit/protocol/rpc" "github.com/stretchr/testify/require" ) @@ -120,3 +122,106 @@ func TestSIPRuleSelect(t *testing.T) { }) } } + +func TestGetSIPTrunkAuthentication(t *testing.T) { + ctx := context.Background() + s, rs := ioStoreDocker(t) + + // Set up test trunks + trunks := []*livekit.SIPInboundTrunkInfo{ + { + SipTrunkId: "trunk1", + Numbers: []string{"1234"}, + AuthUsername: "user1", + AuthPassword: "pass1", + }, + { + SipTrunkId: "trunk2", + Numbers: []string{"5678", "5679"}, + AuthUsername: "user2", + AuthPassword: "pass2", + }, + } + + for _, tr := range trunks { + err := rs.StoreSIPInboundTrunk(ctx, tr) + require.NoError(t, err) + } + + tests := []struct { + name string + call *rpc.SIPCall + wantTrunkID string + wantUser string + wantPass string + wantErr bool + wantErrMsg string + }{ + { + name: "exact match single number", + call: &rpc.SIPCall{ + To: &livekit.SIPUri{User: "1234"}, + From: &livekit.SIPUri{User: "9999"}, + SourceIp: "192.168.1.1", + }, + wantTrunkID: "trunk1", + wantUser: "user1", + wantPass: "pass1", + wantErr: false, + }, + { + name: "exact match multiple numbers", + call: &rpc.SIPCall{ + To: &livekit.SIPUri{User: "5679"}, + From: &livekit.SIPUri{User: "8888"}, + SourceIp: "192.168.1.1", + }, + wantTrunkID: "trunk2", + wantUser: "user2", + wantPass: "pass2", + wantErr: false, + }, + { + name: "no matching trunk", + call: &rpc.SIPCall{ + To: &livekit.SIPUri{User: "9999"}, + From: &livekit.SIPUri{User: "8888"}, + SourceIp: "192.168.1.1", + }, + wantErr: true, + wantErrMsg: `sip trunk not found for destination "user:\"9999\""`, + }, + { + name: "invalid source IP", + call: &rpc.SIPCall{ + To: &livekit.SIPUri{User: "1234"}, + From: &livekit.SIPUri{User: "9999"}, + SourceIp: "invalid-ip", + }, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + req := &rpc.GetSIPTrunkAuthenticationRequest{ + Call: tt.call, + } + resp, err := s.GetSIPTrunkAuthentication(ctx, req) + + if tt.wantErr { + require.Error(t, err) + if tt.wantErrMsg != "" { + require.Contains(t, err.Error(), tt.wantErrMsg) + } + return + } + + require.NoError(t, err) + require.NotNil(t, resp) + require.Equal(t, tt.wantTrunkID, resp.SipTrunkId) + require.Equal(t, tt.wantUser, resp.Username) + require.Equal(t, tt.wantPass, resp.Password) + }) + } +}