Пример #1
0
void process_cisco00000c(struct Ferret *ferret, struct NetFrame *frame, const unsigned char *px, unsigned length)
{
	unsigned offset=0;
	unsigned pid;

	if (offset+2 > length) {
		FRAMERR(frame, "%s: truncated\n", "cisco");
		return;
	}

	pid = ex16be(px);
	SAMPLE(ferret,"Cisco", JOT_NUM("0x00000c-pid",  pid));
	offset+= 2;

	switch (pid) {
	case 0x2000:
		parse_CDP(ferret, frame, px+offset, length-offset);
		break;
	case 0x010b:
		parse_PVSTP(ferret, frame, px+offset, length-offset);
		break;
	case 0x2003: /* Cisco VLAN Trunking Protocol */
		process_cisco_vtp(ferret, frame, px+offset, length-offset);
		break;
	case 0x2004: /* Cisco Dynamic Trunking Protocol */
		parse_dynamic_trunking_protocol(ferret, frame, px+offset, length-offset);
		break;
	default:
		FRAMERR(frame, "%s: unknown value: 0x%x\n", "cisco", pid);
	}
}
Пример #2
0
/**
 * Cisco VLAN Trunking Protocol.
 */
void process_cisco_vtp(struct Ferret *ferret, struct NetFrame *frame, const unsigned char *px, unsigned length)
{
	struct vtp_summary {
     unsigned char  version;         
     unsigned char  code;            
     unsigned char  followers;       
     unsigned char  domain_length;
     unsigned char  domain[32]; 
     unsigned revision;                    
     unsigned updater;                     
     unsigned char  timestamp[12];    
     unsigned char  md5[16];
	} vtp;
	unsigned offset=0;
	const unsigned char *domain_name;
	
	if (offset+4 > length) {
		FRAMERR(frame, "%s: truncated\n", "VTP");
		return;
	}

	vtp.version = px[offset++];
	SAMPLE(ferret,"Cisco", JOT_NUM("VTP version",  vtp.version));
	if (vtp.version != 1) {
		FRAMERR(frame, "%s: unknown version %d\n", "VTP", vtp.version);
		return;
	}

	vtp.code = px[offset++];
	SAMPLE(ferret,"Cisco", JOT_NUM("VTP code",  vtp.code));
	vtp.followers = px[offset++];
	SAMPLE(ferret,"Cisco", JOT_NUM("VTP followers",  vtp.followers));
	vtp.domain_length = px[offset++];
	if (offset + vtp.domain_length > length) {
		FRAMERR(frame, "%s: truncated\n", "VTP");
		return;
	}
	domain_name = px+offset;
	offset += 32;
	
	if (offset + 8 > length) {
		FRAMERR(frame, "%s: truncated\n", "VTP");
		return;
	}
	vtp.revision = ex32be(px+offset);
	offset += 4;

	vtp.updater = ex32be(px+offset);
	offset += 4;

	JOTDOWN(ferret, 
		JOT_MACADDR("ID-MAC", frame->src_mac),
		JOT_PRINT("Cisco VTP Domain", domain_name, vtp.domain_length),
		JOT_NUM("Revision", vtp.revision),
		JOT_IPv4("Updater", vtp.updater),
		0);



}
Пример #3
0
void parse_dynamic_trunking_protocol(struct Ferret *ferret, struct NetFrame *frame, const unsigned char *px, unsigned length)
{
	unsigned offset;

	if (length < 1) {
		FRAMERR(frame, "truncated\n");
		return;
	}

	/* Version */
	if (px[0] != 0x01) {
		FRAMERR(frame, "unexpected\n");
		return;
	}

	/* Look for TLV values */
	for (offset=1; offset+4<length; ) {
		unsigned tag = ex16be(px+offset+0);
		unsigned length = ex16be(px+offset+2);

		if (tag == 0 && length == 0)
			break;

		if (length < 4) {
			FRAMERR(frame, "unexpected\n");
			return;
		}

		length -= 4;
		offset += 4;

		switch (tag) {
		case 0x0001: /* domain */
			JOTDOWN(ferret, 
				JOT_MACADDR("ID-MAC", frame->src_mac),
				JOT_PRINT("DTP-Domain", px+offset, length),
				0);
			break;
		case 0x0002: /* status */
			break;
		case 0x0003: /* Dtptype */
			break;
		case 0x0004: /* neighbor */
			/* TODO: is this interesting? */
			break;
		default:
			FRAMERR(frame, "unknown 0x%x\n", tag);
		}

		offset += length;
	}


}
Пример #4
0
/*TODO: currently, nobody references this function*/
void dns_dynamic_update(struct Ferret *ferret, struct NetFrame *frame, const unsigned char *px, unsigned length, struct DNS *dns)
{
	unsigned i;


	for (i=0; i<dns->answer_count; i++) {
		char name[256];
		unsigned name_length;
		unsigned x;
		struct DNSRECORD *rec = &dns->answers[i];

		name_length = dns_extract_name(frame, px, length, rec->name_offset, name, sizeof(name));

		x = rec->clss<<16 | rec->type;
		
		SAMPLE(ferret,"DynDNS", JOT_NUM("Prereq", x));

		switch (rec->type) {
		case 0x0001: /*A*/
			switch (rec->clss) {
			case 0x0001: /*INTERNET*/
				{
					unsigned ip_address = ex32be(px+rec->rdata_offset);

					if (rec->rdata_length != 4)
						FRAMERR(frame, "dns: data not 4-bytes long, was %d-bytes instead (class=%d, type=%d, name=%s)\n", rec->rdata_length, rec->clss, rec->type, name);


					JOTDOWN(ferret,
						JOT_IPv4("ID-IP", ip_address),
						JOT_PRINT("name",		 	name,				name_length),
						0);

					JOTDOWN(ferret,
						JOT_SZ("proto","NETBIOS"),
						JOT_SZ("op","register"),
						JOT_SRC("ip.src", frame),
						JOT_PRINT("name",		 	name,				name_length),
						JOT_IPv4("address", ip_address),
						0);
				}
				break;
			default:
				FRAMERR(frame, "dns: unknown class=%d (type=%d, name=%s)\n", rec->clss, rec->type, name);
			}
			break;

		}
	}
}
Пример #5
0
void extract_item(struct Ferret *ferret, struct NetFrame *frame, const unsigned char *px, 
				  unsigned length, unsigned *r_offset, 
				  const unsigned char **r_object, unsigned *r_object_len)
{
	unsigned len;

	UNUSEDPARM(ferret);

	if (*r_offset + 1 > length) {
		FRAMERR(frame, "truncated\n");
		*r_offset = length+1;
		return;
	}

	len = px[*r_offset];
	(*r_offset)++;

	if (*r_offset + len > length)
		len = length-*r_offset;

	*r_object = px + *r_offset;
	*r_object_len = len;

	*r_offset += len;
}
Пример #6
0
unsigned 
asn1_integer(struct NetFrame *frame, const unsigned char *px, unsigned length, unsigned *r_offset)
{
	unsigned int_length;
	unsigned result;
	unsigned tag;

	tag = px[(*r_offset)++];
	if (tag != 0x0a && tag != 0x02 && tag != 0x01)
		FRAMERR_BADVAL(frame, "asn1", tag);

	int_length = asn1_length(frame, px, length, r_offset);
	if (int_length == 0xFFFFffff) {
		*r_offset = length;
		return 0xFFFFffff;
	}
	if (*r_offset + int_length > length) {
		FRAMERR(frame, "snmp: truncated\n");
		*r_offset = length;
		return 0xFFFFffff;
	}

	result = 0;
	while (int_length--)
		result = result * 256 + px[(*r_offset)++];

	return result;
}
Пример #7
0
unsigned 
dns_resolve_alias(struct NetFrame *frame, const unsigned char *px, unsigned length, struct DNS *dns, const char *alias, int depth)
{
	unsigned i;

	for (i=dns->question_count; i<dns->record_count; i++) {
		struct DNSRECORD *rec = &dns->records[i];
		char name[256];
		unsigned name_length;

		name_length = dns_extract_name(frame, px, length, rec->name_offset, name, sizeof(name));

		if ((rec->type != 1 && rec->type != 5)|| (rec->clss&0x7FFF) != 1)
			continue;

		if (stricmp(alias, name) == 0) {
			switch (rec->type) {
			case 1:
				return ex32be(px+rec->rdata_offset);
			case 5:
				name_length = dns_extract_name(frame, px, length, rec->rdata_offset, name, sizeof(name));
				if (depth > 10)
					FRAMERR(frame, "dns: too much recursion, alias=\"%s\"\n", alias);
				else
					return dns_resolve_alias(frame, px, length, dns, name, depth+1);
			}
		}
	}

	/*FRAMERR(frame, "dns: could not resolve IP for alias=\"%s\"\n", alias);*/

	return 0;
}
Пример #8
0
unsigned 
asn1_length(struct NetFrame *frame, const unsigned char *px, unsigned length, unsigned *r_offset)
{
	unsigned result;

	if ( (*r_offset >= length) 
		|| 
		((px[*r_offset] & 0x80)  && ((*r_offset) + (px[*r_offset]&0x7F) >= length))) {
		FRAMERR(frame, "snmp: truncated\n");
		*r_offset = length;
		return 0xFFFFffff;
	}
	result = px[(*r_offset)++];
	if (result & 0x80) {
		unsigned length_of_length = result & 0x7F;
		if (length_of_length == 0) {
			FRAMERR(frame, "snmp: unexpected value\n");
			*r_offset = length;
			return 0xFFFFffff;
		}
		result = 0;
		while (length_of_length) {
			result = result * 256 + px[(*r_offset)++];
			if (result > 0x10000) {
				FRAMERR(frame, "snmp: unexpected value\n");
				*r_offset = length;
				return 0xFFFFffff;
			}
			length_of_length--;
		}
	}

	if (result > length-*r_offset)
		result = length-*r_offset;
	if (result > 0x1000000)
		result = 0;
	return result;
}
Пример #9
0
static void 
parse_aim_snac(struct TCPRECORD *sess, struct NetFrame *frame, const unsigned char *px, unsigned length)
{
	enum {
		SNAC_START,
		SNAC_FAMILY_HI, SNAC_FAMILY_LO, 
		SNAC_SUBTYPE_HI, SNAC_SUBTYPE_LO, 
		SNAC_FLAGS_HI, SNAC_FLAGS_LO, 
		SNAC_REQUESTID_0, SNAC_REQUESTID_1, SNAC_REQUESTID_2, SNAC_REQUESTID_3, 
		SNAC_REQUEST_DONE,
		SNAC_REQUEST_DATA,
		SNAC_TLV_START,
		SNAC_TLV_TAG_HI, SNAC_TLV_TAG_LO, SNAC_TLV_LEN_HI, SNAC_TLV_LEN_LO,
		SNAC_TLV_DATA,
		SNAC_TLV_DONE,
		SNAC_IGNORE,

		SNAC_ONCOMING_PRE_BUDDY1,
		SNAC_ONCOMING_PRE_BUDDY2,
		SNAC_ONCOMING_PRE_BUDDY3,
		SNAC_ONCOMING_BUDDY, SNAC_ONCOMING_BUDDY_NAME,

		SNAC_SSI_UNKNOWN_HI, SNAC_SSI_UNKNOWN_LO,
		SNAC_SSI_VERSION, SNAC_SSI_OBJ_COUNT_HI, SNAC_SSI_OBJ_COUNT_LO,
		SNAC_SSI_ENTRY,


		SNAC_SKIP_TO_BUDDY,SNAC_SKIP_TO_TLV,
	};
	struct AIMPARSER *aim = &sess->layer7.aim;
	unsigned offset = 0;

	/* Do the 'close' fucntion that indicates we we've reached the end
	 * of the encapsulating FLAP packet, telling us that anything left undone
	 * parsing the inside SNAC data needs to finish */
	if (px == NULL) {
		if (aim->tlv_len) {
			/* Check to see if the PDU was truncated in the middle
			 * of a TLV */
			FRAMERR(frame, "%s: truncated\n", "AIM");
		}
		return;
	}


	/* Run through the state machine */
	while (offset<length)
	switch (aim->snac_state) {
	case SNAC_START:
		aim->snac_state++;
		break;
	case SNAC_FAMILY_HI:
	case SNAC_FAMILY_LO:
		aim->pdu.family <<= 8;
		aim->pdu.family |= px[offset++];
		aim->snac_state++;
		break;

	case SNAC_SUBTYPE_HI:
	case SNAC_SUBTYPE_LO:
		aim->pdu.subtype <<= 8;
		aim->pdu.subtype |= px[offset++];
		aim->snac_state++;
		break;

	case SNAC_FLAGS_HI:
	case SNAC_FLAGS_LO:
		aim->pdu.flags <<= 8;
		aim->pdu.flags |= px[offset++];
		aim->snac_state++;
		break;

	case SNAC_REQUESTID_0:
	case SNAC_REQUESTID_1:
	case SNAC_REQUESTID_2:
	case SNAC_REQUESTID_3:
		aim->pdu.request_id <<= 8;
		aim->pdu.request_id |= px[offset++];
		aim->snac_state++;
		break;
	case SNAC_REQUEST_DONE:
		if (aim->pdu.channel == 2) {
			switch (aim->pdu.family<<16 | aim->pdu.subtype) {
			case 0x00040006: /* Outgoing Message */
			case 0x00040007: /* Incoming Message */
			case 0x00040014: /* typin to buddy */
				aim->skip_len = 10;
				aim->snac_state = SNAC_SKIP_TO_BUDDY;
				break;
			case 0x0003000b:
			case 0x00020015:
			case 0x00020006:
				aim->snac_state = SNAC_ONCOMING_BUDDY;
				break;
			case 0x00130006: /* family=Server Side Info, subtype=List */
				/* This is a special structure, but it starts with
				 * a 2-byte number followed by a TLV */
				aim->snac_state = SNAC_SSI_UNKNOWN_HI;
				break;
			case 0x00170007: /* signon reply*/
				/* It's just LEN-VALUE encoded, so pretend there is a tag in 
				 * front */
				aim->tlv_tag = 0;
				aim->snac_state = SNAC_TLV_LEN_HI;
				break;
			case 0x00010017: /* family=Generic, subtype=Capabilities */
			case 0x00010018: /* family=Generic, subtype=Capabilities ACK*/
			case 0x00010006: /* family=Generic, subtype=Rate Info request*/
			case 0x00010007: /* family=Generic, subtype=Rate Info responset*/
			case 0x00010008: /* family=Generic, subtype=Rate Info ACK*/
			case 0x00010003:
			case 0x00010002:
			case 0x00040002: /* family=messaging, subtype= Set ICBM Parameter*/
			case 0x00040005: /* family=messaging, subtype=parameter info */
			case 0x0013000e: /* family=aim SSI, subtype=server ack*/
			case 0x00130009: /* family=aim SSI, subtype=modify buffy*/
			case 0x000d0009: /* family=ChatNav , subtype=Info*/
				/* These don't have TLV, but some other data inside */
				aim->snac_state = SNAC_IGNORE;
				break;
			case 0x00010013: /* family=Generic, subtype=message-of-the-day*/
				/* This has some TLVs later in the packet, but starts with
				 * some non-TLV info */
				aim->snac_state = SNAC_IGNORE;
				break;
			case 0x00170002:
			case 0x00170003:
			case 0x00170006:
			case 0x0001001e: /* family=generic, subtype=0x1e*/
				aim->snac_state = SNAC_TLV_START;
				break;
			default:
				switch (aim->pdu.family) {
				case 1:
				case 0x13: /* AIM SSI */
				case 0x18: /* e-mail */
					/* These (probably) don't have TLV stuff */
					aim->snac_state = SNAC_IGNORE;
					break;
				default:
					/* These (probably) have TLV stuff */
					aim->snac_state = SNAC_TLV_START;
				}
				break;

			}
		} else
			aim->snac_state = SNAC_IGNORE;
		break;
	case SNAC_TLV_START:
		strfrag_init(sess->str);
		aim->snac_state++;
		break;
	case SNAC_TLV_TAG_HI:
		aim->tlv_tag = px[offset++];
		aim->snac_state++;
		break;
	case SNAC_TLV_TAG_LO:
		aim->tlv_tag <<= 8;
		aim->tlv_tag |= px[offset++];
		aim->snac_state++;
		break;
	case SNAC_TLV_LEN_HI:
		aim->tlv_len = px[offset++];
		aim->snac_state++;
		break;
	case SNAC_TLV_LEN_LO:
		aim->tlv_len <<= 8;
		aim->tlv_len |= px[offset++];
		aim->snac_state++;
		break;
	case SNAC_TLV_DATA:
		if (aim->tlv_len) {
			unsigned sublen;

			if (aim->tlv_len < length-offset)
				sublen = aim->tlv_len;
			else
				sublen = length-offset;

			parse_tlv(sess, frame, px+offset, sublen);

			offset += sublen;
			aim->tlv_len -= sublen;
		}

		/* We can get here 3 ways.
		 * #1 - the TLV len could have started at zero, in
		 *      which case there is no real data to process.
		 * #2 - the TLV len had a value that crossed packets,
		 *      and we slowly decremented it by bits
		 # #3 - we got here right after processing a chunk
		 */
		if (aim->tlv_len == 0) {
			/* If done parsing the TLV, then do a 'close' operation by
			 * sending a NULL data pointer */
			parse_tlv(sess, frame, 0, 0);
			aim->snac_state = SNAC_TLV_DONE;
		}
		break;
	case SNAC_TLV_DONE:
		switch (aim->pdu.family<<16 | aim->pdu.subtype) {
		case 0x00130006: /* family=Server Side Info, subtype=List */
			/* This has non-TLV data following the TLV */
			aim->snac_state = SNAC_SSI_VERSION;
			break;
		default:
			aim->snac_state = SNAC_TLV_START;
		}
		break;
	case SNAC_IGNORE:
		/* Just ignore the remainder of the data from this point on */
		offset = length;
		break;


	case SNAC_ONCOMING_PRE_BUDDY1:
	case SNAC_ONCOMING_PRE_BUDDY2:
	case SNAC_ONCOMING_PRE_BUDDY3:
		offset++;
		aim->snac_state++;
		break;
	case SNAC_ONCOMING_BUDDY:
		/* The buddy stuff doesn't have a TLV header, so we need
		 * to parse it separately */
		aim->tlv_tag = 0x0000; /* pseudo tag */
		aim->tlv_len = px[offset++];
		if (aim->tlv_len == 0) {
			aim->snac_state = SNAC_ONCOMING_PRE_BUDDY1; 
		} else {
			strfrag_init(sess->str);
			aim->snac_state++;
		}
		break;
	case SNAC_ONCOMING_BUDDY_NAME:
		if (aim->tlv_len) {
			unsigned sublen;
			if (aim->tlv_len < length-offset)
				sublen = aim->tlv_len;
			else
				sublen = length-offset;
			strfrag_append(sess->str, px+offset, sublen);
			offset += sublen;
			aim->tlv_len -= sublen;
		}
		if (aim->tlv_len == 0) {
			/* Save the buddy name */
			strfrag_copy(&sess->str[1], &sess->str[0]);

			/* If done parsing the TLV, then do a 'close' operation by
			 * sending a NULL data pointer */
			parse_tlv(sess, frame, 0, 0);


			switch (aim->pdu.family<<16 | aim->pdu.subtype) {
			case 0x00040006: /* Outgoing Message */
				aim->skip_len = 0;
				aim->snac_state = SNAC_SKIP_TO_TLV;
				break;
			case 0x00040007: /* Incoming Message */
			case 0x00020006: /* Incoming Buddy User Info */
				aim->skip_len = 4;
				aim->snac_state = SNAC_SKIP_TO_TLV;
				break;
			case 0x00040015: /* User Info Query */
				break;
			default:
				aim->snac_state = SNAC_IGNORE;
				break;
			}
		}
		break;
	case SNAC_SSI_UNKNOWN_HI:
		offset++;
		aim->snac_state++;
		break;
	case SNAC_SSI_UNKNOWN_LO:
		offset++;
		aim->snac_state = SNAC_TLV_START;
		break;
	case SNAC_SSI_VERSION:
		if (px[offset++] != 0)
			aim->snac_state = SNAC_IGNORE; /* don't understand this version */
		else
			aim->snac_state = SNAC_SSI_OBJ_COUNT_HI;
		break;
	case SNAC_SSI_OBJ_COUNT_HI:
		aim->ssi_obj_count = px[offset++];
		aim->snac_state++;
		break;
	case SNAC_SSI_OBJ_COUNT_LO:
		aim->ssi_obj_count <<= 8;
		aim->ssi_obj_count |= px[offset++];
		aim->snac_state++;
		break;
	case SNAC_SSI_ENTRY:
		/* Loop through a number of entries */
		while (offset<length && aim->ssi_obj_count) {
			unsigned sublen;

			/* Parse a fragment of data. This function only parses a SINGLE
			 * fragment. Therefore, the returned 'sublen' may be smaller than
			 * the one passed into it */
			aim->ssi_state = 0;
			sublen = parse_ssi_entry(sess, frame, px+offset, length-offset);

			offset += sublen;

			aim->ssi_obj_count--;
		}

		/* there is some more info past the entries, but just ingore it */
		if (aim->ssi_obj_count == 0) {
			aim->snac_state = SNAC_IGNORE;
			strfrag_finish(sess->str+0);
			strfrag_finish(sess->str+1);
		}
		break;
	case SNAC_SKIP_TO_BUDDY:
		{
			unsigned sublen = aim->skip_len;
			if (sublen > length-offset)
				sublen = length-offset;
			aim->skip_len -= sublen;
			offset += sublen;

			if (aim->skip_len == 0)
				aim->snac_state = SNAC_ONCOMING_BUDDY;
		}
		break;
	case SNAC_SKIP_TO_TLV:
		{
			unsigned sublen = aim->skip_len;
			if (sublen > length-offset)
				sublen = length-offset;
			aim->skip_len -= sublen;
			offset += sublen;

			if (aim->skip_len == 0)
				aim->snac_state = SNAC_TLV_START;
		}
		break;
	}
}
Пример #10
0
/**
 * This parses a TLV record instead of a SNAC packet, which is itself 
 * inside of a FLAP PDU. We identify the precise item by the SNAC-family,
 * SNAC-subtype, and TLV-tag */
