From af37be1dccdd5c9b86113a6e02ed794da3102ec4 Mon Sep 17 00:00:00 2001 From: xchaos Date: Tue, 29 Oct 2013 01:32:04 +0000 Subject: [PATCH] network analyzer - first attempt git-svn-id: https://dev.arachne.cz/repos/prometheus/trunk@227 251d49ef-1d17-4917-a970-b30cf55b089b --- Makefile | 2 +- check-kernel-qos | 24 ------ help.c | 1 + ipstruct.h | 3 +- networks.c | 107 +++++++++++++++++++++++++ parsehosts.c | 199 ++++++++++++++++++++++++++++++----------------- parseiptables.c | 4 +- prometheus.c | 35 ++++++--- 8 files changed, 262 insertions(+), 113 deletions(-) delete mode 100755 check-kernel-qos create mode 100644 networks.c diff --git a/Makefile b/Makefile index 0ca93d5..5f3a608 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ prefix=/usr mandir=$(prefix)/share/man sbindir=$(prefix)/sbin sysconfdir=/etc -OBJECTS=parsehosts.o parseiptables.o parselogs.o ipv4subnets.o ipv6subnets.o json.o htmlandlogs.o help.o prometheus.o +OBJECTS=parsehosts.o networks.o parseiptables.o parselogs.o ipv4subnets.o ipv6subnets.o json.o htmlandlogs.o help.o prometheus.o HEADERS=cll1-0.6.2.h ipstruct.h main: prometheus diff --git a/check-kernel-qos b/check-kernel-qos deleted file mode 100755 index e2ac020..0000000 --- a/check-kernel-qos +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash - -echo -n "Checking for HTB support (2.6.x Linux kernel series only) ..." -HTB=`cat /proc/config.gz |gunzip|grep CONFIG_NET_SCH_HTB` -if [ "$HTB" = "CONFIG_NET_SCH_HTB=y" ] || [ "$HTB" = "CONFIG_NET_SCH_HTB=m" ] -then - echo " ok." -else - echo " failed!" - echo "** Missing /proc/config.gz, missing gunzip, or missing HTB support in kernel.. **" - echo "** You are likely to get RTNETLINK error messages when running Prometheus QoS. **" -fi - -echo -n "Checking for SFQ support (2.6.x Linux kernel series only) ..." -SFQ=`cat /proc/config.gz |gunzip|grep CONFIG_NET_SCH_SFQ` -if [ "$SFQ" = "CONFIG_NET_SCH_SFQ=y" ] || [ "$SFQ" = "CONFIG_NET_SCH_SFQ=m" ] -then - echo " ok." -else - echo " failed!" - echo "** Missing /proc/config.gz, missing gunzip, or missing SFQ support in kernel.. **" - echo "** You are likely to get RTNETLINK error messages when running Prometheus QoS. **" -fi - diff --git a/help.c b/help.c index af7368f..c8edf23 100644 --- a/help.c +++ b/help.c @@ -24,6 +24,7 @@ void help(void) -l Mmm YYYY generate HTML summary of Logged traffic (Mmm=Jan-Dec) (and exit)\n\ -m generate HTML summary of traffic for yesterday's Month (and exit)\n\ -y generate HTML summary of traffic for yesterday's Year (and exit)\n\ +-a analyse network topology (agregation statistics, using traceroute)\n\ -? --help show this help scree (and exit)\n\ -v --version show Version number of this utility (and exit)\n"); } diff --git a/ipstruct.h b/ipstruct.h index ea79749..a80946d 100644 --- a/ipstruct.h +++ b/ipstruct.h @@ -21,6 +21,7 @@ struct IP unsigned long pktsdown; struct Keyword *keyword; int v6; + int mask; list(IP); }; @@ -55,5 +56,5 @@ struct Keyword list(Keyword); }; -void TheIP(char *ipaddr); +void TheIP(char *ipaddr, int is_network); /* function implemented in parsehosts.c */ diff --git a/networks.c b/networks.c new file mode 100644 index 0000000..2c7df01 --- /dev/null +++ b/networks.c @@ -0,0 +1,107 @@ +/* Modified by: xChaos, 20131028 */ + +#include "cll1-0.6.2.h" +#include "ipstruct.h" + +#define STRLEN 512 + +extern struct IP *ips, *networks; + +struct IP* find_network_for_ip(char *ipaddr_orig) +{ + struct IP *network; + char *netaddr, *lastnum, *ipaddr; + int ipnum, netnum; + + duplicate(ipaddr_orig, ipaddr); + lastnum = strrchr(ipaddr, '.'); + if(lastnum) + { + ipnum = atoi(lastnum + 1); + *lastnum = 0; + } + + for_each(network, networks) + { + duplicate(network->addr, netaddr); + lastnum = strrchr(netaddr, '.'); + if(lastnum) + { + netnum = atoi(lastnum + 1); + *lastnum = 0; +// printf("%s/%d + %d\n",network->addr,network->mask,(1<<(32-network->mask))); + if( eq(netaddr, ipaddr) + and netnum + (1<<(32-network->mask)) > ipnum + and netnum <= ipnum) + { + return network; + } + } + } + return NULL; +} + +void analyse_topology(char *traceroute) +{ + char *buf, *netaddr, *ptr, *lastnum, *str; + int col, gateway, netnum, tracert; + struct IP *network=NULL, *ip; + + for_each(ip, networks) + { + printf("%s/%d %s min=%d max=%d sum=%d\n",ip->addr, ip->mask, ip->name, ip->min, ip->max, ip->desired); + } + + /*-----------------------------------------------------------------*/ + puts("Analysing network topology ..."); + /*-----------------------------------------------------------------*/ + for_each(ip, networks) + { + printf("%s/%d %s\n",ip->addr, ip->mask, ip->name); + duplicate(ip->addr, buf); + lastnum = strrchr(buf, '.'); + if(lastnum) + { + gateway = atoi(lastnum + 1) + 1; /* this is just common rule... */ + *lastnum = 0; + string(str,STRLEN); + sprintf(str, traceroute, buf, gateway); + shell(str); + input(str,STRLEN) + { + if( not strstr(str, "traceroute") + and not strstr(str, "* * *")) + { + printf("%s",str); + duplicate(str, buf); + valid_columns(ptr, buf, ' ', col) + if(*ptr=='*') + { + col--; + } + else if(col==2) + { + printf("via [%s]\n", ptr); + network = find_network_for_ip(ptr); + if(network) + { + network->min += ip->min; + network->desired += ip->max; + if(ip->max > network->max) + { + network->max = ip->max; + } + } + } + } + } + } + } + sort(network, networks, desc_order_by, min); + sort(network, networks, desc_order_by, max); + for_each(ip, networks) + { + printf("%s/%d %s min=%d max=%d sum=%d\n",ip->addr, ip->mask, ip->name, ip->min, ip->max, ip->desired); + } + exit(-1); +} diff --git a/parsehosts.c b/parsehosts.c index 1e8dbe6..04fce9f 100644 --- a/parsehosts.c +++ b/parsehosts.c @@ -1,4 +1,4 @@ -/* Modified by: xChaos, 20121007 */ +/* Modified by: xChaos, 20131028 */ #include "cll1-0.6.2.h" #include "ipstruct.h" @@ -7,7 +7,7 @@ #define FIRSTIPCLASS 2048 /* globals declared in prometheus.c */ -extern struct IP *ips, *ip, *sharedip; +extern struct IP *ips, *ip, *sharedip, *networks; extern struct Group *groups, *group; extern struct Keyword *keyword, *defaultkeyword, *keywords; extern int class_count; @@ -17,8 +17,11 @@ extern int free_min; extern const int highest_priority; extern char *ip6prefix; +struct IP* find_network_for_ip(char *ipaddr_orig); +/* implemented in networks.c */ + /* This must be object oriented! This looks almost like constructor ;-) */ -void TheIP(char *ipaddr) +void TheIP(char *ipaddr, int is_network) { create(ip,IP); ip->name = ""; @@ -40,14 +43,22 @@ void TheIP(char *ipaddr) ip->pktsdown = 0; ip->keyword = keywords; ip->v6 = (strchr(ip->addr,':')!=NULL); - push(ip,ips); + ip->mask = ((ip->v6)?64:32); + if(is_network) + { + push(ip, networks); + } + else + { + push(ip, ips); + } ip_count++; } struct IP *lastIP6; /* == This function strips extra characters after IPv4 address and stores it = */ -parse_ip(char *str) +void parse_and_append_ip(char *str, struct IP *listhead) { char *ptr, *ipaddr, *ip6range = NULL, *ipname = NULL, *lmsid = NULL; @@ -104,7 +115,7 @@ parse_ip(char *str) if_exists(ip, ips, eq(ip->addr,ip6range)); else { - TheIP(ip6range); + TheIP(ip6range, FALSE); } ip->name = ip6range; ip->keyword = defaultkeyword; /* settings for default keyword */ @@ -119,10 +130,10 @@ parse_ip(char *str) lastIP6 = NULL; } - if_exists(ip, ips, eq(ip->addr,ipaddr)); + if_exists(ip, listhead, eq(ip->addr,ipaddr)); else { - TheIP(ipaddr); + TheIP(ipaddr, (listhead==networks)); } ip->name = ipname; if(lmsid) @@ -138,6 +149,7 @@ void parse_hosts(char *hosts) int groupidx = FIRSTGROUPID; char *str, *ptr; char *substring; + struct IP *network; parse(hosts) { @@ -154,7 +166,7 @@ void parse_hosts(char *hosts) if(substring) { substring += 8; /* "sharing-" */ - parse_ip(str); + parse_and_append_ip(str, ips); ip->sharing = substring; ip->keyword = defaultkeyword; /* settings for default keyword */ if(lastIP6) @@ -170,75 +182,116 @@ void parse_hosts(char *hosts) } else { - /*Do we have to create new QoS class for this IP ? */ - - if_exists(keyword,keywords,(substring=strstr(str,keyword->key))) + substring = strstr(str, "#255."); + if(substring and not strstr(str, "#255.255.255.255")) /* do not ping /32 ranges */ { - parse_ip(str); - if(lastIP6) - { - lastIP6->sharing = ip->name; - lastIP6 = NULL; - } - ip->keyword = keyword; - keyword->ip_count++; - ip->prio = keyword->default_prio; - substring += strlen(keyword->key)+1; - ptr = substring; - while(*ptr and *ptr != '-') - { - ptr++; - } - if(*ptr == '-') + /* netmask detected - save network*/ + unsigned bit; + unsigned num, mask = 8; + substring += 5; + while(substring && *substring) { - *ptr=0; - ip->max = ip->desired = atoi(ptr+1); - } - ip->min = atoi(substring); - if(ip->min <= 0) - { - printf(" %s: Illegal value of minimum bandwidth 0 kbps, using %d kb/s\n", - str, free_min); - ip->min = free_min; - } - if(ip->max <= ip->min) - { - ip->fixedprio = TRUE; - ip->max = ip->min + ip->keyword->reserve_min; - } - else - { - ip->max -= ip->keyword->reserve_max; - if(ip->maxmin) + ptr = substring; + substring = strchr(substring, '.'); + if(substring) + { + *substring = 0; + substring += 1; + } + num = atoi(ptr); + for(bit = 1; bit <=128 ; bit<<=1) { - ip->max=ip->min; + if(bit & num) + { + mask++; + } } - } - ip->mark = FIRSTIPCLASS+1+class_count++; - - if_exists(group,groups,(group->min == ip->min)) - { - group->count++; - group->desired += ip->min; - ip->group = group->id; - } - else + } + parse_and_append_ip(str, networks); + ip->mask = mask; + } + else + { + /*Do we have to create new QoS class for this IP ? */ + if_exists(keyword,keywords,(substring=strstr(str,keyword->key))) { - create(group,Group); - group->min = ip->min; - group->id = groupidx++; - ip->group = group->id; - - if(group->min < 8) group->min = 8; - /* Warning - this is maybe because of primitive tc namespace, can be fixed */ - /* it is because class IDs are derived from min. bandwidth. - xCh */ - //if(group->min>MAX_GUARANTED_KBPS) group->min=MAX_GUARANTED_KBPS; - - group->count = 1; - group->desired = ip->min; - insert(group, groups, desc_order_by,min); - } - }//endif keyword- + parse_and_append_ip(str, ips); + if(lastIP6) + { + lastIP6->sharing = ip->name; + lastIP6 = NULL; + } + ip->keyword = keyword; + keyword->ip_count++; + ip->prio = keyword->default_prio; + substring += strlen(keyword->key)+1; + ptr = substring; + while(*ptr and *ptr != '-') + { + ptr++; + } + if(*ptr == '-') + { + *ptr=0; + ip->max = ip->desired = atoi(ptr+1); + } + ip->min = atoi(substring); + if(ip->min <= 0) + { + printf(" %s: Illegal value of minimum bandwidth 0 kbps, using %d kb/s\n", + str, free_min); + ip->min = free_min; + } + if(ip->max <= ip->min) + { + ip->fixedprio = TRUE; + ip->max = ip->min + ip->keyword->reserve_min; + } + else + { + ip->max -= ip->keyword->reserve_max; + if(ip->maxmin) + { + ip->max=ip->min; + } + } + ip->mark = FIRSTIPCLASS+1+class_count++; + + network = find_network_for_ip(ip->addr); + if(network) + { + network->min += ip->min; + network->desired += ip->max; + if(ip->max > network->max) + { + network->max = ip->max; + } + } + + if_exists(group,groups,(group->min == ip->min)) + { + group->count++; + group->desired += ip->min; + ip->group = group->id; + } + else + { + create(group,Group); + group->min = ip->min; + group->id = groupidx++; + ip->group = group->id; + + if(group->min < 8) group->min = 8; + /* Warning - this is maybe because of primitive tc namespace, can be fixed */ + /* it is because class IDs are derived from min. bandwidth. - xCh */ + //if(group->min>MAX_GUARANTED_KBPS) group->min=MAX_GUARANTED_KBPS; + + group->count = 1; + group->desired = ip->min; + insert(group, groups, desc_order_by,min); + } + }//endif keyword- + }//endif netmask }//endif sharing- } fail diff --git a/parseiptables.c b/parseiptables.c index 1f22d13..946707d 100644 --- a/parseiptables.c +++ b/parseiptables.c @@ -41,7 +41,7 @@ void get_traffic_statistics(const char *whichiptables, int ipv6) unsigned long pkts = 0; char *ipaddr = NULL,*ptr; - valid_columns(ptr, line->str, ' ', col) + valid_columns(ptr, line->str, ' ', col) if(valid) switch(col) { case 1: if(eq(ptr,"Chain")) @@ -150,7 +150,7 @@ void get_traffic_statistics(const char *whichiptables, int ipv6) if_exists(ip, ips, eqi(ip->addr,ipaddr)); else { - TheIP(ipaddr); + TheIP(ipaddr, FALSE); if(eq(ip->addr,"0.0.0.0/0")) { ip->name = "(unregistered)"; diff --git a/prometheus.c b/prometheus.c index b7b3a04..045c182 100644 --- a/prometheus.c +++ b/prometheus.c @@ -132,7 +132,7 @@ const int idxtable_treshold2 = 12; /* this is no longer configurable */ const int idxtable_bitmask1 = 3; /* this is no longer configurable */ const int idxtable_bitmask2 = 3; /* this is no longer configurable */ -struct IP *ips = NULL, *ip, *sharedip; +struct IP *ips = NULL, *networks = NULL, *ip, *sharedip; struct Group *groups = NULL, *group; struct Keyword *keyword, *defaultkeyword=NULL, *keywords=NULL; @@ -154,6 +154,10 @@ void write_json_traffic(char *json); void write_htmlandlogs(char *html, char *d, int total, int just_preview); /* implemented in htmlandlogs.c */ +void analyse_topology(char *traceroute); +/* implemented in networks.c */ + + const char *tr_odd_even(void) { row_odd_even = 1 - row_odd_even; @@ -337,10 +341,10 @@ void get_config(char *config_filename) /* leaf discipline for keywords */ for_each(keyword,keywords) { - if(!strcmpi(keyword->leaf_discipline, "")) - { - keyword->leaf_discipline = qos_leaf; - } + if(!strcmpi(keyword->leaf_discipline, "")) + { + keyword->leaf_discipline = qos_leaf; + } } if(strcmpi(cnf, "mark")) @@ -468,6 +472,7 @@ program char *substring; int parent = 1; + int just_networks = FALSE; int just_flush = FALSE; /* deactivates all previous actions */ int nodelay = FALSE; int just_preview = FALSE; /* preview - generate just stats */ @@ -502,6 +507,7 @@ Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version); argument("-s") { run=TRUE; just_preview=TRUE; start_shaping=TRUE; } argument("-r") { run=TRUE; } argument("-n") { run=TRUE; nodelay=TRUE; } + argument("-a") { run=TRUE; just_networks=TRUE; } argument("-l") { just_logs=TRUE; } argument("-m") { just_logs=TRUE; } argument("-y") { just_logs=TRUE; } @@ -536,7 +542,7 @@ Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version); if(althosts) { - hosts=althosts; + hosts = althosts; } if(just_flush<9) @@ -555,21 +561,26 @@ Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version); } /*-----------------------------------------------------------------*/ - printf("Parsing class defintion file %s ...\n", hosts); + /* cll1.h - let's allocate brand new character buffer... */ /*-----------------------------------------------------------------*/ - parse_hosts(hosts); + string(str,STRLEN); /*-----------------------------------------------------------------*/ - /* cll1.h - let's allocate brand new character buffer... */ + printf("Parsing class defintion file %s ...\n", hosts); /*-----------------------------------------------------------------*/ - string(str,STRLEN); + parse_hosts(hosts); + if(just_networks) + { + analyse_topology("/usr/sbin/traceroute -n -m 10 -w 2 %s.%d"); + exit(-1); + } /*-----------------------------------------------------------------*/ puts("Resolving shared connections ..."); /*-----------------------------------------------------------------*/ - for_each(ip,ips) if(ip->sharing) + for_each(ip, ips) if(ip->sharing) { - for_each(sharedip,ips) if(eq(sharedip->name, ip->sharing)) + for_each(sharedip, ips) if(eq(sharedip->name, ip->sharing)) { sharedip->traffic += ip->traffic; ip->traffic = 0; -- 2.30.2