| /**************************************************************************** |
| * Module for ucd-snmpd reading IP Firewall accounting rules. * |
| * It reads "/proc/net/ip_acct". If the file has a wrong format it silently * |
| * returns erroneous data but doesn't do anything harmfull. Based (on the * |
| * output of) mib2c, wombat.c, proc.c and the Linux kernel. * |
| * Author: Cristian.Estan@net.utcluj.ro * |
| ***************************************************************************/ |
| |
| #include <net-snmp/net-snmp-config.h> |
| |
| #if TIME_WITH_SYS_TIME |
| # include <sys/time.h> |
| # include <time.h> |
| #else |
| # if HAVE_SYS_TIME_H |
| # include <sys/time.h> |
| # else |
| # include <time.h> |
| # endif |
| #endif |
| |
| #include <net-snmp/net-snmp-includes.h> |
| #include <net-snmp/agent/net-snmp-agent-includes.h> |
| |
| #include "util_funcs/header_simple_table.h" |
| #include "ipfwacc.h" |
| |
| /* |
| * According to the 2.0.33 Linux kernel, assuming we use ipv4 any line from |
| * * "/proc/net/ip_acct should fit into |
| * * 8+1+8+2+8+1+8+1+16+1+8+1+4+1+2+1+2+1+20+20+10*(1+5)+2+2+2+2=182 |
| * * characters+ newline. |
| */ |
| #define IPFWRULELEN 200 |
| |
| #define IP_FW_F_ALL 0x0000 /* This is a universal packet firewall */ |
| #define IP_FW_F_TCP 0x0001 /* This is a TCP packet firewall */ |
| #define IP_FW_F_UDP 0x0002 /* This is a UDP packet firewall */ |
| #define IP_FW_F_ICMP 0x0003 /* This is a ICMP packet firewall */ |
| #define IP_FW_F_KIND 0x0003 /* Mask to isolate firewall kind */ |
| #define IP_FW_F_SRNG 0x0008 /* The first two src ports are a min * |
| * and max range (stored in host byte * |
| * order). */ |
| #define IP_FW_F_DRNG 0x0010 /* The first two dst ports are a min * |
| * and max range (stored in host byte * |
| * order). * |
| * (ports[0] <= port <= ports[1]) */ |
| #define IP_FW_F_BIDIR 0x0040 /* For bidirectional firewalls */ |
| #define IP_FW_F_ACCTIN 0x1000 /* Account incoming packets only. */ |
| #define IP_FW_F_ACCTOUT 0x2000 /* Account outgoing packets only. */ |
| |
| static unsigned char rule[IPFWRULELEN]; /*Buffer for reading a line from |
| * /proc/net/ip_acct. Care has been taken |
| * not to read beyond the end of this |
| * buffer, even if rules are in an |
| * unexpected format |
| */ |
| |
| /* |
| * This function reads the rule with the given number into the buffer. It |
| * * returns the number of rule read or 0 if the number is invalid or other |
| * * problems occur. If the argument is 0 it returns the number of accounting |
| * * rules. No caching of rules is done. |
| */ |
| |
| static int |
| readrule(unsigned int number) |
| { |
| int i; |
| FILE *f = fopen("/proc/net/ip_acct", "rt"); |
| |
| if (!f) |
| return 0; |
| /* |
| * get rid of "IP accounting rules" line |
| */ |
| if (!fgets((char *) rule, sizeof(rule), f)) { |
| fclose(f); |
| return 0; |
| } |
| for (i = 1; i != number; i++) |
| if (!fgets((char *) rule, sizeof(rule), f)) { |
| fclose(f); |
| return (number ? 0 : (i - 1)); |
| } |
| if (!fgets((char *) rule, sizeof(rule), f)) { |
| fclose(f); |
| return 0; |
| } |
| fclose(f); |
| return i; |
| } |
| |
| static unsigned long ret_val; /* Used by var_ipfwacc to return ulongs */ |
| |
| /* |
| * This function converts the hexadecimal representation of an IP address from |
| * * the rule buffer to an unsigned long. The result is stored in the ret_val |
| * * variable. The parameter indicates the position where the address starts. It |
| * * only works with uppercase letters and assumes input is correct. Had to use |
| * * this because stol returns a signed long. |
| */ |
| |
| static inline void |
| atoip(int pos) |
| { |
| int i; |
| |
| ret_val = 0; |
| for (i = 0; i < 32; i += 8) { |
| unsigned long value = (((rule[pos]) >= '0' && rule[pos] <= '9') ? |
| rule[pos] - '0' : rule[pos] - 'A' + 10); |
| pos++; |
| value = (value << 4) + (((rule[pos]) >= '0' && rule[pos] <= '9') ? |
| rule[pos] - '0' : rule[pos] - 'A' + 10); |
| pos++; |
| ret_val |= (value << i); |
| } |
| } |
| |
| /* |
| * This function parses the flags field from the line in the buffer |
| */ |
| |
| static unsigned long int |
| getflags(void) |
| { |
| unsigned long int flags; |
| int i = 37; /* position in the rule */ |
| |
| /* |
| * skipping via name |
| */ |
| while (rule[i] != ' ' && i < IPFWRULELEN - 12) |
| i++; |
| /* |
| * skipping via address |
| */ |
| i += 10; |
| for (flags = 0; rule[i] != ' ' && i < IPFWRULELEN - 1; i++) { |
| int value = (((rule[i]) >= '0' && rule[i] <= '9') ? |
| rule[i] - '0' : rule[i] - 'A' + 10); |
| flags = (flags << 4) + value; |
| } |
| return flags; |
| } |
| |
| /* |
| * This function reads into ret_val a field from the rule buffer. The field |
| * * is a base 10 long integer and the parameter skip tells us how many fields |
| * * to skip after the "via addrress" field (including the flag field) |
| */ |
| |
| static void |
| getnumeric(int skip) |
| { |
| int i = 37; /* position in the rule */ |
| |
| /* |
| * skipping via name |
| */ |
| while (rule[i] != ' ' && i < IPFWRULELEN - 12) |
| i++; |
| /* |
| * skipping via address |
| */ |
| i += 10; |
| while (skip > 0) { |
| skip--; |
| /* |
| * skipping field, than subsequent spaces |
| */ |
| while (rule[i] != ' ' && i < IPFWRULELEN - 2) |
| i++; |
| while (rule[i] == ' ' && i < IPFWRULELEN - 1) |
| i++; |
| } |
| for (ret_val = 0; rule[i] != ' ' && i < IPFWRULELEN - 1; i++) |
| ret_val = ret_val * 10 + rule[i] - '0'; |
| } |
| |
| /* |
| * this variable defines function callbacks and type return information |
| * for the ipfwaccounting mib |
| */ |
| |
| struct variable2 ipfwacc_variables[] = { |
| {IPFWACCINDEX, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, |
| var_ipfwacc, 1, {IPFWACCINDEX}}, |
| {IPFWACCSRCADDR, ASN_IPADDRESS, NETSNMP_OLDAPI_RONLY, |
| var_ipfwacc, 1, {IPFWACCSRCADDR}}, |
| {IPFWACCSRCNM, ASN_IPADDRESS, NETSNMP_OLDAPI_RONLY, |
| var_ipfwacc, 1, {IPFWACCSRCNM}}, |
| {IPFWACCDSTADDR, ASN_IPADDRESS, NETSNMP_OLDAPI_RONLY, |
| var_ipfwacc, 1, {IPFWACCDSTADDR}}, |
| {IPFWACCDSTNM, ASN_IPADDRESS, NETSNMP_OLDAPI_RONLY, |
| var_ipfwacc, 1, {IPFWACCDSTNM}}, |
| {IPFWACCVIANAME, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY, |
| var_ipfwacc, 1, {IPFWACCVIANAME}}, |
| {IPFWACCVIAADDR, ASN_IPADDRESS, NETSNMP_OLDAPI_RONLY, |
| var_ipfwacc, 1, {IPFWACCVIAADDR}}, |
| {IPFWACCPROTO, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, |
| var_ipfwacc, 1, {IPFWACCPROTO}}, |
| {IPFWACCBIDIR, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, |
| var_ipfwacc, 1, {IPFWACCBIDIR}}, |
| {IPFWACCDIR, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, |
| var_ipfwacc, 1, {IPFWACCDIR}}, |
| {IPFWACCBYTES, ASN_COUNTER, NETSNMP_OLDAPI_RONLY, |
| var_ipfwacc, 1, {IPFWACCBYTES}}, |
| {IPFWACCPACKETS, ASN_COUNTER, NETSNMP_OLDAPI_RONLY, |
| var_ipfwacc, 1, {IPFWACCPACKETS}}, |
| {IPFWACCNSRCPRTS, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, |
| var_ipfwacc, 1, {IPFWACCNSRCPRTS}}, |
| {IPFWACCNDSTPRTS, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, |
| var_ipfwacc, 1, {IPFWACCNDSTPRTS}}, |
| {IPFWACCSRCISRNG, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, |
| var_ipfwacc, 1, {IPFWACCSRCISRNG}}, |
| {IPFWACCDSTISRNG, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, |
| var_ipfwacc, 1, {IPFWACCDSTISRNG}}, |
| {IPFWACCPORT1, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, |
| var_ipfwacc, 1, {IPFWACCPORT1}}, |
| {IPFWACCPORT2, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, |
| var_ipfwacc, 1, {IPFWACCPORT2}}, |
| {IPFWACCPORT3, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, |
| var_ipfwacc, 1, {IPFWACCPORT3}}, |
| {IPFWACCPORT4, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, |
| var_ipfwacc, 1, {IPFWACCPORT4}}, |
| {IPFWACCPORT5, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, |
| var_ipfwacc, 1, {IPFWACCPORT5}}, |
| {IPFWACCPORT6, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, |
| var_ipfwacc, 1, {IPFWACCPORT6}}, |
| {IPFWACCPORT7, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, |
| var_ipfwacc, 1, {IPFWACCPORT7}}, |
| {IPFWACCPORT8, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, |
| var_ipfwacc, 1, {IPFWACCPORT8}}, |
| {IPFWACCPORT9, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, |
| var_ipfwacc, 1, {IPFWACCPORT9}}, |
| {IPFWACCPORT10, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, |
| var_ipfwacc, 1, {IPFWACCPORT10}} |
| }; |
| |
| oid ipfwacc_variables_oid[] = |
| { 1, 3, 6, 1, 4, 1, 2021, 13, 1, 1, 1 }; |
| |
| void |
| init_ipfwacc(void) |
| { |
| REGISTER_MIB("misc/ipfwacc", ipfwacc_variables, variable2, |
| ipfwacc_variables_oid); |
| } |
| |
| |
| u_char * |
| var_ipfwacc(struct variable *vp, |
| oid * name, |
| size_t * length, |
| int exact, size_t * var_len, WriteMethod ** write_method) |
| { |
| *write_method = 0; /* assume it isnt writable for the time being */ |
| *var_len = sizeof(ret_val); /* assume an integer and change later if not */ |
| |
| if (header_simple_table |
| (vp, name, length, exact, var_len, write_method, readrule(0))) |
| return (NULL); |
| |
| if (readrule(name[*length - 1])) { |
| /* |
| * this is where we do the value assignments for the mib results. |
| */ |
| switch (vp->magic) { |
| case IPFWACCINDEX: |
| ret_val = name[*length - 1]; |
| return ((u_char *) (&ret_val)); |
| case IPFWACCSRCADDR: |
| atoip(0); |
| return ((u_char *) (&ret_val)); |
| case IPFWACCSRCNM: |
| atoip(9); |
| return ((u_char *) (&ret_val)); |
| case IPFWACCDSTADDR: |
| atoip(19); |
| return ((u_char *) (&ret_val)); |
| case IPFWACCDSTNM: |
| atoip(28); |
| return ((u_char *) (&ret_val)); |
| case IPFWACCVIANAME: |
| { |
| int i = 37; /* position in the rule */ |
| while (rule[i] != ' ' && i < IPFWRULELEN - 1) |
| i++; |
| rule[i] = 0; |
| return (rule + 37); |
| } |
| case IPFWACCVIAADDR: |
| { |
| int i = 37; /* position in the rule */ |
| while (rule[i] != ' ' && i < IPFWRULELEN - 9) |
| i++; |
| atoip(i + 1); |
| return ((u_char *) (&ret_val)); |
| } |
| case IPFWACCPROTO: |
| switch (getflags() & IP_FW_F_KIND) { |
| case IP_FW_F_ALL: |
| ret_val = 2; |
| return ((u_char *) (&ret_val)); |
| case IP_FW_F_TCP: |
| ret_val = 3; |
| return ((u_char *) (&ret_val)); |
| case IP_FW_F_UDP: |
| ret_val = 4; |
| return ((u_char *) (&ret_val)); |
| case IP_FW_F_ICMP: |
| ret_val = 5; |
| return ((u_char *) (&ret_val)); |
| default: |
| ret_val = 1; |
| return ((u_char *) (&ret_val)); |
| } |
| case IPFWACCBIDIR: |
| ret_val = ((getflags() & IP_FW_F_BIDIR) ? 2 : 1); |
| return ((u_char *) (&ret_val)); |
| case IPFWACCDIR: |
| ret_val = (getflags() & (IP_FW_F_ACCTIN | IP_FW_F_ACCTOUT)); |
| if (ret_val == IP_FW_F_ACCTIN) |
| ret_val = 2; |
| else if (ret_val == IP_FW_F_ACCTOUT) |
| ret_val = 3; |
| else |
| ret_val = 1; |
| return ((u_char *) (&ret_val)); |
| case IPFWACCBYTES: |
| getnumeric(4); |
| return ((u_char *) (&ret_val)); |
| case IPFWACCPACKETS: |
| getnumeric(3); |
| return ((u_char *) (&ret_val)); |
| case IPFWACCNSRCPRTS: |
| getnumeric(1); |
| return ((u_char *) (&ret_val)); |
| case IPFWACCNDSTPRTS: |
| getnumeric(2); |
| return ((u_char *) (&ret_val)); |
| case IPFWACCSRCISRNG: |
| ret_val = ((getflags() & IP_FW_F_SRNG) ? 1 : 2); |
| return ((u_char *) (&ret_val)); |
| case IPFWACCDSTISRNG: |
| ret_val = ((getflags() & IP_FW_F_DRNG) ? 1 : 2); |
| return ((u_char *) (&ret_val)); |
| case IPFWACCPORT1: |
| case IPFWACCPORT2: |
| case IPFWACCPORT3: |
| case IPFWACCPORT4: |
| case IPFWACCPORT5: |
| case IPFWACCPORT6: |
| case IPFWACCPORT7: |
| case IPFWACCPORT8: |
| case IPFWACCPORT9: |
| case IPFWACCPORT10: |
| getnumeric(5 + (vp->magic) - IPFWACCPORT1); |
| return ((u_char *) (&ret_val)); |
| } |
| } |
| return NULL; |
| } |