📄 fromtcpdump.cc
字号:
// -*- mode: c++; c-basic-offset: 4 -*-/* * fromtcpdump.{cc,hh} -- element reads packets from IP summary dump file * Eddie Kohler * * Copyright (c) 2003 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 "fromtcpdump.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 <click/packet_anno.hh>#include <click/userutils.hh>#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>CLICK_DECLSFromTcpdump::FromTcpdump() : Element(0, 1), _task(this){ _ff.set_landmark_pattern("%f:%l");}FromTcpdump::~FromTcpdump(){}void *FromTcpdump::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);}intFromTcpdump::configure(Vector<String> &conf, ErrorHandler *errh){ bool stop = false, active = true, zero = true, checksum = false; _sampling_prob = (1 << SAMPLING_SHIFT); _absolute_seq = -1; 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, 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"); _stop = stop; _active = active; _zero = zero; _checksum = checksum; _dead = false; return 0;}intFromTcpdump::initialize(ErrorHandler *errh){ // make sure notifier is initialized if (!output_is_push(0)) _notifier.initialize(router()); if (_ff.initialize(errh) < 0) return -1; // read a line String line; if (_ff.peek_line(line, errh) < 0) return -1; else if (!line || !isdigit(line[0])) errh->lwarning(_ff.print_filename(), "first line suspicious; is this a tcpdump output file?"); _format_complaint = false; if (output_is_push(0)) ScheduleInfo::initialize_task(this, &_task, _active, errh); return 0;}voidFromTcpdump::cleanup(CleanupStage){ _ff.cleanup();}static voidappend_net_uint32_t(StringAccum &sa, uint32_t u){ sa << (char)(u >> 24) << (char)(u >> 16) << (char)(u >> 8) << (char)u;}static voidset_checksums(WritablePacket *q, click_ip *iph){ assert(iph == q->ip_header()); iph->ip_sum = 0; iph->ip_sum = click_in_cksum((uint8_t *)iph, iph->ip_hl << 2); if (IP_ISFRAG(iph)) /* nada */; else if (iph->ip_p == IP_PROTO_TCP) { click_tcp *tcph = q->tcp_header(); tcph->th_sum = 0; unsigned csum = click_in_cksum((uint8_t *)tcph, q->transport_length()); tcph->th_sum = click_in_cksum_pseudohdr(csum, iph, q->transport_length()); } else if (iph->ip_p == IP_PROTO_UDP) { click_udp *udph = q->udp_header(); udph->uh_sum = 0; unsigned csum = click_in_cksum((uint8_t *)udph, q->transport_length()); udph->uh_sum = click_in_cksum_pseudohdr(csum, iph, q->transport_length()); }}const char *FromTcpdump::read_tcp_line(WritablePacket *&q, const char *s, const char *end, int *data_len){ click_tcp *tcph = q->tcp_header(); // first, read flags if (s < end && *s == '.') tcph->th_flags = TH_ACK, s++; else { tcph->th_flags = 0; while (s < end && IPSummaryDump::tcp_flag_mapping[(uint8_t) *s]) { tcph->th_flags |= (1 << (IPSummaryDump::tcp_flag_mapping[ (uint8_t) *s ] - 1)); s++; } } if (s >= end || *s != ' ') return s; // second, check for '[bad hdr length]' '[tcp sum ok]' const char *s2; if (s + 9 <= end && memcmp(s + 1, "[bad hdr", 8) == 0 && (s2 = find(s + 9, end, ']')) + 1 < end && s2[1] == ' ') s = s2 + 1; if (s + 14 <= end && memcmp(s + 1, "[tcp sum ok] ", 13) == 0) s += 14; else if (s + 9 <= end && memcmp(s + 1, "[bad tcp", 8) == 0 && (s2 = find(s + 9, end, ']')) + 1 < end && s2[1] == ' ') s = s2 + 2; else s++; // then read sequence numbers uint32_t seq = 0, end_seq = 0, ack_seq = 0; if (s < end && s[0] != 'a') { const char *eseq = cp_unsigned(s, end, 0, &seq); if (eseq == s || eseq >= end || *eseq != ':') return s; const char *eend_seq = cp_unsigned(eseq + 1, end, 0, &end_seq); if (eend_seq == eseq + 1 || eend_seq >= end || *eend_seq != '(') return s; // skip parenthesized length for (s = eend_seq + 1; s < end && isdigit(*s); s++) /* nada */; if (s >= end || *s != ')') return s; else if (s + 1 >= end || s[1] != ' ') return s + 1; else s += 2; } *data_len = end_seq - seq; // check for 'ack' if (s + 4 < end && s[0] == 'a' && s[1] == 'c' && s[2] == 'k' && s[3] == ' ' && isdigit(s[4])) { tcph->th_flags |= TH_ACK; s = cp_unsigned(s + 4, end, 0, &ack_seq); if (s < end && *s == ' ') s++; } // patch sequence numbers FlowRecord *record = 0; bool rev = false; if (tcph->th_flags & TH_ACK) { // first, look up a record for this flow const click_ip *iph = q->ip_header(); rev = (tcph->th_sport < tcph->th_dport || (tcph->th_sport == tcph->th_dport && iph->ip_src.s_addr < iph->ip_dst.s_addr)); if (rev) record = _tcp_map.findp_force(IPFlowID(iph->ip_src, tcph->th_sport, iph->ip_dst, tcph->th_dport)); else record = _tcp_map.findp_force(IPFlowID(iph->ip_dst, tcph->th_dport, iph->ip_src, tcph->th_sport)); // use tcpdump's heuristic for deciding when this is a new flow if ((!record->init_seq[0] && !record->init_seq[1]) || (tcph->th_flags & TH_SYN)) { record->init_seq[rev] = seq; record->init_seq[!rev] = ack_seq - 1; } else { if (_absolute_seq < 0) // heuristic _absolute_seq = (SEQ_GEQ(ack_seq, record->init_seq[!rev]) && ack_seq > 8000); if (seq == 0 && end_seq == 0) seq = end_seq = record->last_seq[rev]; else if (!_absolute_seq) { seq += record->init_seq[rev]; end_seq += record->init_seq[rev]; } if (!_absolute_seq) ack_seq += record->init_seq[!rev]; } // record last seen sequence numbers for assignment to pure acks record->last_seq[rev] = end_seq + (tcph->th_flags & TH_SYN ? 1 : 0) + (tcph->th_flags & TH_FIN ? 1 : 0); if (!record->last_seq[!rev]) record->last_seq[!rev] = ack_seq; } tcph->th_seq = htonl(seq); tcph->th_ack = htonl(ack_seq); // check for 'win' uint32_t u; if (s + 4 < end && s[0] == 'w' && s[1] == 'i' && s[2] == 'n' && s[3] == ' ' && isdigit(s[4])) { s = cp_unsigned(s + 4, end, 0, &u); // XXX check u <= 65535 tcph->th_win = htons(u); if (s < end && *s == ' ') s++; } // check for 'urg' if (s + 4 < end && s[0] == 'u' && s[1] == 'r' && s[2] == 'g' && s[3] == ' ' && isdigit(s[4])) { s = cp_unsigned(s + 4, end, 0, &u); // XXX check u <= 65535 tcph->th_urp = htons(u); if (s < end && *s != ' ') s++; } // check for options StringAccum opt; if (s < end && s[0] == '<') { for (s++; s < end && *s != '>'; ) { int optlen1 = opt.length(); if (s + 3 <= end && s[0] == 'n' && s[1] == 'o' && s[2] == 'p') { opt << (char)TCPOPT_NOP; s += 3; } else if (s + 3 <= end && s[0] == 'e' && s[1] == 'o' && s[2] == 'l') { opt << (char)TCPOPT_EOL; s += 3; } else if (s + 4 < end && s[0] == 'm' && s[1] == 's' && s[2] == 's' && s[3] == ' ' && isdigit(s[4])) { s = cp_unsigned(s + 4, end, 0, &u); // XXX check u <= 65535 opt << (char)TCPOPT_MAXSEG << (char)TCPOLEN_MAXSEG << (char)((u >> 8) & 255) << (char)(u & 255); } else if (s + 7 < end && memcmp(s, "wscale ", 7) == 0 && isdigit(s[7])) { s = cp_unsigned(s + 7, end, 0, &u); // XXX check u <= 255 opt << (char)TCPOPT_WSCALE << (char)TCPOLEN_WSCALE << (char)u; } else if (s + 6 <= end && memcmp(s, "sackOK", 6) == 0) { opt << (char)TCPOPT_SACK_PERMITTED << (char)TCPOLEN_SACK_PERMITTED; s += 6; } else if (s + 10 < end && memcmp(s, "timestamp ", 10) == 0 && isdigit(s[10])) { s = cp_unsigned(s + 10, end, 0, &u); if (s + 1 < end && *s == ' ' && isdigit(s[1])) { uint32_t u2; s = cp_unsigned(s + 1, end, 0, &u2); opt << (char)TCPOPT_TIMESTAMP << (char)TCPOLEN_TIMESTAMP; append_net_uint32_t(opt, u); append_net_uint32_t(opt, u2); } } else if (s + 10 < end && memcmp(s, "sack sack ", 10) == 0 && isdigit(s[10])) { uint32_t nsack, u2; s = cp_unsigned(s + 10, end, 0, &nsack); opt << (char)TCPOPT_SACK << (char)(nsack * 8 + 2); while (s < end && *s == ' ') s++; while (s + 1 < end && *s == '{' && isdigit(s[1])) { s = cp_unsigned(s + 1, end, 0, &u); if (s + 1 < end && *s == ':' && isdigit(s[1])) { s = cp_unsigned(s + 1, end, 0, &u2); if (s < end && *s == '}') { s++; if (record && !_absolute_seq) { u += record->init_seq[!rev]; u2 += record->init_seq[!rev]; } append_net_uint32_t(opt, u); append_net_uint32_t(opt, u2); } } } while (s < end && *s == ' ') s++; } if (s < end && *s == ',') s++; else if (s < end && *s != '>') { // not the option we thought opt.set_length(optlen1); while (s < end && *s != ',' && *s != '>') s++; } } if (s < end && *s == '>') s++; while (opt.length() % 4 != 0) opt << (char)TCPOPT_EOL; q = q->put(opt.length()); memcpy(q->transport_header() + sizeof(click_tcp), opt.data(), opt.length()); q->tcp_header()->th_off = (sizeof(click_tcp) + opt.length()) >> 2; } else tcph->th_off = sizeof(click_tcp) >> 2; return s;}const char *FromTcpdump::read_udp_line(WritablePacket *&, const char *s, const char *end, int *data_len){ // first, check for '[bad hdr length]' '[udp sum ok]' const char *s2; if (s + 9 <= end && memcmp(s + 1, "[bad hdr", 8) == 0 && (s2 = find(s + 9, end, ']')) + 1 < end && s2[1] == ' ') s = s2 + 1; if (s + 14 <= end && memcmp(s + 1, "[udp sum ok] ", 13) == 0) s += 14;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -