Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/cuddly-buttons-guess.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"github.com/livekit/protocol": patch
---

Match SIP Trunks by source IP or mask.
34 changes: 33 additions & 1 deletion sip/sip.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ package sip
import (
"fmt"
"math"
"net/netip"
"regexp"
"sort"
"strconv"
"strings"

"golang.org/x/exp/slices"

Expand Down Expand Up @@ -222,9 +224,36 @@ func ValidateTrunks(trunks []*livekit.SIPTrunkInfo) error {
return nil
}

func matchAddrs(addr string, mask string) bool {
if !strings.Contains(mask, "/") {
return addr == mask
}
ip, err := netip.ParseAddr(addr)
if err != nil {
return false
}
pref, err := netip.ParsePrefix(mask)
if err != nil {
return false
}
return pref.Contains(ip)
}

func matchAddr(addr string, masks []string) bool {
if addr == "" {
return true
}
for _, mask := range masks {
if !matchAddrs(addr, mask) {
return false
}
}
return true
}

// MatchTrunk finds a SIP Trunk definition matching the request.
// Returns nil if no rules matched or an error if there are conflicting definitions.
func MatchTrunk(trunks []*livekit.SIPTrunkInfo, calling, called string) (*livekit.SIPTrunkInfo, error) {
func MatchTrunk(trunks []*livekit.SIPTrunkInfo, srcIP, calling, called string) (*livekit.SIPTrunkInfo, error) {
var (
selectedTrunk *livekit.SIPTrunkInfo
defaultTrunk *livekit.SIPTrunkInfo
Expand All @@ -235,6 +264,9 @@ func MatchTrunk(trunks []*livekit.SIPTrunkInfo, calling, called string) (*liveki
if len(tr.InboundNumbers) != 0 && !slices.Contains(tr.InboundNumbers, calling) {
continue
}
if !matchAddr(srcIP, tr.InboundAddresses) {
continue
}
// Deprecated, but we still check it for backward compatibility.
matchesRe := len(tr.InboundNumbersRegex) == 0
for _, reStr := range tr.InboundNumbersRegex {
Expand Down
22 changes: 21 additions & 1 deletion sip/sip_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ func TestSIPMatchTrunk(t *testing.T) {
for _, c := range trunkCases {
c := c
t.Run(c.name, func(t *testing.T) {
got, err := MatchTrunk(c.trunks, sipNumber1, sipNumber2)
got, err := MatchTrunk(c.trunks, "", sipNumber1, sipNumber2)
if c.expErr {
require.Error(t, err)
require.Nil(t, got)
Expand Down Expand Up @@ -515,3 +515,23 @@ func TestSIPValidateDispatchRules(t *testing.T) {
})
}
}

func TestMatchIP(t *testing.T) {
cases := []struct {
addr string
mask string
exp bool
}{
{addr: "192.168.0.10", mask: "192.168.0.10", exp: true},
{addr: "192.168.0.10", mask: "192.168.0.11", exp: false},
{addr: "192.168.0.10", mask: "192.168.0.0/24", exp: true},
{addr: "192.168.0.10", mask: "192.168.0.10/0", exp: true},
{addr: "192.168.0.10", mask: "192.170.0.0/24", exp: false},
}
for _, c := range cases {
t.Run(c.mask, func(t *testing.T) {
got := matchAddrs(c.addr, c.mask)
require.Equal(t, c.exp, got)
})
}
}