static int analyzer_smtp_event_process_begin(struct event *evt, void *obj, struct proto_process_stack *stack, unsigned int stack_index) { struct analyzer *analyzer = obj; struct analyzer_smtp_priv *apriv = analyzer->priv; struct proto_process_stack *s = &stack[stack_index]; if (!s->ce) return POM_ERR; // Only process stuff if we have the DATA event or if we already have an event struct event_reg *evt_reg = event_get_reg(evt); struct data *evt_data = event_get_data(evt); struct analyzer_smtp_ce_priv *cpriv = conntrack_get_priv(s->ce, analyzer); // It's expected that an SMTP connection will always contain at least one message // So we always create the cpriv and event, no matter what if (!cpriv) { cpriv = malloc(sizeof(struct analyzer_smtp_ce_priv)); if (!cpriv) { pom_oom(sizeof(struct analyzer_smtp_ce_priv)); return POM_ERR; } memset(cpriv, 0, sizeof(struct analyzer_smtp_ce_priv)); if (conntrack_add_priv(s->ce, analyzer, cpriv, analyzer_smtp_ce_priv_cleanup) != POM_OK) { free(cpriv); return POM_ERR; } } if (!cpriv->evt_msg) { cpriv->evt_msg = event_alloc(apriv->evt_msg); if (!cpriv->evt_msg) return POM_ERR; } struct data *msg_data = event_get_data(cpriv->evt_msg); if (evt_reg == apriv->evt_cmd) { if (!cpriv->common_data_fetched) analyzer_smtp_event_fetch_common_data(cpriv, stack, stack_index, POM_DIR_REVERSE(s->direction)); // Process commands // A message was being transmitted and we recevied a new command if (event_is_started(cpriv->evt_msg)) { event_process_end(cpriv->evt_msg); cpriv->evt_msg = NULL; } char *cmd = PTYPE_STRING_GETVAL(evt_data[proto_smtp_cmd_name].value); if (!cmd) return POM_OK; char *arg = PTYPE_STRING_GETVAL(evt_data[proto_smtp_cmd_arg].value); if (arg) { while (*arg == ' ') arg++; } if (!strcasecmp(cmd, "MAIL")) { if (strncasecmp(arg, "FROM:", strlen("FROM:"))) { pomlog(POMLOG_DEBUG "Unparseable MAIL command"); return POM_OK; } arg += strlen("FROM:"); while (*arg == ' ') arg++; if (*arg == '<') arg++; size_t len; char *end = strchr(arg, '>'); if (end) len = end - arg; else len = strlen(arg); PTYPE_STRING_SETVAL_N(msg_data[analyzer_smtp_msg_from].value, arg, len); data_set(msg_data[analyzer_smtp_msg_from]); cpriv->last_cmd = analyzer_smtp_last_cmd_mail_from; } else if (!strcasecmp(cmd, "RCPT")) { if (strncasecmp(arg, "TO:", strlen("TO:"))) { pomlog(POMLOG_DEBUG "Unparseable RCPT command"); return POM_OK; } arg += strlen("TO:"); while (*arg == ' ') arg++; if (*arg == '<') arg++; size_t len; char *end = strchr(arg, '>'); if (end) len = end - arg; else len = strlen(arg); struct ptype *to = ptype_alloc("string"); if (!to) return POM_ERR; PTYPE_STRING_SETVAL_N(to, arg, len); if (data_item_add_ptype(msg_data, analyzer_smtp_msg_to, strdup("to"), to) != POM_OK) { ptype_cleanup(to); return POM_ERR; } cpriv->last_cmd = analyzer_smtp_last_cmd_rcpt_to; } else if (!strcasecmp(cmd, "DATA")) { cpriv->last_cmd = analyzer_smtp_last_cmd_data; if (!event_is_started(cpriv->evt_msg)) { analyzer_smtp_event_fill_common_data(cpriv, msg_data); event_process_begin(cpriv->evt_msg, stack, stack_index, event_get_timestamp(evt)); } else { pomlog(POMLOG_DEBUG "Message event already started !"); } } else if (!strcasecmp(cmd, "RSET")) { // Cleanup the event event_cleanup(cpriv->evt_msg); cpriv->evt_msg = NULL; cpriv->last_cmd = analyzer_smtp_last_cmd_other; } else if (!strcasecmp(cmd, "HELO") || !strcasecmp(cmd, "EHLO")) { if (cpriv->client_hello) { pomlog(POMLOG_DEBUG "We already have a client hello !"); free(cpriv->client_hello); } cpriv->client_hello = strdup(arg); if (!cpriv->client_hello) { pom_oom(strlen(arg) + 1); return POM_ERR; } cpriv->last_cmd = analyzer_smtp_last_cmd_other; } else if (!strcasecmp(cmd, "AUTH")) { if (!strncasecmp(arg, "PLAIN", strlen("PLAIN"))) { arg += strlen("PLAIN"); while (*arg == ' ') arg++; if (cpriv->evt_auth) { event_process_end(cpriv->evt_auth); cpriv->evt_auth = NULL; } if (strlen(arg)) { if (analyzer_smtp_parse_auth_plain(apriv, cpriv, arg) == POM_OK) { event_process_begin(cpriv->evt_auth, stack, stack_index, event_get_timestamp(evt)); cpriv->last_cmd = analyzer_smtp_last_cmd_auth_plain_creds; } } else { cpriv->last_cmd = analyzer_smtp_last_cmd_auth_plain; } } else if (!strncasecmp(arg, "LOGIN", strlen("LOGIN"))) { arg += strlen("LOGIN"); while (*arg == ' ') arg++; if (cpriv->evt_auth) { event_process_end(cpriv->evt_auth); cpriv->evt_auth = NULL; } cpriv->evt_auth = event_alloc(apriv->evt_auth); if (!cpriv->evt_auth) return POM_ERR; struct data *auth_data = event_get_data(cpriv->evt_auth); analyzer_smtp_event_fill_common_data(cpriv, auth_data); // Set the authentication type PTYPE_STRING_SETVAL(auth_data[analyzer_smtp_auth_type].value, "LOGIN"); data_set(auth_data[analyzer_smtp_auth_type]); if (strlen(arg)) { char *username = NULL; size_t out_len = 0; struct ptype *username_pt = NULL; if (decoder_decode_simple("base64", arg, strlen(arg), &username, &out_len) == POM_OK) { username_pt = ptype_alloc("string"); if (username_pt) { PTYPE_STRING_SETVAL_P(username_pt, username); if (data_item_add_ptype(auth_data, analyzer_smtp_auth_params, strdup("username"), username_pt) != POM_OK) { ptype_cleanup(username_pt); event_cleanup(cpriv->evt_auth); cpriv->evt_auth = NULL; username_pt = NULL; } } else { free(username); } } if (!username_pt) { cpriv->last_cmd = analyzer_smtp_last_cmd_other; event_process_begin(cpriv->evt_auth, stack, stack_index, event_get_timestamp(evt)); } } else { cpriv->last_cmd = analyzer_smtp_last_cmd_auth_login; } } } else if (cpriv->last_cmd == analyzer_smtp_last_cmd_auth_plain) { // We are expecting the credentials right now if (analyzer_smtp_parse_auth_plain(apriv, cpriv, cmd) == POM_OK) { event_process_begin(cpriv->evt_auth, stack, stack_index, event_get_timestamp(evt)); cpriv->last_cmd = analyzer_smtp_last_cmd_auth_plain_creds; } else { cpriv->last_cmd = analyzer_smtp_last_cmd_other; } } else if (cpriv->last_cmd == analyzer_smtp_last_cmd_auth_login) { char *username = NULL; size_t out_len = 0; struct ptype *username_pt = NULL; if (decoder_decode_simple("base64", cmd, strlen(cmd), &username, &out_len) == POM_OK) { username_pt = ptype_alloc("string"); if (username_pt) { PTYPE_STRING_SETVAL_P(username_pt, username); struct data *auth_data = event_get_data(cpriv->evt_auth); if (data_item_add_ptype(auth_data, analyzer_smtp_auth_params, strdup("username"), username_pt) != POM_OK) { ptype_cleanup(username_pt); event_process_end(cpriv->evt_auth); cpriv->evt_auth = NULL; username_pt = NULL; } } else { free(username); } } if (!username_pt) { cpriv->last_cmd = analyzer_smtp_last_cmd_other; } else { event_process_begin(cpriv->evt_auth, stack, stack_index, event_get_timestamp(evt)); cpriv->last_cmd = analyzer_smtp_last_cmd_auth_login_user; } } else if (cpriv->last_cmd == analyzer_smtp_last_cmd_auth_login_user) { char *password = NULL; size_t out_len = 0; struct ptype *password_pt = NULL; if (decoder_decode_simple("base64", cmd, strlen(cmd), &password, &out_len) == POM_OK) { password_pt = ptype_alloc("string"); if (password_pt) { PTYPE_STRING_SETVAL_P(password_pt, password); struct data *auth_data = event_get_data(cpriv->evt_auth); if (data_item_add_ptype(auth_data, analyzer_smtp_auth_params, strdup("password"), password_pt) != POM_OK) { ptype_cleanup(password_pt); event_process_end(cpriv->evt_auth); cpriv->evt_auth = NULL; password_pt = NULL; } } else { free(password); } } if (!password_pt) { cpriv->last_cmd = analyzer_smtp_last_cmd_other; } else { cpriv->last_cmd = analyzer_smtp_last_cmd_auth_login_pass; } } else { cpriv->last_cmd = analyzer_smtp_last_cmd_other; } } else if (evt_reg == apriv->evt_reply) { if (!cpriv->common_data_fetched) analyzer_smtp_event_fetch_common_data(cpriv, stack, stack_index, s->direction); // Process replies uint16_t code = *PTYPE_UINT16_GETVAL(evt_data[proto_smtp_reply_code].value); switch (cpriv->last_cmd) { default: case analyzer_smtp_last_cmd_other: if (code == 220 && evt_data[proto_smtp_reply_text].items && evt_data[proto_smtp_reply_text].items->value) { // STARTTLS returns 220 as well so ignore extra code 220 if (!cpriv->server_hello) { char *helo = PTYPE_STRING_GETVAL(evt_data[proto_smtp_reply_text].items->value); cpriv->server_hello = strdup(helo); if (!cpriv->server_hello) { pom_oom(strlen(helo) + 1); return POM_ERR; } } } break; case analyzer_smtp_last_cmd_mail_from: if (code != 250) { // FROM is invalid data_unset(msg_data[analyzer_smtp_msg_from]); } break; case analyzer_smtp_last_cmd_rcpt_to: // For now just don't do anything // It's best to keep a destination in there even if it's invalid or denied break; case analyzer_smtp_last_cmd_data: if (code == 354) { // The message is starting, keep last_cmd intact return POM_OK; } // Message is over (if ever transmited) if (event_is_started(cpriv->evt_msg)) { struct data *msg_data = event_get_data(cpriv->evt_msg); PTYPE_UINT16_SETVAL(msg_data[analyzer_smtp_msg_result].value, code); data_set(msg_data[analyzer_smtp_msg_result]); event_process_end(cpriv->evt_msg); cpriv->evt_msg = NULL; } break; case analyzer_smtp_last_cmd_auth_plain: case analyzer_smtp_last_cmd_auth_login: case analyzer_smtp_last_cmd_auth_login_user: // Check if authentication phase can continue if (code == 334) { // Don't reset cpriv->last_cmd return POM_OK; } else { struct data *evt_data = event_get_data(cpriv->evt_auth); PTYPE_BOOL_SETVAL(evt_data[analyzer_smtp_auth_success].value, 0); data_set(evt_data[analyzer_smtp_auth_success]); event_process_end(cpriv->evt_auth); cpriv->evt_auth = NULL; } break; case analyzer_smtp_last_cmd_auth_plain_creds: case analyzer_smtp_last_cmd_auth_login_pass: { // We just processed the credentials struct data *auth_data = event_get_data(cpriv->evt_auth); char success = 0; if (code == 235) success = 1; PTYPE_BOOL_SETVAL(auth_data[analyzer_smtp_auth_success].value, success); data_set(auth_data[analyzer_smtp_auth_success]); event_process_end(cpriv->evt_auth); cpriv->evt_auth = NULL; break; } } cpriv->last_cmd = analyzer_smtp_last_cmd_other; } return POM_OK; }
static int analyzer_rtp_pload_process(void *obj, struct packet *p, struct proto_process_stack *stack, unsigned int stack_index) { struct analyzer *analyzer = obj; struct analyzer_rtp_priv *priv = analyzer->priv; struct proto_process_stack *pload_stack = &stack[stack_index]; struct proto_process_stack *s = &stack[stack_index - 1]; if (!s->ce) return POM_ERR; struct analyzer_rtp_ce_priv *cp = conntrack_get_priv(s->ce, obj); if (!cp) { cp = malloc(sizeof(struct analyzer_rtp_ce_priv)); if (!cp) { pom_oom(sizeof(struct analyzer_rtp_ce_priv)); return POM_ERR; } memset(cp, 0, sizeof(struct analyzer_rtp_ce_priv)); if (conntrack_add_priv(s->ce, obj, cp, analyzer_rtp_ce_cleanup) != POM_OK) return POM_ERR; } int dir = s->direction; if (!cp->evt[dir]) { cp->evt[dir] = event_alloc(priv->evt_rtp_stream); if (!cp->evt[dir]) return POM_ERR; struct data *evt_data = event_get_data(cp->evt[dir]); ptype_copy(evt_data[analyzer_rtp_stream_ssrc].value, s->pkt_info->fields_value[proto_rtp_field_ssrc]); data_set(evt_data[analyzer_rtp_stream_ssrc]); // For now we always assume RTP is over UDP or TCP if (stack_index > 2) { struct proto_process_stack *l4_stack = &stack[stack_index - 2]; unsigned int i; for (i = 0; !data_is_set(evt_data[analyzer_rtp_stream_src_port]) || !data_is_set(evt_data[analyzer_rtp_stream_dst_port]); i++) { struct proto_reg_info *l4_info = proto_get_info(l4_stack->proto); char *name = l4_info->pkt_fields[i].name; if (!name) break; if (!data_is_set(evt_data[analyzer_rtp_stream_src_port]) && !strcmp(name, "sport")) { ptype_copy(evt_data[analyzer_rtp_stream_src_port].value, l4_stack->pkt_info->fields_value[i]); data_set(evt_data[analyzer_rtp_stream_src_port]); } else if (!data_is_set(evt_data[analyzer_rtp_stream_dst_port]) && !strcmp(name, "dport")) { ptype_copy(evt_data[analyzer_rtp_stream_dst_port].value, l4_stack->pkt_info->fields_value[i]); data_set(evt_data[analyzer_rtp_stream_dst_port]); } } } if (stack_index > 3) { struct proto_process_stack *l3_stack = &stack[stack_index - 3]; unsigned int i; for (i = 0; !data_is_set(evt_data[analyzer_rtp_stream_src_addr]) || !data_is_set(evt_data[analyzer_rtp_stream_dst_addr]); i++) { struct proto_reg_info *l3_info = proto_get_info(l3_stack->proto); char *name = l3_info->pkt_fields[i].name; if (!name) break; if (!data_is_set(evt_data[analyzer_rtp_stream_src_addr]) && !strcmp(name, "src")) { evt_data[analyzer_rtp_stream_src_addr].value = ptype_alloc_from(l3_stack->pkt_info->fields_value[i]); if (evt_data[analyzer_rtp_stream_src_addr].value) data_set(evt_data[analyzer_rtp_stream_src_addr]); } else if (!data_is_set(evt_data[analyzer_rtp_stream_dst_addr]) && !strcmp(name, "dst")) { evt_data[analyzer_rtp_stream_dst_addr].value = ptype_alloc_from(l3_stack->pkt_info->fields_value[i]); if (evt_data[analyzer_rtp_stream_dst_addr].value) data_set(evt_data[analyzer_rtp_stream_dst_addr]); } } } struct proto *sess_proto = telephony_stream_info_get_sess_proto(s->ce); if (sess_proto) { struct proto_reg_info *proto_reg = proto_get_info(sess_proto); PTYPE_STRING_SETVAL(evt_data[analyzer_rtp_stream_sess_proto].value, proto_reg->name); data_set(evt_data[analyzer_rtp_stream_sess_proto]); } char *call_id = telephony_stream_info_get_call_id(s->ce); if (call_id) { PTYPE_STRING_SETVAL_P(evt_data[analyzer_rtp_stream_call_id].value, call_id); data_set(evt_data[analyzer_rtp_stream_call_id]); } if (event_process_begin(cp->evt[dir], stack, stack_index, p->ts) != POM_OK) return POM_ERR; } if (!cp->pload[dir]) { cp->pload[dir] = pload_alloc(cp->evt[dir], 0); if (!cp->pload[dir]) return POM_ERR; struct telephony_codec_info info = { 0 }; if (telephony_stream_info_get_codec(&info, stack, stack_index - 1) == POM_OK) { char *pload_type = telephony_codec_info_get_pload_type(&info); if (pload_type) pload_set_type(cp->pload[dir], pload_type); } } if (pload_append(cp->pload[dir], pload_stack->pload, pload_stack->plen) != POM_OK) return POM_ERR; return POM_OK; }
int analyzer_ppp_pap_event_process_begin(struct event *evt, void *obj, struct proto_process_stack *stack, unsigned int stack_index) { struct analyzer *analyzer = obj; struct analyzer_ppp_pap_priv *apriv = analyzer->priv; struct proto_process_stack *s = &stack[stack_index]; if (!s->ce) return PROTO_ERR; conntrack_lock(s->ce); struct ptype *src = NULL, *dst = NULL; struct analyzer_ppp_pap_ce_priv *cpriv = conntrack_get_priv(s->ce, analyzer); if (!cpriv) { cpriv = malloc(sizeof(struct analyzer_ppp_pap_ce_priv)); if (!cpriv) { pom_oom(sizeof(struct analyzer_ppp_pap_ce_priv)); goto err; } memset(cpriv, 0, sizeof(struct analyzer_ppp_pap_ce_priv)); if (conntrack_add_priv(s->ce, analyzer, cpriv, analyzer_ppp_pap_ce_priv_cleanup) != POM_OK) { free(cpriv); goto err; } // Try to find the source and destination unsigned int i = 0; for (i = 1; i <= 4; i++) { struct proto_process_stack *prev_stack = &stack[stack_index - i]; if (!prev_stack->proto) break; struct proto_reg_info *info = proto_get_info(prev_stack->proto); if (!strcmp(info->name, "vlan")) { cpriv->vlan = ptype_alloc_from(prev_stack->pkt_info->fields_value[proto_vlan_field_vid]); if (!cpriv->vlan) { conntrack_unlock(s->ce); return POM_ERR; } } unsigned int j; for (j = 0; !src || !dst; j++) { struct proto_reg_info *prev_info = proto_get_info(prev_stack->proto); if (!prev_info->pkt_fields) break; char *name = prev_info->pkt_fields[j].name; if (!name) break; if (!src && !strcmp(name, "src")) src = prev_stack->pkt_info->fields_value[j]; else if (!dst && !strcmp(name, "dst")) dst = prev_stack->pkt_info->fields_value[j]; } if (src || dst) break; } struct proto_process_stack *prev_stack = &stack[stack_index - 2]; if (prev_stack->proto) { struct proto_reg_info *info = proto_get_info(prev_stack->proto); cpriv->top_proto = info->name; } } struct event_reg *evt_reg = event_get_reg(evt); int dir = POM_DIR_UNK; if (evt_reg == apriv->evt_request) { if (!cpriv->evt_request) { event_refcount_inc(evt); cpriv->evt_request = evt; } dir = POM_DIR_FWD; } else { if (!cpriv->evt_ack_nack) { event_refcount_inc(evt); cpriv->evt_ack_nack = evt; } dir = POM_DIR_REV; } if (src && dst && dir != POM_DIR_UNK) { if (dir == POM_DIR_FWD) { cpriv->client = ptype_alloc_from(src); cpriv->server = ptype_alloc_from(dst); } else { cpriv->client = ptype_alloc_from(dst); cpriv->server = ptype_alloc_from(src); } } int res = POM_OK; if (cpriv->evt_request && cpriv->evt_ack_nack) res = analyzer_ppp_pap_finalize(apriv, cpriv); conntrack_unlock(s->ce); return res; err: conntrack_unlock(s->ce); return POM_ERR; }
static int analyzer_tftp_pkt_process(void *obj, struct packet *p, struct proto_process_stack *stack, unsigned int stack_index) { struct analyzer_tftp_priv *priv = obj; struct proto_process_stack *s = &stack[stack_index]; struct proto_process_stack *s_prev = &stack[stack_index - 1]; uint16_t opcode = *PTYPE_UINT16_GETVAL(s_prev->pkt_info->fields_value[proto_tftp_field_opcode]); // Get the session struct conntrack_session *session = conntrack_session_get(s_prev->ce); if (!session) return POM_ERR; struct analyzer_tftp_session_priv *spriv = conntrack_session_get_priv(session, obj); if (!spriv) { // Add session priv if it is not done yet spriv = malloc(sizeof(struct analyzer_tftp_session_priv)); if (!spriv) { pom_oom(sizeof(struct analyzer_tftp_session_priv)); goto err; } memset(spriv, 0, sizeof(struct analyzer_tftp_session_priv)); if (conntrack_session_add_priv(session, obj, spriv, analyzer_tftp_session_priv_cleanup) != POM_OK) { free(spriv); goto err; } } void *pload = s->pload; uint32_t plen = s->plen; switch (opcode) { case tftp_rrq: case tftp_wrq: { if (plen < 3) return POM_OK; // Invalid packet // Find the filename // The below should always be valid as proto_tftp already checked this char *filename = pload; char *mode = memchr(filename, 0, plen - 1) + 1; struct analyzer_tftp_file *fq = malloc(sizeof(struct analyzer_tftp_file)); if (!fq) { pom_oom(sizeof(struct analyzer_tftp_file)); goto err; } memset(fq, 0, sizeof(struct analyzer_tftp_file)); // Get the port on which we expect this file // No need to check the IP as we got the session biding struct proto_process_stack *s_l4 = &stack[stack_index - 2]; unsigned int i; for (i = 0; !fq->port ; i++) { struct proto_reg_info *pinfo = proto_get_info(s_l4->proto); char *name = pinfo->pkt_fields[i].name; if (!name) { pomlog(POMLOG_ERR "Source port not found in RRQ/WRQ packets"); goto err; } if (!strcmp(name, "sport")) { fq->port = *PTYPE_UINT16_GETVAL(s_l4->pkt_info->fields_value[i]); break; } } fq->evt = event_alloc(priv->evt_file); if (!fq->evt) { free(fq); goto err; } struct data *evt_data = event_get_data(fq->evt); PTYPE_STRING_SETVAL(evt_data[analyzer_tftp_file_filename].value, filename); data_set(evt_data[analyzer_tftp_file_filename]); PTYPE_STRING_SETVAL(evt_data[analyzer_tftp_file_mode].value, mode); data_set(evt_data[analyzer_tftp_file_mode]); PTYPE_BOOL_SETVAL(evt_data[analyzer_tftp_file_write].value, opcode == tftp_wrq); data_set(evt_data[analyzer_tftp_file_write]); fq->next = spriv->files; if (fq->next) fq->next->prev = fq; spriv->files = fq; conntrack_session_unlock(session); event_process_begin(fq->evt, stack, stack_index, p->ts); break; } case tftp_data: { if (plen < sizeof(uint16_t)) return POM_OK; // Invalid packet struct analyzer_tftp_file *f = conntrack_get_priv(s_prev->ce, obj); struct data *evt_data = NULL; if (!f) { // The file is not yet associated to this connection // Find it in the queue struct proto_process_stack *s_l4 = &stack[stack_index - 2]; unsigned int i; uint16_t sport = 0, dport = 0; for (i = 0; !sport || !dport ; i++) { struct proto_reg_info *pinfo = proto_get_info(s_l4->proto); char *name = pinfo->pkt_fields[i].name; if (!name) { pomlog(POMLOG_ERR "Source port not found in data packets"); goto err; } if (!strcmp(name, "sport")) sport = *PTYPE_UINT16_GETVAL(s_l4->pkt_info->fields_value[i]); if (!strcmp(name, "dport")) dport = *PTYPE_UINT16_GETVAL(s_l4->pkt_info->fields_value[i]); } // Find the file in the session list for (f = spriv->files; ; f = f->next) { evt_data = event_get_data(f->evt); if (*PTYPE_BOOL_GETVAL(evt_data[analyzer_tftp_file_write].value)) { if (f->port == sport) break; } else { if (f->port == dport) break; } } if (!f) { pomlog(POMLOG_DEBUG "File not found in queued file request."); conntrack_session_unlock(session); return POM_OK; } // Remove the file from the queue and assign it to the conntrack if (f->prev) f->prev->next = f->next; else spriv->files = f->next; if (f->next) f->next->prev = f->prev; f->prev = NULL; f->next = NULL; // Create the payload buffer f->pload = pload_alloc(f->evt, PLOAD_FLAG_NEED_MAGIC); if (!f->pload) goto err; conntrack_add_priv(s_prev->ce, obj, f, analyzer_tftp_conntrack_priv_cleanup); } else { evt_data = event_get_data(f->evt); } conntrack_session_unlock(session); if (!f->pload) { pomlog(POMLOG_DEBUG "Ignoring extra packet"); return POM_OK; } // Discard the block ID pload += sizeof(uint16_t); plen -= sizeof(uint16_t); if (pload_append(f->pload, pload, plen) != POM_OK) goto err; uint32_t *size = PTYPE_UINT32_GETVAL(evt_data[analyzer_tftp_file_size].value); *size += plen; if (plen < ANALYZER_TFTP_BLK_SIZE) { // Got last packet ! data_set(evt_data[analyzer_tftp_file_size]); int res = pload_end(f->pload); res += event_process_end(f->evt); f->evt = NULL; f->pload = NULL; if (res) goto err; } break; } case tftp_error: { conntrack_session_unlock(session); struct analyzer_tftp_file *f = conntrack_get_priv(s_prev->ce, obj); if (f && f->pload) { int res = pload_end(f->pload); res += event_process_end(f->evt); f->pload = NULL; f->evt = NULL; if (res) goto err; } break; } default: conntrack_session_unlock(session); break; } return POM_OK; err: conntrack_session_unlock(session); return POM_ERR; }