/* ipfwcount 1.0 (c) Nikolay Moroshkin [www.moroshkin.com] CP866 Программка месячного подсчета счетчиков ipfw. Вызов: ipfwcount входной_файл директория где: входной_файл - файл, содержащий вывод команды "ipfw show" директория - куда класть результаты работы Суть работы: Значения счетчиков (количества пакетов и байтов) из входного файла добавляются к значениям счетчиков файла YYYY-MM.ipfwcount в указанной директории (YYYY - текущий год, MM - месяц), если его нет, он создается. Вывод программы на stdout соответствует тому, что она запишет в этот файл. Его формат аналогичен выводу команды "ipfw show". Больше программа ничего не делает (предполагается остальное возлагать на скрипты). Если во входных данных есть правила с одинаковыми номерами значения их счетчиков будут объедены с тем, которое первым встретилось. Если в процессе периодических запусков появится новое правило, оно будет добавлено к выходному файлу. Если входной файл не существует или невозможно его прочитать, программа ничего не скажет и ничего не добавит к результирующему файлу. Такое же поведение будет, если входной файл пуст. Компиляция: # cc -o ipfwcount ipfwcount.c Пример использования: # ipfw show > /ipfwcount/current.rules.tmp # ipfw -q zero # /ipfwcount/ipfwcount /ipfwcount/current.rules.tmp /ipfwcount # rm /ipfwcount/current.rules.tmp (например, раз в месяц или когда нужно посмотреть текущие значения) В дополнение можно по cron'у делать "ipfw show > backup.rules" каждую минуту, а при перезагрузке скармливать этот файл ipfwcount (после чего удалить backup.rules). */ #include #include #include /* определим тип string, дабы меньше писать в дальнейшем */ #define MAX_STRING_SIZE 256 typedef char string[MAX_STRING_SIZE]; /* структура для хранения полей правила */ struct rule_struct { struct rule_struct *next; unsigned short number; unsigned long packets; unsigned long bytes; string body; }; typedef struct rule_struct rule; /* *********************************************************************** next_pos() Вход: строка данных, разделенных пробелами Выход: указатель на следующее поле данных в строке */ char *next_pos(char *str) { while( *str && (*str!=' ' && *str!='\t') ) str++; while( *str && (*str==' ' || *str=='\t') ) str++; return(str); } /* *********************************************************************** get_rules() - считывает правила и счетчики ipfw в цепочку структур Вход: имя файла в формате ipfw show Выход: цепочка из структур rule. В крайней поле next == NULL */ rule *get_rules(const char *fn) { FILE *wfs; string str; rule *root,*curr; char *ptr,*bptr; if( (wfs=fopen(fn,"rt")) == NULL ) return(NULL); root=curr=NULL; while( fgets(str,MAX_STRING_SIZE,wfs) ) if( str[0]>='0' && str[0]<='9' ) { ptr=str; if(curr) curr=( curr->next=(rule*)malloc(sizeof(rule)) ); else curr=( root=(rule*)malloc(sizeof(rule)) ); curr->next=NULL; curr->number=atoi(ptr); ptr=next_pos(ptr); curr->packets=atol(ptr); ptr=next_pos(ptr); curr->bytes=atol(ptr); ptr=next_pos(ptr); bptr=curr->body; while( *ptr && *ptr!='\n' ) *bptr++ = *ptr++; *bptr = '\0'; } fclose(wfs); return(root); } /* *********************************************************************** free_rules() - освобождает память от цепочки правил Вход: цепочка правил */ void free_rules(rule *root) { rule *tmp; while(root) { tmp=root->next; free(root); root=tmp; } } /* *********************************************************************** fprint_rules() - печатает в поток вывода цепочку правил Вход: поток вывода, цепочка правил */ void fprint_rules(FILE *fs, rule *root) { while(root) { fprintf(fs,"%05hu %8lu %10lu %s\n",root->number,root->packets,root->bytes,root->body); root=root->next; } } /* *********************************************************************** get_result_fn() - формирует имя для файла результатов исходя из даты Вход: директория (переданная через коммандную строку) место, куда положить результат работы ф-ции */ void get_result_fn(const char *dir, string fn) { time_t timer; struct tm *tblock; time(&timer); tblock=localtime(&timer); if(tblock) sprintf(fn,"%s/%d-%2.2d.ipfwcount",dir,tblock->tm_year+1900,tblock->tm_mon+1); else sprintf(fn,"%s/localtime_error.ipfwcount"); } /* *********************************************************************** main() Возвращает: 0 - при нормальной работе 1 - при неверных параметрах в коммандной строке 3 - если не удалось перезаписать файл результатов */ int main(int argc, char *argv[]) { FILE *fs; rule *summand,*result,*s_ptr,*r_ptr; string result_fn; if(argc<3) { printf("Usage: ipfwcount ipfw-show_file log_directory\n"); exit(1); } /* получаем имя файла результатов */ get_result_fn(argv[2],result_fn); /* читаем правила */ summand=get_rules(argv[1]); result=get_rules(result_fn); /* складываем. Если result==NULL, то result=summand */ if(result) for(s_ptr=summand;s_ptr;s_ptr=s_ptr->next) { for(r_ptr=result;r_ptr;r_ptr=r_ptr->next) if( r_ptr->number == s_ptr->number ) { r_ptr->packets += s_ptr->packets; r_ptr->bytes += s_ptr->bytes; break; } if( r_ptr == NULL ) { r_ptr=(rule*)malloc(sizeof(rule)); r_ptr->number=s_ptr->number; r_ptr->packets=s_ptr->packets; r_ptr->bytes=s_ptr->bytes; memcpy(r_ptr->body,s_ptr->body,MAX_STRING_SIZE); r_ptr->next=result; result=r_ptr; } } else { s_ptr=summand; summand=result; result=s_ptr; } /* сохраняем и печатаем result */ if( (fs=fopen(result_fn,"wt")) == NULL ) { printf("Error rewriting %s\n",result_fn); exit(2); } fprint_rules(fs,result); fprint_rules(stdout,result); fclose(fs); /* освобождаем память */ free_rules(summand); free_rules(result); return(0); }