示例#1
0
/*
 * npfctl_table: add, remove or query entries in the specified table.
 *
 * For maximum performance, interface is avoiding proplib(3)'s overhead.
 */
int
npfctl_table(void *data)
{
	npf_ioctl_table_t *nct = data;
	npf_tableset_t *tblset;
	int error;

	npf_core_enter(); /* XXXSMP */
	tblset = npf_core_tableset();
	switch (nct->nct_action) {
	case NPF_IOCTL_TBLENT_ADD:
		error = npf_table_insert(tblset, nct->nct_tid,
		    nct->nct_alen, &nct->nct_addr, nct->nct_mask);
		break;
	case NPF_IOCTL_TBLENT_REM:
		error = npf_table_remove(tblset, nct->nct_tid,
		    nct->nct_alen, &nct->nct_addr, nct->nct_mask);
		break;
	default:
		error = npf_table_lookup(tblset, nct->nct_tid,
		    nct->nct_alen, &nct->nct_addr);
	}
	npf_core_exit(); /* XXXSMP */
	return error;
}
示例#2
0
/*
 * npfctl_sessions_load: import a list of sessions, reconstruct them and load.
 */
int
npfctl_sessions_load(u_long cmd, void *data)
{
	const struct plistref *pref = data;
	npf_sehash_t *sehasht = NULL;
	prop_dictionary_t sesdict, sedict;
	prop_object_iterator_t it;
	prop_array_t selist;
	int error;

	/* Retrieve the dictionary containing session and NAT policy lists. */
	error = prop_dictionary_copyin_ioctl(pref, cmd, &sesdict);
	if (error)
		return error;

	/*
	 * Note: session objects contain the references to the NAT policy
	 * entries.  Therefore, no need to directly access it.
	 */
	selist = prop_dictionary_get(sesdict, "session-list");
	if (prop_object_type(selist) != PROP_TYPE_ARRAY) {
		error = EINVAL;
		goto fail;
	}

	/* Create a session hash table. */
	sehasht = sess_htable_create();
	if (sehasht == NULL) {
		error = ENOMEM;
		goto fail;
	}

	/*
	 * Iterate through and construct each session.
	 */
	error = 0;
	it = prop_array_iterator(selist);
	npf_core_enter();
	while ((sedict = prop_object_iterator_next(it)) != NULL) {
		/* Session - dictionary. */
		if (prop_object_type(sedict) != PROP_TYPE_DICTIONARY) {
			error = EINVAL;
			goto fail;
		}
		/* Construct and insert real session structure. */
		error = npf_session_restore(sehasht, sedict);
		if (error) {
			goto fail;
		}
	}
	npf_core_exit();
	sess_htable_reload(sehasht);
fail:
	prop_object_release(selist);
	if (error && sehasht) {
		/* Destroy session table. */
		sess_htable_destroy(sehasht);
	}
	return error;
}
示例#3
0
int
npfctl_remove_rule(u_long cmd, void *data)
{
	struct plistref *pref = data;
	prop_dictionary_t dict, errdict;
	prop_object_t obj;
	const char *name;
	int error, numrules;

	/* Retrieve and construct the rule. */
	error = prop_dictionary_copyin_ioctl(pref, cmd, &dict);
	if (error) {
		return error;
	}

	/* Dictionary for error reporting. */
	errdict = prop_dictionary_create();

	obj = prop_dictionary_get(dict, "name");
	name = prop_string_cstring_nocopy(obj);
	npf_rule_t *rl;
	error = npf_mk_singlerule(dict, prop_array_create(), &rl, errdict);

	npf_core_enter();
	numrules = npf_named_ruleset_remove(name, npf_core_ruleset(), rl);
	npf_core_exit();
	prop_object_release(dict);

	/* Error report. */
	prop_dictionary_set_int32(errdict, "errno", error);
	prop_dictionary_set_int32(errdict, "numrules", numrules);
	prop_dictionary_copyout_ioctl(pref, cmd, errdict);
	prop_object_release(errdict);
	return error;
}
示例#4
0
int
npfctl_getconf(u_long cmd, void *data)
{
	struct plistref *pref = data;
	prop_dictionary_t npf_dict;
	int error;

	npf_core_enter();
	npf_dict = npf_core_dict();
	prop_dictionary_set_bool(npf_dict, "active", npf_pfil_registered_p());
	error = prop_dictionary_copyout_ioctl(pref, cmd, npf_dict);
	npf_core_exit();

	return error;
}
示例#5
0
static int
npf_insert_nat_rule(prop_dictionary_t natdict, prop_dictionary_t errdict) {
	int error;
	npf_natpolicy_t *np;
	npf_rule_t *rl;
	
	printf("npf_insert_nat_rule\n");
	if (prop_object_type(natdict) != PROP_TYPE_DICTIONARY) {
		printf("rossz tipus!\n");
		NPF_ERR_DEBUG(errdict);
		return EINVAL;
	}

	/*
	 * NAT policies are standard rules, plus additional
	 * information for translation.  Make a rule.
	 */
	error = npf_mk_singlerule(natdict, NULL, &rl, errdict);
	if (error) {
		printf("hiba a mksinglerule alatt\n");
		return error;
	}

	npf_core_enter();
	printf("most ruleset inserteljuk\n");
	npf_ruleset_insert(npf_core_natset(), rl);

	/* Allocate a new NAT policy and assign to the rule. */
	np = npf_nat_newpolicy(natdict, npf_core_natset());
	if (np == NULL) {
		printf("hiba a newpolicy alatt\n");
		NPF_ERR_DEBUG(errdict);
		return ENOMEM;
	}
	npf_rule_setnat(rl, np);

	npf_core_exit();
	
	return 0;
}
示例#6
0
/*
 * npf_packet_handler: main packet handling routine for layer 3.
 *
 * Note: packet flow and inspection logic is in strict order.
 */
