Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F120515551
ipprint.cc
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Fri, Jul 4, 22:46
Size
13 KB
Mime Type
text/x-c
Expires
Sun, Jul 6, 22:46 (2 d)
Engine
blob
Format
Raw Data
Handle
27182202
Attached To
R6591 HyMAB
ipprint.cc
View Options
/*
* ipprint.{cc,hh} -- element prints packet contents to system log
* Max Poletto, Eddie Kohler
*
* Copyright (c) 2000 Mazu Networks, Inc.
* Copyright (c) 2005-2008 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 "ipprint.hh"
#include <click/glue.hh>
#include <click/args.hh>
#include <click/error.hh>
#include <click/straccum.hh>
#include <click/packet_anno.hh>
#include <click/router.hh>
#include <click/nameinfo.hh>
#include <clicknet/ip.h>
#include <clicknet/icmp.h>
#include <clicknet/tcp.h>
#include <clicknet/udp.h>
#if CLICK_USERLEVEL
# include <stdio.h>
#endif
CLICK_DECLS
IPPrint::IPPrint()
{
#if CLICK_USERLEVEL
_outfile = 0;
#endif
}
IPPrint::~IPPrint()
{
}
int
IPPrint::configure(Vector<String> &conf, ErrorHandler *errh)
{
_bytes = 1500;
String contents = "no";
String payload = "no";
_label = "";
_swap = true;
_payload = false;
_active = true;
bool print_id = false;
bool print_time = true;
bool print_paint = false;
bool print_tos = false;
bool print_ttl = false;
bool print_len = false;
bool print_aggregate = false;
bool bcontents;
String channel;
_print_every = 1;
_count_every = 0;
if (Args(conf, this, errh)
.read_p("LABEL", _label)
.read("CONTENTS", WordArg(), contents)
.read("PAYLOAD", WordArg(), payload)
.read("MAXLENGTH", _bytes)
.read("NBYTES", _bytes) // deprecated
.read("ID", print_id)
.read("TIMESTAMP", print_time)
.read("PAINT", print_paint)
.read("TOS", print_tos)
.read("TTL", print_ttl)
.read("SWAP", _swap)
.read("LENGTH", print_len)
.read("AGGREGATE", print_aggregate)
.read("ACTIVE", _active)
#if CLICK_USERLEVEL
.read("OUTFILE", FilenameArg(), _outfilename)
#endif
.read("CHANNEL", WordArg(), channel)
.read("PRINT_EVERY", _print_every)
.complete() < 0)
return -1;
if (BoolArg().parse(contents, bcontents))
_contents = bcontents;
else if ((contents = contents.upper()), contents == "NONE")
_contents = 0;
else if (contents == "HEX")
_contents = 1;
else if (contents == "ASCII")
_contents = 2;
else
return errh->error("bad contents value '%s'; should be 'NONE', 'HEX', or 'ASCII'", contents.c_str());
int payloadv;
payload = payload.upper();
if (payload == "NO" || payload == "FALSE")
payloadv = 0;
else if (payload == "YES" || payload == "TRUE" || payload == "HEX")
payloadv = 1;
else if (payload == "ASCII")
payloadv = 2;
else
return errh->error("bad payload value '%s'; should be 'false', 'hex', or 'ascii'", contents.c_str());
if (payloadv > 0 && _contents > 0)
return errh->error("specify at most one of PAYLOAD and CONTENTS");
else if (payloadv > 0)
_contents = payloadv, _payload = true;
_print_id = print_id;
_print_timestamp = print_time;
_print_paint = print_paint;
_print_tos = print_tos;
_print_ttl = print_ttl;
_print_len = print_len;
_print_aggregate = print_aggregate;
_errh = router()->chatter_channel(channel);
return 0;
}
int
IPPrint::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
IPPrint::cleanup(CleanupStage)
{
#if CLICK_USERLEVEL
if (_outfile)
fclose(_outfile);
_outfile = 0;
#endif
}
StringAccum &
IPPrint::address_pair(StringAccum &sa, const click_ip *iph)
{
sa << IPAddress(iph->ip_src) << " > " << IPAddress(iph->ip_dst);
return sa;
}
void
IPPrint::tcp_line(StringAccum &sa, const Packet *p, int transport_length) const
{
const click_ip *iph = p->ip_header();
const click_tcp *tcph = p->tcp_header();
int ip_len, seqlen;
uint32_t seq;
if (transport_length < 4 || !IP_FIRSTFRAG(iph)) {
address_pair(sa, iph) << (IP_FIRSTFRAG(iph) ? ": truncated-tcp" : ": tcp");
return;
}
sa << IPAddress(iph->ip_src) << '.' << ntohs(tcph->th_sport) << " > "
<< IPAddress(iph->ip_dst) << '.' << ntohs(tcph->th_dport) << ": ";
if (transport_length < 14)
goto truncated_tcp;
ip_len = ntohs(iph->ip_len);
seqlen = ip_len - (iph->ip_hl << 2) - (tcph->th_off << 2);
if (tcph->th_flags & TH_SYN)
sa << 'S', seqlen++;
if (tcph->th_flags & TH_FIN)
sa << 'F', seqlen++;
if (tcph->th_flags & TH_RST)
sa << 'R';
if (tcph->th_flags & TH_PUSH)
sa << 'P';
if (!(tcph->th_flags & (TH_SYN | TH_FIN | TH_RST | TH_PUSH)))
sa << '.';
seq = ntohl(tcph->th_seq);
sa << ' ' << seq << ':' << (seq + seqlen)
<< '(' << seqlen << ',' << p->length() << ',' << ip_len << ')';
if (tcph->th_flags & TH_ACK)
sa << " ack " << ntohl(tcph->th_ack);
if (transport_length < 16)
goto truncated_tcp;
sa << " win " << ntohs(tcph->th_win);
return;
truncated_tcp:
sa << "truncated-tcp";
}
void
IPPrint::udp_line(StringAccum &sa, const Packet *p, int transport_length) const
{
const click_ip *iph = p->ip_header();
const click_udp *udph = p->udp_header();
if (transport_length < 4 || !IP_FIRSTFRAG(iph)) {
address_pair(sa, iph) << (IP_FIRSTFRAG(iph) ? ": truncated-udp" : ": udp");
return;
}
sa << IPAddress(iph->ip_src) << '.' << ntohs(udph->uh_sport) << " > "
<< IPAddress(iph->ip_dst) << '.' << ntohs(udph->uh_dport) << ": ";
if (transport_length < 8)
goto truncated_udp;
sa << "udp " << ntohs(udph->uh_ulen);
return;
truncated_udp:
sa << "truncated-udp";
}
static String
unparse_proto(int ip_p, bool prepend)
{
if (String s = NameInfo::revquery_int(NameInfo::T_IP_PROTO, 0, ip_p))
return s;
else if (prepend)
return String::make_stable("protocol ", 9) + String(ip_p);
else
return String(ip_p);
}
void
IPPrint::icmp_line(StringAccum &sa, const Packet *p, int transport_length) const
{
const click_ip *iph = p->ip_header();
const click_icmp *icmph = p->icmp_header();
address_pair(sa, iph) << ": ";
if (!IP_FIRSTFRAG(iph)) {
sa << "icmp";
return;
} else if (transport_length < 2)
goto truncated_icmp;
switch (icmph->icmp_type) {
case ICMP_ECHOREPLY:
sa << "icmp echo-reply ";
goto icmp_echo;
case ICMP_ECHO:
sa << "icmp echo ";
/* fallthru */
icmp_echo: {
if (transport_length < 8)
goto truncated_icmp;
const click_icmp_sequenced *seqh = reinterpret_cast<const click_icmp_sequenced *>(icmph);
#define swapit(x) (_swap ? ((((x) & 0xff) << 8) | ((x) >> 8)) : (x))
sa << '(' << swapit(seqh->icmp_identifier) << ", " << swapit(seqh->icmp_sequence) << ')';
break;
}
case ICMP_UNREACH: {
String code = NameInfo::revquery_int(NameInfo::T_ICMP_CODE + icmph->icmp_type, this, icmph->icmp_code);
if (!code)
code = "code " + String((int) icmph->icmp_code);
const click_ip *eiph = reinterpret_cast<const click_ip *>(icmph + 1);
int eiph_len = transport_length - sizeof(click_icmp);
if (eiph_len < (int) sizeof(click_ip)) {
sa << "icmp unreachable " << code << ' ';
goto truncated_icmp;
}
const click_udp *eudph = reinterpret_cast<const click_udp *>(reinterpret_cast<const uint8_t *>(eiph) + (eiph->ip_hl << 2));
int eudph_len = eiph_len - (eiph->ip_hl << 2);
sa << "icmp " << IPAddress(eiph->ip_dst) << " unreachable " << code;
switch (icmph->icmp_code) {
case ICMP_UNREACH_PROTOCOL:
sa << ' ' << unparse_proto(eiph->ip_p, false);
break;
case ICMP_UNREACH_PORT:
sa << ' ' << unparse_proto(eiph->ip_p, true);
if (eudph_len < 4)
goto truncated_icmp;
sa << '/' << ntohs(eudph->uh_dport);
break;
case ICMP_UNREACH_NEEDFRAG: {
const click_icmp_needfrag *nfh = reinterpret_cast<const click_icmp_needfrag *>(icmph);
if (nfh->icmp_nextmtu)
sa << " (mtu " << ntohs(nfh->icmp_nextmtu) << ')';
break;
}
}
break;
}
default:
sa << "icmp ";
if (String s = NameInfo::revquery_int(NameInfo::T_ICMP_TYPE, this, icmph->icmp_type))
sa << s;
else
sa << "type " << (int)icmph->icmp_type;
if (String s = NameInfo::revquery_int(NameInfo::T_ICMP_CODE + icmph->icmp_type, this, icmph->icmp_code))
sa << ' ' << s;
else if (icmph->icmp_code)
sa << " code " << (int)icmph->icmp_code;
break;
}
return;
truncated_icmp:
sa << "truncated-icmp";
}
Packet *
IPPrint::simple_action(Packet *p)
{
if (!_active || !p->has_network_header())
return p;
_count_every++;
if(_count_every < _print_every)
return p;
StringAccum sa;
sa << "(" << _count_every << "/" << _print_every << ")";
if (_label)
sa << _label << ": ";
if (_print_timestamp)
sa << p->timestamp_anno() << ": ";
if (_print_aggregate)
sa << '#' << AGGREGATE_ANNO(p);
if (_print_paint)
sa << (_print_aggregate ? "." : "paint ") << (int)PAINT_ANNO(p);
if (_print_aggregate || _print_paint)
sa << ": ";
_count_every = 0;
if (p->network_length() < (int) sizeof(click_ip))
sa << "truncated-ip";
else {
const click_ip *iph = p->ip_header();
int ip_len = ntohs(iph->ip_len);
int payload_len = ip_len - (iph->ip_hl << 2);
int transport_length = p->transport_length();
if (transport_length > payload_len)
transport_length = payload_len;
if (_print_id)
sa << "id " << ntohs(iph->ip_id) << ' ';
if (_print_ttl)
sa << "ttl " << (int)iph->ip_ttl << ' ';
if (_print_tos)
sa << "tos " << (int)iph->ip_tos << ' ';
if (_print_len)
sa << "length " << ip_len << ' ';
if (iph->ip_p == IP_PROTO_TCP)
tcp_line(sa, p, transport_length);
else if (iph->ip_p == IP_PROTO_UDP)
udp_line(sa, p, transport_length);
else if (iph->ip_p == IP_PROTO_ICMP)
icmp_line(sa, p, transport_length);
else
sa << IPAddress(iph->ip_src) << " > " << IPAddress(iph->ip_dst) << ": ip-proto-" << (int)iph->ip_p;
// print fragment info
if (IP_ISFRAG(iph))
sa << " (frag " << ntohs(iph->ip_id) << ':' << payload_len << '@'
<< ((ntohs(iph->ip_off) & IP_OFFMASK) << 3)
<< ((iph->ip_off & htons(IP_MF)) ? "+" : "") << ')';
// print payload
if (_contents > 0) {
const uint8_t *data;
if (_payload) {
if (IP_FIRSTFRAG(iph) && iph->ip_p == IP_PROTO_TCP)
data = p->transport_header() + (p->tcp_header()->th_off << 2);
else if (IP_FIRSTFRAG(iph) && iph->ip_p == IP_PROTO_UDP)
data = p->transport_header() + sizeof(click_udp);
else
data = p->transport_header();
} else
data = p->data();
int bytes = _bytes;
if (data >= p->end_data())
bytes = 0;
else if (bytes < 0 || (int) (p->end_data() - data) < bytes)
bytes = p->end_data() - data;
int amt = 3*bytes + (bytes/4+1) + 3*(bytes/24+1) + 1;
char *buf = sa.reserve(amt);
char *orig_buf = buf;
if (buf && _contents == 1) {
for (int i = 0; i < bytes; i++, data++) {
if ((i % 24) == 0) {
*buf++ = '\n'; *buf++ = ' '; *buf++ = ' ';
} else if ((i % 4) == 0)
*buf++ = ' ';
sprintf(buf, "%02x", *data & 0xff);
buf += 2;
}
} else if (buf && _contents == 2) {
for (int i = 0; i < bytes; i++, data++) {
if ((i % 48) == 0) {
*buf++ = '\n'; *buf++ = ' '; *buf++ = ' ';
} else if ((i % 8) == 0)
*buf++ = ' ';
if (*data < 32 || *data > 126)
*buf++ = '.';
else
*buf++ = *data;
}
}
if (orig_buf) {
assert(buf <= orig_buf + amt);
sa.adjust_length(buf - orig_buf);
}
}
}
#if CLICK_USERLEVEL
if (_outfile) {
sa << '\n';
ignore_result(fwrite(sa.data(), 1, sa.length(), _outfile));
} else
#endif
_errh->message("%s", sa.c_str());
return p;
}
void
IPPrint::add_handlers()
{
add_data_handlers("active", Handler::OP_READ | Handler::OP_WRITE | Handler::CHECKBOX | Handler::CALM, &_active);
}
CLICK_ENDDECLS
EXPORT_ELEMENT(IPPrint)
Event Timeline
Log In to Comment