static void 
parse_tlv(struct TCPRECORD *sess, struct NetFrame *frame, const unsigned char *px, unsigned length)
{
	struct FerretEngine *eng = sess->eng;
	struct Ferret *ferret = eng->ferret;
	struct AIMPARSER *aim = &sess->layer7.aim;
	unsigned h;

	/* This function is going to process the data within a SNAC TLV field. 
	 * We are just going to handle this all in a big switch/case statement. */
#define HASH(x,y,z) (((x)<<16)|((y)<<8)|(z))
	h = HASH(aim->pdu.family, aim->pdu.subtype, aim->tlv_tag);

	/* If we are in the middle of parsing the string, just grab
	 * it in our re-assembly buffer */
	if (px != NULL) {
		strfrag_append(sess->str, px, length);
		return;
	}
	
	/* Process the string we've reassembled. We are going to hash on the full context
	 * of the PDU rather than just the TLV tag */
	switch (h) {
	case 0x00170203: /* family=Sign-on, subtype=Logon, tag=client-id-string */
		JOTDOWN(ferret, 
			JOT_SRC("ID-IP",frame),
			JOT_PRINT("AIM-Client-ID", sess->str->the_string, sess->str->length),
			0);
		break;
	case 0x0017020e: /* family=Sign-on, subtype=Logon, tag=country */
		JOTDOWN(ferret, 
			JOT_SRC("ID-IP",frame),
			JOT_PRINT("AIM-Country", sess->str->the_string, sess->str->length),
			0);
		break;
	case 0x0017020f: /* family=Sign-on, subtype=Logon, tag=language */
		JOTDOWN(ferret, 
			JOT_SRC("ID-IP",frame),
			JOT_PRINT("AIM-Language", sess->str->the_string, sess->str->length),
			0);
		break;
	case 0x00170225: /* family=Sign-on, subtype=Logon, tag=password hash */
		JOTDOWN(ferret, 
			JOT_SRC("ID-IP",frame),
			JOT_HEXSTR("AIM-Password-Hash", sess->str->the_string, sess->str->length),
			0);
		break;
		break;
	case 0x00170201: /* family=Sign-on, subtype=Logon, tag=screen-name */
	case 0x00170601: /* family=Sign-on, subtype=Sign-on, tag=screen-name  */
		/* This is the sign-on 'screen-name' in the packet that the user sends to
		 * the logon server (logon.oscar.aol.com). The server will respond with
		 * a 'challenge'. The user will then send the screen-name and hash of 
		 * challenge and password to the real server he wants to connect to */
		JOTDOWN(ferret, 
			JOT_SRC("ID-IP",frame),
			JOT_PRINT("AIM-Screen-Name", sess->str->the_string, sess->str->length),
			0);
		break;
	case 0x00170301: /* family=Logon, subtype=Reply, tag=screen-name  */
		JOTDOWN(ferret, 
			JOT_DST("ID-IP",frame), /* logon reply screen name sent from server*/
			JOT_PRINT("AIM-Screen-Name", sess->str->the_string, sess->str->length),
			0);
		break;
	case 0x00170311: /* family=Logon, subtype=Reply, tag=email  */
		JOTDOWN(ferret, 
			JOT_DST("ID-IP",frame), /* logon reply screen name sent from server*/
			JOT_PRINT("e-mail", sess->str->the_string, sess->str->length),
			0);
		break;
	case 0x00170349: /* family=Logon, subtype=Reply, tag=auth-protocol  */
		JOTDOWN(ferret, 
			JOT_DST("ID-IP",frame), /* logon reply screen name sent from server*/
			JOT_HEXSTR("AIM-digest-sig", sess->str->the_string, sess->str->length),
			0);
		break;
	case 0x00170700: /*AIM Sign-on(0x17), Sign-on Reply(7), Challenge(10)*/
		/* This is the 'challenge' sent back by logon.oscar.aol.com. The user
		 * will hash this with his password in order to logon to all the other
		 * servers.
		 *
		 * Because of this, we need to attach this string to the session going
		 * in the reverse direction. That will enable us to log the authentication
		 * process in case we want to log the hashes */
		JOTDOWN(ferret, 
			JOT_SRC("ID-IP",frame),
			JOT_PRINT("AIM-Challenge", sess->str->the_string, sess->str->length),
			0);
		break;
	case 0x0017038e: /* authorization cookie */
		/* This is a long string to pull out, but it gives anybody who has
		 * this cookie the ability to log onto any AIM service */
		JOTDOWN(ferret, 
			JOT_DST("ID-IP",frame),
			JOT_HEXSTR("AIM-Auth-Cookie", sess->str->the_string, sess->str->length),
			0);
		break;	
	case  0x00030b00: /* INCOMING oncoming buddy name */
	case  0x00020600:
		if (sess->str->length) {
			JOTDOWN(ferret, 
				JOT_DST("ID-IP",frame),
				JOT_PRINT("AIM-Buddy", sess->str->the_string, sess->str->length),
				0);
			JOTDOWN(ferret, 
				JOT_DST("ID-IP",frame),
				JOT_PRINT("friend", sess->str->the_string, sess->str->length),
				0);
		}
		break;
	case 0x00021500: /* OUTGOING user info query*/
		if (sess->str->length) {
			JOTDOWN(ferret, 
				JOT_SRC("ID-IP",frame),
				JOT_PRINT("AIM-Buddy", sess->str->the_string, sess->str->length),
				0);
			JOTDOWN(ferret, 
				JOT_SRC("ID-IP",frame),
				JOT_PRINT("friend", sess->str->the_string, sess->str->length),
				0);
		}
		break;
	case 0x00040700: /* Messaging, incoming */
		if (sess->str->length) {
			JOTDOWN(ferret, 
				JOT_DST("ID-IP",frame),
				JOT_PRINT("AIM-Buddy", sess->str->the_string, sess->str->length),
				0);
			JOTDOWN(ferret, 
				JOT_DST("ID-IP",frame),
				JOT_PRINT("friend", sess->str->the_string, sess->str->length),
				0);

			strfrag_xfer(sess->str+1, sess->str);
		}
		break;
	case 0x00040702: /* Messaging, INCOMING */
		decode_message(sess, frame, sess->str[0].the_string, sess->str[0].length, 0);
		break;
	case 0x00040600: /* Messaging, outgoing */
		if (sess->str->length) {
			JOTDOWN(ferret, 
				JOT_SRC("ID-IP",frame),
				JOT_PRINT("AIM-Buddy", sess->str->the_string, sess->str->length),
				0);
			JOTDOWN(ferret, 
				JOT_SRC("ID-IP",frame),
				JOT_PRINT("friend", sess->str->the_string, sess->str->length),
				0);

			strfrag_xfer(sess->str+1, sess->str);
		}
		break;
	case 0x00040602: /* Messaging, outgoing */
		decode_message(sess, frame, sess->str[0].the_string, sess->str[0].length, 1);
		break;
	case 0x00020604: /* Buddy Info - away message */
		if (sess->str->length) {
			JOTDOWN(ferret, 
				JOT_DST("ID-IP",frame),
				JOT_PRINT("AIM-Buddy", sess->str[1].the_string, sess->str[1].length),
				JOT_PRINT("Away-Message", sess->str[0].the_string, sess->str[0].length),
				0);
		}
		break;
	case 0x00041400: /* typing, outgoing */
		if (sess->str->length) {
			JOTDOWN(ferret, 
				JOT_SRC("ID-IP",frame),
				JOT_PRINT("AIM-Buddy", sess->str->the_string, sess->str->length),
				0);
			JOTDOWN(ferret, 
				JOT_SRC("ID-IP",frame),
				JOT_PRINT("friend", sess->str->the_string, sess->str->length),
				0);
		}
		break;
	case 0x00040605: /* File transfer */
		parse_message_filexfer_rendezvous(sess, frame, sess->str->the_string, sess->str->length);
		break;

	case 0x00040701:
	case 0x00040703:
	case 0x00040705:
	case 0x0004070b:
	case 0x0004070f:
	case 0x00040713:
	case 0x00040716:
	case 0x0004071d:
	case 0x00040603: /* Messaging, outgoing, server-ack requested */
		break;
	case 0x00130601: /* SNAC Server Side Information Entry List*/
	case 0x001306c9: 
	case 0x001306d6: 
	case 0x0013066a:
	case 0x0013066d: 
	case 0x00130631: 
		/* This is the start of an SSI Entry list, maybe we should 
		 * remember this??? */
		break;
	case 0x00130731:
		if (sess->str[1].length && sess->str[0].length) {
			JOTDOWN(ferret, 
				JOT_DST("ID-IP",frame),
				JOT_PRINT("AIM-Buddy", sess->str[1].the_string, sess->str[1].length),
				JOT_PRINT("AIM-Description", sess->str[0].the_string, sess->str[0].length),
				0);
		}
		break;
	/* Others that I've seen */
	case 0x0017064b:
	case 0x0017065a:
	case 0x0017024c:
	case 0x00170216:
	case 0x00170217:
	case 0x00170218:
	case 0x00170219:
	case 0x0017021a:
	case 0x00170214:
	case 0x0017024a:
	case 0x00170305:
	case 0x00170306:
	case 0x00170313:
	case 0x00170354:
	case 0x00170340:
	case 0x00170343:
	case 0x00170341:
	case 0x00170342:
	case 0x00170348:
	case 0x00170344:
	case 0x00170347:
	case 0x00170345:
	case 0x00170346:
	case 0x00020301:
	case 0x00020302:
	case 0x00020305:
	case 0x00020303:
	case 0x00020304:
	case 0x00030302:
	case 0x00030301:
	case 0x00030304:
	case 0x00040504:
	case 0x00090302:
	case 0x00090301:
	case 0x00020405:
	case 0x00011e1d:
	case 0x00011e06:
	case 0x0004060d:
	case 0x00020601: /* Buddy Info - User Class */
	case 0x00020603: /* Buddy Info - Online Since AND Away Msg Encoding ??? */
	case 0x00020605: /* Buddy Info - Member Since */
	case 0x0002060b: /* Buddy Info - unknown timestamp */
	case 0x0002060d: /* Buddy Info - Capabilities List */
	case 0x0002060f: /* Buddy Info - Session Length */
	case 0x0002061d: /* Buddy Info - Available Message */
	case 0x0002061f: /* Buddy Info - unknown */
	case 0x00020623: /* Buddy Info - unknown timestamp */
	case 0x00020626: /* Buddy Info - unknown timestamp (member since?) */
	case 0x00020627: /* Buddy Info - unknown timestamp */

		break;
	case 0x001306C8: /*SSI: members of this group */
		break;
	default:
		/* TODO: add SAMPLE here */
		switch (h&0xFFFFFF00) {
		case 0x00130300:
			break;
		default:
			FRAMERR(frame, "%s: unknown TLV tag: 0x%08x\n", "AIM", h);
		}
		break;
	}
	strfrag_finish(sess->str);
}
Пример #11
0
void decode_message(struct TCPRECORD *sess, struct NetFrame *frame, const unsigned char *px, unsigned length, unsigned is_outgoing)
{
	struct FerretEngine *eng = sess->eng;
	struct Ferret *ferret = eng->ferret;
	const unsigned char *msg = px;
	unsigned msg_length = length;
	unsigned msg_offset = 0;

	if (msg_length > 2 && ex16be(msg+msg_offset) == 0x501) {
		/*unsigned flags = ex16be(msg+msg_offset);*/
		unsigned len=0;
		msg_offset += 2;
		
		if (msg_offset+2 < msg_length) {
			len = ex16be(msg+msg_offset);
			msg_offset += len+2;
		}

		if (msg_offset+2 < msg_length)
			msg_offset += 2; /* block info */

		if (msg_offset+2 < msg_length) {
			len = ex16be(msg+msg_offset);
			msg_offset += 2; /* block length */
		}

		msg_offset += 4; /* character set */
		if (len > 4)
			len -= 4; /* subtract the charset info from the block lenght*/

		if (msg_offset > msg_length) {
			FRAMERR(frame, "%s: integer overflow\n", "AIM");
			return;
		}

		if (msg_offset + len > msg_length)
			len = msg_length - msg_offset;

		if (len > 6 && strnicmp((const char*)msg+msg_offset, "<HTML>", 6)==0) {
			unsigned char *msg2 = alloca(len);
			unsigned msg2_len;

			msg2_len = strip_html_tags(msg+msg_offset, len, msg2, len);

			if (is_outgoing)
				JOTDOWN(ferret, 
					JOT_SRC("ID-IP",frame),
					JOT_PRINT("AIM-Message-To", sess->str[1].the_string, sess->str[1].length),
					JOT_PRINT("AIM-Message", msg2, msg2_len),
					0);
			else
				JOTDOWN(ferret, 
					JOT_DST("ID-IP",frame),
					JOT_PRINT("AIM-Message-From", sess->str[1].the_string, sess->str[1].length),
					JOT_PRINT("AIM-Message", msg2, msg2_len),
					0);

		} else  {
			if (is_outgoing)
				JOTDOWN(ferret, 
					JOT_SRC("ID-IP",frame),
					JOT_PRINT("AIM-Message-To", sess->str[1].the_string, sess->str[1].length),
					JOT_PRINT("AIM-Message", msg+msg_offset, msg_length-msg_offset),
					0);
			else
				JOTDOWN(ferret, 
					JOT_DST("ID-IP",frame),
					JOT_PRINT("AIM-Message-From", sess->str[1].the_string, sess->str[1].length),
					JOT_PRINT("AIM-Message", msg+msg_offset, msg_length-msg_offset),
					0);
		}

	} else {
		while (msg_offset<msg_length && msg[msg_offset] < 26)
			msg_offset++;

		if (is_outgoing)
			JOTDOWN(ferret, 
				JOT_SRC("ID-IP",frame),
				JOT_PRINT("AIM-Message-To", sess->str[1].the_string, sess->str[1].length),
				JOT_PRINT("AIM-Message", msg+msg_offset, msg_length-msg_offset),
				0);
		else
			JOTDOWN(ferret, 
				JOT_DST("ID-IP",frame),
				JOT_PRINT("AIM-Message-From", sess->str[1].the_string, sess->str[1].length),
				JOT_PRINT("AIM-Message", msg+msg_offset, msg_length-msg_offset),
				0);
	}
}
Пример #12
0
/**
 * Parse the "rendez-vous" TLV within a packet. Since this is a TLV, it has
 * already been reassembled by our string frag parser.
 */
