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