static enum proto_parse_status netbios_parse(struct parser *parser, struct proto_layer *parent, unsigned way, uint8_t const *packet, size_t cap_len, size_t wire_len, struct timeval const *now, proto_okfn_t *okfn) { /* Sanity checks */ if (wire_len < NETBIOS_HEADER_SIZE) return PROTO_PARSE_ERR; if (cap_len < NETBIOS_HEADER_SIZE) return PROTO_TOO_SHORT; if (! packet_is_netbios(packet, cap_len)) return PROTO_PARSE_ERR; /* Parse */ struct netbios_proto_info info; netbios_proto_info_ctor(&info, NETBIOS_HEADER_SIZE, wire_len - NETBIOS_HEADER_SIZE); struct proto_layer layer; proto_layer_ctor(&layer, parent, parser, &info.info); uint8_t const *next_packet = packet + NETBIOS_HEADER_SIZE; struct parser *subparser = proto_cifs->ops->parser_new(proto_cifs, now); if (! subparser) goto fallback; /* List of protocols above NetBios: CIFS, SMB, ... */ int err = proto_parse(subparser, parent, way, next_packet, cap_len - NETBIOS_HEADER_SIZE, wire_len - NETBIOS_HEADER_SIZE, now, okfn); parser_unref(subparser); if (err) goto fallback; return PROTO_OK; fallback: (void)proto_parse(NULL, parent, way, next_packet, cap_len - NETBIOS_HEADER_SIZE, wire_len - NETBIOS_HEADER_SIZE, now, okfn); return PROTO_OK; }
static enum proto_parse_status netbios_parse_frame(struct netbios_parser *netbios_parser, struct proto_info *parent, unsigned way, uint8_t const *packet, size_t cap_len, size_t wire_len, struct timeval const *now, size_t tot_cap_len, uint8_t const *tot_packet, size_t *pos) { if (cap_len == 0 && netbios_parser->sbuf.dir[way].cap_len == 0) { // Ignore pure gap start timeval_reset(netbios_parser->first_packet_tv + way); return PROTO_PARSE_ERR; } if (cap_len > 0 && !timeval_is_set(&netbios_parser->first_packet_tv[way])) { SLOG(LOG_DEBUG, "Set first packet ts for way %d to %s", way, timeval_2_str(now)); netbios_parser->first_packet_tv[way] = *now; } if (wire_len < NETBIOS_HEADER_SIZE + SMB_FLAG_SIZE) { streambuf_set_restart(&netbios_parser->sbuf, way, packet, NETBIOS_HEADER_SIZE + SMB_FLAG_SIZE); return PROTO_OK; } if (cap_len < NETBIOS_HEADER_SIZE + SMB_FLAG_SIZE) { SLOG(LOG_DEBUG, "Got a gap on neccessary bytes"); timeval_reset(netbios_parser->first_packet_tv + way); return PROTO_PARSE_ERR; } if (packet[0] != 0) { SLOG(LOG_DEBUG, "Expected Session message type 0x00, got 0x%"PRIx8, packet[0]); timeval_reset(netbios_parser->first_packet_tv + way); return PROTO_PARSE_ERR; } uint32_t smb_version = READ_U32N(packet + NETBIOS_HEADER_SIZE); if (smb_version != CIFS_SMB_HEADER && smb_version != CIFS_SMB2_HEADER) { static unsigned char smb_header[SMB_FLAG_SIZE] = {0xff, 0x53, 0x4d, 0x42}; static unsigned char smb2_header[SMB_FLAG_SIZE] = {0xfe, 0x53, 0x4d, 0x42}; void *res = memmem(packet + NETBIOS_HEADER_SIZE, cap_len - NETBIOS_HEADER_SIZE, &smb_header, SMB_FLAG_SIZE); if (!res) { res = memmem(packet + NETBIOS_HEADER_SIZE, cap_len - NETBIOS_HEADER_SIZE, &smb2_header, SMB_FLAG_SIZE); } if (!res) { SLOG(LOG_DEBUG, "Netbios payload does not expected header (expected %"PRIx32" or %"PRIx32")," " got %"PRIx32, CIFS_SMB_HEADER, CIFS_SMB2_HEADER, smb_version); return PROTO_PARSE_ERR; } SLOG(LOG_DEBUG, "Found a SMB header in payload, restarting there"); timeval_reset(netbios_parser->first_packet_tv + way); streambuf_set_restart(&netbios_parser->sbuf, way, res - NETBIOS_HEADER_SIZE, NETBIOS_HEADER_SIZE + SMB_FLAG_SIZE); return PROTO_OK; } uint32_t len = READ_U32N((uint32_t*) packet) & 0x00ffffff; *pos = len; size_t current_payload = wire_len - NETBIOS_HEADER_SIZE; SLOG(LOG_DEBUG, "Found netbios payload of %"PRIu32", current payload %zu", len, current_payload); if (len > current_payload) { streambuf_set_restart(&netbios_parser->sbuf, way, packet, len + NETBIOS_HEADER_SIZE); return PROTO_OK; } /* Parse */ struct netbios_proto_info info; netbios_proto_info_ctor(&info, &netbios_parser->parser, parent, NETBIOS_HEADER_SIZE, wire_len - NETBIOS_HEADER_SIZE, len, netbios_parser->first_packet_tv + way); timeval_reset(netbios_parser->first_packet_tv + way); SLOG(LOG_DEBUG, "Parsing netbios content"); uint8_t const *next_packet = packet + NETBIOS_HEADER_SIZE; if (!netbios_parser->msg_parser) { netbios_parser->msg_parser = proto_cifs->ops->parser_new(proto_cifs); } enum proto_parse_status status = PROTO_OK; if (netbios_parser->msg_parser) { status = proto_parse(netbios_parser->msg_parser, &info.info, way, next_packet, cap_len - NETBIOS_HEADER_SIZE, wire_len - NETBIOS_HEADER_SIZE, now, tot_cap_len, tot_packet); if (status == PROTO_OK) return PROTO_OK; } (void)proto_parse(NULL, &info.info, way, next_packet, cap_len - NETBIOS_HEADER_SIZE, wire_len - NETBIOS_HEADER_SIZE, now, tot_cap_len, tot_packet); return status; }