Esempio n. 1
0
static int analyzer_smtp_event_process_end(struct event *evt, void *obj) {

	struct analyzer *analyzer = obj;
	struct event_reg *evt_reg = event_get_reg(evt);
	struct analyzer_smtp_priv *apriv = analyzer->priv;

	if (evt_reg != apriv->evt_cmd)
		return POM_OK;

	// Check if the DATA event ended
	struct data *evt_data = event_get_data(evt);
	char *cmd = PTYPE_STRING_GETVAL(evt_data[proto_smtp_cmd_name].value);
	if (!cmd)
		return POM_OK;
	
	if (!strcasecmp(cmd, "DATA"))
		return POM_OK;
	
	struct analyzer_smtp_ce_priv *cpriv = conntrack_get_priv(event_get_conntrack(evt), analyzer);

	if (event_is_started(cpriv->evt_msg)) {
		event_process_end(cpriv->evt_msg);
		cpriv->evt_msg = NULL;
	}

	return POM_OK;
}
Esempio n. 2
0
static int analyzer_docsis_reg_status_update(struct analyzer_docsis_priv *priv, struct analyzer_docsis_cm *cm, enum docsis_mmt_rng_status new_status, ptime ts, struct proto_process_stack *stack, unsigned int stack_index) {

	if (cm->ranging_status == new_status)
		return POM_OK;

	if (event_has_listener(priv->evt_cm_reg_status)) {
		struct event *evt = event_alloc(priv->evt_cm_reg_status);
		if (!evt) {
			pom_mutex_unlock(&priv->lock);
			return POM_ERR;
		}

		struct data *evt_data = event_get_data(evt);
		PTYPE_UINT8_SETVAL(evt_data[analyzer_docsis_cm_reg_status_old].value, cm->ranging_status);
		data_set(evt_data[analyzer_docsis_cm_reg_status_old]);
		PTYPE_UINT8_SETVAL(evt_data[analyzer_docsis_cm_reg_status_new].value, new_status);
		data_set(evt_data[analyzer_docsis_cm_reg_status_new]);
		PTYPE_MAC_SETADDR(evt_data[analyzer_docsis_cm_reg_status_mac].value, cm->mac);
		data_set(evt_data[analyzer_docsis_cm_reg_status_mac]);
		PTYPE_UINT8_SETVAL(evt_data[analyzer_docsis_cm_reg_status_timeout].value, T4_TIMEOUT * cm->t4_multiplier);
		data_set(evt_data[analyzer_docsis_cm_reg_status_timeout]);

		if (event_process(evt, stack, stack_index, ts) != POM_OK) {
			pom_mutex_unlock(&priv->lock);
			return POM_ERR;
		}
	}

	cm->ranging_status = new_status;

	return POM_OK;
}
Esempio n. 3
0
static int analyzer_rtp_stream_event_cleanup(struct event *evt) {


	struct data *evt_data = event_get_data(evt);

	if (data_is_set(evt_data[analyzer_rtp_stream_src_addr]))
		ptype_cleanup(evt_data[analyzer_rtp_stream_src_addr].value);
	if (data_is_set(evt_data[analyzer_rtp_stream_dst_addr]))
		ptype_cleanup(evt_data[analyzer_rtp_stream_dst_addr].value);

	return POM_OK;
}
Esempio n. 4
0
int output_log_xml_process(struct event *evt, void *obj) {

    struct output_log_xml_priv *priv = obj;
    struct event_reg_info *evt_info = event_get_info(evt);

    xmlBufferPtr buff = xmlBufferCreate();
    if (!buff) {
        pomlog(POMLOG_ERR "Error while creating the xml buffer");
        return POM_ERR;
    }

    xmlTextWriterPtr writer = xmlNewTextWriterMemory(buff, 0);
    if (!writer) {
        pomlog(POMLOG_ERR "Error while creating the xmlTextWriter");
        xmlBufferFree(buff);
        return POM_ERR;
    }

    // <event name="event_name">

    char timestamp[21] = { 0 };
    snprintf(timestamp, 20, "%"PRIu64, (uint64_t) event_get_timestamp(evt));

    if (xmlTextWriterWriteString(writer, BAD_CAST "\n") < 0 ||
            xmlTextWriterStartElement(writer, BAD_CAST "event") < 0 ||
            xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST evt_info->name) < 0 ||
            xmlTextWriterWriteAttribute(writer, BAD_CAST "timestamp", BAD_CAST timestamp) < 0)
        goto err;

    struct data *evt_data = event_get_data(evt);

    int i;
    for (i = 0; i < evt_info->data_reg->data_count; i++) {
        if (evt_info->data_reg->items[i].flags & DATA_REG_FLAG_LIST) {
            // Got a data_list

            if (!evt_data[i].items)
                continue;

            // <data_list name="data_name">
            if (xmlTextWriterWriteString(writer, BAD_CAST "\n\t") < 0 ||
                    xmlTextWriterStartElement(writer, BAD_CAST "data_list") < 0 ||
                    xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST evt_info->data_reg->items[i].name) < 0)
                goto err;

            // <value key="key1">
            struct data_item *itm = evt_data[i].items;
            for (; itm; itm = itm->next) {
                if (xmlTextWriterWriteString(writer, BAD_CAST "\n\t\t") < 0 ||
                        xmlTextWriterStartElement(writer, BAD_CAST "value") < 0 ||
                        xmlTextWriterWriteAttribute(writer, BAD_CAST "key", BAD_CAST itm->key) < 0)
                    goto err;

                char *value = ptype_print_val_alloc(itm->value, NULL);
                if (!value)
                    goto err;

                if (xmlTextWriterWriteString(writer, BAD_CAST value) < 0) {
                    free(value);
                    goto err;
                }

                free(value);

                // </value>
                if (xmlTextWriterEndElement(writer) < 0)
                    goto err;

            }


            // </data_list>
            if (xmlTextWriterWriteString(writer, BAD_CAST "\n\t") < 0 ||
                    xmlTextWriterEndElement(writer) < 0)
                goto err;

        } else {

            // Got a single data

            if (!data_is_set(evt_data[i]))
                continue;


            // <data name="data_name">

            if (xmlTextWriterWriteString(writer, BAD_CAST "\n\t") < 0 ||
                    xmlTextWriterStartElement(writer, BAD_CAST "data") < 0 ||
                    xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST evt_info->data_reg->items[i].name) < 0)
                goto err;

            if (evt_data[i].value) {
                char *value = ptype_print_val_alloc(evt_data[i].value, NULL);
                if (!value)
                    goto err;

                if (xmlTextWriterWriteString(writer, BAD_CAST value) < 0) {
                    free(value);
                    goto err;
                }

                free(value);
            }

            // </data>

            if (xmlTextWriterEndElement(writer) < 0)
                goto err;
        }
    }

    // </event>
    if (xmlTextWriterWriteString(writer, BAD_CAST "\n") < 0 ||
            xmlTextWriterEndElement(writer) < 0 ||
            xmlTextWriterWriteString(writer, BAD_CAST "\n") < 0)
        goto err;

    xmlFreeTextWriter(writer);

    if (pom_write(priv->fd, buff->content, buff->use) != POM_OK) {
        pomlog(POMLOG_ERR "Error while writing to the log file");
        xmlBufferFree(buff);
        return POM_ERR;
    }

    xmlBufferFree(buff);

    if (priv->perf_events)
        registry_perf_inc(priv->perf_events, 1);

    return POM_OK;
