Talk:Arp-scan User Guide

From royhills
Jump to: navigation, search

Misc Stuff

  • Detecting VMware systems
  • Detection of non-Ethernet interface addresses - can this be done?

802.2 LLC/SNAP examples

Windows 95

# arp-scan --llc 172.16.3.127
Interface: eth0, datalink type: EN10MB (Ethernet)
Starting arp-scan 1.7 with 1 hosts (http://www.nta-monitor.com/tools/arp-scan/)
172.16.3.127    00:0c:29:43:90:56       VMware, Inc.

Windows NT Server

$ arp-scan --llc -I eth0 192.168.124.202
Interface: eth0, datalink type: EN10MB (Ethernet)
Starting arp-scan 1.6.1 with 1 hosts (http://www.nta-monitor.com/tools/arp-scan/)
192.168.124.202 00:d0:b7:25:61:6c       INTEL CORPORATION

Windows 2000 Server (build 2195)

# arp-scan --llc 172.16.3.144
Interface: eth0, datalink type: EN10MB (Ethernet)
Starting arp-scan 1.7 with 1 hosts (http://www.nta-monitor.com/tools/arp-scan/)
172.16.3.144    00:0c:29:15:68:88       VMware, Inc.

Note: I cannot get responses from Windows 2000 system SERVER5 using --llc.

Windows 2000 professional w/ ArpUseEtherSNAP = 1

# arp-scan --llc 192.168.1.60
Interface: eth0, datalink type: EN10MB (Ethernet)
Starting arp-scan 1.7 with 1 hosts (http://www.nta-monitor.com/tools/arp-scan/)
192.168.1.60    00:0c:29:02:e2:5d       VMware, Inc. (802.2 LLC/SNAP)

Windows XP SP3

# arp-scan --llc 192.168.1.11
Interface: eth0, datalink type: EN10MB (Ethernet)
Starting arp-scan 1.7 with 1 hosts (http://www.nta-monitor.com/tools/arp-scan/)
192.168.1.11    00:07:e9:d5:6e:c2       Intel Corporation

Note: I cannot get responses from NTA XP workstations using --llc.

Windows 2003 Server

$ arp-scan --llc -I eth0 192.168.124.204
Interface: eth0, datalink type: EN10MB (Ethernet)
Starting arp-scan 1.6.1 with 1 hosts (http://www.nta-monitor.com/tools/arp-scan/)
192.168.124.204 00:11:43:0f:f2:dd       DELL INC.

Windows Vista SP1

# arp-scan --llc 192.168.1.50
Interface: eth0, datalink type: EN10MB (Ethernet)
Starting arp-scan 1.7 with 1 hosts (http://www.nta-monitor.com/tools/arp-scan/)
192.168.1.50    00:1d:09:94:3e:5f       Dell Inc

No Response from:

  • Linux 2.6.20
  • Solaris 8 (SPARC)
  • Solaris 10 (x86)
  • FreeBSD 7.0 (i386)
  • OpenBSD 3.9 (i386)
  • NetBSD 4.0 (i386)
  • Cisco PIX 7.0(7) (PIX 515E)
  • Novell Netware 6.5
  • SCO Openserver 5.0.7

Cisco IOS 12.2

$ arp-scan -I eth0 --llc 192.168.124.254
Interface: eth0, datalink type: EN10MB (Ethernet)
Starting arp-scan 1.6.1 with 1 hosts (http://www.nta-monitor.com/tools/arp-scan/)
192.168.124.254 00:60:5c:f4:c6:f4       CISCO SYSTEMS, INC. (802.2 LLC/SNAP)

Cisco Catalyst IOS 12.1(22) (2950)

$ arp-scan --llc 192.168.124.250
Interface: eth0, datalink type: EN10MB (Ethernet)
Starting arp-scan 1.6.3 with 1 hosts (http://www.nta-monitor.com/tools/arp-scan/)
192.168.124.250 00:12:00:2f:18:c0       Cisco (802.2 LLC/SNAP)

Microsoft Windows

From Microsoft KB Q140913 "Communicating over TCP/IP May Fail Due to 802.3 Frame Type":

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\ArpUseEtherSNAP

Description: Setting this parameter to 1 will force TCP/IP to transmit Ethernet packets using 802.3 SNAP encoding. By default, the stack transmits packets in DIX Ethernet format. Windows NT always receives both formats.

In Windows NT 3.1, when TCP/IP is used on an Ethernet network, it will use only the Ethernet II frame format. It will recognize a SNAP formatted ARP request, but will respond with an Ethernet II formatted ARP reply in the hopes that the remote station TCP/IP stack will recognize the frame type and switch to the Ethernet II frame format.

In Windows NT 3.5, 3.51, and 4.0, there is a registry parameter (ArpUseEtherSNAP) that instructs TCP/IP to use SNAP on an Ethernet (802.3) network. With this parameter set, TCP/IP uses SNAP to encapsulate IP, ICMP, and ARP frames in 802.3 frames. If, however, a SNAP-encapsulated ARP request is responded to with an Ethernet II format ARP reply, or if a Ethernet II format ARP request is received, TCP/IP will automatically switch to using Ethernet II frames on that link.

ARP Implementation Source Code

4.1c BSD

"if_ether.c 4.1 83/03/15"

4.2 BSD

4.2BSD was released in August 1983. The ARP code is in /usr/src/sys/netinet/if_ether.c, which has the version string: "if_ether.c 6.2 83/08/28" The function involved in the processing of received ARP requests is arpinput():

/*
 * Called from ecintr/ilintr when ether packet type ETHERPUP_ARP
 * is received.  Algorithm is exactly that given in RFC 826.
 * In addition, a sanity check is performed on the sender
 * protocol address, to catch impersonators.
 */
arpinput(ac, m)
	register struct arpcom *ac;
	struct mbuf *m;
{
	register struct ether_arp *ea;
	struct ether_header *eh;
	register struct arptab *at = 0;  /* same as "merge" flag */
	struct sockaddr_in sin;
	struct sockaddr sa;
	struct mbuf *mhold;
	struct in_addr isaddr,itaddr,myaddr;

	if (m->m_len < sizeof *ea)
		goto out;
	myaddr = ((struct sockaddr_in *)&ac->ac_if.if_addr)->sin_addr;
	ea = mtod(m, struct ether_arp *);
	if (ntohs(ea->arp_pro) != ETHERPUP_IPTYPE)
		goto out;
	isaddr.s_addr = ((struct in_addr *)ea->arp_spa)->s_addr;
	itaddr.s_addr = ((struct in_addr *)ea->arp_tpa)->s_addr;
	if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)ac->ac_enaddr,
	  sizeof (ac->ac_enaddr)))
		goto out;	/* it's from me, ignore it. */
	if (isaddr.s_addr == myaddr.s_addr) {
		printf("duplicate IP address!! sent from ethernet address: ");
		printf("%x %x %x %x %x %x\n", ea->arp_sha[0], ea->arp_sha[1],
		    ea->arp_sha[2], ea->arp_sha[3],
		    ea->arp_sha[4], ea->arp_sha[5]);
		if (ntohs(ea->arp_op) == ARPOP_REQUEST)
			goto reply;
		goto out;
	}
	ARPTAB_LOOK(at, isaddr.s_addr);
	if (at) {
		bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr,
		   sizeof (ea->arp_sha));
		at->at_flags |= ATF_COM;
		if (at->at_hold) {
			mhold = at->at_hold;
			at->at_hold = 0;
			sin.sin_family = AF_INET;
			sin.sin_addr = isaddr;
			(*ac->ac_if.if_output)(&ac->ac_if, 
			    mhold, (struct sockaddr *)&sin);
		}
	}
	if (itaddr.s_addr != myaddr.s_addr)
		goto out;	/* if I am not the target */
	if (at == 0) {		/* ensure we have a table entry */
		at = arptnew(&isaddr);
		bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr,
		   sizeof (ea->arp_sha));
		at->at_flags |= ATF_COM;
	}
	if (ntohs(ea->arp_op) != ARPOP_REQUEST)
		goto out;
reply:
	bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha,
	   sizeof (ea->arp_sha));
	bcopy((caddr_t)ea->arp_spa, (caddr_t)ea->arp_tpa,
	   sizeof (ea->arp_spa));
	bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
	   sizeof (ea->arp_sha));
	bcopy((caddr_t)&myaddr, (caddr_t)ea->arp_spa,
	   sizeof (ea->arp_spa));
	ea->arp_op = htons(ARPOP_REPLY);
	eh = (struct ether_header *)sa.sa_data;
	bcopy((caddr_t)ea->arp_tha, (caddr_t)eh->ether_dhost,
	   sizeof (eh->ether_dhost));
	eh->ether_type = ETHERPUP_ARPTYPE;
	sa.sa_family = AF_UNSPEC;
	(*ac->ac_if.if_output)(&ac->ac_if, m, &sa);
	return;
out:
	m_freem(m);
	return;
}

BSD Net/2

BSD Net/2 was released in June 1991, and the networking code was widely used. The ARP code is in /usr/src/sys/netinet/if_ether.c, which has the SCCS id "@(#)if_ether.c 7.13 (Berkeley) 10/31/90" in this file. The functions involved in the processing of received ARP requests are arpinput() and in_arpinput(), which are reproduced below.

/*
 * Called from 10 Mb/s Ethernet interrupt handlers
 * when ether packet type ETHERTYPE_ARP
 * is received.  Common length and type checks are done here,
 * then the protocol-specific routine is called.
 */
arpinput(ac, m)
        struct arpcom *ac;
        struct mbuf *m;
{
        register struct arphdr *ar;

        if (ac->ac_if.if_flags & IFF_NOARP)
                goto out;
        if (m->m_len < sizeof(struct arphdr))
                goto out;
        ar = mtod(m, struct arphdr *);
        if (ntohs(ar->ar_hrd) != ARPHRD_ETHER)
                goto out;
        if (m->m_len < sizeof(struct arphdr) + 2 * ar->ar_hln + 2 * ar->ar_pln)
                goto out;

        switch (ntohs(ar->ar_pro)) {

        case ETHERTYPE_IP:
        case ETHERTYPE_IPTRAILERS:
                in_arpinput(ac, m);
                return;

        default:
                break;
        }
out:
        m_freem(m);
}
/*
 * ARP for Internet protocols on 10 Mb/s Ethernet.
 * Algorithm is that given in RFC 826.
 * In addition, a sanity check is performed on the sender
 * protocol address, to catch impersonators.
 * We also handle negotiations for use of trailer protocol:
 * ARP replies for protocol type ETHERTYPE_TRAIL are sent
 * along with IP replies if we want trailers sent to us,
 * and also send them in response to IP replies.
 * This allows either end to announce the desire to receive
 * trailer packets.
 * We reply to requests for ETHERTYPE_TRAIL protocol as well,
 * but don't normally send requests.
 */
in_arpinput(ac, m)
        register struct arpcom *ac;
        struct mbuf *m;
{
        register struct ether_arp *ea;
        struct ether_header *eh;
        register struct arptab *at;  /* same as "merge" flag */
        register struct in_ifaddr *ia;
        struct in_ifaddr *maybe_ia = 0;
        struct mbuf *mcopy = 0;
        struct sockaddr_in sin;
        struct sockaddr sa;
        struct in_addr isaddr, itaddr, myaddr;
        int proto, op, s, completed = 0;

        ea = mtod(m, struct ether_arp *);
        proto = ntohs(ea->arp_pro);
        op = ntohs(ea->arp_op);
        bcopy((caddr_t)ea->arp_spa, (caddr_t)&isaddr, sizeof (isaddr));
        bcopy((caddr_t)ea->arp_tpa, (caddr_t)&itaddr, sizeof (itaddr));
        for (ia = in_ifaddr; ia; ia = ia->ia_next)
                if (ia->ia_ifp == &ac->ac_if) {
                        maybe_ia = ia;
                        if ((itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) ||
                             (isaddr.s_addr == ia->ia_addr.sin_addr.s_addr))
                                break;
                }
        if (maybe_ia == 0)
                goto out;
        myaddr = ia ? ia->ia_addr.sin_addr : maybe_ia->ia_addr.sin_addr;
        if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)ac->ac_enaddr,
            sizeof (ea->arp_sha)))
                goto out;       /* it's from me, ignore it. */
        if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)etherbroadcastaddr,
            sizeof (ea->arp_sha))) {
                log(LOG_ERR,
                    "arp: ether address is broadcast for IP address %x!\n",
                    ntohl(isaddr.s_addr));
                goto out;
        }
        if (isaddr.s_addr == myaddr.s_addr) {
                log(LOG_ERR,
                   "duplicate IP address %x!! sent from ethernet address: %s\n",
                   ntohl(isaddr.s_addr), ether_sprintf(ea->arp_sha));
                itaddr = myaddr;
                if (op == ARPOP_REQUEST)
                        goto reply;
                goto out;
        }
        s = splimp();
        ARPTAB_LOOK(at, isaddr.s_addr);
        if (at) {
                bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr,
                    sizeof(ea->arp_sha));
                if ((at->at_flags & ATF_COM) == 0)
                        completed = 1;
                at->at_flags |= ATF_COM;
                if (at->at_hold) {
                        sin.sin_family = AF_INET;
                        sin.sin_addr = isaddr;
                        (*ac->ac_if.if_output)(&ac->ac_if, at->at_hold,
                                (struct sockaddr *)&sin, (struct rtentry *)0);
                        at->at_hold = 0;
                }
        }
        if (at == 0 && itaddr.s_addr == myaddr.s_addr) {
                /* ensure we have a table entry */
                if (at = arptnew(&isaddr)) {
                        bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr,
                            sizeof(ea->arp_sha));
                        completed = 1;
                        at->at_flags |= ATF_COM;
                }
        }
        splx(s);
