first build with ARP kung-fu, though far from finished with that feature

This commit is contained in:
fyodor 2005-04-29 06:53:17 +00:00
parent 7e61d68a77
commit 3922128b12
14 changed files with 793 additions and 302 deletions

View file

@ -1,4 +1,4 @@
export NMAP_VERSION = 3.82
export NMAP_VERSION = 3.82CSW
NMAP_NAME= nmap
NMAP_URL= http://www.insecure.org/nmap/
NMAP_PLATFORM=@host@

View file

@ -99,6 +99,7 @@
***************************************************************************/
/* $Id$ */
#include <dnet.h>
#include "Target.h"
#include "osscan.h"
@ -125,7 +126,8 @@ void Target::Initialize() {
targetipstring[0] = '\0';
nameIPBuf = NULL;
memset(&MACaddress, 0, sizeof(MACaddress));
MACaddress_set = false;
memset(&SrcMACaddress, 0, sizeof(SrcMACaddress));
MACaddress_set = SrcMACaddress_set = false;
htn.msecs_used = 0;
htn.toclock_running = false;
}
@ -351,7 +353,18 @@ int Target::setMACAddress(const u8 *addy) {
return 0;
}
int Target::setSrcMACAddress(const u8 *addy) {
if (!addy) return 1;
memcpy(SrcMACaddress, addy, 6);
SrcMACaddress_set = 1;
return 0;
}
/* Returns the 6-byte long MAC address, or NULL if none has been set */
const u8 *Target::MACAddress() {
return (MACaddress_set)? MACaddress : NULL;
}
const u8 *Target::SrcMACAddress() {
return (SrcMACaddress_set)? SrcMACaddress : NULL;
}

View file

