Exemple #1
0
void fs_add_ip_fields(fieldset_t *fs, struct iphdr *ip)
{
	fs_add_string(fs, "saddr", make_ip_str(ip->saddr), 1);
	fs_add_string(fs, "daddr", make_ip_str(ip->daddr), 1);
	fs_add_uint64(fs, "ipid", ntohl(ip->id));
	fs_add_uint64(fs, "ttl", ntohl(ip->ttl));
}
Exemple #2
0
void fs_add_ip_fields(fieldset_t *fs, struct ip *ip)
{
	// WARNING: you must update fs_ip_fields_len  as well
	// as the definitions set (ip_fiels) if you
	// change the fields added below:
	fs_add_string(fs, "saddr", make_ip_str(ip->ip_src.s_addr), 1);
	fs_add_uint64(fs, "saddr_raw", (uint64_t) ip->ip_src.s_addr);
	fs_add_string(fs, "daddr", make_ip_str(ip->ip_dst.s_addr), 1);
	fs_add_uint64(fs, "daddr_raw", (uint64_t) ip->ip_dst.s_addr);
	fs_add_uint64(fs, "ipid", ntohs(ip->ip_id));
	fs_add_uint64(fs, "ttl", ip->ip_ttl);
}
Exemple #3
0
static bool process_response_question(char **data, uint16_t* data_len, 
		const char* payload, uint16_t payload_len, fieldset_t* list)
{	
	// Payload is the start of the DNS packet, including header
	// data is handle to the start of this RR
	// data_len is a pointer to the how much total data we have to work with.
	// This is awful. I'm bad and should feel bad.
	uint16_t bytes_consumed = 0;

	char* question_name = get_name(*data, *data_len, payload, payload_len,
			&bytes_consumed);

	// Error.
	if (question_name == NULL) {
		return 1;
	}

	assert(bytes_consumed > 0);

	if ( (bytes_consumed + sizeof(dns_question_tail)) > *data_len) {
		free(question_name);
		return 1;
	}

	dns_question_tail* tail = (dns_question_tail*)(*data + bytes_consumed);

	uint16_t qtype = ntohs(tail->qtype);
	uint16_t qclass = ntohs(tail->qclass);
	
	// Build our new question fieldset
	fieldset_t *qfs = fs_new_fieldset(); 
	fs_add_unsafe_string(qfs, "name", question_name, 1);
	fs_add_uint64(qfs, "qtype", qtype);
	if (qtype > MAX_QTYPE || qtype_qtype_to_strid[qtype] == BAD_QTYPE_VAL) {
		fs_add_string(qfs, "qtype_str", (char*) BAD_QTYPE_STR, 0);
	} else {
		// I've written worse things than this 3rd arg. But I want to be fast.
		fs_add_string(qfs, "qtype_str", 
				(char*)qtype_strs[qtype_qtype_to_strid[qtype]], 0);
	}
	fs_add_uint64(qfs, "qclass", qclass);

	// Now we're adding the new fs to the list.
	fs_add_fieldset(list, NULL, qfs);

	// Now update the pointers.
	*data = *data + bytes_consumed + sizeof(dns_question_tail);
	*data_len = *data_len - bytes_consumed - sizeof(dns_question_tail);

	return 0;
}
Exemple #4
0
void fs_add_system_fields(fieldset_t *fs, int is_repeat, int in_cooldown)
{
	fs_add_uint64(fs, "repeat", is_repeat);
	fs_add_uint64(fs, "cooldown", in_cooldown);

	char *timestr = xmalloc(TIMESTR_LEN+1);
	char *timestr_ms = xmalloc(TIMESTR_LEN+1);
	struct timeval t;
	gettimeofday(&t, NULL);
	struct tm *ptm = localtime(&t.tv_sec);
	strftime(timestr, TIMESTR_LEN, "%Y-%m-%dT%H:%M:%S.%%03d%z", ptm);
	snprintf(timestr_ms, TIMESTR_LEN, timestr, t.tv_usec/1000);
	free(timestr);
	fs_add_string(fs, "timestamp_str", timestr_ms, 1);
	fs_add_uint64(fs, "timestamp_ts", (uint64_t) t.tv_sec);
	fs_add_uint64(fs, "timestamp_us", (uint64_t) t.tv_usec);
}
Exemple #5
0
void fs_add_system_fields(fieldset_t *fs, int is_repeat, int in_cooldown)
{
	fs_add_uint64(fs, "repeat", is_repeat);
	fs_add_uint64(fs, "cooldown", in_cooldown);

	char *timestr = malloc(TIMESTR_LEN+1);
	if (!timestr) {
		log_fatal("recv", "unable to allocate memory for "
				  "timestamp string in fieldset.");
	}
	struct timeval t;
	gettimeofday(&t, NULL);
	struct tm *ptm = localtime(&t.tv_sec);
	strftime(timestr, TIMESTR_LEN, "%Y-%m-%dT%H:%M:%S%z", ptm);
	fs_add_string(fs, "timestamp-str", timestr, 1);
	fs_add_uint64(fs, "timestamp-ts", (uint64_t) t.tv_sec);
	fs_add_uint64(fs, "timestamp-us", (uint64_t) t.tv_usec);
}
Exemple #6
0
void dns_process_packet(const u_char *packet, uint32_t len, fieldset_t *fs,
		uint32_t *validation) 
{	
	struct ip *ip_hdr = (struct ip *) &packet[sizeof(struct ether_header)];
	if (ip_hdr->ip_p == IPPROTO_UDP) {
		struct udphdr *udp_hdr = (struct udphdr *) ((char *) ip_hdr + 
				ip_hdr->ip_hl * 4);
		uint16_t udp_len = ntohs(udp_hdr->uh_ulen);
		assert(udp_len >= dns_packet_len); 
		char* qname_p = NULL;
		dns_question_tail* tail_p = NULL;
		bool is_valid = 0;
		dns_header* dns_header_p = (dns_header*) &udp_hdr[1];
		// verify our dns transaction id
		if (dns_header_p->id == (validation[2] & 0xFFFF)) {
			// Verify our question
			qname_p = (char*) dns_header_p + sizeof(dns_header);
			tail_p = (dns_question_tail*)(dns_packet + sizeof(dns_header) + 
					qname_len);
			// Verify our qname
			if (strcmp(qname, qname_p) == 0) {
				// Verify the qtype and qclass.
				if (tail_p->qtype == htons(qtype) && tail_p->qclass \
						== htons(0x01)) {
					is_valid = 1;
				}
			}
		}
		dns_header* dns_hdr = (dns_header*) &udp_hdr[1];
		uint16_t qr = dns_hdr->qr;
		uint16_t rcode = dns_hdr->rcode;
		// Success: Has the right validation bits and the right Q
		// App success: has qr and rcode bits right
		// Any app level parsing issues: dns_parse_err

		// High level info
		fs_add_string(fs, "classification", (char*) "dns", 0);
		fs_add_uint64(fs, "success", is_valid);
		fs_add_uint64(fs, "app_success", 
				is_valid && (qr == DNS_QR_ANSWER) && (rcode == DNS_RCODE_NOERR));
		// UDP info
		fs_add_uint64(fs, "sport", ntohs(udp_hdr->uh_sport));
		fs_add_uint64(fs, "dport", ntohs(udp_hdr->uh_dport));
		fs_add_uint64(fs, "udp_len", udp_len);
		// ICMP info
		fs_add_null(fs, "icmp_responder");
		fs_add_null(fs, "icmp_type");
		fs_add_null(fs, "icmp_code");
		fs_add_null(fs, "icmp_unreach_str");
	        // DNS data	
		if (!is_valid) {
			// DNS header
			fs_add_null(fs, "dns_id"); 
			fs_add_null(fs, "dns_rd"); 
			fs_add_null(fs, "dns_tc"); 
			fs_add_null(fs, "dns_aa"); 
			fs_add_null(fs, "dns_opcode"); 
			fs_add_null(fs, "dns_qr"); 
			fs_add_null(fs, "dns_rcode"); 
			fs_add_null(fs, "dns_cd"); 
			fs_add_null(fs, "dns_ad"); 
			fs_add_null(fs, "dns_z"); 
			fs_add_null(fs, "dns_ra"); 
			fs_add_null(fs, "dns_qdcount"); 
			fs_add_null(fs, "dns_ancount"); 
			fs_add_null(fs, "dns_nscount"); 
			fs_add_null(fs, "dns_arcount"); 

			fs_add_repeated(fs, "dns_questions", fs_new_repeated_fieldset());
			fs_add_repeated(fs, "dns_answers", fs_new_repeated_fieldset());
			fs_add_repeated(fs, "dns_authorities", fs_new_repeated_fieldset());
			fs_add_repeated(fs, "dns_additionals", fs_new_repeated_fieldset());

			fs_add_uint64(fs, "dns_unconsumed_bytes", 0); 
			fs_add_uint64(fs, "dns_parse_err", 1); 
		} else {
			// DNS header
			fs_add_uint64(fs, "dns_id", ntohs(dns_hdr->id)); 
			fs_add_uint64(fs, "dns_rd", dns_hdr->rd); 
			fs_add_uint64(fs, "dns_tc", dns_hdr->tc); 
			fs_add_uint64(fs, "dns_aa", dns_hdr->aa); 
			fs_add_uint64(fs, "dns_opcode", dns_hdr->opcode); 
			fs_add_uint64(fs, "dns_qr", qr); 
			fs_add_uint64(fs, "dns_rcode", rcode); 
			fs_add_uint64(fs, "dns_cd", dns_hdr->cd); 
			fs_add_uint64(fs, "dns_ad", dns_hdr->ad); 
			fs_add_uint64(fs, "dns_z", dns_hdr->z); 
			fs_add_uint64(fs, "dns_ra", dns_hdr->ra); 
			fs_add_uint64(fs, "dns_qdcount", ntohs(dns_hdr->qdcount)); 
			fs_add_uint64(fs, "dns_ancount", ntohs(dns_hdr->ancount)); 
			fs_add_uint64(fs, "dns_nscount", ntohs(dns_hdr->nscount)); 
			fs_add_uint64(fs, "dns_arcount", ntohs(dns_hdr->arcount)); 
			// And now for the complicated part. Hierarchical data. 
			char* data = ((char*)dns_hdr) + sizeof(dns_header);
			uint16_t data_len = udp_len - sizeof(udp_hdr) - sizeof(dns_header);
			bool err = 0;
			// Questions
			fieldset_t *list = fs_new_repeated_fieldset();
			for (int i = 0; i < ntohs(dns_hdr->qdcount) && !err; i++) {
				err = process_response_question(&data, &data_len, (char*)dns_hdr, 
							udp_len, list);    
			}
			fs_add_repeated(fs, "dns_questions", list);
			// Answers
			list = fs_new_repeated_fieldset();
			for (int i = 0; i < ntohs(dns_hdr->ancount) && !err; i++) {
				err = process_response_answer(&data, &data_len, (char*)dns_hdr,
						 udp_len, list); 
			}
			fs_add_repeated(fs, "dns_answers", list);
			// Authorities
			list = fs_new_repeated_fieldset();
			for (int i = 0; i < ntohs(dns_hdr->nscount) && !err; i++) {
				err = process_response_answer(&data, &data_len, (char*)dns_hdr, 
						udp_len, list);  
			}
			fs_add_repeated(fs, "dns_authorities", list);

			// Additionals
			list = fs_new_repeated_fieldset();
			for (int i = 0; i < ntohs(dns_hdr->arcount) && !err; i++) {
				err = process_response_answer(&data, &data_len, (char*)dns_hdr, 
						udp_len, list);
			}
			fs_add_repeated(fs, "dns_additionals", list);
			// Do we have unconsumed data?
			fs_add_uint64(fs, "dns_unconsumed_bytes", data_len); 
			if (data_len != 0) {
				err = 1;
			}
			// Did we parse OK?
			fs_add_uint64(fs, "dns_parse_err", err); 
		}
		// Now the raw stuff.
		fs_add_binary(fs, "raw_data", (udp_len - sizeof(struct udphdr)),
				(void*) &udp_hdr[1], 0);
		return;
	} else if (ip_hdr->ip_p == IPPROTO_ICMP) {
		struct icmp *icmp = (struct icmp*) ((char *) ip_hdr + 4*ip_hdr->ip_hl);
		struct ip *ip_inner = (struct ip*) ((char *) icmp + 
				ICMP_UNREACH_HEADER_SIZE);
		
		// This is the packet we sent
		struct udphdr *udp_hdr = (struct udphdr *) ((char*) ip_inner + 
				4*ip_inner->ip_hl);
		
		uint16_t udp_len = ntohs(udp_hdr->uh_ulen);
		// High level info	  
		fs_add_string(fs, "classification", (char*) "icmp-unreach", 0);
		fs_add_uint64(fs, "success", 0);
		fs_add_uint64(fs, "app_success", 0);
		// UDP info
		fs_add_uint64(fs, "sport", ntohs(udp_hdr->uh_sport));
		fs_add_uint64(fs, "dport", ntohs(udp_hdr->uh_dport));
		fs_add_uint64(fs, "udp_len", udp_len);
		// ICMP info
		// XXX This is legacy. not well tested.
		fs_add_string(fs, "icmp_responder", make_ip_str(ip_hdr->ip_src.s_addr), 1);
		fs_add_uint64(fs, "icmp_type", icmp->icmp_type);
		fs_add_uint64(fs, "icmp_code", icmp->icmp_code);
		if (icmp->icmp_code <= ICMP_UNREACH_PRECEDENCE_CUTOFF) {
			fs_add_string(fs, "icmp_unreach_str",
				(char *) udp_unreach_strings[icmp->icmp_code], 0);
		} else {
			fs_add_string(fs, "icmp_unreach_str", (char *) "unknown", 0);
		}
		// DNS header
		fs_add_null(fs, "dns_id"); 
		fs_add_null(fs, "dns_rd"); 
		fs_add_null(fs, "dns_tc"); 
		fs_add_null(fs, "dns_aa"); 
		fs_add_null(fs, "dns_opcode"); 
		fs_add_null(fs, "dns_qr"); 
		fs_add_null(fs, "dns_rcode"); 
		fs_add_null(fs, "dns_cd"); 
		fs_add_null(fs, "dns_ad"); 
		fs_add_null(fs, "dns_z"); 
		fs_add_null(fs, "dns_ra"); 
		fs_add_null(fs, "dns_qdcount"); 
		fs_add_null(fs, "dns_ancount"); 
		fs_add_null(fs, "dns_nscount"); 
		fs_add_null(fs, "dns_arcount"); 

		fs_add_repeated(fs, "dns_questions", fs_new_repeated_fieldset());
		fs_add_repeated(fs, "dns_answers", fs_new_repeated_fieldset());
		fs_add_repeated(fs, "dns_authorities", fs_new_repeated_fieldset());
		fs_add_repeated(fs, "dns_additionals", fs_new_repeated_fieldset());

		fs_add_uint64(fs, "dns_unconsumed_bytes", 0); 
		fs_add_uint64(fs, "dns_parse_err", 1); 
		fs_add_binary(fs, "raw_data", len, (char*)packet, 0);
		
		return;

	} else {
		// This should not happen. Both the pcap filter and validate
		// packet prevent this.
		log_fatal("dns", "Die. This can only happen if you "
				"change the pcap filter and don't update the "
				"process function.");
		return;
	}
}
Exemple #7
0
static bool process_response_answer(char **data, uint16_t* data_len, 
		const char* payload, uint16_t payload_len, fieldset_t* list)
{	
	log_trace("dns", "call to process_response_answer, data_len: %d", *data_len);
	// Payload is the start of the DNS packet, including header
	// data is handle to the start of this RR
	// data_len is a pointer to the how much total data we have to work with.
	// This is awful. I'm bad and should feel bad.
	uint16_t bytes_consumed = 0;

	char* answer_name = get_name(*data, *data_len, payload, payload_len,  
			&bytes_consumed);

	// Error.
	if (answer_name == NULL) {
		return 1;
	}

	assert(bytes_consumed > 0);

	if ( (bytes_consumed + sizeof(dns_answer_tail)) > *data_len) {
		free(answer_name);
		return 1;
	}

	dns_answer_tail* tail = (dns_answer_tail*)(*data + bytes_consumed);

	uint16_t type = ntohs(tail->type);
	uint16_t class = ntohs(tail->class);
	uint32_t ttl = ntohl(tail->ttl);
	uint16_t rdlength = ntohs(tail->rdlength);
	char* rdata = tail->rdata;

	if ((rdlength + bytes_consumed + sizeof(dns_answer_tail)) > *data_len) {
		free(answer_name);
		return 1;
	}

	// Build our new question fieldset
	fieldset_t *afs = fs_new_fieldset(); 
	fs_add_unsafe_string(afs, "name", answer_name, 1);
	fs_add_uint64(afs, "type", type);
	if (type > MAX_QTYPE || qtype_qtype_to_strid[type] == BAD_QTYPE_VAL) {
		fs_add_string(afs, "type_str", (char*) BAD_QTYPE_STR, 0);
	} else {
		// I've written worse things than this 3rd arg. But I want to be fast.
		fs_add_string(afs, "type_str", 
				(char*)qtype_strs[qtype_qtype_to_strid[type]], 0);
	}
	fs_add_uint64(afs, "class", class);
	fs_add_uint64(afs, "ttl", ttl);
	fs_add_uint64(afs, "rdlength", rdlength);
	
	// XXX Fill this out for the other types we care about.
	if (type == DNS_QTYPE_NS || type == DNS_QTYPE_CNAME) {

		uint16_t rdata_bytes_consumed = 0;
		char* rdata_name = get_name(rdata, rdlength, payload, payload_len,	
				&rdata_bytes_consumed);

		if (rdata_name == NULL) {
			fs_add_uint64(afs, "rdata_is_parsed", 0);
			fs_add_binary(afs, "rdata", rdlength, rdata, 0);
		} else {
			fs_add_uint64(afs, "rdata_is_parsed", 1);
			fs_add_unsafe_string(afs, "rdata", rdata_name, 1);
		}

	 } else if (type == DNS_QTYPE_MX) {

		uint16_t rdata_bytes_consumed = 0;

		if (rdlength <= 4) {
			fs_add_uint64(afs, "rdata_is_parsed", 0);
			fs_add_binary(afs, "rdata", rdlength, rdata, 0);
		} else {

			char* rdata_name = get_name(rdata + 2, rdlength-2, payload, 
					payload_len, &rdata_bytes_consumed);

			if (rdata_name == NULL) {
				fs_add_uint64(afs, "rdata_is_parsed", 0);
				fs_add_binary(afs, "rdata", rdlength, rdata, 0);
			} else {
		   
				// (largest value 16bit) + " " + answer + null 
				char* rdata_with_pref = xmalloc(5 + 1 + strlen(rdata_name) + 1);
				
				uint8_t num_printed = snprintf(rdata_with_pref, 6, "%hu ", 
						ntohs( *(uint16_t*)rdata));
				memcpy(rdata_with_pref + num_printed, rdata_name, 
						strlen(rdata_name));

				fs_add_uint64(afs, "rdata_is_parsed", 1);
				fs_add_unsafe_string(afs, "rdata", rdata_with_pref, 1);
			}
		}
	} else if (type == DNS_QTYPE_TXT) {

		if (rdlength >= 1 && (rdlength - 1) != *(uint8_t*)rdata ) {
			log_warn("dns", "TXT record with wrong TXT len. Not processing.");
			fs_add_uint64(afs, "rdata_is_parsed", 0);
			fs_add_binary(afs, "rdata", rdlength, rdata, 0);
		} else {
			fs_add_uint64(afs, "rdata_is_parsed", 1);
			char* txt = xmalloc(rdlength);
			memcpy(txt, rdata + 1, rdlength-1);
			fs_add_unsafe_string(afs, "rdata", txt, 1);
		}
	} else if (type == DNS_QTYPE_A) {

		if (rdlength != 4) {
			log_warn("dns", "A record with IP of length %d. Not processing.", 
					rdlength);
			fs_add_uint64(afs, "rdata_is_parsed", 0);
			fs_add_binary(afs, "rdata", rdlength, rdata, 0);
		} else {
			fs_add_uint64(afs, "rdata_is_parsed", 1);
			char* addr = strdup(inet_ntoa( *(struct in_addr*)rdata ));
			fs_add_unsafe_string(afs, "rdata", addr, 1);
		}
	} else if (type == DNS_QTYPE_AAAA) {

		if (rdlength != 16) {
			log_warn("dns", "AAAA record with IP of length %d. Not processing.",
					rdlength);
			fs_add_uint64(afs, "rdata_is_parsed", 0);
			fs_add_binary(afs, "rdata", rdlength, rdata, 0);
		} else {
			fs_add_uint64(afs, "rdata_is_parsed", 1);
			char* ipv6_str = xmalloc(INET6_ADDRSTRLEN);

			inet_ntop(AF_INET6, (struct sockaddr_in6*)rdata, 
					ipv6_str,INET6_ADDRSTRLEN);

			fs_add_unsafe_string(afs, "rdata", ipv6_str, 1);
		}
	} else {
		fs_add_uint64(afs, "rdata_is_parsed", 0);
		fs_add_binary(afs, "rdata", rdlength, rdata, 0);
	}

	// Now we're adding the new fs to the list.
	fs_add_fieldset(list, NULL, afs);

	// Now update the pointers.
	*data = *data + bytes_consumed + sizeof(dns_answer_tail) + rdlength;
	*data_len = *data_len - bytes_consumed - sizeof(dns_answer_tail) - rdlength;

	log_trace("dns", "return success from process_response_answer, data_len: %d", 
			*data_len);

	return 0;
}