📄 ipsumdump_tcp.cc
字号:
// -*- mode: c++; c-basic-offset: 4 -*-/* * ipsumdump_tcp.{cc,hh} -- IP transport summary dump unparsers * Eddie Kohler * * Copyright (c) 2002 International Computer Science Institute * Copyright (c) 2004 Regents of the University of California * Copyright (c) 2008 Meraki, Inc. * * 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 "ipsumdump_tcp.hh"#include <click/packet.hh>#include <click/nameinfo.hh>#include <clicknet/ip.h>#include <clicknet/tcp.h>#include <clicknet/udp.h>#include <clicknet/icmp.h>#include <click/confparse.hh>CLICK_DECLSnamespace IPSummaryDump {enum { T_TCP_SEQ, T_TCP_ACK, T_TCP_FLAGS, T_TCP_WINDOW, T_TCP_URP, T_TCP_OPT, T_TCP_NTOPT, T_TCP_SACK, T_TCP_OFF };static bool tcp_extract(PacketDesc& d, const FieldWriter *f){ int transport_length = d.p->transport_length(); switch (f->user_data) {#define CHECK(l) do { if (!d.tcph || transport_length < (l)) return field_missing(d, IP_PROTO_TCP, (l)); } while (0) case T_TCP_SEQ: CHECK(8); d.v = ntohl(d.tcph->th_seq); return true; case T_TCP_ACK: CHECK(12); d.v = ntohl(d.tcph->th_ack); return true; case T_TCP_FLAGS: CHECK(14); d.v = d.tcph->th_flags | (d.tcph->th_flags2 << 8); return true; case T_TCP_OFF: CHECK(13); d.v = d.tcph->th_off << 2; return true; case T_TCP_WINDOW: CHECK(16); d.v = ntohs(d.tcph->th_win); return true; case T_TCP_URP: CHECK(20); d.v = ntohs(d.tcph->th_urp); return true; case T_TCP_OPT: // need to check that d.tcph->th_off exists if (!d.tcph || transport_length < 13 || (d.tcph->th_off > 5 && transport_length < (int)(d.tcph->th_off << 2))) goto no_tcp_opt; if (d.tcph->th_off <= 5) d.vptr[0] = d.vptr[1] = 0; else { d.vptr[0] = (const uint8_t *) (d.tcph + 1); d.vptr[1] = d.vptr[0] + (d.tcph->th_off << 2) - sizeof(click_tcp); } return true; case T_TCP_NTOPT: case T_TCP_SACK: // need to check that d.tcph->th_off exists if (!d.tcph || transport_length < 13) goto no_tcp_opt; else if (d.tcph->th_off <= 5 || (d.tcph->th_off == 8 && transport_length >= 24 && *(reinterpret_cast<const uint32_t *>(d.tcph + 1)) == htonl(0x0101080A))) d.vptr[0] = d.vptr[1] = 0; else if (transport_length < (int)(d.tcph->th_off << 2)) goto no_tcp_opt; else { d.vptr[0] = (const uint8_t *) (d.tcph + 1); d.vptr[1] = d.vptr[0] + (d.tcph->th_off << 2) - sizeof(click_tcp); } return true;#undef CHECK default: return false; no_tcp_opt: return field_missing(d, IP_PROTO_TCP, transport_length + 1); }}static void tcp_inject(PacketOdesc& d, const FieldReader *f){ if (!d.make_ip(IP_PROTO_TCP) || !d.make_transp()) return; click_tcp *tcph = d.p->tcp_header(); switch (f->user_data) { case T_TCP_SEQ: tcph->th_seq = htonl(d.v); break; case T_TCP_ACK: tcph->th_ack = htonl(d.v); break; case T_TCP_FLAGS: tcph->th_flags = d.v; tcph->th_flags2 = d.v >> 8; break; case T_TCP_OFF: d.v = (d.v + 3) & ~3; if ((int) d.v > (int) (tcph->th_off << 2)) { int more = d.v - (tcph->th_off << 2); if (!(d.p = d.p->put(more))) return; tcph = d.p->tcp_header(); memset(d.p->transport_header() + d.v - more, TCPOPT_EOL, more); } tcph->th_off = d.v >> 2; break; case T_TCP_WINDOW: tcph->th_win = htons(d.v); break; case T_TCP_URP: tcph->th_urp = htons(d.v); break; case T_TCP_OPT: case T_TCP_NTOPT: case T_TCP_SACK: { if (!d.vptr[0] || d.vptr[0] == d.vptr[1]) return; int olen = d.vptr[1] - d.vptr[0]; int th_off = (sizeof(click_tcp) + olen + 3) & ~3; if (d.p->transport_length() < th_off) { if (!(d.p = d.p->put(th_off - d.p->transport_length()))) return; tcph = d.p->tcp_header(); } if (th_off > (int) (tcph->th_off << 2)) tcph->th_off = th_off >> 2; memcpy(d.p->transport_header() + sizeof(click_tcp), d.vptr[0], olen); memset(d.p->transport_header() + sizeof(click_tcp) + olen, TCPOPT_EOL, th_off - olen); break; } }}static void tcp_outa(const PacketDesc& d, const FieldWriter *f){ switch (f->user_data) { case T_TCP_FLAGS: if (d.v == (TH_ACK | TH_PUSH)) *d.sa << 'P' << 'A'; else if (d.v == TH_ACK) *d.sa << 'A'; else if (d.v == 0) *d.sa << '.'; else for (int flag = 0; flag < 9; flag++) if (d.v & (1 << flag)) *d.sa << tcp_flags_word[flag]; break; case T_TCP_OPT: if (!d.vptr) *d.sa << '.'; else unparse_tcp_opt(*d.sa, d.vptr[0], d.vptr[1] - d.vptr[0], DO_TCPOPT_ALL_NOPAD); break; case T_TCP_NTOPT: if (!d.vptr) *d.sa << '.'; else unparse_tcp_opt(*d.sa, d.vptr[0], d.vptr[1] - d.vptr[0], DO_TCPOPT_NTALL); break; case T_TCP_SACK: if (!d.vptr) *d.sa << '.'; else unparse_tcp_opt(*d.sa, d.vptr[0], d.vptr[1] - d.vptr[0], DO_TCPOPT_SACK); break; }}static bool tcp_ina(PacketOdesc& d, const String &str, const FieldReader *f){ switch (f->user_data) { case T_TCP_FLAGS: if (str.equals(".", 1)) d.v = 0; else if (!str) return false; else if (isdigit((unsigned char) str[0])) return cp_integer(str, &d.v) && d.v < 0x1000; else { d.v = 0; for (const char *s = str.begin(); s != str.end(); s++) if (uint8_t fm = IPSummaryDump::tcp_flag_mapping[(unsigned char) *s]) d.v |= 1 << (fm - 1); else return false; } return true; default: return false; }}static void tcp_outb(const PacketDesc& d, bool ok, const FieldWriter *f){ switch (f->user_data) { case T_TCP_OPT: if (!ok || !d.vptr) *d.sa << '\0'; else unparse_tcp_opt_binary(*d.sa, d.vptr[0], d.vptr[1] - d.vptr[0], DO_TCPOPT_ALL); break; case T_TCP_NTOPT: if (!ok || !d.vptr) *d.sa << '\0'; else unparse_tcp_opt_binary(*d.sa, d.vptr[0], d.vptr[1] - d.vptr[0], DO_TCPOPT_NTALL); break; case T_TCP_SACK: if (!ok || !d.vptr) *d.sa << '\0'; else unparse_tcp_opt_binary(*d.sa, d.vptr[0], d.vptr[1] - d.vptr[0], DO_TCPOPT_SACK); break; }}static const uint8_t* tcp_inb(PacketOdesc& d, const uint8_t* s, const uint8_t* ends, const FieldReader *f){ switch (f->user_data) { case T_TCP_OPT: case T_TCP_NTOPT: case T_TCP_SACK: if (s + s[0] + 1 <= ends) { d.vptr[0] = s + 1; d.vptr[1] = d.vptr[0] + s[0]; return s + s[0] + 1; } break; } return ends;}static int tcp_opt_mask_mapping[] = { DO_TCPOPT_PADDING, DO_TCPOPT_PADDING, // EOL, NOP DO_TCPOPT_MSS, DO_TCPOPT_WSCALE, // MAXSEG, WSCALE DO_TCPOPT_SACK, DO_TCPOPT_SACK, // SACK_PERMITTED, SACK DO_TCPOPT_UNKNOWN, DO_TCPOPT_UNKNOWN, // 6, 7 DO_TCPOPT_TIMESTAMP // TIMESTAMP};void unparse_tcp_opt(StringAccum& sa, const uint8_t* opt, int opt_len, int mask){ int initial_sa_len = sa.length(); const uint8_t *end_opt = opt + opt_len; const char *sep = ""; while (opt < end_opt) switch (*opt) { case TCPOPT_EOL: if (mask & DO_TCPOPT_PADDING) sa << sep << "eol"; goto done; case TCPOPT_NOP: if (mask & DO_TCPOPT_PADDING) { sa << sep << "nop"; sep = ";"; } opt++; break; case TCPOPT_MAXSEG: if (opt + opt[1] > end_opt || opt[1] != TCPOLEN_MAXSEG) goto bad_opt; if (!(mask & DO_TCPOPT_MSS)) goto unknown; sa << sep << "mss" << ((opt[2] << 8) | opt[3]); opt += TCPOLEN_MAXSEG; sep = ";"; break; case TCPOPT_WSCALE: if (opt + opt[1] > end_opt || opt[1] != TCPOLEN_WSCALE) goto bad_opt; if (!(mask & DO_TCPOPT_WSCALE)) goto unknown; sa << sep << "wscale" << (int)(opt[2]); opt += TCPOLEN_WSCALE; sep = ";"; break; case TCPOPT_SACK_PERMITTED: if (opt + opt[1] > end_opt || opt[1] != TCPOLEN_SACK_PERMITTED) goto bad_opt; if (!(mask & DO_TCPOPT_SACK)) goto unknown; sa << sep << "sackok"; opt += TCPOLEN_SACK_PERMITTED; sep = ";";
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -