package aoiprxkit import ( "encoding/binary" "fmt" "net" ) const ( DefaultSAPGroup = "224.2.127.254" DefaultSAPPort = 9875 ) type SAPPacket struct { Version uint8 AddressTypeIPv6 bool IsDelete bool Encrypted bool Compressed bool AuthLenWords uint8 MessageIDHash uint16 OriginSource net.IP PayloadType string Payload []byte } type SAPAnnouncement struct { ReceivedAt string `json:"receivedAt"` SourceAddr string `json:"sourceAddr"` MessageID uint16 `json:"messageIdHash"` Delete bool `json:"delete"` PayloadType string `json:"payloadType"` SDP string `json:"sdp"` ParsedSDP SDPInfo `json:"parsedSdp"` } func ParseSAPPacket(buf []byte) (SAPPacket, error) { if len(buf) < 8 { return SAPPacket{}, fmt.Errorf("SAP packet too short") } b0 := buf[0] version := b0 >> 5 if version != 1 { return SAPPacket{}, fmt.Errorf("unsupported SAP version %d", version) } addrTypeIPv6 := (b0 & 0x10) != 0 isDelete := (b0 & 0x04) != 0 encrypted := (b0 & 0x02) != 0 compressed := (b0 & 0x01) != 0 authLenWords := buf[1] msgID := binary.BigEndian.Uint16(buf[2:4]) hdrLen := 4 var origin net.IP if addrTypeIPv6 { if len(buf) < hdrLen+16 { return SAPPacket{}, fmt.Errorf("SAP packet too short for IPv6 source") } origin = net.IP(buf[hdrLen : hdrLen+16]) hdrLen += 16 } else { if len(buf) < hdrLen+4 { return SAPPacket{}, fmt.Errorf("SAP packet too short for IPv4 source") } origin = net.IP(buf[hdrLen : hdrLen+4]) hdrLen += 4 } authBytes := int(authLenWords) * 4 if len(buf) < hdrLen+authBytes { return SAPPacket{}, fmt.Errorf("SAP packet too short for auth section") } hdrLen += authBytes if encrypted || compressed { return SAPPacket{}, fmt.Errorf("encrypted/compressed SAP payloads are not supported") } payloadType := "application/sdp" payloadStart := hdrLen if len(buf) > payloadStart && !(len(buf)-payloadStart >= 4 && string(buf[payloadStart:payloadStart+4]) == "v=0\n" || len(buf)-payloadStart >= 5 && string(buf[payloadStart:payloadStart+5]) == "v=0\r\n") { nul := -1 for i := payloadStart; i < len(buf); i++ { if buf[i] == 0 { nul = i break } } if nul == -1 { return SAPPacket{}, fmt.Errorf("SAP payload type missing NUL terminator") } payloadType = string(buf[payloadStart:nul]) payloadStart = nul + 1 } if payloadStart > len(buf) { return SAPPacket{}, fmt.Errorf("invalid SAP payload start") } return SAPPacket{ Version: version, AddressTypeIPv6: addrTypeIPv6, IsDelete: isDelete, Encrypted: encrypted, Compressed: compressed, AuthLenWords: authLenWords, MessageIDHash: msgID, OriginSource: origin, PayloadType: payloadType, Payload: append([]byte(nil), buf[payloadStart:]...), }, nil }