1 /*-
2 * Copyright (c) 2001, 2004 Lev Walkin <vlm@lionet.info>.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $Id: disp.c,v 1.32 2004/11/12 06:38:03 vlm Exp $
27 */
28
29 #include "ipcad.h"
30 #include "cfgvar.h"
31 #include "storage.h"
32 #include "opt.h"
33 #include "disp.h"
34
35 #define C(f) (unsigned char)((f) & 0xff)
36
37 void
print_ip(FILE * f,struct in_addr ip)38 print_ip(FILE *f, struct in_addr ip) {
39 ip.s_addr = ntohl(ip.s_addr);
40 fprintf(f, "%d.%d.%d.%d",
41 C(ip.s_addr >> 24),
42 C(ip.s_addr >> 16),
43 C(ip.s_addr >> 8),
44 C(ip.s_addr >> 0)
45 );
46 }
47
48 void
print_aligned_ip(FILE * f,struct in_addr ip)49 print_aligned_ip(FILE *f, struct in_addr ip) {
50 int z;
51
52 ip.s_addr = ntohl(ip.s_addr);
53
54 z = fprintf(f, " %d.%d.%d.%d",
55 C(ip.s_addr >> 24),
56 C(ip.s_addr >> 16),
57 C(ip.s_addr >> 8),
58 C(ip.s_addr >> 0)
59 );
60
61 #define ROOM_FOR_IPADDR 17
62 while(z++ < ROOM_FOR_IPADDR)
63 putc(' ', f);
64 }
65
66
67 int
display(FILE * f,disp_storage_e dstore)68 display(FILE *f, disp_storage_e dstore) {
69 flow_t *flows;
70 int entries;
71 time_t storage_created_tstamp;
72 time_t stalled;
73 long long ex_packets;
74 long long ex_bytes;
75 flow_storage_t *storage;
76 int ret;
77
78 switch(dstore) {
79 case DS_ACTIVE: storage = &active_storage; break;
80 case DS_CHECKPOINT: storage = &checkpoint_storage; break;
81 case DS_NETFLOW: storage = &netflow_storage; break;
82 default:
83 errno = EINVAL;
84 return -1;
85 }
86
87 /*
88 * Perform quick operation on the locked table.
89 */
90 lock_storage(storage);
91 stalled = storage->first_miss;
92 ex_packets = storage->missed_packets;
93 ex_bytes = storage->missed_bytes;
94 storage_created_tstamp = storage->create_time;
95
96 ret = get_flow_table(storage, &flows, &entries);
97 unlock_storage(storage);
98
99 if(ret == -1) {
100 fprintf(f, "Memory allocation error.\n");
101 return -1;
102 }
103
104 if(dstore == DS_NETFLOW) {
105 putc('\n', f);
106 fprintf(f, "IP Flow Switching Cache, %ld bytes\n",
107 (long)entries * sizeof(*active_storage.buckets[0]));
108 fprintf(f, " %ld flows, %lld flow alloc failures\n",
109 (long)entries, ex_packets);
110 fprintf(f, " Active flows timeout in %ld minutes\n",
111 (long)(conf->netflow_timeout_active / 60));
112 fprintf(f, " Inactive flows timeout in %ld seconds\n",
113 (long)conf->netflow_timeout_inactive);
114 }
115
116 /*
117 * Print out the table contents.
118 */
119 dump_flow_table(f, flows, entries, dstore);
120
121 if(flows) free(flows);
122
123 if(dstore == DS_NETFLOW)
124 return 0; /* Further info is not necessary */
125
126 if(storage_created_tstamp) {
127 time_t now = time(NULL);
128 time_t age = (now - storage_created_tstamp) / 60;
129
130 fprintf(f, "Accounting data age is %5ld\n", (long)age);
131 fprintf(f, "Accounting data age exact %ld\n",
132 (long)now - storage_created_tstamp);
133 fprintf(f, "Accounting data saved %ld\n", (long)now);
134 }
135
136 if(ex_packets)
137 fprintf(f,
138 "Accounting threshold exceeded for %llu packets "
139 "and %llu bytes\n", ex_packets, ex_bytes);
140
141 if(stalled)
142 fprintf(f, "Information incomplete since %s", ctime(&stalled));
143
144 if(dstore == DS_ACTIVE)
145 show_stats(f);
146
147 return 0;
148 }
149
150 void
dump_flow_table(FILE * f,flow_t * flow,int entries,disp_storage_e mode)151 dump_flow_table(FILE *f, flow_t *flow, int entries, disp_storage_e mode) {
152
153 /*
154 * Print out the header.
155 */
156 if(mode == DS_NETFLOW) {
157 fprintf(f,
158 "\nSrcIf SrcIPaddress"
159 " DstIf DstIPaddress"
160 " Pr SrcP DstP Pkts\n");
161 for(; entries > 0; entries--, flow++) {
162 int sport = flow->src_port;
163 int dport = flow->dst_port;
164 if(sport == -1) sport = dport = 0;
165 if(flow->ifInName[0])
166 fprintf(f, "%-13s", flow->ifInName);
167 else
168 fprintf(f, "%-13s",
169 IFNameBySource(flow->ifSource));
170 print_aligned_ip(f, flow->src);
171 if(flow->ifOutName[0])
172 fprintf(f, "%-13s", flow->ifOutName);
173 else
174 fprintf(f, "%-13s", "<?>");
175 print_aligned_ip(f, flow->dst);
176 fprintf(f, "%02x %04x %04x %5ld",
177 flow->ip_p, sport, dport, (long)flow->packets);
178 putc('\n', f);
179 }
180 putc('\n', f);
181 return;
182 } else if(conf->capture_ports)
183 fprintf(f,
184 "\n Source Destination"
185 " Packets Bytes"
186 " SrcPt DstPt Proto IF\n");
187 else
188 fprintf(f,
189 "\n Source Destination"
190 " Packets Bytes"
191 "\n");
192
193 /*
194 * Print the entries.
195 */
196 for(; entries > 0; entries--, flow++) {
197 print_aligned_ip(f, flow->src);
198 print_aligned_ip(f, flow->dst);
199 fprintf(f,
200 conf->capture_ports
201 ?"%8lu %12qu"
202 :"%18lu %19qu",
203 (unsigned long)flow->packets, flow->bytes);
204 if(conf->capture_ports) {
205 if(flow->src_port == -1)
206 fprintf(f, " %6s %5s", "-", "-");
207 else
208 fprintf(f, " %6d %5d",
209 flow->src_port, flow->dst_port);
210 fprintf(f, " %5d ", flow->ip_p);
211 if(flow->ifInName[0])
212 fprintf(f, "%4s", flow->ifInName);
213 else
214 fprintf(f, "%4s", IFNameBySource(flow->ifSource));
215 }
216 putc('\n', f);
217 }
218
219 putc('\n', f);
220 }
221
222 void
show_stats(FILE * f)223 show_stats(FILE *f) {
224 packet_source_t *ps;
225 size_t active_entries;
226 size_t netflow_entries;
227 size_t used_memory;
228
229 /* Reasonably atomic operations, no locking required */
230 active_entries = active_storage.entries;
231 netflow_entries = netflow_storage.entries;
232 used_memory = active_entries * sizeof(*active_storage.buckets[0]);
233
234 for(ps = conf->packet_sources_head; ps; ps = ps->next) {
235 ps->print_stats(f, ps);
236 }
237
238 fprintf(f, "Flow entries made: %ld\n", (long)active_entries);
239 if(conf->netflow_enabled)
240 fprintf(f, "NetFlow cached flows: %ld\n", (long)netflow_entries);
241
242 if(conf->memsize)
243 fprintf(f, "Memory usage: %ld%% (%ld from %ld)\n",
244 (long)(used_memory * 100 / conf->memsize),
245 (long)used_memory, (long)conf->memsize);
246 else
247 fprintf(f, "Memory usage: %ld kbytes.\n",
248 (long)(used_memory >> 10));
249
250 fprintf(f, "Free slots for rsh clients: %ld\n", (long)max_clients);
251
252 ipcad_uptime(f);
253 system_uptime(f);
254 }
255
256 int
display_internal_averages(FILE * f,const char * ifname)257 display_internal_averages(FILE *f, const char *ifname) {
258 packet_source_t *ps;
259
260 /* Find the interface */
261 for(ps = conf->packet_sources_head; ps; ps = ps->next) {
262 if(strcmp(ps->ifName, ifname) == 0)
263 break;
264 }
265
266 if(!ps)
267 return -1;
268
269 fprintf(f, " %.0f minute average rate %lld bits/sec, %lld packets/sec\n",
270 ps->avg_period / 60,
271 ps->bps_lp * 8,
272 ps->pps_lp
273 );
274
275 return 0;
276 }
277
278 void
show_version(FILE * f)279 show_version(FILE *f) {
280 fprintf(f,
281 IPCAD_VERSION_STRING
282 IPCAD_COPYRIGHT "\n"
283 "\n"
284 );
285
286 ipcad_uptime(f);
287 system_uptime(f);
288 }
289
290
291 void
ipcad_uptime(FILE * f)292 ipcad_uptime(FILE *f) {
293 fprintf(f, "IPCAD uptime is");
294 display_uptime(f, time(NULL) - (time_t)self_started);
295 }
296
297
298 void
display_uptime(FILE * f,time_t uptime)299 display_uptime(FILE *f, time_t uptime) {
300 int days, hrs, mins, secs;
301
302 days = uptime / 86400;
303 uptime %= 86400;
304 hrs = uptime / 3600;
305 uptime %= 3600;
306 mins = uptime / 60;
307 secs = uptime % 60;
308
309 if(days > 0)
310 fprintf(f, " %d day%s", days, days>1?"s":"");
311 if(hrs > 0 && mins > 0)
312 fprintf(f, " %2d:%02d", hrs, mins);
313 else if(hrs > 0)
314 fprintf(f, " %d hour%s,", hrs, hrs>1?"s":"");
315 else if(mins > 0)
316 fprintf(f, " %d minute%s", mins, mins>1?"s":"");
317 else
318 fprintf(f, " %d second%s", secs, secs>1?"s":"");
319 fprintf(f, "\n");
320
321 }
322
323