init constants outside loop
[prads.git] / src / assets.c
blobd7387422f49a6f9461f325bf53cbbdba838c56ba
1 #include "common.h"
2 #include "prads.h"
3 #include "assets.h"
4 #include "sys_func.h"
5 #include "output-plugins/log.h"
6 #include "config.h"
7 #include "mac.h"
9 extern globalconfig config;
10 static asset *passet[BUCKET_SIZE];
12 void update_asset(packetinfo *pi)
14 if (asset_lookup(pi) == SUCCESS) {
15 if (pi->asset != NULL) {
16 pi->asset->vlan = pi->vlan;
17 pi->asset->last_seen = pi->pheader->ts.tv_sec;
18 } else {
19 printf("\nBAD ERROR in update_asset\n");
21 } else {
22 add_asset(pi);
24 return;
27 void update_service_stats(int role, uint16_t proto)
29 if (role==SC_SERVER) {
30 if (proto== 6) config.pr_s.tcp_services++;
31 if (proto==17) config.pr_s.udp_services++;
32 } else {
33 if (proto== 6) config.pr_s.tcp_clients++;
34 if (proto==17) config.pr_s.udp_clients++;
38 void update_os_stats(uint8_t detection)
40 switch (detection) {
41 // fallthrough
42 case CO_SYN:
43 case CO_SYNACK:
44 case CO_ACK:
45 case CO_FIN:
46 case CO_RST:
47 config.pr_s.tcp_os_assets++;
48 break;
49 case CO_UDP:
50 config.pr_s.udp_os_assets++;
51 break;
52 case CO_ICMP:
53 config.pr_s.icmp_os_assets++;
54 break;
55 case CO_DHCP:
56 config.pr_s.dhcp_os_assets++;
57 break;
58 default:
59 break;
63 void flip_connection(packetinfo *pi, asset* masset)
65 if (pi->sc == SC_CLIENT) {
66 if (pi->cxt->reversed == 0)
67 pi->cxt->c_asset = masset;
68 else
69 pi->cxt->s_asset = masset;
70 } else {
71 if (pi->cxt->reversed == 0)
72 pi->cxt->s_asset = masset;
73 else
74 pi->cxt->c_asset = masset;
76 if (pi->sc == SC_CLIENT) {
77 if (pi->cxt->reversed == 0)
78 pi->cxt->c_asset = masset;
79 else
80 pi->cxt->s_asset = masset;
81 } else {
82 if (pi->cxt->reversed == 0)
83 pi->cxt->s_asset = masset;
84 else
85 pi->cxt->c_asset = masset;
89 asset* connection_lookup(packetinfo *pi)
91 if(NULL == pi->cxt){
92 return NULL;
95 if (pi->sc == SC_CLIENT && pi->cxt->reversed == 0 && pi->cxt->c_asset != NULL) {
96 return pi->cxt->c_asset;
97 } else if (pi->sc == SC_CLIENT && pi->cxt->reversed == 1 && pi->cxt->s_asset != NULL) {
98 return pi->cxt->s_asset;
99 } else if (pi->sc == SC_SERVER && pi->cxt->reversed == 0 && pi->cxt->s_asset != NULL) {
100 return pi->cxt->s_asset;
101 } else if (pi->sc == SC_SERVER && pi->cxt->reversed == 1 && pi->cxt->c_asset != NULL) {
102 return pi->cxt->c_asset;
104 return NULL;
106 /* asset *asset_lookup(struct in6_addr ip, int af)
107 * tries to match your packet to a sender we've seen before
109 * 1. already in connection database
110 * 2. ip4 lookup & ip6 lookup
111 * 3. mac lookup
113 * asset_lookup should return 0 on success, 1 on failure
115 uint8_t asset_lookup(packetinfo *pi)
117 uint64_t hash;
118 asset *masset = NULL;
120 if (pi->asset != NULL || NULL != (pi->asset = connection_lookup(pi))){
121 return SUCCESS;
122 } else {
123 if (pi->af == AF_INET) {
124 uint32_t ip;
126 if(pi->arph) {// arp check
127 //memcpy(&ip, pi->arph->arp_spa, sizeof(uint8_t)*4);
128 ip = *(uint32_t*) pi->arph->arp_spa;
129 } else {
130 ip = PI_IP4SRC(pi);
132 hash = ASSET_HASH4(ip);
133 masset = passet[hash];
134 while (masset != NULL) {
135 //if (memcmp(&ip_addr,&rec->ip_addr,16)) {
136 if (masset->af == AF_INET
137 && CMP_ADDR4( &masset->ip_addr, ip))
139 pi->asset = masset;
140 if (pi->cxt != NULL) {
141 flip_connection(pi,masset);
143 return SUCCESS;
145 masset = masset->next;
147 return ERROR;
148 } else if (pi->af == AF_INET6) {
149 hash = ASSET_HASH6(PI_IP6SRC(pi));
150 masset = passet[hash];
151 while (masset != NULL) {
152 if (masset->af == AF_INET6 &&
153 CMP_ADDR6(&masset->ip_addr, &PI_IP6SRC(pi))){
154 pi->asset = masset;
155 if (pi->cxt != NULL) {
156 flip_connection(pi,masset);
158 return SUCCESS;
160 masset = masset->next;
162 return ERROR;
164 return ERROR;
168 /* ----------------------------------------------------------
169 * FUNCTION : update_asset_os
170 * DESCRIPTION : This function will update the OS
171 * : fields of an asset.
172 * INPUT : 0 - IP Address
173 * : 1 - Port
174 * : 2 - detection method
175 * : 3 - raw_fp
176 * : 4 - AF_INET/6
177 * : 5 - uptime
178 * RETURN : 0 - Success!
179 * : 1 - Failure!
180 * ---------------------------------------------------------- */
182 short update_asset_shmem(packetinfo *pi)
184 // flip it upside down: caller packs it?
185 // now how would that eat the program from the inside?
186 // pass the struct around but store it in a shared mem buffer
187 (void)pi->s_port;
188 // what is detection?
189 //detection;
190 // must include this
191 //pi->raw_fp;
192 (void)pi->af;
193 //pi->uptime;
194 // what more do we need in the *pi?
195 switch(pi->type){
196 case SIGNATURE:
197 // signatures identify HOSTS or SERVICES
198 // (or mac resources) .. eventually have graph method
199 return 1; // we did the computation straight on the *pi;
200 case FINGERPRINT:
201 //update_asset_os_shmem(pi);
202 return 2; // whatever
203 default:
204 return 1338; // not leet.
208 short update_asset_os (
209 packetinfo *pi,
210 uint8_t detection,
211 bstring raw_fp,
212 fp_entry *match,
213 int uptime
216 os_asset *tmp_oa = NULL;
217 os_asset *head_oa = NULL;
219 if (asset_lookup(pi) == SUCCESS) {
220 if (pi->asset != NULL) {
221 goto os_update;
222 } else {
223 elog("BAD ERROR in update_asset_os\n");
224 return ERROR;
226 } else {
227 update_asset(pi);
228 if (update_asset_os(pi, detection, raw_fp, match, uptime) == SUCCESS) return SUCCESS;
229 else return ERROR;
232 os_update:
233 tmp_oa = pi->asset->os;
234 head_oa = pi->asset->os;
235 pi->asset->last_seen = pi->pheader->ts.tv_sec;
237 while (tmp_oa != NULL) {
238 if (detection == tmp_oa->detection) {
239 if (raw_fp) {
240 // old style save-the-fp-string OS detection
241 if (biseq(raw_fp, tmp_oa->raw_fp) == 1) {
242 /* Found! */
243 // FIXME: inefficient string copies
244 bdestroy(tmp_oa->raw_fp);
245 tmp_oa->raw_fp = bstrcpy(raw_fp);
246 //tmp_sa->i_attempts++;
247 if(pi->tcph)
248 tmp_oa->port = PI_TCP_SP(pi);
249 else
250 tmp_oa->port = 0;
252 tmp_oa->last_seen = pi->pheader->ts.tv_sec;
253 if (uptime) tmp_oa->uptime = uptime;
254 return SUCCESS;
256 }else if (match){
257 // pointer equality - does this OS asset point
258 // to the same match?
259 if (match->os == tmp_oa->fp.os &&
260 match->desc == tmp_oa->fp.desc){
261 //if (match == tmp_oa->match) {
263 if(pi->tcph)
264 tmp_oa->port = PI_TCP_SP(pi);
265 else
266 tmp_oa->port = 0;
268 tmp_oa->last_seen = pi->pheader->ts.tv_sec;
269 if (uptime)
270 tmp_oa->uptime = uptime;
271 return SUCCESS;
275 tmp_oa = tmp_oa->next;
278 if (tmp_oa == NULL) {
279 update_os_stats(detection);
280 os_asset *new_oa = NULL;
282 // FIXME: allocate resource from shared storage pool
283 new_oa = (os_asset *) calloc(1, sizeof(os_asset));
284 new_oa->detection = detection;
286 if (raw_fp) {
287 // FIXME: don't copy fp, bincode it
288 new_oa->raw_fp = bstrcpy(raw_fp);
289 } else if(match) {
290 // copy the match
291 new_oa->fp = *match;
292 //new_oa->fp = *match; //why copy it two times?
294 //new_oa->i_attempts = 1;
295 new_oa->first_seen = pi->pheader->ts.tv_sec;
296 new_oa->last_seen = pi->pheader->ts.tv_sec;
298 if(pi->tcph)
299 new_oa->port = PI_TCP_SP(pi);
300 else
301 new_oa->port = 0;
303 if (pi->ip4 != NULL) new_oa->ttl = pi->ip4->ip_ttl;
304 else if (pi->ip6 != NULL) new_oa->ttl = pi->ip6->hop_lmt;
305 if (uptime) new_oa->uptime = uptime;
306 new_oa->next = head_oa;
307 if (head_oa != NULL)
308 head_oa->prev = new_oa;
309 new_oa->prev = NULL;
310 pi->asset->os = new_oa;
312 log_asset_os(pi->asset,new_oa);
313 return SUCCESS;
315 return ERROR;
318 /* ----------------------------------------------------------
319 * FUNCTION : update_asset_service
320 * DESCRIPTION : This function will update the service and
321 * : application fields of an asset.
322 * INPUT : 0 - IP Address
323 * : 1 - Port
324 * : 2 - Proto
325 * : 3 - Service
326 * : 4 - Application
327 * RETURN : 0 - Success!
328 * : 1 - Failure!
329 * ---------------------------------------------------------- */
330 short update_asset_service(packetinfo *pi, bstring service, bstring application)
332 serv_asset *tmp_sa = NULL;
333 serv_asset *head_sa = NULL;
334 uint16_t port;
336 if (asset_lookup(pi) == SUCCESS) {
337 if (pi->asset != NULL) {
338 if (pi->sc == SC_CLIENT) {
339 port = pi->d_port;
340 } else {
341 port = pi->s_port;
343 goto service_update;
344 } else {
345 printf("\nBAD ERROR in update_asset_service\n");
346 return ERROR;
348 } else {
349 /* If no asset */
350 update_asset(pi);
351 return update_asset_service(pi, service, application);
354 service_update:
356 /* Find asset within linked list */
357 tmp_sa = head_sa = pi->asset->services;
358 pi->asset->last_seen = pi->pheader->ts.tv_sec;
360 while (tmp_sa != NULL) {
361 if (port == tmp_sa->port && pi->proto == tmp_sa->proto) {
363 * Found!
364 * If we have an id for the service which is != unknown AND the id now is unknown
365 * - just increment i_attempts untill MAX_PKT_CHECK before replacing with unknown
367 * NEW: No more unknown :)
368 * But now we have generic service for the port, example: @https
369 * So now we just check the first char of the string for '@'.
370 * if (application->data[0] != '@') (If the service matched dont starts with a '@')
371 * and the service registered in the service_asset starts with '@', discard it and
372 * register the new asset!
374 if ((application->data[0] != '@') && (tmp_sa->application->data[0] == '@')) {
375 tmp_sa->i_attempts = 0;
376 bdestroy(tmp_sa->service);
377 bdestroy(tmp_sa->application);
378 tmp_sa->service = bstrcpy(service);
379 tmp_sa->application = bstrcpy(application);
380 tmp_sa->last_seen = pi->pheader->ts.tv_sec;
382 log_asset_service(pi->asset,tmp_sa);
383 return SUCCESS;
385 } else if (!(biseq(application, tmp_sa->application) == 1)) {
386 if (tmp_sa->i_attempts > MAX_SERVICE_CHECK) {
387 tmp_sa->i_attempts = 0;
388 bdestroy(tmp_sa->service);
389 bdestroy(tmp_sa->application);
390 tmp_sa->service = bstrcpy(service);
391 tmp_sa->application = bstrcpy(application);
392 tmp_sa->last_seen = pi->pheader->ts.tv_sec;
394 log_asset_service(pi->asset,tmp_sa);
395 return SUCCESS;
397 } else {
398 tmp_sa->i_attempts++;
399 tmp_sa->last_seen = pi->pheader->ts.tv_sec;
400 return SUCCESS;
402 } else {
403 tmp_sa->i_attempts = 0;
404 tmp_sa->last_seen = pi->pheader->ts.tv_sec;
405 return SUCCESS;
408 tmp_sa = tmp_sa->next;
411 if (tmp_sa == NULL) {
412 update_service_stats(pi->sc, pi->proto);
413 serv_asset *new_sa = NULL;
414 new_sa = (serv_asset *) calloc(1, sizeof(serv_asset));
415 new_sa->port = port;
416 if (pi->ip4 != NULL) new_sa->ttl = pi->ip4->ip_ttl;
417 else if (pi->ip6 != NULL) new_sa->ttl = pi->ip6->hop_lmt;
418 new_sa->proto = pi->proto;
419 new_sa->service = bstrcpy(service);
420 new_sa->application = bstrcpy(application);
421 new_sa->role = pi->sc;
422 new_sa->i_attempts = 0;
423 new_sa->first_seen = pi->pheader->ts.tv_sec;
424 new_sa->last_seen = pi->pheader->ts.tv_sec;
425 new_sa->next = pi->asset->services;
426 new_sa->prev = NULL;
427 pi->asset->services = new_sa;
429 log_asset_service(pi->asset, new_sa);
430 return SUCCESS;
432 return ERROR;
435 /* ----------------------------------------------------------
436 * FUNCTION : add_asset
437 * DESCRIPTION : This function will add an asset to the
438 * : specified asset data structure.
439 * INPUT : 0 - packetinfo (af, ip_src, vlan)
440 * RETURN : None!
441 * ---------------------------------------------------------- */
442 void add_asset(packetinfo *pi)
444 uint64_t hash;
445 asset *masset = NULL;
447 config.pr_s.assets++;
449 masset = (asset *) calloc(1, sizeof(asset));
450 masset->af = pi->af;
451 masset->vlan = pi->vlan;
452 masset->i_attempts = 0;
453 masset->first_seen = masset->last_seen = pi->pheader->ts.tv_sec;
455 if (pi->af == AF_INET) {
456 if(pi->arph) // mongo arp check
457 //memcpy(&masset->ip_addr.__u6_addr.__u6_addr32[0], pi->arph->arp_spa, sizeof(uint32_t));
458 IP4ADDR(&masset->ip_addr) = *(uint32_t*) pi->arph->arp_spa;
459 else
460 IP4ADDR(&masset->ip_addr) = PI_IP4SRC(pi);
461 hash = ASSET_HASH4(IP4ADDR(&masset->ip_addr));
462 } else if (pi->af == AF_INET6) {
463 masset->ip_addr = PI_IP6SRC(pi);
464 hash = ASSET_HASH6(PI_IP6SRC(pi));
467 masset->next = passet[hash];
469 if (passet[hash] != NULL)
470 passet[hash]->prev = masset;
471 masset->prev = NULL;
472 masset->os = NULL;
473 masset->services = NULL;
474 masset->macentry = NULL;
475 passet[hash] = masset;
477 #ifdef DEBUGG
478 /* verbose info for sanity checking */
479 static char ip_addr_s[INET6_ADDRSTRLEN];
480 u_ntop(pi->ip_src, pi->af, ip_addr_s);
481 dlog("[*] asset added: %s\n",ip_addr_s);
482 #endif
484 //return masset;
487 short update_asset_arp(u_int8_t arp_sha[MAC_ADDR_LEN], packetinfo *pi)
489 if (asset_lookup(pi) == SUCCESS) {
490 if (pi->asset != NULL) {
491 goto arp_update;
492 } else {
493 printf("\nBAD ERROR in update_asset_arp\n");
494 return ERROR;
496 } else {
498 add_asset(pi);
499 update_asset(pi);
501 if ( pi->asset == NULL ) {
502 elog("update_asset(pi) failed! Asset does not exist! Cant enter MAC!!! die();\n");
503 return ERROR;
505 if (update_asset_arp(arp_sha, pi) == SUCCESS) {
506 return SUCCESS;
507 } else {
508 return ERROR;
512 arp_update:
513 /* Check the ARP data structure for an existing entry */
514 if (memcmp(pi->asset->mac_addr, arp_sha, MAC_ADDR_LEN) == 0) {
515 /* UPDATE TIME STAMP */
516 pi->asset->last_seen = pi->pheader->ts.tv_sec;
517 return SUCCESS;
518 } else {
519 /* UPDATE MAC AND TIME STAMP */
520 /* XXX: this handler suxx! */
521 if(memcmp(pi->asset->mac_addr, "\0\0\0\0\0\0", 6)){
522 printf("ACHTUNG! MAC changed! : ");
523 print_mac(pi->asset->mac_addr);
524 printf(" -> ");
526 print_mac(arp_sha);
527 printf("\n");
530 if(pi->asset->macentry == NULL) {
531 // vendor entry did not exist.
532 mac_entry *match = match_mac(config.sig_mac, arp_sha, 48);
533 pi->asset->macentry = match;
535 memcpy(&pi->asset->mac_addr, arp_sha, MAC_ADDR_LEN);
536 pi->asset->last_seen = pi->pheader->ts.tv_sec;
537 log_asset_arp(pi->asset);
538 return SUCCESS;
542 void del_os_asset(os_asset ** head_oa, os_asset * os)
545 if (os == NULL)
546 return;
547 os_asset *tmp_oa = NULL;
548 os_asset *next_oa = NULL;
549 os_asset *prev_oa = NULL;
551 tmp_oa = os;
552 //bdestroy(tmp_oa->vendor);
553 //bdestroy(tmp_oa->os);
554 bdestroy(tmp_oa->raw_fp);
555 //bdestroy(tmp_oa->matched_fp);
557 next_oa = tmp_oa->next;
558 prev_oa = tmp_oa->prev;
560 if (prev_oa == NULL) {
562 * beginning of list
564 *head_oa = next_oa;
566 * not only entry
568 if (next_oa)
569 next_oa->prev = NULL;
570 } else if (next_oa == NULL) {
572 * at end of list!
574 prev_oa->next = NULL;
575 } else {
577 * a node
579 prev_oa->next = next_oa;
580 next_oa->prev = prev_oa;
583 free(tmp_oa);
584 tmp_oa = NULL;
585 os = next_oa;
586 return;
590 void del_serv_asset(serv_asset ** head_sa, serv_asset * service)
593 if (service == NULL)
594 return;
595 serv_asset *tmp_sa = NULL;
596 serv_asset *next_sa = NULL;
597 serv_asset *prev_sa = NULL;
599 tmp_sa = service;
600 bdestroy(tmp_sa->service);
601 bdestroy(tmp_sa->application);
603 next_sa = tmp_sa->next;
604 prev_sa = tmp_sa->prev;
606 if (prev_sa == NULL) {
608 * beginning of list
610 *head_sa = next_sa;
612 * not only entry
614 if (next_sa)
615 next_sa->prev = NULL;
616 } else if (next_sa == NULL) {
618 * at end of list!
620 prev_sa->next = NULL;
621 } else {
623 * a node
625 prev_sa->next = next_sa;
626 next_sa->prev = prev_sa;
629 free(service);
630 service = NULL;
631 service = next_sa;
632 return;
635 void del_asset(asset * passet, asset ** bucket_ptr)
638 * remove passet from bucket
640 asset *prev = passet->prev; /* OLDER connections */
641 asset *next = passet->next; /* NEWER connections */
642 serv_asset *tmp_sa = passet->services;
643 os_asset *tmp_oa = passet->os;
644 serv_asset *stmp = tmp_sa;
645 os_asset *otmp = tmp_oa;
648 * delete all service assets
650 while (tmp_sa != NULL) {
651 stmp = tmp_sa;
652 tmp_sa = tmp_sa->next;
653 del_serv_asset(&passet->services, stmp);
656 * delete all os assets
658 while (tmp_oa != NULL) {
659 otmp = tmp_oa;
660 tmp_oa = tmp_oa->next;
661 del_os_asset(&passet->os, otmp);
665 * now delete the asset
667 if (prev == NULL) {
668 // beginning of list
669 *bucket_ptr = next;
670 // not only entry
671 if (next)
672 next->prev = NULL;
673 } else if (next == NULL) {
674 // at end of list!
675 prev->next = NULL;
676 } else {
677 // a node.
678 prev->next = next;
679 next->prev = prev;
683 * Free and set to NULL
685 free(passet);
686 passet = NULL;
689 void clear_asset_list()
691 asset *rec = NULL;
692 int akey;
694 for (akey = 0; akey < BUCKET_SIZE; akey++) {
695 rec = passet[akey];
696 while (rec != NULL) {
697 serv_asset *tmp_sa = NULL;
698 os_asset *tmp_oa = NULL;
699 tmp_sa = rec->services;
700 tmp_oa = rec->os;
702 while (tmp_sa != NULL) {
703 /* Delete service asset */
704 serv_asset *stmp = tmp_sa;
705 tmp_sa = tmp_sa->next;
706 del_serv_asset(&rec->services, stmp);
709 while (tmp_oa != NULL) {
710 /* Delete os asset */
711 os_asset *otmp = tmp_oa;
712 tmp_oa = tmp_oa->next;
713 del_os_asset(&rec->os, otmp);
716 /* Delete the main asset */
717 asset *tmp = rec;
718 rec = rec->next;
719 del_asset(tmp, &passet[akey]);
722 olog("asset memory has been cleared\n");
725 /* update_asset_list()
726 ** iterates over all assets,
727 **** all services
728 **** all OS matches
729 ** and expires old (service, os, asset) since CHECK_TIMEOUT
730 ** optionally printing assets updated since ASSET_TIMEOUT
731 * */
732 void update_asset_list()
734 extern time_t tstamp;
735 asset *rec = NULL;
736 int akey;
737 serv_asset *tmp_sa = NULL;
738 os_asset *tmp_oa = NULL;
740 for (akey = 0; akey < BUCKET_SIZE; akey++) {
741 rec = passet[akey];
742 while (rec != NULL) {
743 /* Checks if something has been updated in the asset since last time */
744 if (tstamp - rec->last_seen <= CHECK_TIMEOUT) {
745 tmp_sa = rec->services;
746 tmp_oa = rec->os;
747 if (config.print_updates) log_asset_arp(rec);
749 while (tmp_sa != NULL) {
750 /* Just print out the asset if it is updated since lasttime */
751 if (config.print_updates && tstamp - tmp_sa->last_seen <= CHECK_TIMEOUT) {
752 log_asset_service(rec,tmp_sa);
754 /* If the asset is getting too old - delete it */
755 if (config.print_updates && tstamp - tmp_sa->last_seen >= ASSET_TIMEOUT) {
756 serv_asset *stmp = tmp_sa;
757 tmp_sa = tmp_sa->next;
758 del_serv_asset(&rec->services, stmp);
759 } else {
760 tmp_sa = tmp_sa->next;
764 while (tmp_oa != NULL) {
765 /* Just print out the asset if it is updated since lasttime */
766 if (config.print_updates && tstamp - tmp_oa->last_seen <= CHECK_TIMEOUT) {
767 log_asset_os(rec, tmp_oa);
769 /* If the asset is getting too old - delete it */
770 if (tstamp - tmp_oa->last_seen >= ASSET_TIMEOUT) {
771 os_asset *otmp = tmp_oa;
772 tmp_oa = tmp_oa->next;
773 del_os_asset(&rec->os, otmp);
774 } else {
775 tmp_oa = tmp_oa->next;
780 /* If nothing in the asset has been updated for some time - delete it! */
781 if (tstamp - rec->last_seen >= ASSET_TIMEOUT) {
782 asset *tmp = rec;
783 rec = rec->next;
784 del_asset(tmp, &passet[akey]);
785 } else {
786 rec = rec->next;