<!-- Domain Policy Module User's Guide -->

<chapter>
	
	<title>&adminguide;</title>
	
	<section id="overview" xreflabel="Overview">
	<title>Overview</title>
	<para>
		The Domain Policy module implements draft-lendl-domain-policy-ddds-02 in
		combination with draft-lendl-speermint-federations-02 and 
		draft-lendl-speermint-technical-policy-00. These drafts
		define <acronym>DNS</acronym> records with which a domain can
		announce its federation memberships. A local database can be
		used to map policy rules to routing policy decisions.
		This database can also contain rules concerning destination
		domains independently of draft-lendl-domain-policy-ddds-02.
	</para>
	<para>
		This module requires a database. No caching is implemented.
	</para>
	</section>

	<section id="dependencies" xreflabel="Dependencies">
	<title>Dependencies</title>
	<para>
		The module depends on the following modules (in the other words the 
		listed modules must be loaded before this module):
		<itemizedlist>
		<listitem>
			<para><emphasis>database</emphasis> -- Any database module</para>
		</listitem>
		</itemizedlist>
	</para>
	</section>

	<section id="exported_parameters" xreflabel="Exported Parameters">
	<title>Exported Parameters</title>
	<section id="param_db_url" xreflabel="db_url">
		<title><varname>db_url</varname> (string)</title>
		<para>
		This is <acronym>URL</acronym> of the database to be used.
		</para>
		<para>
		Default value is 
			<quote>&defaultrodb;</quote>
		</para>
		<example>
		<title>Setting db_url parameter</title>
		<programlisting format="linespecific">
modparam("domainpolicy", "db_url", "postgresql://user:pass@db_host/opensips")
</programlisting>
		</example>
	</section>
	<section id="param_dp_table" xreflabel="dp_table">
		<title><varname>dp_table</varname> (string)</title>
		<para>
		Name of table containing the local support domain policy setup.
		</para>
		<para>
		Default value is <quote>domainpolicy</quote>.
		</para>
		<example>
		<title>Setting dp_table parameter</title>
		<programlisting format="linespecific">
modparam("domainpolicy", "dp_table", "supportedpolicies")
</programlisting>
		</example>
	</section>
	<section id="param_dp_col_rule" xreflabel="dp_col_rule">
		<title><varname>dp_col_rule</varname> (string)</title>
		<para>
		Name of column containing the domain policy rule name which is equal
		to the URI as published in the domain policy NAPTRs.
		</para>
		<para>
		Default value is <quote>rule</quote>.
		</para>
		<example>
		<title>Setting dp_col_rule parameter</title>
		<programlisting format="linespecific">
modparam("domainpolicy", "dp_col_rule", "rules")
</programlisting>
		</example>
	</section>
	<section id="param_dp_col_type" xreflabel="dp_col_type">
		<title><varname>dp_col_type</varname> (string)</title>
		<para>
		Name of column containing the domain policy rule type.
		In the case of federation names, this is "fed". For standard
		referrals according to draft-lendl-speermint-technical-policy-00,
		this is "std". For direct domain lookups, this is "dom".
		</para>
		<para>
		Default value is <quote>type</quote>.
		</para>
		<example>
		<title>Setting dp_col_rule parameter</title>
		<programlisting format="linespecific">
modparam("domainpolicy", "dp_col_type", "type")
</programlisting>
		</example>
	</section>


	<section id="param_dp_col_att" xreflabel="dp_col_att">
		<title><varname>dp_col_att</varname> (string)</title>
		<para>
		Name of column containing the AVP's name. If the rule stored in this
		row triggers, than dp_can_connect() will add an AVP with that name.
		</para>
		<para>
		Default value is <quote>att</quote>.
		</para>
		<example>
		<title>Setting dp_col_att parameter</title>
		<programlisting format="linespecific">
modparam("domainpolicy", "dp_col_att", "attribute")
</programlisting>
		</example>
	</section>
	<section id="param_dp_col_val" xreflabel="dp_col_val">
		<title><varname>dp_col_val</varname> (string)</title>
		<para>
		Name of column containing the value for AVPs created by dp_can_connect().
		</para>
		<para>
		Default value is <quote>val</quote>.
		</para>
		<example>
		<title>Setting dp_col_val parameter</title>
		<programlisting format="linespecific">
