static int analyzer_multipart_pload_close(void *obj, void *p) { struct analyzer_multipart_pload_priv *priv = p; if (!priv) return POM_OK; if (priv->boundary) free(priv->boundary); if (priv->pload) pload_end(priv->pload); if (priv->last_line) free(priv->last_line); while (priv->pload_data.items) { struct data_item *itm = priv->pload_data.items; priv->pload_data.items = itm->next; if (itm->key) free(itm->key); if (itm->value) ptype_cleanup(itm->value); free(itm); } free(priv); return POM_OK; }
static int analyzer_smtp_evt_msg_cleanup(struct event *evt) { struct pload *pload = event_get_priv(evt); if (!pload) return POM_OK; pload_end(pload); return POM_OK; }
static int analyzer_tftp_conntrack_priv_cleanup(void *obj, void *priv) { struct analyzer_tftp_file *f = priv; int res = POM_OK; if (f->pload) res += pload_end(f->pload); if (f->evt) res += event_process_end(f->evt); free(f); return res; }
static int analyzer_rtp_ce_cleanup(void *obj, void *priv) { struct analyzer_rtp_ce_priv *cp = priv; int i; for (i = 0; i < POM_DIR_TOT; i++) { if (cp->pload[i]) pload_end(cp->pload[i]); if (cp->evt[i]) event_process_end(cp->evt[i]); } free(cp); return POM_OK; }
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; }
static int analyzer_multipart_pload_write(void *obj, void *p, void *data, size_t len) { struct analyzer_multipart_pload_priv *priv = p; if (priv->state == analyzer_multipart_pload_state_end) return POM_OK; if (priv->state == analyzer_multipart_pload_state_error) return POM_ERR; unsigned int line_len, remaining_len = len; while (remaining_len > 0) { // Because of the NOTE in RFC 2046 section 5.1.1, line start at CR void *cr = memchr(data + 1, '\r', remaining_len - 1); if (!cr || priv->last_line) { size_t add_len = remaining_len; if (cr) add_len = cr - data; size_t new_len = add_len + 1; if (priv->last_line) new_len += strlen(priv->last_line); if (priv->last_line_len < new_len) { char *new_last_line = realloc(priv->last_line, new_len); if (!new_last_line) { pom_oom(new_len); goto err; } if (!priv->last_line_len) new_last_line[0] = 0; priv->last_line_len = new_len; priv->last_line = new_last_line; } strncat(priv->last_line, data, add_len); priv->last_line[new_len - 1] = 0; if (!cr) break; // Process this line and continue to the next if (analyzer_multipart_pload_process_line(priv, priv->last_line, strlen(priv->last_line)) != POM_OK) goto err; // We need to process this part of the payload if (priv->state == analyzer_multipart_pload_state_content && priv->pload_start) { if (pload_append(priv->pload, priv->pload_start, priv->pload_end - priv->pload_start) != POM_OK) goto err; } priv->pload_start = NULL; priv->pload_end = NULL; free(priv->last_line); priv->last_line = NULL; priv->last_line_len = 0; data = cr; remaining_len -= add_len; continue; } line_len = cr - data; if (analyzer_multipart_pload_process_line(priv, data, line_len) != POM_OK) goto err; remaining_len -= line_len; data = cr; } if (priv->state == analyzer_multipart_pload_state_content && priv->pload_start) { if (pload_append(priv->pload, priv->pload_start, priv->pload_end - priv->pload_start) != POM_OK) goto err; } priv->pload_start = NULL; priv->pload_end = NULL; return POM_OK; err: if (priv->pload) { pload_end(priv->pload); priv->pload = NULL; } priv->state = analyzer_multipart_pload_state_error; return POM_ERR; }
static int analyzer_multipart_pload_process_line(struct analyzer_multipart_pload_priv *priv, char *line, size_t len) { char *my_line = line; size_t my_len = len; while (my_len > 0 && (*my_line == '\r' || *my_line == '\n')) { my_line++; my_len--; } if (my_len >= priv->boundary_len && !memcmp(my_line, priv->boundary, priv->boundary_len)) { // Process the rest of the payload if (priv->pload) { if (priv->pload_start && pload_append(priv->pload, priv->pload_start, priv->pload_end - priv->pload_start) != POM_OK) return POM_ERR; pload_end(priv->pload); priv->pload = NULL; } priv->pload_start = NULL; priv->pload_end = NULL; if (my_len >= priv->boundary_len + 2 && my_line[priv->boundary_len] == '-' && my_line[priv->boundary_len + 1] == '-') priv->state = analyzer_multipart_pload_state_end; else priv->state = analyzer_multipart_pload_state_header; return POM_OK; } else if (priv->state == analyzer_multipart_pload_state_header) { if (!my_len) { // End of the headers priv->state = analyzer_multipart_pload_state_content; return POM_OK; } if (mime_header_parse(&priv->pload_data, my_line, my_len) != POM_OK) { priv->state = analyzer_multipart_pload_state_error; return POM_OK; } } else if (priv->state == analyzer_multipart_pload_state_content) { if (!priv->pload) { struct event *rel_event = pload_get_related_event(priv->parent_pload); priv->pload = pload_alloc(rel_event, 0); if (!priv->pload) return POM_ERR; pload_set_parent(priv->pload, priv->parent_pload); // Parse the headers while (priv->pload_data.items) { struct data_item *itm = priv->pload_data.items; priv->pload_data.items = itm->next; if (!strcasecmp(itm->key, "Content-Type")) { pload_set_mime_type(priv->pload, PTYPE_STRING_GETVAL(itm->value)); } else if (!strcasecmp(itm->key, "Content-Transfer-Encoding")) { pload_set_encoding(priv->pload, PTYPE_STRING_GETVAL(itm->value)); } free(itm->key); ptype_cleanup(itm->value); free(itm); } // If it's the begining, discard CRLF line = my_line; len = my_len; } if (priv->pload_end != line) { // Process the payload we had and queue the this one if (priv->pload_start && pload_append(priv->pload, priv->pload_start, priv->pload_end - priv->pload_start) != POM_OK) return POM_ERR; priv->pload_start = line; priv->pload_end = line + len; } else { priv->pload_end += len; } } return POM_OK; }