/* 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" /* Compares two date strings of the format YYYYMMMDD-YYYYMMDD. Returns true if * date1 is less than date2. * Dates are compared on the start date first and then the end date if * necessary */ int compare_datename(const char *date1, const char *date2) { int rv=0; char tmp1[10]; char tmp2[10]; /* Exit Immediately if we weren't passed valid dates */ if(date1==NULL || date2==NULL) return -1; if (strlen(date1) != 19 || strlen(date2) != 19) return -1; /* Extract the start dates */ strncpy(tmp1, date1, 9); strncpy(tmp2, date2, 9); tmp1[9] = tmp2[9] = '\0'; rv = compare_datepart(tmp1, tmp2); /* If start dates were identical, compare end dates */ if (rv==0) { strncpy(tmp1, date1+10, 9); strncpy(tmp2, date2+10, 9); tmp1[9] = tmp2[9] = '\0'; rv = compare_datepart(tmp1, tmp2); } /* Convert greater than to false */ if (rv==-1) rv=0; return rv; } /* Compares two date strings of the format YYYYMMMDD. Returns true if date1 is * less than date2 false if they are equal or -1 if date1 is greater than * date2. */ int compare_datepart(const char *date1, const char *date2) { char year1[5], year2[5]; char month1[4], month2[4]; char day1[3], day2[3]; /* Exit Immediately if we weren't passed valid dates */ if(date1==NULL || date2==NULL) return -1; if (strlen(date1) != 9 || strlen(date2) != 9) return -1; /* Break the start dates out into their components */ strncpy(year1, date1, 4); year1[4] = '\0'; strncpy(month1, date1+4, 3); month1[3] = '\0'; strncpy(day1, date1+7, 2); day1[2] = '\0'; strncpy(year2, date2, 4); year2[4] = '\0'; strncpy(month2, date2+4, 3); month2[3] = '\0'; strncpy(day2, date2+7, 2); day2[2] = '\0'; /* Compare Years */ if (atoi(year1) < atoi(year2)) return 1; else if (atoi(year1) > atoi(year2)) return -1; /* Compare Months */ if (getMonthByName(month1) < getMonthByName(month2)) return 1; else if (getMonthByName(month1) > getMonthByName(month2)) return -1; /* Compare Days */ if (atoi(day1) < atoi(day2)) return 1; else if (atoi(day1) > atoi(day2)) return -1; /* Greater than or Equal */ return 0; } /* Generates a suitable date string from the specified start and end times. * The generated string will be in the format YYYYMMMDD-YYYYMMDD and will be * asprintf'd in to the supplied char* * * Returns 0 on success, > 0 on failure */ char *generate_datename(const time_t start, const time_t end) { if (start < 1 || end < 1) return NULL; char *outstr = NULL; char sday[3]; char eday[3]; sprintf(sday, "%02d", localtime(&start)->tm_mday); sprintf(eday, "%02d", localtime(&end)->tm_mday); asprintf(&outstr, "%d%s%s-%d%s%s", localtime(&start)->tm_year+1900, month_names[localtime(&start)->tm_mon], sday, localtime(&end)->tm_year+1900, month_names[localtime(&end)->tm_mon], eday); return outstr; } /* Write the HTML header */ void html_header(FILE *outfile, const char *rootpath) { /* rootpath is used when the user is generating a stock standard report with no outputURL set. Each report sends through a string like ../../ that provides a path from the directory that this file will reside in to the top level output directory. This string is only used if srg.outputURL is not set */ char *base=""; if (strlen(srg.outputURL)==0 && strlen(rootpath)>0) base = strdup(rootpath); /* Header & Title */ if (srg.usephp && srg.phpheader!=NULL) { /* Include the specified PHP header */ fprintf(outfile, "\n", srg.phpheader); if (srg.authenticate) { fprintf(outfile, "\n\t"); } } else { /* Output a static HTML Header */ fprintf(outfile, "\n"); fprintf(outfile, "\n\n%s\n", srg.title); fprintf(outfile, "\n", version, HOME_URL); fprintf(outfile, "\n"); fprintf(outfile, "\n\n\n", base, srg.cssfile); /* Output some basic layout and headers */ fprintf(outfile, "\n

%s

" "
\n\n", srg.title); } if (strlen(base)>0) free(base); } /* Write the HTML footer */ void html_footer(FILE *outfile, const char *rootpath) { /* rootpath is used when the user is generating a stock standard report with no outputURL set. Each report sends through a string like ../../ that provides a path from the directory that this file will reside in to the top level output directory. This string is only used if srg.outputURL is not set */ char *base=""; if (strlen(srg.outputURL)==0 && strlen(rootpath)>0) base = strdup(rootpath); fprintf(outfile, "
Generated by SRG %s
\n\n", HOME_URL, version); if (srg.usephp && srg.phpfooter!=NULL) { /* Include the specified PHP footer */ fprintf(outfile, "\n"); if (srg.usejs) { fprintf(outfile, "\n", base, srg.jsfile); } fprintf(outfile, "\n"); } if (strlen(base)>0) free(base); } /* Determines whether the specified Cache Result Code is a cache hit */ bool is_cache_hit(const char * inputCode) { // Extract the result code from the status code bool hit=false; char *resultCode; char *tmp = strdup(inputCode); break_string(tmp, '/'); resultCode = tmp; if (!resultCode) { fprintf(stderr, "Incorrect result code! %s\n", inputCode); exit(1); } if (srg.debug) fprintf(stderr, "Checking if %s is a cache hit\n", inputCode); if (strcasecmp(resultCode, "TCP_HIT")==0) hit = true; else if (strcasecmp(resultCode, "TCP_REFRESH_HIT")==0) hit = true; else if (strcasecmp(resultCode, "TCP_REF_FAIL_HIT")==0) hit = true; else if (strcasecmp(resultCode, "TCP_IMS_HIT")==0) hit = true; else if (strcasecmp(resultCode, "TCP_NEGATIVE_HIT")==0) hit = true; else if (strcasecmp(resultCode, "TCP_MEM_HIT")==0) hit = true; else if (strcasecmp(resultCode, "TCP_OFFLINE_HIT")==0) hit = true; else if (strcasecmp(resultCode, "UDP_HIT")==0) hit = true; resultCode = NULL; free(tmp); return hit; } /* Determines whether the specified Cache Result Code was a deny */ bool is_cache_denied(const char * inputCode) { // Extract the result code from the status code bool denied=false; char *resultCode; char *tmp = strdup(inputCode); break_string(tmp, '/'); resultCode = tmp; if (!resultCode) { fprintf(stderr, "Incorrect result code! %s\n", inputCode); exit(1); } if (srg.debug) fprintf(stderr, "Checking if %s is a cache denied\n", inputCode); if (strcasecmp(resultCode, "TCP_DENIED")==0) denied = true; else if (strcasecmp(resultCode, "UDP_DENIED")==0) denied = true; resultCode = NULL; free(tmp); return denied; } /* Converts a short 3-char month abbreviation into it's numerical equivalent */ int getMonthByName(const char *month_name) { if (strcasecmp(month_name,"Jan")==0) return 0; else if (strcasecmp(month_name,"Feb")==0) return 1; else if (strcasecmp(month_name,"Mar")==0) return 2; else if (strcasecmp(month_name,"Apr")==0) return 3; else if (strcasecmp(month_name,"May")==0) return 4; else if (strcasecmp(month_name,"Jun")==0) return 5; else if (strcasecmp(month_name,"Jul")==0) return 6; else if (strcasecmp(month_name,"Aug")==0) return 7; else if (strcasecmp(month_name,"Sep")==0) return 8; else if (strcasecmp(month_name,"Oct")==0) return 9; else if (strcasecmp(month_name,"Nov")==0) return 10; else if (strcasecmp(month_name,"Dec")==0) return 11; assert(0); return -1; } unsigned int getNumericalIP(const char *IPAddress) { unsigned int address=0; /* Get the four components of the IP Address */ unsigned int o1, o2, o3, o4; if (sscanf(IPAddress, "%i.%i.%i.%i", &o1, &o2, &o3, &o4) != 4) { fprintf(stderr, "Invalid IP Address: %s\n", IPAddress); exit(1); } assert(o1<256 && o2 <256 && o3<256 && o4<256); /* Convert it to decimal */ address = (o1<<24)&(o2<<16)&(o3<<8)&(o4); return address; } char *getStringIP(const unsigned int IPAddress) { char *address; asprintf(&address, "%i.%i.%i.%i", (IPAddress>>24)&0xff, (IPAddress>>16)&0xff, (IPAddress>>8)&0xff, (IPAddress)&0xff); return address; } void getNetworkAddress(const in_addr clientAddress, const in_addr netmask, in_addr *network) { network->s_addr = ((clientAddress.s_addr|(~netmask.s_addr))& netmask.s_addr); } char * cleanseStr(char * dirty) { for (unsigned int i = 0; i < strlen(dirty); i++) { if (dirty[i] == ' ' || dirty[i] == '\t' || dirty[i] == '\n') { dirty[i] = '_'; } else { switch(dirty[i]) { case '/': dirty[i] = '^'; break; case '.': dirty[i] = '_'; break; case '?': dirty[i] = '^'; break; case '|': dirty[i] = '^'; break; case '&': dirty[i] = '^'; break; case ';': dirty[i] = '^'; break; case '(': dirty[i] = '^'; break; case ')': dirty[i] = '^'; break; case '*': dirty[i] = '^'; break; case '@': dirty[i] = '^'; break; case '$': dirty[i] = '^'; break; case '`': dirty[i] = '^'; break; case '"': dirty[i] = '^'; break; case '#': dirty[i] = '^'; break; case '!': dirty[i] = '^'; break; case '[': dirty[i] = '^'; break; case ']': dirty[i] = '^'; break; //dirty.insert(i-1, "\\"); break; <- no good } } } return dirty; } char * FormatOutput(unsigned long long num) { int SrcLen; int ExtLen; int c; int d; int grp; int group = 3; char sep_char = ','; char buf[50]; sprintf(buf, "%llu", num); SrcLen = strlen(buf)-1; ExtLen = SrcLen+(SrcLen/group); char *Work = (char *)malloc(ExtLen+2); grp = 0; c = ExtLen; d = SrcLen; if (c > grp) { while (c >= 0) { if (grp == group) { Work[c]= sep_char; --c; grp = 0; } Work[c] = buf[d]; --c; --d; ++grp; } Work[ExtLen+1] = '\0'; } else { free(Work); Work = strdup(buf); } return Work; } /* Return the MD5 Hash of the specified string */ char *md5this(const char plaintextstr[]) { md5_state_t hash_state; md5_byte_t digest[16]; char hex_output[64]; int di; md5_init(&hash_state); md5_append(&hash_state, (const md5_byte_t *) plaintextstr, strlen(plaintextstr)); md5_finish(&hash_state, digest); for (di = 0; di < 16; ++di) { sprintf(hex_output + di*2, "%02x", digest[di]); } return strdup(hex_output); } /* Replaces the first occurence of delim with a null character and returns a * pointer to the next character after it or NULL if there is no more string * left. */ char *break_string(char *string, char delim) { unsigned int i=0; bool delimfound=false; while (string[i] != '\0') { if (string[i] == delim) { string[i] = '\0'; delimfound = true; } i++; if (delimfound) { return &string[i]; } } return NULL; }