modparam("domainpolicy", "dp_col_val", "values")
</programlisting>
		</example>
	</section>
	<section id="param_port_override_avp" xreflabel="port_override_avp">
		<title><varname>port_override_avp</varname> (string)</title>
		<para>
		This parameter defines the name of the AVP where dp_apply_policy() will look
		for an override port number. 
		</para>
		<para>
		Default value is <quote>portoverride</quote>.
		</para>
		<example>
		<title>Setting port_override_avp parameter</title>
		<programlisting format="linespecific">
# string named AVP
modparam("domainpolicy", "port_override_avp", "portoverride")
</programlisting>
		</example>
	</section>
	<section id="param_transport_override_avp" xreflabel="transport_override_avp">
		<title><varname>transport_override_avp</varname> (string)</title>
		<para>
		Name of the AVP which contains the override transport setting. 
		</para>
		<para>
		Default value is <quote>transportoverride</quote>.
		</para>
		<example>
		<title>Setting transport_override_avp parameter</title>
		<programlisting format="linespecific">
# string named AVP
modparam("domainpolicy", "transport_override_avp", "transportoverride")
</programlisting>
		</example>
	</section>

	<section id="param_domain_replacement_avp" xreflabel="domain_replacement_avp">
		<title><varname>domain_replacement_avp</varname> (string)</title>
		<para>
		Name of the AVP which contains a domain replacement. 
		</para>
		<para>
		Default value is <quote>domainreplacement</quote>.
		</para>
		<example>
		<title>Setting domain_replacement_avp parameter</title>
		<programlisting format="linespecific">
# string named AVP
modparam("domainpolicy", "domain_replacement_avp", "domainreplacement")
</programlisting>
		</example>
	</section>

	<section id="param_domain_prefix_avp" xreflabel="domain_prefix_avp">
		<title><varname>domain_prefix_avp</varname> (string)</title>
		<para>
		Name of the AVP which contains a domain prefix. 
		</para>
		<para>
		Default value is <quote>domainprefix</quote>.
		</para>
		<example>
		<title>Setting domain_prefix_avp parameter</title>
		<programlisting format="linespecific">
# string named AVP
modparam("domainpolicy", "domain_prefix_avp", "domainprefix")
</programlisting>
		</example>
	</section>

	<section id="param_domain_suffix_avp" xreflabel="domain_suffix_avp">
		<title><varname>domain_suffix_avp</varname> (string)</title>
		<para>
		Name of the AVP which contains a domain suffix. 
		</para>
		<para>
		Default value is <quote>domainsuffix</quote>.
		</para>
		<example>
		<title>Setting domain_suffix_avp parameter</title>
		<programlisting format="linespecific">
# string named AVP
modparam("domainpolicy", "domain_suffix_avp", "domainsuffix")
</programlisting>
		</example>
	</section>
	<section id="param_send_socket_avp" xreflabel="send_socket_avp">
		<title><varname>send_socket_avp</varname> (string)</title>
		<para>
		Name of the AVP which contains a send_socket. The format of the
		send socket (the payload of this AVP) must be in the format
		[proto:]ip_address[:port]. The function dp_apply_policy will 
		look for this AVP and if defined, it will force the send socket
		to its value (smilar to the force_send_socket core function).
		</para>
		<para>
		Default value is <quote>sendsocket</quote>.
		</para>
		<example>
		<title>Setting send_socket_avp parameter</title>
		<programlisting format="linespecific">
