From dd630f57c65931c3b6c5da8151193d73b2b768bd Mon Sep 17 00:00:00 2001 From: Ludovic Pouzenc Date: Sat, 20 Oct 2012 16:22:14 +0000 Subject: Première version du client TZSP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: file:///var/svn/2012-tzsp/trunk@2 147d2d3d-d0bd-48ea-923a-d90ac20f5906 --- Makefile | 8 ++ pcap2tzsp.c | 304 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ tests.c | 85 +++++++++++++++++ 3 files changed, 397 insertions(+) create mode 100644 Makefile create mode 100644 pcap2tzsp.c create mode 100644 tests.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c9d7637 --- /dev/null +++ b/Makefile @@ -0,0 +1,8 @@ +all : pcap2tzsp + +pcap2tzsp: pcap2tzsp.o + gcc -o pcap2tzsp pcap2tzsp.o -lpcap +pcap2tzsp.o : pcap2tzsp.c + gcc -Wall -c pcap2tzsp.c +clean : + @rm pcap2tzsp.o pcap2tzsp diff --git a/pcap2tzsp.c b/pcap2tzsp.c new file mode 100644 index 0000000..294ec32 --- /dev/null +++ b/pcap2tzsp.c @@ -0,0 +1,304 @@ + +/* Basics */ +#include +#include +#include + +/* Args parsing and basename() for usage */ +#include +#include + +/* UDP stuff */ +#include +#include +#include +#include +#include + +/* Packet capture stuff */ +#include +#include + +#define DEFAULT_FILTER "not ( udp and dst %s and port %s )" +#define DEFAULT_HOST "127.0.0.1" +#define DEFAULT_PORT "37008" +#define DEFAULT_SNAPLEN "64" + +#define UDP_SEND_BUFLEN 1500 +#define MAX_TZSP_PAYLOAD (1500-40-16) +#define MAX_BYTES_TO_CAPTURE (1500-40-16) + + +/* +TODO List + * Corriger bug du filtre par défaut qui capture qd même le traffic TZSP émis + * Utiliser le opt_snaplen réellement + * Resolution DNS host -> IP (c'est l'ip qu'il faut dans le filtre et pas le host !!) + * Stats nombre de packets loupés ? + * Implémenter une bwlimit en sortie (ptks/s et/ou bytes/s) + * Pkt timestamps sur 64bits (quel field prendre ?) + * Comparer les headers envoyés par un mikrotik avec /tool sniffer + * free() de tous les malloc(), calloc() et strdup() + * Graceful stop avec signal() + * Licence GPL +*/ + +/* Functions declaration */ +void capture_loop(char pcap_filter[]); +void process_packet(u_char *void_args, const struct pcap_pkthdr* pkthdr, const u_char * packet); + +/* Custom types definition */ +typedef struct _process_packet_args { + uint64_t pkt_count; + int udp_socket; + struct sockaddr_in udp_sockaddr; +} process_packet_args_t; + +/* Constants */ +const int sockaddr_len=sizeof(struct sockaddr_in); + + +/* Flags from commandline parsing */ +static int opt_verbose; +/* Option arguments from commandline parsing */ +static char *opt_iface=NULL; +static char *opt_host=NULL; +static char *opt_port=NULL; +static char *opt_snaplen=NULL; + + +void usage(char progname[]) { + printf("Usage : %s [--verbose] [--brief] [-i ] [-h ] [-p ] [custom_pcap_filter]\n", progname); + printf("\t : Interface name to capture from (Default : first available interface)\n"); + printf("\t : Host (or IPv4 address) for sending captured packet headers (Default : '%s')\n", DEFAULT_HOST); + printf("\t : Port for sending captured packet headers (Default '%s')\n", DEFAULT_PORT); + printf("\t : libpcap capture filter (Default '%s')\n", DEFAULT_FILTER); + exit(1); +} + +int main(int argc, char *argv[]) { + + /* Command line args parsing */ + int c,i,j,pcap_filter_len; + char *pcap_filter=NULL; + + while (1) { + static struct option long_options[] = { + /* These options set a flag. */ + {"verbose", no_argument, &opt_verbose, 1}, + {"brief", no_argument, &opt_verbose, 0}, + /* These options don't set a flag. + We distinguish them by their indices. */ + {"interface", required_argument, 0, 'i'}, + {"host", required_argument, 0, 'h'}, + {"port", required_argument, 0, 'p'}, + {"snaplen", required_argument, 0, 's'}, + {0, 0, 0, 0} + }; + /* getopt_long stores the option index here. */ + int option_index = 0; + + c = getopt_long(argc, argv, "i:h:p:s:", long_options, &option_index); + + /* Detect the end of the options. */ + if (c == -1) break; + + switch (c) { + case 0: + /* If this option set a flag, do nothing else now. */ + if (long_options[option_index].flag != 0) break; + + //printf ("option %s", long_options[option_index].name); + //if (optarg) printf (" with arg %s", optarg); + //printf ("\n"); + + break; + case 'i': opt_iface= strdup(optarg); break; + case 'h': opt_host= strdup(optarg); break; + case 'p': opt_port= strdup(optarg); break; + case 's': opt_snaplen= strdup(optarg); break; + case '?': + /* getopt_long already printed an error message. */ + usage(basename(argv[0])); + break; + default: + abort(); + } + } + + // Assign default value if no user supplied value + if (opt_host==NULL) opt_host=strdup(DEFAULT_HOST); + if (opt_port==NULL) opt_port=strdup(DEFAULT_PORT); + if (opt_snaplen==NULL) opt_snaplen=strdup(DEFAULT_SNAPLEN); + // No default for opt_iface because will be choosen at runtime + + //if (verbose_flag) puts ("verbose flag is set"); + + /* Construct the pcap_filter */ + pcap_filter_len=0; + if (optind < argc) { + // Any remaining command line arguments is for pcap_filter + for (i=optind; ipkt_count++; + + if (old_tv_sec != pkthdr->ts.tv_sec) { + //printf("DEBUG : throughput=((double) %llu - %llu ) / ( %u - %u )\n", args->pkt_count, old_pkt_count, pkthdr->ts.tv_sec, old_tv_sec); + throughput=((double) args->pkt_count - old_pkt_count ) / (pkthdr->ts.tv_sec - old_tv_sec); + printf("\rPacket Count: %20llu (%8.1f pkt/s)", args->pkt_count, throughput); + fflush(stdout); + old_tv_sec=pkthdr->ts.tv_sec; + old_pkt_count= args->pkt_count; + } + + /* Variable fields for TZSP packet */ + ts=htonl((uint32_t) pkthdr->ts.tv_sec); /* TODO : this cast is bullshit ? */ + len=htons((uint16_t) pkthdr->len); + + /* TaZmen Sniffing Protocol (TZSP) packet forging */ + + //memset((char *) &buf, 0, UDP_SEND_BUFLEN); /* Buffer reset not useful for now */ + buf[0]=0x01; /* Version */ + buf[1]=0x01; /* Type == Packet for transmit */ + buf[2]=0x00; /* Encapsuled protocol (2 bytes) 0x0001 == Ethernet */ + buf[3]=0x01; + + buf[4]=0x0D; /* Tag type == TAG_TIMESTAMP */ + buf[5]=0x04; /* Tag length == 4 bytes */ + + /* buf[6,7,8,9] Timestamp on 4 bytes (network order) */ + memcpy(buf+6, &ts, 4); + + buf[10]=0x29; /* Tag type TAG_RX_FRAME_LENGTH */ + buf[11]=0x02; /* Tag length : 2 bytes */ + memcpy(buf+12,&len, 2); + + buf[14]=0x00; /* Tag type TAG PADDING (for alignement) */ + buf[15]=0x01; /* Tag type TAG END */ + + /* Raw packet copy */ + //TODO : assert that pkthdr->caplen < MAX_TZSP_PAYLOAD + 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"); + } +} + diff --git a/tests.c b/tests.c new file mode 100644 index 0000000..dd6563e --- /dev/null +++ b/tests.c @@ -0,0 +1,85 @@ + + +void diep(char s[], int r) { + perror(s); + exit(r); +} + +void die(char s[], int r) { + fprintf(stderr, "%s() failed\n", s); + exit(r); +} + +#define DEST_IP "127.0.0.1" +#define DEST_PORT 37008 +int send_tzsp_sample_packet() { + const int sockaddr_len=sizeof(struct sockaddr_in); + const char sample_packet[]={ + /*Ether*/ 0xe0,0x91,0xf5,0xa1,0xa3,0xd8,0x00,0x11,0x2f,0xde,0x0d,0xa1,0x08,0x00, + /* IP4 */ 0x45,0x00,0x00,0x3c,0x00,0x00,0x40,0x00,0x40,0x11,0xb4,0x8d,0xc0,0xa8,0x02,0xd2,0xc0,0xa8,0x02,0x01, + /* UDP */ 0xc4,0x89,0x00,0x35,0x00,0x28,0x86,0x5d, + /* DNS */ 0x04,0x59,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x77,0x77,0x77, + 0x06,0x64,0x6f,0x6f,0x64,0x6c,0x65,0x03,0x63,0x6f,0x6d,0x00,0x00,0x01,0x00,0x01 + }; + const int sample_packet_len=sizeof(sample_packet); + struct timeval sample_packet_time; + uint32_t ts; + + int res,len; + int s; /*socket*/ + struct sockaddr_in /*si_me,*/ si_other; + char buf[UDP_SEND_BUFLEN]; + + /* On récupère le timestamp courant pour mettre dans les headers TZSP du paquet capturé d'exemple */ + printf("DEBUG : sizeof(time_t)==%i\n", sizeof(time_t)); + res=gettimeofday(&sample_packet_time,NULL); + if (res==-1) die("gettimeofday",5); + + + /* On prépare le socket UDP */ + s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (s==-1) diep("socket",10); + + memset((char *) &si_other, 0, sockaddr_len); + si_other.sin_family = AF_INET; + si_other.sin_port = htons(DEST_PORT); + res=inet_aton(DEST_IP, &si_other.sin_addr); + if (res==0) die("inet_aton",11); + + /* On forge la trame TZSP */ + + //memset((char *) &buf, 0, UDP_SEND_BUFLEN); + buf[0]=0x01; /* version */ + buf[1]=0x01; /* type == Packet for transmit */ + buf[2]=0x00; /* Encapsuled protocol 0x0001 == Ethernet */ + buf[3]=0x01; + + buf[4]=0x0D; /* Tag type TAG_TIMESTAMP */ + buf[5]=0x04; /* Tag length : 4 bytes */ + + /* buf[6,7,8,9] Timestamp on 4 bytes (network order) */ + ts=htonl((uint32_t) sample_packet_time.tv_sec); /* FIXME : ce cast est une bonne idée ??? */ + memcpy(buf+6, &ts, sizeof(ts)); + + buf[10]=0x29; /* Tag type TAG_RX_FRAME_LENGTH */ + buf[11]=0x02; /* Tag length : 2 bytes */ + len=htons((uint16_t) sample_packet_len); + memcpy(buf+12,&len, sizeof(len)); + + buf[14]=0x00; /* Tag type TAG PADDING (for alignement) */ + buf[15]=0x01; /* Tag type TAG END */ + + /* Raw packet copy */ + //TODO : assert that sample_packet_len < MAX_TZSP_PAYLOAD + memcpy(buf+16,sample_packet, sample_packet_len); + + /* Envoi du paquet UDP (avec comme charge utile le TZSP) */ + res=sendto(s, buf, 16+sample_packet_len, 0, (struct sockaddr *)&si_other, sockaddr_len); + if (res==-1) diep("sendto",12); + + close(s); + + return 0; +} + + -- cgit v1.2.3