📄 fromipsumdump.cc
字号:
// -*- mode: c++; c-basic-offset: 4 -*-/* * fromipsumdump.{cc,hh} -- element reads packets from IP summary dump file * Eddie Kohler * * Copyright (c) 2001 International Computer Science Institute * * 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 "fromipsumdump.hh"#include <click/confparse.hh>#include <click/router.hh>#include <click/standard/scheduleinfo.hh>#include <click/error.hh>#include <click/glue.hh>#include <click/straccum.hh>#include <clicknet/ip.h>#include <clicknet/udp.h>#include <clicknet/tcp.h>#include <click/packet_anno.hh>#include <click/userutils.hh>#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>CLICK_DECLS#ifdef i386# define GET4(p) ntohl(*reinterpret_cast<const uint32_t *>((p)))# define GET2(p) ntohs(*reinterpret_cast<const uint16_t *>((p)))#else# define GET4(p) (((p)[0]<<24) | ((p)[1]<<16) | ((p)[2]<<8) | (p)[3])# define GET2(p) (((p)[0]<<8) | (p)[1])#endif#define GET1(p) ((p)[0])FromIPSummaryDump::FromIPSummaryDump() : Element(0, 1), _work_packet(0), _task(this){ _ff.set_landmark_pattern("%f:%l");}FromIPSummaryDump::~FromIPSummaryDump(){}void *FromIPSummaryDump::cast(const char *n){ if (strcmp(n, Notifier::EMPTY_NOTIFIER) == 0 && !output_is_push(0)) { _notifier.initialize(router()); return static_cast<Notifier *>(&_notifier); } else return Element::cast(n);}intFromIPSummaryDump::configure(Vector<String> &conf, ErrorHandler *errh){ bool stop = false, active = true, zero = true, checksum = false, multipacket = false; uint8_t default_proto = IP_PROTO_TCP; _sampling_prob = (1 << SAMPLING_SHIFT); String default_contents, default_flowid; if (cp_va_parse(conf, this, errh, cpFilename, "dump file name", &_ff.filename(), cpKeywords, "STOP", cpBool, "stop driver when done?", &stop, "ACTIVE", cpBool, "start active?", &active, "ZERO", cpBool, "zero packet data?", &zero, "CHECKSUM", cpBool, "set packet checksums?", &checksum, "SAMPLE", cpUnsignedReal2, "sampling probability", SAMPLING_SHIFT, &_sampling_prob, "PROTO", cpByte, "default IP protocol", &default_proto, "MULTIPACKET", cpBool, "generate multiple packets per record?", &multipacket, "DEFAULT_CONTENTS", cpArgument, "default contents of log", &default_contents, "DEFAULT_FLOWID", cpArgument, "default flow ID", &default_flowid, "CONTENTS", cpArgument, "default contents of log", &default_contents, "FLOWID", cpArgument, "default flow ID", &default_flowid, cpEnd) < 0) return -1; if (_sampling_prob > (1 << SAMPLING_SHIFT)) { errh->warning("SAMPLE probability reduced to 1"); _sampling_prob = (1 << SAMPLING_SHIFT); } else if (_sampling_prob == 0) errh->warning("SAMPLE probability is 0; emitting no packets"); _default_proto = default_proto; _stop = stop; _active = active; _zero = zero; _checksum = checksum; _multipacket = multipacket; _have_flowid = _have_aggregate = _use_flowid = _use_aggregate = _binary = false; if (default_contents) bang_data(default_contents, errh); if (default_flowid) bang_flowid(default_flowid, 0, errh); return 0;}intFromIPSummaryDump::read_binary(String &result, ErrorHandler *errh){ assert(_binary); uint8_t record_storage[4]; const uint8_t *record = _ff.get_unaligned(4, record_storage, errh); if (!record) return 0; int record_length = GET4(record) & 0x7FFFFFFFU; if (record_length < 4) return _ff.error(errh, "binary record too short"); bool textual = (record[0] & 0x80 ? true : false); result = _ff.get_string(record_length - 4, errh); if (!result) return 0; if (textual) { const char *s = result.begin(), *e = result.end(); while (e > s && e[-1] == 0) e--; if (e != result.end()) result = result.substring(s, e); } _ff.set_lineno(_ff.lineno() + 1); return (textual ? 2 : 1);}intFromIPSummaryDump::initialize(ErrorHandler *errh){ // make sure notifier is initialized if (!output_is_push(0)) _notifier.initialize(router()); if (_ff.initialize(errh) < 0) return -1; _minor_version = IPSummaryDump::MINOR_VERSION; // expected minor version String line; if (_ff.peek_line(line, errh) < 0) return -1; else if (line.substring(0, 14) == "!IPSummaryDump") { int major_version; if (sscanf(line.cc() + 14, " %d.%d", &major_version, &_minor_version) == 2) { if (major_version != IPSummaryDump::MAJOR_VERSION || _minor_version > IPSummaryDump::MINOR_VERSION) { _ff.warning(errh, "unexpected IPSummaryDump version %d.%d", major_version, _minor_version); _minor_version = IPSummaryDump::MINOR_VERSION; } } (void) _ff.read_line(line, errh); // throw away line } else { // parse line again, warn if this doesn't look like a dump if (line.substring(0, 8) != "!creator" && line.substring(0, 5) != "!data" && line.substring(0, 9) != "!contents") { if (!_contents.size() /* don't warn on DEFAULT_CONTENTS */) _ff.warning(errh, "missing banner line; is this an IP summary dump?"); } } _format_complaint = false; if (output_is_push(0)) ScheduleInfo::initialize_task(this, &_task, _active, errh); return 0;}voidFromIPSummaryDump::cleanup(CleanupStage){ _ff.cleanup(); if (_work_packet) _work_packet->kill(); _work_packet = 0;}voidFromIPSummaryDump::bang_data(const String &line, ErrorHandler *errh){ Vector<String> words; cp_spacevec(line, words); _contents.clear(); uint32_t all_contents = 0; for (int i = 0; i < words.size(); i++) { String word = cp_unquote(words[i]); int what = parse_content(word); if (what >= W_NONE && what < W_LAST) { _contents.push_back(what); all_contents |= (1 << (what - W_NONE)); } else if (i > 0 || (word != "!data" && word != "!contents")) { _ff.warning(errh, "unknown content type '%s'", word.c_str()); _contents.push_back(W_NONE); } } if (_contents.size() == 0) _ff.error(errh, "no contents specified"); // If we have W_IP_FRAGOFF, ignore W_IP_FRAG. if (all_contents & (1 << (W_IP_FRAGOFF - W_NONE))) for (int i = 0; i < _contents.size(); i++) if (_contents[i] == W_IP_FRAG) _contents[i] = W_NONE; // recheck whether to use '!flowid' and '!aggregate' check_defaults();}voidFromIPSummaryDump::check_defaults(){ _use_flowid = false; _flowid = (_have_flowid ? _given_flowid : IPFlowID()); _use_aggregate = _have_aggregate; for (int i = 0; i < _contents.size(); i++) if (_contents[i] == W_IP_SRC) _flowid.set_saddr(IPAddress()); else if (_contents[i] == W_IP_DST) _flowid.set_daddr(IPAddress()); else if (_contents[i] == W_SPORT) _flowid.set_sport(0); else if (_contents[i] == W_DPORT) _flowid.set_dport(0); else if (_contents[i] == W_AGGREGATE) _use_aggregate = false; if (_flowid || _flowid.sport() || _flowid.dport()) _use_flowid = true;}voidFromIPSummaryDump::bang_flowid(const String &line, click_ip *iph, ErrorHandler *errh){ Vector<String> words; cp_spacevec(line, words); IPAddress src, dst; uint32_t sport = 0, dport = 0, proto = 0; if (words.size() < 5 || (!cp_ip_address(words[1], &src) && words[1] != "-") || (!cp_unsigned(words[2], &sport) && words[2] != "-") || (!cp_ip_address(words[3], &dst) && words[3] != "-") || (!cp_unsigned(words[4], &dport) && words[4] != "-") || sport > 65535 || dport > 65535) { _ff.error(errh, "bad !flowid specification"); _have_flowid = _use_flowid = false; } else { if (words.size() >= 6) { if (cp_unsigned(words[5], &proto) && proto < 256) _default_proto = proto; else if (words[5] == "T") _default_proto = IP_PROTO_TCP; else if (words[5] == "U") _default_proto = IP_PROTO_UDP; else if (words[5] == "I") _default_proto = IP_PROTO_ICMP; else _ff.error(errh, "bad protocol in !flowid"); } _given_flowid = IPFlowID(src, htons(sport), dst, htons(dport)); _have_flowid = true; check_defaults(); if (iph) iph->ip_p = _default_proto; }}voidFromIPSummaryDump::bang_aggregate(const String &line, ErrorHandler *errh){ Vector<String> words; cp_spacevec(line, words); if (words.size() != 2 || !cp_unsigned(words[1], &_aggregate)) { _ff.error(errh, "bad !aggregate specification"); _have_aggregate = _use_aggregate = false; } else { _have_aggregate = true; check_defaults(); }}voidFromIPSummaryDump::bang_binary(const String &line, ErrorHandler *errh){ Vector<String> words; cp_spacevec(line, words); if (words.size() != 1) _ff.error(errh, "bad !binary specification"); for (int i = 0; i < _contents.size(); i++) if (content_binary_size(_contents[i]) < 0) { _ff.error(errh, "contents incompatible with !binary"); // XXX _pos = 0xFFFFFFFFU; // prevent reading more data } _binary = true; _ff.set_landmark_pattern("%f:record %l"); _ff.set_lineno(1);}static voidappend_net_uint32_t(StringAccum &sa, uint32_t u){ sa << (char)(u >> 24) << (char)(u >> 16) << (char)(u >> 8) << (char)u;}const unsigned char *FromIPSummaryDump::parse_ip_opt_ascii(const unsigned char *begin, const unsigned char *end, String *result, int contents){ StringAccum sa; const unsigned char *s = begin; while (1) { const unsigned char *t; uint32_t u1; if (s + 3 < end && memcmp(s, "rr{", 3) == 0 && (contents & DO_IPOPT_ROUTE)) { // record route sa << (char)IPOPT_RR; s += 3; parse_route: int sa_pos = sa.length() - 1; int pointer = -1; sa << '\0' << '\0'; // loop over entries while (1) { if (s < end && *s == '^' && pointer < 0) pointer = sa.length() - sa_pos + 1, s++; if (s >= end || !isdigit(*s)) break; for (int i = 0; i < 4; i++) { u1 = 256; s = cp_unsigned(s, end, 10, &u1) + (i < 3); if (u1 > 255 || (i < 3 && (s > end || s[-1] != '.'))) goto bad_opt; sa << (char)u1; } if (s < end && *s == ',') s++; } if (s >= end || *s != '}') // must end with a brace goto bad_opt; sa[sa_pos + 2] = (pointer >= 0 ? pointer : sa.length() - sa_pos + 1); if (s + 2 < end && s[1] == '+' && isdigit(s[2])) { s = cp_unsigned(s + 2, end, 10, &u1); if (u1 < 64) sa.append_fill('\0', u1 * 4); } else s++; if (sa.length() - sa_pos > 255) goto bad_opt; sa[sa_pos + 1] = sa.length() - sa_pos; } else if (s + 5 < end && memcmp(s, "ssrr{", 5) == 0 && (contents & DO_IPOPT_ROUTE)) { // strict source route option sa << (char)IPOPT_SSRR; s += 5; goto parse_route; } else if (s + 5 < end && memcmp(s, "lsrr{", 5) == 0 && (contents & DO_IPOPT_ROUTE)) { // loose source route option sa << (char)IPOPT_LSRR; s += 5; goto parse_route; } else if (s + 3 < end && (memcmp(s, "ts{", 3) == 0 || memcmp(s, "ts.", 3) == 0) && (contents & DO_IPOPT_TS)) { // timestamp option int sa_pos = sa.length(); sa << (char)IPOPT_TS << (char)0 << (char)0 << (char)0; uint32_t top_bit; int flag = -1; if (s[2] == '.') { if (s + 6 < end && memcmp(s + 3, "ip{", 3) == 0) flag = 1, s += 6; else if (s + 9 < end && memcmp(s + 3, "preip{", 6) == 0) flag = 3, s += 9; else if (isdigit(s[3]) && (t = cp_unsigned(s + 3, end, 0, (uint32_t *)&flag)) && flag <= 15 && t < end && *t == '{') s = t + 1; else goto bad_opt; } else s += 3; int pointer = -1; // loop over timestamp entries while (1) { if (s < end && *s == '^' && pointer < 0) pointer = sa.length() - sa_pos + 1, s++; if (s >= end || (!isdigit(*s) && *s != '!')) break; const unsigned char *entry = s; retry_entry: if (flag == 1 || flag == 3 || flag == -2) { // parse IP address for (int i = 0; i < 4; i++) { u1 = 256; s = cp_unsigned(s, end, 10, &u1) + (i < 3); if (u1 > 255 || (i < 3 && (s > end || s[-1] != '.'))) goto bad_opt; sa << (char)u1; } // prespecified IPs if we get here if (pointer >= 0 && flag == -2) flag = 3; // check for valid value: either "=[DIGIT]", "=!", "=?" // (for pointer >= 0) if (s + 1 < end && *s == '=') { if (isdigit(s[1]) || s[1] == '!') s++; else if (s[1] == '?' && pointer >= 0) { sa << (char)0 << (char)0 << (char)0 << (char)0; s += 2; goto done_entry; } else goto bad_opt; } else if (pointer >= 0) { sa << (char)0 << (char)0 << (char)0 << (char)0; goto done_entry; } else goto bad_opt; } // parse timestamp value assert(s < end); top_bit = 0; if (*s == '!') top_bit = 0x80000000U, s++; if (s >= end || !isdigit(*s)) goto bad_opt; s = cp_unsigned(s, end, 0, &u1); if (s < end && *s == '.' && flag == -1) { flag = -2; s = entry; goto retry_entry; } else if (flag == -1) flag = 0; u1 |= top_bit; append_net_uint32_t(sa, u1); done_entry: // check separator if (s < end && *s == ',') s++; } // done with entries if (s < end && *s++ != '}') goto bad_opt; if (flag == -2) flag = 1; sa[sa_pos + 2] = (pointer >= 0 ? pointer : sa.length() - sa_pos + 1); if (s + 1 < end && *s == '+' && isdigit(s[1]) && (s = cp_unsigned(s + 1, end, 0, &u1)) && u1 < 64) sa.append_fill('\0', u1 * (flag == 1 || flag == 3 ? 8 : 4)); int overflow = 0; if (s + 2 < end && *s == '+' && s[1] == '+' && isdigit(s[2]) && (s = cp_unsigned(s + 2, end, 0, &u1)) && u1 < 16) overflow = u1; sa[sa_pos + 3] = (overflow << 4) | flag; if (sa.length() - sa_pos > 255) goto bad_opt; sa[sa_pos + 1] = sa.length() - sa_pos; } else if (s < end && isdigit(*s) && (contents & DO_IPOPT_UNKNOWN)) { // unknown option s = cp_unsigned(s, end, 0, &u1); if (u1 >= 256) goto bad_opt; sa << (char)u1; if (s + 1 < end && *s == '=' && isdigit(s[1])) { int pos0 = sa.length(); sa << (char)0; do { s = cp_unsigned(s + 1, end, 0, &u1); if (u1 >= 256) goto bad_opt; sa << (char)u1; } while (s + 1 < end && *s == ':' && isdigit(s[1])); if (sa.length() > pos0 + 254) goto bad_opt;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -