/*
* arpprint.{cc,hh} -- element prints packet contents to system log
* Jose Maria Gonzalez
*
* Shameless graft of ipprint.hh/cc and tcpdump-3.8.3/print-arp.c
*
* Copyright (c) 2005-2006 Regents of the University of California
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, subject to the conditions
* listed in the Click LICENSE file. These conditions include: you must
* preserve this copyright notice, and you cannot mention the copyright
* holders in advertising related to the Software without their permission.
* The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
* notice is a summary of the Click LICENSE file; the license in that file is
* legally binding.
*/
#include <click/config.h>
#include "arpprint.hh"
#include <click/glue.hh>
#include <click/confparse.hh>
#include <click/error.hh>
#include <click/straccum.hh>
#include <click/packet_anno.hh>
#include <click/router.hh>
#include <click/nameinfo.hh>
#include <click/etheraddress.hh>
#include <clicknet/ether.h>
#if CLICK_USERLEVEL
# include <stdio.h>
#endif
CLICK_DECLS
/*
* Address Resolution Protocol.
*
* See RFC 826 for protocol description. ARP packets are variable
* in size; the arphdr structure defines the fixed-length portion.
* Protocol type values are the same as those for 10 Mb/s Ethernet.
* It is followed by the variable-sized fields ar_sha, arp_spa,
* arp_tha and arp_tpa in that order, according to the lengths
* specified. Field names used correspond to RFC 826.
*/
ARPPrint::ARPPrint()
{
#if CLICK_USERLEVEL
_outfile = 0;
#endif
}
ARPPrint::~ARPPrint()
{
}
int
ARPPrint::configure(Vector<String> &conf, ErrorHandler *errh)
{
_label = "";
bool print_time = true;
String channel;
if (cp_va_parse(conf, this, errh,
cpOptional,
cpString, "label", &_label,
cpKeywords,
"TIMESTAMP", cpBool, "print packet timestamps?", &print_time,
#if CLICK_USERLEVEL
"OUTFILE", cpFilename, "output filename", &_outfilename,
#endif
cpEnd) < 0)
return -1;
_print_timestamp = print_time;
_errh = router()->chatter_channel(channel);
return 0;
}
int
ARPPrint::initialize(ErrorHandler *errh)
{
#if CLICK_USERLEVEL
if (_outfilename) {
_outfile = fopen(_outfilename.c_str(), "wb");
if (!_outfile)
return errh->error("%s: %s", _outfilename.c_str(), strerror(errno));
}
#else
(void) errh;
#endif
return 0;
}
void
ARPPrint::cleanup(CleanupStage)
{
#if CLICK_USERLEVEL
if (_outfile)
fclose(_outfile);
_outfile = 0;
#endif
}
Packet *
ARPPrint::simple_action(Packet *p)
{
const click_ether_arp *ap = (const click_ether_arp *) p->network_header();
if (!ap)
return p;
StringAccum sa;
if (_label)
sa << _label << ": ";
if (_print_timestamp)
sa << p->timestamp_anno() << ": ";
if (p->network_length() < (int) sizeof(click_arp))
sa << "truncated-arp (" << p->network_length() << ")";
else {
uint16_t hrd = ntohs(ap->ea_hdr.ar_hrd);
uint16_t pro = ntohs(ap->ea_hdr.ar_pro);
uint8_t hln = ap->ea_hdr.ar_hln;
uint8_t pln = ap->ea_hdr.ar_pln;
uint16_t op = ntohs(ap->ea_hdr.ar_op);
if ((pro != ETHERTYPE_IP && pro != ETHERTYPE_TRAIL) ||
pln != 4 || hln == 0) {
sa << "arp-#" << op << " for proto #" << pro << " (" << pln << ") "
<< "hardware #" << hrd << " (" << hln << ")";
return p;
}
const unsigned char *sha = (const unsigned char *)ap->arp_sha;
const unsigned char *spa = (const unsigned char *)ap->arp_spa;
const unsigned char *tha = (const unsigned char *)ap->arp_tha;
const unsigned char *tpa = (const unsigned char *)ap->arp_tpa;
if (pro == ETHERTYPE_TRAIL)
sa << "trailer-";
switch (op) {
case ARPOP_REQUEST:
{
const unsigned char ezero[6] = {0,0,0,0,0,0};
sa << "arp who-has " << IPAddress(tpa);
if ( memcmp (ezero, tha, hln) != 0 )
sa << " (" << EtherAddress(tha) << ")";
sa << " tell " << IPAddress(spa);
break;
}
case ARPOP_REPLY:
sa << "arp reply " << IPAddress(spa);
sa << " is-at " << EtherAddress(sha);
break;
case ARPOP_REVREQUEST:
sa << "rarp who-is " << EtherAddress(tha) << " tell " <<
EtherAddress(sha);
break;
case ARPOP_REVREPLY:
sa << "rarp reply " << EtherAddress(tha) << " at " << IPAddress(tpa);
break;
case ARPOP_INVREQUEST:
sa << "invarp who-is " << EtherAddress(tha) << " tell " <<
EtherAddress(sha);
break;
case ARPOP_INVREPLY:
sa << "invarp reply " << EtherAddress(tha) << " at " <<
IPAddress(tpa);
break;
default:
sa << "arp-#" << op;
// default_print((const u_char *)ap, caplen);
}
if (hrd != ARPHRD_ETHER)
sa << "hardware #" << hrd;
}
#if CLICK_USERLEVEL
if (_outfile) {
sa << '\n';
fwrite(sa.data(), 1, sa.length(), _outfile);
} else
#endif
_errh->message("%s", sa.c_str());
return p;
}
CLICK_ENDDECLS
EXPORT_ELEMENT(ARPPrint)
syntax highlighted by Code2HTML, v. 0.9.1