diff --git a/FPEngine.cc b/FPEngine.cc index f1001dcbb..d362c7325 100644 --- a/FPEngine.cc +++ b/FPEngine.cc @@ -833,6 +833,33 @@ static int vectorize_icmpv6_code(const PacketElement *pe) { return icmpv6->getCode(); } +struct tcpopt_vectorize_ctx { + feature_node *features; + const unsigned int base; + unsigned int optnum; + int mss; + int sackok; + int wscale; + tcpopt_vectorize_ctx(feature_node *f, unsigned int i) + : features(f), base(i), optnum(0), mss(-1), sackok(-1), wscale(-1) {} +}; + +static const u8 MODEL_NUM_OPTS = 16; +static bool tcpopt_vectorize(u8 op, u8 oplen, const u8 *data, void *ctx) { + tcpopt_vectorize_ctx *c = static_cast(ctx); + c->features[c->base + c->optnum].value = op; + c->features[c->base + c->optnum + MODEL_NUM_OPTS].value = oplen; + if (op == TCPOPT_MSS && oplen == 4 && c->mss == -1) + c->mss = (data[2] << 8) + data[3]; + else if (op == TCPOPT_SACKOK && oplen == 2 && c->sackok == -1) + c->sackok = 1; + else if (op == TCPOPT_WSCALE && oplen == 3 && c->wscale == -1) + c->wscale = data[2]; + if (c->optnum++ < MODEL_NUM_OPTS) + return true; + return false; +} + static struct feature_node *vectorize(const FingerPrintResultsIPv6 *FPR) { const char * const IPV6_PROBE_NAMES[] = {"S1", "S2", "S3", "S4", "S5", "S6", "IE1", "IE2", "NS", "U1", "TECN", "T2", "T3", "T4", "T5", "T6", "T7"}; const char * const TCP_PROBE_NAMES[] = {"S1", "S2", "S3", "S4", "S5", "S6", "TECN", "T2", "T3", "T4", "T5", "T6", "T7"}; @@ -877,17 +904,9 @@ static struct feature_node *vectorize(const FingerPrintResultsIPv6 *FPR) { const TCPHeader *tcp; u16 flags; u16 mask; - unsigned int j; - int mss; - int sackok; - int wscale; probe_name = TCP_PROBE_NAMES[i]; - mss = -1; - sackok = -1; - wscale = -1; - tcp = find_tcp(resps[probe_name].getPacket()); if (tcp == NULL) { /* 49 TCP features. */ @@ -899,40 +918,17 @@ static struct feature_node *vectorize(const FingerPrintResultsIPv6 *FPR) { for (mask = 0x001; mask <= 0x800; mask <<= 1) features[idx++].value = (flags & mask) != 0; - for (j = 0; j < 16; j++) { - nping_tcp_opt_t opt; - opt = tcp->getOption(j); - if (opt.value == NULL) - break; - features[idx++].value = opt.type; - /* opt.len includes the two (type, len) bytes. */ - if (opt.type == TCPOPT_MSS && opt.len == 4 && mss == -1) - mss = ntohs(*(u16 *) opt.value); - else if (opt.type == TCPOPT_SACKOK && opt.len == 2 && sackok == -1) - sackok = 1; - else if (opt.type == TCPOPT_WSCALE && opt.len == 3 && wscale == -1) - wscale = *(u8 *) opt.value; + TCPOptions opts; + tcpopt_vectorize_ctx ctx(features, idx); + if (opts.fromTCPHeader(*tcp)) { + opts.foreachOpt(tcpopt_vectorize, &ctx); } - for (; j < 16; j++) - idx++; + idx += MODEL_NUM_OPTS * 2; - for (j = 0; j < 16; j++) { - nping_tcp_opt_t opt; - opt = tcp->getOption(j); - if (opt.value == NULL) - break; - features[idx++].value = opt.len; - } - for (; j < 16; j++) - idx++; - - features[idx++].value = mss; - features[idx++].value = sackok; - features[idx++].value = wscale; - if (mss != 0 && mss != -1) - features[idx++].value = (float)tcp->getWindow() / mss; - else - features[idx++].value = -1; + features[idx++].value = ctx.mss; + features[idx++].value = ctx.sackok; + features[idx++].value = ctx.wscale; + features[idx++].value = (ctx.mss > 0) ? (float)tcp->getWindow() / ctx.mss : -1; } /* ICMPv6 features */ for (i = 0; i < NELEMS(ICMPV6_PROBE_NAMES); i++) { diff --git a/libnetutil/TCPHeader.cc b/libnetutil/TCPHeader.cc index 009ebd93d..0c2aaf036 100644 --- a/libnetutil/TCPHeader.cc +++ b/libnetutil/TCPHeader.cc @@ -813,47 +813,6 @@ const u8 *TCPHeader::getOptions(size_t *optslen) const { return this->h.options; } /* End of getOptions() */ -struct tcpopt_atindex_ctx { - unsigned int index; - unsigned int found; - nping_tcp_opt_t result; - tcpopt_atindex_ctx() : index(0), found(0) { - memset(&result, 0, sizeof(result)); - } -}; - -static bool tcpopt_atindex(u8 op, u8 oplen, const u8 *data, void *ctx) -{ - tcpopt_atindex_ctx *args = static_cast(ctx); - if (args->index == args->found) { - args->result.type = op; - args->result.len = oplen; - args->result.value = data + 2; - return false; - } - args->found += 1; - return true; -} - -/* Returns the index-th option in the TCP header. On success it returns a - * structure filled with option information. If there is no index-th option, - * it returns a structure with st.value==NULL. Note that this function does - * not perform strict validity checking. It does check that the length claimed - * by the options does not exceed the available buffer but it does not check, - * for example, that the MSS option always contains a length of 4. Also, - * if the returned option type is TCPOPT_EOL or TCPOPT_NOOP, the len field - * would be set to zero and the "value" field should NOT be accessed, as it - * will not contain reliable information. */ -nping_tcp_opt_t TCPHeader::getOption(unsigned int index) const { - TCPOptions opts; - tcpopt_atindex_ctx ctx; - if (opts.fromTCPHeader(*this)) { - ctx.index = index; - opts.foreachOpt(tcpopt_atindex, &ctx); - } - return ctx.result; -} - /* Returns a textual representation of a TCP Options code */ const char *TCPHeader::optcode2str(u8 optcode){ diff --git a/libnetutil/TCPHeader.h b/libnetutil/TCPHeader.h index 1890482d4..adab6ea32 100644 --- a/libnetutil/TCPHeader.h +++ b/libnetutil/TCPHeader.h @@ -115,19 +115,6 @@ -/* -+--------+--------+---------+--------... -| Type | Len | Value -+--------+--------+---------+--------... -*/ -struct nping_tcp_opt { - u8 type; /* Option type code. */ - u8 len; /* Option length. */ - const u8 *value; /* Option value */ -}__attribute__((__packed__)); -typedef struct nping_tcp_opt nping_tcp_opt_t; - - class TCPHeader : public TransportLayerElement { private: @@ -252,7 +239,6 @@ class TCPHeader : public TransportLayerElement { int setOptions(const u8 *optsbuff, size_t optslen); const u8 *getOptions(size_t *optslen) const; - nping_tcp_opt_t getOption(unsigned int index) const; static const char *optcode2str(u8 optcode); }; /* End of class TCPHeader */