inline uint32_t make_hash(packetinfo *pi) { if (pi->ip4 != NULL) { return (PI_IP4SRC(pi) + PI_IP4DST(pi)) % BUCKET_SIZE; } else { return (PI_IP6SRC(pi).s6_addr32[0] + PI_IP6SRC(pi).s6_addr32[1] + PI_IP6SRC(pi).s6_addr32[2] + PI_IP6SRC(pi).s6_addr32[3] + PI_IP6DST(pi).s6_addr32[0] + PI_IP6DST(pi).s6_addr32[1] + PI_IP6DST(pi).s6_addr32[2] + PI_IP6DST(pi).s6_addr32[3] ) % BUCKET_SIZE; } }
/* freshly smelling connection :d */ connection *cxt_new(packetinfo *pi) { struct in6_addr ips; struct in6_addr ipd; connection *cxt; config.cxtrackerid++; cxt = (connection *) calloc(1, sizeof(connection)); //assert(cxt); cxt->cxid = config.cxtrackerid; cxt->af = pi->af; if(pi->tcph) cxt->s_tcpFlags |= pi->tcph->t_flags; cxt->start_time = pi->pheader->ts.tv_sec; cxt->last_pkt_time = pi->pheader->ts.tv_sec; if(pi-> af== AF_INET6){ cxt->s_ip = PI_IP6SRC(pi); cxt->d_ip = PI_IP6DST(pi); }else { ips.s6_addr32[0] = pi->ip4->ip_src; ipd.s6_addr32[0] = pi->ip4->ip_dst; cxt->s_ip = ips; cxt->d_ip = ipd; } cxt->s_port = pi->s_port; cxt->d_port = pi->d_port; cxt->proto = pi->proto; cxt->check = 0x00; cxt->reversed = 0; config.curcxt++; return cxt; }
void cxt_new (connection *cxt, packetinfo *pi) { //extern u_int64_t cxtrackerid; config.nftrackerid += 1; cxt->cxid = config.nftrackerid; cxt->af = pi->af; cxt->s_tcpFlags |= (pi->tcph ? pi->tcph->t_flags : 0x00); cxt->s_total_bytes = pi->packet_bytes; cxt->s_total_pkts = 1; cxt->start_time = pi->pheader->ts.tv_sec; cxt->last_pkt_time = pi->pheader->ts.tv_sec; if(pi->af == AF_INET){ cxt->s_ip.s6_addr32[0] = PI_IP4SRC(pi); cxt->d_ip.s6_addr32[0] = PI_IP4DST(pi); }else{ cxt->s_ip = PI_IP6SRC(pi); cxt->d_ip = PI_IP6DST(pi); } cxt->s_port = pi->s_port; cxt->d_port = pi->d_port; cxt->proto = (pi->ip4 ? pi->ip4->ip_p : pi->ip6->next); cxt->check = 0x00; //cxt->c_asset = NULL; //cxt->s_asset = NULL; cxt->files = NULL; cxt->reversed = 0; pi->sc = SC_CLIENT; }
/* asset *asset_lookup(struct in6_addr ip, int af) * tries to match your packet to a sender we've seen before * * 1. already in connection database * 2. ip4 lookup & ip6 lookup * 3. mac lookup * * asset_lookup should return 0 on success, 1 on failure */ uint8_t asset_lookup(packetinfo *pi) { uint64_t hash; asset *masset = NULL; if (pi->asset != NULL || NULL != (pi->asset = connection_lookup(pi))){ return SUCCESS; } else { if (pi->af == AF_INET) { uint32_t ip; if(pi->arph) {// arp check //memcpy(&ip, pi->arph->arp_spa, sizeof(uint8_t)*4); ip = *(uint32_t*) pi->arph->arp_spa; } else { ip = PI_IP4SRC(pi); } hash = ASSET_HASH4(ip); masset = passet[hash]; while (masset != NULL) { //if (memcmp(&ip_addr,&rec->ip_addr,16)) { if (masset->af == AF_INET && CMP_ADDR4( &masset->ip_addr, ip)) { pi->asset = masset; return SUCCESS; } masset = masset->next; } return ERROR; } else if (pi->af == AF_INET6) { hash = ASSET_HASH6(PI_IP6SRC(pi)); masset = passet[hash]; while (masset != NULL) { if (masset->af == AF_INET6 && CMP_ADDR6(&masset->ip_addr, &PI_IP6SRC(pi))){ pi->asset = masset; return SUCCESS; } masset = masset->next; } return ERROR; } return ERROR; } }
/* ---------------------------------------------------------- * FUNCTION : add_asset * DESCRIPTION : This function will add an asset to the * : specified asset data structure. * INPUT : 0 - packetinfo (af, ip_src, vlan) * RETURN : None! * ---------------------------------------------------------- */ void add_asset(packetinfo *pi) { uint64_t hash; asset *masset = NULL; config.pr_s.assets++; masset = (asset *) calloc(1, sizeof(asset)); masset->af = pi->af; masset->vlan = pi->vlan; masset->i_attempts = 0; masset->first_seen = masset->last_seen = pi->pheader->ts.tv_sec; if (pi->af == AF_INET) { if(pi->arph) // mongo arp check //memcpy(&masset->ip_addr.__u6_addr.__u6_addr32[0], pi->arph->arp_spa, sizeof(uint32_t)); IP4ADDR(&masset->ip_addr) = *(uint32_t*) pi->arph->arp_spa; else IP4ADDR(&masset->ip_addr) = PI_IP4SRC(pi); hash = ASSET_HASH4(IP4ADDR(&masset->ip_addr)); } else if (pi->af == AF_INET6) { masset->ip_addr = PI_IP6SRC(pi); hash = ASSET_HASH6(PI_IP6SRC(pi)); } masset->next = passet[hash]; if (passet[hash] != NULL) passet[hash]->prev = masset; masset->prev = NULL; masset->os = NULL; masset->services = NULL; masset->macentry = NULL; passet[hash] = masset; #ifdef DEBUGG /* verbose info for sanity checking */ static char ip_addr_s[INET6_ADDRSTRLEN]; // pi->ip_src does not exist! u_ntop(pi->ip_src, pi->af, ip_addr_s); dlog("[*] asset added: %s\n",ip_addr_s); #endif //return masset; }
/* freshly smelling connection :d */ connection *cxt_new(packetinfo *pi) { struct in6_addr ips; struct in6_addr ipd; connection *cxt; cxtrackerid++; cxt = (connection *) calloc(1, sizeof(connection)); assert(cxt); cxt->cxid = cxtrackerid; cxt->af = pi->af; if(pi->tcph) cxt->s_tcpFlags |= pi->tcph->t_flags; //cxt->s_tcpFlags |= (pi->tcph ? pi->tcph->t_flags : 0x00);//why?? //cxt->d_tcpFlags = 0x00; cxt->s_total_bytes = pi->packet_bytes; cxt->s_total_pkts = 1; cxt->start_time = pi->pheader->ts.tv_sec; cxt->last_pkt_time = pi->pheader->ts.tv_sec; if(pi-> af== AF_INET6){ cxt->s_ip = PI_IP6SRC(pi); cxt->d_ip = PI_IP6DST(pi); }else { // ugly hack :( // the way we do ip4/6 is DIRTY ips.s6_addr32[0] = pi->ip4->ip_src; ipd.s6_addr32[0] = pi->ip4->ip_dst; cxt->s_ip = ips; cxt->d_ip = ipd; } cxt->s_port = pi->s_port; cxt->d_port = pi->d_port; cxt->proto = pi->proto; cxt->check = 0x00; cxt->c_asset = NULL; cxt->s_asset = NULL; cxt->reversed = 0; return cxt; }
int connection_tracking(packetinfo *pi) { struct in6_addr *ip_src; struct in6_addr *ip_dst; struct in6_addr ips; struct in6_addr ipd; uint16_t src_port = pi->s_port; uint16_t dst_port = pi->d_port; int af = pi->af; connection *cxt = NULL; connection *head = NULL; uint32_t hash; if(af == AF_INET6){ ip_src = &PI_IP6SRC(pi); ip_dst = &PI_IP6DST(pi); } else { ips.s6_addr32[0] = pi->ip4->ip_src; ipd.s6_addr32[0] = pi->ip4->ip_dst; ip_src = &ips; ip_dst = &ipd; } /* Find the right connection bucket */ if (af == AF_INET) { hash = CXT_HASH4(IP4ADDR(ip_src), IP4ADDR(ip_dst), src_port, dst_port, pi->proto); } else if (af == AF_INET6) { hash = CXT_HASH6(ip_src, ip_dst, src_port, dst_port, pi->proto); } else { dlog("[D] Only CTX with AF_INET and AF_INET6 are supported: %d\n", af); return 0; } cxt = bucket[hash]; head = cxt; /* Search through the bucket */ while (cxt != NULL) { /* Two-way compare of given connection against connection table */ if (af == AF_INET) { if (CMP_CXT4(cxt, IP4ADDR(ip_src), src_port, IP4ADDR(ip_dst), dst_port)) { /* Client sends first packet (TCP/SYN - UDP?) hence this is a client */ dlog("[D] Found existing v4 client connection.\n"); return cxt_update_client(cxt, pi); } else if (CMP_CXT4(cxt, IP4ADDR(ip_dst), dst_port, IP4ADDR(ip_src), src_port)) { if (pi->sc == SC_SERVER) { /* This is a server */ dlog("[D] Found existing v4 server connection.\n"); return cxt_update_server(cxt, pi); } else { /* This is a client, where we saw a mid-stream DNS response first */ dlog("[D] Found existing unknown v4 server connection.\n"); return cxt_update_client(cxt, pi); } } } else if (af == AF_INET6) { if (CMP_CXT6(cxt, ip_src, src_port, ip_dst, dst_port)) { dlog("[D] Found existing v6 client connection.\n"); return cxt_update_client(cxt, pi); } else if (CMP_CXT6(cxt, ip_dst, dst_port, ip_src, src_port)) { dlog("[D] Found existing v6 client connection.\n"); return cxt_update_server(cxt, pi); } } cxt = cxt->next; } /* Bucket turned upside down didn't yield anything. New connection */ dlog("[D] New connection.\n"); cxt = cxt_new(pi); /* New connections are pushed on to the head of bucket[s_hash] */ cxt->next = head; if (head != NULL) { /* Are we double linked? */ head->prev = cxt; } bucket[hash] = cxt; pi->cxt = cxt; return cxt_update_unknown(cxt, pi); }
int connection_tracking(packetinfo *pi) { struct in6_addr *ip_src; struct in6_addr *ip_dst; struct in6_addr ips; struct in6_addr ipd; uint16_t src_port = pi->s_port; uint16_t dst_port = pi->d_port; int af = pi->af; connection *cxt = NULL; connection *head = NULL; uint32_t hash; if(af== AF_INET6){ ip_src = &PI_IP6SRC(pi); ip_dst = &PI_IP6DST(pi); }else { ips.s6_addr32[0] = pi->ip4->ip_src; ipd.s6_addr32[0] = pi->ip4->ip_dst; ip_src = &ips; ip_dst = &ipd; } // find the right connection bucket if (af == AF_INET) { hash = CXT_HASH4(IP4ADDR(ip_src),IP4ADDR(ip_dst),src_port,dst_port,pi->proto); } else if (af == AF_INET6) { hash = CXT_HASH6(ip_src,ip_dst,src_port,dst_port,pi->proto); } cxt = bucket[hash]; head = cxt; // search through the bucket while (cxt != NULL) { // Two-way compare of given connection against connection table if (af == AF_INET) { if (CMP_CXT4(cxt,IP4ADDR(ip_src),src_port,IP4ADDR(ip_dst),dst_port)){ // Client sends first packet (TCP/SYN - UDP?) hence this is a client return cxt_update_client(cxt, pi); } else if (CMP_CXT4(cxt,IP4ADDR(ip_dst),dst_port,IP4ADDR(ip_src),src_port)) { // This is a server (Maybe not when we start up but in the long run) return cxt_update_server(cxt, pi); } } else if (af == AF_INET6) { if (CMP_CXT6(cxt,ip_src,src_port,ip_dst,dst_port)){ return cxt_update_client(cxt, pi); } else if (CMP_CXT6(cxt,ip_dst,dst_port,ip_src,src_port)){ return cxt_update_server(cxt, pi); } } cxt = cxt->next; } // bucket turned upside down didn't yeild anything. new connection cxt = cxt_new(pi); /* New connections are pushed on to the head of bucket[s_hash] */ cxt->next = head; if (head != NULL) { // are we doubly linked? head->prev = cxt; } bucket[hash] = cxt; pi->cxt = cxt; return cxt_update_client(cxt, pi); }
/* does this ip belong to our network? do we care about the packet? * * unfortunately pcap sends us packets in host order * Return value: boolean */ inline int filter_packet(const int af, void *ipptr) //const struct in6_addr *ip_s) { ip6v ip_vec; ip6v t; int i, our = 0; char output[MAX_NETS]; switch (af) { case AF_INET: { uint32_t *ip = (uint32_t *) ipptr; for (i = 0; i < MAX_NETS && i < config.nets; i++) { if (config.network[i].type != AF_INET) continue; #if DEBUG == 2 inet_ntop(af, &config.network[i].addr.s6_addr32[0], output, MAX_NETS); vlog(0x2, "Filter: %s\n", output); inet_ntop(af, &config.network[i].mask.s6_addr32[0], output, MAX_NETS); vlog(0x2, "mask: %s\n", output); inet_ntop(af, ip, output, MAX_NETS); vlog(0x2, "ip: %s\n", output); #endif if((*ip & config.network[i].mask.s6_addr32[0]) == config.network[i].addr.s6_addr32[0]) { our = 1; break; } } } break; case AF_INET6: { /* 32-bit comparison of ipv6 nets. * can do better here by using 64-bit or SIMD instructions * * * PS: use same code for ipv4 - 0 bytes and SIMD doesnt care*/ ip_vec.ip6 = *((struct in6_addr *)ipptr); for (i = 0; i < MAX_NETS && i < config.nets; i++) { if(config.network[i].type != AF_INET6) continue; #if DEBUG == 2 inet_ntop(af, &config.network[i].addr, output, MAX_NETS); dlog("net: %s\n", output); inet_ntop(af, &config.network[i].mask, output, MAX_NETS); dlog("mask: %s\n", output); inet_ntop(af, &PI_IP6SRC(pi), output, MAX_NETS); dlog("ip: %s\n", output); #endif if (config.network[i].type == AF_INET6) { #if(1) /* apologies for the uglyness */ #ifdef HAVE_SSE2 #define compare128(x,y) __builtin_ia32_pcmpeqd128((x), (y)) // the builtin is only available on sse2! t.v = __builtin_ia32_pcmpeqd128( ip_vec.v & config.network[i].mask_v, config.network[i].addr_v); if (t.i[0] & t.i[1]) #else #define compare128(x,y) memcmp(&(x),&(y),16) t.v = ip_vec.v & config.network[i].mask_v; // xor(a,b) == 0 iff a==b if (!( (t.i[0] ^ config.network[i].addr64[0]) & (t.i[1] ^ config.network[i].addr64[1]) )) #endif { our = 1; break; } #else if ((ip_s.s6_addr32[0] & config.network[i]->mask.s6_addr32[0]) == config.network[i]->addr.s6_addr32[0] && (ip_s.s6_addr32[1] & config.network[i]->mask.s6_addr32[1]) == config.network[i]->addr.s6_addr32[1] && (ip_s.s6_addr32[2] & config.network[i]->mask.s6_addr32[2]) == config.network[i]->addr.s6_addr32[2] && (ip_s.s6_addr32[3] & config.network[i]->mask.s6_addr32[3]) == config.network[i]->addr.s6_addr32[3]) { our = 1; break; } #endif } } } break; default: fprintf(stderr, "non-ip packets of type %d aren't filtered by netmask yet\n", af); our = 1; } #ifdef DEBUG if (af == AF_INET6){ inet_ntop(af, (struct in6addr*) ipptr, output, MAX_NETS); }else{ inet_ntop(af, (uint32_t*)ipptr, output, MAX_NETS); } if (our){ vlog(0x2, "Address %s is in our network.\n", output); } else { vlog(0x2, "Address %s is not our network.\n", output); } #endif return our; }
int cx_track(packetinfo *pi) { struct in6_addr *ip_src; struct in6_addr *ip_dst; struct in6_addr ips; struct in6_addr ipd; uint16_t src_port = pi->s_port; uint16_t dst_port = pi->d_port; int af = pi->af; connection *cxt = NULL; connection *head = NULL; uint32_t hash; if(af== AF_INET6){ ip_src = &PI_IP6SRC(pi); ip_dst = &PI_IP6DST(pi); }else { // ugly hack :( // the way we do ip4/6 is DIRTY // FIX IT?!!? ips.s6_addr32[0] = pi->ip4->ip_src; ipd.s6_addr32[0] = pi->ip4->ip_dst; ip_src = &ips; ip_dst = &ipd; } // find the right connection bucket if (af == AF_INET) { hash = CXT_HASH4(IP4ADDR(ip_src),IP4ADDR(ip_dst)); } else if (af == AF_INET6) { hash = CXT_HASH6(ip_src,ip_dst); } cxt = bucket[hash]; head = cxt; // search through the bucket while (cxt != NULL) { // Two-way compare of given connection against connection table if (af == AF_INET) { if (CMP_CXT4(cxt,IP4ADDR(ip_src),src_port,IP4ADDR(ip_dst),dst_port)){ // Client sends first packet (TCP/SYN - UDP?) hence this is a client return cxt_update_client(cxt, pi); } else if (CMP_CXT4(cxt,IP4ADDR(ip_dst),dst_port,IP4ADDR(ip_src),src_port)) { // This is a server (Maybe not when we start up but in the long run) return cxt_update_server(cxt, pi); } } else if (af == AF_INET6) { if (CMP_CXT6(cxt,ip_src,src_port,ip_dst,dst_port)){ return cxt_update_client(cxt, pi); } else if (CMP_CXT6(cxt,ip_dst,dst_port,ip_src,src_port)){ return cxt_update_server(cxt, pi); } } cxt = cxt->next; } // bucket turned upside down didn't yeild anything. new connection cxt = cxt_new(pi); if(config.cflags & CONFIG_CXWRITE) log_connection(cxt, stdout, CX_NEW); /* * New connections are pushed on to the head of bucket[s_hash] */ cxt->next = head; if (head != NULL) { // are we doubly linked? head->prev = cxt; } bucket[hash] = cxt; pi->cxt = cxt; /* * Return value should be 1, telling to do client service fingerprinting */ return 1; }
inline void cxt_update (packetinfo *pi, uint32_t hash) { connection *cxt = NULL; int ret = 0; /* get our hash bucket and lock it */ cxtbucket *cb = &cxt_hash[hash]; /* see if the bucket already has a connection */ if (cb->cxt == NULL) { /* no, so get a new one */ cxt = cb->cxt = cxt_dequeue(&cxt_spare_q); if (cxt == NULL) { cxt = cb->cxt = connection_alloc(); if (cxt == NULL) { return; } } /* these are protected by the bucket lock */ cxt->hnext = NULL; cxt->hprev = NULL; /* got one, initialize and return */ cxt_new(cxt,pi); cxt_requeue(cxt, NULL, &cxt_est_q); cxt->cb = cb; cxt_update_src(cxt, pi); pi->cxt = cxt; return; } /* ok, we have a flow in the bucket. Let's find out if it is our flow */ cxt = cb->cxt; /* see if this is the flow we are looking for */ if (pi->af == AF_INET) { if (CMP_CXT4(cxt, PI_IP4SRC(pi), pi->s_port, PI_IP4DST(pi), pi->d_port)) { cxt_update_src(cxt, pi); ret = 1; } else if (CMP_CXT4(cxt, PI_IP4DST(pi), pi->d_port, PI_IP4SRC(pi), pi->s_port)) { cxt_update_dst(cxt, pi); ret = 1; } } else if (pi->af == AF_INET6){ if (CMP_CXT6(cxt, &PI_IP6SRC(pi), pi->s_port, &PI_IP6DST(pi), pi->d_port)) { cxt_update_src(cxt, pi); ret = 1; } else if (CMP_CXT6(cxt, &PI_IP6DST(pi), pi->d_port, &PI_IP6SRC(pi), pi->s_port)) { cxt_update_dst(cxt, pi); ret = 1; } } if (ret == 0) { connection *pcxt = NULL; /* previous connection */ while (cxt != NULL) { pcxt = cxt; /* pf is not locked at this point */ cxt = cxt->hnext; if (cxt == NULL) { /* get us a new one and put it and the list tail */ cxt = pcxt->hnext = cxt_dequeue(&cxt_spare_q); if (cxt == NULL) { cxt = cb->cxt = connection_alloc(); if (cxt == NULL) { return; } } cxt->hnext = NULL; cxt->hprev = pcxt; /* initialize and return */ cxt_new(cxt,pi); cxt_requeue(cxt, NULL, &cxt_est_q); cxt->cb = cb; cxt_update_src(cxt, pi); pi->cxt = cxt; return; } if (pi->af == AF_INET) { if (CMP_CXT4(cxt, PI_IP4SRC(pi), pi->s_port, PI_IP4DST(pi), pi->d_port)) { cxt_update_src(cxt, pi); ret = 1; } else if (CMP_CXT4(cxt, PI_IP4DST(pi), pi->d_port, PI_IP4SRC(pi), pi->s_port)) { cxt_update_dst(cxt, pi); ret = 1; } } else if (pi->af == AF_INET6) { if (CMP_CXT6(cxt, &PI_IP6SRC(pi), pi->s_port, &PI_IP6DST(pi), pi->d_port)) { cxt_update_src(cxt, pi); ret = 1; } else if (CMP_CXT6(cxt, &PI_IP6DST(pi), pi->d_port, &PI_IP6SRC(pi), pi->s_port)) { cxt_update_dst(cxt, pi); ret = 1; } } if ( ret != 0) { /* we found our flow, lets put it on top of the * hash list -- this rewards active flows */ if (cxt->hnext) cxt->hnext->hprev = cxt->hprev; if (cxt->hprev) cxt->hprev->hnext = cxt->hnext; cxt->hnext = cb->cxt; cxt->hprev = NULL; cb->cxt->hprev = cxt; cb->cxt = cxt; /* found our connection */ pi->cxt = cxt; return; } /* not found, try the next... */ } } pi->cxt = cxt; /* The 'root' connection was our connection, return it. */ return; }