Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 8 Dec 2010 03:19:14 +0800
From:      rozhuk.im@gmail.com
To:        <freebsd-net@freebsd.org>
Subject:   [arp] possible DoS, fixes and improvements
Message-ID:  <4cfe88b6.1cedd80a.33f5.119d@mx.google.com>

index | next in thread | raw e-mail

[-- Attachment #1 --]
Hi!


1. ah->ar_hln - is depend from ar_hrd?
Yes, and for ARPHRD_ETHER is 6 (ETHER_ADDR_LEN)
For ARPHRD_IEEE1394 - sizeof(struct fw_hwaddr)
ah->ar_hln ignored in ether_output: bcopy(ar_tha(ah), edst, ETHER_ADDR_LEN);

check in in_arpinput:
		if (ifp->if_addrlen != ah->ar_hln) {
			LLE_WUNLOCK(la);
			log(LOG_WARNING,
			    "arp from %*D: addr len: new %d, i/f %d
(ignored)",
			    ifp->if_addrlen, (u_char *) ar_sha(ah), ":",
			    ah->ar_hln, ifp->if_addrlen);
			goto reply;
		}
NO DROP!!!!
In reply we get:
		(void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln);
		(void)memcpy(ar_sha(ah), enaddr, ah->ar_hln);
Or 
			(void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln);
			(void)memcpy(ar_sha(ah), &lle->ll_addr, ah->ar_hln);

How to use it see below.


2. ah->ar_pln - does not checked!
We can make big arp request (512 nulls after struct arphdr + 2*6 + 2*4) ,
valid for host, set ar_plt = 255
And in reply will receive part of stack or core panic:
in_arpinput:
(void)memcpy(ar_spa(ah), &itaddr, ah->ar_pln);
...
m->m_len = sizeof(*ah) + (2 * ah->ar_pln) + (2 * ah->ar_hln);
( eq arphdr_len(ah) )



3. ar_sha(ah) - does not checked for multicast!
Answers to request my be send to multicast addrs
Only broadcast and host addr are checked.
No check is ar_sha(ah) equal to Ethernet.ether_shost
As result:
arp -an
? (172.16.0.2) at 01:80:c2:00:00:01 on em0 expires in 118 seconds [ethernet]



4. holded packet my be sended without any locks

Current:
		if (la->la_hold != NULL) {
			struct mbuf *m_hold, *m_hold_next;

			bcopy(L3_ADDR(la), &sa, sizeof(sa));
			LLE_WUNLOCK(la);
			for (m_hold = la->la_hold, la->la_hold = NULL;
			     m_hold != NULL; m_hold = m_hold_next) {
				m_hold_next = m_hold->m_nextpkt;
				m_hold->m_nextpkt = NULL;
				(*ifp->if_output)(ifp, m_hold, &sa, NULL);
			}
		} else
			LLE_WUNLOCK(la);
		la->la_hold = NULL;
		la->la_numheld = 0;

Here we unlock la and then modify them - this is bad idea!
Patched - see in attached patch.


This sample will work only for Ethernet without locks
if_output -> call arplookup again for every packet for sa_family = AF_INET
AF_UNSPEC - just copy ether_type/arc_type/... and L2 addr from dst->sa_data

		struct mbuf *m_hold, *m_hold_next;
		struct sockaddr dst;

		m_hold = la->la_hold;
		if (m_hold != NULL) {
			dst.sa_len = sizeof(dst);
			dst.sa_family = AF_UNSPEC;	/* prevent call
arpresolve, we know L2 addr dst */

			switch (ntohs(ah->ar_hrd)){
			case ARPHRD_ETHER:
				((struct
ether_header*)&dst.sa_data)->ether_type = ah->ar_pro;
				bcopy(ar_sha(ah), ((struct
ether_header*)&dst.sa_data)->ether_dhost, ah->ar_hln);
				break;
			//case ARPHRD_IEEE802:
			//	break;
			//case ARPHRD_ARCNET:
			//	((struct arc_header
*)&dst.sa_data)->arc_type = ah->ar_pro;
			//	bcopy(ar_sha(ah), ((struct arc_header
*)&dst.sa_data)->arc_dhost, ah->ar_hln);
			//	break;
			//case ARPHRD_FRELAY:
			//	break;
			//case ARPHRD_IEEE1394:
			//	break;
			default:
				bcopy(L3_ADDR(la), &dst, sizeof(dst));
			}
		}
		la->la_hold = NULL;
		la->la_numheld = 0;

		LLE_WUNLOCK(la);

		for (; m_hold != NULL; m_hold = m_hold_next) {
			m_hold_next = m_hold->m_nextpkt;
			m_hold->m_nextpkt = NULL;
			(*ifp->if_output)(ifp, m_hold, &dst, NULL);
		}

Do I need include this improvement in next patch?


Will attached patch included in mainstream code?



PS: patch contain fixes and some code cleanup and improvements.
Only basics tests done, not tested in production.


PPS: tests for 1 and 2
Part of code to generate arp packet

	struct arphdr *ah;
	u_char buff[2048];
	u_int32_t src, dst;

	bzero(buff, sizeof(buff));
	ah = (struct arphdr *)buff;

	src = INET_ADDR(172,16,0,2);
	dst = INET_ADDR(172,16,0,254);// - target!

	ah->ar_hrd = htons(ARPHRD_ETHER);
	ah->ar_pro = htons(ETHERTYPE_IP);
	ah->ar_op = htons(ARPOP_REQUEST);
	ah->ar_hln = 255;//ETHER_ADDR_LEN;
	ah->ar_pln = 255;//INET_ADDR_LEN;
	ETHER_ADDR_COPY(ar_sha(ah), ether_shost);
	INET_ADDR_COPY(ar_spa(ah), &src);
	INET_ADDR_COPY(ar_tpa(ah), &dst);

send_ether(bpf, ether_dhost, ether_shost, ETHERTYPE_ARP, (u_char*)ah, 1200);

returned answer is 1042 bytes size, no core panic
tested on my home freebsd box (i386, 8.2 @ E5300), with custom kernel


0x0030 x 0000 0000 0018 0000 0000 0000 00ff ffff x ................
0x0040 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x0050 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x0060 x 0000 0000 0000 0000 0000 0000 0000 6a2f x ..............j/
0x0070 x c5a0 522f c580 552f c500 412f c500 0008 x ..R/..U/..A/....
0x0080 x f100 0000 f101 b000 0000 000a f100 0000 x ................
0x0090 x 0000 0000 0000 0000 0086 801f a086 80d3 x ................
0x00A0 x 1007 0010 0002 0000 0000 0801 1100 0000 x ................
0x00B0 x 0006 0000 0000 0000 0002 0000 0022 c8cc x ............."..
0x00C0 x cecf 0000 0000 0000 0000 0000 0000 0000 x ................
0x00D0 x 0000 0000 0000 0000 0000 0000 0080 00d0 x ................
0x00E0 x 0100 0000 0000 0000 0000 0000 0000 0000 x ................
0x00F0 x 0000 0000 0004 8005 00a0 1c1c 0000 0000 x ................
0x0100 x 0000 2000 0003 00ac 1000 feac 1000 0210 x ................
0x0110 x 0200 00ac 1000 0200 0000 0000 0000 00a0 x ................
0x0120 x 3520 c570 3820 c5a0 3520 c5a0 3520 c502 x 5..p8...5...5...
0x0130 x e249 fb00 0000 0000 8121 c900 58c2 c07c x .I.......!..X..|
0x0140 x 7cdb c4ea 6856 c000 8121 c9c0 066c c001 x |...hV...!...l..
0x0150 x 0000 0002 0000 0060 7cdb c4a0 3520 c5a0 x .......`|...5...
0x0160 x 3520 c5c4 0000 007f ffff ff80 0000 00cc x 5...............
0x0170 x 59c2 c001 0000 0007 0000 00c0 c31e c500 x Y...............
0x0180 x 5e1c c5a0 3520 c5ac 7cdb c49e 0d49 c000 x ^...5...|....I..
0x0190 x 58c2 c0ec e64b c000 0000 0009 0100 0047 x X....K.........G
0x01A0 x d152 e8a0 3520 c500 0000 0000 5e1c c530 x .R..5.......^..0
0x01B0 x d11e c5a0 3520 c5dc 7cdb c43e 2649 c0a0 x ....5...|..>&I..
0x01C0 x 1a20 c500 5e1c c57d c565 c02d 0500 0070 x ....^..}.e.-...p
0x01D0 x 5e1c c56c 5e1c c5a0 1a20 c530 d11e c5a0 x ^..l^......0....
0x01E0 x 3520 c500 0000 0014 7ddb c4fd e948 c030 x 5.......}....H.0
0x01F0 x d11e c528 7ddb c400 0000 0000 0000 0000 x ...(}...........
0x0200 x 0000 0000 0000 001d 0ff2 4b4a 0000 0000 x ..........KJ....
0x0210 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x0220 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x0230 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x0240 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x0250 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x0260 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x0270 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x0280 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x0290 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x02A0 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x02B0 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x02C0 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x02D0 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x02E0 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x02F0 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x0300 x 0000 0000 00ac 1000 0200 0000 0000 0000 x ................
0x0310 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x0320 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x0330 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x0340 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x0350 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x0360 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x0370 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x0380 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x0390 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x03A0 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x03B0 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x03C0 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x03D0 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x03E0 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x03F0 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x0400 x 0000 0000                               x ....




ah->ar_hln = ETHER_ADDR_LEN; // = 6
ah->ar_pln = 255;//INET_ADDR_LEN;

0x0000 x 0001 0800 06ff 0002 001b 214f f5b3 ac10 x ..........!O....
0x0010 x 00fe ac10 0002 1002 0000 ac10 0002 0000 x ................
0x0020 x 0000 0000 0000 a035 20c5 0000 0000 a035 x .......5.......5
0x0030 x 20c5 a035 20c5 02e2 49fb 0000 0000 00c4 x ...5....I.......
0x0040 x 26c9 0058 c2c0 7c7c dbc4 ea68 56c0 00c4 x &..X..||...hV...
0x0050 x 26c9 c006 6cc0 0100 0000 0200 0000 607c x &...l.........`|
0x0060 x dbc4 a035 20c5 a035 20c5 c400 0000 7fff x ...5...5........
0x0070 x ffff 8000 0000 cc59 c2c0 0100 0000 0700 x .......Y........
0x0080 x 0000 c0c3 1ec5 005e 1cc5 a035 20c5 ac7c x .......^...5...|
0x0090 x dbc4 9e0d 49c0 0058 c2c0 ece6 4bc0 0000 x ....I..X....K...
0x00A0 x 0000 0901 0000 dedc 6b6f a035 20c5 0000 x ........ko.5....
0x00B0 x 0000 005e 1cc5 30d1 1ec5 a035 20c5 dc7c x ...^..0....5...|
0x00C0 x dbc4 3e26 49c0 a01a 20c5 005e 1cc5 7dc5 x ..>&I......^..}.
0x00D0 x 65c0 2d05 0000 705e 1cc5 6c5e 1cc5 a01a x e.-...p^..l^....
0x00E0 x 20c5 30d1 1ec5 a035 20c5 0000 0000 147d x ..0....5.......}
0x00F0 x dbc4 fde9 48c0 30d1 1ec5 287d dbc4 0000 x ....H.0...(}....
0x0100 x 0000 0000 0000 0000 0000 0000 0000 1d0f x ................
0x0110 x f24b 4aac 1000 0200 0000 0000 0000 0000 x .KJ.............
0x0120 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x0130 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x0140 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x0150 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x0160 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x0170 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x0180 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x0190 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x01A0 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x01B0 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x01C0 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x01D0 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x01E0 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x01F0 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x0200 x 0000 0000 0000 0000 0000 0000 0000 0000 x ................
0x0210 x 0000                                    x ..


 
--
Rozhuk Ivan
  