reply:
        switch (proto) {

        case ETHERTYPE_IPTRAILERS:
                /* partner says trailers are OK */
                if (at)
                        at->at_flags |= ATF_USETRAILERS;
                /*
                 * Reply to request iff we want trailers.
                 */
                if (op != ARPOP_REQUEST || ac->ac_if.if_flags & IFF_NOTRAILERS)
                        goto out;
                break;

        case ETHERTYPE_IP:
                /*
                 * Reply if this is an IP request,
                 * or if we want to send a trailer response.
                 * Send the latter only to the IP response
                 * that completes the current ARP entry.
                 */
                if (op != ARPOP_REQUEST &&
                    (completed == 0 || ac->ac_if.if_flags & IFF_NOTRAILERS))
                        goto out;
        }
        if (itaddr.s_addr == myaddr.s_addr) {
                /* I am the target */
                bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha,
                    sizeof(ea->arp_sha));
                bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
                    sizeof(ea->arp_sha));
        } else {
                ARPTAB_LOOK(at, itaddr.s_addr);
                if (at == NULL || (at->at_flags & ATF_PUBL) == 0)
                        goto out;
                bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha,
                    sizeof(ea->arp_sha));
                bcopy((caddr_t)at->at_enaddr, (caddr_t)ea->arp_sha,
                    sizeof(ea->arp_sha));
        }

        bcopy((caddr_t)ea->arp_spa, (caddr_t)ea->arp_tpa,
            sizeof(ea->arp_spa));
        bcopy((caddr_t)&itaddr, (caddr_t)ea->arp_spa,
            sizeof(ea->arp_spa));
        ea->arp_op = htons(ARPOP_REPLY);
        /*
         * If incoming packet was an IP reply,
         * we are sending a reply for type IPTRAILERS.
         * If we are sending a reply for type IP
         * and we want to receive trailers,
         * send a trailer reply as well.
         */
        if (op == ARPOP_REPLY)
                ea->arp_pro = htons(ETHERTYPE_IPTRAILERS);
        else if (proto == ETHERTYPE_IP &&
            (ac->ac_if.if_flags & IFF_NOTRAILERS) == 0)
                mcopy = m_copy(m, 0, (int)M_COPYALL);
        eh = (struct ether_header *)sa.sa_data;
        bcopy((caddr_t)ea->arp_tha, (caddr_t)eh->ether_dhost,
            sizeof(eh->ether_dhost));
        eh->ether_type = ETHERTYPE_ARP;
        sa.sa_family = AF_UNSPEC;
        sa.sa_len = sizeof(sa);
        (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, (struct rtentry *)0);
        if (mcopy) {
                ea = mtod(mcopy, struct ether_arp *);
                ea->arp_pro = htons(ETHERTYPE_IPTRAILERS);
                (*ac->ac_if.if_output)(&ac->ac_if,
                                        mcopy, &sa, (struct rtentry *)0);
        }
        return;