int
npf_packet_handler(void *arg, struct mbuf **mp, ifnet_t *ifp, int di)
{
	nbuf_t *nbuf = *mp;
	npf_cache_t npc;
	npf_session_t *se;
	npf_ruleset_t *rlset;
	npf_rule_t *rl;
	npf_rproc_t *rp;
	int error, retfl;
	int decision;

	/*
	 * Initialise packet information cache.
	 * Note: it is enough to clear the info bits.
	 */
	npc.npc_info = 0;
	decision = NPF_DECISION_BLOCK;
	error = 0;
	retfl = 0;
	rp = NULL;

	/* Cache everything.  Determine whether it is an IP fragment. */
	if (npf_cache_all(&npc, nbuf) & NPC_IPFRAG) {
		/*
		 * Pass to IPv4 or IPv6 reassembly mechanism.
		 */
		error = EINVAL;

		if (npf_iscached(&npc, NPC_IP4)) {
			struct ip *ip = nbuf_dataptr(*mp);
			error = ip_reass_packet(mp, ip);
		} else if (npf_iscached(&npc, NPC_IP6)) {
#ifdef INET6
			/*
			 * Note: ip6_reass_packet() offset is the start of
			 * the fragment header.
			 */
			const u_int hlen = npf_cache_hlen(&npc);
			error = ip6_reass_packet(mp, hlen);
#endif
		}
		if (error) {
			npf_stats_inc(NPF_STAT_REASSFAIL);
			se = NULL;
			goto out;
		}
		if (*mp == NULL) {
			/* More fragments should come; return. */
			npf_stats_inc(NPF_STAT_FRAGMENTS);
			return 0;
		}

		/*
		 * Reassembly is complete, we have the final packet.
		 * Cache again, since layer 4 data is accessible now.
		 */
		nbuf = (nbuf_t *)*mp;
		npc.npc_info = 0;

		if (npf_cache_all(&npc, nbuf) & NPC_IPFRAG) {
			se = NULL;
			goto out;
		}
		npf_stats_inc(NPF_STAT_REASSEMBLY);
	}

	/* Inspect the list of sessions. */
	se = npf_session_inspect(&npc, nbuf, ifp, di, &error);

	/* If "passing" session found - skip the ruleset inspection. */
	if (se && npf_session_pass(se, &rp)) {
		npf_stats_inc(NPF_STAT_PASS_SESSION);
		KASSERT(error == 0);
		goto pass;
	}
	if (error) {
		goto block;
	}

	/* Acquire the lock, inspect the ruleset using this packet. */
	npf_core_enter();
	rlset = npf_core_ruleset();
	rl = npf_ruleset_inspect(&npc, nbuf, rlset, ifp, di, NPF_LAYER_3);
	if (rl == NULL) {
		bool default_pass = npf_default_pass();
		npf_core_exit();

		if (default_pass) {
			npf_stats_inc(NPF_STAT_PASS_DEFAULT);
			goto pass;
		}
		npf_stats_inc(NPF_STAT_BLOCK_DEFAULT);
		goto block;
	}

	/*
	 * Get the rule procedure (acquires a reference) for assocation
	 * with a session (if any) and execution.
	 */
	KASSERT(rp == NULL);
	rp = npf_rule_getrproc(rl);

	/* Apply the rule, release the lock. */
	error = npf_rule_apply(&npc, nbuf, rl, &retfl);
	if (error) {
		npf_stats_inc(NPF_STAT_BLOCK_RULESET);
		goto block;
	}
	npf_stats_inc(NPF_STAT_PASS_RULESET);

	/*
	 * Establish a "pass" session, if required.  Just proceed, if session
	 * creation fails (e.g. due to unsupported protocol).
	 *
	 * Note: the reference on the rule procedure is transfered to the
	 * session.  It will be released on session destruction.
	 */
	if ((retfl & NPF_RULE_STATEFUL) != 0 && !se) {
		se = npf_session_establish(&npc, nbuf, ifp, di);
		if (se) {
			npf_session_setpass(se, rp);
		}
	}
pass:
	decision = NPF_DECISION_PASS;
	KASSERT(error == 0);
	/*
	 * Perform NAT.
	 */
	error = npf_do_nat(&npc, se, nbuf, ifp, di);
block:
	/*
	 * Execute the rule procedure, if any is associated.
	 * It may reverse the decision from pass to block.
	 */
	if (rp) {
		npf_rproc_run(&npc, nbuf, rp, &decision);
	}
out:
	/*
	 * Release the reference on a session.  Release the reference on a
	 * rule procedure only if there was no association.
	 */
	if (se) {
		npf_session_release(se);
	} else if (rp) {
		npf_rproc_release(rp);
	}

	/* Pass the packet if decided and there is no error. */
	if (decision == NPF_DECISION_PASS && !error) {
		/*
		 * XXX: Disable for now, it will be set accordingly later,
		 * for optimisations (to reduce inspection).
		 */
		(*mp)->m_flags &= ~M_CANFASTFWD;
		return 0;
	}

	/*
	 * Block the packet.  ENETUNREACH is used to indicate blocking.
	 * Depending on the flags and protocol, return TCP reset (RST) or
	 * ICMP destination unreachable.
	 */
	if (retfl && npf_return_block(&npc, nbuf, retfl)) {
		*mp = NULL;
	}

	if (!error) {
		error = ENETUNREACH;
	}

	if (*mp) {
		m_freem(*mp);
		*mp = NULL;
	}
	return error;
}