Codebase list libfindrtp / fresh-snapshots/upstream libfindrtp.c
fresh-snapshots/upstream

Tree @fresh-snapshots/upstream (Download .tar.gz)

libfindrtp.c @fresh-snapshots/upstreamraw · history · blame

/*
 *  libfindrtp
 *  Dustin D. Trammell <[email protected]>
 *  12/2006
 *
 *  This library provides RTP based tools a method to auto-identify
 *  an RTP session's endpoint addresses and UDP ports.  It does this
 *  by watching the network for signaling and extracting the negotiated
 *  RTP ports from the signaling messages.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netpacket/packet.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <pcap.h>
#include "libfindrtp.h"

unsigned int libfindrtp_debug;
rtp_pair lfr_rp;


rtp_pair *libfindrtp_find_rtp( char *interface, unsigned int promisc, char *host_a, char *host_b ) {
	rtp_pair *rp;

	memset( &lfr_rp, 0, sizeof(lfr_rp) );

	if( host_a ) {
		if( inet_pton( AF_INET, host_a, &lfr_rp.ip_a_n ) <= 0 ) {
			if(libfindrtp_debug) fprintf( stderr, "libfindrtp_find_rtp() ERROR: %s is not a valid IP address\n", host_a );
			return NULL;
		}
		if(lfr_rp.ip_a_n) {
			lfr_rp.ip_a = ntohl( lfr_rp.ip_a_n );
			sprintf( lfr_rp.ip_a_a, "%s", inet_ntoa( *((struct in_addr *)&lfr_rp.ip_a_n)) );
		}
	}

	if( host_b ) {
		if( inet_pton( AF_INET, host_b, &lfr_rp.ip_b_n ) <= 0 ) {
			if(libfindrtp_debug) fprintf( stderr, "libfindrtp_find_rtp() ERROR: %s is not a valid IP address\n", host_b );
			return NULL;
		}
		if(lfr_rp.ip_b_n) {
			lfr_rp.ip_b = ntohl( lfr_rp.ip_b_n );
			sprintf( lfr_rp.ip_b_a, "%s", inet_ntoa( *((struct in_addr *)&lfr_rp.ip_b_n)) );
		}
	}

	/* network interface */
	if(!interface)
		interface = LIBFINDRTP_IF;
	if(libfindrtp_debug) printf( "Targeting interface %s\n", interface );

	pcap_t *pcap;
	char pcap_errbuf[PCAP_ERRBUF_SIZE];

	pcap = pcap_open_live( interface, 4096, promisc, 0, pcap_errbuf );
	if(!pcap) {
		if(libfindrtp_debug) fprintf( stderr, "libfindrtp ERROR: couldn't open %s in promiscuous mode\n", interface );
		if(libfindrtp_debug) fprintf( stderr, "libfindrtp ERROR: pcap says: %s\n", pcap_errbuf );
		return NULL;
	}

	bpf_u_int32 dev_net;
	bpf_u_int32 dev_mask;
	if( pcap_lookupnet( interface, &dev_net, &dev_mask, pcap_errbuf )) {
		if(libfindrtp_debug) fprintf( stderr, "libfindrtp ERROR: couldn't lookup %s's IP and netmask\n", interface );
		if(libfindrtp_debug) fprintf( stderr, "libfindrtp_find_rtp() ERROR: pcap says: %s\n", pcap_errbuf );
		return NULL;
	}

	char filterbuf[1024];
	if( host_a && host_b ) sprintf( filterbuf, "(host %s or host %s) and ip", host_a, host_b );
	else if( host_a && !host_b ) sprintf( filterbuf, "host %s and ip", host_a );
	else if( host_b && !host_a ) sprintf( filterbuf, "host %s and ip", host_b );
	else sprintf( filterbuf, "ip" );
	if(libfindrtp_debug) printf( "libfindrtp_find_rtp(): using pcap filter \"%s\".\n", filterbuf );

	struct bpf_program pfilter;
	if( pcap_compile( pcap, &pfilter, filterbuf, 1, dev_mask ) ) {
		if(libfindrtp_debug) fprintf( stderr, "libfindrtp_find_rtp() ERROR: couldn't compile pcap filter:\n  \"%s\"", filterbuf );
		return NULL;
	}
	if( pcap_setfilter( pcap, &pfilter ) ) {
		if(libfindrtp_debug) fprintf( stderr, "ERROR: couldn't set this filter:\n  \"%s\"", filterbuf );
		return NULL;
	}

	int pcnt;
	while( !lfr_rp.ip_a || !lfr_rp.port_a || !lfr_rp.ip_b || !lfr_rp.port_b ) {
		pcnt = pcap_dispatch( pcap, 1, _libfindrtp_packet_handler, NULL );
		if(libfindrtp_debug>=2) printf( "State: ip_a == %s | port_a == %d | ip_b == %s | port_b == %d\n", lfr_rp.ip_a_a, lfr_rp.port_a, lfr_rp.ip_b_a, lfr_rp.port_b );
		if( pcnt < 0 ) {
			if(libfindrtp_debug) fprintf( stderr, "libfindrtp_find_rtp() ERROR: during pcap\n");
			return NULL;
		}
	}

	pcap_freecode(&pfilter);

	rp = malloc( sizeof(rtp_pair) );
	memcpy( rp, &lfr_rp, sizeof(rtp_pair) );

	return rp;
}