#include <sys/stat.h>#include <sys/types.h>#include <netinet/tcp.h>#include <netinet/udp.h>#include <netinet/ip.h>#include <netinet/ip6.h>#include <net/ethernet.h>#include <pcap.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>
/*RTSP 端口*/#define RTSP_TCP_PORT_RANGE 554
typedef enum { RTSP_REQUEST, RTSP_REPLY, RTSP_NOT_FIRST_LINE} rtsp_type_t;
static const char *rtsp_methods[] = { "DESCRIBE", "ANNOUNCE", "GET_PARAMETER", "OPTIONS", "PAUSE", "PLAY", "RECORD", "REDIRECT", "SETUP", "SET_PARAMETER", "TEARDOWN"};
/* 用于RTSP统计 */struct rtsp_info_value_t { char *request_method; unsigned long int response_code;};
/* 假定一个字节数组(假定包含一个以空值结尾的字符串)作为参数, 并返回字符串的长度-即该数组的大小,对于空终止符的值减去1。 */#define STRLEN_CONST(str) (sizeof (str) - 1)
static const char rtsp_content_type[] = "Content-Type:";static const char rtsp_transport[] = "Transport:";static const char rtsp_sps_server_port[] = "server_port=";static const char rtsp_cps_server_port[] = "client_port=";static const char rtsp_sps_dest_addr[] = "dest_addr=";static const char rtsp_cps_src_addr[] = "src_addr=";static const char rtsp_rtp_udp_default[] = "rtp/avp";static const char rtsp_rtp_udp[] = "rtp/avp/udp";static const char rtsp_rtp_tcp[] = "rtp/avp/tcp";static const char rtsp_rdt_feature_level[] = "RDTFeatureLevel";static const char rtsp_real_rdt[] = "x-real-rdt/";static const char rtsp_real_tng[] = "x-pn-tng/"; /* synonym for x-real-rdt */static const char rtsp_inter[] = "interleaved=";static const char rtsp_content_length[] = "Content-Length:";
static void rtsp_create_conversation(u_char *line_begin, size_t line_len,rtsp_type_t rtsp_type_packet){ char buf[256]; char *tmp; bool rtp_udp_transport = false; bool rtp_tcp_transport = false; bool rdt_transport = false; //bool is_video = false; /* 是否需要显示视频 */ unsigned int c_data_port, c_mon_port; unsigned int s_data_port, s_mon_port; unsigned int ipv4_1, ipv4_2, ipv4_3, ipv4_4;
if (rtsp_type_packet != RTSP_REPLY) { return; }
/* 将行复制到buf */ if (line_len > sizeof(buf) - 1) { /* 避免溢出缓冲区。 */ line_len = sizeof(buf) - 1; }
memcpy(buf, line_begin, line_len); buf[line_len] = '\0'; printf("%s\n",buf); /* Get past "Transport:" and spaces */ tmp = buf + STRLEN_CONST(rtsp_transport); //printf("tmp %s\n",tmp); while (*tmp && isspace(*tmp)) tmp++;
if ((tmp = strstr(buf, rtsp_cps_src_addr))) {
tmp += strlen(rtsp_cps_src_addr); //printf("tmp ====== %s\n",tmp); if (sscanf(tmp, "\"%u.%u.%u.%u:%u\"", &ipv4_1, &ipv4_2, &ipv4_3, &ipv4_4, &c_data_port) == 5) { char *tmp2; char *tmp3; //printf("ipv4_1 %d\n",ipv4_1); //printf("ipv4_2 %d\n",ipv4_2); //printf("ipv4_3 %d\n",ipv4_3); //printf("ipv4_4 %d\n",ipv4_4); printf("c_data_port %d\n",c_data_port); //Skip leading tmp++; tmp2=strstr(tmp,":"); tmp3=strndup(tmp,tmp2-tmp); printf("src_addr %s\n",tmp3); free(tmp3); } } if ((tmp = strstr(buf, rtsp_sps_dest_addr))) { tmp += strlen(rtsp_sps_dest_addr); if (sscanf(tmp, "\":%u\"", &s_data_port) == 1) { /* :9 mean ignore */ if (s_data_port == 9) { s_data_port = 0; } printf("s_data_port %d\n",s_data_port); } } if ((tmp = strstr(buf, rtsp_sps_server_port))) { tmp += strlen(rtsp_sps_server_port); if (sscanf(tmp, "%u", &s_mon_port) == 1) { printf("s_mon_port %d\n",s_mon_port); } } }
static bool is_rtsp_request_or_reply( unsigned char *line, int offset, rtsp_type_t *type){ unsigned int ii = 0; char *data = reinterpret_cast<char *>(line); int tokenlen; char response_chars[4]; struct rtsp_info_value_t rtsp_info; char *token, *next_token; /*这是RTSP的回复 ? */ if ( strncasecmp("RTSP/", data, 5) == 0) { /* * Yes. */ *type = RTSP_REPLY; /* 第一个标记是版本。 */ offset += 9; memcpy(response_chars, data + offset, 3); response_chars[3] = '\0'; rtsp_info.response_code = strtoul(response_chars, NULL, 10); //printf("rtsp_info.response_code %d\n",rtsp_info.response_code); return true; }
/* 这是RTSP请求吗? 检查该行是否以RTSP请求方法之一开头。 */ for (ii = 0; ii < sizeof rtsp_methods / sizeof rtsp_methods[0]; ii++) { size_t len = strlen(rtsp_methods[ii]); if (strncasecmp(rtsp_methods[ii], data, len) == 0 &&(isspace(data[len]))) { *type = RTSP_REQUEST; rtsp_info.request_method = strndupa(rtsp_methods[ii], len+1); //printf("request_method: %s\n",rtsp_info.request_method);
return true; } }
/* 既不是请求也不是回应 */ *type = RTSP_NOT_FIRST_LINE; return false;}
/* 阅读回复消息的第一行 */static void process_rtsp_reply(u_char *rtsp_data, int offset,rtsp_type_t rtsp_type_packet){ char *lineend = reinterpret_cast<char *>(rtsp_data + offset); char *status = reinterpret_cast<char *>(rtsp_data ); char *status_start; unsigned int status_i;
/* status code */
/* Skip protocol/version */ while (status < lineend && !isspace(*status)) status++; /* Skip spaces */ while (status < lineend && isspace(*status)) status++;
/* Actual code number now */ status_start = status; //printf("status_start %s\n",status_start); status_i = 0; while (status < lineend && isdigit(*status)) status_i = status_i * 10 + *status++ - '0'; //printf("status_i %d\n",status_i); offset += strlen(lineend); rtsp_create_conversation(rtsp_data,offset,rtsp_type_packet);
}
static void process_rtsp_request(u_char *rtsp_data, int offset,rtsp_type_t rtsp_type_packet){ char *lineend = reinterpret_cast<char *>(rtsp_data + offset); // u_char *lineend = rtsp_data + offset; unsigned int ii = 0; char *url; char *url_start; char buf[256]; char *tmp; int content_length = 0; char content_type[256]; /* Request Methods */ for (ii = 0; ii < sizeof rtsp_methods / sizeof rtsp_methods[0]; ii++) { size_t len = strlen(rtsp_methods[ii]); if (strncasecmp(rtsp_methods[ii], lineend, len) == 0 &&(isspace(lineend[len]))) break; }
//printf("process_rtsp_request 0x%.2X,0x%.2X,0x%.2X,0x%.2X\n",lineend[0],lineend[1],lineend[2],lineend[3]); /* URL */ url = lineend;
/* Skip method name again */ while (url < lineend && !isspace(*url)) url++; /* Skip spaces */ while (url < lineend && isspace(*url)) url++; /* URL starts here */ url_start = url; /* Scan to end of URL */ while (url < lineend && !isspace(*url)) url++; printf("%s\n",url_start); printf("111url %s\n",url); if ((tmp = strstr(url_start, rtsp_content_type))) { tmp += strlen(rtsp_content_type); if (sscanf(tmp, "%s", content_type) == 1) { //printf("content_type %s\n",content_type); } } //Content-Length if ((tmp = strstr(url_start, rtsp_content_length))) { tmp += strlen(rtsp_content_length); if (sscanf(tmp, "%u", &content_length) == 1) { //printf("content_length %d\n",content_length); } } }
void dissect_rtsp(u_char *rtsp_data){ int offset = 0; rtsp_type_t rtsp_type_packet; bool is_request_or_reply; u_char *linep, *lineend; u_char c; //bool is_header = false; is_request_or_reply = is_rtsp_request_or_reply(rtsp_data, offset, &rtsp_type_packet); if (is_request_or_reply) goto is_rtsp;
is_rtsp:
switch(rtsp_type_packet) { case RTSP_REQUEST:
process_rtsp_request(rtsp_data, offset,rtsp_type_packet);
break;
case RTSP_REPLY:
process_rtsp_reply(rtsp_data, offset,rtsp_type_packet); break;
case RTSP_NOT_FIRST_LINE: /* Drop through, it may well be a header line */ break; default: break; }
}
static void dissect_rtsp_tcp(struct ip *pIp){ int iHeadLen = pIp->ip_hl*4; int iPacketLen = ntohs(pIp->ip_len) - iHeadLen; int offset = 0; int nFragSeq = 0; struct tcphdr *pTcpHdr = (struct tcphdr *)(((char *)pIp) + iHeadLen); if (pIp->ip_p == IPPROTO_TCP && (ntohs(pTcpHdr->dest) == RTSP_TCP_PORT_RANGE) || (ntohs(pTcpHdr->source) == RTSP_TCP_PORT_RANGE) )/*仅处理TCP协议*/ { int iPayloadLen = iPacketLen - pTcpHdr->doff*4; //printf("TCP Payload Len %d\n",iPayloadLen); u_char *RtspHdr = (u_char*)(pTcpHdr+1); if (RtspHdr == NULL) return; u_char *RtspData = RtspHdr + 12; /*skip OPtions */ //printf("NtpHdr 0x%.2X,0x%.2X,0x%.2X,0x%.2X\n",RtspData[0],RtspData[1],RtspData[2],RtspData[3]); dissect_rtsp(RtspData); } }
评论