static void
parse_message_filexfer_rendezvous(struct TCPRECORD *sess, struct NetFrame *frame, const unsigned char *px, unsigned length)
{
	unsigned offset=0;

	/* skip some fields */
	offset += 2+8;

	/* verify we have the file transfer ID */
	while (offset < 2+8+16) {
		if (px[offset] != (unsigned char)("\x09\x46\x13\x43\x4c\x7f\x11\xd1\x82\x22\x44\x45\x53\x54\x00\x00"[offset-8-2]))
			return; /* not a file transfer command */ /*TODO: SAMPLE this */
		offset++;
	}

	/* go through the embeded TLVs */
	while (offset<length) {
		unsigned tag;
		unsigned len;

		if (offset+4>length)
			break;

		tag = ex16be(px+offset+0);
		len = ex16be(px+offset+2);

		offset += 4;

		/*
            TLV: Unknown
                Value ID: Unknown (0x000a)
                Length: 2
                Value
            TLV: Unknown
                Value ID: Unknown (0x000f)
                Length: 0
                Value
            TLV: Internal IP
                Value ID: Internal IP (0x0003)
                Length: 4
                Value: 12625930
            TLV: External Port
                Value ID: External Port (0x0005)
                Length: 2
                Value: 5190
            TLV: Extended Data
                Value ID: Extended Data (0x2711)
                Length: 17
                Value
		*/
		switch (tag) {
		case 0x000a:
		case 0x000f:
		case 0x0010:
			break;
		case 3: /* Internet IP */
			{
				unsigned j;
				unsigned ip=0;
				for (j=0; j<4 && offset+j<length; j++)
					ip = ip << 8 | px[offset+j];

				JOTDOWN(sess->eng->ferret, 
					JOT_SRC("ID-IP",frame),
					JOT_SZ("AIM", "File-Transfer"),
					JOT_IPv4("Internal-IP", ip),
					0);
			}
			break;
		case 5: /* Internal Port */
			{
				unsigned j;
				unsigned port=0;
				for (j=0; j<2 && offset+j<length; j++)
					port = port << 8 | px[offset+j];

				JOTDOWN(sess->eng->ferret, 
					JOT_SRC("ID-IP",frame),
					JOT_SZ("AIM", "File-Transfer"),
					JOT_NUM("Internal-Port", port),
					0);
			}
			break;
		case 0x2711: /* filename */
			if (len > length-offset)
				len = length-offset;
			if (len > 4) {
				len -= 4;
				offset += 4;
			}

			while (offset < length && len && px[offset] < 26) {
				offset++;
				len--;
			}

			JOTDOWN(sess->eng->ferret, 
				JOT_SRC("ID-IP",frame),
				JOT_SZ("AIM", "File-Transfer"),
				JOT_PRINT("Filename", px+offset, len),
				0);
			break;
		default:
			/* TODO: SAMPLE this */
			FRAMERR(frame, "%s: unknown\n", "AIM");
			break;
		}

		offset += len;
	}
	
}
Пример #13
0
void parse_aim_oscar(struct TCPRECORD *sess, struct NetFrame *frame, const unsigned char *px, unsigned length)
{
	enum {
		FLAP_START,
		FLAP_CMD_0x2a, FLAP_CHANNEL, FLAP_SEQNO_HI, FLAP_SEQNO_LO,
		FLAP_LENGTH_HI, FLAP_LENGTH_LO, FLAP_LENGTH_DONE,
		FLAP_DATA,
	};
	
	struct AIMPARSER *aim = &sess->layer7.aim;
	unsigned offset=0;


	/* Run the bytes through the state machine */
	while (offset<length)
	switch (aim->flap_state) {
	case FLAP_START:
		memset(aim, 0, sizeof(*aim));
		aim->flap_state++;
		break;
	case FLAP_CMD_0x2a:
		if (px[offset] != 0x2a) {

			/* TEMP: notify on corruption so I can look at some samples */
			FRAMERR(frame, "%s: corrupt", "AIM");

			/* If the first byte isn't the well-known command byte,
			 * then ignore the content and scan forward looking for 
			 * it. */
			FRAMERR(frame, "%s: unknown\n", "AIM");
			offset++;
			while (offset<length) {
				/* scan forward looking for the 0x2a byte */
				while (offset<length && px[offset] != 0x2a)
					offset++;
				if (offset+1<length) {
					if (offset<length && px[offset+1] == 2) {
						break;
					} else
						offset++;
				} else if (offset<length) {
					offset++;
				}
			}
		} else {
			offset++;
			aim->flap_state++;
		}
		break;
	case FLAP_CHANNEL:
		aim->pdu.channel = px[offset++];
		aim->flap_state++;
		break;
	case FLAP_SEQNO_HI:
	case FLAP_SEQNO_LO:
		aim->pdu.seqno <<= 8;
		aim->pdu.seqno |= px[offset++];
		aim->flap_state++;
		break;

	case FLAP_LENGTH_HI:
	case FLAP_LENGTH_LO:
		aim->pdu.length <<= 8;
		aim->pdu.length |= px[offset++];
		aim->flap_state++;
		break;

	case FLAP_LENGTH_DONE:
		aim->remaining = aim->pdu.length;
		aim->snac_state = 0; /*SNAC_START*/
		aim->flap_state++;
		break;
	case FLAP_DATA:
		/* If we still have remaining data in the PDU, then parse it.
		 * Otherwise, just go back and look for a new FLAP PDU header */
		if (aim->remaining) {
			unsigned sublen;

			/* Figure out the segment of data to send to the data parser.
			 * This will be the MIN between the packet size and remaining
			 * data */
			if (aim->remaining < length-offset)
				sublen = aim->remaining;
			else
				sublen = length-offset;

			/* Send it to the appropriate parser, depending upon the 
			 * channel-number and state info */
			switch (aim->pdu.channel) {
			case 2: /*SNAC*/
				parse_aim_snac(sess, frame, px+offset, sublen);
				break;
			default:
				parse_aim_data(sess, frame, px+offset, sublen);
				break;
			}

			/* 'consume' the segment of data. If we have completely
			 * consumed the data, then this will automatically go
			 * back to the starting state to get the next PDU */
			offset += sublen;
			aim->remaining -= sublen;

		}

		/* If we have just parsed the above chunk, we'll probably
		 * go directly here. Note that we need to need to double-check
		 * this at the end of the packet so that house-keeping can more
		 * easily age out connections that are in their default states. */
		if (aim->remaining == 0)
			aim->flap_state = FLAP_START;
		break;

	}
}
Пример #14
0
void process_simple_msnms_server_response(struct Seaper *seap, struct NetFrame *frame, const unsigned char *px, unsigned length)
{
	unsigned offset=0;
	unsigned char cmd[16] = "";
	unsigned i;
	unsigned eol=0;

	/*Find out length of the command line */
	for (eol=0; eol<length && px[eol] != '\n'; eol++)
		;

	skip_whitespace(px, length, &offset);

	/* get command */
	i=0;
	while (offset < length && px[offset] != '\n' && !isspace(px[offset])) {
		if (i<sizeof(cmd)-1) {
			cmd[i++] = px[offset];
			cmd[i] = '\0';
		}
		offset++;
	}
	skip_whitespace(px, length, &offset);

	SAMPLE("MSN-MSGR", "command", REC_SZ, cmd, -1);

	switch (CMD(cmd)) {
    case 0x56455200: /* "VER" */
		while (offset < eol) {
			unsigned parm = offset;
			unsigned parm_length = get_parm(px, length, &offset);

			if (is_number(px+parm, parm_length))
				continue;

			if (equals(px+parm, parm_length, "CVR0"))
				continue;


			/* Syntax:
			 * VER <TrID> <protocol> <protocol> .... 
			 *
			 *	Indicates a list of protocols supported
			 *
			 *  Examples:
			 *		VER 0 MSNP8 CVR0
			 *		VER 0 MSNP8 MYPROTOCOL CVR0
			 */
			process_record(seap,
				"ID-IP",	REC_FRAMESRC,	frame, -1,
				"app",		REC_SZ,			"MSN-MSGR",		-1,
				"ver",		REC_PRINTABLE,	px+parm, parm_length,
				0);
		}				

		break;
    case 0x4e4c4e00: /* "NLN" */
		{
			unsigned state, state_length;
			unsigned handle, handle_length;
			unsigned friendly, friendly_length;

			state = offset;
			state_length = get_parm(px, length, &offset);

			handle = offset;
			handle_length = get_parm(px, length, &offset);

			friendly = offset;
			friendly_length = get_parm(px, length, &offset);

			process_record(seap,
				"proto",	REC_SZ,			"MSN-MSGR", -1,
				"ip",		REC_FRAMEDST,	frame, -1,
				"friend",	REC_PRINTABLE,	px+handle, handle_length,
				"name",		REC_PRINTABLE,	px+friendly, friendly_length,
				"state",	REC_PRINTABLE,	px+state, state_length,
				0);
		}				
		break;
    case 0x514e4700: /* "QNG" */
			process_record(seap,
				"proto",	REC_SZ,			"MSN-MSGR", -1,
				"ip",		REC_FRAMEDST,	frame, -1,
				0);
		break;
    case 0x43565200: /* "CVR" */
		break;
    case 0x55535200: /* "USR" */
		break;
    case 0x4d534700: /* "MSG" */
    case 0x58465200: /* "XFR" */
	default:
		FRAMERR(frame, "msn-ms: unknown commanded from client: %.*s\n", length, px);
	}


	
}
Пример #15
0
Файл: udp.c Проект: OPSF/uClinux
void process_udp(struct Seaper *seap, struct NetFrame *frame, const unsigned char *px, unsigned length)
{
	unsigned offset=0;
	struct {
		unsigned src_port;
		unsigned dst_port;
		unsigned length;
		unsigned checksum;
	} udp;

	if (length == 0) {
		FRAMERR(frame, "udp: frame empty\n");
		return;
	}
	if (length < 8) {
		FRAMERR(frame, "udp: frame too short\n");
		return;
	}

	udp.src_port = ex16be(px+0);
	udp.dst_port = ex16be(px+2);
	udp.length = ex16be(px+4);
	udp.checksum = ex16be(px+6);

	frame->src_port = udp.src_port;
	frame->dst_port = udp.dst_port;

	if (udp.length < 8) {
		FRAMERR_TRUNCATED(frame, "udp");
		return;
	}

	if (length > udp.length)
		length = udp.length;

	offset += 8;

	switch (frame->dst_ipv4) {
	case 0xe0000123: /* 224.0.1.35 - SLP */
		if (udp.dst_port == 427)
			SAMPLE("SLP", "packet",	REC_SZ, "test",-1);
		else
			FRAMERR(frame, "unknown port %d\n", udp.dst_port);
		return;
	}

	SAMPLE("UDP", "src",	REC_UNSIGNED, &udp.src_port, sizeof(udp.src_port));
	SAMPLE("UDP", "dst",	REC_UNSIGNED, &udp.dst_port, sizeof(udp.dst_port));

	switch (udp.src_port) {
	case 68:
	case 67:
		process_dhcp(seap, frame, px+offset, length-offset);
		break;
	case 53:
		process_dns(seap, frame, px+offset, length-offset);
		break;
	case 137:
		process_dns(seap, frame, px+offset, length-offset);
		break;
	case 138:
		process_netbios_dgm(seap, frame, px+offset, length-offset);
		break;
	case 389:
		process_ldap(seap, frame, px+offset, length-offset);
		break;
	case 631:
		if (udp.dst_port == 631) {
			process_cups(seap, frame, px+offset, length-offset);
		}
		break;
	case 1900:
		if (length-offset > 9 && memicmp(px+offset, "HTTP/1.1 ", 9) == 0) {
			process_upnp_response(seap, frame, px+offset, length-offset);
		}
		break;
	case 14906: /* ??? */
		break;
	case 4500:
		break;
	default:
		switch (udp.dst_port) {
		case 0:
			break;
		case 68:
		case 67:
			process_dhcp(seap, frame, px+offset, length-offset);
			break;
		case 53:
		case 5353:
			process_dns(seap, frame, px+offset, length-offset);
			break;
		case 137:
			process_dns(seap, frame, px+offset, length-offset);
			break;
		case 138:
			process_netbios_dgm(seap, frame, px+offset, length-offset);
			break;
		case 1900:
			if (frame->dst_ipv4 == 0xeffffffa)
				process_ssdp(seap, frame, px+offset, length-offset);
			break;
		case 5369:
			break;
		case 29301:
			break;
		case 123:
			break;
		case 5499:
			break;
		case 2233: /*intel/shiva vpn*/
			break;
		case 27900: /* GameSpy*/
			break;
		case 9283:
			process_callwave_iam(seap, frame, px+offset, length-offset);
			break;
		case 161:
			process_snmp(seap, frame, px+offset, length-offset);
			break;
		case 192: /* ??? */
			break;
		case 389:
			process_ldap(seap, frame, px+offset, length-offset);
			break;
		case 427: /* SRVLOC */
			process_srvloc(seap, frame, px+offset, length-offset);
			break;
		case 14906: /* ??? */
			break;
		case 500:
			process_isakmp(seap, frame, px+offset, length-offset);
			break;
		case 2222:
			break;
		default:
			if (frame->dst_ipv4 == 0xc0a8a89b || frame->src_ipv4 == 0xc0a8a89b)
				;
			else
			FRAMERR(frame, "udp: unknown, [%d.%d.%d.%d]->[%d.%d.%d.%d] src=%d, dst=%d\n", 
				(frame->src_ipv4>>24)&0xFF,(frame->src_ipv4>>16)&0xFF,(frame->src_ipv4>>8)&0xFF,(frame->src_ipv4>>0)&0xFF,
				(frame->dst_ipv4>>24)&0xFF,(frame->dst_ipv4>>16)&0xFF,(frame->dst_ipv4>>8)&0xFF,(frame->dst_ipv4>>0)&0xFF,
				frame->src_port, frame->dst_port);
		}
	}

}
Пример #16
0
static void 
dns_parse_question_record(struct Ferret *ferret, struct NetFrame *frame, 
						  const unsigned char *px, unsigned length, 
						  struct DNSRECORD *rec, struct DNS *dns)
{
	char name[512]; /* reserve a longer name than the max theoretical limit */
	unsigned name_length;


