package com.netifera.platform.net.internal.pcap.linux; import com.netifera.platform.net.pcap.Datalink; class LinuxArpMap { private final LinuxPacketCapture pcap; LinuxArpMap(LinuxPacketCapture pcap) { this.pcap = pcap; } /* * Linux uses the ARP hardware type to identify the type of an * interface. pcap uses the DLT_xxx constants for this. This * function takes a pointer to a "pcap_t", and an ARPHRD_xxx * constant, as arguments, and sets "handle->linktype" to the * appropriate DLT_XXX constant and sets "handle->offset" to * the appropriate value (to make "handle->offset" plus link-layer * header length be a multiple of 4, so that the link-layer nextPacket * will be aligned on a 4-byte boundary when capturing packets). * (If the offset isn't set here, it'll be 0; add code as appropriate * for cases where it shouldn't be 0.) * * If "cooked_ok" is non-zero, we can use DLT_LINUX_SLL and capture * in cooked mode; otherwise, we can't use cooked mode, so we have * to pick some type that works in raw mode, or fail. * * Sets the link type to DLT_NULL if unable to map the type. */ @SuppressWarnings("fallthrough") public boolean mapToDlt(int arptype, boolean cooked_ok) { switch (arptype) { case Constants.ARPHRD_ETHER: /* * This is (presumably) a real Ethernet capture; give it a * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so * that an application can let you choose it, in case you're * capturing DOCSIS traffic that a Cisco Cable Modem * Termination System is putting out onto an Ethernet (it * doesn't put an Ethernet header onto the wire, it puts raw * DOCSIS frames out on the wire inside the low-level * Ethernet framing). * * XXX - are there any sorts of "fake Ethernet" that have * ARPHRD_ETHER but that *shouldn't offer DLT_DOCSIS as * a Cisco CMTS won't put traffic onto it or get traffic * bridged onto it? ISDN is handled in "live_open_new()", * as we fall back on cooked mode there; are there any * others? */ pcap.dltListClear(); pcap.dltListAdd(Datalink.DLT_EN10MB); pcap.dltListAdd(Datalink.DLT_DOCSIS); /* FALLTHROUGH */ case Constants.ARPHRD_METRICOM: case Constants.ARPHRD_LOOPBACK: pcap.setOffset(2); pcap.setLinkType(Datalink.DLT_EN10MB); break; case Constants.ARPHRD_EETHER: pcap.setLinkType(Datalink.DLT_EN3MB); break; case Constants.ARPHRD_AX25: pcap.setLinkType(Datalink.DLT_AX25); break; case Constants.ARPHRD_PRONET: pcap.setLinkType(Datalink.DLT_PRONET); break; case Constants.ARPHRD_CHAOS: pcap.setLinkType(Datalink.DLT_CHAOS); break; case Constants.ARPHRD_IEEE802_TR: case Constants.ARPHRD_IEEE802: pcap.setOffset(2); pcap.setLinkType(Datalink.DLT_IEEE802); break; case Constants.ARPHRD_ARCNET: pcap.setLinkType(Datalink.DLT_ARCNET_LINUX); break; case Constants.ARPHRD_FDDI: pcap.setOffset(3); pcap.setLinkType(Datalink.DLT_FDDI); break; case Constants.ARPHRD_ATM: /* * The Classical IP implementation in ATM for Linux * supports both what RFC 1483 calls "LLC Encapsulation", * in which each packet has an LLC header, possibly * with a SNAP header as well, prepended to it, and * what RFC 1483 calls "VC Based Multiplexing", in which * different virtual circuits carry different network * layer protocols, and no header is prepended to packets. * * They both have an ARPHRD_ type of ARPHRD_ATM, so * you can't use the ARPHRD_ type to find out whether * captured packets will have an LLC header, and, * while there's a socket ioctl to *set* the encapsulation * type, there's no ioctl to *get* the encapsulation type. * * This means that * * programs that dissect Linux Classical IP frames * would have to check for an LLC header and, * depending on whether they see one or not, dissect * the frame as LLC-encapsulated or as raw IP (I * don't know whether there's any traffic other than * IP that would show up on the socket, or whether * there's any support for IPv6 in the Linux * Classical IP code); * * filter expressions would have to compile into * code that checks for an LLC header and does * the right thing. * * Both of those are a nuisance - and, at least on systems * that support PF_PACKET sockets, we don't have to put * up with those nuisances; instead, we can just capture * in cooked mode. That's what we'll do, if we can. * Otherwise, we'll just fail. */ if (cooked_ok) pcap.setLinkType(Datalink.DLT_LINUX_SLL); else pcap.setLinkType(Datalink.DLT_NULL); break; case Constants.ARPHRD_IEEE80211: pcap.setLinkType(Datalink.DLT_IEEE802_11); break; case Constants.ARPHRD_IEEE80211_PRISM: pcap.setLinkType(Datalink.DLT_PRISM_HEADER); break; case Constants.ARPHRD_IEEE80211_RADIOTAP: pcap.setLinkType(Datalink.DLT_IEEE802_11_RADIO); break; case Constants.ARPHRD_PPP: /* * Some PPP code in the kernel supplies no link-layer * header whatsoever to PF_PACKET sockets; other PPP * code supplies PPP link-layer headers ("syncppp.c"); * some PPP code might supply random link-layer * headers (PPP over ISDN - there's code in Ethereal, * for example, to cope with PPP-over-ISDN captures * with which the Ethereal developers have had to cope, * heuristically trying to determine which of the * oddball link-layer headers particular packets have). * * As such, we just punt, and run all PPP interfaces * in cooked mode, if we can; otherwise, we just treat * it as DLT_RAW, for now - if somebody needs to capture, * on a 2.0[.x] kernel, on PPP devices that supply a * link-layer header, they'll have to add code here to * map to the appropriate DLT_ type (possibly adding a * new DLT_ type, if necessary). */ if (cooked_ok) { pcap.setLinkType(Datalink.DLT_LINUX_SLL); } else { /* * XXX - handle ISDN types here? We can't fall * back on cooked sockets, so we'd have to * figure out from the device name what type of * link-layer encapsulation it's using, and map * that to an appropriate DLT_ value, meaning * we'd map "isdnN" devices to DLT_RAW (they * supply raw IP packets with no link-layer * header) and "isdY" devices to a new DLT_I4L_IP * type that has only an Ethernet packet type as * a link-layer header. * * But sometimes we seem to get random crap * in the link-layer header when capturing on * ISDN devices.... */ pcap.setLinkType(Datalink.DLT_RAW); } break; case Constants.ARPHRD_CISCO: pcap.setLinkType(Datalink.DLT_C_HDLC); break; /* Not sure if this is correct for all tunnels, but it * works for CIPE */ case Constants.ARPHRD_TUNNEL: case Constants.ARPHRD_SIT: case Constants.ARPHRD_CSLIP: case Constants.ARPHRD_SLIP6: case Constants.ARPHRD_CSLIP6: case Constants.ARPHRD_ADAPT: case Constants.ARPHRD_SLIP: case Constants.ARPHRD_RAWHDLC: case Constants.ARPHRD_DLCI: /* * XXX - should some of those be mapped to DLT_LINUX_SLL * instead? Should we just map all of them to DLT_LINUX_SLL? */ pcap.setLinkType(Datalink.DLT_RAW); break; case Constants.ARPHRD_FRAD: pcap.setLinkType(Datalink.DLT_FRELAY); break; case Constants.ARPHRD_LOCALTLK: pcap.setLinkType(Datalink.DLT_LTALK); break; case Constants.ARPHRD_FCPP: case Constants.ARPHRD_FCAL: case Constants.ARPHRD_FCPL: case Constants.ARPHRD_FCFABRIC: /* * We assume that those all mean RFC 2625 IP-over- * Fibre Channel, with the RFC 2625 header at * the beginning of the packet. */ pcap.setLinkType(Datalink.DLT_IP_OVER_FC); break; case Constants.ARPHRD_IRDA: /* Don't expect IP packet out of this interfaces... */ pcap.setLinkType(Datalink.DLT_LINUX_IRDA); break; /* We need to save packet direction for IrDA decoding, * so let's use "Linux-cooked" mode. Jean II */ //handle->md.cooked = 1; /* ARPHRD_LAPD is unofficial and randomly allocated, if reallocation * is needed, please report it to <daniele@orlandi.com> */ case Constants.ARPHRD_LAPD: /* Don't expect IP packet out of this interfaces... */ pcap.setLinkType(Datalink.DLT_LINUX_LAPD); break; case Constants.ARPHRD_NONE: /* * No link-layer header; packets are just IP packets, so use DLT_RAW */ pcap.setLinkType(Datalink.DLT_RAW); break; default: return false; } return true; } }