1 /*
2 pmacct (Promiscuous mode IP Accounting package)
3 pmacct is Copyright (C) 2003-2020 by Paolo Lucente
4 */
5
6 /*
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 */
21
22 /* includes */
23 #include "pmacct.h"
24 #include "addr.h"
25
26 /* Global variables */
27 struct xflow_status_entry *xflow_status_table[XFLOW_STATUS_TABLE_SZ];
28 u_int32_t xflow_status_table_entries;
29 u_int8_t xflow_status_table_error;
30 u_int32_t xflow_tot_bad_datagrams;
31 u_int8_t smp_entry_status_table_memerr, class_entry_status_table_memerr;
32
33 /* functions */
hash_status_table(u_int32_t data,struct sockaddr * sa,u_int32_t size)34 u_int32_t hash_status_table(u_int32_t data, struct sockaddr *sa, u_int32_t size)
35 {
36 int hash = -1;
37
38 if (sa->sa_family == AF_INET)
39 hash = (data ^ ((struct sockaddr_in *)sa)->sin_addr.s_addr) % size;
40 else if (sa->sa_family == AF_INET6) {
41 u_int32_t tmp;
42
43 memcpy(&tmp, ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr+12, 4);
44 hash = (data ^ tmp) % size;
45 // hash = (data ^ ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr32[3]) % size;
46 }
47
48 return hash;
49 }
50
search_status_table(struct sockaddr * sa,u_int32_t aux1,u_int32_t aux2,int hash,int num_entries)51 struct xflow_status_entry *search_status_table(struct sockaddr *sa, u_int32_t aux1, u_int32_t aux2, int hash, int num_entries)
52 {
53 struct xflow_status_entry *entry = xflow_status_table[hash], *saved = NULL;
54 u_int16_t port;
55
56 cycle_again:
57 if (entry) {
58 saved = entry;
59 if (!sa_addr_cmp(sa, &entry->agent_addr) && aux1 == entry->aux1 && aux2 == entry->aux2); /* FOUND IT: we are done */
60 else {
61 entry = entry->next;
62 goto cycle_again;
63 }
64 }
65 else {
66 if (xflow_status_table_entries < num_entries) {
67 entry = malloc(sizeof(struct xflow_status_entry));
68 if (!entry) goto error;
69 else {
70 memset(entry, 0, sizeof(struct xflow_status_entry));
71 sa_to_addr((struct sockaddr *)sa, &entry->agent_addr, &port);
72 entry->aux1 = aux1;
73 entry->aux2 = aux2;
74 entry->seqno = 0;
75 entry->next = FALSE;
76 if (!saved) xflow_status_table[hash] = entry;
77 else saved->next = entry;
78 xflow_status_table_error = TRUE;
79 xflow_status_table_entries++;
80 }
81 }
82 else {
83 error:
84 if (xflow_status_table_error) {
85 Log(LOG_ERR, "ERROR ( %s/%s ): unable to allocate more entries into the xFlow status table.\n", config.name, config.type);
86 xflow_status_table_error = FALSE;
87 return NULL;
88 }
89 }
90 }
91
92 return entry;
93 }
94
update_status_table(struct xflow_status_entry * entry,u_int32_t seqno,int bytes)95 void update_status_table(struct xflow_status_entry *entry, u_int32_t seqno, int bytes)
96 {
97 if (!entry) return;
98
99 entry->counters.total++;
100 entry->counters.bytes += bytes;
101
102 if (!entry->seqno || config.nfacctd_disable_checks) {
103 entry->counters.good++;
104 }
105 else {
106 if (seqno == entry->seqno + entry->inc) entry->counters.good++;
107 else {
108 char agent_ip_address[INET6_ADDRSTRLEN];
109 char collector_ip_address[INET6_ADDRSTRLEN];
110 char null_ip_address[] = "0.0.0.0";
111
112 addr_to_str(agent_ip_address, &entry->agent_addr);
113 if (config.nfacctd_ip)
114 memcpy(collector_ip_address, config.nfacctd_ip, MAX(strlen(config.nfacctd_ip), INET6_ADDRSTRLEN));
115 else
116 strcpy(collector_ip_address, null_ip_address);
117
118 Log(LOG_INFO, "INFO ( %s/%s ): expecting flow '%u' but received '%u' collector=%s:%u agent=%s:%u\n",
119 config.name, config.type, entry->seqno+entry->inc, seqno, collector_ip_address,
120 collector_port, agent_ip_address, entry->aux1);
121 if (seqno > entry->seqno+entry->inc) entry->counters.jumps_f++;
122 else entry->counters.jumps_b++;
123 }
124 }
125
126 entry->seqno = seqno;
127 }
128
print_status_table(time_t now,int buckets)129 void print_status_table(time_t now, int buckets)
130 {
131 struct xflow_status_entry *entry;
132 int idx;
133 char agent_ip_address[INET6_ADDRSTRLEN];
134 char collector_ip_address[INET6_ADDRSTRLEN];
135 char null_ip_address[] = "0.0.0.0";
136
137 Log(LOG_NOTICE, "NOTICE ( %s/%s ): +++\n", config.name, config.type);
138
139 if (config.nfacctd_ip) memcpy(collector_ip_address, config.nfacctd_ip, MAX(strlen(config.nfacctd_ip), INET6_ADDRSTRLEN));
140 else strcpy(collector_ip_address, null_ip_address);
141
142 for (idx = 0; idx < buckets; idx++) {
143 entry = xflow_status_table[idx];
144
145 bucket_cycle:
146 if (entry && entry->counters.total && entry->counters.bytes) {
147 addr_to_str(agent_ip_address, &entry->agent_addr);
148
149 Log(LOG_NOTICE, "NOTICE ( %s/%s ): stats [%s:%u] agent=%s:%u time=%ld packets=%" PRIu64 " bytes=%" PRIu64 " seq_good=%u seq_jmp_fwd=%u seq_jmp_bck=%u\n",
150 config.name, config.type, collector_ip_address, collector_port,
151 agent_ip_address, entry->aux1, (long)now, entry->counters.total, entry->counters.bytes,
152 entry->counters.good, entry->counters.jumps_f, entry->counters.jumps_b);
153
154 if (entry->next) {
155 entry = entry->next;
156 goto bucket_cycle;
157 }
158 }
159 }
160
161 Log(LOG_NOTICE, "NOTICE ( %s/%s ): stats [%s:%u] time=%ld discarded_packets=%u\n",
162 config.name, config.type, collector_ip_address, collector_port,
163 (long)now, xflow_tot_bad_datagrams);
164
165 Log(LOG_NOTICE, "NOTICE ( %s/%s ): ---\n", config.name, config.type);
166 }
167
168 struct xflow_status_entry_sampling *
search_smp_if_status_table(struct xflow_status_entry_sampling * sentry,u_int32_t interface)169 search_smp_if_status_table(struct xflow_status_entry_sampling *sentry, u_int32_t interface)
170 {
171 while (sentry) {
172 if (sentry->interface == interface) return sentry;
173 sentry = sentry->next;
174 }
175
176 return NULL;
177 }
178
179 struct xflow_status_entry_sampling *
search_smp_id_status_table(struct xflow_status_entry_sampling * sentry,u_int32_t sampler_id,u_int8_t return_unequal)180 search_smp_id_status_table(struct xflow_status_entry_sampling *sentry, u_int32_t sampler_id, u_int8_t return_unequal)
181 {
182 /* Match a samplerID or, if samplerID within a data record is zero and no match was
183 possible, then return the last samplerID defined -- last part is C7600 workaround */
184 while (sentry) {
185 if (sentry->sampler_id == sampler_id || (return_unequal && !sampler_id && !sentry->next)) return sentry;
186 sentry = sentry->next;
187 }
188
189 return NULL;
190 }
191
192 struct xflow_status_entry_sampling *
create_smp_entry_status_table(struct xflow_status_entry * entry)193 create_smp_entry_status_table(struct xflow_status_entry *entry)
194 {
195 struct xflow_status_entry_sampling *sentry = entry->sampling, *new = NULL;
196
197 if (sentry) {
198 while (sentry->next) sentry = sentry->next;
199 }
200
201 if (xflow_status_table_entries < XFLOW_STATUS_TABLE_MAX_ENTRIES) {
202 new = malloc(sizeof(struct xflow_status_entry_sampling));
203 if (!new) {
204 if (smp_entry_status_table_memerr) {
205 Log(LOG_ERR, "ERROR ( %s/%s ): unable to allocate more entries into the xflow renormalization table.\n", config.name, config.type);
206 smp_entry_status_table_memerr = FALSE;
207 }
208 }
209 else {
210 if (!entry->sampling) entry->sampling = new;
211 if (sentry) sentry->next = new;
212 new->next = FALSE;
213 smp_entry_status_table_memerr = TRUE;
214 xflow_status_table_entries++;
215 }
216 }
217
218 return new;
219 }
220
221 struct xflow_status_entry_class *
search_class_id_status_table(struct xflow_status_entry_class * centry,pm_class_t class_id)222 search_class_id_status_table(struct xflow_status_entry_class *centry, pm_class_t class_id)
223 {
224 pm_class_t needle, haystack;
225
226 needle = ntohl(class_id);
227
228 while (centry) {
229 haystack = ntohl(centry->class_id);
230
231 if (haystack == needle) return centry;
232 centry = centry->next;
233 }
234
235 return NULL;
236 }
237
238 struct xflow_status_entry_class *
create_class_entry_status_table(struct xflow_status_entry * entry)239 create_class_entry_status_table(struct xflow_status_entry *entry)
240 {
241 struct xflow_status_entry_class *centry = entry->class, *new = NULL;
242
243 if (centry) {
244 while (centry->next) centry = centry->next;
245 }
246
247 if (xflow_status_table_entries < XFLOW_STATUS_TABLE_MAX_ENTRIES) {
248 new = malloc(sizeof(struct xflow_status_entry_class));
249 if (!new) {
250 if (class_entry_status_table_memerr) {
251 Log(LOG_ERR, "ERROR ( %s/%s ): unable to allocate more entries into the xflow classification table.\n", config.name, config.type);
252 class_entry_status_table_memerr = FALSE;
253 }
254 }
255 else {
256 if (!entry->class) entry->class = new;
257 if (centry) centry->next = new;
258 new->next = FALSE;
259 class_entry_status_table_memerr = TRUE;
260 xflow_status_table_entries++;
261 }
262 }
263
264 return new;
265 }
266
set_vector_f_status(struct packet_ptrs_vector * pptrsv)267 void set_vector_f_status(struct packet_ptrs_vector *pptrsv)
268 {
269 pptrsv->vlan4.f_status = pptrsv->v4.f_status;
270 pptrsv->mpls4.f_status = pptrsv->v4.f_status;
271 pptrsv->vlanmpls4.f_status = pptrsv->v4.f_status;
272
273 pptrsv->v6.f_status = pptrsv->v4.f_status;
274 pptrsv->vlan6.f_status = pptrsv->v4.f_status;
275 pptrsv->vlanmpls6.f_status = pptrsv->v4.f_status;
276 pptrsv->mpls6.f_status = pptrsv->v4.f_status;
277 }
278
set_vector_f_status_g(struct packet_ptrs_vector * pptrsv)279 void set_vector_f_status_g(struct packet_ptrs_vector *pptrsv)
280 {
281 pptrsv->vlan4.f_status_g = pptrsv->v4.f_status_g;
282 pptrsv->mpls4.f_status_g = pptrsv->v4.f_status_g;
283 pptrsv->vlanmpls4.f_status_g = pptrsv->v4.f_status_g;
284
285 pptrsv->v6.f_status_g = pptrsv->v4.f_status_g;
286 pptrsv->vlan6.f_status_g = pptrsv->v4.f_status_g;
287 pptrsv->vlanmpls6.f_status_g = pptrsv->v4.f_status_g;
288 pptrsv->mpls6.f_status_g = pptrsv->v4.f_status_g;
289 }
290