[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

arp decoder improvements



Hi,

I've done some work on the arp decoder.  Now some checks are made on the
length of the packet and some layer flags set depending what is found.
(the latest version of my macwatch preprocessors uses these flags).

I've also improved the print routines which now have more op code
strings, added hardware type strings and a tcpdump style ascii output,
e.g:

packet: 2003-12-11 17:18:35.161118 len=62 caplen=62
 alert: [macwatch] Gratuitous arp (sid=5.0 prio=5)
   sll: broadcast proto=0x0806
   arp: Ethernet hw req: who has 10.1.0.30? tell 10.1.0.30 (00:04:23:41:0f:30)

packet: 2003-12-11 17:14:57.375903 len=62 caplen=62
 alert: [macwatch] New protocol address (sid=0.0 prio=5)
   sll: unicast proto=0x0806
   arp: Ethernet hw reply: 192.168.1.218 is at 00:b0:d0:e1:ef:c8
-- 
GPG: B89C D450 5B2C 74D8 58FB A360 9B06 B5C2 26F0 3047
WEB: http://www.johnleach.co.uk
--- firestorm-snapshot/decode_plugins/arp.c	2004-02-14 00:23:49.000000000 +0000
+++ firestorm-devel/decode_plugins/arp.c	2004-03-14 20:50:38.344851048 +0000
@@ -9,6 +9,25 @@
 #include <signature.h>
 #include <decode.h>
 #include <preproc.h>
+#include <pkt/arp.h>
+
+	
+/* Token bucket for arp alerts */
+static struct tokenbucket arp_tb={
+	.cost = (RATE_SEC / 1), /* 1 alert per second */
+	.burst = (RATE_SEC / 1) * 10, /* a burst of 10 alerts per second */
+};
+
+static struct generator arp_gen=init_generator("arp", &arp_tb);
+
+static struct alert alert_trunc={
+	.alert="Truncated arp packet",
+	.sid=5, .rev=0,
+	.priority=5,
+	.gen=&arp_gen,
+	.order = ALERT_BUILTIN,
+};
+
 
 void arp_decode(struct packet *);
 int arp_print(struct layer *l, char *buf, size_t buflen);
@@ -37,37 +56,170 @@
 	null_request()
 };
 