# string named AVP
modparam("domainpolicy", "send_socket_avp", "sendsocket")
</programlisting>
		</example>
	</section>

	</section>



	<section id="exported_functions" xreflabel="exported_functions">
	<title>Exported Functions</title>
	<section id="func_dp_can_connect" xreflabel="dp_can_connect()">
		<title><function moreinfo="none">dp_can_connect()</function></title>
		<para>
		Checks the interconnection policy of the caller. It uses the domain in the 
		request URI to perform the DP-DDDS algorithm according to draft-lendl-domain-policy-ddds-02 
		to retrieve the domain's policy announcements. 
		As of this version, only records conforming to draft-lendl-speermint-federations-02
		and draft-lendl-speermint-technical-policy-00 are supported. 
		</para>
		<para>
		Non-terminal NAPTR records will cause recursion to the replacement domain. dp_can_connect()
		will thus look for policy rules in the referenced domain. Furthermore, an AVP for
		"domainreplacement" (containing the new domain) will be added to the call. This
		will redirect SRV/A record lookups to the new domain.
		</para>
		<para>
		In order to simplify direct domain-based peerings all destination domains are
		treated as if they contain a top priority "D2P+SIP:dom" rule with the domain itself as the 
		value of the rule. Thus any database row with type = 'dom' and rule = 'example.com'
		will override any dynamic DNS-discovered rules.
		</para>
		<para>
		For NAPTRs with service-type "D2P+SIP:fed", the federation IDs 
		(as extracted from the regexp field) are used to retrieve
		policy records from a local local database (basically: "SELECT dp_col_att, dp_col_val FROM 
		dp_table WHERE dp_col_rule = '[federationID]' AND type = 'fed'). If records are found (and all other
		records with the same order value are fulfillable) then AVPs will be created from
		the dp_col_att and dp_col_val columns.
		</para>
		<para>
		For NAPTRs with service-type "D2P+SIP:std", the same procedure is performed. This time,
		the database lookup searched for type = 'std', though.
		</para>
		<para>
		"D2P+SIP:fed" and "D2P+SIP:std" can be mixed freely. If two rules with the same
		"order" match and try to set the same AVP, then the behaviour is undefined.
		</para>
		<para>
		The dp_col_att column specifies the AVP's name. If the AVP start with "s:" or "i:", the 
		corresponding AVP type (string named or integer named) will be generated. If the excat specifier 
		is omited, the AVP type will be guessed.
		</para>
		<para>
		The dp_col_val column will always be interpreted as string. Thus, the AVP's value
		is always string based.
		</para>
		<para>
		dp_can_connect returns:
		</para>
		<itemizedlist>
		<listitem>
		<para>
			<emphasis>-2</emphasis>: on errors during the evaluation. (DNS, DB, ...)
		</para>
		</listitem>
		<listitem>
		<para>
			<emphasis>-1</emphasis>: D2P+SIP records were found, but the policy is not fullfillable.
		</para>
		</listitem>
		<listitem>
		<para>
			<emphasis>1</emphasis>: D2P+SIP records were found and a call is possible
		</para>
		</listitem>
		<listitem>
		<para>
			<emphasis>2</emphasis>: No D2P+SIP records were found. The destination domain does
			not announce a policy for incoming SIP calls.
		</para>
		</listitem>
		</itemizedlist>
		<para>
		This function can be used from REQUEST_ROUTE.
		</para>
		<example>
		<title>dp_can_connect usage</title>
		<programlisting format="linespecific">
...
dp_can_connect();
switch(retcode) {
	case -2:
		xlog("L_INFO","Errors during the DP evaluation\n");
		sl_send_reply(404, "We can't connect you.");
		break;
	case -1:
		xlog("L_INFO","We can't connect to that domain\n");
		sl_send_reply(404, "We can't connect you.");
		break;
	case 1:
		xlog("L_INFO","We found matching policy records\n");
		avp_print();
		dp_apply_policy();
		t_relay();
		break;
	case 2:
		xlog("L_INFO","No DP records found\n");
		t_relay();
		break;
}
...
		</programlisting>
		</example>
	</section>
	<section id="func_dp_apply_policy" xreflabel="dp_apply_policy()">
		<title><function moreinfo="none">dp_apply_policy()</function></title>
		<para>
		This function sets the destination URI according to the policy returned
		from the <function moreinfo="none">dp_can_connect()</function> function.
		Parameter exchange between <function moreinfo="none">dp_can_connect()</function>
		and <function moreinfo="none">dp_apply_policy()</function> is done via AVPs.
		The AVPs can be configured in the module's parameter section.
		</para>
		<para>
		Note: The name of the AVPs must correspond with the names in the 
		<emphasis>att</emphasis> column in the domainpolicy table.
		</para>
		<para>
		Setting the following AVPs in <function moreinfo="none">dp_can_connect()</function>
		(or by any other means)
		cause the following actions in <function moreinfo="none">dp_apply_policy()</function>:
		<itemizedlist>
		<listitem>
		<para>
			<emphasis>port_override_avp</emphasis>: If this AVP is set, the port
			in the destination URI is set to this port. 
			Setting an override port disables NAPTR and
			SRV lookups according to RFC 3263.
		</para>
		<para>
		&nbsp;
		</para>
		</listitem>
		<listitem>
		<para>
			<emphasis>transport_override_avp</emphasis>: If this AVP is set, the transport
			parameter in the destination URI is set to the specified transport ("udp", "tcp",
			"tls").
			Setting an override transport also disables NAPTR lookups, but retains 
			an SRV lookup according to RFC 3263.
		</para>
		<para>
		&nbsp;
		</para>
		</listitem>
		<listitem>
		<para>
			<emphasis>domain_replacement_avp</emphasis>: If this AVP is set, the domain
			in the destination URI will be replaced by this domain. 
		</para>
		<para>
			A non-terminal NAPTR and thus a referral to a new domain implicitly
			sets <emphasis>domain_replacement_avp</emphasis> to the new domain.
		</para>
		<para>
		&nbsp;
		</para>
		</listitem>
		<listitem>
		<para>
			<emphasis>domain_prefix_avp</emphasis>: If this AVP is set, the domain
			in the destination URI will be prefixed with this "subdomain".  
			E.g. if the domain in the request URI is 
			"example.com" and the domain_prefix_avp contains "inbound", the domain 
			in the destinaton URI is set to "inbound.example.com".
		</para>
		<para>
		&nbsp;
		</para>
		</listitem>
		<listitem>
		<para>
			<emphasis>domain_suffix_avp</emphasis>: If this AVP is set, the domain
			in the destination URI will have the content of the AVP appended to it.
			E.g. if the domain in the request URI is 
			"example.com" and the domain_suffix_avp contains "myroot.com", the domain 
			in the destination URI is set to "example.com.myroot.com".
		</para>
		<para>
		&nbsp;
		</para>
		</listitem>
		<listitem>
		<para>
			<emphasis>send_socket_avp</emphasis>: If this AVP is set, the sending socket
			will be forced to the socket in the AVP. The payload format of this AVP must 
			be [proto:]ip_address[:port].
		</para>
		</listitem>
		</itemizedlist>
		</para>

		<para>
		If both prefix/suffix and domain replacements are used, then the replacement is
		performed first and the prefix/suffix are applied to the new domain.
		</para>
		<para>
		This function can be used from REQUEST_ROUTE.
		</para>
		<example>
		<title>dp_apply_policy usage</title>
		<programlisting format="linespecific">