[-- Attachment #2 --]
--- /usr/src/sys/netinet/if_ether.orig	2010-12-02 16:52:06.000000000 +0800
+++ /usr/src/sys/netinet/if_ether.c	2010-12-08 02:49:07.000000000 +0800
@@ -57,6 +57,9 @@
 #include <net/netisr.h>
 #include <net/if_llc.h>
 #include <net/ethernet.h>
+#include <net/iso88025.h>
+#include <net/if_arc.h>
+#include <net/firewire.h>
 #include <net/route.h>
 #include <net/vnet.h>
 
@@ -246,7 +249,7 @@
 	m->m_pkthdr.len = m->m_len;
 	MH_ALIGN(m, m->m_len);
 	ah = mtod(m, struct arphdr *);
-	bzero((caddr_t)ah, m->m_len);
+	bzero(ah, m->m_len);
 #ifdef MAC
 	mac_netinet_arp_send(ifp, m);
 #endif
@@ -254,9 +257,9 @@
 	ah->ar_hln = ifp->if_addrlen;		/* hardware address length */
 	ah->ar_pln = sizeof(struct in_addr);	/* protocol address length */
 	ah->ar_op = htons(ARPOP_REQUEST);
-	bcopy((caddr_t)enaddr, (caddr_t)ar_sha(ah), ah->ar_hln);
-	bcopy((caddr_t)sip, (caddr_t)ar_spa(ah), ah->ar_pln);
-	bcopy((caddr_t)tip, (caddr_t)ar_tpa(ah), ah->ar_pln);
+	bcopy(enaddr, ar_sha(ah), ah->ar_hln);
+	bcopy(sip, ar_spa(ah), ah->ar_pln);
+	bcopy(tip, ar_tpa(ah), ah->ar_pln);
 	sa.sa_family = AF_ARP;
 	sa.sa_len = 2;
 	m->m_flags |= M_BCAST;
@@ -292,8 +295,7 @@
 	if (m != NULL) {
 		if (m->m_flags & M_BCAST) {
 			/* broadcast */
-			(void)memcpy(desten,
-			    ifp->if_broadcastaddr, ifp->if_addrlen);
+			bcopy(ifp->if_broadcastaddr, desten, ifp->if_addrlen);
 			return (0);
 		}
 		if (m->m_flags & M_MCAST && ifp->if_type != IFT_ARCNET) {
@@ -429,42 +431,68 @@
 static void
 arpintr(struct mbuf *m)
 {
-	struct arphdr *ar;
+	struct arphdr *ah;
 
 	if (m->m_len < sizeof(struct arphdr) &&
 	    ((m = m_pullup(m, sizeof(struct arphdr))) == NULL)) {
 		log(LOG_ERR, "arp: runt packet -- m_pullup failed\n");
 		return;
 	}
-	ar = mtod(m, struct arphdr *);
+	ah = mtod(m, struct arphdr *);
 
-	if (ntohs(ar->ar_hrd) != ARPHRD_ETHER &&
-	    ntohs(ar->ar_hrd) != ARPHRD_IEEE802 &&
-	    ntohs(ar->ar_hrd) != ARPHRD_ARCNET &&
-	    ntohs(ar->ar_hrd) != ARPHRD_IEEE1394) {
-		log(LOG_ERR, "arp: unknown hardware address format (0x%2D)\n",
-		    (unsigned char *)&ar->ar_hrd, "");
-		m_freem(m);
-		return;
+	/* check hw addr len and hw addr */
+	switch (ntohs(ah->ar_hrd)){
+	case ARPHRD_ETHER:
+		if (ah->ar_hln != ETHER_ADDR_LEN) {
+			log(LOG_ERR, "arp: invalid length of hardware address\n");
+			goto drop;
+		}
+		/* is from [multi/broad]cast? - sender cant be [multi/broad]cast! */
+		if (ETHER_IS_MULTICAST(ar_sha(ah)) != 0) {
+			log(LOG_ERR, "arp: link address is multicast\n");
+			goto drop;
+		}
+		break;
+	case ARPHRD_IEEE802:
+		if (ah->ar_hln != ISO88025_ADDR_LEN)
+			goto drop;
+		break;
+	case ARPHRD_ARCNET:
+		if (ah->ar_hln != ARC_ADDR_LEN)
+			goto drop;
+		break;
+	case ARPHRD_FRELAY:
+		if (ah->ar_hln != 2)
+			goto drop;
+		break;
+	case ARPHRD_IEEE1394:
+		if (ah->ar_hln != sizeof(struct fw_hwaddr)) /* XXX 8? */
+			goto drop;
+		break;
+	default:
+		log(LOG_ERR, "arp: unknown hardware address format\n");
+		goto drop;
 	}
 
-	if (m->m_len < arphdr_len(ar)) {
-		if ((m = m_pullup(m, arphdr_len(ar))) == NULL) {
+	if (m->m_len < arphdr_len(ah)) {
+		if ((m = m_pullup(m, arphdr_len(ah))) == NULL) {
 			log(LOG_ERR, "arp: runt packet\n");
-			m_freem(m);
 			return;
 		}
-		ar = mtod(m, struct arphdr *);
+		ah = mtod(m, struct arphdr *);
 	}
 
 	ARPSTAT_INC(received);
-	switch (ntohs(ar->ar_pro)) {
+	switch (ntohs(ah->ar_pro)) {
 #ifdef INET
 	case ETHERTYPE_IP:
 		in_arpinput(m);
 		return;
 #endif
 	}
+
+	log(LOG_ERR, "arp: unknown format of protocol address\n");
+drop:
 	m_freem(m);
 }
 
@@ -507,11 +535,10 @@
 	struct rtentry *rt;
 	struct ifaddr *ifa;
 	struct in_ifaddr *ia;
-	struct sockaddr sa;
+	struct sockaddr dst;
 	struct in_addr isaddr, itaddr, myaddr;
 	u_int8_t *enaddr = NULL;
 	int op, flags;
-	int req_len;
 	int bridged = 0, is_bridge = 0;
 	int carp_match = 0;
 	struct sockaddr_in sin;
@@ -519,25 +546,25 @@
 	sin.sin_family = AF_INET;
 	sin.sin_addr.s_addr = 0;
 
-	if (ifp->if_bridge)
-		bridged = 1;
-	if (ifp->if_type == IFT_BRIDGE)
-		is_bridge = 1;
 
-	req_len = arphdr_len2(ifp->if_addrlen, sizeof(struct in_addr));
-	if (m->m_len < req_len && (m = m_pullup(m, req_len)) == NULL) {
-		log(LOG_ERR, "in_arp: runt packet -- m_pullup failed\n");
-		return;
+	ah = mtod(m, struct arphdr *);
+	if (ah->ar_pln != sizeof(struct in_addr)) {
+		log(LOG_ERR, "arp: invalid length of protocol address\n");
+		goto drop;
 	}
 
-	ah = mtod(m, struct arphdr *);
 	op = ntohs(ah->ar_op);
-	(void)memcpy(&isaddr, ar_spa(ah), sizeof (isaddr));
-	(void)memcpy(&itaddr, ar_tpa(ah), sizeof (itaddr));
+	bcopy(ar_spa(ah), &isaddr, sizeof (isaddr));
+	bcopy(ar_tpa(ah), &itaddr, sizeof (itaddr));
 
 	if (op == ARPOP_REPLY)
 		ARPSTAT_INC(rxreplies);
 
+	if (ifp->if_bridge)
+		bridged = 1;
+	if (ifp->if_type == IFT_BRIDGE)
+		is_bridge = 1;
+
 	/*
 	 * For a bridge, we want to check the address irrespective
 	 * of the receive interface. (This will change slightly
@@ -626,6 +653,15 @@
 		enaddr = (u_int8_t *)IF_LLADDR(ifp);
 	myaddr = ia->ia_addr.sin_addr;
 	ifa_free(&ia->ia_ifa);
+
+	/* XXX length of hardware address (ar_hln) already checked in arpintr */
+	if (ifp->if_addrlen != ah->ar_hln) {
+		log(LOG_WARNING,
+		    "arp from %*D: addr len: new %d, i/f %d (ignored)",
+		    ifp->if_addrlen, (u_char *) ar_sha(ah), ":",
+		    ah->ar_hln, ifp->if_addrlen);
+		goto drop;
+	}
 	if (!bcmp(ar_sha(ah), enaddr, ifp->if_addrlen))
 		goto drop;	/* it's from me, ignore it. */
 	if (!bcmp(ar_sha(ah), ifp->if_broadcastaddr, ifp->if_addrlen)) {
@@ -695,16 +731,8 @@
 				    ifp->if_xname);
 			}
 		}
-		    
-		if (ifp->if_addrlen != ah->ar_hln) {
-			LLE_WUNLOCK(la);
-			log(LOG_WARNING,
-			    "arp from %*D: addr len: new %d, i/f %d (ignored)",
-			    ifp->if_addrlen, (u_char *) ar_sha(ah), ":",
-			    ah->ar_hln, ifp->if_addrlen);
-			goto reply;
-		}
-		(void)memcpy(&la->ll_addr, ar_sha(ah), ifp->if_addrlen);
+
+		bcopy(ar_sha(ah), &la->ll_addr, ifp->if_addrlen);
 		la->la_flags |= LLE_VALID;
 
 		EVENTHANDLER_INVOKE(arp_update_event, la);
@@ -728,31 +756,31 @@
 		 * NB: The lock MUST be released before the call to the
 		 * output routine.
 		 */
-		if (la->la_hold != NULL) {
-			struct mbuf *m_hold, *m_hold_next;
+		struct mbuf *m_hold, *m_hold_next;
 
-			memcpy(&sa, L3_ADDR(la), sizeof(sa));
-			LLE_WUNLOCK(la);
-			for (m_hold = la->la_hold, la->la_hold = NULL;
-			     m_hold != NULL; m_hold = m_hold_next) {
-				m_hold_next = m_hold->m_nextpkt;
-				m_hold->m_nextpkt = NULL;
-				(*ifp->if_output)(ifp, m_hold, &sa, NULL);
-			}
-		} else
-			LLE_WUNLOCK(la);
+		m_hold = la->la_hold;
+		if (m_hold != NULL)
+			bcopy(L3_ADDR(la), &dst, sizeof(dst));
 		la->la_hold = NULL;
 		la->la_numheld = 0;
-	} /* end of FIB loop */
+		LLE_WUNLOCK(la);
+
+		/* send packets to output */
+		for (; m_hold != NULL; m_hold = m_hold_next) {
+			m_hold_next = m_hold->m_nextpkt;
+			m_hold->m_nextpkt = NULL;
+			(*ifp->if_output)(ifp, m_hold, &dst, NULL);
+		}
+	}
 reply:
 	if (op != ARPOP_REQUEST)
 		goto drop;
 	ARPSTAT_INC(rxrequests);
 
+	bcopy(ar_sha(ah), ar_tha(ah), ah->ar_hln);
 	if (itaddr.s_addr == myaddr.s_addr) {
 		/* Shortcut.. the receiving interface is the target. */
-		(void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln);
-		(void)memcpy(ar_sha(ah), enaddr, ah->ar_hln);
+		bcopy(enaddr, ar_sha(ah), ah->ar_hln);
 	} else {
 		struct llentry *lle = NULL;
 
@@ -762,8 +790,7 @@
 		IF_AFDATA_UNLOCK(ifp);
 
 		if ((lle != NULL) && (lle->la_flags & LLE_PUB)) {
-			(void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln);
-			(void)memcpy(ar_sha(ah), &lle->ll_addr, ah->ar_hln);
+			bcopy(&lle->ll_addr, ar_sha(ah), ah->ar_hln);
 			LLE_RUNLOCK(lle);
 		} else {
 
@@ -790,9 +817,6 @@
 			}
 			RTFREE_LOCKED(rt);
 
-			(void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln);
-			(void)memcpy(ar_sha(ah), enaddr, ah->ar_hln);
-
 			/*
 			 * Also check that the node which sent the ARP packet
 			 * is on the the interface we expect it to be on. This
@@ -815,6 +839,8 @@
 			}
 			RTFREE_LOCKED(rt);
 
+			bcopy(enaddr, ar_sha(ah), ah->ar_hln);
+
 #ifdef DEBUG_PROXY
 			printf("arp: proxying for %s\n",
 			       inet_ntoa(itaddr));
@@ -835,15 +861,15 @@
 		/* default behaviour; never reply by broadcast. */
 		m->m_flags &= ~(M_BCAST|M_MCAST);
 	}
-	(void)memcpy(ar_tpa(ah), ar_spa(ah), ah->ar_pln);
-	(void)memcpy(ar_spa(ah), &itaddr, ah->ar_pln);
+	bcopy(ar_spa(ah), ar_tpa(ah), ah->ar_pln);
+	bcopy(&itaddr, ar_spa(ah), ah->ar_pln);
 	ah->ar_op = htons(ARPOP_REPLY);
 	ah->ar_pro = htons(ETHERTYPE_IP); /* let's be sure! */
-	m->m_len = sizeof(*ah) + (2 * ah->ar_pln) + (2 * ah->ar_hln);   
+	m->m_len = arphdr_len(ah);   
 	m->m_pkthdr.len = m->m_len;   
-	sa.sa_family = AF_ARP;
-	sa.sa_len = 2;
-	(*ifp->if_output)(ifp, m, &sa, NULL);
+	dst.sa_family = AF_ARP;
+	dst.sa_len = 2;
+	(*ifp->if_output)(ifp, m, &dst, NULL);
 	ARPSTAT_INC(txreplies);
 	return;
 
help

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?4cfe88b6.1cedd80a.33f5.119d>