static void fcoe_proto_info_ctor(struct fcoe_proto_info *info, struct parser *parser, struct proto_info *parent, size_t packet_len, size_t payload, uint8_t version, uint8_t sof, uint8_t eof) { proto_info_ctor(&info->info, parser, parent, packet_len, payload); info->version = version; info->sof = sof; info->eof = eof; }
static void cap_proto_info_ctor(struct cap_proto_info *info, struct parser *parser, struct proto_info *parent, struct frame const *frame) { proto_info_ctor(&info->info, parser, parent, sizeof(*frame), frame->wire_len); info->dev_id = collapse_ifaces ? zero : frame->pkt_source->dev_id; info->tv = frame->tv; }
static enum proto_parse_status pg_sbuf_parse(struct parser *parser, struct proto_info *parent, unsigned way, uint8_t const *payload, size_t cap_len, size_t wire_len, struct timeval const *now, size_t tot_cap_len, uint8_t const *tot_packet) { struct pgsql_parser *pg_parser = DOWNCAST(parser, parser, pgsql_parser); // If this is the first time we are called, init c2s_way if (pg_parser->c2s_way == UNSET) { SLOG(LOG_DEBUG, "First packet, init c2s_way to %u", way); pg_parser->c2s_way = way; } // Now build the proto_info struct sql_proto_info info; proto_info_ctor(&info.info, parser, parent, wire_len, 0); info.is_query = way == pg_parser->c2s_way; info.set_values = 0; switch (pg_parser->phase) { case NONE: return pg_parse_init (pg_parser, &info, way, payload, cap_len, wire_len, now, tot_cap_len, tot_packet); case STARTUP: return pg_parse_startup(pg_parser, &info, way, payload, cap_len, wire_len, now, tot_cap_len, tot_packet); case QUERY: return pg_parse_query (pg_parser, &info, way, payload, cap_len, wire_len, now, tot_cap_len, tot_packet); case EXIT: return PROTO_PARSE_ERR; // we do not expect payload after a termination message } return PROTO_PARSE_ERR; }
static void udp_proto_info_ctor(struct udp_proto_info *info, struct parser *parser, struct proto_info *parent, size_t head_len, size_t payload, uint16_t sport, uint16_t dport) { proto_info_ctor(&info->info, parser, parent, head_len, payload); info->key.port[0] = sport; info->key.port[1] = dport; }
static void skinny_proto_info_ctor(struct skinny_proto_info *info, struct parser *parser, struct proto_info *parent, size_t head_len, size_t payload, enum skinny_msgid msg_id, uint32_t header_ver) { proto_info_ctor(&info->info, parser, parent, head_len, payload); info->set_values = 0; info->msgid = msg_id; info->header_ver = header_ver; }
static void netbios_proto_info_ctor(struct netbios_proto_info *info, struct parser *parser, struct proto_info *parent, size_t header, size_t payload, uint32_t size, struct timeval const *first_packet_tv) { proto_info_ctor(&info->info, parser, parent, header, payload); info->size = size; info->first_packet_tv = *first_packet_tv; }
static void icmpv6_proto_info_ctor(struct icmp_proto_info *info, struct parser *parser, struct proto_info *parent, size_t packet_len, uint8_t type, uint8_t code) { proto_info_ctor(&info->info, parser, parent, packet_len, 0); info->type = type; info->code = code; info->set_values = 0; // Err fields are extracted later }
static void rtp_proto_info_ctor(struct rtp_proto_info *info, struct parser *parser, struct proto_info *parent, struct rtp_hdr const *rtph, size_t head_len, size_t payload) { proto_info_ctor(&info->info, parser, parent, head_len, payload); info->payload_type = READ_U8(&rtph->flags1) & F1_PLD_TYPE_MASK; info->sync_src = READ_U32N(&rtph->ssrc); info->seq_num = READ_U16N(&rtph->seq_num); info->timestamp = READ_U32N(&rtph->timestamp); }
static void netbios_proto_info_ctor(struct netbios_proto_info *info, size_t header, size_t payload) { static struct proto_info_ops const ops = { .to_str = netbios_proto_info_2_str, }; proto_info_ctor(&info->info, &ops, header, payload); info->mode = NETBIOS_CIFS; }
static void sdp_proto_info_ctor(struct sdp_proto_info *info, size_t head_len, size_t payload) { static struct proto_info_ops ops = { .to_str = sdp_info_2_str, }; memset(info, 0, sizeof *info); proto_info_ctor(&info->info, &ops, head_len, payload); }
static void icmp_proto_info_ctor(struct icmp_proto_info *info, size_t packet_len, uint8_t type, uint8_t code) { static struct proto_info_ops ops = { .to_str = icmp_info_2_str, }; proto_info_ctor(&info->info, &ops, packet_len, 0); info->type = type; info->code = code; info->set_values = 0; // Err fields are extracted later }
static void eth_proto_info_ctor(struct eth_proto_info *info, struct parser *parser, struct proto_info *parent, size_t head_len, size_t payload, uint16_t proto, int vlan_id, struct eth_hdr const *ethhdr) { proto_info_ctor(&info->info, parser, parent, head_len, payload); info->vlan_id = collapse_vlans ? vlan_unset : vlan_id; ASSERT_COMPILE(sizeof(info->addr[0]) == sizeof(ethhdr->src)); memcpy(info->addr[0], ethhdr->src, sizeof(info->addr[0])); ASSERT_COMPILE(sizeof(info->addr[1]) == sizeof(ethhdr->dst)); memcpy(info->addr[1], ethhdr->dst, sizeof(info->addr[1])); info->protocol = proto; }
static void rtp_proto_info_ctor(struct rtp_proto_info *info, struct rtp_header const *rtph, size_t head_len, size_t payload) { static struct proto_info_ops ops = { .to_str = rtp_info_2_str, }; proto_info_ctor(&info->info, &ops, head_len, payload); info->payload_type = rtph->payload_type; info->sync_src = ntohl(rtph->ssrc); info->seq_num = ntohs(rtph->seq_num); info->timestamp = ntohl(rtph->timestamp); }
static void tcp_proto_info_ctor(struct tcp_proto_info *info, struct parser *parser, struct proto_info *parent, size_t head_len, size_t payload, uint16_t sport, uint16_t dport, struct tcp_hdr const *tcphdr) { proto_info_ctor(&info->info, parser, parent, head_len, payload); info->key.port[0] = sport; info->key.port[1] = dport; uint8_t const flags = READ_U8(&tcphdr->flags); info->syn = !!(flags & TCP_SYN_MASK); info->ack = !!(flags & TCP_ACK_MASK); info->rst = !!(flags & TCP_RST_MASK); info->fin = !!(flags & TCP_FIN_MASK); info->urg = !!(flags & TCP_URG_MASK); info->psh = !!(flags & TCP_PSH_MASK); // to_srv set later from tcp_subparser info->window = READ_U16N(&tcphdr->window); info->urg_ptr = READ_U16N(&tcphdr->urg_ptr); info->ack_num = READ_U32N(&tcphdr->ack_seq); info->seq_num = READ_U32N(&tcphdr->seq_num); info->rel_seq_num = 0U; info->set_values = 0; // options will be set later info->nb_options = 0; }
static enum proto_parse_status rpc_parse(struct parser *parser, struct proto_info *parent, unsigned unused_ way, uint8_t const *packet, size_t cap_len, size_t wire_len, struct timeval const unused_ *now, size_t unused_ tot_cap_len, uint8_t const unused_ *tot_packet) { struct cursor cursor; cursor_ctor(&cursor, packet, cap_len); if (wire_len < 12) return PROTO_PARSE_ERR; if (cap_len < 12) return PROTO_TOO_SHORT; ASSIGN_INFO_OPT(tcp, parent); struct rpc_proto_info info; proto_info_ctor(&info.info, parser, parent, wire_len, 0); if (tcp) cursor_drop(&cursor, 4); // Drop fragment header cursor_drop(&cursor, 4); info.msg_type = cursor_read_u32n(&cursor); enum proto_parse_status status = PROTO_OK; switch (info.msg_type) { case RPC_CALL: if (wire_len < 40) return PROTO_PARSE_ERR; status = parse_rpc_call(&cursor, &info); break; case RPC_REPLY: status = parse_rpc_reply(&cursor, &info); break; default: return PROTO_PARSE_ERR; } SLOG(LOG_DEBUG, "Parsed rpc status %s, %s", proto_parse_status_2_str(status), rpc_info_2_str(&info.info)); if (status == PROTO_OK) { // TODO We can have a nfs payload (void)proto_parse(NULL, &info.info, way, NULL, 0, 0, now, tot_cap_len, tot_packet); } return status; }
static void sip_proto_info_ctor(struct sip_proto_info *info, struct parser *parser, struct proto_info *parent, size_t head_len, size_t payload) { proto_info_ctor(&info->info, parser, parent, head_len, payload); }
static void sdp_proto_info_ctor(struct sdp_proto_info *info, struct parser *parser, struct proto_info *parent, size_t head_len, size_t payload) { memset(info, 0, sizeof *info); proto_info_ctor(&info->info, parser, parent, head_len, payload); }
static enum proto_parse_status tns_sbuf_parse(struct parser *parser, struct proto_info *parent, unsigned way, uint8_t const *payload, size_t cap_len, size_t wire_len, struct timeval const *now, size_t tot_cap_len, uint8_t const *tot_packet) { struct tns_parser *tns_parser = DOWNCAST(parser, parser, tns_parser); // If this is the first time we are called, init c2s_way if (tns_parser->c2s_way == UNSET) { ASSIGN_INFO_OPT(tcp, parent); if (tcp) tns_parser->c2s_way = tcp->to_srv ? way : !way; else tns_parser->c2s_way = way; SLOG(LOG_DEBUG, "First packet, init c2s_way to %u", tns_parser->c2s_way); } if (!timeval_is_set(&tns_parser->first_ts)) { SLOG(LOG_DEBUG, "Setting first ts to %s", timeval_2_str(now)); tns_parser->first_ts = *now; } // Now build the proto_info struct sql_proto_info info; SLOG(LOG_DEBUG, "Constructing with %zu", wire_len); proto_info_ctor(&info.info, parser, parent, wire_len, 0); info.is_query = way == tns_parser->c2s_way; info.set_values = 0; info.msg_type = SQL_UNKNOWN; info.first_ts = tns_parser->first_ts; // and try to read a TNS PDN struct cursor cursor; cursor_ctor(&cursor, payload, cap_len); uint8_t const *const msg_start = cursor.head; size_t pdu_len = 0; enum tns_type pdu_type = 0; enum proto_parse_status status = cursor_read_tns_hdr(&cursor, &pdu_len, &pdu_type, wire_len); if (status == PROTO_PARSE_ERR) { SLOG(LOG_DEBUG, "Error while parsing tns header"); timeval_reset(&tns_parser->first_ts); return status; } bool has_gap = cap_len < wire_len; if (status == PROTO_TOO_SHORT && !has_gap) { proto_parse(NULL, parent, way, NULL, 0, 0, now, tot_cap_len, tot_packet); streambuf_set_restart(&tns_parser->sbuf, way, msg_start, pdu_len > 0 ? pdu_len : 8); SLOG(LOG_DEBUG, "Payload too short for parsing message, will restart @ %zu", tns_parser->sbuf.dir->restart_offset); return PROTO_OK; } switch (pdu_type) { case TNS_CONNECT: info.msg_type = SQL_STARTUP; status = tns_parse_connect(tns_parser, &info, &cursor); break; case TNS_ACCEPT: info.msg_type = SQL_STARTUP; status = tns_parse_accept(tns_parser, &info, &cursor); break; case TNS_DATA: status = tns_parse_data(tns_parser, &info, &cursor, way); break; case TNS_RESEND: SLOG(LOG_DEBUG, "Got a tns resend"); break; case TNS_REFUSE: case TNS_REDIRECT: case TNS_ABORT: case TNS_MARKER: case TNS_ATTENTION: case TNS_CONTROL: default: // A type we do not handle, skip the PDU break; } // We advertize the tns pdu even if we don't know how to parse it if (status != PROTO_OK) SLOG(LOG_DEBUG, "Error parsing tns packet"); timeval_reset(&tns_parser->first_ts); return proto_parse(NULL, &info.info, way, NULL, 0, 0, now, tot_cap_len, tot_packet); }
static enum proto_parse_status dhcp_parse(struct parser *parser, struct proto_info *parent, unsigned way, uint8_t const *payload, size_t cap_len, size_t wire_len, struct timeval const *now, size_t tot_cap_len, uint8_t const *tot_packet) { struct dhcp const *dhcp = (struct dhcp *)payload; // Sanity Checks // Check that we have at least the size of an DHCP packet for IP protocol if (wire_len < sizeof(*dhcp)) return PROTO_PARSE_ERR; // And that we have enough data to parse it if (cap_len < sizeof(*dhcp)) return PROTO_TOO_SHORT; if (0 != memcmp(dhcp->cookie, &magic_cookie, sizeof(magic_cookie))) { SLOG(LOG_DEBUG, "Bad magic Cookie"); return PROTO_PARSE_ERR; } struct dhcp_proto_info info; proto_info_ctor(&info.info, parser, parent, wire_len, 0); info.opcode = READ_U8(&dhcp->op); if (info.opcode != BOOTP_REQUEST && info.opcode != BOOTP_REPLY) { SLOG(LOG_DEBUG, "Unknown DHCP opcode (%u)", info.opcode); return PROTO_PARSE_ERR; } uint8_t const hlen = READ_U8(&dhcp->hlen); if (hlen > sizeof(dhcp->chaddr)) { SLOG(LOG_DEBUG, "Bad hlen in DHCP (%u)", hlen); return PROTO_PARSE_ERR; } info.xid = READ_U32N(&dhcp->xid); info.set_values = 0; uint32_t const addr = READ_U32(&dhcp->yiaddr); if (addr) { info.set_values |= DHCP_CLIENT_SET; ip_addr_ctor_from_ip4(&info.client, addr); } uint8_t const htype = READ_U8(&dhcp->htype); info.hw_addr_is_eth = htype == 1; if (info.hw_addr_is_eth) { if (hlen != sizeof(info.client_mac)) { SLOG(LOG_DEBUG, "Bad hlen (%u) for Eth type", hlen); return PROTO_PARSE_ERR; } memcpy(info.client_mac, dhcp->chaddr, sizeof(info.client_mac)); } else { memset(info.client_mac, 0, sizeof(info.client_mac)); } memcpy(info.server_name, dhcp->sname, sizeof(info.server_name)); SLOG(LOG_DEBUG, "New DHCP %s", dhcp_opcode_2_str(info.opcode)); // parse options info.msg_type = 0; // mandatory struct cursor c; cursor_ctor(&c, dhcp->options, cap_len - offsetof(struct dhcp, options)); while (c.cap_len >= 2) { uint8_t const type = cursor_read_u8(&c); uint8_t const len = cursor_read_u8(&c); if (c.cap_len < len) { SLOG(LOG_DEBUG, "Cannot read options"); return PROTO_PARSE_ERR; } switch (type) { case 53: // msg type if (len != 1) { SLOG(LOG_DEBUG, "Bad length (%"PRIu8") for msg type DHCP option", len); return PROTO_PARSE_ERR; } info.msg_type = cursor_read_u8(&c); if (info.msg_type > DHCP_INFORM) { SLOG(LOG_DEBUG, "Bad DHCP msg type (%u)", info.msg_type); return PROTO_PARSE_ERR; } break; default: cursor_drop(&c, len); break; } } if (0 == info.msg_type) { // not found SLOG(LOG_DEBUG, "DHCP msg without msg type"); return PROTO_PARSE_ERR; } return proto_parse(NULL, &info.info, way, NULL, 0, 0, now, tot_cap_len, tot_packet); }
static enum proto_parse_status tds_sbuf_parse(struct parser *parser, struct proto_info *parent, unsigned way, uint8_t const *payload, size_t cap_len, size_t wire_len, struct timeval const *now, size_t tot_cap_len, uint8_t const *tot_packet) { struct tds_parser *tds_parser = DOWNCAST(parser, parser, tds_parser); SLOG(LOG_DEBUG, "Got tds packet, data_left %zu, way %d", tds_parser->data_left, way); bool has_gap = wire_len > cap_len; if (tds_parser->had_gap && tds_parser->data_left > 0) { tds_parser->data_left = wire_len > tds_parser->data_left ? 0 : tds_parser->data_left - wire_len; SLOG(LOG_DEBUG, "Discard tds with gap, data_left %zu...", tds_parser->data_left); return PROTO_OK; } tds_parser->had_gap = has_gap; struct tds_header tds_header; bool unknown_token = false; struct cursor cursor; cursor_ctor(&cursor, payload, cap_len); enum proto_parse_status status = tds_parse_header(&cursor, &tds_header, &unknown_token); if (status != PROTO_OK) { // We have an unknown token if the payload is encrypted after a ssl handshake // It is valid but we don't know how to parse it yet // TODO It would be better if we knew the values of the encryption options exchanged in prelogin messages if (unknown_token) return PROTO_OK; return status; } // Sanity check on pkt number if (tds_header.pkt_number > 1 && ((tds_parser->pkt_number + 1) != tds_header.pkt_number)) { SLOG(LOG_DEBUG, "Expected pkt number %"PRIu8", got %"PRIu8"", tds_parser->pkt_number + 1, tds_header.pkt_number); tds_parser->pkt_number = 1; return PROTO_OK; } else if (tds_header.pkt_number <= 1 || (tds_header.status & TDS_EOM)) { SLOG(LOG_DEBUG, "Reset pkt number from %"PRIu8"", tds_parser->pkt_number); tds_parser->pkt_number = 1; } // Sanity check on channels if (tds_parser->channels[way] && (tds_parser->channels[way] != tds_header.channel)) { SLOG(LOG_DEBUG, "Expected channel %"PRIu16", got channel %"PRIu16"", tds_parser->channels[way], tds_header.channel); return PROTO_OK; } if (wire_len > tds_header.len) { SLOG(LOG_DEBUG, "Wire len %zu unexpected (> %zu), considering a gap", wire_len, tds_header.len); has_gap = true; } tds_parser->data_left = wire_len >= tds_header.len ? 0 : tds_header.len - wire_len; SLOG(LOG_DEBUG, "Data left after wire %zu", tds_parser->data_left); if (tds_parser->data_left > 0 && !has_gap) { SLOG(LOG_DEBUG, "Incomplete tds packet, buffering it"); streambuf_set_restart(&tds_parser->sbuf, way, payload, true); return PROTO_OK; } struct tds_proto_info info; proto_info_ctor(&info.info, parser, parent, TDS_PKT_HDR_LEN, tds_header.len - TDS_PKT_HDR_LEN); info.type = tds_header.type; info.status = tds_header.status; info.length = tds_header.len; if (tds_header.channel > 0) { SLOG(LOG_DEBUG, "Saving channel %"PRIu16"", tds_header.channel); tds_parser->channels[way] = tds_header.channel; } SLOG(LOG_DEBUG, "Saving pkt number %"PRIu8"", tds_header.pkt_number); tds_parser->pkt_number = tds_header.pkt_number; SLOG(LOG_DEBUG, "Parsing %s", tds_header_2_str(&tds_header)); if (! tds_parser->msg_parser) { SLOG(LOG_DEBUG, "Building new tds_msg_parser"); tds_parser->msg_parser = proto_tds_msg->ops->parser_new(proto_tds_msg); } if (tds_parser->msg_parser) { proto_parse(tds_parser->msg_parser, &info.info, way, cursor.head, cursor.cap_len, wire_len - TDS_PKT_HDR_LEN, now, tot_cap_len, tot_packet); } // Advertise this packet if it was not done already return proto_parse(NULL, &info.info, way, payload, cap_len, wire_len, now, tot_cap_len, tot_packet); }
static void cifs_proto_info_ctor(struct cifs_proto_info *info, struct parser *parser, struct proto_info *parent, size_t header, size_t payload, struct cifs_hdr const * cifshdr) { proto_info_ctor(&info->info, parser, parent, header, payload); info->command = READ_U8(&cifshdr->command); info->status = READ_U32(&cifshdr->status); }
static enum proto_parse_status tns_sbuf_parse(struct parser *parser, struct proto_info *parent, unsigned way, uint8_t const *payload, size_t cap_len, size_t wire_len, struct timeval const *now, size_t tot_cap_len, uint8_t const *tot_packet) { struct tns_parser *tns_parser = DOWNCAST(parser, parser, tns_parser); // If this is the first time we are called, init c2s_way if (tns_parser->c2s_way == UNSET) { tns_parser->c2s_way = way; SLOG(LOG_DEBUG, "First packet, init c2s_way to %u", tns_parser->c2s_way); } // Now build the proto_info struct sql_proto_info info; proto_info_ctor(&info.info, parser, parent, wire_len, 0); info.is_query = way == tns_parser->c2s_way; info.set_values = 0; info.msg_type = SQL_UNKNOWN; // and try to read a TNS PDN struct cursor cursor; cursor_ctor(&cursor, payload, cap_len); uint8_t const *const msg_start = cursor.head; size_t pdu_len; enum tns_type pdu_type; enum proto_parse_status status = cursor_read_tns_hdr(&cursor, &pdu_len, &pdu_type); if (status == PROTO_PARSE_ERR) return status; if (status == PROTO_TOO_SHORT) { streambuf_set_restart(&tns_parser->sbuf, way, msg_start, true); SLOG(LOG_DEBUG, "Payload too short for parsing message, will restart @ %zu", tns_parser->sbuf.dir->restart_offset); return PROTO_OK; } assert(cursor.cap_len >= pdu_len); // We have the whole msg ready to be read struct cursor msg; cursor_ctor(&msg, cursor.head, pdu_len); switch (pdu_type) { case TNS_CONNECT: info.msg_type = SQL_STARTUP; status = tns_parse_connect(tns_parser, &info, &msg); break; case TNS_ACCEPT: info.msg_type = SQL_STARTUP; status = tns_parse_accept(tns_parser, &info, &msg); break; case TNS_DATA: status = tns_parse_data(tns_parser, &info, &msg, way); break; case TNS_RESEND: SLOG(LOG_DEBUG, "Got a tns resend"); break; case TNS_REFUSE: case TNS_REDIRECT: case TNS_ABORT: case TNS_MARKER: case TNS_ATTENTION: case TNS_CONTROL: default: // A type we do not handle, skip the PDU break; } // We advertize the tns pdu even if we don't know how to parse it if (status != PROTO_OK) SLOG(LOG_DEBUG, "Error parsing tns packet"); return proto_parse(NULL, &info.info, way, NULL, 0, 0, now, tot_cap_len, tot_packet); }
static enum proto_parse_status tds_sbuf_parse(struct parser *parser, struct proto_info *parent, unsigned way, uint8_t const *payload, size_t cap_len, size_t wire_len, struct timeval const *now, size_t tot_cap_len, uint8_t const *tot_packet) { if (cap_len == 0 && wire_len > 0) return PROTO_TOO_SHORT; // We do not know how to handle pure gaps struct tds_parser *tds_parser = DOWNCAST(parser, parser, tds_parser); SLOG(LOG_DEBUG, "Got tds packet, data_left %zu, way %d", tds_parser->data_left, way); bool has_gap = wire_len > cap_len; if (tds_parser->had_gap && tds_parser->data_left > 0) { tds_parser->data_left = wire_len > tds_parser->data_left ? 0 : tds_parser->data_left - wire_len; SLOG(LOG_DEBUG, "Discard tds with gap, data_left %zu...", tds_parser->data_left); timeval_reset(&tds_parser->first_ts); return PROTO_OK; } tds_parser->had_gap = has_gap; struct tds_header tds_header; bool unknown_token = false; struct cursor cursor; enum proto_parse_status status; cursor_ctor(&cursor, payload, cap_len); struct smp_header smp_header = {.length = 0}; if (PROTO_OK != (status = tds_parse_smp_header(&cursor, &smp_header))) return status; if (smp_header.length) { SLOG(LOG_DEBUG, "Smp header: %s", smp_header_2_str(&smp_header)); wire_len -= SMP_PKT_HDR_LEN; cap_len -= SMP_PKT_HDR_LEN; if (smp_header.flags & SMP_ACK) return PROTO_OK; } status = tds_parse_header(&cursor, &tds_header, &unknown_token); if (status != PROTO_OK) { // We have an unknown token if the payload is encrypted after a ssl handshake // It is valid but we don't know how to parse it yet // TODO It would be better if we knew the values of the encryption options exchanged in prelogin messages timeval_reset(&tds_parser->first_ts); if (unknown_token) return PROTO_OK; return status; } // Sanity check on pkt number if (tds_header.pkt_number > 1 && ((tds_parser->pkt_number + 1) != tds_header.pkt_number)) { SLOG(LOG_DEBUG, "Expected pkt number %"PRIu8", got %"PRIu8"", tds_parser->pkt_number + 1, tds_header.pkt_number); tds_parser->pkt_number = 1; timeval_reset(&tds_parser->first_ts); return PROTO_PARSE_ERR; } else if (tds_header.pkt_number <= 1) { SLOG(LOG_DEBUG, "Reset pkt number from %"PRIu8"", tds_parser->pkt_number); tds_parser->pkt_number = 1; } // Sanity check on channels if (tds_parser->channels[way] && (tds_parser->channels[way] != tds_header.channel)) { SLOG(LOG_DEBUG, "Expected channel %"PRIu16", got channel %"PRIu16"", tds_parser->channels[way], tds_header.channel); timeval_reset(&tds_parser->first_ts); return PROTO_PARSE_ERR; } if (wire_len > tds_header.len) { SLOG(LOG_DEBUG, "Wire len %zu unexpected (> %zu), considering a gap", wire_len, tds_header.len); has_gap = true; } tds_parser->data_left = wire_len >= tds_header.len ? 0 : tds_header.len - wire_len; SLOG(LOG_DEBUG, "Data left after wire %zu", tds_parser->data_left); if (tds_parser->data_left > 0 && !has_gap) { SLOG(LOG_DEBUG, "Incomplete tds packet, buffering it"); if (!timeval_is_set(&tds_parser->first_ts)) { SLOG(LOG_DEBUG, "Setting first ts to %s for way %d", timeval_2_str(now), way); tds_parser->first_ts = *now; } proto_parse(NULL, parent, way, NULL, 0, 0, now, tot_cap_len, tot_packet); streambuf_set_restart(&tds_parser->sbuf, way, payload, tds_header.len); return PROTO_OK; } // We have a buffered tds packet at this point if (!timeval_is_set(&tds_parser->first_ts)) { SLOG(LOG_DEBUG, "Setting first ts to %s for way %d since it is not setted", timeval_2_str(now), way); tds_parser->first_ts = *now; } struct tds_proto_info info; proto_info_ctor(&info.info, parser, parent, TDS_PKT_HDR_LEN, tds_header.len - TDS_PKT_HDR_LEN); info.type = tds_header.type; info.status = tds_header.status; info.length = tds_header.len; info.first_ts = tds_parser->first_ts; info.has_gap = has_gap; if (tds_header.channel > 0) { SLOG(LOG_DEBUG, "Saving channel %"PRIu16"", tds_header.channel); tds_parser->channels[way] = tds_header.channel; } SLOG(LOG_DEBUG, "Saving pkt number %"PRIu8"", tds_header.pkt_number); tds_parser->pkt_number = tds_header.pkt_number; SLOG(LOG_DEBUG, "Parsing %s", tds_header_2_str(&tds_header)); if (! tds_parser->msg_parser) { SLOG(LOG_DEBUG, "Building new tds_msg_parser"); tds_parser->msg_parser = proto_tds_msg->ops->parser_new(proto_tds_msg); if (!tds_parser->msg_parser) { SLOG(LOG_INFO, "Could not build tds msg parser"); return PROTO_PARSE_ERR; } } if (tds_header.status & TDS_EOM) { SLOG(LOG_DEBUG, "Reset pkt number from %"PRIu8" since we parsed an EOM", tds_parser->pkt_number); tds_parser->pkt_number = 1; } status = proto_parse(tds_parser->msg_parser, &info.info, way, cursor.head, cursor.cap_len, wire_len - TDS_PKT_HDR_LEN, now, tot_cap_len, tot_packet); if (status != PROTO_OK) { SLOG(LOG_INFO, "Tds msg parse failed, returning %s", proto_parse_status_2_str(status)); return status; } timeval_reset(&tds_parser->first_ts); // Advertise this packet if it was not done already return proto_parse(NULL, &info.info, way, payload, cap_len, wire_len, now, tot_cap_len, tot_packet); } static enum proto_parse_status tds_parse(struct parser *parser, struct proto_info *parent, unsigned way, uint8_t const *payload, size_t cap_len, size_t wire_len, struct timeval const *now, size_t tot_cap_len, uint8_t const *tot_packet) { struct tds_parser *tds_parser = DOWNCAST(parser, parser, tds_parser); enum proto_parse_status const status = streambuf_add(&tds_parser->sbuf, parser, parent, way, payload, cap_len, wire_len, now, tot_cap_len, tot_packet); return status; } /* * Construction/Destruction */ static struct proto proto_tds_; struct proto *proto_tds = &proto_tds_; static struct port_muxer tds_tcp_muxer; void tds_init(void) { log_category_proto_tds_init(); static struct proto_ops const ops = { .parse = tds_parse, .parser_new = tds_parser_new, .parser_del = tds_parser_del, .info_2_str = tds_info_2_str, .info_addr = tds_info_addr }; proto_ctor(&proto_tds_, &ops, "TDS", PROTO_CODE_TDS); port_muxer_ctor(&tds_tcp_muxer, &tcp_port_muxers, 1433, 1433, proto_tds); }