...
if (dp_apply_policy()) {
	t_relay();
}
...
		</programlisting>
		</example>
	</section>
	</section>

	<section>
	<title><acronym>FIFO</acronym> Commands</title>
	<para>
	</para>
	</section>

	<section>
	<title>Usage Scenarios</title>
	<para>
	This section describes how this module can be use to implement 
	selective VoIP peerings.
	</para>

	<section>
	<title>TLS Based Federation</title>
	<para>
	This example shows how a secure peering fabric can be configured based on
	TLS and Domain Policies.
	</para>
	<para>
	Let's assume that an organization called "TLSFED.org" acts as an umbrella for
	VoIP providers who want to peer with each other but don't want to run
	open SIP proxies. TLSFED.org's secretary acts as an X.509 Certification Authority
	that signs the TLS keys of all member's SIP proxies. Each member should automatically
	allow incoming calls from other members. On the other hand, the configuration for
	this federation must not interfere with a member's participation in other VoIP
	peering fabrics. All this can be achieved by the following configuration for
	a participating VoIP operation called example.com:
	</para>
	<itemizedlist>
		<listitem>
		<para><emphasis>Incoming SIP configuration</emphasis>
		</para><para>
			Calls from other members are expected to use TLS and authenticate
			using a client-CERT. To implement this, we cannot share a TCP/TLS port
			with other incoming connection. Thus we need to use tls_server_domain[] to
			dedicate a TCP port for this federation. 
		</para>
		<para>
		&nbsp;
		</para>
		<programlisting format="linespecific">
tls_server_domain[1.2.3.4:5066] {
 tls_certificate   = "/path/to/tlsfed/example-com.key"
 tls_private_key   = "/path/to/tlsfed/example-com.crt"
 tls_ca_list       = "/path/to/tlsfed/ca.pem"
 tls_method        = tlsv1
 tls_verify_client = 1
 tls_require_cleint_certificate = 1
}
		</programlisting>
		<para>
		&nbsp;
		</para>
		</listitem>

		<listitem>
		<para><emphasis>Outgoing SIP configuration</emphasis>
		</para><para>
			Calls to other members also must use the proper client cert. 
			Therefore, a TLS client domain must be configured. We use the 
			federation name as TLS client domain identifier. Therefore, the 
			content of the "tls_client_domain_avp" must be set to this identifier 
			(e.g. by putting it as rule into the domainpolicy table).
		</para>
		<para>
		&nbsp;
		</para>
		<programlisting format="linespecific">
