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