Skip to content

Commit

Permalink
Merge pull request #4 from negbie/master
Browse files Browse the repository at this point in the history
Custom SIP portrange, some error checks
  • Loading branch information
negbie authored Nov 8, 2017
2 parents dab65d8 + b553f73 commit ab352e2
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 50 deletions.
3 changes: 3 additions & 0 deletions build_static.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#!/bin/sh

# Thanks for the idea to use musl!
# https://www.moiji-mobile.com/2017/10/15/static-binaries-for-go-with-docker/

set -ex

apk update
Expand Down
1 change: 1 addition & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type InterfacesConfig struct {
Type string `config:"type"`
ReadFile string `config:"read_file"`
WriteFile string `config:"write_file"`
PortRange string `config:"port_range"`
Snaplen int `config:"snaplen"`
BufferSizeMb int `config:"buffer_size_mb"`
ReadSpeed bool `config:"top_speed"`
Expand Down
44 changes: 22 additions & 22 deletions decoder/decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ type Decoder struct {
unknownCount int
IPFlow gopacket.Flow
UDPFlow gopacket.Flow
lru *lru.Cache
bigcache *bigcache.BigCache
hash hash.Hash64
SIPHash hash.Hash64
SIPCache *lru.Cache
RTCPCache *bigcache.BigCache
}

type Packet struct {
Expand All @@ -56,14 +56,14 @@ func NewDecoder() *Decoder {
host = "sniffer"
}

la, err := lru.New(8000)
sh := xxhash.New()

sc, err := lru.New(8000)
if err != nil {
logp.Err("lru %v", err)
}

xh := xxhash.New()

bConf := bigcache.Config{
rcConf := bigcache.Config{
// number of shards (must be a power of 2)
Shards: 1024,
// time after which entry can be evicted
Expand All @@ -73,7 +73,7 @@ func NewDecoder() *Decoder {
// max entry size in bytes, used only in initial memory allocation
MaxEntrySize: 300,
// prints information about additional memory allocation
Verbose: true,
Verbose: false,
// cache will not allocate more memory than this limit, value in MB
// if value is reached then the oldest entries can be overridden for the new ones
// 0 value means no size limit
Expand All @@ -84,7 +84,7 @@ func NewDecoder() *Decoder {
OnRemove: nil,
}

bc, err := bigcache.NewBigCache(bConf)
rc, err := bigcache.NewBigCache(rcConf)
if err != nil {
logp.Err("bigcache %v", err)
}
Expand All @@ -99,9 +99,9 @@ func NewDecoder() *Decoder {
tcpCount: 0,
dnsCount: 0,
unknownCount: 0,
lru: la,
hash: xh,
bigcache: bc,
SIPHash: sh,
SIPCache: sc,
RTCPCache: rc,
}
go d.flushFrag()
go d.printStats()
Expand All @@ -126,12 +126,12 @@ func (d *Decoder) Process(data []byte, ci *gopacket.CaptureInfo) (*Packet, error
}

if config.Cfg.Dedup {
d.hash.Write(ip4.Payload)
d.SIPHash.Write(ip4.Payload)
//key := fastHash(ip4.Payload)
key := d.hash.Sum64()
d.hash.Reset()
_, dup := d.lru.Get(key)
d.lru.Add(key, nil)
key := d.SIPHash.Sum64()
d.SIPHash.Reset()
_, dup := d.SIPCache.Get(key)
d.SIPCache.Add(key, nil)
if dup == true {
d.dupCount++
return nil, nil
Expand Down Expand Up @@ -251,7 +251,7 @@ func (d *Decoder) cacheSDPIPPort(payload []byte) {
}

restPort := payload[posSDPPort:]
if posRestPort := bytes.Index(restIP, []byte(" RTP")); posRestPort >= 0 {
if posRestPort := bytes.Index(restPort, []byte(" RTP")); posRestPort >= 0 {
SDPPort, err := strconv.Atoi(string(restPort[len("m=audio "):bytes.Index(restPort, []byte(" RTP"))]))
if err != nil {
logp.Warn("%v", err)
Expand All @@ -263,20 +263,20 @@ func (d *Decoder) cacheSDPIPPort(payload []byte) {

if posCallID := bytes.Index(payload, []byte("Call-ID: ")); posCallID >= 0 {
restCallID := payload[posCallID:]
if posRestCallID := bytes.Index(restIP, []byte("\r\n")); posRestCallID >= 0 {
if posRestCallID := bytes.Index(restCallID, []byte("\r\n")); posRestCallID >= 0 {
callID = restCallID[len("Call-ID: "):bytes.Index(restCallID, []byte("\r\n"))]
} else {
logp.Warn("Couldn't find end of Call-ID in '%s'", string(restCallID))
}
} else if posID := bytes.Index(payload, []byte("i: ")); posID >= 0 {
restID := payload[posID:]
if posRestID := bytes.Index(restIP, []byte("\r\n")); posRestID >= 0 {
if posRestID := bytes.Index(restID, []byte("\r\n")); posRestID >= 0 {
callID = restID[len("i: "):bytes.Index(restID, []byte("\r\n"))]
} else {
logp.Warn("Couldn't find end of Call-ID in '%s'", string(restID))
}
}
d.bigcache.Set(SDPIP+RTCPPort, callID)
d.RTCPCache.Set(SDPIP+RTCPPort, callID)
}
}

Expand All @@ -287,7 +287,7 @@ func (d *Decoder) correlateRTCP(payload []byte) ([]byte, []byte, byte) {
return nil, nil, 0
}

corrID, err := d.bigcache.Get(d.IPFlow.Src().String() + d.UDPFlow.Src().String())
corrID, err := d.RTCPCache.Get(d.IPFlow.Src().String() + d.UDPFlow.Src().String())
if err != nil {
logp.Warn("%v", err)
return nil, nil, 0
Expand Down
Binary file added example/rtp_rtcp_sip.pcap
Binary file not shown.
19 changes: 10 additions & 9 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,24 @@ func parseFlags() {
var keepLogFiles int

flag.StringVar(&ifaceConfig.Device, "i", "", "Listen on interface")
flag.StringVar(&ifaceConfig.Type, "t", "pcap", "Capture types are [af_packet, pcap, file]")
flag.StringVar(&ifaceConfig.ReadFile, "rf", "", "Read packets from file. Please use -t file")
flag.StringVar(&ifaceConfig.WriteFile, "wf", "", "Write packets to file")
flag.IntVar(&ifaceConfig.Loop, "lp", 1, "Loop count over ReadFile")
flag.BoolVar(&ifaceConfig.ReadSpeed, "rs", false, "Maximum read speed. Doesn't use packet timestamps")
flag.IntVar(&ifaceConfig.Snaplen, "s", 32768, "Snap length")
flag.StringVar(&ifaceConfig.Type, "t", "pcap", "Capture types are [pcap, af_packet]")
flag.StringVar(&ifaceConfig.ReadFile, "rf", "", "Read packets from pcap file")
flag.StringVar(&ifaceConfig.WriteFile, "wf", "", "Write packets to pcap file")
flag.IntVar(&ifaceConfig.Loop, "lp", 1, "Loop count over ReadFile. Use 0 to loop forever")
flag.BoolVar(&ifaceConfig.ReadSpeed, "rs", false, "Maximum pcap read speed. Doesn't use packet timestamps")
flag.IntVar(&ifaceConfig.Snaplen, "s", 32768, "Snaplength")
flag.StringVar(&ifaceConfig.PortRange, "pr", "5060-5090", "Portrange to capture SIP")
flag.IntVar(&ifaceConfig.BufferSizeMb, "b", 64, "Interface buffersize (MB)")
flag.IntVar(&keepLogFiles, "kl", 4, "Rotate the number of log files")
flag.StringVar(&logging.Level, "l", "info", "Log level [debug, info, warning, error]")
flag.BoolVar(&ifaceConfig.OneAtATime, "o", false, "Read packet for packet")
flag.StringVar(&fileRotator.Path, "p", "./", "Log filepath")
flag.StringVar(&fileRotator.Name, "n", "heplify.log", "Log filename")
flag.Uint64Var(&rotateEveryKB, "r", 16384, "Log filesize (KB)")
flag.StringVar(&config.Cfg.Mode, "m", "SIP", "Capture modes [DNS, LOG, SIP, RTCP, TLS]")
flag.StringVar(&config.Cfg.Mode, "m", "SIP", "Capture modes [DNS, LOG, SIP, SIPRTCP, TLS]")
flag.BoolVar(&config.Cfg.Dedup, "dd", true, "Deduplicate packets")
flag.StringVar(&config.Cfg.Filter, "fi", "", "Filter out interesting packets like SIP INVITES, Handshakes ...")
flag.StringVar(&config.Cfg.Discard, "di", "", "Discard uninteresting packets like SIP OPTIONS, HTTP Requests ...")
flag.StringVar(&config.Cfg.Filter, "fi", "", "Filter interesting packets")
flag.StringVar(&config.Cfg.Discard, "di", "", "Discard uninteresting packets")
flag.StringVar(&config.Cfg.HepServer, "hs", "127.0.0.1:9060", "HEP Server address")
flag.Parse()

Expand Down
31 changes: 16 additions & 15 deletions protos/rtcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,13 +177,13 @@ func (rp *RTCP_Packet) MarshalJSON() ([]byte, error) {
func ParseRTCP(data []byte) ([]byte, error) {
dataLen := len(data)
if dataLen < 28 {
return nil, fmt.Errorf("Useless data inside RTCP packet='%s' length=%d", string(data), len(data))
return nil, fmt.Errorf("Useless data inside RTCP packet='%s' length=%d", string(data), dataLen)
}
pkt := &RTCP_Packet{}
offset := 0

for dataLen > 0 {
if dataLen%4 != 0 || dataLen < 4 {
if dataLen < 4 || dataLen > 576 {
return nil, fmt.Errorf("Fishy RTCP packet=%v length=%d", data, dataLen)
}

Expand All @@ -193,7 +193,7 @@ func ParseRTCP(data []byte) ([]byte, error) {
RTCPType := data[offset+1]
RTCPLength := binary.BigEndian.Uint16(data[offset+2:]) * 4

offset = offset + 4
offset += 4

if receptionReportCount < 0 || receptionReportCount > 4 {
return nil, fmt.Errorf("Fishy RTCP receptionReportCount=%d", receptionReportCount)
Expand All @@ -211,7 +211,7 @@ func ParseRTCP(data []byte) ([]byte, error) {
pkt.SenderInformation.Rtp_timestamp = binary.BigEndian.Uint32(data[offset+12:])
pkt.SenderInformation.Pkt_count = binary.BigEndian.Uint32(data[offset+16:])
pkt.SenderInformation.Octet_count = binary.BigEndian.Uint32(data[offset+20:])
offset = offset + 24
offset += 24

if receptionReportCount > 0 && RTCPLength >= 24 {
tmpReportBlocks := make([]RTCP_report_block, receptionReportCount)
Expand All @@ -227,20 +227,21 @@ func ParseRTCP(data []byte) ([]byte, error) {
tmpReportBlocks[i].Delay_last_SR = binary.BigEndian.Uint32(data[offset+20:])
tmpReportBlocks[i].ReportCount = receptionReportCount
tmpReportBlocks[i].RTCPType = RTCPType
offset = offset + 24
offset += 24
RTCPLength -= 24
pkt.ReportBlocks = pkt.AddReportBlock(tmpReportBlocks[i])
}
}

case TYPE_RTCP_RR:
if RTCPLength < 28 {
if RTCPLength < 4 {
return nil, fmt.Errorf("To small RTCP packet=%v length=%d type=%d", data[offset:RTCPLength], RTCPLength, RTCPType)
}

pkt.Ssrc = binary.BigEndian.Uint32(data[offset:])
offset = offset + 4
offset += 4

if receptionReportCount > 0 && RTCPLength >= 28 {
if receptionReportCount > 0 && RTCPLength >= 24 {
tmpReportBlocks := make([]RTCP_report_block, receptionReportCount)
for i := 0; i < int(receptionReportCount); i++ {
tmpReportBlocks[i].SourceSsrc = binary.BigEndian.Uint32(data[offset:])
Expand All @@ -254,26 +255,27 @@ func ParseRTCP(data []byte) ([]byte, error) {
tmpReportBlocks[i].Delay_last_SR = binary.BigEndian.Uint32(data[offset+20:])
tmpReportBlocks[i].ReportCount = receptionReportCount
tmpReportBlocks[i].RTCPType = RTCPType
offset = offset + 24
offset += 24
RTCPLength -= 24
pkt.ReportBlocks = pkt.AddReportBlock(tmpReportBlocks[i])
}
}

case TYPE_RTCP_SDES:
logp.Debug("rtcp", "Discard RTCP_SDES packet type: %d", RTCPType)
offset = offset + int(RTCPLength)
offset += int(RTCPLength)
case TYPE_RTCP_APP:
logp.Debug("rtcp", "Discard RTCP_APP packet type: %d", RTCPType)
offset = offset + int(RTCPLength)
offset += int(RTCPLength)
case TYPE_RTCP_BYE:
logp.Debug("rtcp", "Discard RTCP_BYE packet type: %d", RTCPType)
offset = offset + int(RTCPLength)
offset += int(RTCPLength)
case TYPE_RTCP_XR:
logp.Debug("rtcp", "Discard RTCP_XR packet type: %d", RTCPType)
offset = offset + int(RTCPLength)
offset += int(RTCPLength)
default:
logp.Debug("rtcp", "Discard unsupported packet type: %d", RTCPType)
offset = offset + int(RTCPLength)
offset += int(RTCPLength)
}

dataLen -= offset
Expand All @@ -285,6 +287,5 @@ func ParseRTCP(data []byte) ([]byte, error) {
return nil, err
}

logp.Debug("rtcp", "RTCP json payload:\n%v\n", string(rtcpPkt))
return rtcpPkt, nil
}
12 changes: 8 additions & 4 deletions sniffer/sniffer.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,11 @@ func (sniffer *SnifferSetup) setFromConfig(cfg *config.InterfacesConfig) error {

switch sniffer.mode {
case "SIP":
sniffer.filter = "(greater 256 and portrange 5060-5090 or ip[6:2] & 0x1fff != 0) or (vlan and (greater 256 and portrange 5060-5090 or ip[6:2] & 0x1fff != 0))"
sniffer.filter = "(greater 256 and portrange " + sniffer.config.PortRange + " or ip[6:2] & 0x1fff != 0) or (vlan and (greater 256 and portrange " + sniffer.config.PortRange + " or ip[6:2] & 0x1fff != 0))"
case "RTCP":
sniffer.filter = "(ip and ip[6] & 0x2 = 0 and ip[6:2] & 0x1fff = 0 and udp and udp[8] & 0xc0 = 0x80 and udp[9] >= 0xc8 && udp[9] <= 0xcc)"
case "SIPRTCP":
sniffer.filter = "(greater 256 and portrange 5060-5090 or ip[6:2] & 0x1fff != 0) or (ip and ip[6] & 0x2 = 0 and ip[6:2] & 0x1fff = 0 and udp and udp[8] & 0xc0 = 0x80 and udp[9] >= 0xc8 && udp[9] <= 0xcc)"
sniffer.filter = "(greater 256 and portrange " + sniffer.config.PortRange + " or ip[6:2] & 0x1fff != 0) or (ip and ip[6] & 0x2 = 0 and ip[6:2] & 0x1fff = 0 and udp and udp[8] & 0xc0 = 0x80 and udp[9] >= 0xc8 && udp[9] <= 0xcc)"
case "LOG":
sniffer.filter = "greater 128 and port 514"
case "DNS":
Expand All @@ -108,7 +108,7 @@ func (sniffer *SnifferSetup) setFromConfig(cfg *config.InterfacesConfig) error {
sniffer.filter = "tcp and port 443 and tcp[(((tcp[12:1] & 0xf0) >> 2)):1] = 0x16 and ((tcp[(((tcp[12:1] & 0xf0) >> 2)+5):1] = 0x01) or (tcp[(((tcp[12:1] & 0xf0) >> 2)+5):1] = 0x02))"
default:
sniffer.mode = "SIP"
sniffer.filter = "(greater 256 and portrange 5060-5090 or ip[6:2] & 0x1fff != 0) or (vlan and (greater 256 and portrange 5060-5090 or ip[6:2] & 0x1fff != 0))"
sniffer.filter = "(greater 256 and portrange " + sniffer.config.PortRange + " or ip[6:2] & 0x1fff != 0) or (vlan and (greater 256 and portrange " + sniffer.config.PortRange + " or ip[6:2] & 0x1fff != 0))"
}

logp.Info("Sniffer type: [%s] device: [%s] mode: [%s]", sniffer.config.Type, sniffer.config.Device, sniffer.mode)
Expand Down Expand Up @@ -167,13 +167,17 @@ func (sniffer *SnifferSetup) Init(testMode bool, mode string, factory WorkerFact
sniffer.mode = mode

if interfaces.Device == "" && interfaces.ReadFile == "" {
fmt.Printf("\nPlease use one of the following devices:\n\n")
fmt.Printf("Please use one of the following devices:\n\n")
_, err := ListDeviceNames(false, false)
if err != nil {
return fmt.Errorf("getting devices list: %v", err)
}
fmt.Println("")
os.Exit(1)
} else if interfaces.Device == "any" && interfaces.Type == "pcap" {
fmt.Println("Interface 'any' and capture type 'pcap' will break VLAN capture!")
fmt.Println("To listen on interface 'any' please use 'af_packet' capture type!")
os.Exit(1)
}

if !testMode {
Expand Down

0 comments on commit ab352e2

Please sign in to comment.