out:
        m_freem(m);
        return;
}

Trailer Encapsulation

Trailer encapsulation was supported by early versions of BSD Unix on DEC VAX hardware. It used ARP packets to negotiate trailer support. quasijarus 4.3BSD on SIMH supports trailer encapsulation and negotiation, and trailer support is enabled by default.

A normal ARP request to a target with trailer encapsulation enabled will result in two response packets: first the normal ARP response, followed by a trailer ARP reply shortly afterwards. The trailer ARP reply is the same as the normal ARP reply, but with the ARP protocol field (ar$pro) set to 0x1000 rather than the standard 0x0800. Here is an example:

12:53:39.866290 arp reply 192.168.1.70 is-at 08:00:2b:12:34:56
12:53:39.866827 trailer-arp reply 192.168.1.70 is-at 08:00:2b:12:34:56

A test using ar$pro set to 0x1000 (ETHERTYPE_TRAIL) on our internal network shows that the netscreen and some printers respond.

$ arp-scan -I eth0 --arppro=0x1000 --localnet
Interface: eth0, datalink type: EN10MB (Ethernet)
Starting arp-scan 1.7 with 256 hosts (http://www.nta-monitor.com/tools/arp-scan/)
192.168.124.155 00:10:db:74:d0:52       Juniper Networks, Inc.
192.168.124.187 00:00:aa:a1:b3:60       XEROX CORPORATION
192.168.124.189 00:14:38:93:93:7e       Hewlett Packard
192.168.124.191 00:01:e6:57:8b:68       Hewlett-Packard Company

RFC 826 Implementation Pseudo Code

"When an address resolution packet is received, the receiving Ethernet module gives the packet to the Address Resolution module which goes through an algorithm similar to the following. Negative conditionals indicate an end of processing and a discarding of the packet."

?Do I have the hardware type in ar$hrd?
Yes: (almost definitely)
  [optionally check the hardware length ar$hln]
  ?Do I speak the protocol in ar$pro?
  Yes:
    [optionally check the protocol length ar$pln]
    Merge_flag := false
    If the pair <protocol type, sender protocol address> is
        already in my translation table, update the sender
	hardware address field of the entry with the new
	information in the packet and set Merge_flag to true. 
    ?Am I the target protocol address?
    Yes:
      If Merge_flag is false, add the triplet <protocol type,
          sender protocol address, sender hardware address> to
	  the translation table.
      ?Is the opcode ares_op$REQUEST?  (NOW look at the opcode!!)
      Yes:
	Swap hardware and protocol fields, putting the local
	    hardware and protocol addresses in the sender fields.
	Set the ar$op field to ares_op$REPLY
	Send the packet to the (new) target hardware address on
	    the same hardware on which the request was received.