@ -176,8 +176,10 @@ class Target {
/* Takes a 6-byte MAC address */
int setMACAddress(const u8 *addy);
int setSrcMACAddress(const u8 *addy);
/* Returns a pointer to 6-byte MAC address, or NULL if none is set */
const u8 *MACAddress();
const u8 *SrcMACAddress();
struct seq_info seq;
FingerPrintResults *FPR;
@ -189,7 +191,7 @@ class Target {
int wierd_responses; /* echo responses from other addresses, Ie a network broadcast address */
unsigned int flags; /* HOST_UP, HOST_DOWN, HOST_FIREWALLED, HOST_BROADCAST (instead of HOST_BROADCAST use wierd_responses */
struct timeout_info to;
char device[64]; /* The device we transmit on -- make sure to adjust some str* calls if I ever change this*/
char device[64]; /* The device we transmit on -- make sure to adjust some str* calls if I ever change this size*/
private:
char *hostname; // Null if unable to resolve or unset
@ -206,6 +208,8 @@ class Target {
char *nameIPBuf; /* for the NameIP(void) function to return */
u8 MACaddress[6];
bool MACaddress_set;
u8 SrcMACaddress[6];
bool SrcMACaddress_set;
struct host_timeout_nfo htn;
};

View file

@ -228,6 +228,6 @@ struct scan_lists {
int prot_count;
};
typedef enum { ACK_SCAN, SYN_SCAN, FIN_SCAN, XMAS_SCAN, UDP_SCAN, CONNECT_SCAN, NULL_SCAN, WINDOW_SCAN, RPC_SCAN, MAIMON_SCAN, IPPROT_SCAN } stype;
typedef enum { ACK_SCAN, SYN_SCAN, FIN_SCAN, XMAS_SCAN, UDP_SCAN, CONNECT_SCAN, NULL_SCAN, WINDOW_SCAN, RPC_SCAN, MAIMON_SCAN, IPPROT_SCAN, PING_SCAN, PING_SCAN_ARP} stype;
#endif /*GLOBAL_STRUCTURES_H */

View file

@ -908,8 +908,9 @@ T7(Resp=Y%DF=N%W=0%ACK=O%Flags=R%Ops=)
PU(Resp=N)
# Apple AirPort Express (Apple Base Station V6.0)
Fingerprint Apple AirPort Express WAP
Fingerprint Apple AirPort Express WAP or Dell Fiber Channel Bridge Module
Class Apple | embedded || WAP
Class Dell | embedded || storage-misc
TSeq(Class=RI%gcd=<6%SI=<A9830&>1000%TS=2HZ)
T1(DF=Y%W=2000%ACK=S++%Flags=AS%Ops=MNWNNT)
T2(Resp=N)

View file

@ -1976,7 +1976,7 @@ match afs m|^[\d\D]{28}\s*(OpenAFS)\s+stable\s+([\d\.]+)\s+([^\0]+)\0| v/$1/$2/$
match afs m|^[\d\D]{28}\s*(OpenAFS)([\d\.]{3}[^\s\0]*)\s+([^\0]+)\0| v/$1/$2/$3/
match afs m|^[\d\D]{28}\s*(OpenAFS)([\d\.]{3}[^\s\0]*)\0| v/$1/$2//
# Transarc AFS
match afs m|^[\d\D]{28}\s*Base\sconfiguration\safs([\d\.]+)\s+([^\s\0\;]+)[\0\;]| v/Transarc AFS/$1/$2/
match afs m|^[\d\D]{28}\s*Base\sconfiguration\safs([\d\.]+)\s+[^\s\0\;]+[\0\;]| v/Transarc AFS/$1/$2/
# Arla
match afs m|^[\d\D]{28}\s*arla-([\d\.]+)\0| v/Arla/$1//

View file

@ -601,6 +601,8 @@ int nmap_main(int argc, char *argv[]) {
o.pingtype |= PINGTYPE_ICMP_TS;
else if (*optarg == '0' || *optarg == 'N' || *optarg == 'D')
o.pingtype = PINGTYPE_NONE;
else if (*optarg == 'R')
o.pingtype |= PINGTYPE_ARP;
else if (*optarg == 'S') {
o.pingtype |= (PINGTYPE_TCP|PINGTYPE_TCP_USE_SYN);
if (isdigit((int) *(optarg+1)))
@ -1792,6 +1794,8 @@ char *scantype2str(stype scantype) {
case RPC_SCAN: return "RPCGrind Scan"; break;
case MAIMON_SCAN: return "Maimon Scan"; break;
case IPPROT_SCAN: return "IPProto Scan"; break;
case PING_SCAN: return "Ping Scan"; break;
case PING_SCAN_ARP: return "ARP Ping Scan"; break;
default: assert(0); break;
}

1
nmap.h
View file

@ -357,6 +357,7 @@ void *realloc();
#define PINGTYPE_RAWTCP 128
#define PINGTYPE_CONNECTTCP 256
#define PINGTYPE_UDP 512
#define PINGTYPE_ARP 1024
/* TCP/IP ISN sequence prediction classes */
#define SEQ_UNKNOWN 0

View file

@ -144,7 +144,7 @@ int testno;
int timeout;
int avnum;
unsigned int sequence_base;
unsigned int openport;
unsigned long openport;
unsigned int bytes;
unsigned int closedport = 31337;
Port *tport = NULL;
@ -227,7 +227,7 @@ snprintf(filter, sizeof(filter), "dst host %s and (icmp or (tcp and src host %s)
}
if (o.verbose && openport != (unsigned long) -1)
log_write(LOG_STDOUT, "For OSScan assuming port %d is open, %d is closed, and neither are firewalled\n", openport, closedport);
log_write(LOG_STDOUT, "For OSScan assuming port %lu is open, %d is closed, and neither are firewalled\n", openport, closedport);
current_port = o.magic_port + NUM_SEQ_SAMPLES +1;
@ -422,7 +422,7 @@ if (o.verbose && openport != (unsigned long) -1)
if ((tcp->th_flags & TH_RST)) {
/* readtcppacket((char *) ip, ntohs(ip->ip_len));*/
if (si->responses == 0) {
fprintf(stderr, "WARNING: RST from port %hu -- is this port really open?\n", openport);
fprintf(stderr, "WARNING: RST from port %lu -- is this port really open?\n", openport);
/* We used to quit in this case, but left-overs from a SYN
scan or lame-ass TCP wrappers can cause this! */
}

File diff suppressed because it is too large Load diff

View file

@ -2100,10 +2100,10 @@ int service_scan(vector<Target *> &Targets) {
bool plural = (Targets.size() != 1);
if (!plural) {
(*(Targets.begin()))->NameIP(targetstr, sizeof(targetstr));
} else snprintf(targetstr, sizeof(targetstr), "%d hosts", Targets.size());
} else snprintf(targetstr, sizeof(targetstr), "%u hosts", (unsigned) Targets.size());
log_write(LOG_STDOUT, "Initiating service scan against %d %s on %s at %02d:%02d\n",
SG->services_remaining.size(),
log_write(LOG_STDOUT, "Initiating service scan against %u %s on %s at %02d:%02d\n",
(unsigned) SG->services_remaining.size(),
(SG->services_remaining.size() == 1)? "service" : "services",
targetstr, tm->tm_hour, tm->tm_min);
}
@ -2136,11 +2136,11 @@ int service_scan(vector<Target *> &Targets) {
if (o.verbose) {
gettimeofday(&now, NULL);
if (SG->num_hosts_timedout == 0)
log_write(LOG_STDOUT, "The service scan took %.2fs to scan %d %s on %d %s.\n",
log_write(LOG_STDOUT, "The service scan took %.2fs to scan %u %s on %u %s.\n",
TIMEVAL_MSEC_SUBTRACT(now, starttv) / 1000.0,
SG->services_finished.size(),
(unsigned) SG->services_finished.size(),
(SG->services_finished.size() == 1)? "service" : "services",
Targets.size(), (Targets.size() == 1)? "host" : "hosts");
(unsigned) Targets.size(), (Targets.size() == 1)? "host" : "hosts");
else log_write(LOG_STDOUT,
"Finished service scan in %.2fs, but %d %s timed out.\n",
TIMEVAL_MSEC_SUBTRACT(now, starttv) / 1000.0,

View file

@ -107,6 +107,7 @@
#include "NmapOps.h"
#include "TargetGroup.h"
#include "Target.h"
#include "scan_engine.h"
extern NmapOps o;
enum pingstyle { pingstyle_unknown, pingstyle_rawtcp, pingstyle_rawudp, pingstyle_connecttcp,
@ -116,6 +117,7 @@ enum pingstyle { pingstyle_unknown, pingstyle_rawtcp, pingstyle_rawudp, pingstyl
extern unsigned long flt_dsthost, flt_srchost;
extern unsigned short flt_baseport;
/* Gets the host number (index) of target in the hostbatch array of
pointers. Note that the target MUST EXIST in the array or all
heck will break loose. */
@ -239,6 +241,44 @@ static int hostupdate(Target *hostbatch[], Target *target,
return 0;
}
/* Conducts an ARP ping sweep of the given hosts to determine which ones
are up on a local ethernet network */
static void arpping(Target *hostbatch[], int num_hosts,
struct scan_lists *ports) {
/* First I change hostbatch into a vector<Target *>, which is what ultra_scan
takes. I remove hosts that cannot be ARP scanned (such as localhost) */
vector<Target *> targets;
int targetno;
targets.reserve(num_hosts);
for(targetno = 0; targetno < num_hosts; targetno++) {
initialize_timeout_info(&hostbatch[targetno]->to);
/* Default timout should be much lower for arp */
hostbatch[targetno]->to.timeout = MIN(o.initialRttTimeout(), 100) * 1000;
if (!hostbatch[targetno]->SrcMACAddress()) {
bool islocal = islocalhost(hostbatch[targetno]->v4hostip());
if (islocal) {
log_write(LOG_STDOUT|LOG_NORMAL,
"ARP ping: Considering %s UP because it is a local IP, despite no MAC address for device %s\n",
hostbatch[targetno]->NameIP(), hostbatch[targetno]->device);
hostbatch[targetno]->flags &= ~(HOST_DOWN|HOST_FIREWALLED);
hostbatch[targetno]->flags |= HOST_UP;
} else {
log_write(LOG_STDOUT|LOG_NORMAL,
"ARP ping: Considering %s DOWN because no MAC address found for device %s.\n",
hostbatch[targetno]->NameIP(), hostbatch[targetno]->device);
hostbatch[targetno]->flags &= ~HOST_FIREWALLED;
hostbatch[targetno]->flags |= HOST_DOWN;
}
continue;
}
targets.push_back(hostbatch[targetno]);
}
if (!targets.empty())
ultra_scan(targets, ports, PING_SCAN_ARP);
return;
}
void hoststructfry(Target *hostbatch[], int nelem) {
genfry((unsigned char *)hostbatch, sizeof(Target *), nelem);
return;
@ -291,7 +331,7 @@ do {
3) We are doing a raw-mode portscan or osscan OR
4) We are on windows and doing ICMP ping */
if (o.isr00t && o.af() == AF_INET &&
((*pingtype & (PINGTYPE_TCP|PINGTYPE_UDP)) || o.RawScan()
((*pingtype & (PINGTYPE_TCP|PINGTYPE_UDP|PINGTYPE_ARP)) || o.RawScan()
#ifdef WIN32
|| (*pingtype & (PINGTYPE_ICMP_PING|PINGTYPE_ICMP_MASK|PINGTYPE_ICMP_TS))
#endif // WIN32
@ -323,6 +363,11 @@ do {
}
}
/* If this is an ARP scan, we must determine the device's MAC address */
if (*pingtype & PINGTYPE_ARP) {
setTargetSrcMACAddressFromDevName(hs->hostbatch[hidx]);
}
/* In some cases, we can only allow hosts that use the same device
in a group. */
if (o.af() == AF_INET && o.isr00t && hidx > 0 &&
@ -336,7 +381,7 @@ do {
goto batchfull;
}
hs->current_batch_sz++;
}
}
if (hs->current_batch_sz < hs->max_batch_sz &&
hs->next_expression < hs->num_expressions) {
@ -358,12 +403,19 @@ if (hs->randomize) {
hoststructfry(hs->hostbatch, hs->current_batch_sz);
}
/* Finally we do the mass ping (if required) */
if ((*pingtype &
/* First I'll do the ARP ping if necessary */
if (*pingtype & PINGTYPE_ARP) {
arpping(hs->hostbatch, hs->current_batch_sz, ports);
}
/* TODO: For efficiency, at some point it might be nice to usually do ARP
ping before mass ping (and so get rid of else below) */
/* Then we do the mass ping (if required - IP-level pings) */
else if ((*pingtype &
(PINGTYPE_ICMP_PING|PINGTYPE_ICMP_MASK|PINGTYPE_ICMP_TS) ) ||
((!o.isr00t || o.af() == AF_INET6 || hs->hostbatch[0]->v4host().s_addr) &&
(*pingtype != PINGTYPE_NONE)))
massping(hs->hostbatch, hs->current_batch_sz, ports, *pingtype);
/* Otherwise -P0 so we just consider every host up */
else for(i=0; i < hs->current_batch_sz; i++) {
initialize_timeout_info(&hs->hostbatch[i]->to);
hs->hostbatch[i]->flags |= HOST_UP; /*hostbatch[i].up = 1;*/

353
tcpip.cc
View file

@ -100,7 +100,7 @@
/* $Id$ */
#include <dnet.h>
#include "tcpip.h"
#include "NmapOps.h"
@ -206,6 +206,53 @@ char *getFinalPacketStats(char *buf, int buflen) {
return buf;
}
/* Takes an ARP PACKET (including ethernet header) and prints it if
packet tracing is enabled. 'frame' must point to the 14-byte
ethernet header (e.g. starting with destination addr). The
direction must be PacketTrace::SENT or PacketTrace::RCVD .
Optional 'now' argument makes this function slightly more
efficient by avoiding a gettimeofday() call. */
void PacketTrace::traceArp(pdirection pdir, const u8 *frame, u32 len,
struct timeval *now) {
struct timeval tv;
char arpdesc[128];
char who_has[INET_ADDRSTRLEN], tell[INET_ADDRSTRLEN];
if (pdir == SENT) {
PktCt.sendPackets++;
PktCt.sendBytes += len;
} else {
PktCt.recvPackets++;
PktCt.recvBytes += len;
}
if (!o.packetTrace()) return;
if (now)
tv = *now;
else gettimeofday(&tv, NULL);
if (len < 42) {
error("Packet tracer: Arp packets must be at least 42 bytes long. Should be exactly that length excl. ethernet padding.");
return;
}
if (frame[21] == 1) /* arp REQUEST */ {
inet_ntop(AF_INET, frame+38, who_has, sizeof(who_has));
inet_ntop(AF_INET, frame+28, tell, sizeof(who_has));
snprintf(arpdesc, sizeof(arpdesc), "who-has %s tell %s", who_has, tell);
} else { /* ARP REPLY */
inet_ntop(AF_INET, frame+28, who_has, sizeof(who_has));
snprintf(arpdesc, sizeof(arpdesc),
"reply %s is-at %02X:%02X:%02X:%02X:%02X:%02X", who_has,
frame[22], frame[23], frame[24], frame[25], frame[26], frame[27]);
}
log_write(LOG_STDOUT|LOG_NORMAL, "%s (%.4fs) ARP %s\n", (pdir == SENT)? "SENT" : "RCVD", o.TimeSinceStartMS(&tv) / 1000.0, arpdesc);
return;
}
/* Takes an IP PACKET and prints it if packet tracing is enabled.
'packet' must point to the IPv4 header. The direction must be
@ -294,6 +341,11 @@ void PacketTrace::traceConnect(u8 proto, const struct sockaddr *sock,
errbuf);
}
/* Converts an IP address given in a sockaddr_storage to an IPv4 or
IPv6 IP address string. Since a static buffer is returned, this is
not thread-safe and can only be used once in calls like printf()
@ -1321,96 +1373,6 @@ fcntl(sd, F_SETFL, options);
return 1;
}
/* Get the source address and interface name */
#if 0
char *getsourceif(struct in_addr *src, struct in_addr *dst) {
int sd, sd2;
u16 p1;
struct sockaddr_in sock;
int socklen = sizeof(struct sockaddr_in);
struct sockaddr sa;
recvfrom6_t sasize = sizeof(struct sockaddr);
int ports, res;
u8 buf[65536];
struct timeval tv;
unsigned int start;
int data_offset, ihl, *intptr;
int done = 0;
/* Get us some unreserved port numbers */
get_random_bytes(&p1, 2);
if (p1 < 5000) p1 += 5000;
if (!getuid()) {
if ((sd2 = socket(AF_INET, SOCK_PACKET, htons(ETH_P_ALL))) == -1)
{perror("Linux Packet Socket troubles"); return 0;}
unblock_socket(sd2);
if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{perror("Socket troubles"); return 0;}
sock.sin_family = AF_INET;
sock.sin_addr = *dst;
sock.sin_port = htons(p1);
if (connect(sd, (struct sockaddr *) &sock, sizeof(struct sockaddr_in)) == -1)
{ perror("UDP connect()");
close(sd);
close(sd2);
return NULL;
}
if (getsockname(sd, (SA *)&sock, &socklen) == -1) {
perror("getsockname");
close(sd);
close(sd2);
return NULL;
}
ports = (ntohs(sock.sin_port) << 16) + p1;
#if ( TCPIP_DEBUGGING )
printf("ports is %X\n", ports);
#endif
if (send(sd, "", 0, 0) == -1)
fatal("Could not send UDP packet");
start = time(NULL);
do {
tv.tv_sec = 2;
tv.tv_usec = 0;
res = recvfrom(sd2, buf, 65535, 0, &sa, &sasize);
if (res < 0) {
if (socket_errno() != EWOULDBLOCK)
perror("recvfrom");
}
if (res > 0) {
#if ( TCPIP_DEBUGGING )
printf("Got packet!\n");
printf("sa.sa_data: %s\n", sa.sa_data);
printf("Hex dump of packet (len %d):\n", res);
hdump(buf, res);
#endif
data_offset = get_link_offset(sa.sa_data);
ihl = (*(buf + data_offset) & 0xf) * 4;
/* If it is big enough and it is IPv4 */
if (res >= data_offset + ihl + 4 &&
(*(buf + data_offset) & 0x40)) {
intptr = (int *) ((char *) buf + data_offset + ihl);
if (*intptr == ntohl(ports)) {
intptr = (int *) ((char *) buf + data_offset + 12);
#if ( TCPIP_DEBUGGING )
printf("We've found our packet [krad]\n");
#endif
memcpy(src, buf + data_offset + 12, 4);
close(sd);
close(sd2);
return strdup(sa.sa_data);
}
}
}
} while(!done && time(NULL) - start < 2);
close(sd);
close(sd2);
}
return NULL;
}
#endif /* 0 */
int getsourceip(struct in_addr *src, const struct in_addr * const dst) {
int sd;
struct sockaddr_in sock;
@ -1442,48 +1404,6 @@ int getsourceip(struct in_addr *src, const struct in_addr * const dst) {
return 1; /* Calling function responsible for checking validity */
}
#if 0
int get_link_offset(char *device) {
int sd;
struct ifreq ifr;
sd = socket(AF_INET, SOCK_DGRAM, 0);
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
#if (defined(SIOCGIFHWADDR) && defined(ARPHRD_ETHER) &&
defined(ARPHRD_METRICOM) && defined(ARPHRD_SLIP) && defined(ARPHRD_CSLIP)
&& defined(ARPHRD_SLIP6) && defined(ARPHRD_PPP) &&
defined(ARPHRD_LOOPBACK) )
if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0 ) {
fatal("Can't obtain link offset. What kind of interface are you using?");
}
close(sd);
switch (ifr.ifr_hwaddr.sa_family) {
case ARPHRD_ETHER: /* These two are standard ethernet */
case ARPHRD_METRICOM:
return 14;
break;
case ARPHRD_SLIP:
case ARPHRD_CSLIP:
case ARPHRD_SLIP6:
case ARPHRD_CSLIP6:
case ARPHRD_PPP:
return 0;
break;
case ARPHRD_LOOPBACK: /* Loopback interface (obviously) */
return 14;
break;
default:
fatal("Unknown link layer device: %d", ifr.ifr_hwaddr.sa_family);
}
#else
printf("get_link_offset called even though your host doesn't support it. Assuming Ethernet or Loopback connection (wild guess)\n");
return 14;
#endif
/* Not reached */
exit(1);
}
#endif
/* Read an IP packet using libpcap . We return the packet and take
a pcap descripter and a pointer to the packet length (which we set
in the function. If you want a maximum length returned, you
@ -1494,7 +1414,6 @@ exit(1);
low values (and 0) degenerate to the timeout specified
in pcap_open_live()
*/
/* If rcvdtime is non-null and a packet is returned, rcvd will be
filled with the time that packet was captured from the wire by
pcap. If linknfo is not NULL, linknfo->headerlen and
@ -1687,6 +1606,106 @@ bool pcap_recv_timeval_valid() {
#endif
}
/* Attempts to read one IPv4/Ethernet ARP reply packet from the pcap
descriptor pd. If it receives one, fills in sendermac (must pass
in 6 bytes), senderIP, and rcvdtime (can be NULL if you don't care)
and returns 1. If it times out and reads no arp requests, returns
0. to_usec is the timeout period in microseconds. Use 0 to avoid
blocking to the extent possible, and -1 to block forever. Returns
-1 or exits if ther is an error. */
int read_arp_reply_pcap(pcap_t *pd, u8 *sendermac, struct in_addr *senderIP,
long to_usec, struct timeval *rcvdtime) {
static int warning = 0;
int datalink;
struct pcap_pkthdr head;
u8 *p;
int timedout = 0;
int badcounter = 0;
struct timeval tv_start, tv_end;
if (!pd) fatal("NULL packet device passed to readarp_reply_pcap");
if (to_usec < 0) {
if (!warning) {
warning = 1;
error("WARNING: Negative timeout value (%lu) passed to readip_pcap() -- using 0", to_usec);
}
to_usec = 0;
}
/* New packet capture device, need to recompute offset */
if ( (datalink = pcap_datalink(pd)) < 0)
fatal("Cannot obtain datalink information: %s", pcap_geterr(pd));
if (datalink != DLT_EN10MB)
fatal("readarp_reply_pcap called on interfaces that is datatype %d rather than DLT_EN10MB (%d)", datalink, DLT_EN10MB);
if (to_usec > 0) {
gettimeofday(&tv_start, NULL);
}
do {
#ifdef WIN32
gettimeofday(&tv_end, NULL);
to_left = MAX(1, (to_usec - TIMEVAL_SUBTRACT(tv_end, tv_start)) / 1000);
// Set the timeout (BUGBUG: this is cheating)
PacketSetReadTimeout(pd->adapter, to_left);
#endif
p = (u8 *) pcap_next(pd, &head);
if (p && head.caplen >= 42) { /* >= because Ethernet padding makes 60 */
/* frame type 0x0806 (arp), hw type eth (0x0001), prot ip (0x0800),
hw size (0x06), prot size (0x04) */
if (memcmp(p + 12, "\x08\x06\x00\x01\x08\x00\x06\x04\x00\x02", 10) == 0) {
memcpy(sendermac, p + 22, 6);
/* I think alignment should allow this ... */
senderIP->s_addr = *(u32 *) (p + 28) ;
break;
}
}
if (!p) {
/* Should we timeout? */
if (to_usec == 0) {
timedout = 1;
} else if (to_usec > 0) {
gettimeofday(&tv_end, NULL);
if (TIMEVAL_SUBTRACT(tv_end, tv_start) >= to_usec) {
timedout = 1;
}
}
} else {
/* We'll be a bit patient if we're getting actual packets back, but
not indefinitely so */
if (badcounter++ > 50)
timedout = 1;
}
} while(!timedout);
if (timedout) return 0;
if (rcvdtime) {
// FIXME: I eventually need to figure out why Windows head.ts time is sometimes BEFORE the time I
// sent the packet (which is according to gettimeofday() in nbase). For now, I will sadly have to
// use gettimeofday() for Windows in this case
// Actually I now allow .05 discrepancy. So maybe this isn't needed. I'll comment out for now.
// Nope: it is still needed at least for Windows. Sometimes the time from he pcap header is a
// COUPLE SECONDS before the gettimeofday() results :(.
#if defined(WIN32) || defined(__amigaos__)
gettimeofday(&tv_end, NULL);
*rcvdtime = tv_end;
#else
*rcvdtime = head.ts;
assert(head.ts.tv_sec);
#endif
}
PacketTrace::traceArp(PacketTrace::RCVD, (u8 *) p, 42, rcvdtime);
return 1;
}
/* This function tries to determine the target's ethernet MAC address
from a received packet as follows:
@ -2452,3 +2471,69 @@ int IPProbe::storePacket(u8 *ippacket, u32 len) {
return 0;
}
ArpProbe::ArpProbe() {
packetbuflen = 0;
packetbuf = NULL;
Reset();
}
void ArpProbe::Reset() {
if (packetbuf)
free(packetbuf);
packetbuflen = 0;
packetbuf = NULL;
ipquery = NULL;
}
ArpProbe::~ArpProbe() {
if (packetbuf) {
free(packetbuf);
packetbuf = NULL;
packetbuflen = 0;
}
Reset();
}
int ArpProbe::storePacket(u8 *arppacket, u32 len) {
assert(packetbuf == NULL);
assert(len == 42);
packetbuf = (u8 *) safe_malloc(len);
memcpy(packetbuf, arppacket, len);
packetbuflen = len;
ipquery = (struct in_addr *) ((u8 *)arppacket + 38);
return 0;
}
/* Finds MAC address of target->device and sets into target. Caches
the results so that it will be really quick if you have many targets
that send out with the same device, and you pass them roughly in
order (only caches one). Returns -1 if cannot find the MAC address
(often meaning this is localhost, or some other non-ethernet device.
Returns 0 upon success. */
int setTargetSrcMACAddressFromDevName(Target *target) {
static u8 MAC_Cache[6];
static char MAC_Cache_Dev[64] = {0};
assert(*target->device);
if (strcmp(target->device, MAC_Cache_Dev) == 0)
target->setSrcMACAddress(MAC_Cache);
else {
eth_t *e;
eth_addr_t et;
assert(sizeof(et) >= 6);
e = eth_open(target->device);
if (!e)
fatal("dnet: Failed to open ethernet device %s\n", target->device);
if (eth_get(e, &et) == -1)
return -1;
// fatal("dnet: Failed to obtain HW MAC address for ethernet device %s\n", target->device);
eth_close(e);
Strncpy(MAC_Cache_Dev, target->device, sizeof(MAC_Cache_Dev));
memcpy(MAC_Cache, (const char *) &et, 6);
target->setSrcMACAddress(MAC_Cache);
}
return 0;
}

47
tcpip.h
View file

@ -295,6 +295,14 @@ class PacketTrace {
static void traceConnect(u8 proto, const struct sockaddr *sock,
int socklen, int connectrc, int connect_errno,
const struct timeval *now);
/* Takes an ARP PACKET (including ethernet header) and prints it if
packet tracing is enabled. 'frame' must point to the 14-byte
ethernet header (e.g. starting with destination addr). The
direction must be PacketTrace::SENT or PacketTrace::RCVD .
Optional 'now' argument makes this function slightly more
efficient by avoiding a gettimeofday() call. */
static void PacketTrace::traceArp(pdirection pdir, const u8 *frame, u32 len,
struct timeval *now);
};
class PacketCounter {
@ -469,6 +477,26 @@ class IPProbe {
void Reset();
private:
};
/* Handles an *IPv4* Arp probe */
class ArpProbe {
public:
ArpProbe();
~ArpProbe();
/* Takes an ARP packet and stores _a copy_ of it, in this Probe,
adjusting proper header pointers and such. Then length better
equal 42! */
int storePacket(u8 *arppacket, u32 len);
u32 packetbuflen; /* Length of the whole packet */
u8 *packetbuf; /* The packet itself */
struct in_addr *ipquery; /* IP address this ARP seeks */
/* Resets everything to NULL. Frees packetbuf if it is filled. You
can reuse a Probe by calling Reset() and then a new
storePacket(). */
void Reset();
private:
};
/* This ideally should be a port that isn't in use for any protocol on our machine or on the target */
@ -634,6 +662,15 @@ char *getFinalPacketStats(char *buf, int buflen);
int setTargetMACIfAvailable(Target *target, struct link_header *linkhdr,
struct ip *ip, int overwrite);
/* Finds MAC address of target->device and sets into target. Caches
the results so that it will be really quick if you have many targets
that send out with the same device, and you pass them roughly in
order (only caches one). Returns -1 if cannot find the MAC address
(often meaning this is localhost, or some other non-ethernet device.
Returns 0 upon success. */
int setTargetSrcMACAddressFromDevName(Target *target);
int islocalhost(const struct in_addr * const addr);
int unblock_socket(int sd);
int Sendto(char *functionname, int sd, const unsigned char *packet, int len,
@ -653,6 +690,16 @@ int get_link_offset(char *device);
lnkinfo->header will be filled with the appropriate values. */
char *readip_pcap(pcap_t *pd, unsigned int *len, long to_usec,
struct timeval *rcvdtime, struct link_header *linknfo);
/* Attempts to read one IPv4/Ethernet ARP reply packet from the pcap
descriptor pd. If it receives one, fills in sendermac (must pass
in 6 bytes), senderIP, and rcvdtime (can be NULL if you don't care)
and returns 1. If it times out and reads no arp requests, returns
0. to_usec is the timeout period in microseconds. Use 0 to avoid
blocking to the extent possible, and -1 to block forever. Returns
-1 or exits if ther is an error. */
int read_arp_reply_pcap(pcap_t *pd, u8 *sendermac, struct in_addr *senderIP,
long to_usec, struct timeval *rcvdtime);
#ifndef HAVE_INET_ATON
int inet_aton(register const char *, struct in_addr *);
#endif