-
Nghia NGUYEN committed with nhnghia 3 years ago1 parent 66a476c3
Showing first 29 files as there are too many
-
-
-
-
-
-
-
-
-
docs/smp_workflow.svg
-
-
lib/mmt-dpi_1.7.0.0_a8ad3c2_Linux_x86_64.debBinary file.
-
-
-
-
-
1 + /* 2 + * main_gen_plugin.c 3 + * 4 + * Created on: 26 sept. 2016 5 + * Created by: Huu Nghia NGUYEN <[email protected]> 6 + * 7 + * Parse rules in .xml file, then generate .c file, then compile to a plugin .so file. 8 + */ 9 + 10 + #include <mmt_core.h> 11 + #include "../lib/mmt_lib.h" 12 + #include "../engine/expression.h" 13 + #include "../engine/rule.h" 14 + #include "../engine/gen_code.h" 15 + 16 + #define MAX_STRING_LEN 10000 17 + 18 + int compile( int argc, char** argv ){ 19 + rule_t **rule_list; 20 + size_t rule_count, i; 21 + char c_file[MAX_STRING_LEN]; 22 + char gcc_param[MAX_STRING_LEN]; 23 + 24 + const char* xml_file, *output_file; 25 + char *embedded_functions; 26 + int ret; 27 + 28 + if( argc != 3 && argc != 4){ 29 + fprintf( stderr, "Usage: %s output_file property_file option", argv[0] ); 30 + fprintf( stderr, "\n - output_file : path of file containing result that can be either a .c file or .so file"); 31 + fprintf( stderr, "\n - property_file : path to property file to read"); 32 + fprintf( stderr, "\n - option : "); 33 + fprintf( stderr, "\n + \"-c\" : generate only code c" ); 34 + fprintf( stderr, "\n + otherwise: generate code c, then compile to .so file."); 35 + fprintf( stderr, "\n This option will be transfered to gcc, for example, \"-I /tmp/include -lmath\""); 36 + fprintf( stderr, "\n"); 37 + return 1; 38 + } 39 + xml_file = argv[2]; 40 + output_file = argv[1]; 41 + 42 + //check output file 43 + if( argc == 4 && strcmp( argv[3], "-c") == 0 ){ 44 + if( !str_end_with( output_file, ".c" ) ){ 45 + log_write( LOG_ERR, "output_file must be end with .c"); 46 + return 1; 47 + } 48 + 49 + snprintf(c_file, sizeof( c_file), "%s", output_file ); 50 + }else{ 51 + if( !str_end_with( output_file, ".so" ) ){ 52 + log_write( LOG_ERR, "output_file must be end with .so"); 53 + return 1; 54 + } 55 + snprintf(c_file, sizeof( c_file), "%s.c", output_file ); 56 + } 57 + 58 + //init mmt_dpi extraction to load list of avaiable protocols 59 + init_extraction(); 60 + 61 + //read rule from .xml file 62 + rule_count = read_rules_from_file( xml_file, &rule_list, &embedded_functions ); 63 + 64 + //generate rules to .c code 65 + generate_fsm( c_file, rule_list, rule_count, embedded_functions ); 66 + 67 + if( argc == 4 && strcmp( argv[3], "-c") == 0 ){ 68 + log_write( LOG_INFO, "Encoded %zu rules from \"%s\" to \"%s\"", rule_count, xml_file, c_file ); 69 + log_write( LOG_INFO, "To compile, use: /usr/bin/gcc -fPIC -shared %s -o output.so", c_file ); 70 + }else{ 71 + //compile code file 72 + if( argc == 3 ) 73 + ret = compile_gen_code(output_file, c_file,"./src/lib -I./src/engine -I ./src/dpi -I/opt/mmt/dpi/include" ); 74 + else{ 75 + snprintf( gcc_param, sizeof( gcc_param), "./src/lib -I./src/engine -I ./src/dpi -I/opt/mmt/dpi/include %s", argv[3] ); 76 + ret = compile_gen_code(output_file, c_file, gcc_param ); 77 + } 78 + 79 + //DEBUG( "ret = %d", ret ); 80 + if( ret == 0 ){ 81 + log_write( LOG_INFO, "Encoded %zu rules from \"%s\" to \"%s\"", rule_count, xml_file, output_file ); 82 + 83 + #ifndef DEBUG_MODE 84 + //delete .c file 85 + remove( c_file ); 86 + #endif 87 + }else 88 + log_write( LOG_ERR, "Cannot encode rule \"%s\". Check options.", xml_file ); 89 + } 90 + 91 + //free each rule 92 + for( i=0; i<rule_count; i++ ) 93 + free_a_rule( rule_list[i], true); 94 + 95 + mmt_mem_free( rule_list ); 96 + mmt_mem_free( embedded_functions ); 97 + close_extraction();// close mmt_dpi 98 + return 0; 99 + } 100 + -
1 + /* 2 + * main_plugin_info.c 3 + * 4 + * Created on: Oct 10, 2016 5 + * Created by: Huu Nghia NGUYEN <[email protected]> 6 + * 7 + * Get information of rules encoded in a binary file (.so) 8 + */ 9 + #include "../lib/base.h" 10 + #include "../lib/mmt_log.h" 11 + #include "../lib/mmt_alloc.h" 12 + #include "../engine/plugins_engine.h" 13 + #include <dirent.h> 14 + #include <dlfcn.h> 15 + 16 + int info( int argc, char** argv ){ 17 + const rule_info_t *const*rules_arr; 18 + size_t i, j, n; 19 + struct tm tm; 20 + 21 + ASSERT( argc <= 2, "Usage: %s [lib_file.so]", argv[0] ); 22 + 23 + if( argc == 1) 24 + //load all plugins from default folder: 25 + // - /opt/mmt/engine/rules 26 + // - ./rules 27 + n = load_mmt_sec_rules( &rules_arr ); 28 + else{ 29 + if( strcmp(argv[1], "-h") == 0 ){ 30 + fprintf( stderr, "Usage: %s [lib_file.so]", argv[0] ); 31 + fprintf( stderr, "\n" ); 32 + return 0; 33 + } 34 + //load only one plugin given by argv[1] 35 + n = load_mmt_sec_rule( &rules_arr, argv[1] ); 36 + } 37 + 38 + //print rules' information 39 + printf("Found %zu rule%s", n, n<=1? ".": "s." ); 40 + 41 + for( i=0; i<n; i++ ){ 42 + printf("\n%zu - Rule id: %d", (i+1), rules_arr[i]->id ); 43 + printf("\n\t- type : %s", rules_arr[i]->type_string ); 44 + printf("\n\t- events_count : %d", rules_arr[i]->events_count ); 45 + printf("\n\t- variables_count : %d", rules_arr[i]->proto_atts_count ); 46 + printf("\n\t- variables : " ); 47 + for( j=0; j<rules_arr[i]->proto_atts_count; j++ ) 48 + printf( "%s%s.%s (%d.%d)", 49 + j==0? "":", ", 50 + rules_arr[i]->proto_atts[j].proto, rules_arr[i]->proto_atts[j].att, 51 + rules_arr[i]->proto_atts[j].proto_id, rules_arr[i]->proto_atts[j].att_id); 52 + 53 + printf("\n\t- description : %s", rules_arr[i]->description ); 54 + printf("\n\t- if_satisfied : %p", rules_arr[i]->if_satisfied ); 55 + //printf("\n\t- create_instance : %pF", rules_arr[i]->create_instance ); 56 + //printf("\n\t- hash_message : %pF", rules_arr[i]->hash_message ); 57 + tm = *localtime(& rules_arr[i]->version->created_date ); 58 + printf("\n\t- version : %s (%s - %d-%d-%d %d:%d:%d), dpi version %s", rules_arr[i]->version->number, 59 + rules_arr[i]->version->hash, 60 + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, 61 + rules_arr[i]->version->dpi ); 62 + } 63 + printf("\n"); 64 + return 0; 65 + } 66 + -
1 + /* 2 + * main_sec_standalone.c 3 + * 4 + * Created on: 18 oct. 2016 5 + * Created by: Huu Nghia NGUYEN <[email protected]> 6 + * 7 + * Standalone mmt-engine application. 8 + * This application can analyze (1) real-time traffic by monitoring a NIC or (2) 9 + * traffic saved in a pcap file. The verdicts will be printed to the current screen. 10 + */ 11 + #include <stdio.h> 12 + #include <stdlib.h> 13 + #include <pcap.h> 14 + #include <string.h> 15 + #include <unistd.h> 16 + #include <sys/types.h> 17 + #include <sys/stat.h> 18 + #include <sys/time.h> 19 + #include <fcntl.h> 20 + #include <getopt.h> 21 + #include <signal.h> 22 + #include <errno.h> 23 + 24 + #include "../lib/mmt_lib.h" 25 + #include "../engine/dpi_message_t.h" 26 + #include "../engine/mmt_security.h" 27 + #include "../engine/verdict_printer.h" 28 + #include "../engine/rule.h" 29 + #include "../forward/forward_packet.h" 30 + 31 + typedef struct context_struct{ 32 + mmt_sec_handler_t *sec_handler; 33 + config_t *config; 34 + forward_packet_context_t *forward_context; 35 + }context_t; 36 + 37 + //Statistic 38 + static size_t total_received_reports = 0; 39 + static size_t total_received_packets = 0; 40 + static size_t proto_atts_count = 0; 41 + proto_attribute_t const *const*proto_atts = NULL; 42 + 43 + static pcap_t *pcap; 44 + 45 + //handler of MMT-SEC 46 + static mmt_sec_handler_t *sec_handler = NULL; 47 + //handler of MMT-DPI 48 + static mmt_handler_t *mmt_dpi_handler = NULL; 49 + static config_t *config = NULL; 50 + 51 + #define DEFAULT_CONFIG_FILE "./mmt-5greplay.conf" 52 + void usage(const char * prg_name) { 53 + printf("%s [<Option>]\n", prg_name); 54 + printf("Option:\n"); 55 + printf("\t-v : Print version information, then exits.\n"); 56 + printf("\t-c <config file> : Gives the path to the configuration file (default: %s).\n", 57 + DEFAULT_CONFIG_FILE); 58 + printf("\t-t <trace file> : Gives the trace file for offline analyse.\n"); 59 + printf("\t-i <interface> : Gives the interface name for live traffic analysis.\n"); 60 + printf("\t-X attr=value : Override configuration attributes.\n"); 61 + printf("\t For example \"-X output.enable=true -Xoutput.output-dir=/tmp/\" will enable output to file and change output directory to /tmp.\n"); 62 + printf("\t This parameter can appear several times.\n"); 63 + printf("\t-x : Prints list of configuration attributes being able to be used with -X, then exits.\n"); 64 + printf("\t-h : Prints this help, then exits.\n"); 65 + } 66 + 67 + /** 68 + * Free a string pointer before clone data to it 69 + */ 70 + static inline void _override_string_conf( char **conf, const char*new_val ){ 71 + mmt_mem_free( *conf ); 72 + *conf = mmt_strdup( new_val ); 73 + } 74 + 75 + 76 + static inline config_t *_parse_options(int argc, char ** argv ) { 77 + int opt; 78 + const char *config_file = DEFAULT_CONFIG_FILE; 79 + config_t *conf = NULL; 80 + const char *options = "t:i:c:X:xh"; 81 + 82 + //to get config 83 + extern char *optarg; 84 + extern int optind; 85 + 86 + char *string_att, *string_val; 87 + 88 + bool is_user_gives_conf_file = false; 89 + 90 + while ((opt = getopt(argc, argv, options)) != EOF) { 91 + switch (opt) { 92 + case 'c': 93 + config_file = optarg; 94 + break; 95 + case 'x': 96 + conf_print_identities_list(); 97 + exit( EXIT_SUCCESS ); 98 + break; 99 + case 'X': 100 + case 't': 101 + case 'i': 102 + break; 103 + case 'h': 104 + default: 105 + usage(argv[0]); 106 + exit( EXIT_SUCCESS ); 107 + 108 + } 109 + } 110 + 111 + conf = conf_load_from_file( config_file ); 112 + if( conf == NULL ){ 113 + log_write_dual(LOG_ERR, "Cannot read configuration file from \"%s\"\n", config_file ); 114 + exit( EXIT_FAILURE ); 115 + } 116 + 117 + //reset getopt function 118 + optind = 0; 119 + 120 + //override some options inside the configuration 121 + while ((opt = getopt(argc, argv, options)) != EOF) { 122 + switch (opt) { 123 + //trace file 124 + case 't': 125 + _override_string_conf( &conf->input->input_source, optarg ); 126 + //switch to offline mode 127 + conf->input->input_mode = OFFLINE_ANALYSIS; 128 + break; 129 + //input interface 130 + case 'i': 131 + _override_string_conf( &conf->input->input_source, optarg ); 132 + //switch to online mode 133 + conf->input->input_mode = ONLINE_ANALYSIS; 134 + break; 135 + 136 + case 'X': 137 + //example: -X file-output.enable=true 138 + //we will separate the phrase "file-output.enable=true" into 2 139 + // to expect: 140 + // string_att = "file-output.enable" 141 + // string_val = "true" 142 + string_att = optarg; 143 + string_val = optarg; 144 + while( *string_val != '\0' ){ 145 + //separated by = character 146 + if( *string_val == '=' ){ 147 + *string_val = '\0'; //NULL ended for attribute 148 + //jump to the part after = character 149 + string_val ++; 150 + break; 151 + } 152 + string_val ++; 153 + } 154 + //not found = character 155 + if( *string_val == '\0' ) 156 + log_write( LOG_WARNING, "Input parameter '%s' is not well-formatted (must be in format parameter=value). Ignored it.", string_att ); 157 + 158 + switch( conf_override_element(conf, string_att, string_val) ){ 159 + case 0: 160 + //log_write( LOG_INFO, "Overridden value of configuration parameter '%s' by '%s'", string_att, string_val ); 161 + break; 162 + case -1: 163 + log_write_dual(LOG_ERR, "Unknown parameter identity %s\n", string_att ); 164 + exit( EXIT_FAILURE ); 165 + } 166 + 167 + } 168 + } 169 + 170 + if( conf_validate(conf) ){ 171 + abort(); 172 + } 173 + 174 + return conf; 175 + } 176 + 177 + 178 + /** 179 + * A function to be called when a rule is validated 180 + * Note: this function can be called from one or many different threads, 181 + * ==> be carefully when using static or shared variables inside it 182 + */ 183 + static void _print_security_verdict( 184 + const rule_info_t *rule, //rule being validated 185 + enum verdict_type verdict, //DETECTED, NOT_RESPECTED 186 + uint64_t timestamp, //moment (by time) the rule is validated 187 + uint64_t counter, //moment (by order of packet) the rule is validated 188 + const mmt_array_t * trace, //historic messages that validates the rule 189 + void *user_data //#user-data being given in register_security 190 + ){ 191 + forward_packet_context_t *context = (forward_packet_context_t *) user_data; 192 + char message[10000]; 193 + size_t len; 194 + 195 + //Special processing when the rule is FORWARD 196 + if( rule->type_id == RULE_TYPE_FORWARD && context ){ 197 + //mark that there exists a FORWARD rule that is satisfied, 198 + // thus do not need to peform default action (forward/drop) on the current packet 199 + // because this action is decided by user in the satisfied rule 200 + forward_packet_mark_being_satisfied( context ); 201 + } 202 + 203 + if( config->output->is_enable ){ 204 + const char *exec_trace = mmt_convert_execution_trace_to_json_string( trace, rule ); 205 + len = snprintf( message, sizeof( message ), "%ld,%"PRIu32",\"%s\",\"%s\",\"%s\",%s", 206 + time( NULL ), 207 + rule->id, 208 + verdict_type_string[verdict], 209 + rule->type_string, 210 + (config->output->is_report_description? rule->description : ""), 211 + exec_trace ); 212 + message[len] = '\0'; 213 + verdict_printer_send( message ); 214 + } 215 + } 216 + 217 + /** 218 + * Convert a pcap packet to a message being understandable by mmt-engine. 219 + * The function returns NULL if the packet contains no interested information. 220 + * Otherwise it creates a new memory segment to store the result message. One need 221 + * to use #free_message_t to free the message. 222 + */ 223 + static inline message_t* _get_packet_info( const ipacket_t *pkt ){ 224 + int i; 225 + void *data; 226 + int type; 227 + 228 + message_t *msg = create_message_t(); 229 + msg->timestamp = mmt_sec_encode_timeval( &pkt->p_hdr->ts ); 230 + msg->counter = pkt->packet_id; 231 + msg->flow_id = get_session_id_from_packet( pkt ); 232 + //get a list of proto/attributes being used by mmt-engine 233 + for( i=0; i<proto_atts_count; i++ ) 234 + dpi_message_set_data( pkt, proto_atts[i]->dpi_type, msg, proto_atts[i]->proto_id, proto_atts[i]->att_id ); 235 + 236 + if( likely( msg->elements_count )) 237 + return msg; 238 + 239 + //need to free #msg when the packet contains no-interested information 240 + free_message_t( msg ); 241 + return NULL; 242 + } 243 + 244 + 245 + /** 246 + * Register an attribute of a protocol to MMT-DPI. They are given by their IDs 247 + * @param proto_id 248 + * @param att_id 249 + * @param verbose 250 + * @return true if it is registered successfully 251 + * false if it has been registered or it can not be registered 252 + */ 253 + static inline bool _register_proto_att_to_mmt_dpi( uint32_t proto_id, uint32_t att_id, bool verbose ){ 254 + //is it registered? 255 + if( is_registered_attribute( mmt_dpi_handler, proto_id, att_id )) 256 + return 0; 257 + if( register_extraction_attribute( mmt_dpi_handler, proto_id, att_id ) ){ 258 + DEBUG( "Registered attribute to extract: %"PRIu32".%"PRIu32, proto_id, att_id ); 259 + return 1; 260 + } 261 + return 0; 262 + } 263 + 264 + /** 265 + * update of list of unique att_protos and register them to MMT-DPI 266 + * @return number of att_protos being registered 267 + */ 268 + static inline size_t _update_and_register_protocols_attributes_to_extract( bool verbose ){ 269 + int i; 270 + size_t ret = 0; 271 + proto_atts_count = mmt_sec_get_unique_protocol_attributes( & proto_atts ); 272 + 273 + for( i=0; i<proto_atts_count; i++ ){ 274 + 275 + ret += _register_proto_att_to_mmt_dpi( proto_atts[i]->proto_id, proto_atts[i]->att_id, verbose ); 276 + 277 + //tcp.p_payload => need payload_len 278 + if( proto_atts[i]->proto_id == PROTO_TCP && proto_atts[i]->att_id == PROTO_PAYLOAD ){ 279 + //tcp.payload_len 280 + ret += _register_proto_att_to_mmt_dpi( PROTO_TCP, TCP_PAYLOAD_LEN, verbose ); 281 + }else if( proto_atts[i]->proto_id == PROTO_IP && proto_atts[i]->att_id == IP_OPTS){ 282 + ret += _register_proto_att_to_mmt_dpi( PROTO_IP, IP_HEADER_LEN, verbose ); 283 + } 284 + } 285 + return ret; 286 + } 287 + 288 + #ifdef MODULE_ADD_OR_RM_RULES_RUNTIME 289 + static inline void _print_add_rm_rules_instruction(){ 290 + log_write( LOG_INFO,"During runtime, user can add or remove some rules using the following commands:\n%s\n%s", 291 + " - to add new rules: add rule_mask, for example: add (1:1-3)(2:4-6)", 292 + " - to remove existing rules: rm rule_range, for example: rm 1-3"); 293 + } 294 + 295 + /** 296 + * Add rules to process and update DPI to extract the corresponding protos/atts 297 + * @param rules_mask 298 + * @return number of rules being added 299 + */ 300 + static inline size_t _add_rules( const char* rules_mask ){ 301 + size_t ret = mmt_sec_add_rules(rules_mask); 302 + //no new rules being added 303 + if( ret == 0 ) 304 + return ret; 305 + 306 + //register the new proto_atts if need 307 + size_t count = _update_and_register_protocols_attributes_to_extract( false ); 308 + DEBUG( "Registered %zu new proto_atts", count ); 309 + 310 + return ret; 311 + } 312 + 313 + 314 + static inline size_t _remove_rules( size_t rules_count, const uint32_t *rules_ids_array ){ 315 + proto_attribute_t const*const* old_proto_atts; 316 + proto_attribute_t const*const* new_proto_atts; 317 + size_t old_proto_atts_count, new_proto_atts_count; 318 + size_t i, j; 319 + 320 + old_proto_atts_count = mmt_sec_get_unique_protocol_attributes( & old_proto_atts ); 321 + 322 + size_t ret = mmt_sec_remove_rules( rules_count, rules_ids_array ); 323 + //no rules being removed ??? 324 + if( ret == 0 ) 325 + return ret; 326 + 327 + new_proto_atts_count = mmt_sec_get_unique_protocol_attributes( & new_proto_atts ); 328 + 329 + //set of proto_atts does not change after removing some rules => donot need to unregister any proto_att 330 + if( old_proto_atts_count == new_proto_atts_count ) 331 + return ret; 332 + 333 + //unregister the att_protos of rules being removed 334 + //for each old protol_att 335 + for( i=0; i<old_proto_atts_count; i++ ){ 336 + for( j=0; j<new_proto_atts_count; j++ ) 337 + if( old_proto_atts[i]->proto_id == new_proto_atts[i]->proto_id && 338 + old_proto_atts[i]->att_id == new_proto_atts[i]->att_id ) 339 + break; //this proto_att is still needed 340 + // 341 + if( j <= new_proto_atts_count ) 342 + continue; 343 + //unregister this old proto_att 344 + unregister_extraction_attribute(mmt_dpi_handler, old_proto_atts[i]->proto_id, old_proto_atts[i]->att_id ); 345 + DEBUG("Unregistered from mmt-dpi: %"PRIu32".%"PRIu32" (%s,%s)", 346 + old_proto_atts[i]->proto_id, old_proto_atts[i]->att_id, 347 + old_proto_atts[i]->proto, old_proto_atts[i]->att ); 348 + } 349 + return ret; 350 + } 351 + 352 + /** 353 + * This has to be called before any stdin input function. 354 + * When I used std::cin before using this function, it never returned true again. 355 + * @return true if user press some keys ended by Enter 356 + */ 357 + static inline bool _is_user_press_keys(){ 358 + struct timeval tv; 359 + fd_set fds; 360 + tv.tv_sec = 0; 361 + tv.tv_usec = 0; 362 + FD_ZERO(&fds); 363 + FD_SET(STDIN_FILENO, &fds); //add stdin to fsd, STDIN_FILENO is 0 364 + select(STDIN_FILENO+1, &fds, NULL, NULL, &tv); 365 + return ( FD_ISSET(STDIN_FILENO, &fds) != 0 ); 366 + } 367 + 368 + void _add_or_remove_rules_if_need(){ 369 + const int len = 1000; 370 + 371 + char buffer[ 1000 ], *c; 372 + size_t count; 373 + uint32_t *rules_id_to_rm_set; 374 + //if user does not press any keys 375 + if( _is_user_press_keys() == false ) 376 + return; 377 + 378 + //get user's string 379 + if( !fgets( buffer, len, stdin) ) 380 + return; 381 + 382 + //as fgets add EOF or EOL at the end of buffer => we need to remove these special characters 383 + c = buffer; 384 + while( *c != '\0' ){ 385 + if( *c == EOF || *c == '\n' ){ 386 + *c = '\0'; 387 + break; 388 + } 389 + c++; 390 + } 391 + 392 + 393 + if( buffer[0] == '\0' ) 394 + return; 395 + 396 + //add xxxx 397 + if( buffer[0] == 'a' && buffer[1] == 'd' && buffer[2] == 'd' && buffer[3] == ' ' ){ 398 + log_write( LOG_INFO, "Added totally %zu rule(s)", _add_rules( &buffer[4] )); 399 + return; 400 + }else //rm xxx 401 + if( buffer[0] == 'r' && buffer[1] == 'm' && buffer[2] == ' ' ){ 402 + count = expand_number_range( &buffer[3], &rules_id_to_rm_set ); 403 + if( count > 0 ){ 404 + count = _remove_rules( count, rules_id_to_rm_set); 405 + } 406 + log_write( LOG_INFO, "Removed totally %zu rule(s)", count); 407 + 408 + //free memory allocated by expand_number_range 409 + mmt_mem_free( rules_id_to_rm_set ); 410 + return; 411 + } 412 + 413 + log_write( LOG_WARNING,"Unknown command \"%s\"", buffer ); 414 + _print_add_rm_rules_instruction(); 415 + } 416 + /* Returns an integer in the range [1, n]. 417 + * 418 + * Uses rand(), and so is affected-by/affects the same seed. 419 + */ 420 + static inline int _rand_int(unsigned int n) { 421 + if ((n - 1) == RAND_MAX) { 422 + return rand(); 423 + } else { 424 + // Chop off all of the values that would cause skew... 425 + long end = RAND_MAX / n; // truncate skew 426 + end *= n; 427 + 428 + // ... and ignore results from rand() that fall above that limit. 429 + // (Worst case the loop condition should succeed 50% of the time, 430 + // so we can expect to bail out of this loop pretty quickly.) 431 + int r; 432 + while ((r = rand()) >= end); 433 + 434 + return r % n + 1; 435 + } 436 + } 437 + 438 + static inline bool _rand_bool(){ 439 + return (_rand_int( 10 ) > 5); 440 + } 441 + #else 442 + #define _add_or_remove_rules_if_need() 443 + #define _print_add_rm_rules_instruction() 444 + #endif 445 + 446 + 447 + 448 + /** 449 + * This function is called by mmt-dpi for each incoming packet containing registered proto/att. 450 + * It gets interested information from the #ipkacet to a message then sends the 451 + * message to mmt-engine. 452 + */ 453 + static int _packet_handle( const ipacket_t *ipacket, void *args ) { 454 + uint32_t rm_rules_arr[50]; 455 + char string[500], *ch = string; 456 + int i; 457 + 458 + context_t *context = (context_t *) args; 459 + MUST_NOT_OCCUR( context == NULL, "args parameter must not be NULL"); //this must not happen 460 + 461 + if( context->config->forward->is_enable ) 462 + forward_packet_on_receiving_packet_before_rule_processing( ipacket, context->forward_context ); 463 + 464 + uint64_t flow_id = get_session_id_from_packet( ipacket ); 465 + 466 + message_t *msg = _get_packet_info( ipacket ); 467 + 468 + total_received_packets ++; 469 + 470 + //if there is no interested information 471 + //TODO: to check if we still need to send timestamp/counter to mmt-sec? 472 + if( unlikely( msg == NULL )) 473 + return 1; 474 + 475 + mmt_sec_process( context->sec_handler, msg ); 476 + 477 + //TODO: remve this block 478 + //#ifdef MODULE_ADD_OR_RM_RULES_RUNTIME 479 + // if( total_received_reports == 1000 ){ 480 + // DEBUG("Add %zu rules", _add_rules("(1:33,32,34)")); 481 + // //need to add/rm or not? 482 + // if( _rand_bool() ){ 483 + // printf("\n%zu\n", total_received_reports ); 484 + // //add or rm rules? 485 + // if( _rand_bool() ){ 486 + // //rm random rules ID 487 + // int nb_rules_to_rm = _rand_int( 5 ); 488 + // for( i=0; i<nb_rules_to_rm; i++ ) 489 + // rm_rules_arr[i] = _rand_int( 50 ); 490 + // mmt_sec_remove_rules( nb_rules_to_rm, rm_rules_arr ); 491 + // }else{ 492 + // //add 493 + // int nb_rules_to_add = _rand_int( 5 ); 494 + // ch = string; 495 + // ch += sprintf(string, "(%d:", _rand_int(9) ); 496 + // for( i=0; i<nb_rules_to_add; i++ ) 497 + // ch += sprintf(ch, "%d,", _rand_int( 50 ) ); 498 + // *ch = '\0'; 499 + // *(ch - 1) = ')'; 500 + // 501 + // _add_rules( string ); 502 + // 503 + // } 504 + // } 505 + // } 506 + //#endif 507 + 508 + total_received_reports ++; 509 + 510 + return 0; 511 + } 512 + 513 + void live_capture_callback( u_char *user, const struct pcap_pkthdr *p_pkthdr, const u_char *data ){ 514 + mmt_handler_t *mmt = (mmt_handler_t*)user; 515 + struct pkthdr header; 516 + 517 + //allow user to add/rm rules 518 + _add_or_remove_rules_if_need(); 519 + 520 + header.ts = p_pkthdr->ts; 521 + header.caplen = p_pkthdr->caplen; 522 + header.len = p_pkthdr->len; 523 + if (!packet_process( mmt, &header, data )) { 524 + fprintf(stderr, "Packet data extraction failure.\n"); 525 + } 526 + //printf("."); fflush( stdout ); 527 + } 528 + 529 + 530 + static inline void termination(){ 531 + struct pcap_stat pcs; /* packet capture filter stats */ 532 + size_t alerts_count; 533 + 534 + pcap_breakloop( pcap ); 535 + 536 + alerts_count = mmt_sec_unregister( sec_handler ); 537 + 538 + if (pcap_stats(pcap, &pcs) < 0) { 539 + // (void) fprintf(stderr, "pcap_stats: %s\n", pcap_geterr( pcap ));//Statistics aren't available from savefiles 540 + }else{ 541 + (void) fprintf(stderr, "\n%12d packets received by filter\n", pcs.ps_recv); 542 + (void) fprintf(stderr, "%12d packets dropped by interface\n", pcs.ps_ifdrop); 543 + (void) fprintf(stderr, "%12d packets dropped by kernel (%3.2f%%)\n", pcs.ps_drop, pcs.ps_drop * 100.0 / pcs.ps_recv); 544 + fflush(stderr); 545 + } 546 + 547 + fprintf(stderr, "%12zu packets received\n", total_received_packets ); 548 + fprintf(stderr, "%12zu messages received\n", total_received_reports ); 549 + fprintf(stderr, "%12zu alerts generated\n", alerts_count ); 550 + 551 + pcap_close( pcap ); 552 + 553 + if( config->output->is_enable ) 554 + verdict_printer_free(); 555 + 556 + mmt_sec_close(); // close mmt_security 557 + close_extraction();// close mmt_dpi 558 + conf_release( config ); 559 + } 560 + 561 + void signal_handler_seg(int signal_type) { 562 + log_write( LOG_ERR, "Interrupted by signal %d", signal_type ); 563 + log_execution_trace(); 564 + exit( signal_type ); 565 + } 566 + 567 + void signal_handler(int signal_type) { 568 + static volatile int times_counter = 0; 569 + 570 + if( times_counter >= 1 ) exit( signal_type ); 571 + times_counter ++; 572 + 573 + log_write( LOG_ERR, "Interrupted by signal %d", signal_type ); 574 + 575 + if( signal_type == SIGINT ){ 576 + log_write( LOG_ERR,"Releasing resource ... (press Ctrl+c again to exit immediately)"); 577 + signal(SIGINT, signal_handler); 578 + } 579 + exit( signal_type ); 580 + } 581 + 582 + 583 + 584 + void register_signals(){ 585 + #ifndef DEBUG_MODE 586 + signal(SIGSEGV, signal_handler_seg ); 587 + #endif 588 + signal(SIGINT, signal_handler); 589 + signal(SIGTERM, signal_handler); 590 + signal(SIGABRT, signal_handler); 591 + } 592 + 593 + int replay(int argc, char** argv) { 594 + char mmt_errbuf[1024]; 595 + 596 + const unsigned char *data; 597 + struct pcap_pkthdr p_pkthdr; 598 + char errbuf[1024]; 599 + int ret; 600 + struct pkthdr header; 601 + size_t i, j, size; 602 + uint16_t *rules_id_filter = NULL; 603 + context_t context; 604 + 605 + register_signals(); 606 + 607 + config = _parse_options(argc, argv); 608 + 609 + ret = mmt_sec_init( config->engine->excluded_rules ); 610 + if( ret != 0 ){ 611 + conf_release( config ); 612 + exit( EXIT_FAILURE ); 613 + } 614 + 615 + if( config->output->is_enable ) 616 + verdict_printer_init( config->output->output_dir, config->output->sample_interval ); 617 + 618 + //init mmt_dpi extraction 619 + init_extraction(); 620 + 621 + //Initialize dpi handler 622 + mmt_dpi_handler = mmt_init_handler(DLT_EN10MB, 0, mmt_errbuf); 623 + if (!mmt_dpi_handler) { /* pcap error ? */ 624 + fprintf(stderr, "MMT handler init failed for the following reason: %s\n", mmt_errbuf); 625 + return EXIT_FAILURE; 626 + } 627 + 628 + forward_packet_context_t *forward_context = forward_packet_alloc( config, mmt_dpi_handler ); 629 + 630 + sec_handler = mmt_sec_register( config->engine->threads_size, 631 + NULL, //core_id is NULL to allow OS arbitrarily arranging security threads on logical cores 632 + config->engine->rules_mask, 633 + true, 634 + _print_security_verdict, 635 + forward_context ); 636 + 637 + _update_and_register_protocols_attributes_to_extract( true ); 638 + 639 + context.config = config; 640 + context.forward_context = forward_context; 641 + context.sec_handler = sec_handler; 642 + 643 + //Register a packet handler, it will be called for every processed packet 644 + register_packet_handler(mmt_dpi_handler, 1, _packet_handle, &context ); 645 + 646 + _print_add_rm_rules_instruction(); 647 + 648 + if( config->input->input_mode == OFFLINE_ANALYSIS ) { 649 + log_write( LOG_INFO,"Analyzing pcap file %s", config->input->input_source ); 650 + pcap = pcap_open_offline(config->input->input_source, errbuf); // open offline trace 651 + if (!pcap) { /* pcap error ? */ 652 + ABORT("pcap_open failed for the following reason: %s\n", errbuf); 653 + } 654 + 655 + while ((data = pcap_next(pcap, &p_pkthdr)) ) { 656 + //allow user to add/rm rules 657 + _add_or_remove_rules_if_need(); 658 + 659 + 660 + header.ts = p_pkthdr.ts; 661 + header.caplen = p_pkthdr.caplen; 662 + header.len = p_pkthdr.len; 663 + if (!packet_process(mmt_dpi_handler, &header, data)) 664 + log_write( LOG_ERR, "Packet data extraction failure.\n"); 665 + } 666 + 667 + } else { 668 + log_write( LOG_INFO,"Listening on interface %s", config->input->input_source ); 669 + 670 + pcap = pcap_create( config->input->input_source, errbuf); 671 + if (pcap == NULL) 672 + ABORT("Couldn't open device %s\n", errbuf); 673 + 674 + pcap_set_snaplen(pcap, config->input->snap_len); 675 + pcap_set_promisc(pcap, 1); 676 + pcap_set_timeout(pcap, 0); 677 + pcap_set_buffer_size(pcap, 100*1000*1000); 678 + pcap_activate(pcap); 679 + 680 + (void)pcap_loop( pcap, -1, &live_capture_callback, (u_char*)mmt_dpi_handler ); 681 + } 682 + 683 + termination(); 684 + forward_packet_release(forward_context); 685 + 686 + return EXIT_SUCCESS; 687 + } 688 + 689 + 690 + /** 691 + * Public API 692 + */ 693 + uint32_t conf_get_number_value( config_identity_t id ){ 694 + switch( id ){ 695 + case CONF_ATT__ENGINE__MAX_INSTANCES: 696 + return config->engine->max_instances; 697 + case CONF_ATT__MEMPOOL__MAX_BYTES: 698 + return config->mempool->max_bytes; 699 + case CONF_ATT__MEMPOOL__MAX_ELEMENTS: 700 + return config->mempool->max_elements; 701 + case CONF_ATT__MEMPOOL__MAX_MESSAGE_SIZE: 702 + return config->mempool->max_message_size; 703 + case CONF_ATT__MEMPOOL__SMP_RING_SIZE: 704 + return config->mempool->smp_ring_size; 705 + default: 706 + ABORT("Does not support yet the config identity %d\n", id); 707 + } 708 + return 0; 709 + } 710 + -
-
-
-
-
-
-
1 + /* 2 + * dpi_message_t.h 3 + * 4 + * Bridging the gap between mmt-dpi data and mmt-engine message 5 + * 6 + * Created on: Mar 24, 2017 7 + * Created by: Huu Nghia NGUYEN <[email protected]> 8 + */ 9 + 10 + #ifndef SRC_LIB_DPI_MESSAGE_T_H_ 11 + #define SRC_LIB_DPI_MESSAGE_T_H_ 12 + 13 + 14 + #include <mmt_core.h> 15 + #include <tcpip/mmt_tcpip.h> 16 + 17 + #include "message_t.h" 18 + 19 + #ifndef ftp_command_struct 20 + /** 21 + * FTP command structure: CMD PARAMETER 22 + */ 23 + typedef struct ftp_command_struct{ 24 + uint16_t cmd; 25 + char *str_cmd; 26 + char *param; 27 + }ftp_command_t; 28 + 29 + /** 30 + * FTP response structure 31 + */ 32 + typedef struct ftp_response_struct{ 33 + uint16_t code; 34 + char *str_code; 35 + char *value; 36 + }ftp_response_t; 37 + 38 + #endif 39 + 40 + /** 41 + * Get length of payload of a protocol 42 + * @param ipacket 43 + * @param proto_id 44 + * @return 45 + */ 46 + static inline size_t dpi_get_payload_len(const ipacket_t * ipacket, uint32_t proto_id ){ 47 + int i = 0; 48 + uint16_t length = 0; 49 + uint16_t offset = 0; 50 + 51 + for (i = 1; i < ipacket->proto_hierarchy->len; i++){ 52 + offset +=ipacket->proto_headers_offset->proto_path[i]; 53 + 54 + if ( ipacket->proto_hierarchy->proto_path[i] == proto_id ){ 55 + //get header offset of the proto after #proto_id 56 + if ( (i+1) < ipacket->proto_hierarchy->len){ 57 + offset +=ipacket->proto_headers_offset->proto_path[i+1]; 58 + length = ipacket->p_hdr->caplen - offset; 59 + 60 + return length; 61 + } 62 + return 0; 63 + } 64 + } 65 + 66 + return 0; 67 + } 68 + 69 + /** 70 + * Get length of data of a protocol 71 + * @param ipacket 72 + * @param proto_id 73 + * @return 74 + */ 75 + static inline size_t dpi_get_data_len( const ipacket_t * ipacket, uint32_t proto_id ){ 76 + int i = 0; 77 + 78 + uint16_t length = 0; 79 + uint16_t offset = 0; 80 + 81 + for (i = 1; i < ipacket->proto_hierarchy->len; i++){ 82 + offset +=ipacket->proto_headers_offset->proto_path[i]; 83 + if ( ipacket->proto_hierarchy->proto_path[i] == proto_id ){ 84 + length = ipacket->p_hdr->caplen - offset; 85 + 86 + return length; 87 + } 88 + } 89 + return 0; 90 + } 91 + 92 + static inline size_t dpi_get_ip_option_len(const ipacket_t * ipacket ){ 93 + uint8_t *ip_header_len = (uint8_t *) get_attribute_extracted_data( ipacket,PROTO_IP,IP_HEADER_LEN ); 94 + 95 + if( likely( ip_header_len != NULL )) 96 + return (*ip_header_len - 20); //IPv4 has 20 bytes of fixed header 97 + return 0; 98 + } 99 + 100 + /** 101 + * Public API 102 + * Convert data in format of MMT-Probe to data in format of MMT-Sec 103 + */ 104 + static inline int dpi_message_set_void_data( const ipacket_t *pkt, const void *data, message_t *msg, uint32_t proto_id, uint32_t att_id ){ 105 + const void *new_data = NULL; 106 + size_t new_data_len = 0; 107 + int new_data_type = MMT_SEC_MSG_DATA_TYPE_BINARY; 108 + 109 + if( unlikely( data == NULL )) 110 + return 0; 111 + 112 + switch( att_id ){ 113 + case PROTO_PAYLOAD: 114 + new_data_type = MMT_SEC_MSG_DATA_TYPE_BINARY; 115 + new_data = data; 116 + new_data_len = dpi_get_payload_len( pkt, proto_id ); 117 + break; 118 + 119 + case PROTO_DATA: 120 + new_data_type = MMT_SEC_MSG_DATA_TYPE_BINARY; 121 + new_data = data; 122 + new_data_len = dpi_get_data_len( pkt, proto_id ); 123 + break; 124 + 125 + case FTP_LAST_COMMAND: 126 + if ( proto_id == PROTO_FTP ){ 127 + new_data_type = MMT_SEC_MSG_DATA_TYPE_STRING; 128 + new_data = ((ftp_command_t *)data)->str_cmd; 129 + new_data_len = strlen( ((ftp_command_t *)data)->str_cmd ); 130 + } 131 + break; 132 + 133 + case FTP_LAST_RESPONSE_CODE: 134 + if ( proto_id == PROTO_FTP ){ 135 + new_data_type = MMT_SEC_MSG_DATA_TYPE_STRING; 136 + new_data = ((ftp_response_t *)data)->str_code; 137 + new_data_len = strlen( ((ftp_response_t *)data)->str_code ); 138 + } 139 + break; 140 + 141 + case IP_OPTS: 142 + if( proto_id == PROTO_IP){ 143 + new_data_type = MMT_SEC_MSG_DATA_TYPE_BINARY; 144 + new_data = data; 145 + new_data_len = dpi_get_ip_option_len( pkt ); 146 + } 147 + break; 148 + 149 + default: 150 + log_write( LOG_WARNING,"Need to process attribute %d.%d for packet %"PRIu64, proto_id, att_id, pkt->packet_id ); 151 + break; 152 + }//end of switch( att_id ) 153 + 154 + if( new_data_len == 0 || new_data == NULL ) 155 + return 0; 156 + 157 + return set_element_data_message_t( msg, proto_id, att_id, new_data, new_data_type, new_data_len ); 158 + } 159 + 160 + 161 + /** 162 + * Convert data encoded by mmt-dpi to one element of message_t. 163 + * - Input: 164 + * + data : data to be converted 165 + * + type : type of #data 166 + * - Output: 167 + * + el : element to be updated in message_t 168 + * + msg : message containing el 169 + * - return: 170 + * + 0 if success 171 + */ 172 + static inline int dpi_message_set_dpi_data( const void *data, int dpi_data_type, message_t *msg, uint32_t proto_id, uint32_t att_id ){ 173 + double number = 0; 174 + const void *new_data= NULL; 175 + size_t new_data_len = 0; 176 + int new_data_type = MMT_SEC_MSG_DATA_TYPE_BINARY; 177 + 178 + //does not exist data for this proto_id and att_id 179 + if( unlikely( data == NULL )) 180 + return 1; 181 + 182 + switch( dpi_data_type ){ 183 + case MMT_UNDEFINED_TYPE: /**< no type constant value */ 184 + break; 185 + case MMT_DATA_CHAR: /**< 1 character constant value */ 186 + number = *(char *) data; 187 + new_data_type = MMT_SEC_MSG_DATA_TYPE_NUMERIC; 188 + new_data = &number; 189 + new_data_len = sizeof( double ); 190 + break; 191 + 192 + case MMT_U8_DATA: /**< unsigned 1-byte constant value */ 193 + number = *(uint8_t *) data; 194 + new_data_type = MMT_SEC_MSG_DATA_TYPE_NUMERIC; 195 + new_data = &number; 196 + new_data_len = sizeof( double ); 197 + break; 198 + 199 + case MMT_DATA_PORT: /**< tcp/udp port constant value */ 200 + case MMT_U16_DATA: /**< unsigned 2-bytes constant value */ 201 + number = *(uint16_t *) data; 202 + new_data_type = MMT_SEC_MSG_DATA_TYPE_NUMERIC; 203 + new_data = &number; 204 + new_data_len = sizeof( double ); 205 + break; 206 + 207 + case MMT_U32_DATA: /**< unsigned 4-bytes constant value */ 208 + number = *(uint32_t *) data; 209 + new_data_type = MMT_SEC_MSG_DATA_TYPE_NUMERIC; 210 + new_data = &number; 211 + new_data_len = sizeof( double ); 212 + break; 213 + 214 + case MMT_U64_DATA: /**< unsigned 8-bytes constant value */ 215 + number = *(uint64_t *) data; 216 + new_data_type = MMT_SEC_MSG_DATA_TYPE_NUMERIC; 217 + new_data = &number; 218 + new_data_len = sizeof( double ); 219 + break; 220 + 221 + case MMT_DATA_FLOAT: /**< float constant value */ 222 + number = *(float *) data; 223 + new_data_type = MMT_SEC_MSG_DATA_TYPE_NUMERIC; 224 + new_data = &number; 225 + new_data_len = sizeof( double ); 226 + break; 227 + 228 + case MMT_DATA_IP6_ADDR: /**< ip6 address constant value */ 229 + new_data_type = MMT_SEC_MSG_DATA_TYPE_BINARY; 230 + new_data = data; 231 + new_data_len = 16; 232 + break; 233 + 234 + case MMT_DATA_MAC_ADDR: /**< ethernet mac address constant value */ 235 + new_data_type = MMT_SEC_MSG_DATA_TYPE_BINARY; 236 + new_data = data; 237 + new_data_len = 6; 238 + break; 239 + 240 + case MMT_DATA_IP_NET: /**< ip network address constant value */ 241 + case MMT_DATA_IP_ADDR: /**< ip address constant value */ 242 + new_data_type = MMT_SEC_MSG_DATA_TYPE_BINARY; 243 + new_data = data; 244 + new_data_len = 4; 245 + break; 246 + 247 + case MMT_DATA_TIMEVAL: /**< number of seconds and microseconds constant value */ 248 + new_data_type = MMT_SEC_MSG_DATA_TYPE_BINARY; 249 + new_data = data; 250 + new_data_len = sizeof( struct timeval ); 251 + break; 252 + 253 + //special cases: pointer is processed separately 254 + //case MMT_DATA_POINTER: /**< pointer constant value (size is void *) */ 255 + 256 + case MMT_DATA_BUFFER: /**< binary buffer content */ 257 + case MMT_DATA_POINT: /**< point constant value */ 258 + case MMT_DATA_PORT_RANGE: /**< tcp/udp port range constant value */ 259 + case MMT_DATA_DATE: /**< date constant value */ 260 + case MMT_DATA_TIMEARG: /**< time argument constant value */ 261 + case MMT_DATA_STRING_INDEX: /**< string index constant value (an association between a string and an integer) */ 262 + case MMT_DATA_LAYERID: /**< Layer ID value */ 263 + case MMT_DATA_FILTER_STATE: /**< (filter_id: filter_state) */ 264 + case MMT_DATA_PARENT: /**< (filter_id: filter_state) */ 265 + case MMT_STATS: /**< pointer to MMT Protocol statistics */ 266 + printf("WARN: does not support MMT-DPI data type %d\n", dpi_data_type ); 267 + break; 268 + 269 + case MMT_BINARY_DATA: /**< binary constant value */ 270 + new_data_type = MMT_SEC_MSG_DATA_TYPE_BINARY; 271 + new_data = data; 272 + new_data_len = BINARY_64DATA_TYPE_LEN; 273 + break; 274 + 275 + case MMT_BINARY_VAR_DATA: /**< binary constant value with variable size given by function getExtractionDataSizeByProtocolAndFieldIds */ 276 + new_data_type = MMT_SEC_MSG_DATA_TYPE_BINARY; 277 + new_data = data; 278 + new_data_len = BINARY_1024DATA_TYPE_LEN; 279 + break; 280 + 281 + case MMT_STRING_DATA: /**< text string data constant value. Len plus data. Data is expected to be '\0' terminated and maximum BINARY_64DATA_LEN long */ 282 + case MMT_STRING_LONG_DATA: /**< text string data constant value. Len plus data. Data is expected to be '\0' terminated and maximum STRING_DATA_LEN long */ 283 + new_data_type = MMT_SEC_MSG_DATA_TYPE_STRING; 284 + new_data = ((mmt_binary_var_data_t *)data)->data; 285 + new_data_len = ((mmt_binary_var_data_t *)data)->len; 286 + break; 287 + 288 + 289 + case MMT_HEADER_LINE: /**< string pointer value with a variable size. The string is not necessary null terminating */ 290 + new_data_type = MMT_SEC_MSG_DATA_TYPE_STRING; 291 + new_data = ((mmt_header_line_t *)data)->ptr; 292 + new_data_len = ((mmt_header_line_t *)data)->len; 293 + break; 294 + 295 + case MMT_GENERIC_HEADER_LINE: /**< structure representing an RFC2822 header line with null terminating field and value elements. */ 296 + case MMT_STRING_DATA_POINTER: /**< pointer constant value (size is void *). The data pointed to is of type string with null terminating character included */ 297 + new_data_type = MMT_SEC_MSG_DATA_TYPE_STRING; 298 + new_data = data; 299 + new_data_len = strlen( (char*) data); 300 + break; 301 + 302 + case MMT_DATA_PATH: /**< protocol path constatn value */ 303 + new_data_type = MMT_SEC_MSG_DATA_TYPE_BINARY; 304 + new_data = data; 305 + new_data_len = sizeof( proto_hierarchy_t ); 306 + break; 307 + 308 + default: 309 + break; 310 + } 311 + 312 + if( unlikely( new_data_len == 0 || new_data == NULL )) 313 + return 0; 314 + 315 + return set_element_data_message_t( msg, proto_id, att_id, new_data, new_data_type, new_data_len ); 316 + } 317 + 318 + 319 + /** 320 + * Convert data encoded in a pcap packet to readable data that is either a double 321 + * or a string ending by '\0'. 322 + * This function will create a new memory segment to store its result. 323 + */ 324 + static inline int dpi_message_set_data( const ipacket_t *pkt, int dpi_data_type, message_t *msg, uint32_t proto_id, uint32_t att_id ){ 325 + uint8_t *data = (uint8_t *) get_attribute_extracted_data( pkt, proto_id, att_id ); 326 + 327 + //does not exist data for this proto_id and att_id 328 + if( data == NULL ) 329 + return 1; 330 + 331 + if( dpi_data_type == MMT_DATA_POINTER ){ 332 + return dpi_message_set_void_data( pkt, data, msg, proto_id, att_id ); 333 + } 334 + 335 + return dpi_message_set_dpi_data( data, dpi_data_type, msg, proto_id, att_id ); 336 + } 337 + 338 + #endif /* SRC_LIB_DPI_MESSAGE_T_H_ */ 339 + -
1 + /* 2 + * expression.c 3 + * 4 + * Created on: 21 sept. 2016 5 + * Created by: Huu Nghia NGUYEN <[email protected]> 6 + */ 7 + 8 + #include <ctype.h> 9 + #include <stdlib.h> 10 + #include <limits.h> 11 + #include <mmt_core.h> 12 + 13 + #include "../lib/mmt_lib.h" 14 + #include "mmt_utils.h" 15 + #include "expression.h" 16 + 17 + #define MAX_STR_SIZE 10000 18 + 19 + /** 20 + * Convert from MMT_DPI_DATA_TYPE to MMT_SEC_DATA_TYPE that is either a MMT_SEC_MSG_DATA_TYPE_STRING or a MMT_SEC_MSG_DATA_TYPE_NUMERIC 21 + */ 22 + inline int convert_data_type( int type ){ 23 + switch( type ){ 24 + case MMT_U8_DATA: 25 + case MMT_U16_DATA: 26 + case MMT_U32_DATA: 27 + case MMT_U64_DATA: 28 + case MMT_DATA_PORT: 29 + case MMT_DATA_CHAR: 30 + case MMT_DATA_FLOAT: 31 + return MMT_SEC_MSG_DATA_TYPE_NUMERIC; 32 + 33 + case MMT_DATA_MAC_ADDR: 34 + case MMT_STRING_DATA: 35 + case MMT_STRING_LONG_DATA: 36 + case MMT_BINARY_VAR_DATA: 37 + case MMT_BINARY_DATA: 38 + case MMT_HEADER_LINE: 39 + case MMT_DATA_IP_ADDR: 40 + case MMT_DATA_IP6_ADDR: 41 + case MMT_STRING_DATA_POINTER: 42 + return MMT_SEC_MSG_DATA_TYPE_STRING; 43 + 44 + case MMT_DATA_POINTER: 45 + case MMT_DATA_PATH: 46 + case MMT_DATA_TIMEVAL: 47 + case MMT_DATA_BUFFER: 48 + case MMT_DATA_POINT: 49 + case MMT_DATA_PORT_RANGE: 50 + case MMT_DATA_DATE: 51 + case MMT_DATA_TIMEARG: 52 + case MMT_DATA_STRING_INDEX: 53 + case MMT_DATA_IP_NET: 54 + case MMT_DATA_LAYERID: 55 + case MMT_DATA_FILTER_STATE: 56 + case MMT_DATA_PARENT: 57 + case MMT_STATS: 58 + return MMT_SEC_MSG_DATA_TYPE_BINARY; 59 + default: 60 + return UNKNOWN; 61 + } 62 + return MMT_SEC_MSG_DATA_TYPE_STRING; 63 + } 64 + 65 + size_t str_trim( uint8_t *string, size_t size ){ 66 + return size; 67 + } 68 + /** 69 + * public API 70 + */ 71 + size_t get_variables_inside_expression( const expression_t *expr ){ 72 + size_t size = 0; 73 + return size; 74 + } 75 + 76 + /** Public API */ 77 + constant_t *expr_create_a_constant( enum data_type type, size_t data_size, void *data ){ 78 + constant_t *cont = mmt_mem_alloc( sizeof( constant_t )); 79 + cont->data_type = type; 80 + cont->data_size = data_size; 81 + cont->data = data; 82 + return cont; 83 + } 84 + 85 + static inline void _to_lower( char *str){ 86 + char *p; 87 + //change name to lower case 88 + for( p = str; *p != '\0'; p ++) 89 + *p = tolower( *p ); 90 + } 91 + 92 + /** Public API */ 93 + variable_t *expr_create_a_variable( char *proto, char *attr, uint16_t ref_index ){ 94 + variable_t *var = mmt_mem_alloc( sizeof( variable_t )); 95 + //_to_lower( proto ); 96 + //_to_lower( attr ); 97 + var->proto = proto; 98 + var->att = attr; 99 + var->ref_index = ref_index; 100 + var->proto_id = get_protocol_id_by_name( var->proto ); 101 + ASSERT( var->proto_id != ((uint32_t)-1), "Error: Unknown protocol \"%s\".", proto ); 102 + var->att_id = get_attribute_id_by_protocol_id_and_attribute_name( var->proto_id, var->att ); 103 + ASSERT( var->att_id != ((uint32_t)-1), "Error: Unknown attribute \"%s\" of protocol \"%s\".", attr, proto ); 104 + var->dpi_type = get_attribute_data_type( var->proto_id, var->att_id ); 105 + var->data_type = convert_data_type( var->dpi_type ); 106 + 107 + ASSERT( var->data_type != UNKNOWN, "Error 2: Data type for %s.%s has not implemented yet.", proto, attr); 108 + 109 + return var; 110 + } 111 + 112 + /** Public API */ 113 + operation_t *expr_create_an_operation( char *name, enum operator operator ){ 114 + operation_t *opt = mmt_mem_alloc( sizeof( operation_t )); 115 + opt->name = name; 116 + opt->operator = operator; 117 + opt->params_list = NULL; 118 + opt->data_type = UNKNOWN; 119 + opt->params_size = 0; 120 + return opt; 121 + } 122 + 123 + /** Public API */ 124 + expression_t *expr_create_an_expression( enum expression type, void *data ){ 125 + expression_t *expr = mmt_mem_alloc( sizeof( expression_t)); 126 + expr->type = type; 127 + expr->father = NULL; 128 + switch( type ){ 129 + case VARIABLE: 130 + expr->variable = data; 131 + break; 132 + case CONSTANT: 133 + expr->constant = data; 134 + break; 135 + case OPERATION: 136 + expr->operation = data; 137 + break; 138 + } 139 + return expr; 140 + } 141 + 142 + /** Public API */ 143 + void expr_free_a_constant( constant_t *x, bool free_data){ 144 + if( free_data == YES ) 145 + mmt_free_and_assign_to_null( x->data ); 146 + mmt_free_and_assign_to_null( x ); 147 + } 148 + 149 + /** Public API */ 150 + void expr_free_a_variable( variable_t *x, bool free_data){ 151 + if( free_data == YES ){ 152 + mmt_free_and_assign_to_null( x->proto ); 153 + mmt_free_and_assign_to_null( x->att ); 154 + } 155 + mmt_free_and_assign_to_null( x ); 156 + } 157 + 158 + /** Public API */ 159 + void expr_free_an_operation( operation_t *x, bool free_data){ 160 + link_node_t *ptr, *q; 161 + //free data and parameters of this operation 162 + if( free_data == YES){ 163 + mmt_free_and_assign_to_null( x->name ); 164 + 165 + ptr = x->params_list; 166 + while( ptr != NULL ){ 167 + q = ptr; 168 + ptr = ptr->next; 169 + 170 + //free data of a node of linked-list 171 + expr_free_an_expression( (expression_t *) q->data, free_data ); 172 + q->data = NULL; 173 + //free a node of linked-list 174 + mmt_free_and_assign_to_null( q ); 175 + q = NULL; 176 + } 177 + } 178 + mmt_free_and_assign_to_null( x ); 179 + } 180 + 181 + /** Public API */ 182 + void expr_free_an_expression( expression_t *expr, bool free_data){ 183 + switch( expr->type ){ 184 + case VARIABLE: 185 + expr_free_a_variable( expr->variable, free_data); 186 + break; 187 + case CONSTANT: 188 + expr_free_a_constant( expr->constant, free_data ); 189 + break; 190 + case OPERATION: 191 + expr_free_an_operation( expr->operation, free_data ); 192 + break; 193 + } 194 + mmt_free_and_assign_to_null( expr ); 195 + } 196 + 197 + /** 198 + * Get index of the first character in string such that it is not a space 199 + * - Return: 200 + * + 0 if there is no space 201 + * + str_size if the string contains only space 202 + * + index where the character is not a space 203 + */ 204 + static inline size_t _jump_space( const char *string, size_t str_size ){ 205 + size_t i=0; 206 + if( (string == NULL) || (str_size == 0) ) 207 + return 0; 208 + //a pointer created by mmt_malloc always have \0 at the end 209 + for( i=0; i<str_size; i++ ) 210 + if( ! isspace( string[i] ) ) 211 + return i; 212 + return 0; 213 + } 214 + 215 + 216 + size_t _parse_a_proto_name( char **name, const char *string, size_t str_size, bool is_allow_number_prefix ){ 217 + size_t i = 0, index = 0; 218 + const char *temp; 219 + char *p; 220 + *name = NULL; 221 + if( string == NULL || str_size == 0 ) 222 + return 0; 223 + 224 + index = _jump_space( string, str_size ); 225 + 226 + //all of string are spaces 227 + if( index == str_size ) return index; 228 + 229 + temp = string + index; 230 + 231 + //whether allow a name start by: number/alphabet/_ 232 + if( !is_allow_number_prefix ) 233 + //first character must be an alphabet 234 + if( ! (isalpha(*temp ) || *temp == '_') ) 235 + return index; 236 + 237 + //the next characters can be alphabet or digit 238 + while( (isalnum( *(temp+i) ) || *(temp +i) == '_' ) && index < str_size ){ 239 + i++; 240 + index ++; 241 + } 242 + 243 + //duplicate the name 244 + *name = mmt_mem_dup( temp, i ); 245 + 246 + return index; 247 + } 248 + 249 + 250 + size_t _parse_a_name( char **name, const char *string, size_t str_size ){ 251 + return _parse_a_proto_name( name, string, str_size, false ); 252 + } 253 + /** 254 + * Parse a string that is put inside by ' ' or " " 255 + */ 256 + size_t _parse_a_string( char **name, const char *string, size_t str_size ){ 257 + size_t i = 0, index = 0; 258 + const char *temp; 259 + *name = NULL; 260 + 261 + if( string == NULL || str_size == 0 ) 262 + return 0; 263 + 264 + index = _jump_space( string, str_size ); 265 + 266 + //all of string are spaces 267 + if( index == str_size ) return index; 268 + 269 + temp = string + index; 270 + 271 + //first character must be the open bracket: " or ' 272 + if( *temp != '"' && *temp != '\'') 273 + return index; 274 + 275 + i = 1; 276 + index ++; 277 + //find a close bracket 278 + while( *(temp+i) != *temp && index < str_size ){ 279 + i++; 280 + index ++; 281 + } 282 + 283 + //must be found the closer 284 + ASSERT( index < str_size, "Error 3.a: String is in incorrect format: %s", temp ); 285 + 286 + //duplicate the name 287 + if( i-1 == 0) 288 + *name = mmt_mem_dup( "", 1 ); 289 + else 290 + *name = mmt_mem_dup( temp + 1, i - 1 ); 291 + 292 + //jump over the closer 293 + return index + 1; 294 + } 295 + 296 + /** 297 + * Parse a number: integer or float 298 + */ 299 + size_t _parse_a_number( double **num, const char *string, size_t str_size ){ 300 + size_t i = 0, index = 0; 301 + bool has_dot = NO; 302 + const char *temp; 303 + char *str; 304 + *num = NULL; 305 + if( string == NULL || str_size == 0 ) 306 + return 0; 307 + 308 + index = _jump_space( string, str_size ); 309 + 310 + //all of string are spaces 311 + if( index == str_size ) return index; 312 + 313 + temp = string + index; 314 + //first character must be an number 315 + if( ! isdigit(*temp )) 316 + return index; 317 + 318 + //the next characters can be a dot or a digit 319 + while( (isdigit(*(temp+i)) || *(temp+i) == '.' ) && index < str_size ){ 320 + if( *(temp+i) == '.' ){ 321 + //already saw a dot then we break at the second dot 322 + if( has_dot == YES ) 323 + break; 324 + else 325 + has_dot = YES; 326 + } 327 + 328 + i++; 329 + index ++; 330 + } 331 + 332 + //duplicate the name 333 + str = mmt_mem_dup( temp, i ); 334 + *num = mmt_mem_alloc( sizeof( double )); 335 + **num = atof( str ); 336 + 337 + mmt_mem_free( str ); 338 + 339 + return index; 340 + } 341 + 342 + /** 343 + * get number of digits of an integer 344 + */ 345 + size_t _num_digits( int n ){ 346 + if (n < 0) return _num_digits ((n == INT_MIN) ? INT_MAX : -n); 347 + if (n < 10) return 1; 348 + return 1 + _num_digits (n / 10); 349 + } 350 + 351 + /** 352 + * A constant is either a number or a string 353 + */ 354 + size_t _parse_constant( constant_t **expr, const char *string, size_t str_size ){ 355 + size_t index; 356 + char *name = NULL; 357 + double *number = NULL; 358 + *expr = NULL; 359 + if( string == NULL || str_size == 0 ) 360 + return 0; 361 + 362 + index = _parse_a_number( &number, string, str_size ); 363 + //found a number 364 + if( number != NULL ){ 365 + *expr = expr_create_a_constant(MMT_SEC_MSG_DATA_TYPE_NUMERIC, sizeof( double), number); 366 + return index; 367 + } 368 + 369 + //not found any number => find a string 370 + index = _parse_a_string( &name, string, str_size ); 371 + if( name != NULL ){ 372 + *expr = expr_create_a_constant(MMT_SEC_MSG_DATA_TYPE_STRING, mmt_mem_size( name ), name); 373 + return index; 374 + } 375 + return index; 376 + } 377 + 378 + /** 379 + * Parse a variable that is in format: proto.att[.index], e.g., TCP.SRC or TCP.SRC.1 380 + */ 381 + size_t _parse_variable( variable_t **expr, const char *string, size_t str_size ){ 382 + size_t index, old_index; 383 + bool is_start_by_number; 384 + char *str_1 = NULL, *str_2 = NULL; 385 + uint16_t ref_index = UNKNOWN_REF_INDEX; 386 + char const *temp; 387 + double *num = NULL; 388 + 389 + *expr = NULL; 390 + 391 + index = _jump_space( string, str_size ); 392 + if( (string == NULL) || (str_size == 0) || index == str_size ) 393 + return index; 394 + 395 + temp = string + index; 396 + 397 + //mark: if started by a number => must be PROTO.ATT 398 + is_start_by_number = isdigit( *temp ); 399 + old_index = index; 400 + 401 + index = _parse_a_proto_name( &str_1, temp, str_size, true ); 402 + 403 + //has proto? 404 + if( str_1 != NULL ){ 405 + //must have a dot 406 + if( string[ index ] == '.' ){ 407 + index ++; //jump over this dot 408 + temp = string + index ; 409 + index += _parse_a_proto_name( &str_2, temp, str_size - index, true ); 410 + //has att ? 411 + if( str_2 != NULL ){ 412 + //has index ? 413 + if( string[ index ] == '.' ){ 414 + index ++; //jump over the second dot 415 + temp = string + index; //2 dots 416 + index += _parse_a_number( &num, temp, str_size - index ); 417 + ref_index = (uint16_t ) (*num); 418 + mmt_free_and_assign_to_null( num ); 419 + } 420 + 421 + *expr = expr_create_a_variable( str_1, str_2, ref_index ); 422 + return index; 423 + } 424 + else 425 + mmt_free_and_assign_to_null( str_1 ); 426 + } else { 427 + //this is not a proto.att 428 + //=> do not allow to start by a number 429 + if( is_start_by_number ){ 430 + mmt_free_and_assign_to_null( str_1 ); 431 + return old_index; 432 + } 433 + } 434 + } 435 + 436 + return index; 437 + } 438 + 439 + static inline char _get_the_next_char( const char *string ){ 440 + while( isspace( *string )) string ++; 441 + return *string; 442 + } 443 + 444 + static inline bool _parse_a_boolean_expression( bool is_first_time, expression_t *expr, const char *string ){ 445 + //parse expression and create sub-tree, expr->operator = top operator 446 + //((ARP.OPCODE == 2)&&(ARP.SRC_PROTO == ARP.SRC_PROTO.1)) 447 + //OR, AND, NEQ, EQ, GT, GTE, LT, LTE, THEN, COMPUTE, XC, XCE, XD, XDE, XE, ADD, SUB, MUL, DIV 448 + size_t index; 449 + 450 + const char *temp = string; 451 + const char *temp2 = string; 452 + double *new_number = NULL; 453 + expression_t *new_expr; 454 + operation_t *new_op; 455 + variable_t *new_var; 456 + char *new_string; 457 + 458 + //jump 459 + while ( isspace(*temp))temp++; 460 + 461 + if (*temp == '(') { 462 + temp2 = temp + 1; 463 + if ( is_first_time == YES) { 464 + _parse_a_boolean_expression(NO, expr, temp2); 465 + } else { 466 + //create new_expr 467 + //we have not known yet the operator of new_op 468 + //it will be determined after 469 + new_op = expr_create_an_operation(NULL, UNKNOWN ); 470 + new_expr = expr_create_an_expression( OPERATION, new_op ); 471 + new_expr->father = expr; 472 + //append new_expr to expr->params_list 473 + expr->operation->params_list = append_node_to_link_list( expr->operation->params_list, new_expr ); 474 + expr->operation->params_size ++; 475 + 476 + _parse_a_boolean_expression(NO, new_expr, temp2); 477 + } 478 + } else if (*temp == ')') { 479 + ASSERT( expr->father != NULL || _get_the_next_char(temp + 1) == '\0', "Error 37d: Unexpected: %s", temp + 1 ); 480 + _parse_a_boolean_expression(NO, expr->father, temp + 1); 481 + } else if (*temp == '\0') { 482 + //do nothing 483 + } else if (*temp == '\'') { 484 + //a 'string' 485 + index = _parse_a_string( &new_string, temp, MAX_STR_SIZE ); 486 + 487 + new_expr = expr_create_an_expression( CONSTANT, 488 + expr_create_a_constant(MMT_SEC_MSG_DATA_TYPE_STRING, mmt_mem_size( new_string ), new_string) ); 489 + new_expr->father = expr; 490 + 491 + //append new_expr to expr->params_list 492 + expr->operation->params_list = append_node_to_link_list( expr->operation->params_list, new_expr ); 493 + expr->operation->params_size ++; 494 + _parse_a_boolean_expression(NO, expr, temp + index); 495 + } else if (isdigit(*temp) || isalpha(*temp) || *temp == '_') { 496 + 497 + //a variable: PROTO.FIELD.EVENT 498 + index = _parse_variable( &new_var, temp, MAX_STR_SIZE ); 499 + 500 + //not a variable 501 + //=> give one more chance to check constant: (1) a number or (2) an id (true/false) 502 + if( new_var == NULL ){ 503 + //(1) check number 504 + if( isdigit( *temp )){ 505 + //a number 1.0 506 + index = _parse_a_number( &new_number, temp, MAX_STR_SIZE ); 507 + //found a number 508 + //create a new expression 509 + new_expr = expr_create_an_expression( CONSTANT, expr_create_a_constant(MMT_SEC_MSG_DATA_TYPE_NUMERIC, sizeof( double), new_number) ); 510 + new_expr->father = expr; 511 + //append new_expr to expr->params_list 512 + expr->operation->params_list = append_node_to_link_list( expr->operation->params_list, new_expr ); 513 + expr->operation->params_size ++; 514 + } else { 515 + //(2) check id 516 + index = _parse_a_name( &new_string, temp, MAX_STR_SIZE ); 517 + new_number = mmt_mem_alloc( sizeof( double ) ); 518 + if( strcmp( new_string, "true") == 0 ){ 519 + *new_number = true; 520 + }else if( strcmp( new_string, "false") == 0 ){ 521 + *new_number = false; 522 + }else { 523 + mmt_mem_free( new_number ); 524 + ABORT("Error 37c: Illegal name:\"%s\".\nExpected either \"true\", \"false\", or proto.att or proto.att.ref", temp ); 525 + } 526 + new_expr = expr_create_an_expression( CONSTANT, expr_create_a_constant(MMT_SEC_MSG_DATA_TYPE_NUMERIC, sizeof( double), new_number) ); 527 + new_expr->father = expr; 528 + //append new_expr to expr->params_list 529 + expr->operation->params_list = append_node_to_link_list( expr->operation->params_list, new_expr ); 530 + expr->operation->params_size ++; 531 + } 532 + }else{ 533 + new_expr = expr_create_an_expression( VARIABLE, new_var ); 534 + new_expr->father = expr; 535 + //append new_expr to expr->params_list 536 + expr->operation->params_list = append_node_to_link_list( expr->operation->params_list, new_expr ); 537 + expr->operation->params_size ++; 538 + } 539 + 540 + _parse_a_boolean_expression(NO, expr, temp + index); 541 + 542 + } else if (*temp == '#') { 543 + //an embedded function: #func(param_1, param_2) 544 + temp ++; 545 + index = _parse_a_name( &new_string, temp, MAX_STR_SIZE ); 546 + 547 + new_op = expr_create_an_operation( new_string, FUNCTION ); 548 + new_expr = expr_create_an_expression( OPERATION, new_op ); 549 + new_expr->father = expr; 550 + 551 + //append new_expr to expr->params_list 552 + expr->operation->params_list = append_node_to_link_list( expr->operation->params_list, new_expr ); 553 + expr->operation->params_size ++; 554 + //parse the parameters of this function 555 + _parse_a_boolean_expression(YES, new_expr, temp + index ); 556 + } else if (isdigit(*temp)) { 557 + 558 + } else if (*temp == '&' && *(temp + 1) == '&') { 559 + // && 560 + //must no change operator: either unknown for the first element in the list or the same 561 + //=> to explain: a && b || c 562 + // need ((a && b) || c) 563 + ASSERT( (expr->type == OPERATION && (expr->operation->operator == AND || expr->operation->operator == UNKNOWN)), 564 + "Error 39a: Unexpect \"%s\"\n", temp ); 565 + temp2 = temp + 2; 566 + expr->type = OPERATION; 567 + expr->operation->operator = AND; 568 + expr->operation->name = mmt_mem_dup( "&&", 2); 569 + _parse_a_boolean_expression(NO, expr, temp2); 570 + } else if (*temp == '|' && *(temp + 1) == '|') { 571 + // || 572 + ASSERT( (expr->type == OPERATION && (expr->operation->operator == OR || expr->operation->operator == UNKNOWN)), 573 + "Error 39a: Unexpect \"%s\"\n", temp ); 574 + temp2 = temp + 2; 575 + expr->type = OPERATION; 576 + expr->operation->operator = OR; 577 + expr->operation->name = mmt_mem_dup( "||", 2); 578 + _parse_a_boolean_expression(NO, expr, temp2); 579 + } else if (*temp == '=' && *(temp + 1) == '=') { 580 + // == 581 + ASSERT( (expr->type == OPERATION && expr->operation->operator == UNKNOWN ), 582 + "Error 39a: Unexpect \"%s\"\n", temp ); 583 + temp2 = temp + 2; 584 + // set value 585 + expr->type = OPERATION; 586 + expr->operation->operator = EQ; 587 + expr->operation->name = mmt_mem_dup( "==", 2); 588 + //continue 589 + _parse_a_boolean_expression(NO, expr, temp2); 590 + } else if (*temp == '!' && *(temp + 1) == '=') { 591 + // != 592 + ASSERT( (expr->type == OPERATION && expr->operation->operator == UNKNOWN ), 593 + "Error 39a: Unexpect \"%s\"\n", temp ); 594 + temp2 = temp + 2; 595 + expr->type = OPERATION; 596 + expr->operation->operator = NEQ; 597 + expr->operation->name = mmt_mem_dup( "!=", 2); 598 + _parse_a_boolean_expression(NO, expr, temp2); 599 + } else if (*temp == '>' && *(temp + 1) != '=') { 600 + // > 601 + ASSERT( (expr->type == OPERATION && expr->operation->operator == UNKNOWN ), 602 + "Error 39a: Unexpect \"%s\"\n", temp ); 603 + temp2 = temp + 1; 604 + expr->type = OPERATION; 605 + expr->operation->operator = GT; 606 + expr->operation->name = mmt_mem_dup( ">", 1); 607 + _parse_a_boolean_expression(NO, expr, temp2); 608 + } else if (*temp == '>' && *(temp + 1) == '=') { 609 + // >= 610 + ASSERT( (expr->type == OPERATION && expr->operation->operator == UNKNOWN ), 611 + "Error 39a: Unexpect \"%s\"\n", temp ); 612 + temp2 = temp + 2; 613 + expr->type = OPERATION; 614 + expr->operation->operator = GTE; 615 + expr->operation->name = mmt_mem_dup( ">=", 2); 616 + _parse_a_boolean_expression(NO, expr, temp2); 617 + } else if (*temp == '<' && *(temp + 1) != '=') { 618 + // < 619 + ASSERT( (expr->type == OPERATION && expr->operation->operator == UNKNOWN ), 620 + "Error 39a: Unexpect \"%s\"\n", temp ); 621 + temp2 = temp + 1; 622 + expr->type = OPERATION; 623 + expr->operation->operator = LT; 624 + expr->operation->name = mmt_mem_dup( "<", 1); 625 + _parse_a_boolean_expression(NO, expr, temp2); 626 + } else if (*temp == '<' && *(temp + 1) == '=') { 627 + // <= 628 + ASSERT( (expr->type == OPERATION && expr->operation->operator == UNKNOWN ), 629 + "Error 39a: Unexpect \"%s\"\n", temp ); 630 + temp2 = temp + 2; 631 + expr->type = OPERATION; 632 + expr->operation->operator = LTE; 633 + expr->operation->name = mmt_mem_dup( "<=", 2); 634 + _parse_a_boolean_expression(NO, expr, temp2); 635 + } else if (*temp == '+') { 636 + // + 637 + ASSERT( (expr->type == OPERATION && (expr->operation->operator == ADD || expr->operation->operator == UNKNOWN) ), 638 + "Error 39a: Unexpect \"%s\"\n", temp ); 639 + temp2 = temp + 1; 640 + expr->type = OPERATION; 641 + expr->operation->operator = ADD; 642 + expr->operation->name = mmt_mem_dup( "+", 1); 643 + _parse_a_boolean_expression(NO, expr, temp2); 644 + } else if (*temp == '-') { 645 + // - 646 + ASSERT( (expr->type == OPERATION && (expr->operation->operator == SUB || expr->operation->operator == UNKNOWN)), 647 + "Error 39a: Unexpect \"%s\"\n", temp ); 648 + temp2 = temp + 1; 649 + expr->type = OPERATION; 650 + expr->operation->operator = SUB; 651 + expr->operation->name = mmt_mem_dup( "-", 1); 652 + _parse_a_boolean_expression(NO, expr, temp2); 653 + } else if (*temp == '*') { 654 + // * 655 + ASSERT( (expr->type == OPERATION && (expr->operation->operator == MUL || expr->operation->operator == UNKNOWN)), 656 + "Error 39a: Unexpect \"%s\"\n", temp ); 657 + temp2 = temp + 1; 658 + expr->type = OPERATION; 659 + expr->operation->operator = MUL; 660 + expr->operation->name = mmt_mem_dup( "*", 1); 661 + _parse_a_boolean_expression(NO, expr, temp2); 662 + } else if (*temp == '/') { 663 + // '/' 664 + ASSERT( (expr->type == OPERATION && (expr->operation->operator == DIV || expr->operation->operator == UNKNOWN)), 665 + "Error 39a: Unexpect \"%s\"\n", temp ); 666 + temp2 = temp + 1; 667 + expr->type = OPERATION; 668 + expr->operation->operator = DIV; 669 + expr->operation->name = mmt_mem_dup( "/", 1); 670 + _parse_a_boolean_expression(NO, expr, temp2); 671 + } else if( *temp == ',' && expr->type == OPERATION && expr->operation->operator == FUNCTION ){ 672 + temp ++; 673 + while( isspace( *temp)) temp ++; 674 + //waiting for another parameter 675 + ASSERT( *temp != ')', "Error 37b: Illegal delimiter of function %s: ,%c", expr->operation->name, *temp ); 676 + //*tmp != ')' ==> continue parsing the next parameter of function 677 + _parse_a_boolean_expression(NO, expr, temp); 678 + }else{ 679 + (void)fprintf(stderr, "Error 37: Illegal character found in boolean expression: %c%c.\n", *temp, *(temp + 1)); 680 + exit(-1); 681 + } 682 + return 0; 683 + } 684 + 685 + /** 686 + * public API 687 + */ 688 + int parse_expression( expression_t **expr, const char *string, size_t str_size ){ 689 + expression_t *ret = NULL; 690 + operation_t *new_op; 691 + *expr = NULL; 692 + if( string == NULL ) 693 + return 0; 694 + 695 + //we have not known yet the operator of new_op 696 + //it will be determined after 697 + new_op = expr_create_an_operation(NULL, UNKNOWN ); 698 + ret = expr_create_an_expression( OPERATION, new_op ); 699 + *expr = ret; 700 + return _parse_a_boolean_expression( YES, ret, string ); 701 + } 702 + 703 + /** 704 + * public API 705 + */ 706 + size_t expr_stringify_constant( char **string, const constant_t *expr){ 707 + char buff[ MAX_STR_SIZE ]; 708 + int size; 709 + double d; 710 + 711 + if( expr == NULL ){ 712 + string = NULL; 713 + return 0; 714 + } 715 + 716 + if( expr->data_type == MMT_SEC_MSG_DATA_TYPE_NUMERIC ){ 717 + d = *(double *)expr->data; 718 + //integer 719 + size = snprintf(buff, sizeof(buff), "%.2f", d); 720 + size --; //jump over last '\0'; 721 + //remove zero at the end, e.g., 10.00 ==> 10 722 + while( size > 1 && buff[ size - 1 ] == '0' ) 723 + size --; 724 + if( buff[ size - 1 ] == '.' ) size --; 725 + }else if( expr->data_type == MMT_SEC_MSG_DATA_TYPE_STRING ){ 726 + size = snprintf( buff, sizeof(buff), "\"%s\"", (char *)expr->data ); 727 + }else{ 728 + size = snprintf( buff, sizeof(buff), "\"__na__\""); 729 + } 730 + 731 + *string = mmt_mem_dup( buff, size ); 732 + 733 + return size; 734 + } 735 + 736 + /** 737 + * public API 738 + */ 739 + size_t expr_stringify_variable( char **string, const variable_t *var){ 740 + size_t size = 0; 741 + char buff[ 250 ]; 742 + *string = NULL; 743 + 744 + if( var == NULL ){ 745 + return 0; 746 + } 747 + 748 + if( var->ref_index != UNKNOWN_REF_INDEX ){ 749 + size = snprintf(buff, sizeof( buff ), "_%s_%s_%d", var->proto, var->att, var->ref_index); 750 + }else{ 751 + size = snprintf(buff, sizeof( buff ), "_%s_%s", var->proto, var->att ); 752 + } 753 + *string = mmt_mem_dup( buff, size ); 754 + return size; 755 + } 756 + 757 + static inline bool _is_comparison_operator( int op ){ 758 + return op == NEQ || op == EQ || op == GT || op == GTE || op == LT || op == LTE; 759 + } 760 + 761 + static inline bool _is_string_variable( const operation_t *opt ){ 762 + link_node_t *ptr; 763 + expression_t *expr; 764 + ptr = opt->params_list; 765 + while( ptr != NULL ){ 766 + expr = (expression_t *) ptr->data; 767 + if( expr->type != VARIABLE || expr->variable->data_type != MMT_SEC_MSG_DATA_TYPE_STRING ) 768 + return NO; 769 + ptr = ptr->next; 770 + } 771 + return YES; 772 + } 773 + 774 + static inline bool _is_string_param( const operation_t *opt ){ 775 + link_node_t *ptr; 776 + expression_t *expr; 777 + ptr = opt->params_list; 778 + while( ptr != NULL ){ 779 + expr = (expression_t *) ptr->data; 780 + if( expr->type == VARIABLE && expr->variable->data_type != MMT_SEC_MSG_DATA_TYPE_STRING ) 781 + return NO; 782 + if( expr->type == CONSTANT && expr->variable->data_type != MMT_SEC_MSG_DATA_TYPE_STRING ) 783 + return NO; 784 + ptr = ptr->next; 785 + } 786 + return YES; 787 + } 788 + /** 789 + * Public API 790 + */ 791 + size_t expr_stringify_operation( char **string, const operation_t *opt ){ 792 + char *tmp = NULL; 793 + const char *delim; 794 + link_node_t *node; 795 + size_t index = 0; 796 + expression_t *expr; 797 + 798 + char str[ MAX_STR_SIZE ]; 799 + //change comparison of string to function: "a" == "b" ==> 0 == strcmp("a", "b") 800 + if( _is_comparison_operator( opt->operator ) && _is_string_param ( opt ) ){ 801 + //delimiter 802 + delim = ","; 803 + index += snprintf( &str[ index ], MAX_STR_SIZE, "0 %s %s(", opt->name, 804 + _is_string_variable( opt) ? "mmt_mem_cmp" : "strcmp" ); 805 + }else if( opt->operator == FUNCTION ){ 806 + delim = ","; 807 + index += snprintf( &str[ index ], MAX_STR_SIZE, "%s(", opt->name ); 808 + }else{ 809 + delim = opt->name; 810 + index += snprintf( &str[ index ], MAX_STR_SIZE, "(" ); 811 + } 812 + 813 + //parameters 814 + node = opt->params_list; 815 + //no parameter 816 + if( node == NULL ){ 817 + index += snprintf( &str[ index ], MAX_STR_SIZE - index, ")"); 818 + } 819 + else while( node != NULL ){ 820 + expr = (expression_t *) node->data; 821 + (void) expr_stringify_expression( &tmp, expr ); 822 + //the last parameter ==> no need delimiter but a close-bracket 823 + if( node->next == NULL ){ 824 + index += snprintf( &str[ index ], MAX_STR_SIZE - index, "%s)", tmp); 825 + }else{ 826 + index += snprintf( &str[ index ], MAX_STR_SIZE - index, "%s %s ", tmp , delim); 827 + } 828 + //tmp was created in expr_stringify_expression( &tmp ... 829 + mmt_mem_free( tmp ); 830 + node = node->next; 831 + }; 832 + 833 + //clone string 834 + *string = mmt_mem_dup( str, index ); 835 + 836 + return index; 837 + } 838 + /** 839 + * public API 840 + */ 841 + size_t expr_stringify_expression( char **string, const expression_t *expr){ 842 + //nothing to do 843 + if( expr == NULL ){ 844 + string = NULL; 845 + return 0; 846 + } 847 + switch( expr->type ){ 848 + case CONSTANT: 849 + return expr_stringify_constant( string, expr->constant ); 850 + case VARIABLE: 851 + return expr_stringify_variable( string, expr->variable ); 852 + case OPERATION: 853 + return expr_stringify_operation( string, expr->operation ); 854 + default: 855 + DEBUG( "Undefined" ); 856 + return 0; 857 + } 858 + } 859 + 860 + 861 + size_t _get_unique_variables_of_expression( const expression_t *expr, mmt_map_t *map ){ 862 + size_t var_count = 0; 863 + void *ptr; 864 + link_node_t *p; 865 + 866 + if( expr == NULL ) return 0; 867 + 868 + switch( expr->type ){ 869 + case VARIABLE: 870 + ptr = mmt_map_set_data( map, expr->variable, expr->variable, NO ); 871 + if( ptr == NULL ) 872 + var_count ++; 873 + break; 874 + case CONSTANT: 875 + break; 876 + case OPERATION: 877 + p = expr->operation->params_list; 878 + //get variables in parameters of the operation 879 + while( p != NULL ){ 880 + var_count += _get_unique_variables_of_expression( (expression_t *) p->data, map ); 881 + p = p->next; 882 + } 883 + break; 884 + } 885 + return var_count; 886 + } 887 + 888 + /** 889 + * Public API 890 + */ 891 + size_t get_unique_variables_of_expression( const expression_t *expr, mmt_map_t **variables_map, bool has_index ){ 892 + size_t var_count = 0; 893 + mmt_map_t *map; 894 + 895 + *variables_map = NULL; 896 + if( expr == NULL ) return 0; 897 + if( has_index == YES ) 898 + map = mmt_map_init( compare_variable_name_and_index ); 899 + else 900 + map = mmt_map_init( compare_variable_name ); 901 + 902 + var_count = _get_unique_variables_of_expression( expr, map ); 903 + 904 + //free the map being allocated 905 + if( var_count == 0 ) 906 + mmt_map_free( map, NO ); 907 + else 908 + *variables_map = map; 909 + 910 + return var_count; 911 + } 912 + /** 913 + * public API 914 + */ 915 + constant_t *evaluate_expression( const expression_t *expr, const constant_t **constants, size_t const_size ){ 916 + constant_t *ret = (constant_t *) mmt_mem_alloc( sizeof( constant_t )); 917 + return ret; 918 + } 919 + 920 + 921 + void expr_update_data_type( expression_t *expr ){ 922 + 923 + } 924 + -
1 + /* 2 + * bool_expression.h 3 + * 4 + * Created on: 21 sept. 2016 5 + * Created by: Huu Nghia NGUYEN <[email protected]> 6 + * 7 + * Boolean expression of an event 8 + */ 9 + 10 + #ifndef SRC_LIB_EXPRESSION_H_ 11 + #define SRC_LIB_EXPRESSION_H_ 12 + 13 + #include <stdlib.h> 14 + #include <stdint.h> 15 + #include <string.h> 16 + 17 + #include "../lib/mmt_lib.h" 18 + #include "message_t.h" 19 + 20 + #define UNKNOWN_REF_INDEX ((uint16_t)UNKNOWN) 21 + 22 + /** 23 + * Constant 24 + */ 25 + typedef struct{ 26 + enum data_type data_type; 27 + /** 28 + * size of the pointer *data 29 + */ 30 + size_t data_size; 31 + void *data; 32 + } constant_t; 33 + 34 + /** 35 + * Convert from data types from MMT_DPI to #data_type that is 36 + * either a MMT_SEC_MSG_DATA_TYPE_NUMERIC or a MMT_SEC_MSG_DATA_TYPE_STRING 37 + */ 38 + int convert_data_type( int mmt_dpi_data_type ); 39 + 40 + /** 41 + * Variable 42 + */ 43 + typedef struct{ 44 + int data_type; 45 + int dpi_type; 46 + //a variable: TCP.SRC or TCP.SRC.1 47 + char *proto, *att; 48 + uint32_t proto_id, att_id;//those are generated from their name: tcp => 354 49 + uint16_t ref_index; 50 + } variable_t; 51 + 52 + 53 + enum operator{ 54 + //boolean operator: or, and 55 + OR, AND, 56 + NOT, 57 + //comparison operators: not equal, equal, ... 58 + NEQ, EQ, GT, GTE, LT, LTE, 59 + //numeric operators: + - * / 60 + ADD, SUB, MUL, DIV, 61 + //a embedded function 62 + FUNCTION 63 + }; 64 + 65 + 66 + /** 67 + * Expression that is x-ary expression: 68 + * that can be a function: name( param_1, param_2, ...) 69 + * or a boolean expression: or( param_1, param_2, ...) 70 + * or a calculation expression: *( param_1, param_2, ... ) 71 + */ 72 + typedef struct operation_struct{ 73 + //type id of return data 74 + enum data_type data_type; 75 + enum operator operator; 76 + 77 + /** 78 + * Representation of operator in plain text 79 + * that is either a function name or an operator 80 + */ 81 + char *name; 82 + /** 83 + * Number of parameters 84 + */ 85 + size_t params_size; 86 + /** 87 + * List of parameters, it data has type expression_t 88 + */ 89 + link_node_t *params_list; 90 + }operation_t; 91 + 92 + /** 93 + * An expression is either a variable, or a constant, or an operation 94 + */ 95 + typedef struct expression_struct{ 96 + enum expression { VARIABLE, CONSTANT, OPERATION} type; 97 + 98 + union{ 99 + constant_t *constant; 100 + variable_t *variable; 101 + operation_t *operation; 102 + }; 103 + struct expression_struct *father; 104 + }expression_t; 105 + 106 + 107 + 108 + /** 109 + * Get a set of variables (distinguished by "proto" and "att") of an expression. 110 + * - Input: 111 + * + expr 112 + * - Output: 113 + * + create and assign a map containing unique variables 114 + * - Return: 115 + * + number of unique variables 116 + */ 117 + size_t get_unique_variables_of_expression( const expression_t *expr, mmt_map_t **variables_map, bool has_ref); 118 + 119 + /** 120 + * Parse a string to get expression 121 + * - Input 122 + * + string: 123 + * + size : size of the string 124 + * - Output 125 + * + expr : that is a pointer points to the result 126 + * - Return 127 + * + O if success 128 + * + error code if fail 129 + * - Note: 130 + * use mmt_free to free the expr when one does not need it anymore 131 + */ 132 + int parse_expression( expression_t **expr, const char *string, size_t size ); 133 + 134 + /** 135 + * Convert an expression to a string 136 + * - Input 137 + * + expr: the expression to be stringified 138 + * - Output 139 + * + string that is a pointer points to the result. 140 + * - Return 141 + * + the size of the result string 142 + * - Note: 143 + * use mmt_free to free the string when one does not need it anymore 144 + */ 145 + size_t expr_stringify_constant( char **string, const constant_t *expr); 146 + size_t expr_stringify_variable( char **string, const variable_t *var); 147 + size_t expr_stringify_operation( char **string, const operation_t *opt ); 148 + size_t expr_stringify_expression( char **string, const expression_t *expr); 149 + 150 + 151 + constant_t *expr_create_a_constant( enum data_type type, size_t data_size, void *data ); 152 + variable_t *expr_create_a_variable( char *proto, char *attr, uint16_t ref_index ); 153 + operation_t *expr_create_an_operation( char *name, enum operator operator ); 154 + expression_t *expr_create_an_expression( enum expression type, void *data ); 155 + 156 + void expr_update_data_type( expression_t *expr ); 157 + /** 158 + * Free a constant 159 + */ 160 + void expr_free_a_constant( constant_t *, bool free_data); 161 + void expr_free_a_variable( variable_t *, bool free_data); 162 + void expr_free_an_operation( operation_t *, bool free_data); 163 + void expr_free_an_expression( expression_t *, bool free_data); 164 + 165 + constant_t *evaluate_expression( const expression_t *expr, const constant_t **constants, size_t const_size ); 166 + 167 + 168 + /** 169 + * Compare 2 variables by its "proto" and "att" 170 + */ 171 + static inline int compare_variable_name( const void *v1, const void *v2){ 172 + variable_t *x = (variable_t *)v1, *y = (variable_t *)v2; 173 + int d1, d2; 174 + ASSERT( v1 != NULL && v2 != NULL, "Error: Variables are NULL" ); 175 + d1 = strcmp( x->proto, y->proto ); 176 + d2 = strcmp( x->att, y->att ); 177 + if( d1 == 0 && d2 == 0 ) 178 + return 0; 179 + else if( d1 != 0 ) 180 + return d1; 181 + else 182 + return d2; 183 + } 184 + 185 + static inline int compare_variable_name_and_index( const void *v1, const void *v2){ 186 + variable_t *x = (variable_t *)v1, *y = (variable_t *)v2; 187 + int d1, d2, d3; 188 + ASSERT( v1 != NULL && v2 != NULL, "Error: Variables are NULL" ); 189 + d1 = strcmp( x->proto, y->proto ); 190 + d2 = strcmp( x->att, y->att ); 191 + d3 = x->ref_index - y->ref_index; 192 + if( d1 == 0 && d2 == 0 && d3 == 0 ) 193 + return 0; 194 + else if( d1 != 0 ) 195 + return d1; 196 + else if( d2 != 0 ) 197 + return d2; 198 + else 199 + return d3; 200 + } 201 + #endif /* SRC_LIB_EXPRESSION_H_ */ 202 +