	/* If this is actually a bonjour packet, then pass it off to the
	 * Bonjour module */
	if (!dns->is_response && frame->dst_port == 5353)
		bonjour_parse_question_record(ferret, frame, px, length, rec, dns);
	else if (dns->is_response && frame->src_port == 5353) 
		bonjour_parse_question_record(ferret, frame, px, length, rec, dns);

	/* First, let's extract a pretty version of the name */
	name_length = dns_extract_name(frame, px, length, rec->name_offset, name, sizeof(name));

	switch (rec->type<<16 | rec->clss) {
	case TYPECLASS(1,1): /* type=A(IPv4 address), class=INTERNET*/
		if (!is_valid_opcode(dns->opcode, 0, 0x10, -1)) {
			FRAMERR(frame, "%s: unknown opcode=%d\n", "DNS", dns->opcode);
			return;
		}
		JOTDOWN(ferret,
			JOT_SZ("proto","DNS"),
			JOT_SZ("query","A"),
			"ip.src", dns->is_response?REC_FRAMEDST:REC_FRAMESRC,  frame, -1,
			JOT_PRINT("name", name, name_length),
			0);
		break;
	case TYPECLASS(2,1): /* type=NS(name-server), class=INTERNET*/
		if (!is_valid_opcode(dns->opcode, 0x10, -1)) {
			FRAMERR(frame, "%s: unknown opcode=%d\n", "DNS", dns->opcode);
			return;
		}
		JOTDOWN(ferret,
			JOT_SZ("proto","DNS"),
			JOT_SZ("query","NS"),
			"ip.src", dns->is_response?REC_FRAMEDST:REC_FRAMESRC,  frame, -1,
			JOT_PRINT("name", name, name_length),
			0);
		break;
	case TYPECLASS(6,1): /* type=SOA(Start of Authority), class=INTERNET*/
		if (!is_valid_opcode(dns->opcode, 0x10, -1)) {
			FRAMERR(frame, "%s: unknown opcode=%d\n", "DNS", dns->opcode);
			return;
		}
		JOTDOWN(ferret,
			JOT_SZ("proto","DNS"),
			JOT_SZ("query","SOA"),
			"ip.src", dns->is_response?REC_FRAMEDST:REC_FRAMESRC,  frame, -1,
			JOT_PRINT("name", name,	name_length),
			0);
		break;
	case TYPECLASS(10,1): /* type=NULL, class=INTERNET*/
		/* Regress: defcon2008-dns2.pcap(100803): name=Vaaaaiaqaac.tunnel.fastcoder.net */
		/* I'm not sure what this is, other than passing data as Null records.
		 * This would be a good thing for an intrusion-detection system to trigger
		 * on. */
		break;
	case TYPECLASS(12,1): /* type=PTR(pointer, aka. reverse), class=INTERNET*/
		if (!is_valid_opcode(dns->opcode, 0x10, -1)) {
			FRAMERR(frame, "%s: unknown opcode=%d\n", "DNS", dns->opcode);
			return;
		}
		JOTDOWN(ferret,
			JOT_SZ("proto","DNS"),
			JOT_SZ("op","reverse"),
			"ip.src",	dns->is_response?REC_FRAMEDST:REC_FRAMESRC, frame, -1,
			JOT_PRINT("name",		 	name,						name_length),
			0);
		break;
	case TYPECLASS(13,1): /* type=HINFO, class=INTERNET*/
		/* Regress: defcon2008-dns2.pcap(292428) */
		break;
	case TYPECLASS(15,1): /* type=MX, class=INTERNET*/
		/* Regress: defcon2008-dns2.pcap(18661) */
		break;
	case TYPECLASS(16,1): /* type=TXT(text), class=INTERNET*/
		/* CASE: I see these in mDNS. A machine sends out a query for a
		 * record to the multi-cast address right before it then multi-casts
		 * the answer. I don't think there is anything useful to extract here
		 * at this time */

		if (!is_valid_opcode(dns->opcode, OP_QUERY, 0x10, -1)) {
			FRAMERR(frame, "%s: unknown opcode=%d\n", "DNS", dns->opcode);
			return;
		}
		break;
	case TYPECLASS(35,1): /* type=NAPTR(naming authority pointer), class=INTERNET*/
		if (!is_valid_opcode(dns->opcode, OP_QUERY, 0x10, -1)) {
			FRAMERR(frame, "%s: unknown opcode=%d\n", "DNS", dns->opcode);
			return;
		}
		/* Reference: defcon2008-dns2.pcap(277617) */
		break;
	case TYPECLASS(0x1c,1): /* type=AAAA(IPv6 address), class=INTERNET*/
		if (!is_valid_opcode(dns->opcode, 0x10, -1)) {
			FRAMERR(frame, "%s: unknown opcode=%d\n", "DNS", dns->opcode);
			return;
		}
		JOTDOWN(ferret,
			JOT_SZ("proto","DNS"),
			JOT_SZ("query","AAAA"),
			"ip.src", dns->is_response?REC_FRAMEDST:REC_FRAMESRC,  frame, -1,
			JOT_PRINT("name", name, name_length),
			0);
		break;
	case TYPECLASS(0x1c,0x8001): /* type=AAAA(IPv6 address), class=mDNS-FLUSH*/
		if (!is_valid_opcode(dns->opcode, -1)) {
			FRAMERR(frame, "%s: unknown opcode=%d\n", "DNS", dns->opcode);
			return;
		}
		/* TODO: move this to the mDNS-Bonjour parser */
		JOTDOWN(ferret,
			JOT_SZ("proto","MDNS"),
			JOT_SZ("query","AAAA"),
			"ip.src", dns->is_response?REC_FRAMEDST:REC_FRAMESRC,  frame, -1,
			JOT_PRINT("flush", name, name_length),
			0);
		break;
	case TYPECLASS(0x21,1): /* type=SRV(Service Location), class=INTERNET*/
		if (!is_valid_opcode(dns->opcode, OP_QUERY, 0x10, -1)) {
			FRAMERR(frame, "%s: unknown opcode=%d\n", "DNS", dns->opcode);
			return;
		}
		JOTDOWN(ferret,
			JOT_SZ("proto","DNS"),
			JOT_SZ("query","srv"),
			"ip.src", dns->is_response?REC_FRAMEDST:REC_FRAMESRC,  frame, -1,
			JOT_PRINT("name",		 	name,						name_length),
			0);
		break;
	/*case TYPECLASS(255,1):*/ /* type=ANY, class=INTERNET*/
	case TYPECLASS(255,0x8001): /* type=ANY, class=FLUSH(mDNS/Bonjour)*/
		if (!is_valid_opcode(dns->opcode, -1)) {
			FRAMERR(frame, "%s: unknown opcode=%d\n", "DNS", dns->opcode);
			return;
		}
		JOTDOWN(ferret,
			JOT_SZ("proto","DNS"),
			JOT_SZ("op","flush"),
			"ip.src",	dns->is_response?REC_FRAMEDST:REC_FRAMESRC, frame, -1,
			JOT_PRINT("name",		 	name,						name_length),
			0);
		if (endsWith(name, "._ipp._tcp.local")) {
			JOTDOWN(ferret,
				"Bonjour",	dns->is_response?REC_FRAMEDST:REC_FRAMESRC, frame, -1,
				JOT_PRINT("Printer", name, name_length-strlen("._ipp._tcp.local")),
				0);
		} else if (endsWith(name, ".local"))
			JOTDOWN(ferret,
				"ID-IP",	dns->is_response?REC_FRAMEDST:REC_FRAMESRC, frame, -1,
				JOT_PRINT("name",		 	name,						name_length-strlen(".local")),
				0);
		else
			FRAMERR(frame, "%s: unknown value: %s\n", "dns", name);

		break;
	case TYPECLASS(255,1): /* type=ANY, class=INTERNET*/
		if (!is_valid_opcode(dns->opcode, 0, 0x10, -1)) {
			FRAMERR(frame, "%s: unknown opcode=%d\n", "DNS", dns->opcode);
			return;
		}
		JOTDOWN(ferret,
			JOT_SZ("proto","DNS"),
			JOT_SZ("query","ANY"),
			"ip.src", dns->is_response?REC_FRAMEDST:REC_FRAMESRC,  frame, -1,
			JOT_PRINT("name", name, name_length),
			0);
		break;
	default:
		FRAMERR(frame, "dns: unknown [type=0x%x(%d), class=0x%x(%d)] name=%s)\n", 
				rec->type, rec->type, 
				rec->clss, rec->clss, 
				name);
	}
}
Пример #17
0
/**
 * This is the main function of the DNS parser.
 *
 * This is where the each DNS 'answer' (or 'additional' or 'authoritative') 
 * record is parsed. Mostly, we ignore the return code, though some functions
 * pay attention to and provide slightly different information depending
 * upon the opcode.
 */
static void 
dns_parse_resource_record(struct Ferret *ferret, struct NetFrame *frame, 
						  const unsigned char *px, unsigned length, 
						  struct DNSRECORD *rec, struct DNS *dns)
{
	char name[512]; /* reserve a longer name than the max theoretical limit */
	unsigned name_length;
	char name2[512]; /* reserve a longer name than the max theoretical limit */
	unsigned name2_length;
	unsigned ip_address;
	unsigned offset = rec->rdata_offset;
	unsigned offset_max = MIN(rec->rdata_offset+rec->rdata_length, length);

	/* MULTICAST DNS (mDNS): handle the multicast DNS records differently
	 * from normal DNS records. */
	if (!dns->is_response && frame->dst_port == 5353) {
		bonjour_parse_resource_record(ferret, frame, px, length, rec, dns);
		return; 
	} else if (dns->is_response && (frame->src_port == 5353 || (frame->dst_port == 5353 && frame->src_port != 53))) {
		bonjour_parse_resource_record(ferret, frame, px, length, rec, dns);
		return;
	}

	/* NETBIOS: handle NetBIOS records differently from normal DNS records */
	if (!dns->is_response && frame->dst_port == 137) {
		netbios_parse_resource_record(ferret, frame, px, length, rec, dns);
		return; 
	} else if (dns->is_response && frame->src_port == 137) {
		netbios_parse_resource_record(ferret, frame, px, length, rec, dns);
		return;
	}


	/* First, let's extract a pretty version of the name */
	name_length = dns_extract_name(frame, px, length, rec->name_offset, name, sizeof(name));
	
	if (rec->type == 0x8001)
		FRAMERR(frame, "TODO\n");

	if (rec->clss == 0xfe)
		return;

	/* RFC2671 - Extension Mechanisms for DNS (EDNS0) */
	if (rec->type == 41) {
		/* Regress: defcon2008/dump000.pca(12541) */
		/* TODO: parse this */
		return;
	}

	/* Haven't implemented dynamic update yet
	 * TODO: */
	if (dns->opcode == 21 || dns->opcode == 5)
		return;

