Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #undef _BIGENDIAN
- #include <sys/types.h>
- #include <sys/socket.h>
- #define __FAVOR_BSD /* To unify tcp and udp headers for both FBSD & Linux */
- #include <netinet/in_systm.h>
- #include <netinet/in.h>
- #include <netinet/ip.h>
- #include <netinet/udp.h>
- #include <netinet/tcp.h>
- #include <net/ethernet.h>
- #include <arpa/inet.h>
- #include <pcap.h>
- #include <fcntl.h>
- #include <boost/date_time/posix_time/posix_time.hpp>
- #ifndef MIN
- # define MIN(a, b) ((a)<(b)?(a):(b))
- #endif
- typedef struct rtp_header
- {
- #ifdef _BIGENDIAN
- uint16_t version:2;
- uint16_t padbit:1;
- uint16_t extbit:1;
- uint16_t cc:4;
- uint16_t markbit:1;
- uint16_t paytype:7;
- #else
- uint16_t cc:4;
- uint16_t extbit:1;
- uint16_t padbit:1;
- uint16_t version:2;
- uint16_t paytype:7;
- uint16_t markbit:1;
- #endif
- uint16_t seq_number;
- uint32_t timestamp;
- uint32_t ssrc;
- uint32_t csrc[16];
- } __attribute__((packed)) rtp_header_t;
- #define HASH(a, b, c, d) (((a)^(b))^(((c)^(d))))
- typedef struct rtcp_header
- {
- #ifdef _BIGENDIAN
- uint8_t version:2;
- uint8_t padbit:1;
- uint8_t count:5;
- #else
- uint8_t count:5;
- uint8_t padbit:1;
- uint8_t version:2;
- #endif
- uint8_t type;
- uint16_t length;
- } __attribute__((packed)) rtcp_header_t;
- #undef VERBOSE
- #define LOGUNK
- enum packet_type_t {
- PT_UNKNOWN, PT_RTP, PT_RTCP, PT_SIP, PT_TCPSIP, PT_UDPFRAGMENT
- };
- bool isSIPPort(unsigned short port) {
- return port == 5060 || port == 15060 || port == 23432;
- }
- packet_type_t detectTcpSip(struct ip *ip, uint32_t *hash) {
- struct tcphdr* tcp;
- tcp = (struct tcphdr*)( (uint8_t*)ip + (ip->ip_hl<<2)); // ip_hl is in units of 4 bytes (32 bits)
- if (ip->ip_p != IPPROTO_TCP) {
- #ifdef LOGUNK
- fprintf(stderr, "Invalid IP-level protocol\n");
- #endif
- return PT_UNKNOWN;
- }
- if(isSIPPort(ntohs(tcp->th_sport)) || isSIPPort(ntohs(tcp->th_dport))) {
- *hash = HASH(ip->ip_src.s_addr, ip->ip_dst.s_addr, tcp->th_sport, tcp->th_dport);
- return PT_TCPSIP;
- }
- #ifdef LOGUNK
- fprintf(stderr, "TCP ports don't match\n");
- #endif
- return PT_UNKNOWN;
- }
- packet_type_t detectPacketType(const uint8_t* pdata, struct pcap_pkthdr* phdr, uint32_t *hash)
- {
- // ethernet
- struct ether_header* ep;
- struct ip* ip;
- struct udphdr* uh;
- ep = (struct ether_header*)pdata;
- if (ntohs (ep->ether_type) != ETHERTYPE_IP) {
- #ifdef LOGUNK
- fprintf(stderr, "Invalid PHY type protocol\n");
- #endif
- return PT_UNKNOWN;
- }
- ip = (struct ip*)(pdata + sizeof(struct ether_header));
- #ifdef VERBOSE
- printf("IP length=%d", ntohs(ip->ip_len));
- printf(" hdr_length=%d", 4*ip->ip_hl);
- printf(" src=%s", inet_ntoa(ip->ip_src));
- printf(" dst=%s", inet_ntoa(ip->ip_dst));
- printf(" proto=%d", ip->ip_p);
- #endif
- if (phdr->len < sizeof(struct ether_header) + ntohs(ip->ip_len)) {
- fprintf(stderr, "error: IP packet larger than containing ethernet packet \n");
- #ifdef LOGUNK
- fprintf(stderr, "Invalid ethernet packet length\n");
- #endif
- return PT_UNKNOWN;
- }
- // filter udp packets only
- if (ip->ip_p != IPPROTO_UDP) {
- return detectTcpSip(ip, hash);
- }
- //if(ntohs(ip->ip_off)&IP_MF || (ntohs(ip->ip_off )&IP_OFFMASK != 0)) {
- // Ignore IP packet fragments other than first
- if((ntohs(ip->ip_off)&IP_OFFMASK) != 0) {
- #ifdef VERBOSE
- printf("\n");
- #endif
- fprintf(stderr, "error: fragment of IP packet!\n");
- return PT_UDPFRAGMENT;
- }
- // udp
- uh = (struct udphdr*)( (uint8_t*)ip + (ip->ip_hl<<2)); // ip_hl is in units of 4 bytes (32 bits)
- uint32_t len = MIN(ntohs(uh->uh_ulen), htons(ip->ip_len) - (ip->ip_hl << 2));
- #ifdef VERBOSE
- printf(" sport=%d", ntohs(uh->uh_sport));
- printf(" dport=%d", ntohs(uh->uh_dport));
- printf(" udp_length=%d", ntohs(uh->uh_ulen));
- printf("\n");
- #endif
- if(ntohs(ip->ip_len) < 4*ip->ip_hl + len) {
- fprintf(stdout, "error: UDP packet smaller than containing IP packet for unknown reason\n");
- return PT_UNKNOWN;
- }
- *hash = HASH(ip->ip_src.s_addr, ip->ip_dst.s_addr, uh->uh_sport, uh->uh_dport);
- if(isSIPPort(ntohs(uh->uh_sport)) || isSIPPort(ntohs(uh->uh_dport)))
- return PT_SIP;
- // rtp
- rtp_header_t* rtp;
- rtcp_header_t* rtcp;
- rtp = (rtp_header_t*)((uint8_t*)uh + sizeof(struct udphdr));
- rtcp = (rtcp_header_t*)((uint8_t*)uh + sizeof(struct udphdr));
- if(len < sizeof(rtcp_header_t)) {
- #ifdef LOGUNK
- fprintf(stderr, "Invalid RTCP header length\n");
- #endif
- return PT_UNKNOWN;
- }
- if(rtcp->version != 2) { // Version is common for RTP and RTCP
- #ifdef LOGUNK
- fprintf(stderr, "Unknown RTP/RTCP version\n");
- #endif
- return PT_UNKNOWN;
- }
- if(rtcp->type >= 200 && rtcp->type <= 204) {
- return PT_RTCP;
- }
- if(len < 12) {
- #ifdef LOGUNK
- fprintf(stderr, "Invalid RTP header length\n");
- #endif
- return PT_UNKNOWN;
- }
- if (rtp->paytype <= 34 || rtp->paytype >= 96) {
- return PT_RTP;
- }
- #ifdef LOGUNK
- fprintf(stderr, "Invalid RTP payload type\n");
- #endif
- return PT_UNKNOWN;
- }
- int main(int argc, char * argv[])
- {
- using namespace boost::posix_time;
- assert( argc == 2);
- bool verbose(false);
- pcap_t* p;
- char errbuf[PCAP_ERRBUF_SIZE];
- p = pcap_open_offline(argv[1], errbuf);
- if (p == NULL) {
- fprintf(stderr, "could not open input file %s: %s \n", argv[1], errbuf);
- exit(0);
- }
- ptime begin = microsec_clock::local_time();
- time_duration rtpProcessTime = seconds(0);
- int rtpPackets(0), totalPackets(0), rtcpPackets(0), sipPackets(0), fragPackets(0), unkPackets(0);
- uint32_t hash;
- for (totalPackets = 0; true; ++totalPackets)
- {
- struct pcap_pkthdr hdr;
- struct pcap_pkthdr* phdr = &hdr;
- const uint8_t* pdata = pcap_next(p, &hdr);
- if (pdata == NULL) {
- break;
- }
- packet_type_t pt;
- ptime b = microsec_clock::local_time();
- pt = detectPacketType(pdata, phdr, &hash);
- ptime e = microsec_clock::local_time();
- switch(pt) {
- case PT_UDPFRAGMENT:
- fragPackets ++;
- break;
- case PT_RTP:
- std::cout << "Hash value: " << (hash%3) << std::endl;
- rtpPackets ++;
- break;
- case PT_RTCP:
- rtcpPackets ++;
- break;
- case PT_SIP:
- case PT_TCPSIP:
- sipPackets ++;
- break;
- case PT_UNKNOWN:
- unkPackets ++;
- }
- rtpProcessTime += (e-b);
- }
- ptime end = microsec_clock::local_time();
- std::cout << "Total Packets: " << totalPackets << std::endl;
- std::cout << "Detected RTP Packets: " << rtpPackets << std::endl;
- std::cout << "Detected RTCP Packets: " << rtcpPackets << std::endl;
- std::cout << "Detected SIP Packets: " << sipPackets << std::endl;
- std::cout << "Detected UDP Fragments: " << fragPackets << std::endl;
- std::cout << "Other (Unknown) Packets: " << unkPackets << std::endl;
- std::cout << "Total Time taken: " << (end-begin) << std::endl;
- std::cout << "Average Total Time Per Packet: " << ((end-begin)/totalPackets) << std::endl;
- std::cout << "Average Time Per RTP Check: " << (rtpProcessTime/totalPackets) << std::endl;
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement