From d659ce6701878068bd475ef1f482c0a601b138bb Mon Sep 17 00:00:00 2001
From: Ludovic Pouzenc <ludovic@pouzenc.fr>
Date: Sun, 21 Oct 2012 16:05:19 +0000
Subject: Partie UDP revampée (write() à la place de sendto() grace à
 l'utilisation de connect() en UDP... Oui oui, c'est possible et normal.
 Résolution des noms avec getnameinfo(). Synthèse du filter par défaut en
 fonction de ça. Reste à tester avec un PC en IPv6 !
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

git-svn-id: file:///var/svn/2012-tzsp/trunk@10 147d2d3d-d0bd-48ea-923a-d90ac20f5906
---
 pcap2tzsp.c | 155 +++++++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 106 insertions(+), 49 deletions(-)

(limited to 'pcap2tzsp.c')

diff --git a/pcap2tzsp.c b/pcap2tzsp.c
index 8ec9e9f..e84f5bf 100644
--- a/pcap2tzsp.c
+++ b/pcap2tzsp.c
@@ -13,11 +13,12 @@
 #include <libgen.h>
 
 /* UDP stuff */
-#include <arpa/inet.h>
-#include <netinet/in.h>
+/*#include <arpa/inet.h>
+#include <netinet/in.h> no longer used */
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <unistd.h>
+#include <netdb.h> /* Name resolution */
 
 /* Packet capture stuff */
 #include <pcap.h>
@@ -28,7 +29,7 @@
 
 /* Option default values (as strings) */
 #define DEFAULT_FILTER "not ( icmp[icmptype]=icmp-unreach or (udp and dst %s and port %s) )"
-#define DEFAULT_HOST "127.0.0.1"
+#define DEFAULT_HOST "localhost"
 #define DEFAULT_PORT "37008"
 #define DEFAULT_SNAPLEN "70"
 
@@ -43,18 +44,20 @@
 #define MIN_BYTES_TO_CAPTURE 16
 #define MAX_BYTES_TO_CAPTURE (1500-20-8-16)
 
-
+/* Max len of a numerical form of host address 39 chars in IPv6 */
+#define NI_MAXHOST_NUMERIC 40
 /*
 TODO List
   * Resolution DNS host -> IP (c'est l'ip qu'il faut dans le filtre et pas le host !!)
   * Implémenter une bwlimit en sortie (ptks/s et/ou bytes/s)
-  * TZSP over IPv6
+  * TZSP over IPv6 (le filter doit avoir le dst qui va bien , pas le nom, l'adresse)
   * getopts -v et --help
   * Licence GPL
 */
 
 /* Functions declaration */
-void capture_loop(char pcap_filter[]); 
+int make_dgram_socket(char host[], char service[], int hint_flags, char **resolved_address);
+void start_capture_loop(char *pcap_filter); 
 void process_packet(u_char *void_args, const struct pcap_pkthdr* pkthdr, const u_char * packet);
 
 /* Custom types definition */
@@ -62,13 +65,9 @@ typedef struct _process_packet_args {
 	/* Types like in libpcap because I don't want to mess around hours */
 	u_int captured_pkt_count;
 	u_int sent_pkt_count;
-	int udp_socket;
-	struct sockaddr_in udp_sockaddr;
+	int socket;
 } process_packet_args_t;
 
-/* Constants */
-const int sockaddr_len=sizeof(struct sockaddr_in);
-
 
 /* Flags from commandline parsing */
 static int opt_verbose;
@@ -182,40 +181,91 @@ int main(int argc, char *argv[]) {
 				j+=sprintf(pcap_filter+j, "%s", argv[i]);
 			}
 		}
-	} else {
-		// Else, use the default filter (skip the TZSP packet flow to host:port)
-		pcap_filter_len = strlen(DEFAULT_FILTER) -4 + strlen(opt_host) + strlen(opt_port) + 1;
-		pcap_filter=calloc(pcap_filter_len+1, sizeof(char));
-		j=sprintf(pcap_filter, DEFAULT_FILTER, opt_host, opt_port);
 	}
-	//printf ("Capture filter will be : '%s' (pcap_filter_len-j==%i)\n", pcap_filter, pcap_filter_len-j);
-
 
 	signal(SIGINT, sig_handler);
 	/* Run the capture loop */
-	capture_loop(pcap_filter);
-
-	free(pcap_filter);
+	start_capture_loop(pcap_filter);
 
 	free(opt_host);
 	free(opt_port);
 	free(opt_snaplen);
 	if (opt_iface!=NULL) free(opt_iface);
+	if (pcap_filter!=NULL) free(pcap_filter);
 
 	return 0;
 }
 
+int make_dgram_socket(char host[], char service[], int hint_flags, char **resolved_address) {
+
+	/* Code taken from Client program example of getaddrinfo(3) manpage */
+
+	struct addrinfo hints;
+	struct addrinfo *result, *rp;
+	char hbuf[NI_MAXHOST_NUMERIC];
+	int sfd, s;
+
+	/* Obtain address(es) matching host/port */
 
-void capture_loop(char pcap_filter[]) { 
+	memset(&hints, 0, sizeof(struct addrinfo));
+	hints.ai_family = AF_UNSPEC;	/* Allow IPv4 or IPv6 */
+	hints.ai_socktype = SOCK_DGRAM;	/* Datagram socket */
+	hints.ai_flags = hint_flags | AI_CANONNAME;
+	hints.ai_protocol = 0;		/* Any protocol */
+
+	s = getaddrinfo(host, service, &hints, &result);
+	if (s != 0) {
+		fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
+		exit(EXIT_FAILURE);
+	}
+
+	/* getaddrinfo() returns a list of address structures.
+	   Try each address until we successfully connect(2).
+	   If socket(2) (or connect(2)) fails, we (close the socket
+	   and) try the next address. */
+
+	for (rp = result; rp != NULL; rp = rp->ai_next) {
+		sfd = socket(rp->ai_family, rp->ai_socktype,
+				rp->ai_protocol);
+		if (sfd == -1)
+			continue;
+
+		if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
+			break;		/* Success */
+
+		close(sfd);
+	}
+
+	if (rp == NULL) {		/* No address succeeded */
+		freeaddrinfo(result);
+		return -1;
+	}
+
+	/* This part was not in the example as is */
+	if ( resolved_address != NULL) {
+		/* If wanted, return numerical form of the choosen host address */
+		if ( getnameinfo(rp->ai_addr, rp->ai_addrlen, hbuf, 
+			NI_MAXHOST_NUMERIC, NULL, 0, NI_NUMERICHOST) == 0 ) {
+			*resolved_address=strdup(hbuf);
+		}
+	}
+
+	freeaddrinfo(result);		/* No longer needed */
+	return sfd;
+}
+
+
+void start_capture_loop(char *pcap_filter) { 
 
 	//Global for signal handling
 	//pcap_t *pcap_handle = NULL; 
+	char *resolved_address=NULL;
 	static char *pcap_device=NULL;
 	char pcap_errbuf[PCAP_ERRBUF_SIZE];
 	struct bpf_program pcap_filter_prog;
 	struct pcap_stat stat;
 	process_packet_args_t process_packet_args;
-	int snaplen;
+	int snaplen, hints_flags, pcap_filter_len, pcap_filter_synthetised=0;
 
 	memset(pcap_errbuf,0,PCAP_ERRBUF_SIZE); 
 	memset(&process_packet_args,0,sizeof(process_packet_args_t)); 
@@ -237,16 +287,15 @@ void capture_loop(char pcap_filter[]) {
 		exit(12);
 	}
 
-	/* Already done : memset((char *) &(process_packet_args.udp_sockaddr), 0, sockaddr_len); */
-	process_packet_args.udp_sockaddr.sin_family = AF_INET;
-	process_packet_args.udp_sockaddr.sin_port = htons(atoi(opt_port));
-	if (inet_aton(opt_host, &(process_packet_args.udp_sockaddr.sin_addr))==0) {
-		fprintf(stderr, "inet_aton : Impossible de parser l'IP %s\n",opt_host);
-		exit(11);
+	/* UDP socket creation */
+	hints_flags=AI_NUMERICSERV | AI_ADDRCONFIG | AI_V4MAPPED;
+	if (opt_verbose) printf("Opening socket for sending TZSP to %s:%s\n", opt_host, opt_port);
+	if ( ( process_packet_args.socket = make_dgram_socket(opt_host, opt_port, hints_flags, &resolved_address) ) == -1 ) {
+		fprintf(stderr, "ERROR : Couldn't make a socket to %s:%s\n", opt_host, opt_port);
+		exit(10);
 	}
-	
 
-	/* Initialisation pcap */
+	/* pcap init */
 	if (opt_verbose) printf("Opening device %s for capturing\n", pcap_device);
 
 	/* Open device in promiscuous mode */ 
@@ -255,12 +304,25 @@ void capture_loop(char pcap_filter[]) {
 		exit(21);
 	}
 
+	if (pcap_filter==NULL) {
+		pcap_filter_synthetised=1;
+		// Synthethise a default filter that skip the TZSP packet flow to host:port
+		pcap_filter_len = strlen(DEFAULT_FILTER) -4 + strlen(resolved_address) + strlen(opt_port) + 1;
+		pcap_filter=calloc(pcap_filter_len, sizeof(char));
+		//XXX pos=snprintf(pcap_filter, pcap_filter_len, DEFAULT_FILTER, resolved_address, opt_port);
+		/*res=*/ (void)sprintf(pcap_filter, DEFAULT_FILTER, resolved_address, opt_port);
+		//printf ("DEBUG : Capture filter will be : '%s' (pcap_filter_len-res==%i)\n", pcap_filter, pcap_filter_len-res);
+	}
+	free(resolved_address);
+
 	if (opt_verbose) printf("Compiling the following capture filter : '%s'\n", pcap_filter);
 	if ( pcap_compile(pcap_handle,&pcap_filter_prog,pcap_filter,1,PCAP_NETMASK_UNKNOWN) == -1 ) {
 		fprintf(stderr,"ERROR : %s\n", pcap_geterr(pcap_handle) );
 		exit(22);
 	}
 
+	if (pcap_filter_synthetised) free(pcap_filter);
+
 	if ( pcap_setfilter(pcap_handle,&pcap_filter_prog) == -1 ) {
 		fprintf(stderr,"ERROR : %s\n", pcap_geterr(pcap_handle) );
 		exit(23);
@@ -268,13 +330,6 @@ void capture_loop(char pcap_filter[]) {
 
 	pcap_freecode(&pcap_filter_prog);
 
-	/* Initialisation socket UDP */
-	process_packet_args.udp_socket=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
-	if (process_packet_args.udp_socket==-1) {
-		perror("socket");
-		exit(10);
-	}
-
 	/* Loop forever & call process_packet() for every received packet */ 
 	if ( pcap_loop(pcap_handle, -1, process_packet, (u_char *)&process_packet_args) == -1) {
 		fprintf(stderr, "ERROR: %s\n", pcap_geterr(pcap_handle) );
@@ -292,7 +347,8 @@ void capture_loop(char pcap_filter[]) {
 		stat.ps_recv, stat.ps_drop);
 
 	pcap_close(pcap_handle);
-	close(process_packet_args.udp_socket);
+	close(process_packet_args.socket);
+	//XXX freeaddrinfo(target_addrinfo);
 }
 
 
@@ -304,12 +360,12 @@ void process_packet(u_char *void_args, const struct pcap_pkthdr* pkthdr, const u
 	static time_t old_tv_sec=0;
 	static u_int old_captured_pkt_count=0;
 
-	int res;
+	int res, tzsp_len;
 	double throughput;
 
-	uint32_t ts; /* In network byte order */
 	//uint32_t pkt_num; /* In network byte order */
-	uint16_t len; /* In network byte order */
+	uint32_t field_ts; /* In network byte order */
+	uint16_t field_len; /* In network byte order */
 	char buf[UDP_SEND_BUFLEN];
 	/* struct timespec ts_reqsleep; For simulation */
 
@@ -332,8 +388,8 @@ void process_packet(u_char *void_args, const struct pcap_pkthdr* pkthdr, const u
 	//TODO : bwlimit HERE (not before, no after)
 
 	/* Variable fields for TZSP packet */
-	ts=htonl((uint32_t) pkthdr->ts.tv_sec); /* TODO : this cast is bullshit ? */
-	len=htons((uint16_t) pkthdr->len);
+	field_ts=htonl((uint32_t) pkthdr->ts.tv_sec); /* TODO : this cast is bullshit ? */
+	field_len=htons((uint16_t) pkthdr->len);
 	//pkt_num=htons((uint32_t) args->captured_pkt_count);
 
 	/* TaZmen Sniffing Protocol (TZSP) packet forging */
@@ -348,7 +404,7 @@ void process_packet(u_char *void_args, const struct pcap_pkthdr* pkthdr, const u
 	buf[5]=0x04; /* Tag length == 4 bytes */
 
 	/* buf[6,7,8,9] Timestamp on 4 bytes (network order) */
-	memcpy(buf+6, &ts, 4);	
+	memcpy(buf+6, &field_ts, 4);	
 
 	/* Wireshark don't dissect that */
 	//buf[10]=0x28; /* Tag type TAG_PACKET_COUNT */
@@ -357,7 +413,7 @@ void process_packet(u_char *void_args, const struct pcap_pkthdr* pkthdr, const u
 
 	buf[10]=0x29; /* Tag type TAG_RX_FRAME_LENGTH */
 	buf[11]=0x02; /* Tag length == 2 bytes */
-	memcpy(buf+12,&len, 2);
+	memcpy(buf+12, &field_len, 2);
 
 	buf[14]=0x00; /* Tag type TAG PADDING (for alignement) */
 	buf[15]=0x01; /* Tag type TAG END */
@@ -367,9 +423,10 @@ void process_packet(u_char *void_args, const struct pcap_pkthdr* pkthdr, const u
 	memcpy(buf+16,packet, pkthdr->caplen);
 
 	/* TZSP packet sending (over the UDP socket) */
-	res=sendto(args->udp_socket, buf, 16+pkthdr->caplen, 0, (struct sockaddr *)&(args->udp_sockaddr), sockaddr_len);
-	if (res==-1) {
-		fprintf(stderr, "sendto() error\n");
+	tzsp_len=16+pkthdr->caplen;
+	res=write(args->socket, buf, tzsp_len);
+	if (res != tzsp_len) {
+		fprintf(stderr, "write() on UDP socket error (written %i of %i bytes)\n", res, tzsp_len);
 	} else {
 		args->sent_pkt_count++;
 	}
-- 
cgit v1.2.3