	switch (rec->type<<16 | rec->clss) {
	case TYPECLASS(1,0x8001): /* type=A(IPv4 address), class=INTERNET(cache flush) */
		bonjour_parse_resource_record(ferret, frame, px, length, rec, dns);
		break;
	case TYPECLASS(1,1): /* type=A(IPv4 address), class=INTERNET */
		if (!is_valid_opcode(dns->opcode, 0x10, 5, -1)) {
			FRAMERR(frame, "%s: unknown opcode=%d\n", "DNS", dns->opcode);
			return;
		}

		ip_address = ex32be(px+rec->rdata_offset);
		if (rec->rdata_length != 4)
			FRAMERR(frame, "dns: data not 4-bytes long, was %d-bytes instead (class=%d, type=%d, name=%s)\n", rec->rdata_length, rec->clss, rec->type, name);

		JOTDOWN(ferret,
			JOT_PRINT("ID-DNS", name,	name_length),
			JOT_IPv4("address",	ip_address),
			0);
		break;
	case TYPECLASS(2,1): /* type=NS, class=INTERNET */
		if (!is_valid_opcode(dns->opcode, 0x10, -1)) {
			FRAMERR(frame, "%s: unknown opcode=%d\n", "DNS", dns->opcode);
			return;
		}
		name2_length = dns_extract_name(frame, px, length, rec->rdata_offset, name2, sizeof(name2));
		ip_address = dns_resolve_alias(frame, px, length, dns, name2, 0);

		JOTDOWN(ferret,
			JOT_PRINT("ID-DNS",	name, name_length),
			JOT_PRINT("Name-Server", name2, name2_length),
			JOT_IPv4("address", ip_address),
			0);
		break;
	case TYPECLASS(5,1): /*type=CNAME(aliased canonical name), class=INTERNET */
		if (!is_valid_opcode(dns->opcode, 0x10, 5, -1)) {
			FRAMERR(frame, "%s: unknown opcode=%d\n", "DNS", dns->opcode);
			return;
		}
		name2_length = dns_extract_name(frame, px, length, rec->rdata_offset, name2, sizeof(name2));

		ip_address = dns_resolve_alias(frame, px, length, dns, name2, 0);

		if (ip_address != 0) {
			JOTDOWN(ferret,
				JOT_PRINT("ID-DNS", name,	name_length),
				JOT_IPv4("alias",ip_address),
				0);
		}
		JOTDOWN(ferret,
			JOT_PRINT("ID-DNS", name,	name_length),
			JOT_PRINT("alias", name2, name2_length),
			0);
		break;
	case TYPECLASS(6,1): /*type=SOA, class=INTERNET*/
		if (!is_valid_opcode(dns->opcode, 0x10, -1)) {
			FRAMERR(frame, "%s: unknown opcode=%d\n", "DNS", dns->opcode);
			return;
		}
		/*
		 * Authoritative Name Server
		 */
		name2_length = dns_extract_name(frame, px, length, offset, name2, sizeof(name2));
		JOTDOWN(ferret,
			JOT_PRINT("ID-DNS",	name, name_length),
			JOT_SZ("SOA", "Start of zone authority"),
			JOT_PRINT("Name-Server", name2, name2_length),
			0);
		ip_address = dns_resolve_alias(frame, px, length, dns, name2, 0);
		if (ip_address)
		JOTDOWN(ferret,
			JOT_PRINT("ID-DNS",	name, name_length),
			JOT_SZ("SOA", "Start of zone authority"),
			JOT_PRINT("Name-Server", name2, name2_length),
			JOT_IPv4("address", ip_address),
			0);
		skip_name(px, length, &offset);

		/* Contact */
		if (offset < offset_max) {
			name2_length = dns_extract_name(frame, px, length, offset, name2, sizeof(name2));
			JOTDOWN(ferret,
				JOT_PRINT("ID-DNS",	name, name_length),
				JOT_SZ("SOA", "Start of zone authority"),
				JOT_PRINT("Contact", name2, name2_length),
				0);
			skip_name(px, length, &offset);
		}

		break;
	case TYPECLASS(10,1): /* type=NULL, class=INTERNET*/
		/* Regress: defcon2008-dns2.pcap(100803): name=Vaaaaiaqaac.tunnel.fastcoder.net */
		/* I'm not sure what this is, other than passing data as Null records.
		 * This would be a good thing for an intrusion-detection system to trigger
		 * on. */
		break;
	case TYPECLASS(12,0x8001): /*type=PTR, class=INTERNET */
		bonjour_parse_resource_record(ferret, frame, px, length, rec, dns);
		break;
	case TYPECLASS(12,1): /*type=PTR(pointer reverse lookup), class=INTERNET */
		if (!is_valid_opcode(dns->opcode, 0x10, -1)) {
			FRAMERR(frame, "%s: unknown opcode=%d\n", "DNS", dns->opcode);
			return;
		}
		if (name_length > 6 && memcmp(name+name_length-6, ".local", 6) == 0) {

			JOTDOWN(ferret,
				JOT_SRC("ID-IP", frame),
				JOT_PRINT("Service", name,name_length),
				0);

			/* Extract MAC address */
			{
				const unsigned char *p_name;
				unsigned name_length;
				const unsigned char *p_mac = find_mac(px, MIN(length, rec->rdata_offset+rec->rdata_length), rec->rdata_offset, &p_name, &name_length);
				if (p_mac) {
					JOTDOWN(ferret,
						JOT_SRC("ID-IP", frame),
						JOT_PRINT("mac",		 	p_mac,						19),
						0);
					JOTDOWN(ferret,
						JOT_SRC("ID-IP", frame),
						JOT_PRINT("name",		 	p_name,						name_length),
						0);
				}
			}

		} else if (endsWith(name, ".in-addr.arpa")) {
			/* Extract a 4-byte IPv4 address 
			 * Example: "18.0.0.10.in-addr.arpa"*/
			unsigned ipv4=0;
			unsigned i;
			unsigned j=0;

			for (i=0; i<4; i++) {
				unsigned num = 0;

				for (; name[j] && name[j] != '.'; j++) {
					if ('0' <= name[j] && name[j] <= '9')
						num = num * 10 + name[j]-'0';
				}
				while (name[j] == '.')
					j++;
				ipv4 |= num<<(i*8);
			}
			/* Now get the name it points to */
			name2_length = dns_extract_name(frame, px, length, offset, name2, sizeof(name2));

			JOTDOWN(ferret,
				JOT_PRINT("ID-DNS", name2, name2_length),
				JOT_IPv4("ID-IP", ipv4),
				JOT_SRC("dnssrv", frame),
				0);
		} else
			; //FRAMERR(frame, "dns: unknown PTR record\n");
		break;
	case TYPECLASS(13,0x8001): /*type=HINFO, class=INTERNET */
		bonjour_parse_resource_record(ferret, frame, px, length, rec, dns);
		break;
	case TYPECLASS(15,1): /*type=MX, class=INTERNET */
		/* Regress: defcon2008-dns2.pcap(18661) */
		break;
	case TYPECLASS(16,0x8001):		/*type=TXT, class=INTERNET(cache flush)*/
		bonjour_parse_resource_record(ferret, frame, px, length, rec, dns);
		break;
	case TYPECLASS(16,1):		/*type=TXT, class=INTERNET */
		if (!is_valid_opcode(dns->opcode, 0x10, 5, -1)) {
			FRAMERR(frame, "%s: unknown opcode=%d\n", "DNS", dns->opcode);
			return;
		}

		if (stricmp(name, "current.cvd.clamav.net") == 0) {
			/* This is a single string containing a version string, like:
			 * 0.91.1:44:3855:1186270141:1
			 */
			break;
		} else if (starts_with("_DM-NOTIFICATION.", name, strlen(name))) {
			/* Regress: defcon2008\dump001.pcap(87082) */
			/* TODO */
			break;
		} else if (endsWith(name, "._workstation._tcp.local")) {
			/* Regress: defcon2008-dns2.pcap(56127): "mike-desktop [00:0c:29:f6:58:ca]._workstation._tcp.local" */
			break;
		} else if (endsWith(name, ".asn.cymru.com")) {
			/* Regress: defcon2008-dns2.pcap(98958) */
			/* This is a system for mapping IP to ASN numbers:
			 * http://www.team-cymru.org/Services/ip-to-asn.html */
			break;
		} else if (endsWith(name, ".wrs.trendmicro.com")) {
			/* Regress: defcon2008-dns2.pcap(184904) */
			/* Appears to check whether IP addresses are trustworthy */
			break;
		} else {
			FRAMERR(frame, "%s: unknown TXT record %s", "DNS", name);
		}
		break;
	case TYPECLASS(0x1c,1): /*type=AAAA(IPv6 address), class=INTERNET*/
	case TYPECLASS(0x1c,255): /*type=AAAA(IPv6 address), class=INTERNET*/
		if (!is_valid_opcode(dns->opcode, 0x10, 5, -1)) {
			FRAMERR(frame, "%s: unknown opcode=%d\n", "DNS", dns->opcode);
			return;
		}
		switch (dns->opcode) {
		case 0x10:
			{
				const unsigned char *ipv6_address = px+rec->rdata_offset;
				if (rec->rdata_length != 16)
					FRAMERR(frame, "dns: data not 16-bytes long, was %d-bytes instead (class=%d, type=%d, name=%s)\n", rec->rdata_length, rec->clss, rec->type, name);

				JOTDOWN(ferret,
					JOT_SZ("proto","DNS"),
					JOT_SZ("op","lookup"),
					JOT_SRC("ip.src", frame),
					JOT_PRINT("name", name, name_length),
					JOT_IPv6("address", ipv6_address,				16),
					0);
			}
		case 5: /* dynamic update*/
			/* Regress: defcon2008-dns2.pcap(7958) */
			break;
		default:
			FRAMERR(frame, "%s: unknown opcode=%d\n", "DNS", dns->opcode);
		}
		break;
	case TYPECLASS(33,1): /*type=SRV, class=INTERNET */
		if (!is_valid_opcode(dns->opcode, 0x10, -1)) {
			FRAMERR(frame, "%s: unknown opcode=%d\n", "DNS", dns->opcode);
			return;
		}

		if (rec->rdata_length < 7)
			FRAMERR(frame, "dns: unknown type=%d (class=%d, name=%s)\n", rec->type, rec->clss, name);
		else {
			unsigned port = px[rec->rdata_offset+4]<<8 | px[rec->rdata_offset+5];
			name2_length = dns_extract_name(frame, px, length, rec->rdata_offset+6, name2, sizeof(name2));
			ip_address = dns_resolve_alias(frame, px, length, dns, name2, 0);

			if (ip_address != 0) {
				JOTDOWN(ferret,
					JOT_PRINT("ID-DNS", name,	name_length),
					JOT_PRINT("Server", name2,	name2_length),
					JOT_NUM("Port", port),
					JOT_IPv4("IPv4",ip_address),
					0);
			} else
				JOTDOWN(ferret,
					JOT_PRINT("ID-DNS", name,	name_length),
					JOT_PRINT("Server", name2,	name2_length),
					JOT_NUM("Port", port),
					0);
		}
		break;
	default:
		FRAMERR(frame, "dns: unknown type=%d (class=%d, name=%s)\n", rec->type, rec->clss, name);
	}
}
Пример #18
0
void process_dhcp(struct Seaper *seap, struct NetFrame *frame, const unsigned char *px, unsigned length)
{
	unsigned offset;
	struct DHCP dhcp;

	memset(&dhcp, 0, sizeof(dhcp));
	if (length < 200) {
		FRAMERR(frame, "dhcp: frame too short\n");
		return;
	}

	dhcp.op = px[0];
	dhcp.hardware_type = px[1];
	dhcp.hardware_address_length = px[2];
	dhcp.hops = px[3];

	dhcp.transaction_id = ex32be(px+4);
	dhcp.seconds_elapsed = ex16be(px+8);
	dhcp.flags = ex16be(px+10);

	dhcp.ciaddr = ex32be(px+12);
	dhcp.yiaddr = ex32be(px+16);
	dhcp.siaddr = ex32be(px+20);
	dhcp.giaddr = ex32be(px+24);

	memcpy(dhcp.chaddr, px+28, 16);
	dhcp.chaddr[16] = '\0';

	memcpy(dhcp.sname, px+28+16, 64);
	dhcp.sname[64] = '\0';

	memcpy(dhcp.file, px+28+16+64, 128);
	dhcp.file[128] = '\0';

	offset = 28+16+64+128;

	if (offset+4 > length)
		return;

	if (memcmp(px+offset, "\x63\x82\x53\x63", 4) != 0)
		return;
	offset += 4;

	/* Process special options */
	dhcp.msg = dhcp_number(px, length, 53);
	switch (dhcp.msg) {
	case 8: /* inform */
		/* Process vendor specific information */
		{
			const unsigned char *spec;
			unsigned spec_length;
			const unsigned char *id;
			unsigned id_length;

			dhcp_get_option(px, length, 43, &spec, &spec_length);
			dhcp_get_option(px, length, 60, &id, &id_length);

			if (spec_length && id_length) {
				process_record(seap,
					"application",	REC_PRINTABLE, id, id_length,
					"info",			REC_PRINTABLE, spec, spec_length,
					0);
			}
		}
	}



	process_dhcp_options(seap, frame, px, length, offset, &dhcp);

	if (dhcp.overload_filename)
		process_dhcp_options(seap, frame, px, 28+16+64+128, 28+16+64, &dhcp);
	if (dhcp.overload_servername)
		process_dhcp_options(seap, frame, px, 28+16+64, 28+16, &dhcp);

	SAMPLE("BOOTP", "type",	REC_UNSIGNED, &dhcp.op,	sizeof(dhcp.op));
	switch (dhcp.op) {
	case 1: /*BOOTP request */
		break;
	case 2: /*BOOTP reply*/ 
		switch (dhcp.msg) {
		case 2:
			break;
		case 5: /*ack*/
			break;
		case 6: /*DHCP NACK*/
			{
				const unsigned char *dst_mac;
				unsigned src_ip;

				if (dhcp.hardware_address_length != 6) {
					FRAMERR(frame, "dhcp: expected hardware address length = 6, found length = %d\n", dhcp.hardware_address_length);
					break;
				}
				if (memcmp(dhcp.chaddr, "\0\0\0\0\0\0", 6) == 0) {
					FRAMERR(frame, "dhcp: expected hardware address, but found [00:00:00:00:00:00]\n");
					break;
				} else
					dst_mac = &dhcp.chaddr[0];

				if (dhcp.server_identifier)
					src_ip = dhcp.server_identifier;
				else if (dhcp.siaddr)
					src_ip = dhcp.siaddr;
				else
					src_ip = frame->src_ipv4;

				process_record(seap,
					"proto",	REC_SZ,			"DHCP",		-1,
					"op",		REC_SZ,			"NACK",		-1,
					"src.ip",	REC_IPv4,		&src_ip,	sizeof(src_ip),
					"dst.mac",	REC_MACADDR,	dst_mac,	6,
					0);
			}
			break;
		case 8:
			break;
		default:
			FRAMERR(frame, "dhcp: unknown dhcp msg type %d\n", dhcp.msg);
			break;
		}
		break;
	default:
			FRAMERR(frame, "dhcp: unknown bootp op code %d\n", dhcp.op);
		break;

	}

}
Пример #19
0
void process_tcp(struct Ferret *ferret, struct NetFrame *frame, const unsigned char *px, unsigned length)
{
	struct {
		unsigned src_port;
		unsigned dst_port;
		unsigned seqno;
		unsigned ackno;
		unsigned header_length;
		unsigned flags;
		unsigned window;
		unsigned checksum;
		unsigned urgent;
	} tcp;

	ferret->statistics.tcp++;

	if (length == 0) {
		FRAMERR(frame, "tcp: frame empty\n");
		return;
	}
	if (length < 20) {
		FRAMERR(frame, "tcp: frame too short\n");
		return;
	}

/*
	    0                   1                   2                   3   
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |          Source Port          |       Destination Port        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                        Sequence Number                        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    Acknowledgment Number                      |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |  Data |           |U|A|P|R|S|F|                               |
   | Offset| Reserved  |R|C|S|S|Y|I|            Window             |
   |       |           |G|K|H|T|N|N|                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |           Checksum            |         Urgent Pointer        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    Options                    |    Padding    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                             data                              |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/

	tcp.src_port = ex16be(px+0);
	tcp.dst_port = ex16be(px+2);
	tcp.seqno = ex32be(px+4);
	tcp.ackno = ex32be(px+8);
	tcp.header_length = px[12]>>2;
	tcp.flags = px[13];
	tcp.window = ex16be(px+14);
	tcp.checksum = ex16be(px+16);
	tcp.urgent = ex16be(px+18);

	frame->src_port = tcp.src_port;
	frame->dst_port = tcp.dst_port;

	if (tcp.header_length < 20) {
		/* Regress: defcon2008\dump027.pcap(39901) */
		//FRAMERR(frame, "tcp: header too short, expected length=20, found length=%d\n", tcp.header_length);
		return;
	}
	if (tcp.header_length > length) {
		//FRAMERR(frame, "tcp: header too short, expected length=%d, found length=%d\n", tcp.header_length, length);
		return;
	}
	if ((tcp.flags & 0x20) && tcp.urgent > 0) {
		FRAMERR(frame, "tcp: found %d bytes of urgent data\n", tcp.urgent);
		return;
	}

	/* Check the checksum */
	if (!validate_tcp_checksum(px, length, frame->src_ipv4, frame->dst_ipv4)) {
		/* Regress: defcon2008-msnmsgr.pcap(24066) */
		ferret->statistics.errs_tcp_checksum++;		
		return;
	}

	/*TODO: need to check checksum */

	if (tcp.header_length > 20) {
		unsigned o = 20;
		unsigned max = tcp.header_length;

		while (o < tcp.header_length) {
			unsigned tag = px[o++];
			unsigned len;

			if (tag == 0)
				break;
			if (tag == 1)
				continue;

			if (o >= max) {
				FRAMERR(frame, "tcp: options too long\n");
				break;
			}
			len = px[o++];

			if (len < 2) {
				FRAMERR(frame, "tcp: invalid length field\n");
				break;
			}
			if (o+len-2 > max) {
				FRAMERR(frame, "tcp: options too long\n");
				break;
			}

			switch (tag) {
			case 0x02: /* max seg size */
				if (len != 4)
					FRAMERR(frame, "tcp: unknown length: option=%d, length=%d\n", tag, len);
				break;
			case 0x04: /* SACK permitted */
				if (len != 2)
					FRAMERR(frame, "tcp: unknown length: option=%d, length=%d\n", tag, len);
				break;
			case 0x05: /* SACK */
				break;
			case 0x08: /*timestamp*/
				break;
			case 0x03: /*window scale*/
				break;
			default:
				FRAMERR(frame, "tcp: unknown option=%d, length=%d\n", tag, len);
			}

			o += len-2;
		}
	}


	SAMPLE(ferret,"TCP", JOT_NUM("flags", tcp.flags));

	/* Process an "acknowledgement". Among other things, this will identify
	 * when packets have been missed: if the other side claims to have
	 * received a packet, but we never saw it, then we know that it was
	 * dropped somewhere on the network (probably because we are getting
	 * a weak signal via wireless). */
	if (tcp.flags & TCP_ACK) {
		tcp_ack_data(ferret, frame, tcp.ackno);
	}

	switch (tcp.flags & 0x3F) {
	case TCP_SYN:
		tcp_syn(ferret, frame);
		break;
	case TCP_SYN|TCP_ACK:
		tcp_synack(ferret, frame);
		break;
	case TCP_FIN:
	case TCP_FIN|TCP_ACK:
	case TCP_FIN|TCP_ACK|TCP_PSH:
		tcp_fin(ferret, frame);
		break;
	case TCP_ACK:
	case TCP_ACK|TCP_PSH:
		if (length > tcp.header_length)
			tcp_data(ferret, frame, px+tcp.header_length, length-tcp.header_length, tcp.seqno, tcp.ackno);
		break;
	case TCP_RST:
	case TCP_RST|TCP_ACK:
		break;
	case 0x40|TCP_ACK:
		break;
	case TCP_RST|TCP_ACK|TCP_FIN:
	case TCP_RST|TCP_ACK|TCP_PSH:
		break;
	default:
		FRAMERR(frame, "tcp: unexpected combo of flags: 0x%03x\n", tcp.flags);
	}
}
Пример #20
0
static void
tcp_data_parse(struct TCPRECORD *sess, struct NetFrame *frame, const unsigned char *px, unsigned length, unsigned seqno, unsigned is_frag)
{
	unsigned i;

	/*
	 * MISSING FRAGMENT
	 * 
	 * This tests to see if there is a discontinuity. If the current seqno
	 * is greater than the next-expected-seqno, then we have a missing
	 * fragment somewhere. Therefore, we need to add the fragment to the 
	 * queue to be processed when (if ever) the missing fragment arrives
	 */
	if (SEQ_FIRST_BEFORE_SECOND(sess->seqno, seqno)) {

		if (SEQ_FIRST_BEFORE_SECOND(sess->seqno+1999000, seqno)) {
			/* This fragment is too far in the future, so discard it */
			FRAMERR(frame, "tcp: orphan fragment\n");
			/* defcon2008/dump002.pcap(93562)
			 * This packet goes over 100,000 bytes in the future passed
			 * missed fragment before retransmitting it */
			return;
		}

		/* Don't remember this fragment if it's coming from the remembered
		 * fragment queue */
		if (is_frag)
			return;

		/* Remeber this segment so that we can process it later when we 
		 * get something appropriate. */
		tcpfrag_add(&(sess->segments), px, length, seqno);
		return;

	}
	
	
	/* 
	 * PREVIOUS FRAGMENT and RETRANSMISSION
	 *
	 * This tests to see end of this fragment is a sequence number that
	 * we've already processed. This will be the case on repeated
	 * transmissions of the same packet as well.
	 */
	if (SEQ_FIRST_BEFORE_SECOND(seqno+length, sess->seqno) || seqno+length == sess->seqno) {
		/* This fragment is completely before the current one, therefore
		 * we can completely ignore it */
		return;
	}


	/* 
	 * OVERLAPPING FRAGMENT 
	 *
	 * This tests the case where the current fragment starts somewhere
	 * in the middle of something we've already processed. There is still
	 * some new data, so we just ignore the old bit.
	 */
	if (SEQ_FIRST_BEFORE_SECOND(seqno, sess->seqno)) {
		/* Regress: ferret-regress-00001-tcp-overlap.pcap frame 20 */
		unsigned sublen = sess->seqno - seqno;
		seqno += sublen;
		length -= sublen;
		px += sublen;
	}


	/* TEMP: change this to an assert */
	if (sess->seqno != seqno)
		FRAMERR(frame, "programming error\n");

	/*
	 * PARSE THE DATA WITH A PROTOCOL PARSER
	 */
	if (sess->parser)
		sess->parser(sess, frame, px, length);
	sess->seqno = seqno+length;

	/* STRING RE-ASSEMBLER:
	 *	If we are in the middle of parsing a string from the packet,
	 *  then it's currently pointing into the packet that's about to
	 *	disappear. Therefore, we need to allocate a backing store
	 *	for it that will be preserved along with the TCP stream so
	 *	that the packet can disappear */
	for (i=0; i<sizeof(sess->str)/sizeof(sess->str[0]); i++) {
		if (sess->str[i].length && sess->str[i].backing_store == NULL)
			strfrag_force_backing_store(&sess->str[i]);
	}

}
Пример #21
0
/*
 * Cisco Discovery Protocol 
 */
