Network.Security.Tools [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Network.Security.Tools [Electronic resources] - نسخه متنی

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید









10.2. Getting Started with libpcap



Now that we have
libpcap installed, we can write our first
network packet-capture tool. The example we are going to demonstrate
is a simple tool for capturing Address Resolution Protocol (ARP)
packets from a local network interface. A slightly more complex tool
utilizing libpcap to capture and process TCP
headers (SYNplescan) is discussed in Chapter 11.



Some of the operations we will undertake with
libpcap work only if you are running as the root
user. Therefore, tools written that use libpcap
(as per the examples) commonly need to be run by the root user, or be
SETUID root. Your tool should be careful of what it does with input
and captured packets so that it is not vulnerable to buffer overflows
and other security vulnerabilities. A well-written tool should
generally drop privileges after functions requiring root privileges
have been performed.




10.2.1. Overview of Arpsniff



ARP

is the protocol used in IP networks to map
network protocol addresses
(most often, IP addresses) to link layer
hardware addresses. When a system on a
network needs to communicate with another system on the local subnet
(for example, another system on the local TCP/IP subnet), it consults
its cache of hardware and protocol addresses (commonly
Ethernet Media Access Control, or MAC
addresses) to determine if a matching system is known. Otherwise, an
ARP exchange is sent to the network device hardware broadcast
address, as shown in Figure 10-1.




Figure 10-1. Overview of an ARP exchange



Arpsniff is designed to capture both packets in the ARP packet
interchanges occurring on the network, and to output the IP addresses
of the machines involved. This could be useful for discovering live
hosts on the network, or for some other network reconnaissance
purpose. For clarity we can separate Arpsniff into five major
sections of libpcap functionality to understand
what we are doing at each step:



Identify the network interface.



Open the network interface.



Configure packet-capture options.



Capture and process packets.



Close down gracefully.




Note that Arpsniff captures interchanges on the network only if you
are not in a switched environment. If you are in a
switched environment you might see only one of the
packetsi.e., the packet sent to the subnet broadcast address.
Several techniques exist for capturing all packets on a switched
environment. The Ettercap sniffer uses several of these techniques,
including ARP poisoning. Visit http://ettercap.sourceforge.net/ for more
information.




10.2.2. Identify the Network Interface



To capture packets from a network
interface, we need to supply libpcap with a
network interface to use for packet capture. We have a number of
different options, including specifying a network interface, asking
libpcap to automatically find an appropriate
interface, obtaining a list of the available interfaces, and in
recent versions of libpcap, using all available
interfaces to capture traffic.



libpcap does not support all network interfaces.
Most Ethernet cards will work, as will most wireless cards while
capturing packets on the network you are associated to.
libpcap generates an error for any network
interface supplied to it that it cannot determine how to open.



The easiest way is to let libpcap choose a
suitable interface:


#include <pcap.h>
char *device; /* device to sniff on */
char errbuf[PCAP_ERRBUF_SIZE]; /* pcap error messages buffer */
device = pcap_lookupdev (errbuf); /* let pcap find a compatible device */
if (device == NULL) /* there was an error */
{
fprintf (stderr, "%s", errbuf);
exit (1);
}


To use the libpcap functions, we are including
the pcap.h header file. This contains the
libpcap function definitions as well as other
handy, predefined values, such as
PCAP_ERRBUF_SIZE.


The prototype for pcap_lookupdev is as follows:


char *pcap_lookupdev(char *errbuf)


This function returns the name of an appropriate interface to be used
for packet capture. For Linux this is typically
eth0 or something similar, but this might be
different for other operating systems.


The function returns NULL and the
errbuf array is populated with an error message if
an error occursfor example, if no suitable interfaces were
located or if the user running the tool did not have sufficient
privileges to perform the operation. A number of functions within
libpcap use an errbuf array
in this way to return meaningful error messages to the calling tool.


Instead of letting libpcap choose a suitable
interface, you can allow the user to specify one. For some tools it
is useful to be able to obtain a list of usable network interfaces:


pcap_if_t *alldevsp;       /* list of interfaces */
if (pcap_findalldevs (&alldevsp, errbuf) < 0)
{
fprintf (stderr, "%s", errbuf);
exit (1);
}
while (alldevsp != NULL)
{
printf ("%s\n", alldevsp->name);
alldevsp = alldevsp->next;
}


The pcap_findalldevs function takes a
pcap_if_t pointer and returns a linked list of
information about the interfaces found. The
pcap_if_t (a type derived from
pcap_if) structure contains several pieces of
information that might be useful to a tool:


struct pcap_if
{
struct pcap_if *next;
char *name; /* interface name */
char *description; /* human-readable description of interface, or NULL */
struct pcap_addr *addresses;
bpf_u_int32 flags; /* PCAP_IF_LOOPBACK if a loopback interface */
};


The linked list is populated with the names and descriptions of all
the interfaces libpcap can use, as well as the
IP address and netmask of the interfaces, as follows:


struct pcap_addr
{
struct pcap_addr *next;
struct sockaddr *addr; /* interface address */
struct sockaddr *netmask; /* netmask for that address */
struct sockaddr *broadaddr; /* broadcast address */
struct sockaddr *dstaddr; /* point-to-point destination or NULL */
};


You could use the information this returns to allow the person using
the tool to select an appropriate interface to use, such as the
network to which the interface is attached.



10.2.3. Open the Network Interface



Once we have
a network interface supplied by the user, or
libpcap has located an appropriate interface, we
can open the interface for packet capture:


pcap_t *handle;
handle = pcap_open_live (device, /* device to sniff on */
BUFSIZ, /* maximum number of bytes to capture per packet */
1, /* promisc - 1 to set card in promiscuous mode, 0 to not */
0, /* to_ms - amount of time to perform packet capture in milliseconds */
/* 0 = sniff until error */
errbuf); /* error message buffer if something goes wrong */
if (handle == NULL) /* there was an error */
{
fprintf (stderr, "%s", errbuf);
exit (1);
}
if (strlen (errbuf) > 0)
{
fprintf (stderr, "Warning: %s", errbuf); /* a warning was generated */
errbuf[0] = 0; /* reset error buffer */
}


pcap_t provides a packet-capture descriptor to the
opened session which is used throughout the tool.
pcap_t is a typedef of the
pcap structure that is used internally within
libpcap; however, the user should never need to
know what this structure actually contains.


The prototype for
pcap_open_live is as follows:


pcap_t *pcap_open_live(const char *device, int snaplen, int promisc, 
int to_ms, char *errbuf)


The pcap_open_live function is used to open
network interfaces for packet capture, and as such it takes several
parameters, as shown in Table 10-1.



Table 10-1. Parameters to pcap_open_live



Parameter




Description



device




The interface on which to capture traffic. This is either a string
such as eth0, or any, or
NULL, and it can be used to capture traffic from
all interfaces on recent Linux systems.



snaplen




The maximum number of bytes to capture per packet (snapshot length).
If this is less than the length of the packet, the packet is
truncated. Note that this has nothing to do with Ethernet SNAP
headers.



promisc




Flag to determine whether the interface should be put into
promiscuous mode. Promiscuous mode instructs the network interface to
capture all traffic on a shared medium network (such as Ethernet),
regardless of whether it was intended for the system running the
tool. Note that the interface could be in promiscuous mode for some
other reason, and it might not be supported for all network
interfaces.



to_ms




Timeout in milliseconds before a read operation returns. This is not
supported on all platforms. A value of 0 causes
the read to wait until an error occurs.



errbuf




Error buffer. If an error or warning occurs, this is populated with a
human-readable error message.




Although all options are present for all platforms supported by
libpcap, some options will work only if
supported by the underlying operating system or device drivers. In
particular, promiscuous mode might not work as expected on all
devices. A good example is wireless network devices. Most wireless
network devices will allow libpcap to capture
wireless traffic in promiscuous mode in Unix-like operating systems,
allowing a tool to capture packets on the network to which the user
is associated. On Windows, this is not supported by all drivers. To
capture all packets, including those not on the network to which a
user is associated, special driver support is required. This is
covered later in this chapter.




10.2.4. Configure Packet-Capture Options



Once we have an active packet-capture
interface we can determine or set a number of options before we start
capturing packets from the interface. For example, we can determine
the type of interface that has been opened:


if (pcap_datalink (handle) != DLT_EN10MB)
{
fprintf (stderr, "This program only supports Ethernet cards!\n");
exit (1);
}


The pcap_datalink function returns the type of the
underlying link layer from the pcap_t handle
passed to it.


The prototype for pcap_datalink is as follows:


int pcap_datalink(pcap_t *p)


This function will generate an error if the selected network
interface was not an Ethernet interface (10MB, 100MB, 1000MB, or
more). It is wise to check the data link type before trying to
manipulate data captured from the network interface, as this
determines what format the data is in.


The data link layers that
libpcap can return include network data link
types (such as Ethernet), as well as encapsulation types such as the
common dial-up Point to Point Protocol (PPP) and OpenBSD pflog. Table 10-2 shows supported link types as of
libpcap Version 0.8.3.



Table 10-2. Link layers supported by libpcap



Data link type




Description




DLT_EN10MB




Ethernet devices, including 10MB, 100MB, 1000MB, and up




DLT_IEEE802_11




802.11 wireless devices; can include all the different variants of
802.11, including 802.11, 802.11a, 802.11b, 802.11g, and so on




DLT_NULL




BSD loop-back encapsulation




DLT_IEEE802




802.5 token ring devices




DLT_ARCNET




ARCNET devices




DLT_SLIP




Serial Line Internet Protocol (SLIP; predecessor to PPP)




DLT_PPP




PPP




DLT_SLIP_BSDOS




BSD/OS SLIP




DLT_PPP_BSDOS




BSD/OS PPP




DLT_ATM_CLIP




Linux Classical IP (CLIP) over ATM




DLT_FDDI




Fiber Distributed Data Interface (FDDI; data over fiber optic cable)




DLT_ATM_RFC1483




RFC 1483 encapsulated Asynchronous Transfer Mode (ATM)




DLT_RAW




Raw IP packet




DLT_PPP_SERIAL




PPP in HDLC framing (RFC 1662 or Cisco PPP with HDLC framing)




DLT_PPP_ETHER




PPP over Ethernet (PPPoE); commonly used in DSL networks




DLT_C_HDLC




Cisco PPP with HDLC framing




DLT_FRELAY




Frame relay devices




DLT_LOOP




OpenBSD loop-back encapsulation




DLT_ENC




OpenBSD encapsulated IP




DLT_LINUX_SLL




Linux cooked capture encapsulation




DLT_LTALK




Apple LocalTalk




DLT_PFLOG




OpenBSD pflog firewall log




DLT_PRISM_HEADER




802.11 Prism monitor mode devices




DLT_IP_OVER_FC




RFC 2625 IP over Fiber Channel




DLT_SUNATM




Sun raw ATM devices




DLT_IEEE802_11_RADIO




BSD wireless with Radiotap header




DLT_APPLE_IP_OVER_IEEE1394




Apple IP over IEEE-1394 (FireWire)




DLT_IEEE802_11_RADIO_AVS




AVS wireless monitor mode devices




DLT_ARCNET_LINUX




Linux ARCNET devices




DLT_LINUX_IRDA




Linux IRDA devices



Some platforms and interfaces can have multiple link types available.
In this case we need to interrogate the underlying data link layer to
see what link types are supported. We can do this using
pcap_list_datalinks with the
pcap_t handle from the opened session:


int *dlt_buf;         /* array of supported data link types */
int num; /* number of supported link type */
int i; /* counter for for loop */
num = pcap_list_datalinks(handle, &dlt_buf);
for (i=0; i<num; i++)
{
printf("%d - %s - %s\n",dlt_buf[i],
pcap_datalink_val_to_name(dlt_buf[i]),
pcap_datalink_val_to_description(dlt_buf[i]));
}


This example uses three functions to enumerate the data link types,
and to display human-readable names and descriptions for them. The
prototypes of these functions are as follows:


int pcap_list_datalinks(pcap_t *p, int **dlt_buf);
const char *pcap_datalink_val_to_name(int dlt);
const char *pcap_datalink_val_to_description(int dlt);


In most cases, the preceding code displays only one link type and the
output usually is something such as the following:


> ./example
> 1 - EN10MB - Ethernet


However, when multiple data link types are supported, something such
as the following can be displayed. This was run on FreeBSD 5.2 with
an Atheros-based wireless network card:


> ./example
> 127 - IEEE802_11_RADIO - 802.11 plus BSD radio information header
> 105 - IEEE802_11 - 802.11
> 1 - EN10MB - Ethernet


In this case, in which multiple link types are returned, we can
select the desired link type using
pcap_set_datalink, which has the following
prototype:


int pcap_set_datalink(pcap_t *p, int dlt);


For example, the following code is required on recent versions of
FreeBSD to capture data in Radiotap format from supported wireless
cards:


if (pcap_set_datalink (handle, DLT_IEEE802_11_RADIO) == -1)
{
pcap_perror (handle, "Error on pcap_set_datalink: ");
exit (1);
}


Now that we have determined that the link type we are capturing on is
Ethernet-based, we can assume the interface has an IP address and
netmask (as Arpsniff does not work on a non-IP network). We can
determine the IP address and netmask
as follows:


bpf_u_int32 netp;     /* ip address of interface */
bpf_u_int32 maskp; /* subnet mask of interface */
if (pcap_lookupnet (device, &netp, &maskp, errbuf) == -1)
{
fprintf (stderr, "%s", errbuf);
exit (1);
}


The
pcap_lookupnet function has the following prototype:


int pcap_lookupnet(const char *device, bpf_u_int32 *netp, bpf_u_int32 *maskp,
char *errbuf)


This function returns the network address and netmask as an integer
value. To convert these to a human-readable format, you can do
something such as the following:


char *net_addr;
struct in_addr addr;
addr.s_addr = netp;
net_addr = inet_ntoa(addr);


The pcap_lookupnet function does not take a
pcap_t argument, as it can be run on an interface
before it is opened for packet capture. This could be used to locate
a particular interface as an alternative to using
pcap_findalldevs. You also can use this
information when setting a Berkeley Packet Filter (BPF) on the
capture, which requires the netmask of the network to be capturing
on.


libpcap supports
BPF
filter programs for filtering incoming packets. BPF is a powerful
filtering language based on a programmable state engine running
pseudo-Assembly language instructions, as shown in Example 10-1.



Example 10-1. tcpdump -d output for "arp" filter


(000) ldh      [12]
(001) jeq #0x806 jt 2 jf 3
(002) ret #68
(003) ret #0


libpcap supports BPF at the kernel level for
systems that have operating system support for BPF, such as AIX, and
in a user-space implementation in the libpcap
library for systems that do not have kernel BPF implementations. On
systems that have BPF support at the kernel level, filtering can be
done very quickly and efficiently, as the packets the filter drops do
not have to be copied from the kernel space to the tool running in
user space.


Using libpcap we can generate a BPF filter from
a tcpdump-style, human-readable
filter string using the
pcap_compile function, as shown here:


char *filter = "arp";   /* filter for BPF (human readable) */
struct bpf_program fp; /* compiled BPF filter */
if (pcap_compile (handle, &fp, filter, 0, maskp) == -1)
{
fprintf (stderr, "%s", pcap_geterr (handle));
exit (1);
}


The prototype for pcap_compile is as follows:


int pcap_compile(pcap_t *p, struct bpf_program *fp, char *str, int optimize,
bpf_u_int32 netmask)


This function supports the same human-readable filter syntax used by
tcpdump. Read the full syntax from the
tcpdump manpage, or online at http://www.tcpdump.org. Table 10-3 shows some examples of the syntax.



Table 10-3. Example of human-readable filters



Filter syntax




Description




udp or arp




Only UDP or ARP packets are passed.



icmp[icmptype] != icmp-echo




All ICMP packets that are not echo requests/replies.



host 192.168.0.12




All packets to/from 192.168.0.12.



ip proto 47




Only IP protocol 47 (GRE) packets.



Once the human-readable syntax has been compiled into the state
machine pseudocode, we can set the filter on the capture session we
have initiated as follows:


if (pcap_setfilter (handle, &fp) == -1)
{
fprintf (stderr, "%s", pcap_geterr (handle));
exit (1);
}


Here is the prototype for the
pcap_setfilter function:


int pcap_setfilter(pcap_t *p, struct bpf_program *fp)q


The pcap_setfilter function sets the BPF program
in the kernel where BPF support is present or in a user-space
implementation if there is no kernel support for BPF.


After we have successfully set the filter on our capture, we can free
the memory used for the filter (in this case, a rather trivial
amount) as follows:


pcap_freecode (&fp);


Now we are ready to capture some packets from the interface we have
opened, with the BPF filter we have set. For Arpsniff we have set a
filter of arp, so we should only have ARP packets
passed to us by the filter.



10.2.5. Capture and Process Packets



libpcap has several options for handling the
capture and processing of packets. The three main functions for
capturing and processing packets are shown in Table 10-4.



Table 10-4. libpcap packet-capture functions



Function




Prototype




Description



pcap_next_ex



int pcap_next_ex 
(pcap_t *p,
struct pcap_pkthdr **pkt_header,
const u_char **pkt_data)




Reads the next packet from the capture session, returning success or
failure. The following values are returned:




1





Packet was read.





0





Timeout expired.





-1





An error occurred.





-2





Packets are being read from a saved file, and no more packets are
available.





If the packet was read, the pkt_header and
pkt_data pointers are set to the packet header and
packet data, respectively.



pcap_dispatch



int pcap_dispatch
(pcap_t *p,
int cnt,
pcap_handler callback,
u_char *user)




Reads up to cnt packets from the session. A
cnt value of -1 reads all
packets in the buffer. pcap_dispatch uses a
callback function (discussed in a bit) to process packets, and
returns the number of packets processed.
pcap_dispatch returns when a read timeout occurs
on supported platforms.


The user value is a user-specified value to be passed to the callback
function, and can be NULL.



pcap_loop



int pcap_loop
(pcap_t *p,
int cnt,
pcap_handler callback,
u_char *user)




Reads cnt packets from the session.
pcap_loop uses a callback function to process
packets, loops forever until cnt packets are
processed (a value of -1 loops forever), and
returns the following:




0





cnt packets read.





-1





An error occurred.





-2





Loop was terminated by pcap_breakloop.





The user value is a user-specified value to be passed to the callback
function, and can be NULL.



Also available to the user for simple tasks is the
pcap_next function. This is a wrapper to the
pcap_dispatch function with a cnt
of 1.



Read timeouts specified in
pcap_open_live
are not supported consistently across platforms, and as such you
can't rely on pcap_dispatch
returning after the read timeout on all platforms. For this reason
you should not use pcap_dispatch as a polling
mechanism.


pcap_next has the following prototype:


const u_char *pcap_next(pcap_t *p, struct pcap_pkthdr *h)


As the pcap_next function doesn't
support error messages, you should use
pcap_next_ex instead if capturing single packets.


For Arpsniff we are going to use pcap_loop as
follows:


if ((r = pcap_loop (handle, -1, process_packet, NULL)) < 0)
{
if (r == -1) /* pcap error */
{
fprintf (stderr, "%s", pcap_geterr (handle));
exit (1);
}
/* otherwise return should be -2, meaning pcap_breakloop has been called */
}


The process_packet parameter passed to
pcap_loop is the name of the function we have
written to handle the packet in whichever way we want when it has
been captured. Both pcap_dispatch and
pcap_loop use a callback function with the same
parameters as follows:


void process_packet (u_char *user, const struct pcap_pkthdr *header,
const u_char *packet)


The callback function does not return anything, as
pcap_loop would not know what to do with the
returned value. As parameters, pcap_loop passes in
a header with information about the packet, as well as a pointer to
the body of the packet itself. The user value is
the value specified in pcap_loop and is not
commonly used.


Now we can write the main functionality of the tool within the
callback function, and we can run this every time a packet matching
the filter is run.



10.2.6. Close Down



Once we are
finished capturing packets, we should gracefully close down the
connection before we exit the tool. Two functions can come in handy
in this case.


Arpsniff uses a trivial signal
handler to intercept the Ctrl-C break sequence. Because the tool is
in an endless loop, due to the pcap_loop function,
the signal handler calls the
pcap_breakloop function. This function, which is
available only in recent versions of libpcap, is
designed for use in signal handlers or similar tools, and allows the
packet- capture loop to be interrupted smoothly and the tool to exit
gracefully. pcap_breakloop takes only one argument
and has the following prototype:


void pcap_breakloop(pcap_t *)


Now that we have exited the packet-capture loop, we can close the
packet-capture handler and associated resources using the
pcap_close function, which has the following
prototype:


void pcap_close(pcap_t *p)



10.2.7. Arpsniff



Example 10-2 shows the complete code for the Arpsniff tool we have been discussing. You
should be able to compile this on most Linux distributions as
follows:


gcc -o arpsniff arpsniff.c -lpcap


The -lpcap option instructs gcc
to link the final binary tool against the pcap
library.


Note that this has been developed on Gentoo Linux on x86, and with
the removal of the pcap_breakloop call on Red Hat
Enterprise Linux on x86. Although it should work on other Linux
variants, it might not work on other Unix-like systems without a
little tweaking.



Example 10-2. Arpsniff source code


#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <net/if.h>
#include <pcap.h>
#include <netinet/if_ether.h>
/* ugly shortcut -- Ethernet packet headers are 14 bytes */
#define ETH_HEADER_SIZE 14
/* for the sake of clarity we'll use globals for a few things */
char *device; /* device to sniff on */
int verbose = 0; /* verbose output about device */
pcap_t *handle; /* handle for the opened pcap session */
/* gracefully handle a Control C */
void
ctrl_c ( )
{
printf ("Exiting\n");
pcap_breakloop (handle); /* tell pcap_loop or pcap_dispatch to stop capturing */
pcap_close(handle);
exit (0);
}
/* usage */
void
usage (char *name)
{
printf ("%s - simple ARP sniffer\n", name);
printf ("Usage: %s [-i interface] [-l] [-v]\n", name);
printf (" -i interface to sniff on\n");
printf (" -l list available interfaces\n");
printf (" -v print verbose info\n\n");
exit (1);
}
/* callback function to process a packet when captured */
void
process_packet (u_char *user, const struct pcap_pkthdr *header,
const u_char * packet)
{
struct ether_header *eth_header; /* in ethernet.h included by if_eth.h */
struct ether_arp *arp_packet; /* from if_eth.h */
eth_header = (struct ether_header *) packet;
arp_packet = (struct ether_arp *) (packet + ETH_HEADER_SIZE);
if (ntohs (eth_header->ether_type) == ETHERTYPE_ARP) /* if it is an ARP packet */
{
printf ("Source: %d.%d.%d.%d\t\tDestination: %d.%d.%d.%d\n",
arp_packet->arp_spa[0],
arp_packet->arp_spa[1],
arp_packet->arp_spa[2],
arp_packet->arp_spa[3],
arp_packet->arp_tpa[0],
arp_packet->arp_tpa[1],
arp_packet->arp_tpa[2],
arp_packet->arp_tpa[3]);
}
}
int
main (int argc, char *argv[])
{
char o; /* for option processing */
char errbuf[PCAP_ERRBUF_SIZE]; /* pcap error messages buffer */
struct pcap_pkthdr header; /* packet header from pcap */
const u_char *packet; /* packet */
bpf_u_int32 netp; /* ip address of interface */
bpf_u_int32 maskp; /* subnet mask of interface */
char *filter = "arp"; /* filter for BPF (human readable) */
struct bpf_program fp; /* compiled BPF filter */
int r; /* generic return value */
pcap_if_t *alldevsp; /* list of interfaces */
while ((o = getopt (argc, argv, "i:vl")) > 0)
{
switch (o)
{
case 'i':
device = optarg;
break;
case 'l':
if (pcap_findalldevs (&alldevsp, errbuf) < 0)
{
fprintf (stderr, "%s", errbuf);
exit (1);
}
while (alldevsp != NULL)
{
printf ("%s\n", alldevsp->name);
alldevsp = alldevsp->next;
}
exit (0);
case 'v':
verbose = 1;
break;
default:
usage (argv[0]);
break;
}
}
/* setup signal handler so Control-C will gracefully exit */
signal (SIGINT, ctrl_c);
/* find device for sniffing if needed */
if (device == NULL) /* if user hasn't specified a device */
{
device = pcap_lookupdev (errbuf); /* let pcap find a compatible device */
if (device == NULL) /* there was an error */
{
fprintf (stderr, "%s", errbuf);
exit (1);
}
}
/* set errbuf to 0 length string to check for warnings */
errbuf[0] = 0;
/* open device for sniffing */
handle = pcap_open_live (device, /* device to sniff on */
BUFSIZ, /* maximum number of bytes to capture per packet */
/* BUFSIZE is defined in pcap.h */
1, /* promisc - 1 to set card in promiscuous mode, 0 to not */
0, /* to_ms - amount of time to perform packet capture in milliseconds */
/* 0 = sniff until error */
errbuf); /* error message buffer if something goes wrong */
if (handle == NULL) /* there was an error */
{
fprintf (stderr, "%s", errbuf);
exit (1);
}
if (strlen (errbuf) > 0)
{
fprintf (stderr, "Warning: %s", errbuf); /* a warning was generated */
errbuf[0] = 0; /* re-set error buffer */
}
if (verbose)
{
printf ("Using device: %s\n", device);
/* printf ("Using libpcap version %s", pcap_lib_version); */
}
/* find out the datalink type of the connection */
if (pcap_datalink (handle) != DLT_EN10MB)
{
fprintf (stderr, "This program only supports Ethernet cards!\n");
exit (1);
}
/* get the IP subnet mask of the device, so we set a filter on it */
if (pcap_lookupnet (device, &netp, &maskp, errbuf) == -1)
{
fprintf (stderr, "%s", errbuf);
exit (1);
}
/* compile the filter, so we can capture only stuff we are interested in */
if (pcap_compile (handle, &fp, filter, 0, maskp) == -1)
{
fprintf (stderr, "%s", pcap_geterr (handle));
exit (1);
}
/* set the filter for the device we have opened */
if (pcap_setfilter (handle, &fp) == -1)
{
fprintf (stderr, "%s", pcap_geterr (handle));
exit (1);
}
/* we'll be nice and free the memory used for the compiled filter */
pcap_freecode (&fp);
if ((r = pcap_loop (handle, -1, process_packet, NULL)) < 0)
{
if (r == -1) /* pcap error */
{
fprintf (stderr, "%s", pcap_geterr (handle));
exit (1);
}
/* otherwise return should be -2, meaning pcap_breakloop has been called */
}
/* close our devices */
pcap_close (handle);
}



Example
10-3 shows a sample run of the
Arpsniff tool, capturing the IP address
ranges in use on this network by capturing ARP
packets.



Example 10-3. Sample run of the Arpsniff tool


clarkju@home$ sudo arpsniff
Source: 192.168.0.123 Destination: 192.168.0.1
Source: 192.168.0.1 Destination: 192.168.0.123
Source: 192.168.0.123 Destination: 192.168.0.101
Source: 192.168.0.101 Destination: 192.168.0.123
Source: 192.168.0.123 Destination: 192.168.0.138
Source: 192.168.0.138 Destination: 192.168.0.123
Source: 192.168.0.138 Destination: 192.168.0.123
Source: 192.168.0.123 Destination: 192.168.0.138



/ 85