%{ /* ** Copyright (C) 2005-2007 by Carnegie Mellon University. ** ** @OPENSOURCE_HEADER_START@ ** ** Use of the SILK system and related source code is subject to the terms ** of the following licenses: ** ** GNU Public License (GPL) Rights pursuant to Version 2, June 1991 ** Government Purpose License Rights (GPLR) pursuant to DFARS 252.225-7013 ** ** NO WARRANTY ** ** ANY INFORMATION, MATERIALS, SERVICES, INTELLECTUAL PROPERTY OR OTHER ** PROPERTY OR RIGHTS GRANTED OR PROVIDED BY CARNEGIE MELLON UNIVERSITY ** PURSUANT TO THIS LICENSE (HEREINAFTER THE "DELIVERABLES") ARE ON AN ** "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY ** KIND, EITHER EXPRESS OR IMPLIED AS TO ANY MATTER INCLUDING, BUT NOT ** LIMITED TO, WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE, ** MERCHANTABILITY, INFORMATIONAL CONTENT, NONINFRINGEMENT, OR ERROR-FREE ** OPERATION. CARNEGIE MELLON UNIVERSITY SHALL NOT BE LIABLE FOR INDIRECT, ** SPECIAL OR CONSEQUENTIAL DAMAGES, SUCH AS LOSS OF PROFITS OR INABILITY ** TO USE SAID INTELLECTUAL PROPERTY, UNDER THIS LICENSE, REGARDLESS OF ** WHETHER SUCH PARTY WAS AWARE OF THE POSSIBILITY OF SUCH DAMAGES. ** LICENSEE AGREES THAT IT WILL NOT MAKE ANY WARRANTY ON BEHALF OF ** CARNEGIE MELLON UNIVERSITY, EXPRESS OR IMPLIED, TO ANY PERSON ** CONCERNING THE APPLICATION OF OR THE RESULTS TO BE OBTAINED WITH THE ** DELIVERABLES UNDER THIS LICENSE. ** ** Licensee hereby agrees to defend, indemnify, and hold harmless Carnegie ** Mellon University, its trustees, officers, employees, and agents from ** all claims or demands made against them (and any related losses, ** expenses, or attorney's fees) arising out of, or relating to Licensee's ** and/or its sub licensees' negligent use or willful misuse of or ** negligent conduct or willful misconduct regarding the Software, ** facilities, or other rights or assistance granted by Carnegie Mellon ** University under this License, including, but not limited to, any ** claims of product liability, personal injury, death, damage to ** property, or violation of any laws or regulations. ** ** Carnegie Mellon University Software Engineering Institute authored ** documents are sponsored by the U.S. Department of Defense under ** Contract F19628-00-C-0003. Carnegie Mellon University retains ** copyrights in all material produced under this contract. The U.S. ** Government retains a non-exclusive, royalty-free license to publish or ** reproduce these documents, or allow others to do so, for U.S. ** Government purposes only pursuant to the copyright license under the ** contract clause at 252.227.7013. ** ** @OPENSOURCE_HEADER_END@ */ /* ** Parser for probe configuration file ** */ #define DECLARE_IFMAP_VARIABLES 1 #include "silk.h" RCSIDENT("$SiLK: probeconfparse.y 6821 2007-04-06 16:20:51Z mthomas $"); #include "probeconf.h" #include "probeconfscan.h" #include "silk_site.h" #include "sksite.h" #include "libflowsource.h" /* LOCAL DEFINES AND TYPEDEFS */ /* Set DEBUG to 1 to enable debugging printf messasges, 0 otherwise. * Generally best to leave this commented out so gcc -DDEBUG=1 will * work */ /* #define DEBUG 1 */ /* Verify DEBUG is set */ #ifndef DEBUG # define DEBUG 0 #endif /* For printing messages when DEBUG is non-zero. Use as: * DEBUG_PRINTF(("x is %d\n", x)); * Note ((double parens)) */ #if DEBUG # define DEBUG_PRINTF(x) printf x #else # define DEBUG_PRINTF(x) #endif /* magic value used to denote that a uint16_t---which are stored in * uint32_t's in the parser---has not yet been given a value. */ #define UINT16_NO_VALUE 0x10000 /* 0xFFFF + 1 */ /* to avoid repeatedly creating and destroying number lists, we keep a * pool of free number_lists. this is the size of the pool. */ #define NUMBER_LIST_POOL_CAPACITY 16 /* as NUMBER_LIST_POOL_CAPACITY, except for lists of strings (char*) */ #define STRING_LIST_POOL_CAPACITY 2 /* as NUMBER_LIST_POOL_CAPACITY, except for lists of wildcard ips */ #define WILDCARD_IP_LIST_POOL_CAPACITY 2 /* parsing a probe fills in this struct; then we use it to create an * skProbe. */ typedef struct { /* probe's name: either sensor name or based on type */ char *probe_name; /* empty if probe_name is unique, otherwise sensor name */ char uniq_prefix[3 + SK_MAX_STRLEN_SENSOR]; /* SNMP interface map */ number_list_t *interfaces[NUM_IFMAPS]; /* categorize based on IP blocks */ wildcard_ip_list_t *ipblocks[NUM_IFMAPS]; /* whether the ipblocks are negative blocks */ int negated[NUM_IFMAPS]; /* the list of ISP IPs; for 'forrouter' support */ number_list_t *isp_ip; /* index that should cover all IP-blocks or SNMP-interfaces not * covered by other indexes */ uint32_t remainder; /* priority for probe */ uint32_t priority; /* host to accept from */ name_ip_pair_t accept_from_host; /* IP to bind as when being to listen for connections */ in_addr_t listen_as_host; /* port to bind to when listening for connections */ uint32_t listen_on_port; /* path to unix domain socket to listen on */ char *listen_on_usocket; /* path to regular file to read data from */ char *read_from_file; /* path to directory to poll for newly inserted files */ char *poll_directory; /* number of errors encountered during parsing */ int error_count; /* first *-index seen */ int interface_first_seen; /* first *-ipblock seen */ int ipblock_first_seen; /* sensor id this probe collects for */ sensorID_t sid; /* the type of this probe */ probe_enum_t probe_type; /* the protocol of this probe */ probe_proto_t protocol; /* log flags for this probe */ uint32_t log_flags; } probe_attr_t; /* LOCAL FUNCTIONS */ /* wrappers around an sk_vector_t of integers, of skOctetMap_t*, and * of char* */ static number_list_t *number_list_new(void); static void number_list_append_value(number_list_t *nl, uint32_t value); static string_list_t *string_list_new(void); static void string_list_append_value(string_list_t *sl, char *value); static wildcard_ip_list_t *wildcard_ip_list_new(void); static void wildcard_ip_list_append_value( wildcard_ip_list_t *wipl, skOctetMap_t *value); /* add a new flag to the log flags */ static uint32_t log_flags_add_flag(uint32_t old_val, uint32_t value); /* create a sensor */ static void sensor_new_sensor(char *s, string_list_t *sl); /* functions to set attributes of a probe_attr_t */ static void sensor_probe(char *s); static void probe_name(char *s); static void probe_priority(uint32_t n); static void probe_probe_type(probe_enum_t t); static void probe_protocol(probe_proto_t t); static void probe_isp_ip(number_list_t *nl); static void probe_interface(uint32_t idx, number_list_t *nl); static void probe_ipblock( uint32_t idx, wildcard_ip_list_t *wipl, int negated); static void probe_listen_as_host(uint32_t a); static void probe_listen_on_port(uint32_t n); static void probe_listen_on_usocket(char *s); static void probe_read_from_file(char *s); static void probe_poll_directory(char *s); static void probe_accept_from_host(name_ip_pair_t *a); static void probe_log_flags(uint32_t n); /* functions to convert string input to another form */ static uint32_t parse_int_u16(const char *s); static uint32_t parse_ip_addr(const char *s); static skOctetMap_t *parse_wildcard_addr(const char *s); static name_ip_pair_t *parse_resolvable_host(const char *s); static probe_enum_t parse_probe_type(const char *s); static probe_proto_t parse_protocol(const char *s); static char *parse_sensor_name(const char *s); static uint32_t parse_log_flag(const char *s); /* LOCAL VARIABLES */ /* the size of the free number_list pool and the number of entries in * the pool. */ static number_list_t *number_list_pool[NUMBER_LIST_POOL_CAPACITY]; static int number_list_pool_count = 0; /* the size of the free string_list pool and the number of entries in * the pool. */ static string_list_t *string_list_pool[STRING_LIST_POOL_CAPACITY]; static int string_list_pool_count = 0; /* the size of the free wildcard_ip_list pool and the number of * entries in the pool. */ static wildcard_ip_list_t *wildcard_ip_list_pool[WILDCARD_IP_LIST_POOL_CAPACITY]; static int wildcard_ip_list_pool_count = 0; /* The parser works on a single global set of probe attributes */ static probe_attr_t g_static_probe; static probe_attr_t *p = &g_static_probe; %} %union { char *string; number_list_t *u32_list; string_list_t *str_list; name_ip_pair_t *addr; wildcard_ip_list_t *omap_list; skOctetMap_t *oct_map; uint32_t u32; probe_enum_t p_type; probe_proto_t p_proto; } %token ACCEPT_FROM_HOST_T %token CLASS_T %token COMMA %token EOL %token ISP_IP_T %token LISTEN_AS_HOST_T %token LISTEN_ON_PORT_T %token LISTEN_ON_USOCKET_T %token LOG_FLAGS_T %token PRIORITY_T %token PROBE_NAME_T %token PROBE_TYPE_T %token PROTOCOL_T %token READ_FROM_FILE_T %token POLL_DIRECTORY_T %token REMAINDER_T %token SENSOR_PROBE_T %token SENSOR_T %token ID %token INTERFACE %token IPBLOCK %type int_u16 %type int_u16_list %type resolvable_host %type wildcard_ip_list %type wildcard_ip %type dotted_quad %type dotted_quad_list %type class %type class_list %type probe_type %type probe_protocol %type sensor_name %type syspath %type log_flags_list %type log_flag %% /* * ****************** GRAMMAR RULES *********************************** */ input: input_block | input input_block | error { skAppPrintErr((PARSE_MSG_ERROR "\tMisplaced or unrecognized keyword"), probescan_filename, probescan_line); }; input_block: sensor_defn | probe_defn ; /* * A sensor */ sensor_defn: SENSOR_T sensor_name EOL CLASS_T class_list EOL { probe_end(); sensor_new_sensor($2, $5); }; /* * A probe */ probe_defn: sensor_probe_clause probe_clauses ; probe_clauses: /* empty */ | probe_clauses probe_clause ; probe_clause: probe_name_clause | priority_clause | probe_type_clause | probe_protocol_clause | isp_ip_clause | interface_clause | ipblock_clause | listen_host_clause | listen_port_clause | listen_usocket_clause | read_file_clause | poll_directory_clause | accept_host_clause | log_flags_clause | error { skAppPrintErr((PARSE_MSG_ERROR "\tBad keyword or missing value"), probescan_filename, probescan_line); }; sensor_probe_clause: SENSOR_PROBE_T sensor_name EOL { probe_end(); probe_start(); sensor_probe($2); }; priority_clause: PRIORITY_T int_u16 EOL { probe_priority($2); }; probe_name_clause: PROBE_NAME_T sensor_name EOL { probe_name($2); }; probe_type_clause: PROBE_TYPE_T probe_type EOL { probe_probe_type($2); }; probe_protocol_clause: PROTOCOL_T probe_protocol EOL { probe_protocol($2); }; isp_ip_clause: ISP_IP_T dotted_quad_list EOL { probe_isp_ip($2); }; interface_clause: INTERFACE int_u16_list EOL { probe_interface($1, $2); } | INTERFACE REMAINDER_T EOL { probe_interface($1, NULL); }; ipblock_clause: IPBLOCK wildcard_ip_list EOL { probe_ipblock($1, $2, 0); } | IPBLOCK REMAINDER_T EOL { probe_ipblock($1, NULL, 0); }; listen_host_clause: LISTEN_AS_HOST_T dotted_quad EOL { probe_listen_as_host($2); }; listen_port_clause: LISTEN_ON_PORT_T int_u16 EOL { probe_listen_on_port($2); }; listen_usocket_clause: LISTEN_ON_USOCKET_T syspath EOL { probe_listen_on_usocket($2); }; read_file_clause: READ_FROM_FILE_T syspath EOL { probe_read_from_file($2); }; poll_directory_clause: POLL_DIRECTORY_T syspath EOL { probe_poll_directory($2); }; accept_host_clause: ACCEPT_FROM_HOST_T resolvable_host EOL { probe_accept_from_host($2); }; log_flags_clause: LOG_FLAGS_T log_flags_list EOL { probe_log_flags($2); }; /* * Parse a list of 16-bit integers. Returns as number_list_t* */ int_u16_list: int_u16 { number_list_t *nl = number_list_new(); number_list_append_value(nl, $1); $$ = nl; } | int_u16_list int_u16 { number_list_append_value($1, $2); $$ = $1; } | int_u16_list COMMA int_u16 { number_list_append_value($1, $3); $$ = $1; }; int_u16: ID { $$ = parse_int_u16($1); }; /* * Create a string_list from a list of class names */ class_list: class { string_list_t *sl = string_list_new(); string_list_append_value(sl, $1); $$ = sl; } | class_list class { string_list_append_value($1, $2); $$ = $1; } | class_list COMMA class { string_list_append_value($1, $3); $$ = $1; }; class: ID { $$ = strdup($1); }; /* * Parse a list of wildcard IP addresses. Return as an * octetmap_list_t* */ wildcard_ip_list: wildcard_ip { wildcard_ip_list_t *wipl = wildcard_ip_list_new(); wildcard_ip_list_append_value(wipl, $1); $$ = wipl; } | wildcard_ip_list wildcard_ip { wildcard_ip_list_append_value($1, $2); $$ = $1; } | wildcard_ip_list COMMA wildcard_ip { wildcard_ip_list_append_value($1, $3); $$ = $1; }; wildcard_ip: ID { $$ = parse_wildcard_addr($1); }; /* * Parse a list of dotted-quad IP addresses. Addresses do not * have to resolve. Return as a number_list_t* */ dotted_quad_list: dotted_quad { number_list_t *nl = number_list_new(); number_list_append_value(nl, $1); $$ = nl; } | dotted_quad_list dotted_quad { number_list_append_value($1, $2); $$ = $1; } | dotted_quad_list COMMA dotted_quad { number_list_append_value($1, $3); $$ = $1; }; dotted_quad: ID { $$ = parse_ip_addr($1); }; /* * Parse a single resolvable hostname. */ resolvable_host: ID { $$ = parse_resolvable_host($1); }; /* * Parse probe type */ probe_type: ID { $$ = parse_probe_type($1); }; /* * Parse probe protocol */ probe_protocol: ID { $$ = parse_protocol($1); }; /* * Sensor and/or probe name; just strdup() it for now. */ sensor_name: ID { $$ = parse_sensor_name($$); }; /* * System path (file, directory, etc); just strdup() it for now. */ syspath: ID { $$ = strdup($1); }; /* * Parse log flags: either a single flag or a list of flags */ log_flags_list: log_flag { $$ = $1; } | log_flags_list log_flag { uint32_t n = log_flags_add_flag($1, $2); $$ = n; } | log_flags_list COMMA log_flag { uint32_t n = log_flags_add_flag($1, $3); $$ = n; }; log_flag: ID { $$ = parse_log_flag($1); }; %% /* * ******************* SUPPORTING CODE ****************************** */ /* * ***** Number Lists *********************************************** * * * number_list, a sk_vector_t of uint32_t's */ /* get a new number_list from the free-pool; if pool is empty, create * a new one */ static number_list_t *number_list_new(void) { number_list_t *nl; /* if there are any in the pool, return one. Otherwise create one. */ if (number_list_pool_count) { --number_list_pool_count; nl = number_list_pool[number_list_pool_count]; skVectorClear(nl); } else { nl = skVectorNew(sizeof(uint32_t)); } return nl; } /* add the number_list to the free-pool. If the pool is full, just * destroy the number_list. */ static void number_list_destroy(number_list_t *nl) { /* If the pool is full, destroy the list we were handed; otherwise * add it to the pool. */ if (number_list_pool_count == NUMBER_LIST_POOL_CAPACITY) { skVectorDestroy(nl); } else { number_list_pool[number_list_pool_count] = nl; ++number_list_pool_count; } } /* remove all number_list's from the pool and destroy them */ static void number_list_pool_empty(void) { int i; for (i = 0; i < number_list_pool_count; ++i) { skVectorDestroy(number_list_pool[i]); } number_list_pool_count = 0; } /* append the value to the number_list */ static void number_list_append_value(number_list_t *nl, uint32_t value) { skVectorAppendValue(nl, &value); } /* get the number of entries in the number_list */ static size_t number_list_entries(number_list_t *nl) { return skVectorGetCount(nl); } /* get the value at the specified position */ static uint32_t number_list_get_value(number_list_t *nl, size_t position) { uint32_t val; skVectorGetValue(&val, nl, position); return val; } /* * ***** String Lists *********************************************** * * * string_list, a sk_vector_t of char*'s, where each char* is a strdup() */ /* get a new string_list from the free-pool; if pool is empty, create * a new one */ static string_list_t *string_list_new(void) { string_list_t *sl; /* if there are any in the pool, return one. Otherwise create one. */ if (string_list_pool_count) { --string_list_pool_count; sl = string_list_pool[string_list_pool_count]; skVectorClear(sl); } else { sl = skVectorNew(sizeof(char*)); } return sl; } /* add the string_list to the free-pool. If the pool is full, just * destroy the string_list. */ static void string_list_destroy(string_list_t *sl) { size_t i, c; char *s; /* free the strings in the vector */ c = skVectorGetCount(sl); for (i = 0; i < c; ++i) { skVectorGetValue(&s, sl, i); if (s != NULL) { free(s); } } /* If the pool is full, destroy the list we were handed; otherwise * add it to the pool. */ if (string_list_pool_count == STRING_LIST_POOL_CAPACITY) { skVectorDestroy(sl); } else { string_list_pool[string_list_pool_count] = sl; ++string_list_pool_count; } } /* remove all string_list's from the pool and destroy them */ static void string_list_pool_empty(void) { int i; for (i = 0; i < string_list_pool_count; ++i) { skVectorDestroy(string_list_pool[i]); } string_list_pool_count = 0; } /* append the value to the string_list */ static void string_list_append_value(string_list_t *sl, char *value) { skVectorAppendValue(sl, &value); } /* get the string of entries in the string_list */ static size_t string_list_entries(string_list_t *sl) { return skVectorGetCount(sl); } /* get the value at the specified position */ static const char* string_list_get_value(string_list_t *sl, size_t position) { char *val; skVectorGetValue(&val, sl, position); return val; } /* * ***** Wildcard IP Lists ****************************************** * * * wildcard_ip_list, an sk_vector_t of skOctetMap_t's */ /* get a new wildcard_ip_list from the free-pool; if pool is empty, * create a new one */ static wildcard_ip_list_t *wildcard_ip_list_new(void) { wildcard_ip_list_t *wipl; /* if there are any in the pool, return one. Otherwise create one. */ if (wildcard_ip_list_pool_count) { --wildcard_ip_list_pool_count; wipl = wildcard_ip_list_pool[wildcard_ip_list_pool_count]; skVectorClear(wipl); } else { wipl = skVectorNew(sizeof(skOctetMap_t*)); } return wipl; } /* add the wildcard_ip_list to the free-pool. If the pool is full, * just destroy the wildcard_ip_list. */ static void wildcard_ip_list_destroy(wildcard_ip_list_t *wipl) { size_t i, c; skOctetMap_t *omap; /* free the octet-maps in the vector */ c = skVectorGetCount(wipl); for (i = 0; i < c; ++i) { skVectorGetValue(&omap, wipl, i); if (omap != NULL) { free(omap); } } /* If the pool is full, destroy the list we were handed; otherwise * add it to the pool. */ if (wildcard_ip_list_pool_count == WILDCARD_IP_LIST_POOL_CAPACITY) { skVectorDestroy(wipl); } else { wildcard_ip_list_pool[wildcard_ip_list_pool_count] = wipl; ++wildcard_ip_list_pool_count; } } /* remove all wildcard_ip_list's from the pool and destroy them */ static void wildcard_ip_list_pool_empty(void) { int i; for (i = 0; i < wildcard_ip_list_pool_count; ++i) { skVectorDestroy(wildcard_ip_list_pool[i]); } wildcard_ip_list_pool_count = 0; } /* append the value to the wildcard_ip_list */ static void wildcard_ip_list_append_value( wildcard_ip_list_t *wipl, skOctetMap_t *value) { skVectorAppendValue(wipl, &value); } /* get the wildcard_ip of entries in the wildcard_ip_list */ static size_t wildcard_ip_list_entries(wildcard_ip_list_t *wipl) { return skVectorGetCount(wipl); } /* get the value at the specified position */ static skOctetMap_t *wildcard_ip_list_get_value( wildcard_ip_list_t *wipl, size_t position) { skOctetMap_t *omap; skVectorGetValue(&omap, wipl, position); return omap; } /* * ***** Sensors **************************************************** */ /* * sensor_new_sensor(name, class_list); * * Create sensor 'name' that belongs to classes 'class_list'. */ static void sensor_new_sensor(char *s, string_list_t *sl) { int rv = sksiteCreateTemporarySensor(s, (sk_vector_t*)sl); if (rv > 0) { /* invalid class */ skAppPrintErr((PARSE_MSG_ERROR "\tDo not recognize class name '%s'"), probescan_filename, probescan_line, string_list_get_value(sl, rv-1)); } else if (rv < 0) { switch (rv) { case -2: /* invalid sensor name */ skAppPrintErr((PARSE_MSG_ERROR "\tSensor name '%s' is not of correct form"), probescan_filename, probescan_line, s); break; case -3: /* duplicate sensor */ skAppPrintErr((PARSE_MSG_ERROR "\tA sensor named '%s' already exists"), probescan_filename, probescan_line, s); break; case -4: /* too many or too few classes */ if (string_list_entries(sl) == 0) { skAppPrintErr((PARSE_MSG_ERROR "\tNo classes given for test sensor '%s'"), probescan_filename, probescan_line, s); } else { skAppPrintErr((PARSE_MSG_ERROR "\tToo many classes given " "for test sensor '%s'"), probescan_filename, probescan_line, s); } break; case -1: /* bad input */ default: skAppPrintErr((PARSE_MSG_ERROR "\tUnexpected value from sksite: %d"), probescan_filename, probescan_line, rv); break; } } if (s) { free(s); s = NULL; } if (sl) { string_list_destroy(sl); } } /* * ***** Probes ***************************************************** */ /* print the probe attributes -- for debugging */ static void probe_print(void) { #if DEBUG size_t if_count; size_t isp_count; size_t i, j; DEBUG_PRINTF((("Got a probe (%d errors)\n" "\t probe_name = '%s'\n" "\t sensor_for_probe = '%u'\n" "\t priority = '%u'\n" "\t probe_type = '%u'\n" "\t protocol = '%u'\n"), p->error_count, p->probe_name, p->sid, p->priority, p->probe_type, p->protocol)); isp_count = ((p->isp_ip != NULL) ? number_list_entries(p->isp_ip) : 0); DEBUG_PRINTF(("\t isp_count = '%u'", (unsigned int)isp_count)); if (isp_count > 0) { for (i = 0; i < isp_count; ++i) { uint32_t val = number_list_get_value(p->isp_ip, i); DEBUG_PRINTF(("%s%u(%s)", ((0 == i) ? " [" : ","), val, num2dot(val))); } DEBUG_PRINTF(("]")); } DEBUG_PRINTF(("\n")); for (i = 0; i < NUM_IFMAPS; ++i) { if_count = ((p->interfaces[i] != NULL) ? number_list_entries(p->interfaces[i]) : 0); DEBUG_PRINTF(("\t interface_count[%lu] = '%lu'", i, if_count)); if (if_count > 0) { for (j = 0; j < if_count; ++j) { DEBUG_PRINTF(("%s%u", ((0 == j) ? " [" : ","), number_list_get_value(p->interfaces[i], j))); } DEBUG_PRINTF(("]")); } DEBUG_PRINTF(("\n")); } DEBUG_PRINTF((("\t listen_as_host = '%u' '%s'\n" "\t listen_on_port = '%u'\n" "\t listen_on_usocket = '%s'\n" "\t read_from_file = '%s'\n" "\t poll_directory = '%s'\n" "\t log_flags = '%u'\n"), p->listen_as_host, num2dot(p->listen_as_host), p->listen_on_port, (p->listen_on_usocket ? p->listen_on_usocket : "NULL"), (p->read_from_file ? p->read_from_file : "NULL"), (p->poll_directory ? p->poll_directory : "NULL"), p->log_flags)); DEBUG_PRINTF((("\t accept_from_host = '%s' '%u' '%s'\n"), (p->accept_from_host.name ? p->accept_from_host.name : "NULL"), p->accept_from_host.ip, num2dot(p->accept_from_host.ip))); #endif /* DEBUG */ } /* Take all the data on the global probe_attr_t and use it to create a * new skProbe. */ static void probe_attr_to_sk_probe(void) { probe_def_t *probe = NULL; int rv = 0; size_t i; rv = skProbeCreate(&probe); if (rv) { goto END; } rv = skProbeSetSensor(probe, p->sid); if (rv) { goto END; } rv = skProbeSetName(probe, p->probe_name); if (rv) { goto END; } if (p->priority != UINT16_NO_VALUE) { rv = skProbeSetPriority(probe, p->priority); if (rv) { goto END; } } if (p->probe_type != PROBE_ENUM_INVALID) { rv = skProbeSetType(probe, p->probe_type); if (rv) { goto END; } } if (p->protocol != PROBE_PROTO_UNSET) { rv = skProbeSetProtocol(probe, p->protocol); if (rv) { goto END; } } if (p->isp_ip) { rv = skProbeSetIspIps(probe, p->isp_ip); if (rv) { goto END; } } if (p->log_flags != UINT16_NO_VALUE) { rv = skProbeSetLogFlags(probe, p->log_flags); if (rv) { goto END; } } for (i = 0; i < NUM_IFMAPS; ++i) { if (p->interfaces[i]) { rv = skProbeSetInterfaces(probe, p->interfaces[i], i); if (rv) { goto END; } } else if (p->ipblocks[i]) { rv = skProbeSetIpBlock(probe, p->ipblocks[i], p->negated[i], i); if (rv) { goto END; } /* the probe is now managing the skOctetMap_t's; clear the * vector of ipblocks so the maps do not get * deallocated. */ skVectorClear(p->ipblocks[i]); } } if (p->remainder != UINT16_NO_VALUE) { if (p->ipblock_first_seen != UINT16_NO_VALUE) { rv = skProbeSetIpBlockRemainingIps(probe, p->remainder); } else { assert(p->interface_first_seen != UINT16_NO_VALUE); rv = skProbeSetInterfaceToRemainder(probe, p->remainder); } if (rv) { goto END; } } if (p->listen_as_host) { rv = skProbeSetListenAsAddr(probe, p->listen_as_host); if (rv) { goto END; } } if (p->listen_on_port != UINT16_NO_VALUE) { rv = skProbeSetListenOnPort(probe, p->listen_on_port); if (rv) { goto END; } } if (p->listen_on_usocket) { rv = skProbeSetListenOnUnixDomainSocket(probe, p->listen_on_usocket); if (rv) { goto END; } } if (p->read_from_file) { rv = skProbeSetFileSource(probe, p->read_from_file); if (rv) { goto END; } } if (p->poll_directory) { rv = 0 /* skProbeSetPollDirectory(probe, p->poll_directory) */; if (rv) { goto END; } } if (p->accept_from_host.name) { rv = skProbeSetAcceptFromHost(probe, p->accept_from_host.name, p->accept_from_host.ip); if (rv) { goto END; } } rv = probeConfProbeVerify(probe); END: if ((rv != 0) && (NULL != probe)) { ++g_probe_err; skProbeDestroy(&probe); } } /* This should be called just before starting a new probe and when we * finish reading a file (to complete the last probe). It will try to * convert the data from config file---which is stored in the global * probe_attr_t---to an skProbe, and then it will free() all memory * the parser has allocated for this probe_attr_t */ void probe_end(void) { int i; if (p->probe_name != NULL) { probe_print(); if (p->error_count == 0) { probe_attr_to_sk_probe(); } } /* Free everything we allocated */ if (p->probe_name) { free(p->probe_name); } if (p->isp_ip) { number_list_destroy(p->isp_ip); } for (i = 0; i < NUM_IFMAPS; ++i) { if (p->interfaces[i]) { number_list_destroy(p->interfaces[i]); } } if (p->listen_on_usocket) { free(p->listen_on_usocket); } if (p->accept_from_host.name) { free(p->accept_from_host.name); } memset(p, 0, sizeof(probe_attr_t)); } /* Begin a new probe by setting the memory of the global probe_attr_t * into its initial state. */ void probe_start(void) { memset(p, 0, sizeof(probe_attr_t)); p->priority = UINT16_NO_VALUE; p->probe_type = PROBE_ENUM_INVALID; p->protocol = PROBE_PROTO_UNSET; p->listen_on_port = UINT16_NO_VALUE; p->sid = SK_INVALID_SENSOR; p->remainder = UINT16_NO_VALUE; p->interface_first_seen = UINT16_NO_VALUE; p->ipblock_first_seen = UINT16_NO_VALUE; p->log_flags = UINT16_NO_VALUE; } /* * sensor_probe(sensor_name); * * Start a new probe that belongs to the sensor 'sensor_name'. Set * the probe's name to 'sensor_name' as well. */ static void sensor_probe(char *s) { /* see if this is a defined sensor */ p->sid = sksiteSensorLookup(s); if (p->sid == SK_INVALID_SENSOR) { skAppPrintErr((PARSE_MSG_ERROR "\tName '%s' is not the name of a sensor"), probescan_filename, probescan_line, s); ++p->error_count; } /* Set the probe's name to 's' */ p->probe_name = s; } /* * probe_name(probe_name); * * Set the name of the global probe to 'probe_name'. */ static void probe_name(char *s) { size_t len; /* name is legal? */ if (0 != sksiteSensorNameIsLegal(s)) { /* message already printed */ ++p->error_count; } if (p->probe_name) { free(p->probe_name); } /* store info */ p->probe_name = s; /* set the unique prefix used when printing error messages, but * don't set it if the probe-name is the same as the probe's * sensor */ if (p->sid != SK_INVALID_SENSOR && sksiteSensorLookup(s) != p->sid) { /* probe's name is different than sensor's name */ if ( sksiteSensorExists(p->sid) ) { sksiteSensorGetName(p->uniq_prefix, sizeof(p->uniq_prefix), p->sid); len = strlen(p->uniq_prefix); assert(len <= SK_MAX_STRLEN_SENSOR); p->uniq_prefix[len] = '/'; p->uniq_prefix[len+1] = '\0'; } } } /* * probe_priority(n); * * Set the priority of the global probe to n. */ static void probe_priority(uint32_t n) { /* see if parser got valid value(s) */ if (n == UINT16_NO_VALUE) { /* error msg printed by parser */ ++p->error_count; return; } /* check for value out of range */ if (n > PROBE_MAX_PRIORITY) { skAppPrintErr((PARSE_MSG_ERROR "\tPriority %u too large; use 0 <= n <= %d"), probescan_filename, probescan_line, n, PROBE_MAX_PRIORITY); ++p->error_count; return; } /* warn on overwrite */ if (p->priority != UINT16_NO_VALUE) { skAppPrintErr((PARSE_MSG_WARN "\tOverwriting previous %s value for probe %s%s"), probescan_filename, probescan_line, probescan_clause, p->uniq_prefix, p->probe_name); } /* store info */ p->priority = n; } /* * probe_probe_type(t); * * Set the probe-type of the global probe to 't'. */ static void probe_probe_type(probe_enum_t t) { /* see if parser got valid value(s) */ if (t == PROBE_ENUM_INVALID) { /* error msg printed by parser */ ++p->error_count; return; } /* warn on overwrite */ if (p->probe_type != PROBE_ENUM_INVALID) { skAppPrintErr((PARSE_MSG_WARN "\tOverwriting previous %s value for probe %s%s"), probescan_filename, probescan_line, probescan_clause, p->uniq_prefix, p->probe_name); } /* store info */ p->probe_type = t; } /* * probe_protocol(t); * * Set the probe-type of the global probe to 't'. */ static void probe_protocol(probe_proto_t t) { /* see if parser got valid value(s) */ if (t == PROBE_PROTO_UNSET) { /* error msg printed by parser */ ++p->error_count; return; } /* warn on overwrite */ if (p->protocol != PROBE_PROTO_UNSET) { skAppPrintErr((PARSE_MSG_WARN "\tOverwriting previous %s value for probe %s%s"), probescan_filename, probescan_line, probescan_clause, p->uniq_prefix, p->probe_name); } /* store info */ p->protocol = t; } /* * probe_isp_ip(list); * * Set the isp-ip's on the global probe to 'list'. */ static void probe_isp_ip(number_list_t *nl) { size_t i; size_t count = number_list_entries(nl); uint32_t val; /* see if parser got valid value(s) */ for (i = 0; i < count; ++i) { val = number_list_get_value(nl, i); if (val == 0) { ++p->error_count; return; } } /* warn on overwrite */ if (p->isp_ip != NULL) { skAppPrintErr((PARSE_MSG_WARN "\tOverwriting previous %s value for probe %s%s"), probescan_filename, probescan_line, probescan_clause, p->uniq_prefix, p->probe_name); number_list_destroy(p->isp_ip); } /* store info */ p->isp_ip = nl; } /* * probe_interface(idx, list); * * Set the ifmap-interface list indexed by 'idx' on the global * probe to 'list'. * * If 'list' is NULL, set the ifmap-interface list to all the * indexes NOT listed on other interfaces---set it to the * 'remainder' of the interfaces. */ static void probe_interface(uint32_t idx, number_list_t *nl) { size_t i; size_t count; uint32_t val; assert(idx < NUM_IFMAPS); if (nl) { count = number_list_entries(nl); /* see if parser got valid value(s) */ for (i = 0; i < count; ++i) { val = number_list_get_value(nl, i); if (val == UINT16_NO_VALUE) { ++p->error_count; return; } } } /* cannot set interface when ip-block already set */ if (p->ipblock_first_seen != UINT16_NO_VALUE) { skAppPrintErr((PARSE_MSG_ERROR "\tCannot set %s for probe %s%s because\n" "\t%s-index was previously set"), probescan_filename, probescan_line, probescan_clause, p->uniq_prefix, p->probe_name, ifmap_group_id_name[p->ipblock_first_seen]); ++p->error_count; return; } /* only one interface may contain the remainding SNMP values */ if ((nl == NULL) && (p->remainder != UINT16_NO_VALUE)) { if (p->remainder == idx) { /* repeated: "foo-index remainder". ignore */ return; } skAppPrintErr((PARSE_MSG_ERROR "\tCannot set %s for probe %s%s because\n" "\tthe %s interface has already claimed the" "remaining SNMP values"), probescan_filename, probescan_line, probescan_clause, p->uniq_prefix, p->probe_name, ifmap_group_id_name[p->remainder]); ++p->error_count; return; } /* warn on overwrite */ if (p->interfaces[idx] != NULL) { skAppPrintErr((PARSE_MSG_WARN "\tOverwriting previous %s value for probe %s%s"), probescan_filename, probescan_line, probescan_clause, p->uniq_prefix, p->probe_name); number_list_destroy(p->interfaces[idx]); p->interfaces[idx] = NULL; } else if (p->remainder == idx) { skAppPrintErr((PARSE_MSG_WARN "\tOverwriting previous %s value for probe %s%s"), probescan_filename, probescan_line, probescan_clause, p->uniq_prefix, p->probe_name); p->remainder = UINT16_NO_VALUE; } /* store info */ if (nl) { p->interfaces[idx] = nl; } else { p->remainder = idx; } if (p->interface_first_seen == UINT16_NO_VALUE) { p->interface_first_seen = idx; } } /* * probe_ipblock(idx, ip_list, negated); * * When 'ip_list' is NULL, set a flag for this 'idx' noting that * its interface-ipblock list should be set to any IP addresses not * covered by other IP blocks. * * When 'negated' is 0, set the interface-ipblocks for the * 'idx' interface of the global probe to 'ip_list'. * * When negated is non-zero, set the interface-ipblocks for the * 'idx' interface of the global probe to the inverse of 'ip_list'. */ static void probe_ipblock( uint32_t idx, wildcard_ip_list_t *wipl, int negated) { size_t i; size_t count; skOctetMap_t *val; assert(idx < NUM_IFMAPS); if (wipl) { count = wildcard_ip_list_entries(wipl); /* see if parser got valid value(s) */ for (i = 0; i < count; ++i) { val = wildcard_ip_list_get_value(wipl, i); if (val == NULL) { ++p->error_count; return; } } } /* cannot set ip-block when interface already set */ if (p->interface_first_seen != UINT16_NO_VALUE) { skAppPrintErr((PARSE_MSG_ERROR "\tCannot set %s for probe %s%s because\n" "\t%s-index was previously set"), probescan_filename, probescan_line, probescan_clause, p->uniq_prefix, p->probe_name, ifmap_group_id_name[p->interface_first_seen]); ++p->error_count; return; } /* only one interface may contain the remainding IPs */ if ((wipl == NULL) && (p->remainder != UINT16_NO_VALUE)) { if (p->remainder == idx) { /* repeated: "foo-ipblock remainder". ignore */ return; } skAppPrintErr((PARSE_MSG_ERROR "\tCannot set %s for probe %s%s because\n" "\tthe %s interface has already claimed the" "remaining IP space"), probescan_filename, probescan_line, probescan_clause, p->uniq_prefix, p->probe_name, ifmap_group_id_name[p->remainder]); ++p->error_count; return; } /* warn on overwrite */ if (p->ipblocks[idx] != NULL) { skAppPrintErr((PARSE_MSG_WARN "\tOverwriting previous %s value for probe %s%s"), probescan_filename, probescan_line, probescan_clause, p->uniq_prefix, p->probe_name); wildcard_ip_list_destroy(p->ipblocks[idx]); p->ipblocks[idx] = NULL; } else if (p->remainder == idx) { skAppPrintErr((PARSE_MSG_WARN "\tOverwriting previous %s value for probe %s%s"), probescan_filename, probescan_line, probescan_clause, p->uniq_prefix, p->probe_name); p->remainder = UINT16_NO_VALUE; } /* store info */ if (wipl) { p->negated[idx] = negated; p->ipblocks[idx] = wipl; } else { p->remainder = idx; } if (p->ipblock_first_seen == UINT16_NO_VALUE) { p->ipblock_first_seen = idx; } } /* * probe_listen_as_host(n); * * Set the global probe to listen for flows as the host IP 'n'. */ static void probe_listen_as_host(uint32_t n) { /* see if parser got valid value(s) */ if (n == 0) { /* error msg printed by parser */ ++p->error_count; return; } /* warn on overwrite */ if (p->listen_as_host != 0) { skAppPrintErr((PARSE_MSG_WARN "\tOverwriting previous %s value for probe %s%s"), probescan_filename, probescan_line, probescan_clause, p->uniq_prefix, p->probe_name); } /* store info */ p->listen_as_host = n; } /* * probe_listen_on_port(n); * * Set the global probe to listen for flows on port 'n'. */ static void probe_listen_on_port(uint32_t n) { /* see if parser got valid value(s) */ if (n == UINT16_NO_VALUE) { /* error msg printed by parser */ ++p->error_count; return; } /* warn on overwrite */ if (p->listen_on_port != UINT16_NO_VALUE) { skAppPrintErr((PARSE_MSG_WARN "\tOverwriting previous %s value for probe %s%s"), probescan_filename, probescan_line, probescan_clause, p->uniq_prefix, p->probe_name); } /* store info */ p->listen_on_port = n; } /* * probe_listen_on_usocket(s); * * Set the global probe to listen for flows on the unix domain socket 's'. */ static void probe_listen_on_usocket(char *s) { /* warn on overwrite */ if (p->listen_on_usocket != NULL) { skAppPrintErr((PARSE_MSG_WARN "\tOverwriting previous %s value for probe %s%s"), probescan_filename, probescan_line, probescan_clause, p->uniq_prefix, p->probe_name); } /* store info; we already made a copy of 's' */ p->listen_on_usocket = s; } /* * probe_read_from_file(s); * * Set the global probe to read flows from the file 's'. */ static void probe_read_from_file(char *s) { /* warn on overwrite */ if (p->read_from_file != NULL) { skAppPrintErr((PARSE_MSG_WARN "\tOverwriting previous %s value for probe %s%s"), probescan_filename, probescan_line, probescan_clause, p->uniq_prefix, p->probe_name); } /* store info; we already made a copy of 's' */ p->read_from_file = s; } /* * probe_poll_directory(s); * * Set the global probe to read flows from files that appear in the * directory 's'. */ static void probe_poll_directory(char *s) { /* warn on overwrite */ if (p->poll_directory != NULL) { skAppPrintErr((PARSE_MSG_WARN "\tOverwriting previous %s value for probe %s%s"), probescan_filename, probescan_line, probescan_clause, p->uniq_prefix, p->probe_name); } /* store info; we already made a copy of 's' */ p->poll_directory = s; } /* * probe_accept_from_host(a); * * Set the global probe to accept data from the host a. */ static void probe_accept_from_host(name_ip_pair_t *a) { /* see if parser got valid value(s) */ if (a->ip == 0) { /* error msg printed by parser */ ++p->error_count; if (a->name) { free(a->name); } } else { /* warn on overwrite */ if (p->accept_from_host.name != NULL) { skAppPrintErr((PARSE_MSG_WARN "\tOverwriting previous %s value for probe %s%s"), probescan_filename, probescan_line, probescan_clause, p->uniq_prefix, p->probe_name); free(p->accept_from_host.name); } /* store info */ p->accept_from_host.ip = a->ip; p->accept_from_host.name = a->name; } a->name = NULL; } /* * probe_log_flags(n); * * Set the log flags on the probe to 'n'; */ static void probe_log_flags(uint32_t n) { /* warn on overwrite */ if (p->log_flags != UINT16_NO_VALUE) { skAppPrintErr((PARSE_MSG_WARN "\tOverwriting previous %s value for probe %s%s"), probescan_filename, probescan_line, probescan_clause, p->uniq_prefix, p->probe_name); } if (n == UINT16_NO_VALUE) { /* some error in parsing log flags */ ++p->error_count; } /* store value */ p->log_flags = n; } /* * val = parse_int_u16(s); * * Parse 's' as a integer from 0 to 0xFFFF inclusive. */ static uint32_t parse_int_u16(const char *s) { uint32_t num; int rv; rv = skStringParseUint32(&num, s, 0, 0xFFFF); if (rv == 0) { /* everything is good. */ } else if (rv == -12) { skAppPrintErr((PARSE_MSG_ERROR "\tValue (%s) for %s is too large; use 0 <= n < 65536"), probescan_filename, probescan_line, s, probescan_clause); num = UINT16_NO_VALUE; } else { skAppPrintErr((PARSE_MSG_ERROR "\tUnable to parse %s value '%s'"), probescan_filename, probescan_line, probescan_clause, s); num = UINT16_NO_VALUE; } return num; } /* * octet_map = parse_wildcard_addr(ip); * * Parse 'ip' as an IP address block in SiLK wildcard notation. * Because the scanner does not allow comma as part of an ID, we * will never see things like "10.20.30.40,50". * * Return the set of ips as an skOctetMap_t*, or NULL on error. */ static skOctetMap_t *parse_wildcard_addr(const char *s) { skOctetMap_t *omap; omap = malloc(sizeof(skOctetMap_t)); if (!omap) { return NULL; } if (skStringParseWildcardIP(omap, s)) { skAppPrintErr((PARSE_MSG_ERROR "\tCannot parse IP address block '%s'"), probescan_filename, probescan_line, s); free(omap); return NULL; } return omap; } /* * ip = parse_ip_addr(ip); * * Parse 'ip' as an IP address. Return the IP. */ static uint32_t parse_ip_addr(const char *s) { uint32_t num; if (skStringParseIP(&num, s)) { skAppPrintErr((PARSE_MSG_ERROR "\tCannot parse IP addresses '%s'"), probescan_filename, probescan_line, s); num = 0; } return num; } /* * name_ip = parse_resolvable_host(name); * * Parse 'name' as a resolvable host, i.e., pass 'name' to * gethostbyname(). Returns a pointer to a static struct that * contains the name and the IP address. */ static name_ip_pair_t *parse_resolvable_host(const char *s) { static name_ip_pair_t a = {(in_addr_t)0, NULL}; struct hostent *he; in_addr_t addr; if (a.name) { free(a.name); } memset(&a, 0, sizeof(name_ip_pair_t)); a.name = strdup(s); he = gethostbyname(s); if (he == NULL || he->h_length != sizeof(in_addr_t)) { skAppPrintErr((PARSE_MSG_ERROR "\tUnable to resolve %s value '%s'"), probescan_filename, probescan_line, probescan_clause, s); } else { memcpy(&addr, he->h_addr, sizeof(in_addr_t)); a.ip = ntohl(addr); } return &a; } /* * type = parse_probe_type(s); * * Parse 's' as the type of a probe. Return the type. */ static probe_enum_t parse_probe_type(const char *s) { probe_enum_t type; type = skProbetypeNameToEnum(s); if (type == PROBE_ENUM_INVALID) { skAppPrintErr((PARSE_MSG_ERROR "\tDo not recognize probe type '%s'"), probescan_filename, probescan_line, s); } return type; } /* * proto = parse_protocol(s); * * Parse 's' as a protocol. Return the protocol. */ static probe_proto_t parse_protocol(const char *s) { probe_proto_t proto = PROBE_PROTO_UNSET; uint32_t num; if (isdigit((int)*s)) { /* parse as a number */ if (skStringParseUint32(&num, s, 0, 255)) { skAppPrintErr((PARSE_MSG_ERROR "\tInvalid protocol value '%s'"), probescan_filename, probescan_line, s); } else { switch (num) { case 6: proto = PROBE_PROTO_TCP; break; case 17: proto = PROBE_PROTO_UDP; break; case 132: proto = PROBE_PROTO_SCTP; break; default: skAppPrintErr((PARSE_MSG_ERROR "\tInvalid protocol value '%u'"), probescan_filename, probescan_line, num); break; } } } else { proto = skProbeNameToProtocol(s); if (proto == PROBE_PROTO_UNSET) { skAppPrintErr((PARSE_MSG_ERROR "\tDo not recognize protocol '%s'"), probescan_filename, probescan_line, s); } } return proto; } /* * sensor_name = parse_sensor_name(s); * * Complain if 's' is an illegal sensor name. Return a copy of s. */ static char *parse_sensor_name(const char *s) { int rv; rv = sksiteSensorNameIsLegal(s); if (rv != 0) { if (rv > 0) { skAppPrintErr((PARSE_MSG_ERROR "\tSensor name '%s'" " contains the illegal character '%c'"), probescan_filename, probescan_line, s, s[rv-1]); } else if (rv == -1) { skAppPrintErr((PARSE_MSG_ERROR "\tSensor name '%s'" " is too short."), probescan_filename, probescan_line, s); } else if (rv == -2) { skAppPrintErr((PARSE_MSG_ERROR "\tSensor name '%s' " " is too long; only %d characters permitted."), probescan_filename, probescan_line, s, SK_MAX_STRLEN_SENSOR); } } return strdup(s); } /* * new_flags = log_flags_add_flag(old_flags, flag); * * Add 'flag' to the 'old_flags' and return the new flags. Warn if * either value is explicitly "NONE". */ static uint32_t log_flags_add_flag(uint32_t old_flags, uint32_t flag) { if ((old_flags == SOURCE_LOG_NONE) || (flag == SOURCE_LOG_NONE)) { skAppPrintErr((PARSE_MSG_ERROR "\tThe %s 'none' ignored when" " mixed with other values on probe %s%s"), probescan_filename, probescan_line, probescan_clause, p->uniq_prefix, p->probe_name); } return (old_flags | flag); } /* * flag = parse_log_flag(s); * * Parse the string 's' as a log flag. */ static uint32_t parse_log_flag(const char *s) { if (!s || !*s) { skAppPrintErr((PARSE_MSG_ERROR "\tMissing value for %s on probe %s%s"), probescan_filename, probescan_line, probescan_clause, p->uniq_prefix, p->probe_name); return UINT16_NO_VALUE; } switch (*s) { case 'a': if (0 == strcmp(s, "all")) { return SOURCE_LOG_ALL; } break; case 'b': if (0 == strcmp(s, "bad")) { return SOURCE_LOG_BAD; } break; case 'm': if (0 == strcmp(s, "missing")) { return SOURCE_LOG_MISSING; } break; case 'n': if (0 == strcmp(s, "none")) { return SOURCE_LOG_NONE; } break; } skAppPrintErr((PARSE_MSG_ERROR "\tDo not recognize %s value '%s' on probe %s%s"), probescan_filename, probescan_line, probescan_clause, s, p->uniq_prefix, p->probe_name); return UINT16_NO_VALUE; } int yyerror(char UNUSED(*s)) { return 0; } void probeConfParseTeardown(void) { number_list_pool_empty(); string_list_pool_empty(); wildcard_ip_list_pool_empty(); } /* ** Local variables: ** mode:c ** indent-tabs-mode:nil ** c-basic-offset:4 ** End: */