err:
    pomlog(POMLOG_ERR "An error occured while processing the event");
    xmlFreeTextWriter(writer);
    xmlBufferFree(buff);

    return POM_ERR;

}
Esempio n. 5
0
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;
}
Esempio n. 6
0
static int analyzer_smtp_parse_auth_plain(struct analyzer_smtp_priv *apriv, struct analyzer_smtp_ce_priv *cpriv, char *auth_plain) {

	// Parse SASL AUTH PLAIN as described in RFC 4616

	// The decoded arg must be at least 3 bytes
	if (strlen(auth_plain) < 4 || memchr(auth_plain, '=', 4)) {
		pomlog(POMLOG_DEBUG "AUTH PLAIN argument too short");
		return POM_OK;
	}

	// Allocate the event
	cpriv->evt_auth = event_alloc(apriv->evt_auth);
	if (!cpriv->evt_auth)
		return POM_ERR;

	struct data *evt_data = event_get_data(cpriv->evt_auth);

	analyzer_smtp_event_fill_common_data(cpriv, evt_data);

	// Set the authentication type
	PTYPE_STRING_SETVAL(evt_data[analyzer_smtp_auth_type].value, "PLAIN");
	data_set(evt_data[analyzer_smtp_auth_type]);

	// Parse the authentication stuff
	char *creds_str = NULL;
	size_t out_len = 0;
	if (decoder_decode_simple("base64", auth_plain, strlen(auth_plain), &creds_str, &out_len) != POM_OK) {
		pomlog(POMLOG_DEBUG "Unable to decode AUTH PLAIN message");
		return POM_OK;
	}

	if (out_len < 3) {
		pomlog(POMLOG_DEBUG "Invalid decoded AUTH PLAIN data");
		return POM_OK;
	}



	char *tmp = creds_str;

	// Add the identity
	if (strlen(tmp)) {
		// SASL AUTH PLAIN specifies 
		struct ptype *identity = ptype_alloc("string");
		if (!identity)
			goto err;
		PTYPE_STRING_SETVAL(identity, tmp);
		if (data_item_add_ptype(evt_data, analyzer_smtp_auth_params, strdup("identity"), identity) != POM_OK) {
			ptype_cleanup(identity);
			goto err;
		}
	}
	tmp += strlen(tmp) + 1;
	
	// Add the username
	struct ptype *username = ptype_alloc("string");
	if (!username)
		goto err;
	PTYPE_STRING_SETVAL(username, tmp);
	if (data_item_add_ptype(evt_data, analyzer_smtp_auth_params, strdup("username"), username) != POM_OK) {
		ptype_cleanup(username);
		goto err;
	}
	tmp += strlen(tmp) + 1;

	// Add the password
	struct ptype *password = ptype_alloc("string");
	if (!password)
		goto err;
	PTYPE_STRING_SETVAL(password, tmp);
	if (data_item_add_ptype(evt_data, analyzer_smtp_auth_params, strdup("password"), password) != POM_OK) {
		ptype_cleanup(password);
		goto err;
	}

	free(creds_str);
	return POM_OK;

err:

	event_cleanup(cpriv->evt_auth);
	cpriv->evt_auth = NULL;

	free(creds_str);

	return POM_ERR;
}
Esempio n. 7
0
int analyzer_ppp_pap_finalize(struct analyzer_ppp_pap_priv *apriv, struct analyzer_ppp_pap_ce_priv *cpriv) {

    if (!cpriv->evt_request)
        return POM_OK;

    struct event *evt = NULL;
    struct data *evt_data = NULL;

    struct data *evt_req_data = event_get_data(cpriv->evt_request);

    evt = event_alloc(apriv->evt_auth);
    if (!evt)
        return POM_ERR;

    evt_data = event_get_data(evt);

    if (ptype_copy(evt_data[analyzer_ppp_pap_auth_peer_id].value, evt_req_data[evt_ppp_pap_request_peer_id].value) != POM_OK) {
        event_cleanup(evt);
        return POM_ERR;
    }
    data_set(evt_data[analyzer_ppp_pap_auth_peer_id]);

    if (ptype_copy(evt_data[analyzer_ppp_pap_auth_password].value, evt_req_data[evt_ppp_pap_request_password].value) != POM_OK) {
        event_cleanup(evt);
        return POM_ERR;
    }
    data_set(evt_data[analyzer_ppp_pap_auth_password]);


    if (cpriv->client) {
        evt_data[analyzer_ppp_pap_auth_client].value = cpriv->client;
        data_set(evt_data[analyzer_ppp_pap_auth_client]);
        data_do_clean(evt_data[analyzer_ppp_pap_auth_client]);
        cpriv->client = NULL;
    }

    if (cpriv->server) {
        evt_data[analyzer_ppp_pap_auth_server].value = cpriv->server;
        data_set(evt_data[analyzer_ppp_pap_auth_server]);
        data_do_clean(evt_data[analyzer_ppp_pap_auth_server]);
        cpriv->server = NULL;
    }

    if (cpriv->vlan) {
        evt_data[analyzer_ppp_pap_auth_vlan].value = cpriv->vlan;
        data_set(evt_data[analyzer_ppp_pap_auth_vlan]);
        data_do_clean(evt_data[analyzer_ppp_pap_auth_vlan]);
        cpriv->vlan = NULL;
    }

    if (cpriv->top_proto) {
        PTYPE_STRING_SETVAL(evt_data[analyzer_ppp_pap_auth_top_proto].value, cpriv->top_proto);
        data_set(evt_data[analyzer_ppp_pap_auth_top_proto]);
    }

    if (ptype_copy(evt_data[analyzer_ppp_pap_auth_identifier].value, evt_req_data[evt_ppp_pap_request_identifier].value) != POM_OK) {
        event_cleanup(evt);
        return POM_ERR;
    }
    data_set(evt_data[analyzer_ppp_pap_auth_identifier]);

    if (cpriv->evt_ack_nack) {
        struct data *evt_ack_data = event_get_data(cpriv->evt_ack_nack);
        uint8_t code = *PTYPE_UINT8_GETVAL(evt_ack_data[evt_ppp_pap_ack_nack_code].value);

        if (code == 2) {
            PTYPE_BOOL_SETVAL(evt_data[analyzer_ppp_pap_auth_success].value, 1);
        } else {
            PTYPE_BOOL_SETVAL(evt_data[analyzer_ppp_pap_auth_success].value, 0);
        }
        data_set(evt_data[analyzer_ppp_pap_auth_success]);

        event_refcount_dec(cpriv->evt_ack_nack);
        cpriv->evt_ack_nack = NULL;
    }

    ptime ts = event_get_timestamp(cpriv->evt_request);

    event_refcount_dec(cpriv->evt_request);
    cpriv->evt_request = NULL;

    return event_process(evt, NULL, 0, ts);
}
Esempio n. 8
0
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;
}
Esempio n. 9
0
static int proto_eap_process(void *proto_priv, struct packet *p, struct proto_process_stack *stack, unsigned int stack_index) {

	struct proto_process_stack *s = &stack[stack_index];

	if (sizeof(struct eap_header) > s->plen)
		return PROTO_INVALID;

	struct proto_eap_priv *priv = proto_priv;

	struct eap_header *hdr = s->pload;

	PTYPE_UINT8_SETVAL(s->pkt_info->fields_value[proto_eap_field_code], hdr->code);
	PTYPE_UINT8_SETVAL(s->pkt_info->fields_value[proto_eap_field_identifier], hdr->identifier);

	
	if (hdr->code < 1 || hdr->code > 4)
		return PROTO_INVALID;

	uint16_t len = ntohs(hdr->length);

	if (len > s->plen)
		return PROTO_INVALID;

	// Keep only the payload lenght
	len -= sizeof(struct eap_header);
	
	if (conntrack_get(stack, stack_index) != POM_OK)
		return PROTO_ERR;

	if (conntrack_delayed_cleanup(s->ce, *PTYPE_UINT32_GETVAL(priv->p_timeout), p->ts) != POM_OK) {
		conntrack_unlock(s->ce);
		return PROTO_ERR;
	}
	conntrack_unlock(s->ce);

	if (hdr->code == 3 || hdr->code == 4) {
		// Content length is 0 for success and failure
		if (len != 4)
			return PROTO_INVALID;
		len = 0;

		if (!event_has_listener(priv->evt_success_failure))
			return PROTO_OK;

		struct event *evt = event_alloc(priv->evt_success_failure);
		if (!evt)
			return PROTO_ERR;
		struct data *evt_data = event_get_data(evt);
		PTYPE_UINT8_SETVAL(evt_data[evt_eap_common_identifier].value, hdr->identifier);
		data_set(evt_data[evt_eap_common_identifier]);
		PTYPE_BOOL_SETVAL(evt_data[evt_eap_success_failure_success].value, (hdr->code == 3 ? 1 : 0));
		data_set(evt_data[evt_eap_success_failure_success]);

		return event_process(evt, stack, stack_index, p->ts);
	}

	// At this point, code is either 1 or 2 (request/response)

	void *pload = s->pload + sizeof(struct eap_header);

	uint8_t type = 0;

	// There is at least 1 byte of data for request/response
	if (len < 1)
		return PROTO_INVALID;
	len--;

	type = *(uint8_t*)pload;
	pload++;

	struct event *evt = NULL;
	struct data *evt_data = NULL;
	
	switch (type) {
		case 1: // Identity
			
			if (!event_has_listener(priv->evt_identity))
				break;

			evt = event_alloc(priv->evt_identity);
			if (!evt)
				return PROTO_ERR;
			if (len) {
				evt_data = event_get_data(evt);
				PTYPE_STRING_SETVAL_N(evt_data[evt_eap_identity_identity].value, pload, len);
				data_set(evt_data[evt_eap_identity_identity]);
			}

			break;

		case 4: // MD5-Challenge
		
			if (!event_has_listener(priv->evt_md5_challenge))
				break;

			if (len < 17)
				return PROTO_INVALID;

			uint8_t value_size = *(uint8_t*)pload;
			if (value_size != 16)
				return PROTO_INVALID;

			pload++;
			len--;

			evt = event_alloc(priv->evt_md5_challenge);
			if (!evt)
				return PROTO_ERR;
			evt_data = event_get_data(evt);

			PTYPE_BYTES_SETLEN(evt_data[evt_eap_md5_challenge_value].value, 16);
			PTYPE_BYTES_SETVAL(evt_data[evt_eap_md5_challenge_value].value, pload);
			data_set(evt_data[evt_eap_md5_challenge_value]);
			
			if (len > 16) {
				PTYPE_STRING_SETVAL_N(evt_data[evt_eap_md5_challenge_name].value, pload + 16, len - 16);
				data_set(evt_data[evt_eap_md5_challenge_name]);
			}
			break;
	}
	
	if (evt) {
		if (!evt_data)
			evt_data = event_get_data(evt);
		PTYPE_UINT8_SETVAL(evt_data[evt_eap_common_identifier].value, hdr->identifier);
		data_set(evt_data[evt_eap_common_identifier]);
		PTYPE_UINT8_SETVAL(evt_data[evt_eap_common_code].value, hdr->code);
		data_set(evt_data[evt_eap_common_code]);

		if (event_process(evt, stack, stack_index, p->ts) != POM_OK)
			return PROTO_ERR;
	}


	return PROTO_OK;

}
Esempio n. 10
0
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;
}
Esempio n. 11
0
static int proto_smtp_process(void *proto_priv, struct packet *p, struct proto_process_stack *stack, unsigned int stack_index) {

	struct proto_process_stack *s = &stack[stack_index];
	struct proto_process_stack *s_next = &stack[stack_index + 1];

	if (conntrack_get_unique_from_parent(stack, stack_index) != POM_OK) {
		pomlog(POMLOG_ERR "Could not get conntrack entry");
		return PROTO_ERR;
	}

	// There should no need to keep the lock here since we are in the packet_stream lock from proto_tcp
	conntrack_unlock(s->ce);

	struct proto_smtp_priv *ppriv = proto_priv;

	struct proto_smtp_conntrack_priv *priv = s->ce->priv;
	if (!priv) {
		priv = malloc(sizeof(struct proto_smtp_conntrack_priv));
		if (!priv) {
			pom_oom(sizeof(struct proto_smtp_conntrack_priv));
			return PROTO_ERR;
		}
		memset(priv, 0, sizeof(struct proto_smtp_conntrack_priv));

		priv->parser[POM_DIR_FWD] = packet_stream_parser_alloc(SMTP_MAX_LINE, PACKET_STREAM_PARSER_FLAG_TRIM);
		if (!priv->parser[POM_DIR_FWD]) {
			free(priv);
			return PROTO_ERR;
		}

		priv->parser[POM_DIR_REV] = packet_stream_parser_alloc(SMTP_MAX_LINE, PACKET_STREAM_PARSER_FLAG_TRIM);
		if (!priv->parser[POM_DIR_REV]) {
			packet_stream_parser_cleanup(priv->parser[POM_DIR_FWD]);
			free(priv);
			return PROTO_ERR;
		}

		priv->server_direction = POM_DIR_UNK;

		s->ce->priv = priv;
	}

	if (priv->flags & PROTO_SMTP_FLAG_INVALID)
		return PROTO_OK;

	struct packet_stream_parser *parser = priv->parser[s->direction];
	if (packet_stream_parser_add_payload(parser, s->pload, s->plen) != POM_OK)
		return PROTO_ERR;

	char *line = NULL;
	size_t len = 0;
	while (1) {

		// Some check to do prior to parse the payload
		
		if (s->direction == POM_DIR_REVERSE(priv->server_direction)) {
			if (priv->flags & PROTO_SMTP_FLAG_STARTTLS) {
				// Last command was a STARTTLS command, this is the TLS negociation
				// Since we can't parse this, mark it as invalid
				priv->flags |= PROTO_SMTP_FLAG_INVALID;
				return PROTO_OK;

			} else if (priv->flags & PROTO_SMTP_FLAG_CLIENT_DATA) {

				// We are receiving payload data, check where the end is
				void *pload;
				size_t plen;
				packet_stream_parser_get_remaining(parser, &pload, &plen);

				if (!plen)
					return PROTO_OK;

				// Look for the "<CR><LF>.<CR><LF>" sequence
				if (priv->data_end_pos > 0) {
					
					// The previous packet ended with something that might be the final sequence
					// Check if we have the rest
					int i, found = 1;
					for (i = 0; i < PROTO_SMTP_DATA_END_LEN - priv->data_end_pos && i <= plen; i++) {
						if (*(char*)(pload + i) != PROTO_SMTP_DATA_END[priv->data_end_pos + i]) {
							found = 0;
							break;
						}
					}
					if (found) {
						// If we have already processed the dot after <CR><LF> there is no way to remove it
						// Thus we mark this connection as invalid. Most MTA will send at worst the last
						// 3 bytes of the end sequence in a sequence packet
						if (i != plen || (priv->data_end_pos >= 2 && plen < 3)) {
							pomlog(POMLOG_DEBUG "The final line was not at the of a packet as expected !");
							priv->flags |= PROTO_SMTP_FLAG_INVALID;
							event_process_end(priv->data_evt);
							priv->data_evt = NULL;
							return PROTO_OK;
						}
						s_next->pload = pload;
						s_next->plen = plen - PROTO_SMTP_DATA_END_LEN + 2; // The last line return is part of the payload
						priv->flags |= PROTO_SMTP_FLAG_CLIENT_DATA_END;

						priv->flags &= ~PROTO_SMTP_FLAG_CLIENT_DATA;
						priv->data_end_pos = 0;

						return PROTO_OK;
					}
					priv->data_end_pos = 0;
				}


				char *dotline = pom_strnstr(pload, PROTO_SMTP_DATA_END, plen);
				if (dotline) {
					if (pload + plen - PROTO_SMTP_DATA_END_LEN != dotline) {
						pomlog(POMLOG_DEBUG "The final line was not at the of a packet as expected !");
						priv->flags |= PROTO_SMTP_FLAG_INVALID;
						event_process_end(priv->data_evt);
						priv->data_evt = NULL;
						return PROTO_OK;
					}
					s_next->pload = pload;
					s_next->plen = plen - PROTO_SMTP_DATA_END_LEN + 2; // The last line return is part of the payload
					priv->flags |= PROTO_SMTP_FLAG_CLIENT_DATA_END;

					priv->flags &= ~PROTO_SMTP_FLAG_CLIENT_DATA;

				} else {
					// Check if the end of the payload contains part of the "<CR><LF>.<CR><LF>" sequence
					int i, found = 0;
					for (i = 1 ; (i < PROTO_SMTP_DATA_END_LEN) && (i <= plen); i++) {
						if (!memcmp(pload + plen - i, PROTO_SMTP_DATA_END, i)) {
							found = 1;
							break;
						}
					}

					if (found)
						priv->data_end_pos = i;

					s_next->pload = pload;
					s_next->plen = plen;
				}

				return PROTO_OK;
			}
		}

		// Process commands
		if (packet_stream_parser_get_line(parser, &line, &len) != POM_OK)
			return PROTO_ERR;

		if (!line)
			return PROTO_OK;

		if (!len) // Probably a missed packet
			return PROTO_OK;

		// Try to find the server direction
		if (priv->server_direction == POM_DIR_UNK) {
			unsigned int code = atoi(line);
			if (code > 0) {
				priv->server_direction = s->direction;
			} else {
				priv->server_direction = POM_DIR_REVERSE(s->direction);
			}
		}

		if (s->direction == priv->server_direction) {

			// Parse the response code and generate the event
			if ((len < 5) || // Server response is 3 digit error code, a space or hyphen and then at least one letter of text
				(line[3] != ' ' && line[3] != '-')) {
				pomlog(POMLOG_DEBUG "Too short or invalid response from server");
				priv->flags |= PROTO_SMTP_FLAG_INVALID;
				return POM_OK;
			}

			int code = atoi(line);
			if (code == 0) {
				pomlog(POMLOG_DEBUG "Invalid response from server");
				priv->flags |= PROTO_SMTP_FLAG_INVALID;
				return POM_OK;
			}

			if (event_has_listener(ppriv->evt_reply)) {

				struct data *evt_data = NULL;
				if (priv->reply_evt) {
					evt_data = event_get_data(priv->reply_evt);
					uint16_t cur_code = *PTYPE_UINT16_GETVAL(evt_data[proto_smtp_reply_code].value);
					if (cur_code != code) {
						pomlog(POMLOG_WARN "Multiline code not the same as previous line : %hu -> %hu", cur_code, code);
						event_process_end(priv->reply_evt);
						priv->reply_evt = NULL;
					}
				}


				if (!priv->reply_evt) {
					priv->reply_evt = event_alloc(ppriv->evt_reply);
					if (!priv->reply_evt)
						return PROTO_ERR;

					evt_data = event_get_data(priv->reply_evt);
					PTYPE_UINT16_SETVAL(evt_data[proto_smtp_reply_code].value, code);
					data_set(evt_data[proto_smtp_reply_code]);

				}

				if (len > 4) {
					struct ptype *txt = ptype_alloc("string");
					if (!txt)
						return PROTO_ERR;
					PTYPE_STRING_SETVAL_N(txt, line + 4, len - 4);
					if (data_item_add_ptype(evt_data, proto_smtp_reply_text, strdup("text"), txt) != POM_OK)
						return PROTO_ERR;
				}
				
				if (!event_is_started(priv->reply_evt))
					event_process_begin(priv->reply_evt, stack, stack_index, p->ts);
			}


			if (line[3] != '-') {
				// Last line in the response
				if (priv->reply_evt) {
					event_process_end(priv->reply_evt);
					priv->reply_evt = NULL;
				}
			}
			
			if (priv->flags & PROTO_SMTP_FLAG_STARTTLS) {
				// The last command was STARTTLS
				priv->flags &= ~PROTO_SMTP_FLAG_STARTTLS;
				if (code == 220) {
					// TLS has the go, we can't parse  from now so mark as invalid
					priv->flags |= PROTO_SMTP_FLAG_INVALID;
					return POM_OK;
				}
			}

		} else {

			// Client command

			if (len < 4) { // Client commands are at least 4 bytes long
				pomlog(POMLOG_DEBUG "Too short or invalid query from client");
				priv->flags |= PROTO_SMTP_FLAG_INVALID;
				return POM_OK;
			}

			// Make sure it's a command by checking it's at least a four letter word
			int i;
			for (i = 0; i < 4; i++) {
				// In some case it can also be a base64 encoded word
				if (! ((line[i] >= 'A' && line[i] <= 'Z')
					|| (line[i] >= 'a' && line[i] <= 'z')
					|| (line[i] >= '0' && line [i] <= '9')
					|| line[i] == '='))
					break;
			}

			if ((i < 4)) {
				pomlog(POMLOG_DEBUG "Recieved invalid client command");
				priv->flags |= PROTO_SMTP_FLAG_INVALID;
				return POM_OK;
			}

			if (!strncasecmp(line, "DATA", strlen("DATA")) && len == strlen("DATA")) {
				priv->flags |= PROTO_SMTP_FLAG_CLIENT_DATA;
			} else if (!strncasecmp(line, "STARTTLS", strlen("STARTTLS")) && len == strlen("STARTTLS")) {
				priv->flags |= PROTO_SMTP_FLAG_STARTTLS;
			}


			if (event_has_listener(ppriv->evt_cmd)) {
				struct event *evt = event_alloc(ppriv->evt_cmd);
				if (!evt)
					return PROTO_ERR;

				size_t cmdlen = len;
				char *space = memchr(line, ' ', len);
				if (space)
					cmdlen = space - line;

				struct data *evt_data = event_get_data(evt);
				PTYPE_STRING_SETVAL_N(evt_data[proto_smtp_cmd_name].value, line, cmdlen);
				data_set(evt_data[proto_smtp_cmd_name]);
				if (space) {
					PTYPE_STRING_SETVAL_N(evt_data[proto_smtp_cmd_arg].value, space + 1, len - 1 - cmdlen);
					data_set(evt_data[proto_smtp_cmd_arg]);
				}

				if (priv->flags & PROTO_SMTP_FLAG_CLIENT_DATA) {
					// The event ends at the end of the message
					priv->data_evt = evt;
					return event_process_begin(evt, stack, stack_index, p->ts);
				} else {
					return event_process(evt, stack, stack_index, p->ts);
				}
			}

		}



	}

	return PROTO_OK;

}
Esempio n. 12
0
static int analyzer_docsis_pkt_process(void *obj, struct packet *p, struct proto_process_stack *stack, unsigned int stack_index) {

	struct analyzer *analyzer = obj;
	struct analyzer_docsis_priv *priv = analyzer->priv;

	struct proto_process_stack *s = &stack[stack_index];

	uint8_t *type = PTYPE_UINT8_GETVAL(s->pkt_info->fields_value[proto_docsis_mgmt_field_type]);

	char *mac_dst = PTYPE_MAC_GETADDR(s->pkt_info->fields_value[proto_docsis_mgmt_field_dst]);

	// FIXME : improve this filtering at the source
	// Filter some useless messages we don't care about
	
	if (*type == MMT_UCD2 || *type == MMT_UCD3 || *type == MMT_MDD)
		return POM_OK;

	if (*type != MMT_RNG_RSP) {
		pomlog(POMLOG_DEBUG "Unhandled DOCSIS MGMT message type %u for destination mac %02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX", *type, mac_dst[0], mac_dst[1], mac_dst[2], mac_dst[3], mac_dst[4], mac_dst[5]);
		return POM_OK;
	}

	// Use the last bits for the modem ID
	uint16_t id = ntohs(*(uint16_t*) (mac_dst + 4)) & ANALYZER_DOCSIS_CM_MASK;

	pom_mutex_lock(&priv->lock);

	struct analyzer_docsis_cm *cm;
	for (cm = priv->cms[id]; cm; cm = cm->next) {
		if (!memcmp(cm->mac, mac_dst, sizeof(cm->mac)))
			break;
	}

	if (!cm) {
		// Cable modem not found !
		cm = malloc(sizeof(struct analyzer_docsis_cm));
		if (!cm) {
			pom_mutex_unlock(&priv->lock);
			pom_oom(sizeof(struct analyzer_docsis_cm));
			return POM_ERR;
		}
		memset(cm, 0, sizeof(struct analyzer_docsis_cm));

		cm->t = timer_alloc(cm, analyzer_docsis_cm_timeout);
		if (!cm->t) {
			pom_mutex_unlock(&priv->lock);
			free(cm);
			return POM_ERR;
		}
	
		cm->analyzer = analyzer;
		memcpy(cm->mac, mac_dst, sizeof(cm->mac));
		cm->t4_multiplier = 1;

		cm->next = priv->cms[id];
		if (cm->next)
			cm->next->prev = cm;

		priv->cms[id] = cm;

		// Announce the new CM
		if (event_has_listener(priv->evt_cm_new)) {
			struct event *evt = event_alloc(priv->evt_cm_new);
			if (!evt) {
				pom_mutex_unlock(&priv->lock);
				return POM_ERR;
			}

			struct data *evt_data = event_get_data(evt);
			PTYPE_MAC_SETADDR(evt_data[analyzer_docsis_cm_new_mac].value, cm->mac);
			data_set(evt_data[analyzer_docsis_cm_new_mac]);
			PTYPE_STRING_SETVAL(evt_data[analyzer_docsis_cm_new_input].value, p->input->name);
			data_set(evt_data[analyzer_docsis_cm_new_input]);

			if (event_process(evt, stack, stack_index, p->ts) != POM_OK) {
				pom_mutex_unlock(&priv->lock);
				return POM_ERR;
			}
		}
	}


	switch (*type) {

		case MMT_RNG_RSP:
			analyzer_docsis_pkt_parse_rng_rsp(priv, cm, p, stack, stack_index);
			break;

		// FIXME If ranging_status is 0 and we receive another msg, probably it's actually registered
		// and we need to call analyzer_docsis_reg_status_update();

	}

	timer_queue_now(cm->t, T4_TIMEOUT * cm->t4_multiplier, p->ts);

	pom_mutex_unlock(&priv->lock);

	return POM_OK;
}
Esempio n. 13
0
static int proto_ppp_pap_process(void *proto_priv, struct packet *p, struct proto_process_stack *stack, unsigned int stack_index) {

	struct proto_process_stack *s = &stack[stack_index];

	if (sizeof(struct ppp_pap_header) > s->plen)
		return PROTO_INVALID;

	struct ppp_pap_header *pchdr = s->pload;
	size_t len = ntohs(pchdr->length);

	if (len > s->plen)
		return PROTO_INVALID;

	// Keep only the payload len
	len -= sizeof(struct ppp_pap_header);

	PTYPE_UINT8_SETVAL(s->pkt_info->fields_value[proto_ppp_pap_field_code], pchdr->code);
	PTYPE_UINT8_SETVAL(s->pkt_info->fields_value[proto_ppp_pap_field_identifier], pchdr->identifier);

	struct proto_ppp_pap_priv *priv = proto_priv;

	if (conntrack_get(stack, stack_index) != POM_OK)
		return PROTO_ERR;
	if (conntrack_delayed_cleanup(s->ce, *PTYPE_UINT32_GETVAL(priv->p_auth_timeout), p->ts) != POM_OK) {
		conntrack_unlock(s->ce);
		return PROTO_ERR;
	}
	
	conntrack_unlock(s->ce);

	if (pchdr->code == 1 && event_has_listener(priv->evt_request)) {

		if (len < 4)
			return PROTO_INVALID;

		uint8_t *peer_id_len = s->pload + sizeof(struct ppp_pap_header);
		if (*peer_id_len > len - 2)
			return PROTO_INVALID;

		len -= (*peer_id_len + 1);
		uint8_t *pwd_len = peer_id_len + *peer_id_len + 1;
		if (*pwd_len > len - 1)
			return PROTO_INVALID;


		// Process the challenge/response event
		struct event *evt = event_alloc(priv->evt_request);
		if (!evt)
			return PROTO_ERR;

		struct data *evt_data = event_get_data(evt);
		PTYPE_UINT8_SETVAL(evt_data[evt_ppp_pap_request_code].value, pchdr->code);
		data_set(evt_data[evt_ppp_pap_request_code]);
		PTYPE_UINT8_SETVAL(evt_data[evt_ppp_pap_request_identifier].value, pchdr->identifier);
		data_set(evt_data[evt_ppp_pap_request_identifier]);

	
		PTYPE_STRING_SETVAL_N(evt_data[evt_ppp_pap_request_peer_id].value, (char *)peer_id_len + 1, *peer_id_len);
		data_set(evt_data[evt_ppp_pap_request_peer_id]);

		PTYPE_STRING_SETVAL_N(evt_data[evt_ppp_pap_request_password].value, (char *)pwd_len + 1, *pwd_len);
		data_set(evt_data[evt_ppp_pap_request_password]);

		if (event_process(evt, stack, stack_index, p->ts) != POM_OK)
			return PROTO_ERR;

	}

	if ((pchdr->code == 2 || pchdr->code == 3) && event_has_listener(priv->evt_ack_nack)) {
		
		struct event *evt = event_alloc(priv->evt_ack_nack);
		if (!evt)
			return PROTO_ERR;

		struct data *evt_data = event_get_data(evt);
		PTYPE_UINT8_SETVAL(evt_data[evt_ppp_pap_ack_nack_code].value, pchdr->code);
		data_set(evt_data[evt_ppp_pap_ack_nack_code]);
		PTYPE_UINT8_SETVAL(evt_data[evt_ppp_pap_ack_nack_identifier].value, pchdr->identifier);
		data_set(evt_data[evt_ppp_pap_ack_nack_identifier]);

		uint8_t *msg_len = s->pload + sizeof(struct ppp_pap_header);
		if (*msg_len > len - 1)
			return PROTO_INVALID;

		PTYPE_STRING_SETVAL_N(evt_data[evt_ppp_pap_ack_nack_message].value, (char *)msg_len + 1, *msg_len);
		data_set(evt_data[evt_ppp_pap_ack_nack_message]);

		if (event_process(evt, stack, stack_index, p->ts) != POM_OK)
			return PROTO_ERR;

	}

	return PROTO_OK;

}
Esempio n. 14
0
int analyzer_eap_finalize(struct analyzer_eap_priv *apriv, struct analyzer_eap_ce_priv *cpriv) {

	if (!cpriv->evt_request || !cpriv->evt_response)
		return POM_OK;

	struct event *evt = NULL;
	struct data *evt_data = NULL;

	struct data *evt_req_data = event_get_data(cpriv->evt_request);
	struct data *evt_rsp_data = event_get_data(cpriv->evt_response);

	if (!data_is_set(evt_rsp_data[evt_eap_md5_challenge_value]))
		return POM_OK;
	if (!data_is_set(evt_req_data[evt_eap_md5_challenge_value]))
		return POM_OK;

	evt = event_alloc(apriv->evt_md5_auth);
	if (!evt)
		return POM_ERR;

	evt_data = event_get_data(evt);

	if (ptype_copy(evt_data[analyzer_eap_md5_challenge].value, evt_req_data[evt_eap_md5_challenge_value].value) != POM_OK)
		return POM_ERR;
	data_set(evt_data[analyzer_eap_md5_challenge]);
	if (ptype_copy(evt_data[analyzer_eap_md5_response].value, evt_rsp_data[evt_eap_md5_challenge_value].value) != POM_OK)
		return POM_ERR;
	data_set(evt_data[analyzer_eap_md5_response]);
		


	if (cpriv->client) {
		evt_data[analyzer_eap_common_client].value = cpriv->client;
		data_set(evt_data[analyzer_eap_common_client]);
		data_do_clean(evt_data[analyzer_eap_common_client]);
		cpriv->client = NULL;
	}

	if (cpriv->server) {
		evt_data[analyzer_eap_common_server].value = cpriv->server;
		data_set(evt_data[analyzer_eap_common_server]);
		data_do_clean(evt_data[analyzer_eap_common_server]);
		cpriv->server = NULL;
	}

	if (cpriv->vlan) {
		evt_data[analyzer_eap_common_vlan].value = cpriv->vlan;
		data_set(evt_data[analyzer_eap_common_vlan]);
		data_do_clean(evt_data[analyzer_eap_common_vlan]);
		cpriv->vlan = NULL;
	}

	if (cpriv->top_proto) {
		PTYPE_STRING_SETVAL(evt_data[analyzer_eap_common_top_proto].value, cpriv->top_proto);
		data_set(evt_data[analyzer_eap_common_top_proto]);
	}

	if (ptype_copy(evt_data[analyzer_eap_common_identifier].value, evt_req_data[evt_eap_common_identifier].value) != POM_OK)
		return POM_ERR;
	data_set(evt_data[analyzer_eap_common_identifier]);

	if (!data_is_set(evt_rsp_data[evt_eap_md5_challenge_name]))
		return POM_OK;

	if (ptype_copy(evt_data[analyzer_eap_common_username].value, evt_rsp_data[evt_eap_md5_challenge_name].value) != POM_OK)
		return POM_ERR;
	data_set(evt_data[analyzer_eap_common_username]);

	if (cpriv->evt_result) {
		struct data *evt_res_data = event_get_data(cpriv->evt_result);
		ptype_copy(evt_data[analyzer_eap_common_success].value, evt_res_data[evt_eap_success_failure_success].value);
		data_set(evt_data[analyzer_eap_common_success]);

		event_refcount_dec(cpriv->evt_result);
		cpriv->evt_result = NULL;
	}

	ptime ts = event_get_timestamp(cpriv->evt_response);

	event_refcount_dec(cpriv->evt_request);
	cpriv->evt_request = NULL;
	event_refcount_dec(cpriv->evt_response);
	cpriv->evt_response = NULL;

	return event_process(evt, NULL, 0, ts);
}
Esempio n. 15
0
int analyzer_eap_event_process_begin(struct event *evt, void *obj, struct proto_process_stack *stack, unsigned int stack_index) {

	struct analyzer *analyzer = obj;

	struct analyzer_eap_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_eap_ce_priv *cpriv = conntrack_get_priv(s->ce, analyzer);
	if (!cpriv) {
		cpriv = malloc(sizeof(struct analyzer_eap_ce_priv));
		if (!cpriv) {
			pom_oom(sizeof(struct analyzer_eap_ce_priv));
			goto err;
		}
		memset(cpriv, 0, sizeof(struct analyzer_eap_ce_priv));


		if (conntrack_add_priv(s->ce, analyzer, cpriv, analyzer_eap_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)
					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);
	struct data *evt_data = event_get_data(evt);

	int dir = POM_DIR_UNK;

	if (evt_reg == apriv->evt_md5_challenge) {
		uint8_t code = *PTYPE_UINT8_GETVAL(evt_data[evt_eap_common_code].value);

		if (code == 1) {
			if (!cpriv->evt_request) {
				event_refcount_inc(evt);
				cpriv->evt_request = evt;
			}
			dir = POM_DIR_REV;
		} else if (code == 2) {
			if (!cpriv->evt_response) {
				event_refcount_inc(evt);
				cpriv->evt_response = evt;
			}
			dir = POM_DIR_FWD;
		}


	} else {
		if (!cpriv->evt_result) {
			event_refcount_inc(evt);
			cpriv->evt_result = 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_response && cpriv->evt_result)
		res = analyzer_eap_finalize(apriv, cpriv);

	conntrack_unlock(s->ce);

	return res;

err:
	conntrack_unlock(s->ce);
	return POM_ERR;

}