int registry_uid_assign(struct registry_instance *instance, char* uid) { registry_lock(); struct registry_param *p; for (p = instance->params; p && strcmp(p->name, "uid"); p = p->next); if (!p) { pomlog(POMLOG_ERR "Could not find the uid parameter"); registry_unlock(); return POM_ERR; } uint32_t old_uid = *PTYPE_UINT32_GETVAL(p->value); if (ptype_parse_val(p->value, uid) != POM_OK) { pomlog(POMLOG_ERR "Could not parse the new uid"); registry_unlock(); return POM_ERR; } uint32_t new_uid = *PTYPE_UINT32_GETVAL(p->value); size_t i; for (i = 0; registry_uid_table[i] != old_uid && i < registry_uid_table_size; i++); if (i < registry_uid_table_size) { registry_uid_table[i] = new_uid; } registry_unlock(); return POM_OK; }
static int proto_udp_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 udphdr) > s->plen) return PROTO_INVALID; struct udphdr *hdr = s->pload; uint16_t ulen = ntohs(hdr->uh_ulen); uint16_t sport = ntohs(hdr->uh_sport); uint16_t dport = ntohs(hdr->uh_dport); if (ulen > s->plen) return PROTO_INVALID; PTYPE_UINT16_SETVAL(s->pkt_info->fields_value[proto_udp_field_sport], sport); PTYPE_UINT16_SETVAL(s->pkt_info->fields_value[proto_udp_field_dport], dport); if (conntrack_get(stack, stack_index) != POM_OK) return POM_ERR; int res = POM_ERR; struct proto_process_stack *s_next = &stack[stack_index + 1]; if (s->ce->children) { res = conntrack_delayed_cleanup(s->ce, 0, p->ts); s_next->proto = s->ce->children->ce->proto; } else { uint32_t *conntrack_timeout = PTYPE_UINT32_GETVAL(param_conntrack_timeout); res = conntrack_delayed_cleanup(s->ce, *conntrack_timeout, p->ts); } conntrack_unlock(s->ce); s_next->pload = s->pload + sizeof(struct udphdr); s_next->plen = ulen - sizeof(struct udphdr); if (!s_next->proto) { if (dport == 53 || sport == 53) s_next->proto = proto_dns; if (dport == 69 || sport == 69) s_next->proto = proto_tftp; } return res; }
static int input_pcap_interface_open(struct input *i) { struct input_pcap_priv *p = i->priv; char errbuf[PCAP_ERRBUF_SIZE + 1] = { 0 }; char *interface = PTYPE_STRING_GETVAL(p->tpriv.iface.p_interface); p->p = pcap_create(interface, errbuf); if (!p->p) { pomlog(POMLOG_ERR "Error opening interface %s : %s", interface, errbuf); return POM_ERR; } char *promisc = PTYPE_BOOL_GETVAL(p->tpriv.iface.p_promisc); int err = pcap_set_promisc(p->p, *promisc); if (err) pomlog(POMLOG_WARN "Error while setting promisc mode : %s", pcap_statustostr(err)); uint32_t buff_size = *PTYPE_UINT32_GETVAL(p->tpriv.iface.p_buff_size); err = pcap_set_buffer_size(p->p, buff_size); if (err) pomlog(POMLOG_WARN "Error while setting the pcap buffer size : %s", pcap_statustostr(err)); err = pcap_activate(p->p); if (err < 0) { pomlog(POMLOG_ERR "Error while activating pcap : %s", pcap_statustostr(err)); return POM_ERR; } else if (err > 0) { pomlog(POMLOG_WARN "Warning while activating pcap : %s", pcap_statustostr(err)); } return input_pcap_common_open(i); }
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 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 proto_ipv4_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]; struct ip* hdr = s->pload; unsigned int hdr_len = hdr->ip_hl * 4; if (s->plen < sizeof(struct ip) || // length smaller than header hdr->ip_hl < 5 || // ip header < 5 bytes ntohs(hdr->ip_len) < hdr_len || // datagram size < ip header length ntohs(hdr->ip_len) > s->plen) { // datagram size > given size return PROTO_INVALID; } PTYPE_IPV4_SETADDR(s->pkt_info->fields_value[proto_ipv4_field_src], hdr->ip_src); PTYPE_IPV4_SETADDR(s->pkt_info->fields_value[proto_ipv4_field_dst], hdr->ip_dst); PTYPE_UINT8_SETVAL(s->pkt_info->fields_value[proto_ipv4_field_tos], hdr->ip_tos); PTYPE_UINT8_SETVAL(s->pkt_info->fields_value[proto_ipv4_field_ttl], hdr->ip_ttl); // Handle conntrack stuff if (conntrack_get(stack, stack_index) != POM_OK) return PROTO_ERR; s_next->pload = s->pload + hdr_len; s_next->plen = ntohs(hdr->ip_len) - hdr_len; s_next->proto = proto_get_by_number(s->proto, hdr->ip_p); int res = POM_ERR; if (s->ce->children) { res = conntrack_delayed_cleanup(s->ce, 0, p->ts); } else { uint32_t *conntrack_timeout = PTYPE_UINT32_GETVAL(param_conntrack_timeout); res = conntrack_delayed_cleanup(s->ce, *conntrack_timeout, p->ts); } if (res == POM_ERR) { conntrack_unlock(s->ce); return PROTO_ERR; } uint16_t frag_off = ntohs(hdr->ip_off); // Check if packet is fragmented and need more handling if (frag_off & IP_DONT_FRAG) { conntrack_unlock(s->ce); return PROTO_OK; // Nothing to do } if (!(frag_off & IP_MORE_FRAG) && !(frag_off & IP_OFFSET_MASK)) { conntrack_unlock(s->ce); return PROTO_OK; // Nothing to do, full packet } uint16_t offset = (frag_off & IP_OFFSET_MASK) << 3; size_t frag_size = ntohs(hdr->ip_len) - (hdr->ip_hl * 4); // Ignore invalid fragments if (frag_size > 0xFFFF) { conntrack_unlock(s->ce); return PROTO_INVALID; } if (frag_size > s->plen + hdr_len) { conntrack_unlock(s->ce); return PROTO_INVALID; } // Account for one more fragment registry_perf_inc(perf_frags, 1); struct proto_ipv4_fragment *tmp = s->ce->priv; // Let's find the right buffer for (; tmp && tmp->id != hdr->ip_id; tmp = tmp->next); if (!tmp) { // Buffer not found, create it tmp = malloc(sizeof(struct proto_ipv4_fragment)); if (!tmp) { pom_oom(sizeof(struct proto_ipv4_fragment)); conntrack_unlock(s->ce); return PROTO_ERR; } memset(tmp, 0, sizeof(struct proto_ipv4_fragment)); tmp->t = conntrack_timer_alloc(s->ce, proto_ipv4_fragment_cleanup, tmp); if (!tmp->t) { conntrack_unlock(s->ce); free(tmp); return PROTO_ERR; } tmp->id = hdr->ip_id; if (!s_next->proto) { // Set processed flag so no attempt to process this will be done tmp->flags |= PROTO_IPV4_FLAG_PROCESSED; conntrack_unlock(s->ce); conntrack_timer_cleanup(tmp->t); free(tmp); return PROTO_STOP; } tmp->multipart = packet_multipart_alloc(s_next->proto, 0); if (!tmp->multipart) { conntrack_unlock(s->ce); conntrack_timer_cleanup(tmp->t); free(tmp); return PROTO_ERR; } tmp->next = s->ce->priv; if (tmp->next) tmp->next->prev = tmp; s->ce->priv = tmp; } // Fragment was already handled if (tmp->flags & PROTO_IPV4_FLAG_PROCESSED) { conntrack_unlock(s->ce); registry_perf_inc(perf_frags_dropped, 1); return PROTO_STOP; } // Add the fragment if (packet_multipart_add_packet(tmp->multipart, p, offset, frag_size, (s->pload - (void*)p->buff) + (hdr->ip_hl * 4)) != POM_OK) { conntrack_unlock(s->ce); packet_multipart_cleanup(tmp->multipart); conntrack_timer_cleanup(tmp->t); free(tmp); return PROTO_ERR; } tmp->count++; // Schedule the timeout for the fragment uint32_t *frag_timeout = PTYPE_UINT32_GETVAL(param_frag_timeout); conntrack_timer_queue(tmp->t, *frag_timeout, p->ts); if (!(frag_off & IP_MORE_FRAG)) tmp->flags |= PROTO_IPV4_FLAG_GOT_LAST; if ((tmp->flags & PROTO_IPV4_FLAG_GOT_LAST) && !tmp->multipart->gaps) tmp->flags |= PROTO_IPV4_FLAG_PROCESSED; conntrack_unlock(s->ce); if ((tmp->flags & PROTO_IPV4_FLAG_PROCESSED)) { int res = packet_multipart_process(tmp->multipart, stack, stack_index + 1); tmp->multipart = NULL; // Multipart will be cleared automatically if (res == PROTO_ERR) { return PROTO_ERR; } else if (res == PROTO_INVALID) { registry_perf_inc(perf_frags_dropped, tmp->count); } else { registry_perf_inc(perf_reassembled_pkts, 1); } } return PROTO_STOP; // Stop processing the packet }
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; }