Пример #1
0
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;
}
Пример #2
0
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;
}
Пример #3
0
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;
}
Пример #4
0
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;
}
Пример #5
0
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;
}
Пример #6
0
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;
}
Пример #7
0
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
}
Пример #8
0
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);
}
Пример #9
0
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;
}
Пример #10
0
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);
}
Пример #11
0
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
}
Пример #12
0
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;
}
Пример #13
0
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);
}
Пример #14
0
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;
}
Пример #15
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;
}
Пример #16
0
Файл: sip.c Проект: rixed/junkie
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);
}
Пример #17
0
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);
}
Пример #18
0
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);
}
Пример #19
0
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);
}
Пример #20
0
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);
}
Пример #21
0
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);
}
Пример #22
0
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);
}
Пример #23
0
Файл: tds.c Проект: iHaD/junkie
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);
}