static void 
parse_CDP(struct Ferret *ferret, struct NetFrame *frame, const unsigned char *px, unsigned length)
{
	unsigned offset=0;
	unsigned version;
	//unsigned ttl;
	//unsigned checksum;

	if (offset+4 > length) {
		FRAMERR(frame, "%s: truncated\n", "cisco");
		return;
	}

	frame->layer3_protocol = LAYER3_MGMT;

	version = px[offset++];
	//ttl = px[offset++];
	//checksum = ex16be(px+2);
	offset += 2;

	SAMPLE(ferret,"Cisco Discovery Protocol", 
		JOT_NUM("version",version));

	while (offset < length) {
		unsigned tag;
		unsigned len;
		unsigned i;

		if (offset+4 > length) {
			FRAMERR(frame, "%s: truncated\n", "cisco");
			return;
		}

		tag = ex16be(px+offset);
		len = ex16be(px+offset+2);
		offset += 4;

		if (len < 4) {
			FRAMERR(frame, "%s: bad value: 0x%x\n", "cdp", tag);
			return;
		} else
			len -= 4;

		if (len > length-offset)
			len = length-offset;
		
		SAMPLE(ferret,"Cisco Discovery Protocol", JOT_NUM("tag",  tag));

		switch (tag) {
		case 0x0000:
			return;
		case 0x0001: /* Device ID */
			JOTDOWN(ferret, 
				JOT_MACADDR("ID-MAC", frame->src_mac),
				JOT_PRINT("Cisco Device ID", px+offset,len),
				0);
			break;
		case 0x0002: /* Addresses */
			if (len < 4) {
				FRAMERR(frame, "%s: truncated\n", "cdp");
				break;
			}
			i=0;
			{
				unsigned address_count = ex32be(px+offset);

				i += 4;

				while (address_count && i<len) {
					unsigned protocol_type;
					unsigned protocol_length;
					unsigned protocol = 0;
					unsigned address_length;
					if (i-len < 5)
						break;
					address_count--;

					protocol_type = px[offset+i++];
					protocol_length = px[offset+i++];
					if (protocol_length != 1)
						FRAMERR(frame, "%s: unknown value: 0x%x\n", "cdp", protocol_length);
					while (protocol_length && i<len) {
						protocol <<= 8;
						protocol |= px[offset+i++];
						protocol_length--;
					}
					address_length = ex16be(px+offset+i);
					i+= 2;
					switch (protocol_type) {
					case 1:
						switch (protocol) {
						case 0xCC: /*IPv4 address */
							if (address_length != 4)
								FRAMERR(frame, "%s: unknown value: 0x%x\n", "cdp", address_length);
							else if (len-i < 4)
								FRAMERR(frame, "%s: truncated\n", "cdp");
							else {
								unsigned ip = ex32be(px+offset+i);
								JOTDOWN(ferret, 
									JOT_MACADDR("ID-MAC", frame->src_mac),
									JOT_IPv4("ip", ip),
									0);
								JOTDOWN(ferret, 
									JOT_IPv4("ID-IP", ip),
									JOT_MACADDR("mac", frame->src_mac),
									0);
							}
							break;
						default:
							SAMPLE(ferret,"CDP", JOT_NUM("ip-protocol-type",  protocol));
							FRAMERR(frame, "%s: unknown value: 0x%x\n", "cdp", protocol);
						}
						break;
					default:
						SAMPLE(ferret,"CDP", JOT_NUM("address-protocol-type",  protocol_type));
						FRAMERR(frame, "%s: unknown value: 0x%x\n", "cdp", protocol_type);
						break;
					}
				}
			}


			break;
		case 0x0003: /* Port ID*/
			JOTDOWN(ferret, 
				JOT_MACADDR("ID-MAC", frame->src_mac),
				JOT_PRINT("Cisco Port ID", px+offset,len),
				0);
			break;
		case 0x0004:
			{
				unsigned n = 0;

				for (i=0; i<len; i++) {
					n <<= 8;
					n |= px[offset + i];
				}
				if (n & 0x00000001)
					JOTDOWN(ferret, JOT_MACADDR("ID-MAC", frame->src_mac), JOT_SZ("Capabilities", "router"), 0);
				if (n & 0x00000002)
					JOTDOWN(ferret, JOT_MACADDR("ID-MAC", frame->src_mac), JOT_SZ("Capabilities", "bridge"), 0);
				if (n & 0x00000004)
					JOTDOWN(ferret, JOT_MACADDR("ID-MAC", frame->src_mac), JOT_SZ("Capabilities", "source route bridge"), 0);
				if (n & 0x00000008)
					JOTDOWN(ferret, JOT_MACADDR("ID-MAC", frame->src_mac), JOT_SZ("Capabilities", "switch"), 0);
				if (n & 0x00000010)
					JOTDOWN(ferret, JOT_MACADDR("ID-MAC", frame->src_mac), JOT_SZ("Capabilities", "host"), 0);
				if (n & 0x00000020)
					JOTDOWN(ferret, JOT_MACADDR("ID-MAC", frame->src_mac), JOT_SZ("Capabilities", "IGMP"), 0);
				if (n & 0x00000040)
					JOTDOWN(ferret, JOT_MACADDR("ID-MAC", frame->src_mac), JOT_SZ("Capabilities", "repeater"), 0);
			}
			break;
		case 0x0005: /* IOS Version */
			for (i=0; i<len; i++)
				if (!isspace(px[offset+i]))
					break;
			JOTDOWN(ferret, 
				JOT_MACADDR("ID-MAC", frame->src_mac),
				JOT_PRINT("IOS Version", px+offset+i,len-i),
				0);
			break;
		case 0x0006: /* Platform*/
			JOTDOWN(ferret, 
				JOT_MACADDR("ID-MAC", frame->src_mac),
				JOT_PRINT("Cisco Platform", px+offset,len),
				0);
			break;
		case 0x0008: /* Hello: cluster mgmt */
			break;
		case 0x0009: /* VTP mgmnt domain */
			JOTDOWN(ferret, 
				JOT_MACADDR("ID-MAC", frame->src_mac),
				JOT_PRINT("VTP Mgmt Domain", px+offset,len),
				0);
			break;
		case 0x000a: /* Native VLAN */
			break;
		case 0x000b: /* Duplex */
			break;
		case 0x0012: /* Trust Bitmap */
			break;
		case 0x0013: /* Untrusted Port CoS */
			break;
		case 0x0016: /* Management Addresses */
			/* TODO: decode the management addresses */
			break;
		default:
			FRAMERR(frame, "%s: unknown value: 0x%x\n", "cdp", tag);
		}

		offset += len;
		
	}
}
Пример #22
0
void process_dhcp_options(struct Seaper *seap, struct NetFrame *frame, const unsigned char *px, unsigned length, unsigned offset, struct DHCP *dhcp)
{
	seap;
	while (offset < length) {
		unsigned tag;
		unsigned len;

		tag = px[offset++];
		if (tag == 0xFF)
			break; /*end of list*/
		if (tag == 0x00)
			continue; /*padding*/

		if (offset >= length) {
			FRAMERR(frame, "dhcp: option too short\n");
			break;
		}
		len = px[offset++];
		if (offset >= length) {
			FRAMERR(frame, "dhcp: option too short\n");
			break;
		}

		SAMPLE("DHCP", "tag",	REC_UNSIGNED, &tag,	sizeof(tag));

		switch (tag) {
		case 1: /*0x01 - Subnet tag */
			break;
		case 3: /*Router */
			if (len !=  4)
				FRAMERR(frame, "dhcp: abnormal length, tag=%d, len=%d\n", tag, len);
			else {
				unsigned ip = ex32be(px+offset);
				process_record(seap,
					"proto",	REC_SZ,			"DHCP",		-1,
					"server",	REC_FRAMESRC,	frame, -1, 
					"op",		REC_SZ,			"offer",-1,
					"router",	REC_IPv4,		&ip,	sizeof(ip),
					0);
			}
			break;
		case 6: /*DNS server*/
			{
				unsigned i;
				for (i=0; i<len; i+=4) {
					unsigned ip = ex32be(px+offset+i);
					process_record(seap,
						"proto",	REC_SZ,			"DHCP",		-1,
						"server",	REC_FRAMESRC,	frame, -1,
						"op",		REC_SZ,			"offer",-1,
						"dns-server",REC_IPv4,		&ip,	sizeof(ip),
						0);
				}
			}
			break;
		case 12: /*0x0c - Hostname */
			if (len ==  0)
				FRAMERR(frame, "dhcp: abnormal length, tag=%d, len=%d\n", tag, len);
			else
				process_record(seap,
					"ID-MAC",	REC_MACADDR,	dhcp->chaddr,	6,
					"proto",	REC_SZ,			"DHCP",		-1,
					"op",		REC_SZ,			"Hostname",-1,
					"hostname",	REC_PRINTABLE,	px+offset,	len,
					0);
			break;
		case 15: /*0x0f - Domain Name */
			if (len ==  0)
				FRAMERR(frame, "dhcp: abnormal length, tag=%d, len=%d\n", tag, len);
			else
				process_record(seap,
					"proto",	REC_SZ,			"DHCP",		-1,
					"server",	REC_FRAMESRC,	frame, -1,
					"op",		REC_SZ,			"offer",-1,
					"domainname",	REC_PRINTABLE,	px+offset,	len,
					0);
			break;
		case 31: /*perform router discovery*/
			{
				unsigned discovery=0;
				unsigned i;
				for (i=0; i<len; i++)
					discovery = discovery*10 + px[offset+i];
				process_record(seap,
					"proto",	REC_SZ,			"DHCP",		-1,
					"server",	REC_FRAMESRC,	frame, -1,
					"op",		REC_SZ,			"offer",-1,
					"discovery",REC_UNSIGNED,	&discovery,	sizeof(discovery),
					0);
			}
			break;
		case 53: /*0x35 - DHCP message type*/
			if (len != 1) {
				FRAMERR(frame, "dhcp: abnormal length, tag=%d, len=%d\n", tag, len);
				break;
			}
			dhcp->msg = px[offset];

			switch (dhcp->msg) {
			case 1: /*discover*/
			case 2: /*offer*/
			case 3: /*request*/
			case 5: /*ack*/
			case 6: /*nak*/
			case 7: /* release */
			case 8: /*inform*/
				SAMPLE("DHCP", "msg",	REC_UNSIGNED, &dhcp->msg,	sizeof(dhcp->msg));
				break;
			default:
				FRAMERR(frame, "dhcp: ungknown msg type %d\n", dhcp->msg);
			}
			break;
		case 55: /* 0x37 - Parameter Request List */
			if (len == 0)
				FRAMERR(frame, "dhcp: abnormal length, tag=%d, len=%d\n", tag, len);
			break;
		case 0x36: /* Server Identifier*/
			if (len != 4) {
				FRAMERR(frame, "dhcp: abnormal option length\n");
				break;
			}
			dhcp->server_identifier = ex32be(px+offset);
			break;
		case 43: /* vendor info*/
			if (len ==  0)
				FRAMERR(frame, "dhcp: abnormal length, tag=%d, len=%d\n", tag, len);
			else
				process_record(seap,
					"ID-MAC",	REC_MACADDR,	dhcp->chaddr,	6,
					"proto",	REC_SZ,			"DHCP",		-1,
					"op",		REC_SZ,			"Vendor-Info",-1,
					"info",	REC_PRINTABLE,	px+offset,	len,
					0);
			break;
		case 60: /* 0x3c - Vendor class identifier */
			if (len ==  0)
				FRAMERR(frame, "dhcp: abnormal length, tag=%d, len=%d\n", tag, len);
			else
				process_record(seap,
					"ID-MAC",	REC_MACADDR,	dhcp->chaddr,	6,
					"proto",	REC_SZ,			"DHCP",		-1,
					"op",		REC_SZ,			"Vendor-ID",-1,
					"vendor",	REC_PRINTABLE,	px+offset,	len,
					0);
			break;
		case 61: /* 0x3d - Client identifier */
			if (len < 2)
				FRAMERR(frame, "dhcp: abnormal length, tag=%d, len=%d\n", tag, len);
			else {
				const unsigned char *clientid = px+offset+1;
				switch (px[offset]) {
				case 0:
					break;
				case 1:
					if (len != 7)
						FRAMERR(frame, "dhcp: abnormal length, tag=%d, len=%d\n", tag, len);
					else {
						if (memcmp(dhcp->chaddr, "\0\0\0\0\0\0", 6) == 0) {
							FRAMERR(frame, "untested code path\n");
							memcpy(dhcp->chaddr, clientid, 6);
							dhcp->hardware_type = 1;
							dhcp->hardware_address_length = 6;
						}
						else if (memcmp(dhcp->chaddr, clientid, 6) != 0) {
							FRAMERR(frame, "untested code path\n");
							process_record(seap,
								"ID-MAC",	REC_MACADDR,	dhcp->chaddr,	6,
								"proto",	REC_SZ,			"DHCP",		-1,
								"op",		REC_SZ,			"Client-ID",-1,
								"new.mac",	REC_MACADDR,	clientid,	6,
								0);
						}
					}
				}
			}
			break;
		case 50: /* 0x32 - Request IP */
			if (len != 4)
				FRAMERR(frame, "dhcp: abnormal length, tag=%d, len=%d\n", tag, len);
			else {
				unsigned ip_address = ex32be(px+offset);
				process_record(seap,
					"ID-MAC",	REC_MACADDR,	dhcp->chaddr,	6,
					"proto",	REC_SZ,			"DHCP",		-1,
					"op",		REC_SZ,			"Request-IP",-1,
					"ip",		REC_IPv4,		&ip_address,	sizeof(ip_address),
					0);
			}
			break;
		case 51: /* IP address lease time */
			if (len !=  4)
				FRAMERR(frame, "dhcp: abnormal length, tag=%d, len=%d\n", tag, len);
			else {
				unsigned lease_time = ex32be(px+offset);
				process_record(seap,
					"proto",	REC_SZ,			"DHCP",		-1,
					"server",	REC_FRAMESRC,	frame, -1,
					"op",		REC_SZ,			"offer",-1,
					"leasetime",REC_UNSIGNED,	&lease_time,	sizeof(lease_time),
					0);
			}
			break;
		case 52: /* Option Overload */
			if (len != 1)
				FRAMERR(frame, "dhcp: abnormal length, tag=%d, len=%d\n", tag, len);
			else {
				if (px[offset] & 1)
					dhcp->overload_filename = 1;
				if (px[offset] & 2)
					dhcp->overload_servername = 1;
			}
			break;
		case 57: /* Mac DHCP message size, used by diskless clients to report 1500 so they don't have to reassemble?*/
			break;
		case 81:
			if (len < 4)
				FRAMERR(frame, "dhcp: abnormal length, tag=%d, len=%d\n", tag, len);
			else {
				const char *name = (const char*)px+offset+3;
				unsigned name_length = len-3;

				process_record(seap,
					"ID-MAC",	REC_MACADDR,	dhcp->chaddr,	6,
					"proto",	REC_SZ,			"DHCP",		-1,
					"op",		REC_SZ,			"FQDN", -1,
					"fqdn",		REC_PRINTABLE,	name, name_length,
					0);
				
				if (dhcp->op != 1)
					FRAMERR(frame, "implement this code path\n");
			}
			break;

		case 116: /*0x74 - Auto-configure */
			if (len != 1) {
				FRAMERR(frame, "dhcp: abnormal option length\n");
				break;
			}
			switch (px[offset]) {
			case 0: dhcp->rfc2563_auto_configure = 2; break;
			case 1: dhcp->rfc2563_auto_configure = 1; break;
			default:
				FRAMERR(frame, "dhcp: bad value, tag=%d, len=%d\n", tag, len);
			}
			break;
		case 44: /* netbios over tcp/ip server */
			break;
		default:
			FRAMERR(frame, "dhcp: tag: unknown %d (0x%02x)\n", tag, tag);
			break;
		}


		offset += len;
	}
}
Пример #23
0
void parse_atalk_nbp(struct Ferret *ferret, struct NetFrame *frame, const unsigned char *px, unsigned length)
{
	struct {
		unsigned op;
		unsigned count;
		unsigned xid;
	} nbp;
	unsigned offset=0;

	if (length < 2) {
		FRAMERR(frame, "%s: truncated\n", "NBP");
		return;
	}

	/*
	 * Parse the header first
	 */
	nbp.op = (px[0]>>4)&0x0F;
	nbp.count = (px[0]>>0)&0x0F;
	nbp.xid = px[1];

	offset = 2;

	/*
	 * Parse all the name-bindings
	 */
	while (nbp.count) {
		unsigned atalk_addr;
		unsigned atalk_port;
		unsigned enumerator;
		unsigned object_len;
		const unsigned char *object;
		unsigned type_len;
		const unsigned char *type;
		unsigned zone_len;
		const unsigned char *zone;

		nbp.count--;

		if (offset + 6 > length) {
			FRAMERR(frame, "%s: truncated\n", "NBP");
			return;
		}

		atalk_addr = ex24be(px+offset);
		offset += 3;
		atalk_port = px[offset++];
		enumerator = px[offset++];
		

		/* Extract the items */
		extract_item(ferret, frame, px, length, &offset, &object, &object_len);
		extract_item(ferret, frame, px, length, &offset, &type, &type_len);
		extract_item(ferret, frame, px, length, &offset, &zone, &zone_len);

		if (offset > length)
			break;

		switch (nbp.op) {
		case 2:
			JOTDOWN(ferret,
				JOT_SRC("ID-ATALK", frame),
				JOT_PRINT("Lookup",  type, type_len),
				JOT_PRINT("Object",  object, object_len),
				JOT_PRINT("Zone",  zone, zone_len),
				0);
			break;
		default:
			FRAMERR(frame, "%s: not implemented\n", "NBP");
		}

	}


	
}
Пример #24
0
/**
 * This function extracts a DNS name from the packet and formats it according
 * to DNS rules. Essentially, this means that if a '.' dot character appears inside
 * of a label, then we'll show  '\.' escaped dot. Likewise, if the '\' escape
 * character appears inside of a label, we'll '\\' escape it as well. Otherwise,
 * we'll show all binary and spaces as they are natively in the stream.
 */
unsigned 
dns_extract_name(struct NetFrame *frame, const unsigned char *px, unsigned length, unsigned offset, char *name, unsigned sizeof_name)
{
	int recurse_count = 0;
	unsigned name_offset = 0;

	name[0] = '\0';

	/* For all labels ... */
	while (offset < length) {
		unsigned len;

		/* The 'empty' label ends the DNS name */
		if (px[offset] == 0x00)
			break;

		/* Look for a Lempel-Ziv compression, which points backwards in the packet
		 * to some other repeated name, as much as 16k into the packet */
		if (px[offset] & 0xC0) {

			/* Check for repeated recursion. We can point to another label,
			 * or to annother pointer. Indeed, a vulnerability in older
			 * DNS implementations is where if the pointer pointed to itself,
			 * then the DNS would go into an infinite loop endlessly following
			 * that pointer */
			if (recurse_count > 100) {
				FRAMERR(frame, "dns: name: recursion exceeded %d\n", recurse_count);
				break;
			}
			recurse_count++;

			/* This is actually a 2-byte field, so we need to check for the 
			 * extra byte has not run past the end of the packet */
			if (offset+2 > length) {
				FRAMERR(frame, "dns: name: not enough bytes\n");
				strcpy_s(name, sizeof_name, "(err)");
				return 5;
			}

			/* Extract the lower 14-bits and use that as the new offset. Note that
			 * this means we can use this compression features that point to a name
			 * past the 16k boundary, but that isn't really a big problem because
			 * packets really never get that big. */
			offset = ex16be(px+offset)&0x3FFF;

			continue;
		} 
		
		/* Otherwise, we have a normal label. The first step is to grab the 
		 * length of this label and make sure we haven 't gone past the end
		 * of the packet */
		len = px[offset++];
		if (offset >= length) {
			FRAMERR(frame, "dns: name: not enough bytes\n");
			strcpy_s(name, sizeof_name, "(err)");
			return 5;
		}
		if (offset+len > length) {
			FRAMERR(frame, "dns: name: not enough bytes\n");
			strcpy_s(name, sizeof_name, "(err)");
			return 5;
		}

		/* If there were already a label in the name, make sure that there
		 * is the '.' character between the previoius label an this label. */
		if (name_offset > 0) {
			if (name_offset+1 >= sizeof_name) {
				FRAMERR(frame, "dns: name: too long\n");
				strcpy_s(name, sizeof_name, "(err)");
				return 5;
			}
			name[name_offset++] = '.';
		}

		/* Make sure there is enough space left in the name, as well as enough
		 * psace for the NUL terminating character */
		if (name_offset+len+1 >= sizeof_name) {
			FRAMERR(frame, "dns: name: too long\n");
			strcpy_s(name, sizeof_name, "(err)");
			return 5;
		}

		/* Copy over the name */
		memcpy(name+name_offset, px+offset, len);
		name_offset += len;
		name[name_offset] = '\0';

		/* Now go onto the next label in the DNS name */
		offset += len;
	}

	return name_offset;
}
Пример #25
0
void squirrel_ethernet_frame(struct Squirrel *squirrel, struct NetFrame *frame, const unsigned char *px, unsigned length)
{
	unsigned offset;
	unsigned ethertype;
	unsigned oui;

	if (length <= 14) {
		; /*FRAMERR(frame, "wifi.data: too short\n");*/
		return;
	}

	frame->src_mac = px+6;
	frame->dst_mac = px+0;

	offset = 12;


	/* Look for SAP header */
	if (offset + 6 >= length) {
		FRAMERR(frame, "wifi.sap: too short\n");
		return;
	}

	ethertype = ex16be(px+offset);
	offset += 2;

	switch (ethertype) {
	case 0x0800:
		squirrel_ip(squirrel, frame, px+offset, length-offset);
		break;
	case 0x0806:
		squirrel_arp(squirrel, frame, px+offset, length-offset);
		break;
	case 0x888e: /*802.11x authentication*/
		//squirrel_802_1x_auth(squirrel, frame, px+offset, length-offset);
		break;
	case 0x86dd: /* IPv6*/
		//squirrel_ipv6(squirrel, frame, px+offset, length-offset);
		break;
	case 0x809b:
		//squirrel_ipv6(squirrel, frame, px+offset, length-offset);
		break;
	case 0x872d: /* Cisco OWL */
		break;
	case 0x9000: /* Loopback */
		break;
	default:
		if (ethertype < 1518) {
			if (memcmp(px+offset, "\xaa\xaa\x03", 3) != 0) {
				return;
			}
			offset +=3 ;

			oui = ex24be(px+offset);

			if (squirrel->filter.snap_oui_count) {
				if (filter_has_port(squirrel->filter.snap_ouis, squirrel->filter.snap_oui_count, oui))
					frame->flags.found.filtered = 1;
			}

			/* Look for OUI code */
			switch (oui){
			case 0x000000:
				/* fall through below */
				break;
			case 0x004096: /* Cisco Wireless */
				return;
				break;
			case 0x00000c:
				offset +=3;
                if (offset < length) {
					;//squirrel_cisco00000c(squirrel, frame, px+offset, length-offset);
                }
				return;
			case 0x080007:
				break; /*apple*/
			default:
				FRAMERR(frame, "Unknown SAP OUI: 0x%06x\n", oui);
				return;
			}
			offset +=3;

			/* EtherType */
			if (offset+2 >= length) {
				FRAMERR(frame, "ethertype: packet too short\n");
				return;
			}

		}

		if (ethertype == length-offset && ex16be(px+offset) == 0xAAAA) {
			;
		}
		else
			FRAMERR_BADVAL(frame, "ethertype", ethertype);
	}
}
Пример #26
0
void process_dns(struct Ferret *ferret, struct NetFrame *frame, const unsigned char *px, unsigned length)
{
	unsigned offset;
	struct DNS dns[1];
	unsigned record_count;
	unsigned total_records;
	unsigned i;

	/* Count the number of DNS packets we process. This includes
	 * all types of DNS */
	ferret->statistics.dns++;

	memset(dns, 0, sizeof(dns[0]));

	if (length < 12) {
		/* Regress: defcon2008-dns2.pcap(95639) */
		; //FRAMERR(frame, "dns: frame too short\n");
		return;
	}

	/* Parse the DNS header, the 'fixed' portion of the packet
	 * before the variable length records 
		+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
		|                      ID                       |
		+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
		|QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
		+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
		|                    QDCOUNT                    |
		+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
		|                    ANCOUNT                    |
		+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
		|                    NSCOUNT                    |
		+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
		|                    ARCOUNT                    |
		+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
	ID              A 16 bit identifier assigned by the program that
					generates any kind of query.  This identifier is copied
					the corresponding reply and can be used by the requester
					to match up replies to outstanding queries.
	QR              A one bit field that specifies whether this message is a
					query (0), or a response (1).
	OPCODE          A four bit field that specifies kind of query in this
					message.  This value is set by the originator of a query
					and copied into the response.  The values are:
					0               a standard query (QUERY)
					1               an inverse query (IQUERY)
					2               a server status request (STATUS)
					3-15            reserved for future use
	AA              Authoritative Answer - this bit is valid in responses,
					and specifies that the responding name server is an
					authority for the domain name in question section.

					Note that the contents of the answer section may have
					multiple owner names because of aliases.  The AA bit
					corresponds to the name which matches the query name, or
					the first owner name in the answer section.
	TC              TrunCation - specifies that this message was truncated
					due to length greater than that permitted on the
					transmission channel.
	RD              Recursion Desired - this bit may be set in a query and
					is copied into the response.  If RD is set, it directs
					the name server to pursue the query recursively.
					Recursive query support is optional.
	RA              Recursion Available - this be is set or cleared in a
					response, and denotes whether recursive query support is
					available in the name server.
	Z               Reserved for future use.  Must be zero in all queries
					and responses.
	RCODE           Response code - this 4 bit field is set as part of
					responses.  The values have the following
					interpretation:
					0               No error condition
					1               Format error - The name server was
									unable to interpret the query.
					2               Server failure - The name server was
									unable to process this query due to a
									problem with the name server.
					3               Name Error - Meaningful only for
									responses from an authoritative name
									server, this code signifies that the
									domain name referenced in the query does
									not exist.
					4               Not Implemented - The name server does
									not support the requested kind of query.
					5               Refused - The name server refuses to
									perform the specified operation for
									policy reasons.  For example, a name
									server may not wish to provide the
									information to the particular requester,
									or a name server may not wish to perform
									a particular operation (e.g., zone
					6-15            Reserved for future use.
	QDCOUNT         an unsigned 16 bit integer specifying the number of
					entries in the question section.
	ANCOUNT         an unsigned 16 bit integer specifying the number of
					resource records in the answer section.
	NSCOUNT         an unsigned 16 bit integer specifying the number of name
					server resource records in the authority records
					section.
	ARCOUNT         an unsigned 16 bit integer specifying the number of
					resource records in the additional records section.
	*/

	dns->id = ex16be(px+0);
	dns->is_response = ((px[2]&0x80) != 0);
	dns->opcode = (px[2]>>3)&0x01F;
	dns->flags = ex16be(px+2)&0x7F0;
	dns->rcode = px[3]&0x0F;

	dns->question_count = ex16be(px+4);
	dns->answer_count = ex16be(px+6);
	dns->authority_count = ex16be(px+8);
	dns->additional_count = ex16be(px+10);

	/* Remember a total count of the records. There are a lot of corrupted packets
	 * with data after the counted records, so we need to stop parsing once all
	 * the counted records have been parsed. */
	total_records = dns->question_count + dns->answer_count + dns->authority_count + dns->additional_count;

	offset = 12;
	record_count = 0;


	/* After parsing the fixed header, we no PRE-PROCESS the variable length records.
	 * All we want to do at this point is to find their locations within the packet.
	 * The reason we want to pre-process these is that some records will refer to
	 * other records in the same packet. A good example are CNAME records 
	 * that require looking up other records in order to fully resolve. We can
	 * do the resolution easier if we can preprocess the list first */
	while (offset < length && record_count < 100) {
		struct DNSRECORD *rec = &dns->records[record_count];

		/* Even if there is remaining data in the packet, do not parse past
		 * the total count of all the records */
		if (record_count >= total_records) {
			SAMPLE(ferret,"dns", JOT_NUM("too-many-records", total_records));
			break;
		}

		/* NAME
		 * The first part of a DNS record is the variable length name. The name
		 * consists of a sequence of LABELS. Each label starts with a tag. The 
		 * tag can be one of three things:
		 *	- a value of zero, which ends the name
		 *	- a length from 1-63, which means we need to continue processing
		 *    more labels
		 *  - a two-byte 'pointer' to the remainder of the name, which means that
		 *	  we stop pre-processing the name. We don't actually parse out the
		 *	  full name at this stage in the code (so we won't follow that pointer),
		 *	  we are just concerned with skipping the name at this point. */
		rec->name_offset = offset;
		while (offset < length) {

			/* Test for end label */
			if (px[offset] == 0x00) {
				offset++;
				break;
			}

			/* Test for compression 'pointer' */
			if (px[offset] & 0xC0) {
				offset += 2;
				break;
			}

			/* Skip the 'length' number of bytes, plus the length byte itself */
			offset += px[offset] + 1;

			if (offset > length) {
				FRAMERR(frame, "dns: past end of packet\n");
				return;
			}
		}

		/* Now parse out the 'type' and 'class' fields. These are the
		 * 4 bytes immediately following the name */
		if (offset + 4 > length) {
			FRAMERR(frame, "dns: past end of packet\n");
			return;
		}
		rec->type = ex16be(px+offset+0);
		rec->clss = ex16be(px+offset+2);
		offset += 4;
		record_count++;


		/* If this is a 'question' record, then we don't do any further processing.
		 * Since question records are just asking for data, they don't contain
		 * any data themselves. Otherwise, if the record will contain data that
		 * we need to also parse */
		if (record_count <= dns->question_count)
			continue;
		
		/* This bit of code parses out the remainder of the data in the record. For
		 * the most part, we just need to parse the 'length' field for the record
		 * data, remember it for use later, then skip the remainder of this record
		 * and continue processing the next record */
		if (offset + 6 > length) {
			/* Regress: defcon2008-dns2.pcap(88069) */
			FRAMERR(frame, "dns: past end of packet\n");
			return;
		}
		rec->ttl = ex32be(px+offset+0);
		rec->rdata_length = ex16be(px+offset+4);
		offset += 6;
		rec->rdata_offset = offset;
		offset += rec->rdata_length;

		if (offset > length) {
			FRAMERR(frame, "dns: past end of packet\n");
			return;
		}
	}
	dns->record_count = record_count;

	/* We stored the records in one large array, but there are four kinds
	 * of records (questions, answers, authority, additional). We figure out
	 * which records belong to which type according to the counts */
	if (dns->question_count > record_count) {
		dns->question_count = record_count;
		FRAMERR(frame, "%s: bad record count\n", "DNS");
	}
	if (dns->answer_count > record_count - dns->question_count) {
		dns->answer_count = record_count - dns->question_count;
		/* Regress: defcon2008-dns2.pcap(158112) */
		; //FRAMERR(frame, "%s: bad record count\n", "DNS");
	}
	if (dns->authority_count > record_count - dns->question_count - dns->answer_count) {
		dns->authority_count = record_count - dns->question_count - dns->answer_count;
		FRAMERR(frame, "%s: bad record count\n", "DNS");
	}
	if (dns->additional_count > record_count - dns->question_count - dns->answer_count - dns->authority_count) {
		dns->additional_count = record_count - dns->question_count - dns->answer_count - dns->authority_count;
		FRAMERR(frame, "%s: bad record count\n", "DNS");
	}
	dns->questions = &dns->records[0];
	dns->answers = &dns->records[dns->question_count];
	dns->authorities = &dns->records[dns->question_count + dns->answer_count];
	dns->additionals = &dns->records[dns->question_count + dns->answer_count + dns->authority_count];

	/* 
	 * First, we parse out all the question records. These don't contain any data
	 * themselves, but they do give us interesting information about what a client
	 * is looking for. Also, some protocols, such as NetBIOS and mDNS/Bonjour will
	 * tell us additional information about the client.
	 */
	if (dns->is_response && dns->rcode == 0)
	for (i=0; i<dns->question_count; i++) {
		struct DNSRECORD *rec = &dns->questions[i];
		dns_parse_question_record(ferret, frame, px, length, rec, dns);
	}

	/* Now parse all the resource records after the questions */
	for (i=0; i<dns->answer_count; i++) {
		struct DNSRECORD *rec = &dns->answers[i];
		dns_parse_resource_record(ferret, frame, px, length, rec, dns);
	}
	for (i=0; i<dns->authority_count; i++) {
		struct DNSRECORD *rec = &dns->authorities[i];
		dns_parse_resource_record(ferret, frame, px, length, rec, dns);
	}
	for (i=0; i<dns->additional_count; i++) {
		struct DNSRECORD *rec = &dns->additionals[i];
		dns_parse_resource_record(ferret, frame, px, length, rec, dns);
	}

#if 0
	switch (dns->opcode) {
	case 0x00: /*query request*/
	case 0x10: /*query response */

		switch (dns->rcode) {
		case 0:
		case 3: /* No such name */
			SAMPLE(ferret,"DNS", JOT_NUM("rcode", dns->rcode));
			break;
		case 2: /* Server error */
			SAMPLE(ferret,"DNS", JOT_NUM("rcode", dns->rcode));
			break;
		default:
			FRAMERR(frame, "dns: unknown rcode=%d (opcode=%d)\n", dns->rcode, dns->opcode);
		}
		break;
	case 0x06: /*release*/
		switch (dns->rcode) {
		case 0:
			for (i=0; i<dns->additional_count; i++) {
				char name[256];
				unsigned name_length;
				struct DNSRECORD *rec = &dns->additionals[i];

				if (rec->type == 0x8001)
					FRAMERR(frame, "test\n");

				name_length = dns_extract_name(frame, px, length, rec->name_offset, name, sizeof(name));

				switch (rec->type) {
				case 0x0020: /*NETBIOS */
					switch (rec->clss) {
					case 0x0001: /*INTERNET*/
						{
							unsigned ip_address = ex32be(px+rec->rdata_offset+2);
							char netbios_name[256];

							if (rec->rdata_length != 6)
								FRAMERR(frame, "dns: data not 4-bytes long, was %d-bytes instead (class=%d, type=%d, name=%s)\n", rec->rdata_length, rec->clss, rec->type, name);

							translate_netbios_name(frame, name, netbios_name, sizeof(netbios_name));

							JOTDOWN(ferret,
								JOT_SZ("proto","NETBIOS"),
								JOT_SZ("op","release"),
								JOT_DST("ip.src", frame),
								JOT_PRINT("name",		 	netbios_name,				strlen(netbios_name)),
								JOT_IPv4("address", ip_address),
								0);

							JOTDOWN(ferret,
								JOT_IPv4("ID-IP", ip_address),
								JOT_PRINT("netbios",	 	netbios_name,				strlen(netbios_name)),
								0);

						}
						break;
					default:
						FRAMERR(frame, "dns: unknown class=%d (type=%d, name=%s)\n", rec->clss, rec->type, name);
					}
					break;
				default:
					FRAMERR(frame, "dns: unknown type=%d (class=%d, name=%s)\n", rec->type, rec->clss, name);
				}
			}
		}
		break;
	case 0x05: /*netbios registration request*/
		if (frame->dst_port == 53)
			dns_dynamic_update(ferret, frame, px, length, dns);
		else
			process_request_update(ferret, frame, px, length, dns);
		break;
	case 0x08:
		for (i=0; i<dns->additional_count; i++)
			DECODEANSWER(ferret, frame, px, length, dns, &dns->additionals[i], "refresh");
		break;
	case 0x01: /*inverse query request*/
	case 0x11: /*inverse query reqsponse*/
	case 0x02: /*status request*/
	case 0x12: /*status response*/
	case 0x04: /*notify request*/
	case 0x14: /*notify response*/
	case 0x15: /*update response*/
	case 0x0f: /*multi-home registration*/
		for (i=0; i<dns->additional_count; i++)
			DECODEANSWER(ferret, frame, px, length, dns, &dns->additionals[i], "multi-home");
		break;
	default:
		FRAMERR(frame, "dns: unknown opcode %d\n", dns->opcode);
	}
#endif
}
Пример #27
0
void parse_atalk_ddp(struct Ferret *ferret, struct NetFrame *frame, const unsigned char *px, unsigned length)
{
    unsigned offset=0;
    struct {
        unsigned hop_count;
        unsigned datagram_length;
        unsigned checksum;
        unsigned protocol_type;
        unsigned address_src;
        unsigned address_dst;
        unsigned port_src;
        unsigned port_dst;
    } ddp;

    ferret->statistics.atalk++;

    if (length < 13) {
        FRAMERR(frame, "%s: truncated\n", "DDP");
        return;
    }



    ddp.hop_count = px[0]>>4;
    ddp.datagram_length = (px[0]&0xF)<<8 | px[1];
    ddp.checksum = ex16be(px+2);
    ddp.address_dst = ex16be(px+4)<<8;
    ddp.address_src = ex16be(px+6)<<8;
    ddp.address_dst |= px[8];
    ddp.address_src |= px[9];
    ddp.port_dst = px[10];
    ddp.port_src = px[11];
    ddp.protocol_type = px[12];

    if (length > ddp.datagram_length) {
        if (length-ddp.datagram_length == 4)
            ferret->statistics.remaining_4++; /*hints that an FCS trails*/
        length = ddp.datagram_length;
    }

    frame->ipver = ADDRESS_ATALK_EDDP;
    frame->src_ipv4 = ddp.address_src;
    frame->dst_ipv4 = ddp.address_dst;
    frame->src_port = ddp.port_src;
    frame->dst_port = ddp.port_dst;

    /* skip the header */
    offset += 13;

    /* If this is a broadcast packet, we can make the assumption
     * that the sender is on the local subnet */
    JOTDOWN(ferret,
            JOT_MACADDR("ID-MAC", frame->src_mac),
            JOT_SRC("AppleTalk", frame),
            0);

    /* Parse the next layer */
    SAMPLE(ferret, "ATALK-DDP",JOT_NUM("protocol", ddp.protocol_type));
    SAMPLE(ferret, "ATALK-DDP",JOT_NUM("dst-port", ddp.port_dst));

    switch (ddp.protocol_type) {
    case 0x02: /* NBP - Name Binding Protocol */
        parse_atalk_nbp(ferret, frame, px+offset, length-offset);
        break;
    case 0x06: /* ZIP (Zone Information Protocol) */
        break;
    case 0x01: /* RTMP (Routing Table Maintenance Protocol), works like RIP */
    case 0x03: /* ATP (Appletalk Transfer Protocol) */
    case 0x04: /* Echo, works like ICMP Echo */
    case 0x05: /* RTMP requests */
    case 0x07: /* ADSP (Appletalk Data Stream Protocol) */
    case 0x08: /* SNMP, same as normal SNMP */
    case 0x16: /* IP over AppleTalk */
    default:
        FRAMERR(frame, "%s: unknown protocol=%d, srcport=%d, dstport=%d\n", "DDP", ddp.protocol_type,
                ddp.port_src, ddp.port_dst);
    }

}
Пример #28
0
void process_simple_msnms_client_request(struct Seaper *seap, struct NetFrame *frame, const unsigned char *px, unsigned length)
{
	unsigned offset=0;
	unsigned char cmd[16] = "";
	unsigned i;
	unsigned eol=0;

	/*Find out length of the command line */
	for (eol=0; eol<length && px[eol] != '\n'; eol++)
		;

	skip_whitespace(px, length, &offset);

	/* get command */
	i=0;
	while (offset < length && px[offset] != '\n' && !isspace(px[offset])) {
		if (i<sizeof(cmd)-1) {
			cmd[i++] = px[offset];
			cmd[i] = '\0';
		}
		offset++;
	}
	skip_whitespace(px, length, &offset);

	SAMPLE("MSN-MSGR", "command", REC_SZ, cmd, -1);

	switch (CMD(cmd)) {
    case 0x56455200: /* "VER" */
		while (offset < eol) {
			unsigned parm = offset;
			unsigned parm_length = get_parm(px, length, &offset);

			if (is_number(px+parm, parm_length))
				continue;

			if (equals(px+parm, parm_length, "CVR0"))
				continue;


			/* Syntax:
			 * VER <TrID> <protocol> <protocol> .... 
			 *
			 *	Indicates a list of protocols supported
			 *
			 *  Examples:
			 *		VER 0 MSNP8 CVR0
			 *		VER 0 MSNP8 MYPROTOCOL CVR0
			 */
			process_record(seap,
				"ID-IP",	REC_FRAMESRC,	frame, -1,
				"app",		REC_SZ,			"MSN-MSGR",		-1,
				"ver",		REC_PRINTABLE,	px+parm, parm_length,
				0);
		}				

		break;
    case 0x4e4c4e00: /* "NLN" */
		break;
    case 0x514e4700: /* "QNG" */
		break;
    case 0x43565200: /* "CVR" */
/*
    *  The first parameter is hexadecimal number specifying your locale ID (e.g. "0x0409" For U.S. English).
    * The second parameter is your OS type (e.g. "win" for Windows).
    * The third parameter is your OS version (e.g. "4.10" for Windows 98).
    * The fourth parameter is the architecture of your computer (e.g. "i386" for Intel-comaptible PCs of type 386 or above).
    * The fifth parameter is your client name (e.g. "MSMSGR" for the official MSN Messenger client).
    * The sixth parameter is your client version (e.g. "6.0.0602").
    * The seventh parameter is always "MSMSGS" in the official client. Your guess about what this means is as good as mine.
    * The eighth parameter is your passport.
*/
		{
			unsigned trid, trid_length;
			unsigned localid, localid_length;
			unsigned ostype, ostype_length;
			unsigned osver, osver_length;
			unsigned arch, arch_length;
			unsigned clientname, clientname_length;
			unsigned clientver, clientver_length;
			unsigned msmsgs, msmsgs_length;
			unsigned passport, passport_length;

			trid = offset;
			trid_length = get_parm(px, length, &offset);
			
			localid=offset;
			localid_length = get_parm(px, length, &offset);
			
			ostype=offset;
			ostype_length = get_parm(px, length, &offset);
			
			osver=offset;
			osver_length = get_parm(px, length, &offset);
			
			arch=offset;
			arch_length = get_parm(px, length, &offset);
			
			clientname=offset;
			clientname_length = get_parm(px, length, &offset);
			
			clientver=offset;
			clientver_length = get_parm(px, length, &offset);
			
			msmsgs=offset;
			msmsgs_length = get_parm(px, length, &offset);
			
			passport=offset;
			passport_length = get_parm(px, length, &offset);
			
			process_record(seap,
				"ID-IP",	REC_FRAMESRC,	frame, -1,
				"Passport",	REC_PRINTABLE,	px+passport, passport_length,
				0);

			process_record(seap,
				"proto",	REC_SZ,			"MSN-MSGR", -1,
				"ip",		REC_FRAMESRC,	frame, -1,
				"localid",	REC_PRINTABLE, px+localid, localid_length,
				0);
			process_record(seap,
				"proto",	REC_SZ,			"MSN-MSGR", -1,
				"ip",		REC_FRAMESRC,	frame, -1,
				"ostype",	REC_PRINTABLE, px+ostype, ostype_length,
				0);
			process_record(seap,
				"proto",	REC_SZ,			"MSN-MSGR", -1,
				"ip",		REC_FRAMESRC,	frame, -1,
				"osver",	REC_PRINTABLE	, px+osver, osver_length,
				0);
			process_record(seap,
				"proto",	REC_SZ,			"MSN-MSGR", -1,
				"ip",		REC_FRAMESRC,	frame, -1,
				"arch",		REC_PRINTABLE	, px+arch, arch_length,
				0);
			process_record(seap,
				"proto",	REC_SZ,			"MSN-MSGR", -1,
				"ip",		REC_FRAMESRC,	frame, -1,
				"clientname",	REC_PRINTABLE, px+clientname, clientname_length,
				0);
			process_record(seap,
				"proto",	REC_SZ,			"MSN-MSGR", -1,
				"ip",		REC_FRAMESRC,	frame, -1,
				"clientver",REC_PRINTABLE, px+clientver, clientver_length,
				0);
			process_record(seap,
				"proto",	REC_SZ,			"MSN-MSGR", -1,
				"ip",		REC_FRAMESRC,	frame, -1,
				"msmsgs",	REC_PRINTABLE, px+msmsgs, msmsgs_length,
				0);
			process_record(seap,
				"proto",	REC_SZ,			"MSN-MSGR", -1,
				"ip",		REC_FRAMESRC,	frame, -1,
				"passport",	REC_PRINTABLE, px+passport, passport_length,
				0);

		}				
		break;
    case 0x55535200: /* "USR" */
	/*After receiving the response to CVR, you must send the USR command. It has a TrID.
    * The first parameter is the authentication system (always TWN).
    * The second parameter is always the letter I (standing for initiating authentication).
    * The third parameter is the account name that you want to log on with.
	*/
		{
			unsigned trid, trid_length;
			unsigned twn, twn_length;
			unsigned ii, ii_length;
			unsigned username, username_length;

			trid = offset;
			trid_length = get_parm(px, length, &offset);
			
			twn = offset;
			twn_length = get_parm(px, length, &offset);

			ii = offset;
			ii_length = get_parm(px, length, &offset);

			username = offset;
			username_length = get_parm(px, length, &offset);

			process_record(seap,
				"proto",	REC_SZ,			"MSN-MSGR", -1,
				"ip",		REC_FRAMESRC,	frame, -1,
				"username",	REC_PRINTABLE, px+username, username_length,
				0);
			process_record(seap,
				"ID-IP",	REC_FRAMESRC,	frame, -1,
				"MSN-username",	REC_PRINTABLE,	px+username, username_length,
				0);
		}				
		break;
    case 0x4d534700: /* "MSG" */
    case 0x58465200: /* "XFR" */
	default:
		FRAMERR(frame, "msn-ms: unknown commanded from client: %.*s\n", length, px);
	}


	
}
Пример #29
0
void parse_PVSTP(struct Ferret *ferret, struct NetFrame *frame, const unsigned char *px, unsigned length)
{
	unsigned port_id;

	if (length < 4) {
		FRAMERR(frame, "truncated\n");
		return;
	}

	/* Protocol Identifier */
	if (ex16be(px+0) != 0) {
		FRAMERR(frame, "unexpected\n");
		return;
	}

	frame->layer3_protocol = LAYER3_STP;

	/* Protocol Version Identifier */
	if (px[2] != 0) {
		FRAMERR(frame, "unexpected\n");
		return;
	}

	/* BPDU type */
	switch (px[3]) {
	case 0:
		if (length < 28) {
			FRAMERR(frame, "truncated\n");
			return;
		}
		JOTDOWN(ferret, 
			JOT_MACADDR("ID-MAC", frame->src_mac),
			JOT_SZ("Type", "bridge"),
			JOT_MACADDR("root", px+7),
			0);
		JOTDOWN(ferret, 
			JOT_MACADDR("ID-MAC", frame->src_mac),
			JOT_SZ("Type", "bridge"),
			JOT_MACADDR("ID", px+19),
			0);
		port_id = ex16be(px+25);
		JOTDOWN(ferret, 
			JOT_MACADDR("ID-MAC", frame->src_mac),
			JOT_SZ("Type", "bridge"),
			JOT_NUM("port-id", port_id),
			0);
		break;
	case 0x80:
		JOTDOWN(ferret, 
			JOT_MACADDR("ID-MAC", frame->src_mac),
			JOT_SZ("Type", "bridge"),
			0);
		break;
	default:
		FRAMERR(frame, "unexpected\n");
		return;
	}



}