struct conntrack_entry *conntrack_find(struct conntrack_list *lst, struct ptype *fwd_value, struct ptype *rev_value, struct conntrack_entry *parent) { if (!fwd_value) return NULL; for (; lst; lst = lst->next) { struct conntrack_entry *ce = lst->ce; // Check the parent conntrack if (ce->parent && ce->parent->ce != parent) continue; // Check the forward value if (!ptype_compare_val(PTYPE_OP_EQ, ce->fwd_value, fwd_value)) continue; // Check the reverse value if present if (ce->rev_value) { if (!rev_value) { // Conntrack_entry has a reverse value but none was provided continue; } if (!ptype_compare_val(PTYPE_OP_EQ, ce->rev_value, rev_value)) continue; } else if (rev_value) { // Conntrack entry does not have a reverse value but one was provided continue; } return ce; } // No conntrack entry found return NULL; }
int proto_process(struct packet *p, struct proto_process_stack *stack, unsigned int stack_index) { struct proto_process_stack *s = &stack[stack_index]; struct proto *proto = s->proto; if (!proto || !proto->info->process) return PROTO_ERR; int res = proto->info->process(proto->priv, p, stack, stack_index); registry_perf_inc(proto->perf_pkts, 1); registry_perf_inc(proto->perf_bytes, s->plen); if (res != PROTO_OK) return res; // Process the expectations ! pom_rwlock_rlock(&proto->expectation_lock); struct proto_expectation *e = proto->expectations; while (e) { int expt_dir = POM_DIR_UNK; struct proto_expectation_stack *es = e->tail; struct ptype *fwd_value = s->pkt_info->fields_value[s->proto->info->ct_info->fwd_pkt_field_id]; struct ptype *rev_value = s->pkt_info->fields_value[s->proto->info->ct_info->rev_pkt_field_id]; if ((!es->fields[POM_DIR_FWD] || ptype_compare_val(PTYPE_OP_EQ, es->fields[POM_DIR_FWD], fwd_value)) && (!es->fields[POM_DIR_REV] || ptype_compare_val(PTYPE_OP_EQ, es->fields[POM_DIR_REV], rev_value))) { // Expectation matched the forward direction expt_dir = POM_DIR_FWD; } else if ((!es->fields[POM_DIR_FWD] || ptype_compare_val(PTYPE_OP_EQ, es->fields[POM_DIR_FWD], rev_value)) && (!es->fields[POM_DIR_REV] || ptype_compare_val(PTYPE_OP_EQ, es->fields[POM_DIR_REV], fwd_value))) { // Expectation matched the reverse direction expt_dir = POM_DIR_REV; } if (expt_dir == POM_DIR_UNK) { // Expectation not matched e = e->next; continue; } es = es->prev; int stack_index_tmp = stack_index - 1; while (es) { struct proto_process_stack *s_tmp = &stack[stack_index_tmp]; if (s_tmp->proto != es->proto) { e = e->next; continue; } fwd_value = s_tmp->pkt_info->fields_value[s_tmp->proto->info->ct_info->fwd_pkt_field_id]; rev_value = s_tmp->pkt_info->fields_value[s_tmp->proto->info->ct_info->rev_pkt_field_id]; if (expt_dir == POM_DIR_FWD) { if ((es->fields[POM_DIR_FWD] && !ptype_compare_val(PTYPE_OP_EQ, es->fields[POM_DIR_FWD], fwd_value)) || (es->fields[POM_DIR_REV] && !ptype_compare_val(PTYPE_OP_EQ, es->fields[POM_DIR_REV], rev_value))) { e = e->next; continue; } } else { if ((es->fields[POM_DIR_FWD] && !ptype_compare_val(PTYPE_OP_EQ, es->fields[POM_DIR_FWD], rev_value)) || (es->fields[POM_DIR_REV] && !ptype_compare_val(PTYPE_OP_EQ, es->fields[POM_DIR_REV], fwd_value))) { e = e->next; continue; } } es = es->prev; stack_index_tmp--; } // Expectation matched ! // Relock with write access pom_rwlock_unlock(&proto->expectation_lock); pom_rwlock_wlock(&proto->expectation_lock); debug_expectation("Expectation %p matched !", e); // Remove it from the list if (e->next) e->next->prev = e->prev; if (e->prev) e->prev->next = e->next; else proto->expectations = e->next; struct proto_process_stack *s_next = &stack[stack_index + 1]; s_next->proto = e->proto; if (conntrack_get_unique_from_parent(stack, stack_index + 1) != POM_OK) { proto_expectation_cleanup(e); return PROTO_ERR; } s_next->ce->priv = e->priv; if (conntrack_session_bind(s_next->ce, e->session)) { proto_expectation_cleanup(e); return PROTO_ERR; } registry_perf_dec(e->proto->perf_expt_pending, 1); registry_perf_inc(e->proto->perf_expt_matched, 1); proto_expectation_cleanup(e); conntrack_unlock(s_next->ce); break; } pom_rwlock_unlock(&proto->expectation_lock); return res; }
int registry_config_save(char *config_name) { if (strlen(config_name) >= REGISTRY_CONFIG_NAME_MAX) { pomlog(POMLOG_ERR "Configuration name too long, max %u characters.", REGISTRY_CONFIG_NAME_MAX); return POM_ERR; } struct dataset_query *dsq_config_list = NULL, *dsq_config = NULL; struct datastore *sys_dstore = system_datastore(); if (!sys_dstore) return POM_ERR; struct datastore_connection *dc = datastore_connection_new(sys_dstore); if (!dc) return POM_ERR; dsq_config_list = datastore_dataset_query_open(sys_dstore, REGISTRY_CONFIG_LIST, registry_config_list_dataset_template, dc); if (!dsq_config_list) goto err; if (datastore_dataset_query_set_string_condition(dsq_config_list, 0, PTYPE_OP_EQ, config_name) != POM_OK) goto err; dsq_config = datastore_dataset_query_open(sys_dstore, REGISTRY_CONFIG, registry_config_dataset_template, dc); if (!dsq_config) goto err; if (datastore_transaction_begin(dc) != POM_OK) goto err; // Find out if we already have a config by that name int res = datastore_dataset_read_single(dsq_config_list); if (res == DATASET_QUERY_MORE) { // Delete existing stuff about this config if (datastore_dataset_query_set_uint64_condition(dsq_config, 0, PTYPE_OP_EQ, dsq_config_list->data_id) != POM_OK) goto err; if (datastore_dataset_delete(dsq_config_list) != DATASET_QUERY_OK) goto err; if (datastore_dataset_delete(dsq_config) != DATASET_QUERY_OK) goto err; } if (res < 0) goto err; // Add the config to the config list PTYPE_STRING_SETVAL(dsq_config_list->values[0].value, config_name); PTYPE_TIMESTAMP_SETVAL(dsq_config_list->values[1].value, pom_gettimeofday()); if (datastore_dataset_write(dsq_config_list) != DATASET_QUERY_OK) goto err; PTYPE_UINT64_SETVAL(dsq_config->values[0].value, dsq_config_list->data_id); registry_lock(); struct registry_class *cls; // Browse each class for (cls = registry_head; cls; cls = cls->next) { // Browse each instance of the class struct registry_instance *inst; for (inst = cls->instances; inst; inst = inst->next) { // Don't add the instance if it's not added by the user if (cls->instance_add) { // The system datastore will always exist if (inst == sys_dstore->reg_instance) continue; char *buff = malloc(strlen(cls->name) + 1 + strlen(inst->name) + 1); if (!buff) { pom_oom(strlen(cls->name) + 1 + strlen(inst->name) + 1); goto err_locked; } strcpy(buff, cls->name); strcat(buff, "."); strcat(buff, inst->name); PTYPE_STRING_SETVAL_P(dsq_config->values[1].value, buff); struct registry_param *p; for (p = inst->params; p && strcmp(p->name, "type"); p = p->next); if (p) { dsq_config->values[2].is_null = 0; char *type = PTYPE_STRING_GETVAL(p->value); PTYPE_STRING_SETVAL(dsq_config->values[2].value, type); } else { dsq_config->values[2].is_null = 1; } PTYPE_UINT8_SETVAL(dsq_config->values[3].value, registry_config_instance); if (datastore_dataset_write(dsq_config) != DATASET_QUERY_OK) goto err_locked; } // Browse the parametrers and add the non default ones struct registry_param *param; for (param = inst->params; param; param = param->next) { // Check if the parameter value is not the default one anymore if (param->default_value) { struct ptype *defval = ptype_alloc_from(param->value); if (!defval) goto err_locked; if (ptype_parse_val(defval, param->default_value) != POM_OK) { pomlog(POMLOG_ERR "Unable to parse default value !"); ptype_cleanup(defval); goto err_locked; } if (ptype_compare_val(PTYPE_OP_EQ, param->value, defval)) { // Param still has the default value, do nothing ptype_cleanup(defval); continue; } ptype_cleanup(defval); } char *buff = malloc(strlen(cls->name) + 1 + strlen(inst->name) + 1 + strlen(param->name) + 1); if (!buff) { pom_oom(strlen(cls->name) + 1 + strlen(inst->name) + 1 + strlen(param->name) + 1); goto err_locked; } strcpy(buff, cls->name); strcat(buff, "."); strcat(buff, inst->name); strcat(buff, "."); strcat(buff, param->name); PTYPE_STRING_SETVAL_P(dsq_config->values[1].value, buff); char *value = ptype_print_val_alloc(param->value, NULL); if (!value) goto err_locked; dsq_config->values[2].is_null = 0; PTYPE_STRING_SETVAL_P(dsq_config->values[2].value, value); PTYPE_UINT8_SETVAL(dsq_config->values[3].value, registry_config_instance_param); if (datastore_dataset_write(dsq_config) != DATASET_QUERY_OK) goto err_locked; } } } registry_config_serial++; registry_serial++; xmlrcpcmd_serial_inc(); registry_unlock(); if (datastore_transaction_commit(dc) != POM_OK) goto err; datastore_dataset_query_cleanup(dsq_config_list); datastore_dataset_query_cleanup(dsq_config); datastore_connection_release(dc); pomlog("Registry configuration saved as \"%s\"", config_name); return POM_OK; err_locked: registry_unlock(); err: if (dsq_config_list) datastore_dataset_query_cleanup(dsq_config_list); if (dsq_config) datastore_dataset_query_cleanup(dsq_config); if (dc) { datastore_transaction_rollback(dc); datastore_connection_release(dc); } return POM_ERR; }
int proto_process(struct packet *p, struct proto_process_stack *stack, unsigned int stack_index) { struct proto_process_stack *s = &stack[stack_index]; struct proto *proto = s->proto; if (!proto || !proto->info->process) return PROTO_ERR; int res = proto->info->process(proto->priv, p, stack, stack_index); registry_perf_inc(proto->perf_pkts, 1); registry_perf_inc(proto->perf_bytes, s->plen); if (res != PROTO_OK) return res; int matched = 0; // Process the expectations ! pom_rwlock_rlock(&proto->expectation_lock); struct proto_expectation *e = NULL; for (e = proto->expectations; e; e = e->next) { if (e->flags & PROTO_EXPECTATION_FLAG_MATCHED) { // Another thread already matched the expectation, continue continue; } // Bit one means it matches the forward direction // Bit two means it matches the reverse direction int expt_dir = 3; struct proto_expectation_stack *es = e->tail; int stack_index_tmp = stack_index; while (es) { struct proto_process_stack *s_tmp = &stack[stack_index_tmp]; if (s_tmp->proto != es->proto) { expt_dir = 0; break; } struct ptype *fwd_value = s_tmp->pkt_info->fields_value[s_tmp->proto->info->ct_info->fwd_pkt_field_id]; struct ptype *rev_value = s_tmp->pkt_info->fields_value[s_tmp->proto->info->ct_info->rev_pkt_field_id]; if (expt_dir & 1) { if ((es->fields[POM_DIR_FWD] && !ptype_compare_val(PTYPE_OP_EQ, es->fields[POM_DIR_FWD], fwd_value)) || (es->fields[POM_DIR_REV] && !ptype_compare_val(PTYPE_OP_EQ, es->fields[POM_DIR_REV], rev_value))) { expt_dir &= ~1; // It doesn't match in the forward direction } } if (expt_dir & 2) { if ((es->fields[POM_DIR_FWD] && !ptype_compare_val(PTYPE_OP_EQ, es->fields[POM_DIR_FWD], rev_value)) || (es->fields[POM_DIR_REV] && !ptype_compare_val(PTYPE_OP_EQ, es->fields[POM_DIR_REV], fwd_value))) { expt_dir &= ~2; } } if (!expt_dir) break; es = es->prev; stack_index_tmp--; } if (expt_dir) { // It matched if (!(__sync_fetch_and_or(&e->flags, PROTO_EXPECTATION_FLAG_MATCHED) & PROTO_EXPECTATION_FLAG_MATCHED)) { // Something matched matched++; } } } pom_rwlock_unlock(&proto->expectation_lock); if (!matched) return POM_OK; // At least one expectation matched ! debug_expectation("%u expectation matched !", matched); // Relock with write access pom_rwlock_wlock(&proto->expectation_lock); e = proto->expectations; while (e) { struct proto_expectation *cur = e; e = e->next; if (!(cur->flags & PROTO_EXPECTATION_FLAG_MATCHED)) continue; // Remove the expectation from the conntrack if (cur->next) cur->next->prev = cur->prev; if (cur->prev) cur->prev->next = cur->next; else proto->expectations = cur->next; // Remove matched and queued flags __sync_fetch_and_and(&cur->flags, ~(PROTO_EXPECTATION_FLAG_MATCHED | PROTO_EXPECTATION_FLAG_QUEUED)); struct proto_process_stack *s_next = &stack[stack_index + 1]; s_next->proto = cur->proto; if (conntrack_get_unique_from_parent(stack, stack_index + 1) != POM_OK) { proto_expectation_cleanup(cur); continue; } if (!s_next->ce->priv) { s_next->ce->priv = cur->priv; // Prevent cleanup of private data while cleaning the expectation cur->priv = NULL; } if (cur->session) { if (conntrack_session_bind(s_next->ce, cur->session)) { proto_expectation_cleanup(cur); continue; } } registry_perf_dec(cur->proto->perf_expt_pending, 1); registry_perf_inc(cur->proto->perf_expt_matched, 1); if (cur->match_callback) { // Call the callback with the conntrack locked cur->match_callback(cur, cur->callback_priv, s_next->ce); // Nullify callback_priv so it doesn't get cleaned up cur->callback_priv = NULL; } if (cur->expiry) { // The expectation was added using 'add_and_cleanup' function proto_expectation_cleanup(cur); } conntrack_unlock(s_next->ce); } pom_rwlock_unlock(&proto->expectation_lock); return res; }