/* SRG - Squid Report Generator Copyright 2003 University of Waikato This file is part of SRG. SRG is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. SRG is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with SRG; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "srg.h" #include "config.h" #include "prototypes.h" #include /* Tell people how to use srg */ void usage(void) { printf("usage: %s [options]\n" "Options:\n" "-a
Perform analysis only on requests from the\n" " specified IP address.\n" "-C Location of the srg config file.\n" "-d Enable debugging output\n" "-E If the username does not exist, look up the\n" " username using info in this file\n" "-f The file to process\n" "-g Group analysis by specified criteria\n" " A=address, S=subnet, U=username\n" "-H Perform DNS lookups on IP addresses to\n" " be displayed in reports.\n" "--help -h Display this help\n" "-m Specify maximum number of days to keep a\n" " report\n" "-M Output a summary report suitable for \n" " emailing.\n" "-n Specify the netmask to be used when grouping\n" " by subnet, ie. 255.255.255.0\n" "-o Output Directory\n" "-O URL where reports will be located\n" "-r Enable javascript column sorting in output\n" "-R Show transfer rate in reports\n" "-s / Perform analysis only on requests from the\n" " specified subnet.\n" "-S Show time value in reports\n" "-t '-' Time period to perform analysis in. Records\n" " that are not inside this period will not be\n" " analysed. i.e. '31/10/2003-1/11/2003'\n" "-u Perform analysis only on requests from the\n" " specified username.\n" "-v Verbose mode. Print relevant messages.\n" "-V Print Version and exit.\n" , progname); } /* Configure srg */ bool do_configuration(int argc, char **argv) { char ch; /* Initialise configuration options */ set_defaults(); /* The real config options */ char *conffile = NULL; /* Temp config options for config *f*ile */ char *accesslogf = NULL; char *outputdirf = NULL; char *outputurlf = NULL; char *titlef = NULL; char *cssfilef = NULL; char *filterbyf = NULL; char *filtercritf = NULL; char *groupbyf = NULL; char *groupbynetf = NULL; char *time_periodf = NULL; char *phpheadf = NULL; char *phpfootf = NULL; char *ip2userf = NULL; int debugf = 0; int locationf = 0; int showtimesf = 0; int showratesf = 0; int nonameshowipf = 0; int hidedeniedf = 0; int maxagef = 0; int authf = 0; int lookuphostf = -1; int verbosef = 0; int emailreportf = 0; int sortcolumnsf = 0; /* temp config options for *c*ommand line */ char *accesslogc = NULL; char *outputdirc = NULL; char *outputurlc = NULL; char *cssfilec = NULL; char *filtercritc = NULL; char *titlec = NULL; char *phpheadc = NULL; char *phpfootc = NULL; char *ip2userc = NULL; char *groupbynetc=NULL; char *timesc = NULL; int filterbyc = 0; int groupbyc = 0; int debugc = 0; int locationc = 0; int showtimesc = 0; int showratesc = 0; int nonameshowipc = 0; int hidedeniedc = 0; int authc = 0; int maxagec = 0; int lookuphostc = -1; int verbosec = 0; int emailreportc = 0; int sortcolumnsc = 0; /* Config options from the config file */ config_t main_config[] = { {"log_file", TYPE_STR|TYPE_NULL, &accesslogf}, {"output_dir", TYPE_STR|TYPE_NULL, &outputdirf}, {"output_url", TYPE_STR|TYPE_NULL, &outputurlf}, {"title", TYPE_STR|TYPE_NULL, &titlef}, {"cssfile", TYPE_STR|TYPE_NULL, &cssfilef}, {"emailreport", TYPE_BOOL|TYPE_NULL, &emailreportf}, {"filterby", TYPE_STR|TYPE_NULL, &filterbyf}, {"filtercrit", TYPE_STR|TYPE_NULL, &filtercritf}, {"groupby", TYPE_STR|TYPE_NULL, &groupbyf}, {"groupbynetmask", TYPE_STR|TYPE_NULL, &groupbynetf}, {"time_period", TYPE_STR|TYPE_NULL, &time_periodf}, {"phpheader", TYPE_STR|TYPE_NULL, &phpheadf}, {"phpfooter", TYPE_STR|TYPE_NULL, &phpfootf}, {"debug", TYPE_BOOL|TYPE_NULL, &debugf}, {"location", TYPE_BOOL|TYPE_NULL, &locationf}, {"show_times", TYPE_BOOL|TYPE_NULL, &showtimesf}, {"show_rates", TYPE_BOOL|TYPE_NULL, &showratesf}, {"nonameexists_showip", TYPE_BOOL|TYPE_NULL, &nonameshowipf}, {"iptouser_file", TYPE_STR|TYPE_NULL, &ip2userf}, {"dontshow_onlydeniedusers", TYPE_BOOL|TYPE_NULL, &hidedeniedf}, {"php_authentication", TYPE_BOOL|TYPE_NULL, &authf}, {"max_age", TYPE_INT|TYPE_NULL, &maxagef}, {"lookup_hosts", TYPE_BOOL|TYPE_NULL, &lookuphostf}, {"verbose", TYPE_BOOL|TYPE_NULL, &verbosef}, {"sort_columns", TYPE_BOOL|TYPE_NULL, &sortcolumnsf}, {NULL, 0, NULL} }; static struct option long_options[] = { {"help", 0, 0, 'h'}, {0, 0, 0, 0} }; int optindex=0; if (argc<2) { usage(); exit(1); } /* Parse command line arguments */ while((ch = getopt_long(argc, argv, "a:Ac:C:dDeE:f:g:hHLm:Mn:o:O:p:P:rRs:St:T:u:vV", long_options, &optindex)) != -1) { switch(ch) { case 'a': filtercritc = strdup(optarg); filterbyc += BY_IP; break; case 'A': fprintf(stderr, "WARNING: -A is deprecated, see the " "FAQ for details.\n"); authc = 1; break; case 'c': fprintf(stderr, "WARNING: -c is deprecated, see the " "FAQ for details.\n"); cssfilec = strdup(optarg); break; case 'C': conffile = strdup(optarg); break; case 'd': debugc++; break; case 'D': fprintf(stderr, "WARNING: -D is deprecated, see the " "FAQ for details.\n"); hidedeniedc = 1; break; case 'e': fprintf(stderr, "WARNING: -e is deprecated, see the " "FAQ for details.\n"); nonameshowipc = 1; break; case 'E': ip2userc = strdup(optarg); break; case 'f': accesslogc = strdup(optarg); break; case 'g': if (strcmp(optarg,"A")==0) groupbyc += BY_IP; else if (strcmp(optarg, "S")==0) groupbyc += BY_SUBNET; else if (strcmp(optarg, "U")==0) groupbyc += BY_USER; else { fprintf(stderr, "%s: '%s' is an invalid " "option to -g!\n", argv[0], optarg); usage(); exit(1); } break; case 'h': usage(); exit(0); break; case 'H': lookuphostc = 1; break; case 'L': fprintf(stderr, "WARNING: -L is deprecated, see the " "FAQ for details.\n"); locationc++; break; case 'm': maxagec = atoi(optarg); break; case 'M': emailreportc++; break; case 'n': groupbynetc = strdup(optarg); break; case 'o': outputdirc = strdup(optarg); break; case 'O': outputurlc = strdup(optarg); break; case 'p': fprintf(stderr, "WARNING: -p is deprecated, see the " "FAQ for details.\n"); phpheadc = strdup(optarg); break; case 'P': fprintf(stderr, "WARNING: -P is deprecated, see the " "FAQ for details.\n"); phpfootc = strdup(optarg); break; case 'r': sortcolumnsc = 1; break; case 'R': showratesc = 1; break; case 's': filtercritc = strdup(optarg); filterbyc += BY_SUBNET; break; case 'S': showtimesc = 1; break; case 't': timesc = strdup(optarg); break; case 'T': fprintf(stderr, "WARNING: -T is deprecated, see the " "FAQ for details.\n"); titlec = strdup(optarg); break; case 'u': filtercritc = strdup(optarg); filterbyc += BY_USER; break; case 'v': verbosec = 1; break; case 'V': printf("srg (Squid Report Generator) %s\n\t%s\n", version, cvsid); exit(1); case '?': usage(); exit(1); break; } } if (conffile != NULL) { if (parse_config(main_config,conffile)) { fprintf(stderr, "Bad Config file %s, giving up\n", conffile); exit(1); } } free(conffile); /* Check if debugging information should be printed */ if (debugc > 0 || debugf > 0) { fprintf(stderr, "Setting 'debug' and 'verbose' rules to true\n"); srg.debug++; srg.verbose = 1; } if (verbosec > 0 || verbosef > 0) { if (srg.debug) fprintf(stderr, "Setting verbose to true\n"); srg.verbose = 1; } //If period is specified in config file, but not in command line if (time_periodf != NULL && strlen(timesc) < 1) { if (srg.debug) fprintf(stderr, "Setting time period to %s from " "config file\n",time_periodf); timesc = time_periodf; } if (titlec != NULL) { if (srg.debug) fprintf(stderr, "Setting title to %s from command " "line\n",titlec); srg.title = strdup(titlec); } else if (titlef != NULL) { if (srg.debug) fprintf(stderr, "Setting title to %s from config " "file\n",titlef); srg.title = strdup(titlef); } free(titlec); free(titlef); if (accesslogc != NULL) { if (srg.debug) fprintf(stderr, "Setting input file to %s from " "command line\n",accesslogc); srg.accessLog = strdup(accesslogc); } else if (accesslogf != NULL) { if (srg.debug) fprintf(stderr, "Setting input file to %s from " "config file\n",accesslogf); srg.accessLog = strdup(accesslogf); } free(accesslogc); free(accesslogf); if (outputdirc != NULL) { if (srg.debug) fprintf(stderr, "Setting output directory to %s " "from command line\n",outputdirc); srg.outputDir = strdup(outputdirc); } else if (outputdirf != NULL) { if (srg.debug) fprintf(stderr, "Setting output directory to %s " "from config file\n",outputdirf); srg.outputDir = strdup(outputdirf); } free(outputdirc); free(outputdirf); if (outputurlc != NULL) { if (srg.debug) fprintf(stderr, "Setting output URL to %s " "from command line\n",outputurlc); srg.outputURL = strdup(outputurlc); } else if (outputurlf != NULL) { if (srg.debug) fprintf(stderr, "Setting output URL to %s " "from config file\n",outputurlf); srg.outputURL = strdup(outputurlf); } free(outputurlc); free(outputurlf); if (cssfilec != NULL) { if (srg.debug) fprintf(stderr, "Setting CSS file to %s from " "command line\n",cssfilec); srg.cssfile = strdup(cssfilec); srg.defaultcss = 0; } else if (cssfilef != NULL) { if (srg.debug) fprintf(stderr, "Setting CSS file to %s from " "config file\n",cssfilef); srg.cssfile = strdup(cssfilef); srg.defaultcss = 0; } else { if (strlen(srg.outputURL)) { asprintf(&srg.cssfile, "%s/%s", srg.outputURL, CSS_NAME); } } free(cssfilec); free(cssfilef); if (phpheadc != NULL) { if (srg.debug) fprintf(stderr, "Setting PHP header file to %s " "from command line\n",phpheadc); srg.phpheader = strdup(phpheadc); } else if (phpheadf != NULL) { if (srg.debug) fprintf(stderr, "Setting PHP header file to %s " "from config file\n",phpheadf); srg.phpheader = strdup(phpheadf); } free(phpheadc); free(phpheadf); if (phpfootc != NULL) { if (srg.debug) fprintf(stderr, "Setting PHP footer file to %s " "from command line\n",phpfootc); srg.phpfooter = strdup(phpfootc); } else if (phpfootf != NULL) { if (srg.debug) fprintf(stderr, "Setting PHP footer file to %s " "from config file\n",phpfootf); srg.phpfooter = strdup(phpfootf); } free(phpfootc); free(phpfootf); if (srg.phpheader || srg.phpfooter) { srg.usephp = true; srg.indexfname = "index.php"; } if (ip2userc != NULL) { if (srg.debug) fprintf(stderr, "Setting IP to user file to %s " "from command line\n",ip2userc); srg.ip2user = strdup(ip2userc); } else if (ip2userf != NULL) { if (srg.debug) fprintf(stderr, "Setting IP to user file to %s " "from config file\n",ip2userf); srg.ip2user = strdup(ip2userf); } free(ip2userc); free(ip2userf); if (maxagec > 0) { if (srg.debug) fprintf(stderr, "Setting maximum report age to " "%d from command line\n",maxagec); srg.maxreportage = maxagec; } else if (maxagef > 0) { if (srg.debug) fprintf(stderr, "Setting maximum report age to " "%d from config file\n",maxagef); srg.maxreportage = maxagef; } if (filterbyc > 0) { if (srg.debug) fprintf(stderr, "Setting 'filter' to %d from " "command line\n",filterbyc); srg.filter.by = filterbyc; } else if (filterbyf != NULL && filtercritf != NULL) { if (strcmp(filterbyf,"BY_IP")==0) srg.filter.by = BY_IP; else if (strcmp(filterbyf, "BY_SUBNET")==0) srg.filter.by = BY_SUBNET; else if (strcmp(filterbyf, "BY_USER")==0) srg.filter.by = BY_USER; else { fprintf(stderr, "Error in config file: '%s' is " "an invalid option to filterby!\n", filterbyf); usage(); exit(1); } if (srg.debug) fprintf(stderr, "Setting 'filter' to %s from " "config file\n",filterbyf); } free(filterbyf); if (filtercritc != NULL) { if (srg.debug) fprintf(stderr, "Setting filter criteria to %s " "from command line\n",filtercritc); switch (srg.filter.by) { case BY_USER: srg.filter.user = strdup(filtercritc); break; case BY_IP: if (inet_aton(filtercritc, &srg.filter.address)==0) { fprintf(stderr, "Invalid filter criteria for " "address filter: %s\n", filtercritc); exit(1); } break; case BY_SUBNET: char *networkAddress; char *netmask; char *tmp = filtercritc; netmask = break_string(tmp, '/'); networkAddress = tmp; if (inet_aton(netmask, &srg.filter.netmask)==0) { fprintf(stderr, "Invalid filter criteria for " "subnet filter (netmask): %s\n", tmp); exit(1); } if (inet_aton(networkAddress, &srg.filter.network)==0) { fprintf(stderr, "Invalid filter criteria for " "subnet filter (network): %s\n", tmp); exit(1); } break; } } else if (filtercritf != NULL && filterbyf != NULL) { if (srg.debug) fprintf(stderr, "Setting filter criteria to %s " "from config file\n",filtercritf); switch (srg.filter.by) { case BY_USER: srg.filter.user = strdup(filtercritf); break; case BY_IP: if (inet_aton(filtercritf, &srg.filter.address)==0) { fprintf(stderr, "Invalid filter criteria for " "address filter: %s\n", filtercritf); exit(1); } break; case BY_SUBNET: char *networkAddress; char *netmask; char *tmp = filtercritf; netmask = break_string(tmp, '/'); networkAddress = tmp; if (inet_aton(netmask, &srg.filter.netmask)==0) { fprintf(stderr, "Invalid filter criteria for " "subnet filter (netmask): %s\n", tmp); exit(1); } if (inet_aton(networkAddress, &srg.filter.network)==0) { fprintf(stderr, "Invalid filter criteria for " "subnet filter (network): %s\n", tmp); exit(1); } break; } } free(filtercritc); filtercritc = NULL; free(filtercritf); filtercritf = NULL; if (groupbyc > 0) { if (srg.debug) fprintf(stderr, "Setting 'groupby' rule to %d " "from command line\n", groupbyc); srg.groupBy = groupbyc; } else if (groupbyf != NULL) { if (strcmp(groupbyf,"A")==0) srg.groupBy += BY_IP; else if (strcmp(groupbyf, "S")==0) { srg.groupBy += BY_SUBNET; if (inet_aton(groupbynetf, &srg.groupByNetmask)==0) { fprintf(stderr, "Error in config file: %s is " "not a valid grouping netmask!\n", groupbynetf); exit(1); } } else if (strcmp(groupbyf, "U")==0) srg.groupBy += BY_USER; else { fprintf(stderr, "Error in config file: '%s' is " "an invalid option to groupby!\n", groupbyf); exit(1); } if (srg.debug) fprintf(stderr, "Setting 'groupby' rule to %s " "from config file\n",groupbyf); } free(groupbyf); if (groupbynetc) { if (srg.debug) fprintf(stderr, "Setting 'groupby netmask' rule " "to %s\n", groupbynetc); if (inet_aton(groupbynetc, &srg.groupByNetmask)==0) { fprintf(stderr, "Error in config file: %s is " "not a valid grouping netmask!\n", groupbynetf); exit(1); } } free(groupbynetc); free(groupbynetf); if (nonameshowipc > 0 || nonameshowipf > 0) { if (srg.debug) fprintf(stderr, "Setting 'noname_showip' rule to " "true\n"); srg.nonameshowip++; } if (locationc > 0 || locationf > 0) { if (srg.debug) fprintf(stderr, "Setting 'show Location reports' " "rule to true\n"); srg.locationStats++; } if (showtimesc > 0 || showtimesf > 0) { if (srg.debug) fprintf(stderr, "Setting 'show times in reports' " "rule to true\n"); srg.showtimes++; } if (showratesc > 0 || showratesf > 0) { if (srg.debug) fprintf(stderr, "Setting 'show rates in reports' " "rule to true\n"); srg.showrates++; } if (hidedeniedc > 0 || hidedeniedf > 0) { if (srg.debug) fprintf(stderr, "Setting 'don't show denied groups' " "rule to true\n"); srg.hideDeniedOnly++; } if (lookuphostc > 0 || (lookuphostf > 0 && lookuphostc < 0)) { if (srg.debug) fprintf(stderr, "Setting 'perform host lookup' " "rule to true\n"); srg.lookupHosts++; } if (authc > 0 || authf > 0) { if (phpheadc == NULL && phpheadf == NULL) { fprintf(stderr, "Must specify a PHP header to " "use authentication."); usage(); exit(1); } if (srg.debug) fprintf(stderr, "Setting 'PHP authentication' " "rule to true\n"); srg.authenticate++; } if (emailreportc || emailreportf) srg.emailreport++; if (sortcolumnsc || sortcolumnsf) { if (srg.debug) fprintf(stderr, "Setting 'column sorting' rule to " "true\n"); srg.sortcolumns++; srg.usejs++; if (strlen(srg.outputURL)>0) { asprintf(&srg.jsfile, "%s/%s", srg.outputURL, SRG_JS_NAME); } } /* if the period is specified at all, set the srg variables so. */ char *sStart=NULL; char *sEnd=NULL; char *tmp=NULL; if (timesc) { /* Parse the command line option and get the start and end * times */ tmp = strdup(timesc); sEnd = break_string(tmp, '-'); sStart = tmp; if (!sStart || !sEnd) { fprintf(stderr, "%s: invalid time format on the " "commandline!\nRun with -h for usage info.\n", argv[0]); exit(1); } srg.startTime = get_date(sStart, NULL); srg.endTime = get_date(sEnd, NULL); sStart = NULL; sEnd = NULL; free(tmp); /* Check that the start and end times were valid */ if (srg.startTime==-1 || srg.endTime==-1) { fprintf(stderr, "%s: unable to parse the start or end" "time!\nRun with -h for usage info.\n", argv[0]); exit(1); } /* Check that the end time is after the start time */ if (srg.startTime == srg.endTime) { struct tm * starttm = localtime(&srg.startTime); if (starttm->tm_hour == 0 && starttm->tm_min == 0 && starttm->tm_sec == 0) { if (srg.debug) fprintf(stderr,"No times specified, " "assuming start at 00:00 " "and end at 23:59"); srg.endTime += 86399; } } if (srg.startTime >= srg.endTime) { fprintf(stderr, "%s: End Time must be after Start " "Time!\n", argv[0]); usage(); exit(1); } } free(timesc); /* Only allowed to filter on one Criteria */ if (srg.groupBy > BY_MAX) { fprintf(stderr, "%s: -a -s -u options are mutually " "exclusive!\n", argv[0]); usage(); exit(1); } /* Check required parameters are set */ if (srg.groupBy == BY_SUBNET) { if (srg.groupByNetmask.s_addr==0) { fprintf(stderr, "%s: please specify a netmask " "with -n!\n", argv[0]); usage(); exit(1); } } return true; } /* Set program defaults */ void set_defaults(void) { srg.debug=0; srg.verbose=0; srg.groupBy=0; srg.showtimes=0; srg.showrates=0; srg.nonameshowip=0; srg.startTime=(time_t)0; srg.endTime=(time_t)0; srg.accessLog="access.log"; srg.outputDir="srg_reports"; srg.outputURL=""; srg.filter.by= BY_NONE; srg.filter.user = NULL; srg.filter.address.s_addr=0; srg.filter.network.s_addr=0; srg.filter.netmask.s_addr=0; srg.groupByNetmask.s_addr=0; srg.cssfile=CSS_NAME; srg.title="SRG - Squid Log Analysis"; srg.phpheader=NULL; srg.phpfooter=NULL; srg.indexfname = "index.html"; srg.ip2user=NULL; srg.locationStats=1; srg.hideDeniedOnly=0; srg.authenticate=0; srg.lookupHosts=0; srg.emailreport=0; srg.maxreportage=0; srg.usephp = false; srg.defaultcss=1; srg.sortcolumns=0; srg.jsfile=SRG_JS_NAME; srg.usejs=0; } /* Initialise the javascript in the specified directory */ void init_javascript(const char *dir) { char *filename = NULL; FILE *outfile = NULL; /* Check if the script file already exists */ asprintf(&filename, "%s/%s", dir, SRG_JS_NAME); if (access(filename, R_OK)==0) { free(filename); return; } /* Create the file */ outfile = fopen(filename, "w"); if (!outfile) { fprintf(stderr, "Error: Could not open %s for writing! - %s\n", filename, strerror(errno)); free(filename); exit(1); } /* Write out the script file */ fprintf(outfile, "/* SRG %s - Default Javascript \n", version); fprintf(outfile, " *\n" " * If you make modifications to this script you *must* modify the \n" " * first line otherwise your changes may be overwritten when SRG is\n" " * upgraded.\n" " * \n" " */\n\n" "function extractOrder(order) {\n" " if (order==1)\n" " return \"descending\";\n" " else\n" " return \"ascending\";\n" "}\n" "function extractText(cell) {\n" " if (cell.hasChildNodes()) {\n" " return extractText(cell.childNodes[0]);\n" " } else {\n" " return cell.nodeValue;\n" " }\n" "}\n" "function makeHeader(row, celln, ord) {\n" " var link, cell;\n" " cell = row.cells[celln];\n" " cellt = extractText(cell)\n" " ot = extractOrder(ord)\n" " link =\"\"+cellt+\"\";\n" " cell.innerHTML=link;\n" "}\n" "g_table=document.getElementById(\"srgtable\");\n" "g_head_rows=g_table.tHead.rows\n" "g_msgdiv=document.getElementById(\"srg-message\");\n" "if (g_head_rows.length==1) {\n" " for (i=0;i