added files
[bcm963xx.git] / userapps / opensource / net-snmp / agent / mibgroup / misc / ipfwacc.c
1 /****************************************************************************
2  * Module for ucd-snmpd reading IP Firewall accounting rules.               *
3  * It reads "/proc/net/ip_acct". If the file has a wrong format it silently *
4  * returns erroneous data but doesn't do anything harmfull. Based (on the   *
5  * output of) mib2c, wombat.c, proc.c and the Linux kernel.                 *
6  * Author: Cristian.Estan@net.utcluj.ro                                     *
7  ***************************************************************************/
8
9 #include <net-snmp/net-snmp-config.h>
10
11 #if TIME_WITH_SYS_TIME
12 # include <sys/time.h>
13 # include <time.h>
14 #else
15 # if HAVE_SYS_TIME_H
16 #  include <sys/time.h>
17 # else
18 #  include <time.h>
19 # endif
20 #endif
21
22 #include <net-snmp/net-snmp-includes.h>
23 #include <net-snmp/agent/net-snmp-agent-includes.h>
24
25 #include "util_funcs.h"
26 #include "ipfwacc.h"
27
28 /*
29  * According to the 2.0.33 Linux kernel, assuming we use ipv4 any line from
30  * * "/proc/net/ip_acct should fit into
31  * * 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
32  * * characters+ newline.
33  */
34 #define IPFWRULELEN 200
35
36 #define IP_FW_F_ALL     0x0000  /* This is a universal packet firewall */
37 #define IP_FW_F_TCP     0x0001  /* This is a TCP packet firewall      */
38 #define IP_FW_F_UDP     0x0002  /* This is a UDP packet firewall      */
39 #define IP_FW_F_ICMP    0x0003  /* This is a ICMP packet firewall     */
40 #define IP_FW_F_KIND    0x0003  /* Mask to isolate firewall kind      */
41 #define IP_FW_F_SRNG    0x0008  /* The first two src ports are a min  *
42                                  * and max range (stored in host byte *
43                                  * order).                            */
44 #define IP_FW_F_DRNG    0x0010  /* The first two dst ports are a min  *
45                                  * and max range (stored in host byte *
46                                  * order).                            *
47                                  * (ports[0] <= port <= ports[1])     */
48 #define IP_FW_F_BIDIR   0x0040  /* For bidirectional firewalls        */
49 #define IP_FW_F_ACCTIN  0x1000  /* Account incoming packets only.     */
50 #define IP_FW_F_ACCTOUT 0x2000  /* Account outgoing packets only.     */
51
52 static unsigned char rule[IPFWRULELEN]; /*Buffer for reading a line from
53                                          * /proc/net/ip_acct. Care has been taken
54                                          * not to read beyond the end of this 
55                                          * buffer, even if rules are in an 
56                                          * unexpected format
57                                          */
58
59 /*
60  * This function reads the rule with the given number into the buffer. It
61  * * returns the number of rule read or 0 if the number is invalid or other
62  * * problems occur. If the argument is 0 it returns the number of accounting
63  * * rules. No caching of rules is done.
64  */
65
66 static int
67 readrule(unsigned int number)
68 {
69     int             i;
70     FILE           *f = fopen("/proc/net/ip_acct", "rt");
71
72     if (!f)
73         return 0;
74     /*
75      * get rid of "IP accounting rules" line
76      */
77     if (!fgets(rule, sizeof(rule), f)) {
78         fclose(f);
79         return 0;
80     }
81     for (i = 1; i != number; i++)
82         if (!fgets(rule, sizeof(rule), f)) {
83             fclose(f);
84             return (number ? 0 : (i - 1));
85         }
86     if (!fgets(rule, sizeof(rule), f)) {
87         fclose(f);
88         return 0;
89     }
90     fclose(f);
91     return i;
92 }
93
94 static unsigned long ret_val;   /* Used by var_ipfwacc to return ulongs */
95
96 /*
97  * This function converts the hexadecimal representation of an IP address from
98  * * the rule buffer to an unsigned long. The result is stored in the ret_val
99  * * variable. The parameter indicates the position where the address starts. It
100  * * only works with uppercase letters and assumes input is correct. Had to use
101  * * this because stol returns a signed long. 
102  */
103
104 static inline void
105 atoip(int pos)
106 {
107     int             i;
108
109     ret_val = 0;
110     for (i = 0; i < 32; i += 8) {
111         unsigned long   value = (((rule[pos]) >= '0' && rule[pos] <= '9') ?
112                                  rule[pos] - '0' : rule[pos] - 'A' + 10);
113         pos++;
114         value = (value << 4) + (((rule[pos]) >= '0' && rule[pos] <= '9') ?
115                                 rule[pos] - '0' : rule[pos] - 'A' + 10);
116         pos++;
117         ret_val |= (value << i);
118     }
119 }
120
121 /*
122  * This function parses the flags field from the line in the buffer 
123  */
124
125 static unsigned long int
126 getflags(void)
127 {
128     unsigned long int flags;
129     int             i = 37;     /* position in the rule */
130
131     /*
132      * skipping via name 
133      */
134     while (rule[i] != ' ' && i < IPFWRULELEN - 12)
135         i++;
136     /*
137      * skipping via address 
138      */
139     i += 10;
140     for (flags = 0; rule[i] != ' ' && i < IPFWRULELEN - 1; i++) {
141         int             value = (((rule[i]) >= '0' && rule[i] <= '9') ?
142                                  rule[i] - '0' : rule[i] - 'A' + 10);
143         flags = (flags << 4) + value;
144     }
145     return flags;
146 }
147
148 /*
149  * This function reads into ret_val a field from the rule buffer. The field
150  * * is a base 10 long integer and the parameter skip tells us how many fields
151  * * to skip after the "via addrress" field (including the flag field)
152  */
153
154 static void
155 getnumeric(int skip)
156 {
157     int             i = 37;     /* position in the rule */
158
159     /*
160      * skipping via name 
161      */
162     while (rule[i] != ' ' && i < IPFWRULELEN - 12)
163         i++;
164     /*
165      * skipping via address 
166      */
167     i += 10;
168     while (skip > 0) {
169         skip--;
170         /*
171          * skipping field, than subsequent spaces 
172          */
173         while (rule[i] != ' ' && i < IPFWRULELEN - 2)
174             i++;
175         while (rule[i] == ' ' && i < IPFWRULELEN - 1)
176             i++;
177     }
178     for (ret_val = 0; rule[i] != ' ' && i < IPFWRULELEN - 1; i++)
179         ret_val = ret_val * 10 + rule[i] - '0';
180 }
181
182 /*
183  * this variable defines function callbacks and type return information 
184  * for the ipfwaccounting mib 
185  */
186
187 struct variable2 ipfwacc_variables[] = {
188     {IPFWACCINDEX, ASN_INTEGER, RONLY, var_ipfwacc, 1, {IPFWACCINDEX}},
189     {IPFWACCSRCADDR, ASN_IPADDRESS, RONLY, var_ipfwacc, 1,
190      {IPFWACCSRCADDR}},
191     {IPFWACCSRCNM, ASN_IPADDRESS, RONLY, var_ipfwacc, 1, {IPFWACCSRCNM}},
192     {IPFWACCDSTADDR, ASN_IPADDRESS, RONLY, var_ipfwacc, 1,
193      {IPFWACCDSTADDR}},
194     {IPFWACCDSTNM, ASN_IPADDRESS, RONLY, var_ipfwacc, 1, {IPFWACCDSTNM}},
195     {IPFWACCVIANAME, ASN_OCTET_STR, RONLY, var_ipfwacc, 1,
196      {IPFWACCVIANAME}},
197     {IPFWACCVIAADDR, ASN_IPADDRESS, RONLY, var_ipfwacc, 1,
198      {IPFWACCVIAADDR}},
199     {IPFWACCPROTO, ASN_INTEGER, RONLY, var_ipfwacc, 1, {IPFWACCPROTO}},
200     {IPFWACCBIDIR, ASN_INTEGER, RONLY, var_ipfwacc, 1, {IPFWACCBIDIR}},
201     {IPFWACCDIR, ASN_INTEGER, RONLY, var_ipfwacc, 1, {IPFWACCDIR}},
202     {IPFWACCBYTES, ASN_COUNTER, RONLY, var_ipfwacc, 1, {IPFWACCBYTES}},
203     {IPFWACCPACKETS, ASN_COUNTER, RONLY, var_ipfwacc, 1, {IPFWACCPACKETS}},
204     {IPFWACCNSRCPRTS, ASN_INTEGER, RONLY, var_ipfwacc, 1,
205      {IPFWACCNSRCPRTS}},
206     {IPFWACCNDSTPRTS, ASN_INTEGER, RONLY, var_ipfwacc, 1,
207      {IPFWACCNDSTPRTS}},
208     {IPFWACCSRCISRNG, ASN_INTEGER, RONLY, var_ipfwacc, 1,
209      {IPFWACCSRCISRNG}},
210     {IPFWACCDSTISRNG, ASN_INTEGER, RONLY, var_ipfwacc, 1,
211      {IPFWACCDSTISRNG}},
212     {IPFWACCPORT1, ASN_INTEGER, RONLY, var_ipfwacc, 1, {IPFWACCPORT1}},
213     {IPFWACCPORT2, ASN_INTEGER, RONLY, var_ipfwacc, 1, {IPFWACCPORT2}},
214     {IPFWACCPORT3, ASN_INTEGER, RONLY, var_ipfwacc, 1, {IPFWACCPORT3}},
215     {IPFWACCPORT4, ASN_INTEGER, RONLY, var_ipfwacc, 1, {IPFWACCPORT4}},
216     {IPFWACCPORT5, ASN_INTEGER, RONLY, var_ipfwacc, 1, {IPFWACCPORT5}},
217     {IPFWACCPORT6, ASN_INTEGER, RONLY, var_ipfwacc, 1, {IPFWACCPORT6}},
218     {IPFWACCPORT7, ASN_INTEGER, RONLY, var_ipfwacc, 1, {IPFWACCPORT7}},
219     {IPFWACCPORT8, ASN_INTEGER, RONLY, var_ipfwacc, 1, {IPFWACCPORT8}},
220     {IPFWACCPORT9, ASN_INTEGER, RONLY, var_ipfwacc, 1, {IPFWACCPORT9}},
221     {IPFWACCPORT10, ASN_INTEGER, RONLY, var_ipfwacc, 1, {IPFWACCPORT10}}
222 };
223
224 oid             ipfwacc_variables_oid[] =
225     { 1, 3, 6, 1, 4, 1, 2021, 13, 1, 1, 1 };
226
227 void
228 init_ipfwacc(void)
229 {
230     REGISTER_MIB("misc/ipfwacc", ipfwacc_variables, variable2,
231                  ipfwacc_variables_oid);
232 }
233
234
235 u_char         *
236 var_ipfwacc(struct variable *vp,
237             oid * name,
238             size_t * length,
239             int exact, size_t * var_len, WriteMethod ** write_method)
240 {
241     *write_method = 0;          /* assume it isnt writable for the time being */
242     *var_len = sizeof(ret_val); /* assume an integer and change later if not */
243
244     if (header_simple_table
245         (vp, name, length, exact, var_len, write_method, readrule(0)))
246         return (NULL);
247
248     if (readrule(name[*length - 1])) {
249         /*
250          * this is where we do the value assignments for the mib results. 
251          */
252         switch (vp->magic) {
253         case IPFWACCINDEX:
254             ret_val = name[*length - 1];
255             return ((u_char *) (&ret_val));
256         case IPFWACCSRCADDR:
257             atoip(0);
258             return ((u_char *) (&ret_val));
259         case IPFWACCSRCNM:
260             atoip(9);
261             return ((u_char *) (&ret_val));
262         case IPFWACCDSTADDR:
263             atoip(19);
264             return ((u_char *) (&ret_val));
265         case IPFWACCDSTNM:
266             atoip(28);
267             return ((u_char *) (&ret_val));
268         case IPFWACCVIANAME:
269             {
270                 int             i = 37; /* position in the rule */
271                 while (rule[i] != ' ' && i < IPFWRULELEN - 1)
272                     i++;
273                 rule[i] = 0;
274                 return (rule + 37);
275             }
276         case IPFWACCVIAADDR:
277             {
278                 int             i = 37; /* position in the rule */
279                 while (rule[i] != ' ' && i < IPFWRULELEN - 9)
280                     i++;
281                 atoip(i + 1);
282                 return ((u_char *) (&ret_val));
283             }
284         case IPFWACCPROTO:
285             switch (getflags() & IP_FW_F_KIND) {
286             case IP_FW_F_ALL:
287                 ret_val = 2;
288                 return ((u_char *) (&ret_val));
289             case IP_FW_F_TCP:
290                 ret_val = 3;
291                 return ((u_char *) (&ret_val));
292             case IP_FW_F_UDP:
293                 ret_val = 4;
294                 return ((u_char *) (&ret_val));
295             case IP_FW_F_ICMP:
296                 ret_val = 5;
297                 return ((u_char *) (&ret_val));
298             default:
299                 ret_val = 1;
300                 return ((u_char *) (&ret_val));
301             }
302         case IPFWACCBIDIR:
303             ret_val = ((getflags() & IP_FW_F_BIDIR) ? 2 : 1);
304             return ((u_char *) (&ret_val));
305         case IPFWACCDIR:
306             ret_val = (getflags() & (IP_FW_F_ACCTIN | IP_FW_F_ACCTOUT));
307             if (ret_val == IP_FW_F_ACCTIN)
308                 ret_val = 2;
309             else if (ret_val == IP_FW_F_ACCTOUT)
310                 ret_val = 3;
311             else
312                 ret_val = 1;
313             return ((u_char *) (&ret_val));
314         case IPFWACCBYTES:
315             getnumeric(4);
316             return ((u_char *) (&ret_val));
317         case IPFWACCPACKETS:
318             getnumeric(3);
319             return ((u_char *) (&ret_val));
320         case IPFWACCNSRCPRTS:
321             getnumeric(1);
322             return ((u_char *) (&ret_val));
323         case IPFWACCNDSTPRTS:
324             getnumeric(2);
325             return ((u_char *) (&ret_val));
326         case IPFWACCSRCISRNG:
327             ret_val = ((getflags() & IP_FW_F_SRNG) ? 1 : 2);
328             return ((u_char *) (&ret_val));
329         case IPFWACCDSTISRNG:
330             ret_val = ((getflags() & IP_FW_F_DRNG) ? 1 : 2);
331             return ((u_char *) (&ret_val));
332         case IPFWACCPORT1:
333         case IPFWACCPORT2:
334         case IPFWACCPORT3:
335         case IPFWACCPORT4:
336         case IPFWACCPORT5:
337         case IPFWACCPORT6:
338         case IPFWACCPORT7:
339         case IPFWACCPORT8:
340         case IPFWACCPORT9:
341         case IPFWACCPORT10:
342             getnumeric(5 + (vp->magic) - IPFWACCPORT1);
343             return ((u_char *) (&ret_val));
344         }
345     }
346     return NULL;
347 }