2 * copyright (c) 2001-2008 Emil Mikulic.
4 * acct.c: traffic accounting
6 * Permission to use, copy, modify, and distribute this file for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
28 #include <arpa/inet.h> /* for inet_aton() */
30 #include <netinet/tcp.h>
31 #include <stdlib.h> /* for free */
32 #include <string.h> /* for memcpy */
34 uint64_t total_packets
= 0, total_bytes
= 0;
36 static int using_localnet
= 0;
37 static in_addr_t localnet
, localmask
;
39 /* Parse the net/mask specification into two IPs or die trying. */
41 acct_init_localnet(const char *spec
)
47 tokens
= split('/', spec
, &num_tokens
);
49 errx(1, "expecting network/netmask, got \"%s\"", spec
);
51 if (inet_aton(tokens
[0], &addr
) != 1)
52 errx(1, "invalid network address \"%s\"", tokens
[0]);
53 localnet
= addr
.s_addr
;
55 if (inet_aton(tokens
[1], &addr
) != 1)
56 errx(1, "invalid network mask \"%s\"", tokens
[1]);
57 localmask
= addr
.s_addr
;
58 /* FIXME: improve so we can accept masks like /24 for 255.255.255.0 */
65 verbosef("local network address: %s", ip_to_str(localnet
));
66 verbosef(" local network mask: %s", ip_to_str(localmask
));
68 if ((localnet
& localmask
) != localnet
)
69 errx(1, "this is an invalid combination of address and mask!\n"
70 "it cannot match any address!");
73 /* Account for the given packet summary. */
75 acct_for(const pktsummary
*sm
)
77 struct bucket
*hs
= NULL
, *hd
= NULL
;
78 struct bucket
*ps
, *pd
;
81 #if 0 /* WANT_CHATTY? */
82 printf("%15s > ", ip_to_str(sm
->src_ip
));
83 printf("%15s ", ip_to_str(sm
->dest_ip
));
84 printf("len %4d proto %2d", sm
->len
, sm
->proto
);
86 if (sm
->proto
== IPPROTO_TCP
|| sm
->proto
== IPPROTO_UDP
)
87 printf(" port %5d : %5d", sm
->src_port
, sm
->dest_port
);
88 if (sm
->proto
== IPPROTO_TCP
)
89 printf(" %s%s%s%s%s%s",
90 (sm
->tcp_flags
& TH_FIN
)?"F":"",
91 (sm
->tcp_flags
& TH_SYN
)?"S":"",
92 (sm
->tcp_flags
& TH_RST
)?"R":"",
93 (sm
->tcp_flags
& TH_PUSH
)?"P":"",
94 (sm
->tcp_flags
& TH_ACK
)?"A":"",
95 (sm
->tcp_flags
& TH_URG
)?"U":""
102 total_bytes
+= sm
->len
;
105 dir_in
= dir_out
= 0;
107 if (using_localnet
) {
108 if ((sm
->src_ip
& localmask
) == localnet
)
110 if ((sm
->dest_ip
& localmask
) == localnet
)
112 if (dir_in
== 1 && dir_out
== 1)
113 /* Traffic staying within the network isn't counted. */
114 dir_in
= dir_out
= 0;
116 if (sm
->src_ip
== localip
)
118 if (sm
->dest_ip
== localip
)
123 daylog_acct((uint64_t)sm
->len
, GRAPH_OUT
);
124 graph_acct((uint64_t)sm
->len
, GRAPH_OUT
);
127 daylog_acct((uint64_t)sm
->len
, GRAPH_IN
);
128 graph_acct((uint64_t)sm
->len
, GRAPH_IN
);
131 if (hosts_max
== 0) return; /* skip per-host accounting */
134 hs
= host_get(sm
->src_ip
);
136 hs
->total
+= sm
->len
;
137 memcpy(hs
->u
.host
.mac_addr
, sm
->src_mac
, sizeof(sm
->src_mac
));
138 hs
->u
.host
.last_seen
= now
;
140 hd
= host_get(sm
->dest_ip
); /* this can invalidate hs! */
142 hd
->total
+= sm
->len
;
143 memcpy(hd
->u
.host
.mac_addr
, sm
->dst_mac
, sizeof(sm
->dst_mac
));
144 hd
->u
.host
.last_seen
= now
;
147 hs
= host_find(sm
->src_ip
);
149 ps
= host_get_ip_proto(hs
, sm
->proto
);
151 ps
->total
+= sm
->len
;
154 pd
= host_get_ip_proto(hd
, sm
->proto
);
156 pd
->total
+= sm
->len
;
158 if (ports_max
== 0) return; /* skip ports accounting */
164 if ((sm
->src_port
<= highest_port
) && (hs
!= NULL
))
166 ps
= host_get_port_tcp(hs
, sm
->src_port
);
168 ps
->total
+= sm
->len
;
171 if (sm
->dest_port
<= highest_port
)
173 pd
= host_get_port_tcp(hd
, sm
->dest_port
);
175 pd
->total
+= sm
->len
;
176 if (sm
->tcp_flags
== TH_SYN
)
177 pd
->u
.port_tcp
.syn
++;
182 if ((sm
->src_port
<= highest_port
) && (hs
!= NULL
))
184 ps
= host_get_port_udp(hs
, sm
->src_port
);
186 ps
->total
+= sm
->len
;
189 if (sm
->dest_port
<= highest_port
)
191 pd
= host_get_port_udp(hd
, sm
->dest_port
);
193 pd
->total
+= sm
->len
;
198 /* known protocol, don't complain about it */
202 verbosef("unknown IP proto (%04x)", sm
->proto
);
206 /* vim:set ts=3 sw=3 tw=78 expandtab: */