tls_client_domain["tlsfed"] {
 tls_certificate   = "/path/to/tlsfed/example-com.key"
 tls_private_key   = "/path/to/tlsfed/example-com.crt"
 tls_ca_list       = "/path/to/tlsfed/ca.pem"
 tls_method        = tlsv1
 tls_verify_server = 1
}
		</programlisting>
		</listitem>
	</itemizedlist>

	</section>

	<section>
	<title>SIP Hub based Federation</title>
	<para>
	This example shows how a peering fabric based on a central SIP hub can be configured.
	</para>
	<para>
	Let's assume that an organization called "HUBFED.org" acts as an umbrella for
	VoIP providers who want to peer with each other but don't want to run
	open SIP proxies. Instead, HUBFED.org operates a central SIP proxy which will
	relay calls between all participating members. Each member thus only needs to
	allow incoming calls from that central hub (which could be done by firewalling).
	All this can be achieved by the following configuration for
	a participating VoIP operation called example.com:
	</para>
	<itemizedlist>
		<listitem>
		<para><emphasis>DNS configuration</emphasis>
		</para><para>
			The destination network announces its membership in this
			federation.
		</para>
		<para>
		&nbsp;
		</para>
		<programlisting format="linespecific">
$ORIGIN destination.example.org
@ IN NAPTR 10 50   "U"  "D2P+SIP:fed" (
                 "!^.*$!http://HUBFED.org/!" . )
		</programlisting>
		<para>
		&nbsp;
		</para>
		</listitem>


		<listitem>
		<para><emphasis>Outgoing SIP configuration</emphasis>
		</para><para>
			Calls to other members need to be redirected to the central proxy.
			The domainpolicy table just needs to list the federation and link
			it to the central proxy's domain name:
		</para>
		<para>
		&nbsp;
		</para>
		<programlisting format="linespecific">
mysql> select * from domainpolicy;
+----+--------------------+------+-------------------+----------------+
| id | rule               | type | att               | val            |
+----+--------------------+------+-------------------+----------------+
| 1  | http://HUBFED.org/ | fed  | domainreplacement | sip.HUBFED.org |
+----+--------------------+------+-------------------+----------------+
		</programlisting>
		<para>
		&nbsp;
		</para>
		</listitem>
	</itemizedlist>
	</section>
	



	<section>
	<title>Walled Garden Federation</title>
	<para>
	This example assumes that a set of SIP providers have established
	a secure Layer 3 network between their proxies. It does not
	matter whether this network is build by means of IPsec, a private
	Layer 2 network, or by simple firewalling. We will use the 10.x
	network (for the walled garden net) and "http://l3fed.org/" 
	(as federation identifier) in this example.
	</para>
	<para>
	A member of this federation (e.g. example.com) can not announce its
	SIP proxy's 10.x address in the standard SRV / A records of his domain,
	as this address is only meaningful for other members of this federation.
	In order to facilite different IP address resolution paths within the 
	federation vs. outside the federation, all members of "http://l3fed.org/"
	agree to prefix the destination domains with "l3fed" before the
	SRV (or A) lookup.
	</para>
	<para>
	Here is the configuration for example.com:
	</para>
	<itemizedlist>
		<listitem>
		<para><emphasis>DNS configuration</emphasis>
		</para><para>
			The destination network announces its membership in this
			federation.
		</para>
		<para>
		&nbsp;
		</para>
		<programlisting format="linespecific">
$ORIGIN example.com
@ IN NAPTR 10 50   "U"  "D2P+SIP:fed" (
                 "!^.*$!http://l3fed.org/!" . )
_sip._udp      IN SRV 10 10 5060 publicsip.example.com.
_sip._udp.l3fe IN SRV 10 10 5060 l3fedsip.example.com.

publicsip      IN A   193.XXX.YYY.ZZZ 
l3fedsip       IN A   10.0.0.42
		</programlisting>
		<para>
		&nbsp;
		</para>
		</listitem>


		<listitem>
		<para><emphasis>Outgoing SIP configuration</emphasis>
		</para><para>
			The domainpolicy table just needs to link the federation identifier
			to the agreed apon prefix:
		</para>
		<para>
		&nbsp;
		</para>
		<programlisting format="linespecific">
mysql> select * from domainpolicy;
+----+-------------------+------+--------------+-------+
| id | rule              | type | att          | val   |
+----+-------------------+------+--------------+-------+
| 1  | http://l3fed.org/ | fed  | domainprefix | l3fed |
+----+-------------------+------+--------------+-------+
		</programlisting>
		<para>
		&nbsp;
		</para>
		</listitem>
	</itemizedlist>
	</section>
	

	</section>

	<section>
	<title>Known Limitations</title>
	<para>
	</para>
	</section>

</chapter>