-char *opnames[]={NULL,
-	"Hardware request","Hardware reply",
-	"Protocol request","Protocol reply",
-	NULL, NULL, NULL,
-	"Peer request","Peer reply"
+char *opnames[] = { NULL,
+	/* RFC 826 */
+	"hw req","hw reply",
+	/* RFC 903 */
+	"Proto req","Proto reply",
+	/* RFC 1931 */
+	"DRARP req", "DRARP reply", "DRARP error",
+	/* RFC 1293 */
+	"InARP req","InARP reply",
+	/* RFC 1577 */
+	"ARP nak",
+	/* Multicast Address Resolution Server */
+	"MARS req", "MARS multi", "MARS mserv", "MARS join", "MARS leave",
+	"MARS nak", "MARS unserv", "MARS sjoin", "MARS sleave",
+	"MARS grouplist request", "MARS grouplist reply", "MARS redirect map",
+	"MAPOS unarp"
+};
+
+char *hwtypes[] = { NULL,
+	"Ethernet",
+	"Experimental ethernet",
+	"AX.25",
+	"ProNET token ring",
+	"Chaos",
+	"IEEE 802",
+	"ARCNET",
+	"Hyperchannel",
+	"Lanstar",
+	"Autonet short address",
+	"LocalTalk",
+	"LocalNet",
+	"Ultra link",
+	"SMDS",
+	"Frame Relay",
+	"ATM",
+	"HDLC",
+	"Fibre channel",
+	"ATM",
+	"Serial line",
+	"ATM",
+	"MIL-STD-188-220",
+	"Metricom",
+	"IEEE 1394.1995",
+	"MAPOS",
+	"Twinaxial",
+	"EUI-64",
+	"HIPARP",
+	"ISO7816-3",
+	"ARPSec",
+	"IPsec tunnel",
+	"Infiniband"
 };
 
 void arp_decode(struct packet *p)
 {
-	struct layer *l=&p->layer[p->llen];
-
-	if ( l->h.raw+sizeof(struct pkt_arphdr) > p->end ) {
+	struct layer *l = &p->layer[p->llen];
+	void *payload = l->h.raw + sizeof(struct pkt_arphdr);
+	u_int8_t hln = l->h.arp->hln;
+	u_int8_t pln = l->h.arp->pln;
+
+	/* Check length of packet */
+	if (payload + (hln*2) + (pln*2) <= p->end) {
+		l->flags |= LF_TARGET | LF_SENDER;
+	} else if (payload + hln + pln <= p->end) { 
+		/* Linux seems to process truncated arp packets with sender
+		 * addresses intact */
+		l->flags |= LF_SENDER;
+	} else {
+		/* Truncated arp packet */
+		/* With Ethernet, this is actually very unlikely due to
+		 * Ethernet frame padding to minimum size of FIXME: 60 bytes.
+		 * We just end up using bytes from this padding as
+		 * sender/target addresses if the arp packet is truncated
+		 * somewhere after the header.   It looks like Linux does this
+		 * too. */
+		alert_tag(p, &alert_trunc);
 		dispatch(p);
 		return;
 	}
-
+	
 	p->llen++;
 
 	dispatch(p);
 }
+	
+/* print a variable length hardware address in ascii (00:11:22...) */
+static int print_haddr(char *s, int slen, u_int8_t *b, u_int8_t hln)
+{
+	int i;
+
+	if (hln*3 > slen)
+		return 0;
+
+	for (i = 1 ; i <= hln; i++, b++) {
+		s += snprintf(s, 4, "%02x%c", *b&0xff, i == hln ? '\0' : ':');
+	}
+	return 1;
+}
+
+/* print a variable length protocol address in ascii (10.9.8...) */
+static int print_paddr(char *s, int slen, u_int8_t *b, u_int8_t pln)
+{
+	int i;
+	if (pln*4 > slen)
+		return 0;
+	
+	for (i = 1 ; i <= pln; i++, b++) {
+		s += snprintf(s, 5, "%i%c", *b&0xff, i == pln ? '\0' : '.');
+	}
+	return 1;
+}
 
 int arp_print(struct layer *l, char *buf, size_t buflen)
 {
-	u_int16_t op=ntohs(l->h.arp->op);
+	u_int16_t op = ntohs(l->h.arp->op);
+	u_int16_t hrd = ntohs(l->h.arp->hrd);
+	u_int8_t hln = l->h.arp->hln;
+	u_int8_t pln = l->h.arp->pln;
+	u_int8_t *payload = l->h.raw + sizeof(struct pkt_arphdr);
+	char shwtype[16];
+	char sop[16]="";
+	char ssh[24]="n/a", ssp[24]="n/a";
+	char tsh[24]="n/a", tsp[24]="n/a";
+
+	/* print hardware rtpe */
+	if ( hrd < (sizeof(hwtypes)/sizeof(*hwtypes)) && hwtypes[hrd] ) {
+		snprintf(shwtype, sizeof(shwtype), hwtypes[hrd]); /* not user input */
+	}else{
+		snprintf(shwtype, sizeof(shwtype),
+			"Unknown hw type (0x%.4x)", hrd);
+	}
 
+	/* print op code */
 	if ( op < (sizeof(opnames)/sizeof(*opnames)) && opnames[op] ) {
-		return snprintf(buf, buflen, opnames[op]); /* not user input */
+		snprintf(sop, sizeof(sop), opnames[op]); /* not user input */
 	}else{
-		return snprintf(buf, buflen,
+		snprintf(sop, sizeof(sop),
 			"Unknown opcode (0x%.4x)", op);
 	}
+
+	if (l->flags & LF_SENDER) {
+		print_haddr(ssh, sizeof(ssh), payload, hln);
+		print_paddr(ssp, sizeof(ssp), payload + hln, pln);
+	}
+	
+	if (l->flags & LF_TARGET) {
+		print_haddr(tsh, sizeof(tsh), payload + hln + pln, hln);
+		print_paddr(tsp, sizeof(tsp), payload + hln + pln + hln, pln);
+	}
+
+	switch (op) {
+	/* Request */
+	case 1:
+		return snprintf(buf, buflen, "%s %s: who has %s? tell %s (%s)",
+				shwtype, sop, tsp, ssp, ssh);
+	/* Reply */
+	case 2:
+		return snprintf(buf, buflen, "%s %s: %s is at %s", 
+				shwtype, sop, ssp, ssh);
+	default:
+		return snprintf(buf, buflen, "%s %s %s/%s > %s/%s", 
+				shwtype, sop, ssh, ssp, tsh, tsp);
+	}
+		
 }
 
 void rarp_decode(struct packet *p)
@@ -97,5 +249,5 @@
 	.author_name	= "Gianni Tedesco",
 	.author_email	= "gianni@xxxxxxxxxxxxxxxx",
 	.ver_major	= 2,
-	.ver_minor	= 0,
+	.ver_minor	= 1,
 };

Attachment: signature.asc
Description: This is a digitally signed message part