static int analyzer_docsis_event_listeners_notify(void *obj, struct event_reg *evt_reg, int has_listeners) { struct analyzer *analyzer = obj; struct analyzer_docsis_priv *priv = analyzer->priv; if (has_listeners) { // Check if we are already listening if (priv->pkt_listener) return POM_OK; if (!priv->filter) { priv->filter = packet_filter_compile("docsis_mgmt.type > 3"); if (!priv->filter) { pomlog(POMLOG_ERR "Error while building filter"); return POM_ERR; } } priv->pkt_listener = proto_packet_listener_register(proto_get("docsis_mgmt"), 0, obj, analyzer_docsis_pkt_process, priv->filter); if (!priv->pkt_listener) return POM_ERR; } else { if (event_has_listener(priv->evt_cm_new) || event_has_listener(priv->evt_cm_reg_status)) return POM_OK; if (proto_packet_listener_unregister(priv->pkt_listener) != POM_OK) return POM_ERR; priv->pkt_listener = NULL; } return POM_OK; }
static int analyzer_arp_event_listeners_notify(void *obj, struct event_reg *evt_reg, int has_listeners) { struct analyzer *analyzer = obj; struct analyzer_arp_priv *priv = analyzer->priv; if (has_listeners) { // Check if we are already listening if (priv->pkt_listener) return POM_OK; priv->pkt_listener = proto_packet_listener_register(proto_get("arp"), 0, obj, analyzer_arp_pkt_process); if (!priv->pkt_listener) return POM_ERR; } else { // Check if there is still an event being listened if (event_has_listener(priv->evt_new_sta) || event_has_listener(priv->evt_sta_changed)) return POM_OK; if (proto_packet_listener_unregister(priv->pkt_listener) != POM_OK) return POM_ERR; priv->pkt_listener = NULL; } return POM_OK; }
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; }
static int analyzer_smtp_event_listeners_notify(void *obj, struct event_reg *evt_reg, int has_listeners) { struct analyzer *analyzer = obj; struct analyzer_smtp_priv *priv = analyzer->priv; if (evt_reg == priv->evt_msg) { if (has_listeners) { priv->pkt_listener = proto_packet_listener_register(proto_get("smtp"), PROTO_PACKET_LISTENER_PLOAD_ONLY, obj, analyzer_smtp_pkt_process, NULL); if (!priv->pkt_listener) return POM_ERR; } else { if (proto_packet_listener_unregister(priv->pkt_listener) != POM_OK) return POM_ERR; priv->pkt_listener = NULL; } } if (!priv->listening && (event_has_listener(priv->evt_msg) || event_has_listener(priv->evt_auth))) { if (event_listener_register(priv->evt_cmd, analyzer, analyzer_smtp_event_process_begin, analyzer_smtp_event_process_end) != POM_OK) { return POM_ERR; } else if (event_listener_register(priv->evt_reply, analyzer, analyzer_smtp_event_process_begin, analyzer_smtp_event_process_end) != POM_OK) { event_listener_unregister(priv->evt_cmd, analyzer); return POM_ERR; } priv->listening = 1; } else if (priv->listening && !event_has_listener(priv->evt_msg) && !event_has_listener(priv->evt_auth)) { event_listener_unregister(priv->evt_cmd, analyzer); event_listener_unregister(priv->evt_reply, analyzer); priv->listening = 0; } return POM_OK; }
static int analyzer_docsis_event_listeners_notify(void *obj, struct event_reg *evt_reg, int has_listeners) { struct analyzer *analyzer = obj; struct analyzer_docsis_priv *priv = analyzer->priv; if (has_listeners) { // Check if we are already listening if (priv->pkt_listener) return POM_OK; if (!priv->filter) { priv->filter = filter_proto_build("docsis_mgmt", "type", PTYPE_OP_GT, "3"); if (!priv->filter) { pomlog(POMLOG_ERR "Error while building filter"); return POM_ERR; } } priv->pkt_listener = proto_packet_listener_register(proto_get("docsis_mgmt"), 0, obj, analyzer_docsis_pkt_process); if (!priv->pkt_listener) return POM_ERR; // Filter out useless broadcast docsis_mgmt packets proto_packet_listener_set_filter(priv->pkt_listener, priv->filter); } else { if (event_has_listener(priv->evt_cm_new) || event_has_listener(priv->evt_cm_reg_status)) return POM_OK; if (proto_packet_listener_unregister(priv->pkt_listener) != POM_OK) return POM_ERR; priv->pkt_listener = NULL; } return POM_OK; }
int analyzer_eap_event_listeners_notify(void *obj, struct event_reg *evt_reg, int has_listeners) { struct analyzer *analyzer = obj; struct analyzer_eap_priv *priv = analyzer->priv; if (event_has_listener(priv->evt_md5_auth)) { if (event_listener_register(priv->evt_md5_challenge, analyzer, analyzer_eap_event_process_begin, NULL) != POM_OK) { return POM_ERR; } else if (event_listener_register(priv->evt_success_failure, analyzer, analyzer_eap_event_process_begin, NULL) != POM_OK) { event_listener_unregister(priv->evt_md5_challenge, analyzer); return POM_ERR; } } else { if (event_listener_unregister(priv->evt_md5_challenge, analyzer) != POM_OK || event_listener_unregister(priv->evt_success_failure, analyzer) != POM_OK) return POM_ERR; } return POM_OK; }
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; }
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; }
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; }
static int analyzer_arp_pkt_process(void *obj, struct packet *p, struct proto_process_stack *stack, unsigned int stack_index) { struct analyzer *analyzer = obj; struct analyzer_arp_priv *priv = analyzer->priv; struct proto_process_stack *s = &stack[stack_index]; struct proto_process_stack *s_prev = &stack[stack_index - 1]; struct in_addr arp_ip = PTYPE_IPV4_GETADDR(s->pkt_info->fields_value[proto_arp_field_sender_proto_addr]); // Discard bogon 0.0.0.0 if (!arp_ip.s_addr) return POM_OK; // Find that IP in the table uint32_t id = arp_ip.s_addr & ANALYZER_ARP_HOST_MASK; char *arp_mac = PTYPE_MAC_GETADDR(s->pkt_info->fields_value[proto_arp_field_sender_hw_addr]); uint16_t vlan = 0; if (s_prev->proto == priv->proto_vlan) vlan = *PTYPE_UINT16_GETVAL(s_prev->pkt_info->fields_value[proto_vlan_field_vid]); pom_mutex_lock(&priv->lock); struct analyzer_arp_host *host; for (host = priv->hosts[id]; host; host = host->next) { if (host->ip.s_addr == arp_ip.s_addr && host->vlan == vlan) break; } if (!host) { // Host not found ! host = malloc(sizeof(struct analyzer_arp_host)); if (!host) { pom_mutex_unlock(&priv->lock); pom_oom(sizeof(struct analyzer_arp_host)); return POM_ERR; } memset(host, 0, sizeof(struct analyzer_arp_host)); host->ip.s_addr = arp_ip.s_addr; memcpy(host->mac, arp_mac, sizeof(host->mac)); host->vlan = vlan; host->next = priv->hosts[id]; if (host->next) host->next->prev = host; priv->hosts[id] = host; pom_mutex_unlock(&priv->lock); // Announce the new station if (event_has_listener(priv->evt_new_sta)) { struct event *evt = event_alloc(priv->evt_new_sta); if (!evt) return POM_ERR; struct data *evt_data = evt->data; ptype_copy(evt_data[analyzer_arp_new_sta_mac_addr].value, s->pkt_info->fields_value[proto_arp_field_sender_hw_addr]); data_set(evt_data[analyzer_arp_new_sta_mac_addr]); ptype_copy(evt_data[analyzer_arp_new_sta_ip_addr].value, s->pkt_info->fields_value[proto_arp_field_sender_proto_addr]); data_set(evt_data[analyzer_arp_new_sta_ip_addr]); PTYPE_UINT16_SETVAL(evt_data[analyzer_arp_new_sta_vlan].value, vlan); data_set(evt_data[analyzer_arp_new_sta_vlan]); PTYPE_STRING_SETVAL(evt_data[analyzer_arp_new_sta_input].value, p->input->name); data_set(evt_data[analyzer_arp_new_sta_input]); if (event_process(evt, stack, stack_index) != POM_OK) return POM_ERR; } // Nothing else to do return POM_OK; } // Host was found, check mac if (memcmp(host->mac, arp_mac, sizeof(host->mac))) { if (event_has_listener(priv->evt_sta_changed)) { struct event *evt = event_alloc(priv->evt_sta_changed); if (!evt) { pom_mutex_unlock(&priv->lock); return POM_ERR; } struct data *evt_data = evt->data; PTYPE_MAC_SETADDR(evt_data[analyzer_arp_sta_changed_old_mac_addr].value, host->mac); data_set(evt_data[analyzer_arp_sta_changed_old_mac_addr]); ptype_copy(evt_data[analyzer_arp_sta_changed_new_mac_addr].value, s->pkt_info->fields_value[proto_arp_field_sender_hw_addr]); data_set(evt_data[analyzer_arp_sta_changed_new_mac_addr]); ptype_copy(evt_data[analyzer_arp_sta_changed_ip_addr].value, s->pkt_info->fields_value[proto_arp_field_sender_proto_addr]); data_set(evt_data[analyzer_arp_sta_changed_ip_addr]); PTYPE_UINT16_SETVAL(evt_data[analyzer_arp_sta_changed_vlan].value, vlan); data_set(evt_data[analyzer_arp_sta_changed_vlan]); PTYPE_STRING_SETVAL(evt_data[analyzer_arp_sta_changed_input].value, p->input->name); data_set(evt_data[analyzer_arp_sta_changed_input]); if (event_process(evt, stack, stack_index) != POM_OK) { pom_mutex_unlock(&priv->lock); return POM_ERR; } } memcpy(host->mac, arp_mac, sizeof(host->mac)); } pom_mutex_unlock(&priv->lock); return POM_OK; }
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; }