1 /* $Id: reportdef.c 684 2018-11-07 19:26:36Z bhockney $ */
2 
3 /* (C) 2004-2018 by Bob Hockney <zeus@ix.netcom.com>    *
4  *                                                      *
5  * report definition parser for wfwl_syslog             *
6  *                                                      *
7  * This code is distributed under the terms of GNU GPL  */
8 
9 #include <errno.h>
10 #include <sys/stat.h>
11 #include <string.h>
12 #include <strings.h>
13 #include <ctype.h>
14 #include <netdb.h>
15 #include <math.h>
16 
17 #include <reportdef.h>
18 #include <main.h>
19 #include <utils.h>
20 
21 struct sort_order *sort = NULL;
22 struct field_order *fields = NULL;
23 struct selection *selection = NULL;
24 struct fields_used fields_used;
25 struct select_sum select_sum;
26 extern struct options opt;
27 
28 unsigned int sort_count = 0;
29 unsigned int column_count = 0;
30 unsigned int selection_count = 0;
31 
32 /* This array controls how report definition keys are parsed for sorting,       *
33  * criteria, and columns. Fields in the array are                               *
34  *         key:             Key string                                          *
35  *         sort_key:        Sort index                                          *
36  *         sel_key:         Selection index                                     *
37  *         sel_type:        Selection type                                      *
38  *         aggregate_value: Pointer for selection aggregate value               *
39  *         field_used:      Pointer to fields_used struct for columns           *
40  *         col_key:         Column index                                        *
41  *         cache_resolve:   Cache constant for host and service columns         *
42  *         use_geoip:       whether source, dest or neither geoip fields needed *
43  *                                                                              */
44 struct reportdef_keys keys [] = {
45   {"ahesp_spi",SORT_AHESP_SPI,SEL_AHESP_SPI,SEL_NUM,NULL,&fields_used.ahesp_spi,COL_AHESP_SPI,0,0},
46   {"icmptype",SORT_ICMP_TYPE,0,0,NULL,&fields_used.icmp_type,COL_ICMP_TYPE,0,0},
47   {"icmpcode",SORT_ICMP_CODE,0,0,NULL,&fields_used.icmp_code,COL_ICMP_CODE,0,0},
48   {"icmpechoid",SORT_ICMP_ECHOID,0,0,NULL,&fields_used.icmp_echoid,COL_ICMP_ECHOID,0,0},
49   {"icmpechoseq",SORT_ICMP_ECHOSEQ,0,0,NULL,&fields_used.icmp_echoseq,COL_ICMP_ECHOSEQ,0,0},
50   {"icmp_code",0,SEL_ICMP_CODE,SEL_NUM,NULL,NULL,0,0,0},
51   {"icmp_type",0,SEL_ICMP_TYPE,SEL_NUM,NULL,NULL,0,0,0},
52   {"icmp_echoid",0,SEL_ICMP_ECHOID,SEL_NUM,NULL,NULL,0,0,0},
53   {"icmp_echoseq",0,SEL_ICMP_ECHOSEQ,SEL_NUM,NULL,NULL,0,0,0},
54   {"icmpv6_code",0,SEL_ICMPv6_CODE,SEL_NUM,NULL,NULL,0,0,0},
55   {"icmpv6_type",0,SEL_ICMPv6_TYPE,SEL_NUM,NULL,NULL,0,0,0},
56   {"icmpv6_echoid",0,SEL_ICMPv6_ECHOID,SEL_NUM,NULL,NULL,0,0,0},
57   {"icmpv6_echoseq",0,SEL_ICMPv6_ECHOSEQ,SEL_NUM,NULL,NULL,0,0,0},
58   {"icmp_fragmtu",SORT_ICMP_MTU,SEL_ICMP_FRAGMTU,SEL_NUM,NULL,&fields_used.icmp_mtu,COL_ICMP_MTU,0,0},
59   {"icmp_gateway",SORT_ICMP_GW,SEL_ICMP_GATEWAY,SEL_IPADDR,NULL,&fields_used.icmp_gw,COL_ICMP_GATEWAY,0,0},
60   {"ip_csum",SORT_CSUM,SEL_IP_CSUM,SEL_NUM,NULL,&fields_used.csum,COL_IP_CSUM,0,0},
61   {"ip_fragoff",SORT_FRAGOFF,SEL_IP_FRAGOFF,SEL_NUM,NULL,&fields_used.fragoff,COL_IP_FRAGOFF,0,0},
62   {"ip_id",SORT_IP_ID,SEL_IP_ID,SEL_NUM,NULL,&fields_used.ipid,COL_IP_ID,0,0},
63   {"ip_ihl",SORT_IP_IHL,SEL_IP_IHL,SEL_NUM,NULL,&fields_used.ihl,COL_IP_IHL,0,0},
64   {"ip_protocol",SORT_PROTOCOL,SEL_PROTOCOL,SEL_PROTO,NULL,&fields_used.protocol,COL_IP_PROTO,0,0},
65   {"ip_daddr",SORT_DESTHOST,SEL_DESTHOST,SEL_IPADDR,NULL,&fields_used.dhost,COL_DESTHOST,0,0},
66   {"ip_saddr",SORT_SOURCEHOST,SEL_SOURCEHOST,SEL_IPADDR,NULL,&fields_used.shost,COL_SOURCEHOST,0,0},
67   {"ip_tos",SORT_IP_TOS,SEL_IP_TOS,SEL_NUM,NULL,&fields_used.tos,COL_IP_TOS,0,0},
68   {"ip_totlen",SORT_IP_TOTLEN,SEL_IP_TOTLEN,SEL_NUM,NULL,&fields_used.totlen,COL_IP_LEN,0,0},
69   {"ip_ttl",SORT_IP_TTL,SEL_IP_TTL,SEL_NUM,NULL,&fields_used.ttl,COL_IP_TTL,0,0},
70   {"ip_df",0,SEL_IP_DF,SEL_DFMF,NULL,NULL,0,0,0},
71   {"ip_mf",0,SEL_IP_MF,SEL_DFMF,NULL,NULL,0,0,0},
72   {"ip6_payloadlen",SORT_IP6_PAY_LEN,SEL_IP6_PAY_LEN,SEL_NUM,NULL,&fields_used.pay_len,COL_IP6_PAY_LEN,0,0},
73   {"ip6_flowlabel",SORT_IP6_FLOWLABEL,SEL_IP6_FLOWLABEL,SEL_NUM,NULL,&fields_used.flowlabel,COL_IP6_FLOWLABEL,0,0},
74   {"dport",SORT_DESTPORT,0,0,NULL,&fields_used.dport,COL_DESTPORT,0,0},
75   {"sport",SORT_SOURCEPORT,0,0,NULL,&fields_used.sport,COL_SOURCEPORT,0,0},
76   {"tcp_dport",0,SEL_TCP_DPORT,SEL_NUM,NULL,NULL,0,0,0},
77   {"tcp_sport",0,SEL_TCP_SPORT,SEL_NUM,NULL,NULL,0,0,0},
78   {"udp_dport",0,SEL_UDP_DPORT,SEL_NUM,NULL,NULL,0,0,0},
79   {"udp_sport",0,SEL_UDP_SPORT,SEL_NUM,NULL,NULL,0,0,0},
80   {"dst_host",0,0,0,NULL,&fields_used.dhost_name,COL_DESTHOST_NAME,CACHE_RESOLVE,0},
81   {"src_host",0,0,0,NULL,&fields_used.shost_name,COL_SOURCEHOST_NAME,CACHE_RESOLVE,0},
82   {"dst_service",0,0,0,NULL,&fields_used.dst_service,COL_DEST_SERVICE,CACHE_RESOLVE,0},
83   {"src_service",0,0,0,NULL,&fields_used.src_service,COL_SOURCE_SERVICE,CACHE_RESOLVE,0},
84   {"tcp_ackseq",SORT_TCP_ACKSEQ,SEL_TCP_ACKSEQ,SEL_NUM,NULL,&fields_used.tcp_ack_seq,COL_TCP_ACKSEQ,0,0},
85   {"tcp_options",SORT_TCP_OPTS,SEL_TCP_OPTS_EXACT,SEL_BOOLEAN,NULL,&fields_used.flags,COL_TCP_OPTIONS,0,0},
86   {"tcp_seq",SORT_TCP_SEQ,SEL_TCP_SEQ,SEL_NUM,NULL,&fields_used.tcp_seq,COL_TCP_SEQ,0,0},
87   {"tcp_urgp",SORT_TCP_URGP,SEL_TCP_URGP,SEL_NUM,NULL,&fields_used.tcp_urgp,COL_TCP_URGP,0,0},
88   {"tcp_window",SORT_TCP_WINDOW,SEL_TCP_WINDOW,SEL_NUM,NULL,&fields_used.tcp_window,COL_TCP_WINDOW,0,0},
89   {"tcp_ack",0,SEL_TCP_ACK,SEL_BOOLEAN,NULL,NULL,0,0,0},
90   {"tcp_fin",0,SEL_TCP_FIN,SEL_BOOLEAN,NULL,NULL,0,0,0},
91   {"tcp_psh",0,SEL_TCP_PSH,SEL_BOOLEAN,NULL,NULL,0,0,0},
92   {"tcp_rst",0,SEL_TCP_RST,SEL_BOOLEAN,NULL,NULL,0,0,0},
93   {"tcp_syn",0,SEL_TCP_SYN,SEL_BOOLEAN,NULL,NULL,0,0,0},
94   {"tcp_urg",0,SEL_TCP_URG,SEL_BOOLEAN,NULL,NULL,0,0,0},
95   {"tcp_flags",0,SEL_TCP_FLAGS,SEL_BOOLEAN,NULL,NULL,0,0,0},
96   {"udp_len",SORT_UDP_LEN,SEL_UDP_LEN,SEL_NUM,NULL,&fields_used.udp_len,COL_UDP_LEN,0,0},
97   {"local_hostname",SORT_LOCAL_HOST,SEL_LOCAL_HOST,SEL_REGEX,NULL,&fields_used.hostname,COL_LOCAL_HOST,0,0},
98   {"oob_in",SORT_IN_IF,SEL_IN_IF,SEL_REGEX,NULL,&fields_used.inif,COL_IN_IF,0,0},
99   {"oob_mark",SORT_FWMARK,SEL_OOB_MARK,SEL_NUM,NULL,&fields_used.fwmark,COL_FWMARK,0,0},
100   {"oob_out",SORT_OUT_IF,SEL_OUT_IF,SEL_REGEX,NULL,&fields_used.outif,COL_OUT_IF,0,0},
101   {"oob_prefix",SORT_PREFIX,SEL_PREFIX,SEL_REGEX,NULL,&fields_used.log_label,COL_LOG_PREFIX,0,0},
102   {"oob_family",SORT_OOB_FAMILY,SEL_OOB_FAMILY,SEL_NUM,NULL,&fields_used.family,COL_OOB_FAMILY,0,0},
103   {"oob_protocol",SORT_OOB_PROTOCOL,SEL_OOB_PROTOCOL,SEL_NUM,NULL,&fields_used.oob_protocol,COL_OOB_PROTOCOL,0,0},
104   {"mac_saddr_str",SORT_MAC_SADDR,SEL_MAC_DADDR,SEL_REGEX,NULL,&fields_used.mac_saddr_str,COL_MAC_SADDR,0,0},
105   {"mac_daddr_str",SORT_MAC_DADDR,SEL_MAC_SADDR,SEL_REGEX,NULL,&fields_used.mac_daddr_str,COL_MAC_DADDR,0,0},
106   {"raw_mac",SORT_MAC,SEL_MAC,SEL_REGEX,NULL,&fields_used.raw_mac,COL_MAC,0,0},
107   {"id",SORT_ID,0,SEL_ID,NULL,NULL,COL_ID,0,0},
108   {"sname",SORT_SNAME,0,0,NULL,&fields_used.sname,COL_SNAME,0,0},
109   {"count",SORT_COUNT,0,0,NULL,&fields_used.count,COL_COUNT,0,0},
110   {"min_count",0,0,SEL_AGG_COUNT,(time_t *)&select_sum.min_count,NULL,0,0,0},
111   {"max_count",0,0,SEL_AGG_COUNT,(time_t *)&select_sum.max_count,NULL,0,0,0},
112   {"local_time",SORT_LOCAL_TIME,0,0,NULL,&fields_used.local_time,COL_LOCAL_TIME,0,0},
113   {"earliest",SORT_START_TIME,0,0,NULL,&fields_used.earliest,COL_START_TIME,0,0},
114   {"latest",SORT_END_TIME,0,0,NULL,&fields_used.latest,COL_END_TIME,0,0},
115   {"min_date",0,SEL_MIN_DATE,SEL_DATE,NULL,NULL,0,0,0},
116   {"max_date",0,SEL_MAX_DATE,SEL_DATE,NULL,NULL,0,0,0},
117   {"min_latest",0,0,SEL_AGG_DATE,&select_sum.min_latest,NULL,0,0,0},
118   {"max_earliest",0,0,SEL_AGG_DATE,&select_sum.max_earliest,NULL,0,0,0},
119   {"continent_code_s",SORT_CONTINENT_CODE_SRC,SEL_CONTINENT_CODE_SRC,SEL_REGEX,NULL,&fields_used.continent_code_s,COL_CONTINENT_CODE_SRC,0,GEOIP_USE_SRC},
120   {"continent_name_s",SORT_CONTINENT_NAME_SRC,SEL_CONTINENT_NAME_SRC,SEL_REGEX,NULL,&fields_used.continent_name_s,COL_CONTINENT_NAME_SRC,0,GEOIP_USE_SRC},
121   {"country_iso_code_s",SORT_COUNTRY_ISO_CODE_SRC,SEL_COUNTRY_ISO_CODE_SRC,SEL_REGEX,NULL,&fields_used.country_iso_code_s,COL_COUNTRY_ISO_CODE_SRC,0,GEOIP_USE_SRC},
122   {"country_name_s",SORT_COUNTRY_NAME_SRC,SEL_COUNTRY_NAME_SRC,SEL_REGEX,NULL,&fields_used.country_name_s,COL_COUNTRY_NAME_SRC,0,GEOIP_USE_SRC},
123   {"subdivision_1_iso_code_s",SORT_SUBDIVISION_1_ISO_CODE_SRC,SEL_SUBDIVISION_1_ISO_CODE_SRC,SEL_REGEX,NULL,&fields_used.subdivision_1_iso_code_s,COL_SUBDIVISION_1_ISO_CODE_SRC,0,GEOIP_USE_SRC},
124   {"subdivision_1_name_s",SORT_SUBDIVISION_1_NAME_SRC,SEL_SUBDIVISION_1_NAME_SRC,SEL_REGEX,NULL,&fields_used.subdivision_1_name_s,COL_SUBDIVISION_1_NAME_SRC,0,GEOIP_USE_SRC},
125   {"subdivision_2_iso_code_s",SORT_SUBDIVISION_2_ISO_CODE_SRC,SEL_SUBDIVISION_2_ISO_CODE_SRC,SEL_REGEX,NULL,&fields_used.subdivision_2_iso_code_s,COL_SUBDIVISION_2_ISO_CODE_SRC,0,GEOIP_USE_SRC},
126   {"subdivision_2_name_s",SORT_SUBDIVISION_2_NAME_SRC,SEL_SUBDIVISION_2_NAME_SRC,SEL_REGEX,NULL,&fields_used.subdivision_2_name_s,COL_SUBDIVISION_2_NAME_SRC,0,GEOIP_USE_SRC},
127   {"city_name_s",SORT_CITY_NAME_SRC,SEL_CITY_NAME_SRC,SEL_REGEX,NULL,&fields_used.city_name_s,COL_CITY_NAME_SRC,0,GEOIP_USE_SRC},
128   {"metro_code_s",SORT_METRO_CODE_SRC,SEL_METRO_CODE_SRC,SEL_NUM,NULL,&fields_used.metro_code_s,COL_METRO_CODE_SRC,0,GEOIP_USE_SRC},
129   {"accuracy_radius_s",SORT_ACCURACY_RADIUS_SRC,SEL_ACCURACY_RADIUS_SRC,SEL_NUM,NULL,&fields_used.accuracy_radius_s,COL_ACCURACY_RADIUS_SRC,0,GEOIP_USE_SRC},
130   {"time_zone_s",SORT_TIME_ZONE_SRC,SEL_TIME_ZONE_SRC,SEL_REGEX,NULL,&fields_used.time_zone_s,COL_TIME_ZONE_SRC,0,GEOIP_USE_SRC},
131   {"registered_country_geoname_id_s",SORT_REGISTERED_COUNTRY_GEONAME_ID_SRC,SEL_REGISTERED_COUNTRY_GEONAME_ID_SRC,SEL_REGEX,NULL,&fields_used.registered_country_geoname_id_s,COL_REGISTERED_COUNTRY_GEONAME_ID_SRC,0,GEOIP_USE_SRC},
132   {"represented_country_geoname_id_s",SORT_REPRESENTED_COUNTRY_GEONAME_ID_SRC,SEL_REPRESENTED_COUNTRY_GEONAME_ID_SRC,SEL_REGEX,NULL,&fields_used.represented_country_geoname_id_s,COL_REPRESENTED_COUNTRY_GEONAME_ID_SRC,0,GEOIP_USE_SRC},
133   {"is_anonymous_proxy_s",SORT_IS_ANONYMOUS_PROXY_SRC,SEL_IS_ANONYMOUS_PROXY_SRC,SEL_BOOLEAN,NULL,&fields_used.is_anonymous_proxy_s,COL_IS_ANONYMOUS_PROXY_SRC,0,GEOIP_USE_SRC},
134   {"is_satellite_provider_s",SORT_IS_SATELLITE_PROVIDER_SRC,SEL_IS_SATELLITE_PROVIDER_SRC,SEL_BOOLEAN,NULL,&fields_used.is_satellite_provider_s,COL_IS_SATELLITE_PROVIDER_SRC,0,GEOIP_USE_SRC},
135   {"postal_code_s",SORT_POSTAL_CODE_SRC,SEL_POSTAL_CODE_SRC,SEL_REGEX,NULL,&fields_used.postal_code_s,COL_POSTAL_CODE_SRC,0,GEOIP_USE_SRC},
136   {"latitude_s",SORT_LATITUDE_SRC,SEL_LATITUDE_SRC,SEL_DOUBLE,NULL,&fields_used.latitude_s,COL_LATITUDE_SRC,0,GEOIP_USE_SRC},
137   {"longitude_s",SORT_LONGITUDE_SRC,SEL_LONGITUDE_SRC,SEL_DOUBLE,NULL,&fields_used.longitude_s,COL_LONGITUDE_SRC,0,GEOIP_USE_SRC},
138   {"continent_code_d",SORT_CONTINENT_CODE_DST,SEL_CONTINENT_CODE_DST,SEL_REGEX,NULL,&fields_used.continent_code_d,COL_CONTINENT_CODE_DST,0,GEOIP_USE_DST},
139   {"continent_name_d",SORT_CONTINENT_NAME_DST,SEL_CONTINENT_NAME_DST,SEL_REGEX,NULL,&fields_used.continent_name_d,COL_CONTINENT_NAME_DST,0,GEOIP_USE_DST},
140   {"country_iso_code_d",SORT_COUNTRY_ISO_CODE_DST,SEL_COUNTRY_ISO_CODE_DST,SEL_REGEX,NULL,&fields_used.country_iso_code_d,COL_COUNTRY_ISO_CODE_DST,0,GEOIP_USE_DST},
141   {"country_name_d",SORT_COUNTRY_NAME_DST,SEL_COUNTRY_NAME_DST,SEL_REGEX,NULL,&fields_used.country_name_d,COL_COUNTRY_NAME_DST,0,GEOIP_USE_DST},
142   {"subdivision_1_iso_code_d",SORT_SUBDIVISION_1_ISO_CODE_DST,SEL_SUBDIVISION_1_ISO_CODE_DST,SEL_REGEX,NULL,&fields_used.subdivision_1_iso_code_d,COL_SUBDIVISION_1_ISO_CODE_DST,0,GEOIP_USE_DST},
143   {"subdivision_1_name_d",SORT_SUBDIVISION_1_NAME_DST,SEL_SUBDIVISION_1_NAME_DST,SEL_REGEX,NULL,&fields_used.subdivision_1_name_d,COL_SUBDIVISION_1_NAME_DST,0,GEOIP_USE_DST},
144   {"subdivision_2_iso_code_d",SORT_SUBDIVISION_2_ISO_CODE_DST,SEL_SUBDIVISION_2_ISO_CODE_DST,SEL_REGEX,NULL,&fields_used.subdivision_2_iso_code_d,COL_SUBDIVISION_2_ISO_CODE_DST,0,GEOIP_USE_DST},
145   {"subdivision_2_name_d",SORT_SUBDIVISION_2_NAME_DST,SEL_SUBDIVISION_2_NAME_DST,SEL_REGEX,NULL,&fields_used.subdivision_2_name_d,COL_SUBDIVISION_2_NAME_DST,0,GEOIP_USE_DST},
146   {"city_name_d",SORT_CITY_NAME_DST,SEL_CITY_NAME_DST,SEL_REGEX,NULL,&fields_used.city_name_d,COL_CITY_NAME_DST,0,GEOIP_USE_DST},
147   {"metro_code_d",SORT_METRO_CODE_DST,SEL_METRO_CODE_DST,SEL_NUM,NULL,&fields_used.metro_code_d,COL_METRO_CODE_DST,0,GEOIP_USE_DST},
148   {"accuracy_radius_d",SORT_ACCURACY_RADIUS_DST,SEL_ACCURACY_RADIUS_DST,SEL_NUM,NULL,&fields_used.accuracy_radius_d,COL_ACCURACY_RADIUS_DST,0,GEOIP_USE_DST},
149   {"time_zone_d",SORT_TIME_ZONE_DST,SEL_TIME_ZONE_DST,SEL_REGEX,NULL,&fields_used.time_zone_d,COL_TIME_ZONE_DST,0,GEOIP_USE_DST},
150   {"registered_country_geoname_id_d",SORT_REGISTERED_COUNTRY_GEONAME_ID_DST,SEL_REGISTERED_COUNTRY_GEONAME_ID_DST,SEL_REGEX,NULL,&fields_used.registered_country_geoname_id_d,COL_REGISTERED_COUNTRY_GEONAME_ID_DST,0,GEOIP_USE_DST},
151   {"represented_country_geoname_id_d",SORT_REPRESENTED_COUNTRY_GEONAME_ID_DST,SEL_REPRESENTED_COUNTRY_GEONAME_ID_DST,SEL_REGEX,NULL,&fields_used.represented_country_geoname_id_d,COL_REPRESENTED_COUNTRY_GEONAME_ID_DST,0,GEOIP_USE_DST},
152   {"is_anonymous_proxy_d",SORT_IS_ANONYMOUS_PROXY_DST,SEL_IS_ANONYMOUS_PROXY_DST,SEL_BOOLEAN,NULL,&fields_used.is_anonymous_proxy_d,COL_IS_ANONYMOUS_PROXY_DST,0,GEOIP_USE_DST},
153   {"is_satellite_provider_d",SORT_IS_SATELLITE_PROVIDER_DST,SEL_IS_SATELLITE_PROVIDER_DST,SEL_BOOLEAN,NULL,&fields_used.is_satellite_provider_d,COL_IS_SATELLITE_PROVIDER_DST,0,GEOIP_USE_DST},
154   {"postal_code_d",SORT_POSTAL_CODE_DST,SEL_POSTAL_CODE_DST,SEL_REGEX,NULL,&fields_used.postal_code_d,COL_POSTAL_CODE_DST,0,GEOIP_USE_DST},
155   {"latitude_d",SORT_LATITUDE_DST,SEL_LATITUDE_DST,SEL_DOUBLE,NULL,&fields_used.latitude_d,COL_LATITUDE_DST,0,GEOIP_USE_DST},
156   {"longitude_d",SORT_LONGITUDE_DST,SEL_LONGITUDE_DST,SEL_DOUBLE,NULL,&fields_used.longitude_d,COL_LONGITUDE_DST,0,GEOIP_USE_DST},
157   {"extra",0,0,0,NULL,NULL,0,0,0},
158   {"extra_value",0,0,0,NULL,NULL,0,0,0},
159   {"oob_earliest",0,0,0,NULL,NULL,0,0,0},
160   {"oob_latest",0,0,0,NULL,NULL,0,0,0},
161   {"oob_time_sec",0,0,0,NULL,NULL,0,0,0},
162   {"oob_time_usec",0,0,0,NULL,NULL,0,0,0},
163   {"oob_max_date",0,0,0,NULL,NULL,0,0,0},
164   {"oob_min_date",0,0,0,NULL,NULL,0,0,0},
165   {"oob_max_earliest",0,0,0,NULL,NULL,0,0,0},
166   {"oob_min_latest",0,0,0,NULL,NULL,0,0,0},
167   {NULL,0,0,0,NULL,NULL,0,0,0}
168 };
169 
170 /* Function to get string parameter.
171  *
172  * Leading whitespace is discarded.  If the next character is a
173  * single or double quote, then line is taken until last matching
174  * quote is encountered, with embedded quotes left intact.
175  * Anything trailing the last matching quote is discarded.
176  * If no matching quote is found, then the rest of the line is
177  * returned including the first quote character, but with trailing
178  * whitespace discarded.  Leading and trailing whitespace is
179  * included if within matching quotes.
180  */
181 
str_parameter(char * string)182 char * str_parameter(char *string)
183 {
184   char *quote, *startquote = NULL, *endquote, *pnt, *ret;
185 
186   ret = string;
187 
188   while (*ret == ' ' || *ret == '\t')
189     ++ret;
190 
191   quote = strdup(ret);
192   if ( *ret == '"' || *ret == '\'') {
193     startquote = ret;
194     xstrncpy(quote, ret, 1 + 1);
195   } else {
196     *quote = '\0';
197     startquote = ret;
198   }
199 
200   ++ret;
201   endquote = strrchr(ret, *quote);
202   pnt = ret;
203   while ((endquote == NULL || *endquote == '\0' || endquote != pnt) && *pnt != '\n' && *pnt != '\0')
204     ++pnt;
205 
206   /* When pnt reaches matching end quote, or end of string, terminator is  *
207    * written over current character.  If matching quote was found, opening *
208    * quote is overwritten with space.  Trailing whitespace, if any, is     *
209    * discarded                                                             */
210 
211   *pnt = '\0';
212 
213   if ((endquote != NULL && (*quote == '"' || *quote == '\'') && endquote == pnt)) {
214     *startquote = ' ';
215   } else {
216     --ret;
217   }
218 
219   if (*endquote == '\0' || endquote != pnt) {
220     --pnt;
221     while (*pnt == ' ' || *pnt == '\t' || *pnt == '\n') {
222       *pnt = '\0';
223       --pnt;
224     }
225   }
226 
227   free(quote);
228   return ret;
229 }
230 
double_parameter(char * string,int linenum)231 double double_parameter(char *string, int linenum)
232 {
233   char *pnt, *para;
234 
235   if (string == NULL) return 0;
236 
237   para = string;
238 
239   while (*para == ' ' || *para == '\t' || *para == '"')
240     ++para;
241 
242   pnt = para;
243   while (*pnt != '\n' && *pnt != ' ' && *pnt != '"' && *pnt != ':'
244          && *pnt != '#' && *pnt != ',' && *pnt != '\t' && *pnt != '\0') {
245     if(!isxdigit((int)*pnt) && strncasecmp(pnt, "x", 1) != 0 && strncmp(pnt, ".", 1) != 0 && strncmp(pnt, "-", 1) != 0) {
246       if (opt.verbose >= VERBOSE_INFO)
247         fprintf(stderr, "Error in report definition, line %d: %s not a double\n", linenum, pnt);
248       return 0;
249     }
250 
251     ++pnt;
252   }
253   *pnt = '\0';
254 
255   return strtod (para, NULL);
256 }
257 
num_parameter(char * string,int linenum)258 unsigned long int num_parameter(char *string, int linenum)
259 {
260   char *pnt, *para, *retptr;
261   unsigned long ret;
262 
263   if (string == NULL) return 0;
264 
265   para = string;
266 
267   while (*para == ' ' || *para == '\t' || *para == '"')
268     ++para;
269 
270   pnt = para;
271   while (*pnt != '\n' && *pnt != ' ' && *pnt != '"' && *pnt != ':'
272          && *pnt != '#' && *pnt != ',' && *pnt != '\t' && *pnt != '\0') {
273     if(!isxdigit((int)*pnt) && strncasecmp(pnt, "x", 1) != 0 && strncasecmp(pnt, "b", 1) != 0) {
274       if (opt.verbose >= VERBOSE_INFO)
275         fprintf(stderr, "Error in report definition, line %d: %s not a number\n", linenum, pnt);
276       return 0;
277     }
278 
279     ++pnt;
280   }
281   *pnt = '\0';
282 
283   ret = strtoul (para, &retptr, 0);
284 
285   if (*retptr == '\0')
286     return ret;
287   else if (strncasecmp(retptr, "b", 1) == 0)
288     ret = strtoul (++retptr, NULL, 2);
289   else
290     ret = 0;
291 
292   return ret;
293 }
294 
yes_or_no(char * string,int linenum)295 unsigned char yes_or_no(char *string, int linenum)
296 {
297   char *pnt, *orig;
298 
299   orig = strdup(string);
300 
301   while (*string == ' ' || *string == '\t' || *string == '"')
302     ++string;
303 
304   pnt = string;
305 
306   while (*pnt != '\n' && *pnt != ' ' && *pnt != '"' && *pnt != '#' && *pnt != '\t' && *pnt != '\0')
307     ++pnt;
308   *pnt = '\0';
309 
310   if((strncasecmp(string, "yes", 3) == 0)
311      || (strncasecmp(string, "1", 1) == 0)
312      || (strncasecmp(string, "on", 2) == 0)
313      || (strncasecmp(string, "true", 4) == 0)) {
314     if (opt.verbose >= VERBOSE_DEBUG)
315       fprintf(stderr, "%s was parsed to %s and evaluated to true\n", orig, string);
316 
317     free(orig);
318     return true;
319   } else if((strlen(string) == 0)
320             || (strncasecmp(string, "0", 1) == 0)
321             || (strncasecmp(string, "no", 2) == 0)
322             || (strncasecmp(string, "off", 3) == 0)
323             || (strncasecmp(string, "false", 5) == 0)) {
324     if (opt.verbose >= VERBOSE_DEBUG)
325       fprintf(stderr, "%s was parsed to %s and evaluated to false\n", orig, string);
326 
327     free(orig);
328     return false;
329   } else {
330     if (opt.verbose >= VERBOSE_DEBUG)
331       fprintf(stderr, "Error in report definition, line %d, assuming 'true'\n", linenum);
332 
333     free(orig);
334     return true;
335   }
336 }
337 
resolve_protobyname(char * proto)338 int resolve_protobyname(char *proto)
339 {
340   struct protoent *protoent;
341 
342   proto = str_parameter(proto);
343   protoent = getprotobyname(proto);
344   if (protoent != NULL) {
345     return (protoent->p_proto);
346   } else {
347     return 0;
348   }
349 }
350 
351 /* Adds an item to the fields list. */
add_column(struct field_order * new,char * key,char * parm,int linenum)352 struct field_order * add_column(struct field_order *new, char *key, char *parm, int linenum)
353 {
354   struct field_order *col, *list = NULL, *last = NULL, *this = NULL, *next = NULL;
355   int j;
356 
357   for (j=0; keys[j].key != NULL; j++) {
358     if(strcmp(keys[j].key, key) == 0)
359       break;
360   }
361 
362   list = new;
363 
364   if (keys[j].key == NULL) {
365     if (opt.verbose >= VERBOSE_ALERT)
366       fprintf(stderr, "Skipping unrecognized column: %s\n", strip_nl(key));
367 
368     return list;
369   }
370 
371   if (!keys[j].col_key) {
372     if (opt.verbose >= VERBOSE_ERROR)
373       fprintf(stderr, "ignoring key = %s\n", key);
374 
375     return list;
376   }
377 
378   col = xmalloc(sizeof(struct field_order));
379   col->next = NULL;
380   xstrncpy(col->keyname, keys[j].key, SHORTLEN);
381   col->position = num_parameter(parm, linenum);
382   if (keys[j].field_used != NULL) *keys[j].field_used = 1;
383   col->field = keys[j].col_key;
384   if (keys[j].cache_resolve)
385     opt.resolve_hosts |= keys[j].cache_resolve;
386   opt.use_geoip |= keys[j].use_geoip;
387 
388   column_count++;
389   last = list;
390   this = list;
391   next = NULL;
392   if (this != NULL) next = this->next;
393 
394   while (this != NULL) {
395     if (opt.verbose >= VERBOSE_ERROR) {
396     fprintf(stderr, "Inserting column %s into list: this->position = %i\n", key, this->position);
397     }
398     if (col->position > this->position) {
399     last = this;
400     this = last->next;
401     if (this != NULL) next = this->next;
402     continue;
403     } else {
404     break;
405     }
406   }
407 
408   if (opt.verbose >= VERBOSE_DEBUG) {
409     if (last != NULL) fprintf(stderr, "Last->position: %i\n", last->position);
410     if (this != NULL) fprintf(stderr, "This->position: %i\n", this->position);
411     if (next != NULL) fprintf(stderr, "Next->position: %i\n", next->position);
412   }
413 
414   if (list == NULL) {
415     if (opt.verbose >= VERBOSE_DEBUG) {
416     fprintf(stderr, "First item seen; position: %i\n", col->position);
417     }
418     list = col;
419   } else { /* not first item seen */
420     if (list->next == NULL) {
421     if (opt.verbose >= VERBOSE_DEBUG) {
422       fprintf(stderr, "Second item seen; position: %i\n", col->position);
423     }
424     if (col->position > list->position) {
425       list->next = col;
426     } else {
427       this = list;
428       list = col;
429       list->next = this;
430     }
431     } else { /* not second item seen */
432     if (opt.verbose >= VERBOSE_DEBUG) {
433       fprintf(stderr, "Not first or second item; position: %i\n", col->position);
434     }
435     if (this == NULL) {
436       if (opt.verbose >= VERBOSE_DEBUG) {
437       fprintf(stderr, "this->position = NULL = place item last\n");
438       }
439       last->next = col;
440       col->next = NULL;
441     } else { /* not last */
442       if (this->position == last->position) {
443       if (opt.verbose >= VERBOSE_DEBUG) {
444         fprintf(stderr, "this->position = last->position = place item first\n");
445       }
446       col->next = list;
447       list = col;
448       } else { /* not first */
449       if (opt.verbose >= VERBOSE_DEBUG) {
450         fprintf(stderr, "this->position > last->position = insert item\n");
451       }
452       last->next = col;
453       col->next = this;
454       } /* end: else clause of test to place item first */
455     } /* end: else clause of test to place item last */
456     } /* end: else clause of test for second item seen */
457   } /* end: else clause of test for first item seen */
458 
459   if (opt.verbose >= VERBOSE_WARNING)
460     fprintf(stderr, "Added column %s at position %i\n", key, col->position);
461 
462   return list;
463 }
464 
465 /* Adds an item to the criteria list.                       *
466  * If selection->have_value = -1, then only invert flag was *
467  *   present and entry should not be used for selection     */
add_selection(char * key,char * parm,int linenum,int mode)468 void add_selection(char *key, char *parm, int linenum, int mode)
469 {
470   struct selection *sel = NULL, *addl = NULL, *prior = NULL;
471   int seen, bits, res, skip = 0;
472   static int fragoff_flags = 0;
473   char *ptr = NULL, *ptrr, *parms;
474   struct in_addr inp;
475 #if HAVE_INET_NTOP
476   struct in6_addr inp6;
477 #endif
478   char buf[INET6_ADDRSTRLEN], re_err[SHORTLEN], delim;
479   char stime[SHORTLEN];
480   char addr[16], mask[16];
481   int j;
482 
483   *buf = '\0';
484 
485   for (j=0; keys[j].key != NULL; j++) {
486     if(strcmp(keys[j].key, key) == 0)
487       break;
488   }
489 
490   /* skip any unrecognized criterion */
491   if (keys[j].key == NULL) {
492     if (opt.verbose >= VERBOSE_ALERT)
493       fprintf(stderr, "Skipping unrecognized criterion: %s\n", strip_nl(key));
494 
495     return;
496   }
497 
498   if (!keys[j].sel_type) {
499     if (opt.verbose >= VERBOSE_ERROR)
500       fprintf(stderr, "ignoring key = %s\n", key);
501 
502     return;
503   }
504 
505   sel = xmalloc(sizeof(struct selection));
506   sel->value = 0;
507   sel->max_value = 0;
508   sel->double_value = 0;
509   sel->max_double_value = 0;
510   *sel->svalue = '\0';
511   sel->in_addr = 0;
512   sel->netmask = -1;
513 #if HAVE_INET_NTOP
514   memset(sel->in6_addr.s6_addr, 0x00, sizeof(struct in6_addr));
515 #endif
516   sel->in6_bits = 128;
517   sel->family = AF_INET;
518   regcomp(&sel->buf, ".", REG_NOSUB);
519   sel->invert = 0;
520   sel->field = -1;
521   sel->type = 0;
522   sel->next = NULL;
523   xstrncpy(sel->keyname, key, SHORTLEN);
524   parms = strdup(parm);
525 
526   switch(keys[j].sel_type) {
527     case SEL_DATE:
528     case SEL_BOOLEAN:
529     case SEL_DFMF:
530       if (mode != DEF_WHERE) {
531         if (opt.verbose >= VERBOSE_ALERT)
532           fprintf(stderr, "Skipping invert flag for criterion: %s\n", key);
533 
534         free(sel);
535         return;
536       }
537       /* fall through */
538     case SEL_NUM:
539     case SEL_DOUBLE:
540     case SEL_IPADDR:
541     case SEL_REGEX:
542     case SEL_PROTO:
543       sel->field = keys[j].sel_key;
544       if (keys[j].sel_type == SEL_DFMF)
545         sel->type = SEL_NUM;
546       else
547         sel->type = keys[j].sel_type;
548       break;
549     case SEL_AGG_COUNT:
550       *keys[j].aggregate_value = num_parameter(parm, linenum);
551       free(sel);
552       return;
553     case SEL_AGG_DATE:
554       *keys[j].aggregate_value = num_parameter(parm, linenum);
555       free(sel);
556       return;
557     case SEL_ID:
558       opt.packet = num_parameter(parm, linenum);
559       free(sel);
560       return;
561     default:
562       break;
563   }
564 
565   switch (mode) {
566     case DEF_INVERT:
567       sel->invert = yes_or_no(parm, linenum);
568       break;
569     case DEF_WHERE:
570       switch (sel->type) {
571         case SEL_PROTO:
572           xstrncpy(sel->svalue, str_parameter(parm), SHORTLEN);
573           ptr = strpbrk((char *)&sel->svalue, ",");
574           if (ptr != NULL)
575             *ptr = '\0';
576           if(isdigit((unsigned char)*sel->svalue)) {
577             sel->value = num_parameter(parm, linenum);
578             ptrr = strpbrk((char *)&sel->svalue, ":");
579             if (ptrr == NULL) {
580               sel->max_value = sel->value;
581             } else {
582               sel->max_value = num_parameter(++ptrr, linenum);
583             }
584           } else {
585             sel->value = resolve_protobyname(sel->svalue);
586             sel->max_value = sel->value;
587           }
588           if (ptr != NULL)
589             parm = ++ptr;
590           break;
591         case SEL_NUM:
592           xstrncpy((char *)&sel->svalue, str_parameter(parm), SHORTLEN);
593           sel->value = num_parameter(parm, linenum);
594           ptr = strpbrk((char *)&sel->svalue, ",");
595           if (ptr != NULL)
596             *ptr = '\0';
597           ptrr = strpbrk((char *)&sel->svalue, ":");
598           if (ptrr == NULL) {
599             sel->max_value = sel->value;
600           } else {
601             sel->max_value = num_parameter(++ptrr, linenum);
602           }
603           if (ptr != NULL)
604             parm = ++ptr;
605         break;
606         case SEL_DOUBLE:
607           xstrncpy((char *)&sel->svalue, str_parameter(parm), SHORTLEN);
608           sel->double_value = double_parameter(parm, linenum);
609           ptr = strpbrk((char *)&sel->svalue, ",");
610           if (ptr != NULL)
611             *ptr = '\0';
612           ptrr = strpbrk((char *)&sel->svalue, ":");
613           if (ptrr == NULL) {
614             sel->max_double_value = sel->double_value;
615           } else {
616             sel->max_double_value = double_parameter(++ptrr, linenum);
617           }
618           if (ptr != NULL)
619             parm = ++ptr;
620         break;
621         case SEL_IPADDR:
622           xstrncpy(sel->svalue, str_parameter(parm), SHORTLEN);
623           ptr = strpbrk((char *)&sel->svalue, ",");
624           if (ptr != NULL)
625             *ptr = '\0';
626 #if HAVE_INET_NTOP
627           if (strpbrk((char *)&sel->svalue, ":"))
628             sel->family = AF_INET6;
629 #endif
630           ptrr = strpbrk((char *)&sel->svalue, "/");
631           if (ptrr != NULL) {
632             strncpy(&delim, ptrr, 1);
633             *ptrr = '\0';
634           }
635           if (sel->family == AF_INET) {
636             if (convert_ip(AF_INET, sel->svalue, &inp, NULL, NULL)) { /* error */
637               if (opt.verbose >= VERBOSE_NOTICE)
638                 fprintf(stderr, "Couldn't convert %s\n", sel->svalue);
639               break;
640             }
641             sel->in_addr = ntohl(inp.s_addr);
642 #if HAVE_INET_NTOP
643           } else {
644             if (convert_ip(AF_INET6, sel->svalue, NULL, &inp6, NULL)) { /* error */
645               if (opt.verbose >= VERBOSE_NOTICE)
646                 fprintf(stderr, "Couldn't convert %s\n", sel->svalue);
647               break;
648             }
649             memcpy(sel->in6_addr.s6_addr, inp6.s6_addr, sizeof(struct in6_addr));
650 #endif
651           }
652           if (ptrr != NULL) {
653             strncpy(ptrr, &delim, 1);
654             if (sel->family == AF_INET) {
655               if (strpbrk(++ptrr, ".") == NULL) {
656                 sel->netmask = ~(uint32_t)(pow(2, 32 - num_parameter(ptrr, linenum)) - 1);
657               } else {
658                 sel->netmask =  inet_network(str_parameter(ptrr));
659               }
660               sel->in_addr = sel->in_addr & sel->netmask;
661             } else {
662               bits = atoi(++ptrr);
663               if (bits >= 0 && bits <= 128)
664                 sel->in6_bits = bits;
665             }
666           }
667           if (ptr != NULL)
668             parm = ++ptr;
669           break;
670         case SEL_REGEX:
671           xstrncpy(sel->svalue, str_parameter(parm), SHORTLEN);
672           res = regcomp(&sel->buf, sel->svalue, REG_NOSUB||REG_EXTENDED);
673           if (res) { /* error */
674             if (opt.verbose >= VERBOSE_NOTICE) {
675               regerror(res, &sel->buf, re_err, SHORTLEN);
676               fprintf(stderr, "Error in regular expression \"%s\" for key %s, skipping:\n  %s\n", sel->svalue, key, re_err);
677             }
678             regcomp(&sel->buf, ".", REG_NOSUB);
679             skip++;
680           }
681           break;
682         case SEL_DATE:
683           sel->value = num_parameter(parm, linenum);
684           if (strftime((char *)&stime,SHORTLEN,"%c %Z",localtime((time_t *)&sel->value)))
685             xstrncpy(sel->svalue, (char *)&stime, SHORTLEN);
686           break;
687         case SEL_BOOLEAN:
688           sel->value = yes_or_no(parm, linenum);
689           break;
690         default:
691           /* error */
692           break;
693       } /* end switch (sel->type) */
694       opt.use_geoip |= keys[j].use_geoip;
695       break;
696     default:
697       /* error */
698       break;
699   } /* end switch (mode) */
700 
701 
702   if (sel->field == SEL_TCP_FLAGS) {
703     sel->value = 0;
704     strcpy(sel->keyname, "tcp_flags");
705   }
706 
707   if (sel->field == SEL_TCP_SYN) {
708     sel->value = TCP_SYN;
709     strcpy(sel->keyname, "tcp_flags");
710     sel->field = SEL_TCP_FLAGS;
711   }
712 
713   if (sel->field == SEL_TCP_ACK) {
714     sel->value = TCP_ACK;
715     strcpy(sel->keyname, "tcp_flags");
716     sel->field = SEL_TCP_FLAGS;
717   }
718 
719   if (sel->field == SEL_TCP_FIN) {
720     sel->value = TCP_FIN;
721     strcpy(sel->keyname, "tcp_flags");
722     sel->field = SEL_TCP_FLAGS;
723   }
724 
725   if (sel->field == SEL_TCP_RST) {
726     sel->value = TCP_RST;
727     strcpy(sel->keyname, "tcp_flags");
728     sel->field = SEL_TCP_FLAGS;
729   }
730 
731   if (sel->field == SEL_TCP_URG) {
732     sel->value = TCP_URG;
733     strcpy(sel->keyname, "tcp_flags");
734     sel->field = SEL_TCP_FLAGS;
735   }
736 
737   if (sel->field == SEL_TCP_PSH) {
738     sel->value = TCP_PSH;
739     strcpy(sel->keyname, "tcp_flags");
740     sel->field = SEL_TCP_FLAGS;
741   }
742 
743   if (sel->field == SEL_TCP_OPTS_EXACT) {
744     sel->value = TCP_OPTS_EXACT;
745     strcpy(sel->keyname, "tcp_flags");
746     sel->field = SEL_TCP_FLAGS;
747   }
748 
749   if (sel->field == SEL_IP_DF || sel->field == SEL_IP_MF) {
750     fragoff_flags |= sel->value;
751     sel->field = SEL_IP_FRAGOFF;
752     strcpy(sel->keyname, "ip_fragoff");
753   }
754 
755   prior = selection;
756   seen = 0;
757   while (prior != NULL) {
758     if (prior->field == sel->field) {
759       seen = 1;
760       if (mode == DEF_INVERT) {
761         prior->invert = sel->invert;
762       }
763 
764       if (sel->field == SEL_TCP_FLAGS)
765         sel->value = sel->value | prior->value;
766 
767       if (sel->field == SEL_IP_FRAGOFF) {
768         sel->value |= prior->value;
769         sel->max_value |= prior->max_value;
770       }
771 
772       if (mode == DEF_WHERE) {
773         prior->have_value = 0;
774         prior->value = sel->value;
775         prior->max_value = sel->max_value;
776         xstrncpy(prior->svalue, sel->svalue, SHORTLEN);
777         sel->invert = prior->invert; /* for multiple add */
778         break;
779       }
780     }
781     /* not seen */
782     prior = prior->next;
783   }
784 
785   if (!seen && !skip) {
786     selection_count++;
787   }
788 
789   if (!skip &&(!seen && mode == DEF_INVERT)) {
790     sel->have_value = -1;
791   } else {
792     sel->have_value = 0;
793   }
794 
795   if (!seen && !skip) {
796     sel->next = selection;
797     selection= sel;
798   }
799 
800   if (opt.verbose >= VERBOSE_WARNING && !skip) {
801     switch (mode) {
802       case DEF_INVERT:
803         fprintf(stderr, "Added invert flag for criterion: %s\n", key);
804         break;
805       case DEF_WHERE:
806         if (sel->field == SEL_TCP_FLAGS) {
807           fprintf(stderr, "Added criterion: %s\n", key);
808         } else {
809           inp.s_addr = htonl(sel->in_addr);
810           xstrncpy(addr, inet_ntoa(inp), SHORTLEN);
811           inp.s_addr = htonl(sel->netmask);
812           xstrncpy(mask, inet_ntoa(inp), SHORTLEN);
813           fprintf(stderr, "Added criterion: %s; Value: %lu; Max value: %lu; Svalue: %s; Family: %i; Addr: %s; Netmask: %s;"
814 #if HAVE_INET_NTOP
815             " In6_addr: %s; In6_bits: %u"
816 #endif
817             "\n",
818               key, sel->value, sel->max_value, sel->svalue, sel->family, addr, mask
819 #if HAVE_INET_NTOP
820               ,inet_ntop(AF_INET6, sel->in6_addr.s6_addr, buf, INET6_ADDRSTRLEN), sel->in6_bits
821 #endif
822           );
823         }
824         break;
825       default:
826         break;
827     }
828   }
829 
830   /* If multiple values are specified, add new selection criterion for each */
831   str_parameter(parms); /* drop quotes */
832   if (mode == DEF_WHERE && (sel->type == SEL_NUM || sel->type == SEL_DOUBLE || sel->type == SEL_IPADDR || sel->type == SEL_PROTO) && ptr != NULL ) {
833 
834     while (ptr != NULL) {
835 
836       addl = xmalloc(sizeof(struct selection));
837       addl->field = sel->field;
838       xstrncpy(addl->keyname, sel->keyname, SHORTLEN);
839       addl->type = sel->type;
840 #if HAVE_INET_NTOP
841       memset(addl->in6_addr.s6_addr, 0x00, sizeof(struct in6_addr));
842 #endif
843       addl->in6_bits = 128;
844       addl->family = AF_INET;
845       regcomp(&addl->buf, ".", REG_NOSUB);
846       addl->invert = sel->invert;
847       addl->have_value = sel->have_value;
848       addl->in_addr = 0;
849       addl->netmask = -1;
850 
851       xstrncpy((char *)&addl->svalue, str_parameter(parm), SHORTLEN);
852       ptr = strpbrk((char *)&addl->svalue, ",");
853       if (ptr != NULL)
854         *ptr = '\0';
855       if (sel-> type == SEL_NUM) {
856         addl->value = num_parameter(parm, linenum);
857         ptrr = strpbrk((char *)&addl->svalue, ":");
858         if (ptrr == NULL) {
859           addl->max_value = addl->value;
860         } else {
861           addl->max_value = num_parameter(++ptrr, linenum);
862         }
863         if (sel->field == SEL_IP_FRAGOFF) {
864           addl->value |= fragoff_flags;
865           addl->max_value |= fragoff_flags;
866         }
867       } else if (sel-> type == SEL_DOUBLE) {
868         addl->double_value = double_parameter(parm, linenum);
869         ptrr = strpbrk((char *)&addl->svalue, ":");
870         if (ptrr == NULL) {
871           addl->max_double_value = addl->double_value;
872         } else {
873           addl->max_double_value = double_parameter(++ptrr, linenum);
874         }
875       } else if (sel->type == SEL_IPADDR) {
876         if (strpbrk((char *)&addl->svalue, ":") == NULL) {
877           addl->family = AF_INET;
878 #if HAVE_INET_NTOP
879         } else {
880           addl->family = AF_INET6;
881 #endif
882         }
883         ptrr = strpbrk((char *)&addl->svalue, "/");
884         if (ptrr != NULL) {
885           strncpy(&delim, ptrr, 1);
886           *ptrr = '\0';
887         }
888         if (addl->family == AF_INET) {
889           if (convert_ip(AF_INET, addl->svalue, &inp, NULL, NULL)) { /* error */
890             if (opt.verbose >= VERBOSE_NOTICE)
891               fprintf(stderr, "Couldn't convert %s\n", addl->svalue);
892             break;
893           }
894           addl->in_addr = ntohl(inp.s_addr);
895 #if HAVE_INET_NTOP
896         } else {
897           if (convert_ip(AF_INET6, addl->svalue, NULL, &inp6, NULL)) { /* error */
898             if (opt.verbose >= VERBOSE_NOTICE)
899               fprintf(stderr, "Couldn't convert %s\n", addl->svalue);
900             break;
901           }
902           memcpy(addl->in6_addr.s6_addr, inp6.s6_addr, sizeof(struct in6_addr));
903 #endif
904         }
905         if (ptrr != NULL) {
906           strncpy(ptrr, &delim, 1);
907           if (addl->family == AF_INET) {
908             if (strpbrk(++ptrr, ".") == NULL) {
909               addl->netmask = ~(uint32_t)(pow(2, 32 - num_parameter(ptrr, linenum)) - 1);
910             } else {
911               addl->netmask = inet_network(str_parameter(ptrr));
912             }
913             addl->in_addr = addl->in_addr & addl->netmask;
914           } else {
915             bits = atoi(++ptrr);
916             if (bits >= 0 && bits <= 128)
917               addl->in6_bits = bits;
918           }
919         }
920       } else if (sel->type == SEL_PROTO) {
921         if(isdigit((unsigned char)*addl->svalue)) {
922           addl->value = num_parameter(parm, linenum);
923           ptrr = strpbrk((char *)&addl->svalue, ":");
924           if (ptrr == NULL) {
925             addl->max_value = addl->value;
926           } else {
927             addl->max_value = num_parameter(++ptrr, linenum);
928           }
929         } else {
930           addl->value = resolve_protobyname(addl->svalue);
931           addl->max_value = addl->value;
932         }
933       }
934 
935       if (ptr != NULL)
936         parm = ++ptr;
937 
938       if (opt.verbose >= VERBOSE_WARNING) {
939         inp.s_addr = htonl(addl->in_addr);
940         xstrncpy(addr, inet_ntoa(inp), SHORTLEN);
941         inp.s_addr = htonl(addl->netmask);
942         xstrncpy(mask, inet_ntoa(inp), SHORTLEN);
943         fprintf(stderr, "Added criterion: %s; Value: %lu; Max value %lu; Svalue: %s; Family: %i; Addr: %s; Netmask: %s;"
944 #if HAVE_INET_NTOP
945           " In6_addr: %s; In6_bits: %u"
946 #endif
947           "\n",
948             key, addl->value, addl->max_value, addl->svalue, addl->family, addr, mask
949 #if HAVE_INET_NTOP
950             ,inet_ntop(AF_INET6, addl->in6_addr.s6_addr, buf, INET6_ADDRSTRLEN), addl->in6_bits
951 #endif
952         );
953       }
954 
955       addl->next = selection;
956       selection = addl;
957 
958       selection_count++;
959 
960     }
961 
962   }
963 
964   free(parms);
965 
966   if (seen) {
967     free(sel);
968   }
969 
970   return;
971 }
972 
973 /* Adds an item to the sort list.                         *
974  * If sort_order->position = -35768, then only order flag *
975  *   was present and entry should not be used for sorting */
add_sort(struct sort_order * new,char * key,char * parm,int linenum,int mode)976 struct sort_order * add_sort(struct sort_order *new, char *key, char *parm, int linenum, int mode)
977 {
978   struct sort_order *srt = NULL, *have = NULL, *last = NULL, *this = NULL, *prev = NULL, *next = NULL, *list = NULL, *old = NULL;
979   int seen, j;
980 
981   for (j=0; keys[j].key != NULL; j++) {
982     if(strcmp(keys[j].key, key) == 0)
983       break;
984   }
985 
986   list = new;
987 
988   if (keys[j].key == NULL) {
989     if (opt.verbose >= VERBOSE_ALERT)
990       fprintf(stderr, "Skipping unrecognized sort field: %s\n", strip_nl(key));
991 
992     return list;
993   }
994 
995   if (!keys[j].sort_key) {
996     if (opt.verbose >= VERBOSE_ERROR)
997       fprintf(stderr, "ignoring key = %s\n", key);
998 
999     return list;
1000   }
1001 
1002   srt = xmalloc(sizeof(struct sort_order));
1003   srt->next = NULL;
1004   xstrncpy(srt->keyname, key, SHORTLEN);
1005   srt->order = 0;
1006   srt->position = 0;
1007   srt->field = keys[j].sort_key;
1008 
1009   switch (mode) {
1010     case DEF_SORT:
1011       srt->position = num_parameter(parm, linenum);
1012       opt.use_geoip |= keys[j].use_geoip;
1013       break;
1014     case DEF_ORDER:
1015       if (yes_or_no(parm, linenum)){
1016         srt->order = ORDER_DESCENDING;
1017       }
1018       break;
1019     default:
1020       /* error */
1021       break;
1022   }
1023 
1024   have = list;
1025   seen = 0;
1026   while (have != NULL) {
1027     if (have->field == srt->field) {
1028       seen = 1;
1029       break;
1030     } else {
1031       prev = have;
1032       have = have->next;
1033     }
1034   }
1035 
1036   if (seen) {
1037     if (mode == DEF_SORT) {
1038       /* If we have seen key before and are doing sort position now,
1039        * break it out of list and treat it as new item to be inserted */
1040       have->position = srt->position;
1041         /* if item is currently first in list, make second item first */
1042         if (list == have) list = list->next;
1043         old = srt;
1044         srt = have;
1045         free(old);
1046         if (prev != NULL) {
1047           prev->next = have->next;
1048         }
1049         srt->next = NULL;
1050     } else {
1051       if (mode == DEF_ORDER) {
1052         have->order = srt->order;
1053       } else {;} /* error */
1054     }
1055   } else if (mode == DEF_ORDER) {
1056     srt->position = SORT_INV_NO_SORT;
1057     srt->next = list;
1058     list = srt;
1059     free(have);
1060   }
1061 
1062   if (mode == DEF_SORT) {
1063     sort_count++;
1064     last = list;
1065     this = list;
1066     next = NULL;
1067     if (this != NULL) next = this->next;
1068 
1069     while (this != NULL) {
1070       if (opt.verbose >= VERBOSE_ERROR) {
1071         fprintf(stderr, "Inserting sort field %s into list: this->position = %i\n", key, this->position);
1072       }
1073       if (srt->position < this->position) {
1074         last = this;
1075         this = last->next;
1076         if (this != NULL) next = this->next;
1077         continue;
1078       } else {
1079         break;
1080       }
1081     }
1082 
1083     if (opt.verbose >= VERBOSE_DEBUG) {
1084       if (last != NULL) fprintf(stderr, "Last->position: %i\n", last->position);
1085       if (this != NULL) fprintf(stderr, "This->position: %i\n", this->position);
1086       if (next != NULL) fprintf(stderr, "Next->position: %i\n", next->position);
1087     }
1088 
1089     if (list == NULL || (list->position == SORT_INV_NO_SORT && last->position == SORT_INV_NO_SORT)) {
1090       if (opt.verbose >= VERBOSE_DEBUG) {
1091         fprintf(stderr, "First item seen; position: %i\n", srt->position);
1092       }
1093       if (list != NULL)
1094         srt->next = list;
1095       list = srt;
1096     } else { /* not first item seen */
1097       if (list->next == NULL || (this == NULL && list->next->position == SORT_INV_NO_SORT \
1098            && last != NULL && srt->position > last->position)) {
1099         if (opt.verbose >= VERBOSE_DEBUG) {
1100           fprintf(stderr, "Second item seen; position: %i\n", srt->position);
1101         }
1102         if (srt->position < list->position) {
1103           if (list->next != NULL)
1104             srt->next = list->next;
1105           list->next = srt;
1106         } else {
1107           this = list;
1108           list = srt;
1109           list->next = this;
1110         }
1111       } else { /* not second item seen */
1112         if (opt.verbose >= VERBOSE_DEBUG) {
1113           fprintf(stderr, "Not first or second item; position: %i\n", srt->position);
1114         }
1115         if (this == NULL) {
1116           if (opt.verbose >= VERBOSE_DEBUG) {
1117             fprintf(stderr, "this->position = NULL = place item last\n");
1118           }
1119           last->next = srt;
1120           srt->next = NULL;
1121         } else { /* not last */
1122           if (this->position == last->position) {
1123             if (opt.verbose >= VERBOSE_DEBUG) {
1124               fprintf(stderr, "this->position = last->position = place item first\n");
1125             }
1126             srt->next = list;
1127             list = srt;
1128           } else { /* not first */
1129             if (opt.verbose >= VERBOSE_DEBUG) {
1130               fprintf(stderr, "this->position < last->position = insert item\n");
1131             }
1132             last->next = srt;
1133             srt->next = this;
1134           } /* end: else clause of test to place item first */
1135         } /* end: else clause of test to place item last */
1136       } /* end: else clause of test for second item seen */
1137     } /* end: else clause of test for first item seen */
1138   } /* end: if(mode == DEF_SORT} */
1139 
1140   if (opt.verbose >= VERBOSE_WARNING) {
1141     switch (mode) {
1142       case DEF_ORDER:
1143         fprintf(stderr, "Added descending flag for sort field %s\n", key);
1144         break;
1145       case DEF_SORT:
1146           fprintf(stderr, "Added sort field %s at position %i\n", key, srt->position);
1147         break;
1148       default:
1149         break;
1150     }
1151   }
1152 
1153   return list;
1154 }
1155 
1156 /* parses single line from reportdef */
1157 /* called with (linebuf, linenum) */
parse_reportdef(char * input,int linenum)1158 void parse_reportdef(char *input, int linenum)
1159 {
1160   char *command, *key, *parm, *ptr;
1161   unsigned int type, len = 0;
1162 
1163   while (*input == ' ' || *input == '\t')
1164     ++input;
1165 
1166   if (*input == '#' || *input == '\n')
1167     return;
1168 
1169   command = strdup(input);
1170   key = strdup(input);
1171   ptr = key;
1172 
1173   len = strcspn(command, " =");
1174   xstrncpy(key, command, len + 1);
1175 
1176   parm = strpbrk(command, "=");
1177   if (!(parm == NULL))
1178     parm++;
1179 
1180   type = DEF_NONE;
1181 
1182   if (strncmp(key, "w_", 2) == 0)
1183     type = DEF_WHERE;
1184 
1185   if (strncmp(key, "i_", 2) == 0)
1186     type = DEF_INVERT;
1187 
1188   if (strncmp(key, "s_", 2) == 0)
1189     type = DEF_SORT;
1190 
1191   if (strncmp(key, "o_", 2) == 0)
1192     type = DEF_ORDER;
1193 
1194   if (strncmp(key, "c_", 2) == 0)
1195     type = DEF_COLUMN;
1196 
1197 /* Ignore these */
1198   if (strncmp(key, "h_", 2) == 0)
1199     type = DEF_NONE;
1200 
1201   if (strncmp(key, "l_", 2) == 0)
1202     type = DEF_NONE;
1203 
1204   if (type != DEF_NONE) {
1205      key++; key++;
1206   }
1207 
1208 /* Other options */
1209   if (strncmp(key, "summarize", 9) == 0)
1210     type = DEF_SUM;
1211 
1212   if (strncmp(key, "populate_cache", 14) == 0) {
1213     opt.resolve_hosts |= CACHE_POPULATE;
1214     type = DEF_OPTION;
1215   }
1216 
1217   if (strncmp(key, "upd_hosts", 9) == 0) {
1218     opt.resolve_hosts |= CACHE_UPDATE;
1219     type = DEF_OPTION;
1220   }
1221 
1222   if (strncmp(key, "populate_cache_full", 19) == 0) {
1223     opt.resolve_hosts |= CACHE_POPULATE_FULL;
1224     type = DEF_OPTION;
1225   }
1226 
1227   if (strncmp(key, "syslog_dir", 10) == 0) {
1228     xstrncpy(opt.pathname, str_parameter(parm), SHORTLEN);
1229     type = DEF_OPTION;
1230   }
1231 
1232   if (strncmp(key, "db", 2) == 0) {
1233     xstrncpy(opt.db, str_parameter(parm), SHORTLEN);
1234     type = DEF_OPTION;
1235   }
1236 
1237   if (strncmp(key, "mysql_server", 12) == 0) {
1238     xstrncpy(opt.mysql_server, str_parameter(parm), SHORTLEN);
1239     type = DEF_OPTION;
1240   }
1241 
1242   if (strncmp(key, "mysql_wfwl_db", 13) == 0) {
1243     xstrncpy(opt.mysql_wfwl_db, str_parameter(parm), SHORTLEN);
1244     type = DEF_OPTION;
1245   }
1246 
1247   if (strncmp(key, "mysql_user", 10) == 0) {
1248     xstrncpy(opt.mysql_user, str_parameter(parm), SHORTLEN);
1249     type = DEF_OPTION;
1250   }
1251 
1252   if (strncmp(key, "mysql_pass", 10) == 0) {
1253     xstrncpy(opt.mysql_pass, str_parameter(parm), SHORTLEN);
1254     type = DEF_OPTION;
1255   }
1256 
1257   if (strncmp(key, "pgsql_server", 12) == 0) {
1258     xstrncpy(opt.pgsql_server, str_parameter(parm), SHORTLEN);
1259     type = DEF_OPTION;
1260   }
1261 
1262   if (strncmp(key, "pgsql_db", 8) == 0) {
1263     xstrncpy(opt.pgsql_db, str_parameter(parm), SHORTLEN);
1264     type = DEF_OPTION;
1265   }
1266 
1267   if (strncmp(key, "pgsql_user", 10) == 0) {
1268     xstrncpy(opt.pgsql_user, str_parameter(parm), SHORTLEN);
1269     type = DEF_OPTION;
1270   }
1271 
1272   if (strncmp(key, "pgsql_pass", 10) == 0) {
1273     xstrncpy(opt.pgsql_pass, str_parameter(parm), SHORTLEN);
1274     type = DEF_OPTION;
1275   }
1276 
1277   if (strncmp(key, "pgsql_wfwl_schema", 17) == 0) {
1278     xstrncpy(opt.pgsql_wfwl_schema, str_parameter(parm), SHORTLEN - 1);
1279     type = DEF_OPTION;
1280   }
1281 
1282   if (strncmp(key, "pgsql_have_namespace", 20) == 0) {
1283     opt.pgsql_have_namespace = 1;
1284     type = DEF_OPTION;
1285   }
1286 
1287   if (strncmp(key, "geoip2_locale", 11) == 0) {
1288     xstrncpy(opt.geoip2_locale, str_parameter(parm), BUFSIZE);
1289     type = DEF_OPTION;
1290   }
1291 
1292   if (strncmp(key, "geoip2_file", 11) == 0) {
1293     xstrncpy(opt.geoip2_file, str_parameter(parm), BUFSIZE);
1294     type = DEF_OPTION;
1295   }
1296 
1297   if (strncmp(key, "geoip_php_lookup", 16) == 0) {
1298     if(yes_or_no(parm, linenum))
1299       opt.use_geoip |= GEOIP_OFF;
1300     type = DEF_OPTION;
1301   }
1302 
1303   if (type == DEF_OPTION) {
1304     if (opt.verbose >= VERBOSE_ALERT) {
1305       if (strncmp(key,"mysql_pass", 10) == 0||strncmp(key,"pgsql_pass", 10) == 0) {
1306         fprintf(stderr, "Added option: %s; Value: %s\n", key, "************");
1307       } else {
1308         fprintf(stderr, "Added option: %s; Value: %s\n", key, strip_nl(str_parameter(parm)));
1309       }
1310     }
1311   } else if (type != DEF_NONE) {
1312     if (opt.verbose >= VERBOSE_ERROR) {
1313       fprintf(stderr, "Processing report definition line Type: %u; Key: %s; Parameter: %s", type, key, parm);
1314     }
1315   } else { /* type == DEF_NONE */
1316     if (opt.verbose >= VERBOSE_ERROR) {
1317       fprintf(stderr, "Ignoring report definition line: %s", command);
1318     }
1319   }
1320 
1321   if (!(parm == NULL))
1322   switch (type) {
1323     case DEF_SUM:
1324       if (yes_or_no(parm, linenum)) {
1325         opt.mode = LOG_SUMMARY;
1326       } else {
1327         opt.mode = LOG_DETAIL;
1328       }
1329       break;
1330     case DEF_WHERE:
1331       add_selection(key, parm, linenum, DEF_WHERE);
1332       break;
1333     case DEF_INVERT:
1334       add_selection(key, parm, linenum, DEF_INVERT);
1335       break;
1336     case DEF_SORT:
1337       sort = add_sort(sort, key, parm, linenum, DEF_SORT);
1338       break;
1339     case DEF_ORDER:
1340       sort = add_sort(sort, key, parm, linenum, DEF_ORDER);
1341       break;
1342     case DEF_COLUMN:
1343       fields = add_column(fields, key, parm, linenum);
1344       break;
1345     case DEF_OPTION:
1346     case DEF_NONE:
1347       break;
1348     default:
1349       /* error */
1350       break;
1351   }
1352 
1353   free(ptr);
1354   free(command);
1355 
1356   return;
1357 }
1358 
1359 /* Entry point; called from main.c */
read_reportdef(char * reportdef)1360 unsigned char read_reportdef(char *reportdef)
1361 {
1362   char buf[BUFSIZE], *name;
1363   FILE *fd;
1364   int linenum = 1, retval;
1365   char keyname[SHORTLEN];
1366   char position[SHORTLEN];
1367   char addr[16], mask[16];
1368   char stime[SHORTLEN];
1369   struct stat info;
1370   struct sort_order *srt;
1371   struct field_order *col;
1372   struct selection *sel;
1373   struct in_addr in;
1374 
1375   name = strdup(reportdef);
1376 
1377   /* validate reportdef file */
1378   if (strcmp(reportdef, "-")) {
1379     retval = stat(reportdef, &info);
1380     if (retval == -1) {
1381       fprintf(stderr, "Cannot open report definition file %s, exiting.\n", reportdef);
1382       return EXIT_FAILURE;
1383     }
1384     if (!S_ISREG(info.st_mode)) {
1385       fprintf(stderr, "%s is not a regular file, exiting.\n", reportdef);
1386       return EXIT_FAILURE;
1387     }
1388 
1389     if(opt.verbose >= VERBOSE_INFO)
1390       fprintf(stderr, "Processing report definition file '%s'\n", name);
1391 
1392     fd = fopen(name, "r");
1393     if (fd == NULL) {
1394       fprintf(stderr, "fopen %s: %s\n", name, strerror(errno));
1395       exit(EXIT_FAILURE);
1396     }
1397   } else {
1398 
1399     if(opt.verbose >= VERBOSE_INFO)
1400       fprintf(stderr, "Processing report definition from stdin\n");
1401 
1402     fd = stdin;
1403   }
1404 
1405   /* initialize fields_used */
1406   /* this is used for summarization testing.                                *
1407    * tests done against this static data are faster by a factor of at       *
1408    * least two over iterating though field_order linked list for each line. */
1409   fields_used.count = 0;
1410   fields_used.sname = 0;
1411   fields_used.local_time = 0;
1412   fields_used.earliest = 0;
1413   fields_used.latest = 0;
1414   fields_used.hostname = 0;
1415   fields_used.log_label = 0;
1416   fields_used.protocol = 0;
1417   fields_used.family = 0;
1418   fields_used.totlen = 0;
1419   fields_used.shost = 0;
1420   fields_used.sport = 0;
1421   fields_used.dhost = 0;
1422   fields_used.dport = 0;
1423   fields_used.shost_name = 0;
1424   fields_used.dhost_name = 0;
1425   fields_used.src_service = 0;
1426   fields_used.dst_service = 0;
1427   fields_used.flags = 0;
1428   fields_used.oob_protocol = 0;
1429   fields_used.mac_saddr_str = 0;
1430   fields_used.mac_daddr_str = 0;
1431   fields_used.raw_mac = 0;
1432   fields_used.fwmark = 0;
1433   fields_used.inif = 0;
1434   fields_used.outif = 0;
1435   fields_used.tos = 0;
1436   fields_used.ttl = 0;
1437   fields_used.ihl = 0;
1438   fields_used.csum = 0;
1439   fields_used.ipid = 0;
1440   fields_used.fragoff = 0;
1441   fields_used.pay_len = 0;
1442   fields_used.flowlabel = 0;
1443   fields_used.tcp_seq = 0;
1444   fields_used.tcp_ack_seq = 0;
1445   fields_used.tcp_window = 0;
1446   fields_used.tcp_urgp = 0;
1447   fields_used.udp_len = 0;
1448   fields_used.icmp_type = 0;
1449   fields_used.icmp_code = 0;
1450   fields_used.icmp_echoid = 0;
1451   fields_used.icmp_echoseq = 0;
1452   fields_used.icmp_gw = 0;
1453   fields_used.icmp_mtu = 0;
1454   fields_used.ahesp_spi = 0;
1455   fields_used.continent_code_s = 0;
1456   fields_used.continent_name_s = 0;
1457   fields_used.country_iso_code_s = 0;
1458   fields_used.country_name_s = 0;
1459   fields_used.subdivision_1_iso_code_s = 0;
1460   fields_used.subdivision_1_name_s = 0;
1461   fields_used.subdivision_2_iso_code_s = 0;
1462   fields_used.subdivision_2_name_s = 0;
1463   fields_used.city_name_s = 0;
1464   fields_used.metro_code_s = 0;
1465   fields_used.accuracy_radius_s = 0;
1466   fields_used.time_zone_s = 0;
1467   fields_used.registered_country_geoname_id_s = 0;
1468   fields_used.represented_country_geoname_id_s = 0;
1469   fields_used.is_anonymous_proxy_s = 0;
1470   fields_used.is_satellite_provider_s = 0;
1471   fields_used.postal_code_s = 0;
1472   fields_used.latitude_s = 0;
1473   fields_used.longitude_s = 0;
1474   fields_used.continent_code_d = 0;
1475   fields_used.continent_name_d = 0;
1476   fields_used.country_iso_code_d = 0;
1477   fields_used.country_name_d = 0;
1478   fields_used.subdivision_1_iso_code_d = 0;
1479   fields_used.subdivision_1_name_d = 0;
1480   fields_used.subdivision_2_iso_code_d = 0;
1481   fields_used.subdivision_2_name_d = 0;
1482   fields_used.city_name_d = 0;
1483   fields_used.metro_code_d = 0;
1484   fields_used.accuracy_radius_d = 0;
1485   fields_used.time_zone_d = 0;
1486   fields_used.registered_country_geoname_id_d = 0;
1487   fields_used.represented_country_geoname_id_d = 0;
1488   fields_used.is_anonymous_proxy_d = 0;
1489   fields_used.is_satellite_provider_d = 0;
1490   fields_used.postal_code_d = 0;
1491   fields_used.latitude_d = 0;
1492   fields_used.longitude_d = 0;
1493 
1494   /* initialize select_sum */
1495   select_sum.min_count = 0;
1496   select_sum.max_count = 0;
1497   select_sum.max_earliest = 0;
1498   select_sum.min_latest = 0;
1499 
1500   while (fgets(buf, BUFSIZE, fd)) {
1501     if (opt.verbose >= VERBOSE_DEBUG)
1502       fprintf(stderr, "Input line is: %s", buf);
1503 
1504     parse_reportdef(buf, linenum);
1505     linenum++;
1506   }
1507 
1508   if (opt.mode == LOG_DETAIL && fields_used.sname == 0) {
1509     strcpy(keyname, "sname");
1510     strcpy(position, "99");
1511     fields = add_column(fields, keyname, position, 999);
1512   }
1513 
1514   if (opt.verbose >= VERBOSE_INFO) {
1515     fprintf(stderr, "Number of columns: %u\n", column_count);
1516   }
1517 
1518   if (opt.verbose >= VERBOSE_NOTICE) {
1519     col = fields;
1520     while (col != NULL) {
1521       fprintf(stderr, "COLUMNS: Key: %s; Field %i; Position: %i\n", col->keyname, col->field, col->position);
1522       col = col->next;
1523     }
1524   }
1525 
1526   if (opt.verbose >= VERBOSE_INFO) {
1527     fprintf(stderr, "Number of criteria: %u\n", selection_count);
1528   }
1529 
1530   if (opt.verbose >= VERBOSE_NOTICE) {
1531     sel = selection;
1532     while (sel != NULL) {
1533       in.s_addr = htonl(sel->in_addr);
1534       xstrncpy(addr, inet_ntoa(in), SHORTLEN);
1535       in.s_addr = htonl(sel->netmask);
1536       xstrncpy(mask, inet_ntoa(in), SHORTLEN);
1537       fprintf(stderr, "SELECTION: Key: %s; Field %i; Value: %lu Max value: %lu; Double: %.7g; Max double: %.7g; Svalue: %s; Family: %i; Addr: %s; Netmask: %s;"
1538 #if HAVE_INET_NTOP
1539         " In6_addr: %s; In6_bits: %u;"
1540 #endif
1541         " Invert: %i; Have Value: %i\n",
1542         sel->keyname, sel->field, sel->value, sel->max_value, sel->double_value, sel->max_double_value, sel->svalue, sel->family, addr, mask,
1543 #if HAVE_INET_NTOP
1544         inet_ntop(AF_INET6, sel->in6_addr.s6_addr, buf, INET6_ADDRSTRLEN), sel->in6_bits,
1545 #endif
1546         sel->invert, sel->have_value);
1547 
1548       sel = sel->next;
1549     }
1550     if (select_sum.min_count !=0)
1551       fprintf(stderr, "SELECTION: Key: min_count; Value: %lu\n", select_sum.min_count);
1552     if (select_sum.max_count !=0)
1553       fprintf(stderr, "SELECTION: Key: max_count; Value: %lu\n", select_sum.max_count);
1554     if (select_sum.max_earliest !=0) {
1555       if (strftime((char *)&stime,SHORTLEN,"%c %Z",localtime((time_t *)&select_sum.max_earliest)))
1556       fprintf(stderr, "SELECTION: Key: max_earliest; Value: %lu; Svalue: %s\n", (unsigned long int)select_sum.max_earliest,(char *)&stime);
1557     }
1558     if (select_sum.min_latest !=0) {
1559       if (strftime((char *)&stime,SHORTLEN,"%c %Z",localtime((time_t *)&select_sum.min_latest)))
1560       fprintf(stderr, "SELECTION: Key: min_latest; Value: %lu; Svalue: %s\n", (unsigned long int)select_sum.min_latest,(char *)&stime);
1561     }
1562   }
1563 
1564   if (opt.verbose >= VERBOSE_INFO) {
1565     fprintf(stderr, "Number of sorts: %u\n", sort_count);
1566   }
1567 
1568   if (opt.verbose >= VERBOSE_NOTICE) {
1569     srt = sort;
1570     while (srt != NULL) {
1571       fprintf(stderr, "SORT: Key: %s; Field %i; Position: %i Order: %i\n",
1572         srt->keyname, srt->field, srt->position, srt->order);
1573       srt = srt->next;
1574     }
1575   }
1576 
1577   if ((strcmp(reportdef, "-"))) {
1578     if(opt.verbose >= VERBOSE_WARNING)
1579       fprintf(stderr, "Done processing report definition file '%s'\n", name);
1580   } else {
1581     if(opt.verbose >= VERBOSE_WARNING)
1582       fprintf(stderr, "Done processing report definition from stdin\n");
1583   }
1584 
1585   free(name);
1586 
1587   retval = fclose(fd);
1588   if (retval == EOF) {
1589     perror("fclose");
1590     exit(EXIT_FAILURE);
1591   }
1592 
1593   return EXIT_SUCCESS;
1594 }
1595