📄 bandwidthd.c
字号:
#include "bandwidthd.h"#ifdef HAVE_LIBPQ#include <libpq-fe.h>#endif// We must call regular exit to write out profile data, but child forks are supposed to usually// call _exit?#ifdef PROFILE#define _exit(x) exit(x)#endif/*#ifdef DEBUG#define fork() (0)#endif*/// ****************************************************************************************// ** Global Variables// ****************************************************************************************static pcap_t *pd;unsigned int GraphIntervalCount = 0;unsigned int IpCount = 0;unsigned int SubnetCount = 0;time_t IntervalStart;int RotateLogs = FALSE; struct SubnetData SubnetTable[SUBNET_NUM];struct IPData IpTable[IP_NUM];int DataLink;int IP_Offset;struct IPDataStore *IPDataStore = NULL;extern int bdconfig_parse(void);extern FILE *bdconfig_in;struct config config;pid_t workerchildpids[NR_WORKER_CHILDS];void signal_handler(int sig) { switch (sig) { case SIGHUP: signal(SIGHUP, signal_handler); RotateLogs++; if (config.tag == '1') { int i; /* signal children */ for (i=0; i < NR_WORKER_CHILDS; i++) kill(workerchildpids[i], SIGHUP); } break; case SIGTERM: if (config.tag == '1') { int i; /* send term signal to children */ for (i=0; i < NR_WORKER_CHILDS; i++) kill(workerchildpids[i], SIGTERM); } // TODO: Might want to make sure we're not in the middle of wrighting out a log file exit(0); break; } }void bd_CollectingData(char *filename) { FILE *index; index = fopen(filename, "wt"); if (index) { fprintf(index, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n"); fprintf(index, "<HTML><HEAD><TITLE>Bandwidthd</TITLE>\n"); if (config.meta_refresh) fprintf(index, "<META HTTP-EQUIV=\"REFRESH\" content=\"%u\">\n", config.meta_refresh); fprintf(index, "<META HTTP-EQUIV=\"EXPIRES\" content=\"-1\">\n"); fprintf(index, "<META HTTP-EQUIV=\"PRAGMA\" content=\"no-cache\">\n"); fprintf(index, "</HEAD>\n<BODY><center><img src=\"logo.gif\" ALT=\"Logo\"><BR>\n"); fprintf(index, "<BR>\n - <a href=\"index.html\">Daily</a> -- <a href=\"index2.html\">Weekly</a> -- "); fprintf(index, "<a href=\"index3.html\">Monthly</a> -- <a href=\"index4.html\">Yearly</a><BR>\n"); fprintf(index, "</CENTER><BR>bandwidthd has nothing to graph. This message should be replaced by graphs in a few minutes. If it's not, please see the section titled \"Known Bugs and Troubleshooting\" in the README"); fprintf(index, "</BODY></HTML>\n"); fclose(index); } else { syslog(LOG_ERR, "Cannot open %s for writing", filename); exit(1); } }int WriteOutWebpages(long int timestamp){ struct IPDataStore *DataStore = IPDataStore; struct SummaryData **SummaryData; int NumGraphs = 0; pid_t graphpid; int Counter; /* Did we catch any packets since last time? */ if (!DataStore) return -1; // break off from the main line so we don't miss any packets while we graph graphpid = fork(); switch (graphpid) { case 0: /* we're the child, graph. */ {#ifdef PROFILE // Got this incantation from a message board. Don't forget to set // GMON_OUT_PREFIX in the shell extern void _start(void), etext(void); syslog(LOG_INFO, "Calling profiler startup..."); monstartup((u_long) &_start, (u_long) &etext);#endif signal(SIGHUP, SIG_IGN); nice(4); // reduce priority so I don't choke out other tasks // Count Number of IP's in datastore for (DataStore = IPDataStore, Counter = 0; DataStore; Counter++, DataStore = DataStore->Next); // +1 because we don't want to accidently allocate 0 SummaryData = malloc(sizeof(struct SummaryData *)*Counter+1); DataStore = IPDataStore; while (DataStore) // Is not null { if (DataStore->FirstBlock->NumEntries > 0) { SummaryData[NumGraphs] = (struct SummaryData *) malloc(sizeof(struct SummaryData)); GraphIp(DataStore, SummaryData[NumGraphs++], timestamp+LEAD*config.range); } DataStore = DataStore->Next; } MakeIndexPages(NumGraphs, SummaryData); _exit(0); } break; case -1: syslog(LOG_ERR, "Forking grapher child failed!"); return -2; break; default: /* parent + successful fork, assume graph success */ return 0; break; }}void setchildconfig (int level) { static unsigned long long graph_cutoff; switch (level) { case 0: config.range = RANGE1; config.interval = INTERVAL1; config.tag = '1'; graph_cutoff = config.graph_cutoff; break; case 1: // Overide skip_intervals for children config.skip_intervals = CONFIG_GRAPHINTERVALS; config.range = RANGE2; config.interval = INTERVAL2; config.tag = '2'; config.graph_cutoff = graph_cutoff*(RANGE2/RANGE1); break; case 2: // Overide skip_intervals for children config.skip_intervals = CONFIG_GRAPHINTERVALS; config.range = RANGE3; config.interval = INTERVAL3; config.tag = '3'; config.graph_cutoff = graph_cutoff*(RANGE3/RANGE1); break; case 3: // Overide skip_intervals for children config.skip_intervals = CONFIG_GRAPHINTERVALS; config.range = RANGE4; config.interval = INTERVAL4; config.tag = '4'; config.graph_cutoff = graph_cutoff*(RANGE4/RANGE1); break; default: syslog(LOG_ERR, "setchildconfig got an invalid level argument: %d", level); _exit(1); }}void makepidfile(pid_t pid) { FILE *pidfile; pidfile = fopen("/var/run/bandwidthd.pid", "wt"); if (pidfile) { if (fprintf(pidfile, "%d\n", pid) == 0) { syslog(LOG_ERR, "Bandwidthd: failed to write '%d' to /var/run/bandwidthd.pid", pid); fclose(pidfile); unlink("/var/run/bandwidthd.pid"); } else fclose(pidfile); } else syslog(LOG_ERR, "Could not open /var/run/bandwidthd.pid for write"); }int main(int argc, char **argv) { struct bpf_program fcode; u_char *pcap_userdata = 0;#ifdef HAVE_PCAP_FINDALLDEVS pcap_if_t *Devices;#endif char Error[PCAP_ERRBUF_SIZE]; struct stat StatBuf; int i; int ForkBackground = TRUE; int ListDevices = FALSE; int Counter; config.dev = NULL; config.filter = "ip"; config.skip_intervals = CONFIG_GRAPHINTERVALS; config.graph_cutoff = CONFIG_GRAPHCUTOFF; config.promisc = TRUE; config.graph = TRUE; config.output_cdf = FALSE; config.recover_cdf = FALSE; config.meta_refresh = CONFIG_METAREFRESH; config.output_database = FALSE; config.db_connect_string = NULL; config.sensor_id = "unset"; openlog("bandwidthd", LOG_CONS, LOG_DAEMON); if (stat("./etc/bandwidthd.conf", &StatBuf)) { chdir(INSTALL_DIR); if (stat("./etc/bandwidthd.conf", &StatBuf)) { printf("Cannot find ./etc/bandwidthd.conf or %s/etc/bandwidthd.conf\n", INSTALL_DIR); syslog(LOG_ERR, "Cannot find ./etc/bandwidthd.conf or %s/etc/bandwidthd.conf", INSTALL_DIR); exit(1); } } bdconfig_in = fopen("./etc/bandwidthd.conf", "rt"); if (!bdconfig_in) { syslog(LOG_ERR, "Cannot open bandwidthd.conf"); printf("Cannot open ./etc/bandwidthd.conf\n"); exit(1); } bdconfig_parse(); /* // Scary printf("Estimated max ram utilization\nDataPoints = %.0f/%ld = %.0f\nIPData = %d * DataPoints = %.1f (%.2fKBytes) per IP\nIP_NUM = %d\nTotal = %.1fMBytes * 4 to 8 = %.1fMBytes to %.1fMBytes\n", RANGE1, INTERVAL1, RANGE1/INTERVAL1, sizeof(struct IPData), (float) sizeof(struct IPData)*(RANGE1/INTERVAL1), (float) (sizeof(struct IPData)*(RANGE1/INTERVAL1))/1024.0, IP_NUM, (float)((sizeof(struct IPData)*(RANGE1/INTERVAL1)*IP_NUM)/1024.0)/1024.0, (float)4*((sizeof(struct IPData)*(RANGE1/INTERVAL1)*IP_NUM)/1024.0)/1024.0, (float)8*((sizeof(struct IPData)*(RANGE1/INTERVAL1)*IP_NUM)/1024.0)/1024.0); printf("Sizeof unsigned long: %d, sizeof unsigned long long: %d\n%lu, %llu\n", sizeof(unsigned long), sizeof (unsigned long long), (unsigned long) (0-1), (unsigned long long) (0-1)); exit(1); */ for(Counter = 1; Counter < argc; Counter++) { if (argv[Counter][0] == '-') { switch(argv[Counter][1]) { case 'D': ForkBackground = FALSE; break; case 'l': ListDevices = TRUE; break; default: printf("Improper argument: %s\n", argv[Counter]); exit(1); } } }#ifdef HAVE_PCAP_FINDALLDEVS pcap_findalldevs(&Devices, Error); if (config.dev == NULL && Devices->name) config.dev = strdup(Devices->name); if (ListDevices) { while(Devices) { printf("Description: %s\nName: \"%s\"\n\n", Devices->description, Devices->name); Devices = Devices->next; } exit(0); }#else if (ListDevices) { printf("List devices is not supported by you version of libpcap\n"); exit(0); }#endif if (config.graph) { bd_CollectingData("htdocs/index.html"); bd_CollectingData("htdocs/index2.html"); bd_CollectingData("htdocs/index3.html"); bd_CollectingData("htdocs/index4.html"); } /* detach from console. */ if (ForkBackground) if (fork2()) exit(0); makepidfile(getpid()); setchildconfig(0); /* initialize first (day graphing) process config */ if (config.graph || config.output_cdf) { /* fork processes for week, month and year graphing. */ for (i=0; i<NR_WORKER_CHILDS; i++) { workerchildpids[i] = fork(); /* initialize children and let them start doing work, * while parent continues to fork children. */ if (workerchildpids[i] == 0) { /* child */ setchildconfig(i+1); break; } if (workerchildpids[i] == -1) { /* fork failed */ syslog(LOG_ERR, "Failed to fork graphing child (%d)", i); /* i--; ..to retry? -> possible infinite loop */ continue; } } if(config.recover_cdf) RecoverDataFromCDF(); } IntervalStart = time(NULL); syslog(LOG_INFO, "Opening %s", config.dev); pd = pcap_open_live(config.dev, 100, config.promisc, 1000, Error); if (pd == NULL) { syslog(LOG_ERR, "%s", Error); exit(0); } if (pcap_compile(pd, &fcode, config.filter, 1, 0) < 0) { pcap_perror(pd, "Error"); printf("Malformed libpcap filter string in bandwidthd.conf\n"); syslog(LOG_ERR, "Malformed libpcap filter string in bandwidthd.conf"); exit(1); } if (pcap_setfilter(pd, &fcode) < 0) pcap_perror(pd, "Error"); switch (DataLink = pcap_datalink(pd)) { default: if (config.dev) printf("Unknown Datalink Type %d, defaulting to ethernet\nPlease forward this error message and a packet sample (captured with \"tcpdump -i %s -s 2000 -n -w capture.cap\") to hinkle@derbyworks.com\n", DataLink, config.dev); else printf("Unknown Datalink Type %d, defaulting to ethernet\nPlease forward this error message and a packet sample (captured with \"tcpdump -s 2000 -n -w capture.cap\") to hinkle@derbyworks.com\n", DataLink); syslog(LOG_INFO, "Unkown datalink type, defaulting to ethernet"); case DLT_EN10MB: syslog(LOG_INFO, "Packet Encoding: Ethernet"); IP_Offset = 14; //IP_Offset = sizeof(struct ether_header); break; #ifdef DLT_LINUX_SLL case DLT_LINUX_SLL: syslog(LOG_INFO, "Packet Encoding: Linux Cooked Socket"); IP_Offset = 16; break;#endif#ifdef DLT_RAW case DLT_RAW: printf("Untested Datalink Type %d\nPlease report to hinkle@derbyworks.net if bandwidthd works for you\non this interface\n", DataLink); printf("Packet Encoding:\n\tRaw\n"); syslog(LOG_INFO, "Untested packet encoding: Raw"); IP_Offset = 0; break;#endif case DLT_IEEE802: printf("Untested Datalink Type %d\nPlease report to hinkle@derbyworks.net if bandwidthd works for you\non this interface\n", DataLink); printf("Packet Encoding:\nToken Ring\n"); syslog(LOG_INFO, "Untested packet encoding: Token Ring");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -