📄 intro.sgml
字号:
# with private IP address in requests; the condition# is processed if such a contact header field is# foundif (search("^(Contact|m): .*@(192\.168\.|10\.|172\.16)")) {# .... # this condition is true if request URI matches# the regular expression "@bat\.iptel\.org" if (uri=~"@bat\.iptel\.org") {# ...# and this condition is true if a request came# from an IP address (useful for example for# authentication by IP address if digest is not# supported) AND the request method is INVITE# if ( (src_ip==192.68.77.110 and method=="INVITE")# ...</programlisting> </example> </section> <!-- operators and operands --> <section> <title>URI Matching</title> <para>URI matching expressions have a broad use in a SIP server and deserve more explanation. Typical uses of URI matching include implementation of numbering plans, domain matching, binding external applications to specific URIs, etc. This section shows examples of typical applications of URI-matching. </para> <section id="domainmatching"> <title>Domain Matching</title> <para> One of most important uses of URI matching is deciding whether a request is targeted to a served or outside domain. Typically, different request processing applies. Requests for outside domains are simply forwarded to them, whereas more complex logic applies to requests for a served domain. The logic may include saving user's contacts when REGISTER requests are received, forwarding requests to current user's location or a PSTN gateways, interaction with external applications, etc. </para> <para> The easiest way to decide whether a request belongs a served domain is using the <command moreinfo="none">myself</command> operand. The expression "uri==myself" returns true if domain name in request URI matches name of the host at which <application moreinfo="none">ser</application> is running. This may be insufficient in cases when server name is not equal to domain name for which the server is responsible. For example, the "uri==myself" condition does not match if a server "sipserver.foo.bar" receives a request for "sip:john.doe@foo.bar". To match other names in URI than server's own, set up the <varname>alias</varname> configuration option. The option may be used multiple times, each its use adds a new item to a list of aliases. The myself condition returns then true also for any hostname on the list of aliases. <example> <title>Use of uri==myself Expression</title> <programlisting format="linespecific"># ser powers a domain "foo.bar" and runs at host sipserver.foo.bar;# Names of served domains need to be stated in the aliases# option; myself would not match them otherwise and would only# match requests with "sipserver.foo.bar" in request-URIalias="foo.bar"alias="sales.foo.bar"route[0] { if (uri==myself) { # the request either has server name or some of the # aliases in its URI log(1,"request for served domain") # some domain-specific logic follows here .... } else { # aha -- the server is not responsible for this # requests; that happens for example with the following URIs # - sip:a@marketing.foo.bar # - sip:a@otherdomain.bar log(1,"request for outbound domain"); # outbound forwarding t_relay(); };} </programlisting> </example> </para> <para> It is possible to recognize whether a request belongs to a domain using regular expressions too. Care needs to be paid to construction of regular expressions. URI syntax is rich and an incorrect expression would result in incorrect call processing. The following example shows how an expression for domain matching can be formed. <example id="redomainmatching"> <title>Domain Matching Using Regular Expressions</title> <para> In this example, server named "sip.foo.bar" with IP address 192.168.0.10 is responsible for the "foo.bar" domain. That means, requests with the following hostnames in URI should be matched: <itemizedlist> <listitem> <para> foo.bar, which is the name of server domain </para> </listitem> <listitem> <para> sip.foo.bar, since it is server's name and some devices put server's name in request URI </para> </listitem> <listitem> <para> 192.168.0.10, since it is server's IP address and some devices put server's IP address in request URI </para> </listitem> </itemizedlist> Note how this regular expression is constructed. In particular: <itemizedlist> <listitem> <para> User name is optional (it is for example never included in REGISTER requests) and there are no restrictions on what characters it contains. That is what <emphasis>(.+@)?</emphasis> mandates. </para> </listitem> <listitem> <para> Hostname must be followed by port number, parameters or headers -- that is what the delimiters <emphasis>[:;\?]</emphasis> are good for. If none it these follows, the URI must be ended (<emphasis>$</emphasis>). Otherwise, longer hostnames such as 192.168.0.101 or foo.bar.otherdomain.com would mistakenly match. </para> </listitem> <listitem> <para> Matches are case-insensitive. All hostnames "foo.bar", "FOO.BAR" and "FoO.bAr" match. </para> </listitem> </itemizedlist> </para> <programlisting>if (uri=~"^sip:(.+@)?(192\.168\.0\.10|(sip\.)?foo\.bar)([:;\?].*)?$") log(1, "yes, it is a request for our domain"); break; }; </programlisting> </example> </para> </section> <!-- domain matching --> <section id="numberingplans"> <title>Numbering Plans</title> <para> Other use of URI matching is implementation of dialing plans. A typical task when designing a dialing plan for SIP networks is to distinguish between "pure-IP" and PSTN destinations. IP users typically have either alphanumerical or numerical usernames. The numerical usernames are convenient for PSTN callers who can only use numeric keypads. Next-hop destination of IP users is looked up dynamically using user location database. On the other hand, PSTN destinations are always indicated by numerical usernames. Requests to PSTN are statically forwarded to well-known PSTN gateways. </para> <example> <title>A simple Numbering Plan</title> <para> This example shows a simple dialing plan which reserves dialing prefix "8" for IP users, other numbers are used for PSTN destinations and all other non-numerical usernames are used for IP users. </para> <programlisting format="linespecific"># is it a PSTN destination? (is username numerical and does not begin with 8?)if (uri=~"^sip:[0-79][0-9]*@") { # ... forward to gateways then; # check first to which PSTN destination the requests goes; # if it is US (prefix "1"), use the gateway 192.168.0.1... if (uri=~"^sip:1") { # strip the leading "1" strip(1); forward(192.168.0.1, 5060); } else { # ... use the gateway 10.0.0.1 for all other destinations forward(10.0.0.1, 5060); } break;} else { # it is an IP destination -- try to lookup it up in user location DB if (!lookup("location")) { # bad luck ... user off-line sl_send_reply("404", "Not Found"); break; } # user on-line...forward to his current destination forward(uri:host,uri:port);} </programlisting> </example> </section> <!-- numbering plans --> </section> </section> <!-- conditional statements --> <section id="urirewriting"> <title>Request URI Rewriting</title> <para> The ability to give users and services a unique name using URI is a powerful tool. It allows users to advertise how to reach them, to state to whom they wish to communicate and what services they wish to use. Thus, the ability to change URIs is very important and is used for implementation of many services. "Unconditional forwarding" from user "boss" to user "secretary" is a typical example of application relying on change of URI address. </para> <para> <application moreinfo="none">ser</application> has the ability to change request URI in many ways. A script can use any of the following built-in actions to change request URI or a part of it: <command>rewriteuri</command>, <command>rewritehost</command>, <command>rewritehostport</command>, <command>rewriteuser</command>, <command>rewriteuserpass</command> and <command>rewriteport</command>. When later in the script a forwarding action is encountered, the action forwards the request to address in the rewritten URI. <example> <title>Rewriting URIs</title> <programlisting format="linespecific">if (uri=~"dan@foo.bar") { rewriteuri("sip:bla@somewherelse.com") # forward statelessly to the destination in current URI, i.e., # to sip:bla@somewherelese.com:5060 forward( uri:host, uri:port);} </programlisting> </example> </para> <para>Two more built-in URI-rewriting commands are of special importance for implementation of dialing plans and manipulation of dialing prefixes. <command>prefix(s) </command>, inserts a string "s" in front of SIP address and <command>strip(n)</command> takes away the first "n" characters of a SIP address. See <xref linkend="urirewritingexamples"> for examples of use of built-in URI-rewriting actions. </para> <para> Commands exported by external modules can change URI too and many do so. The most important application is changing URI using the user location database. The command <command>lookup(table)</command> looks up current user's location and rewrites user's address with it. If there is no registered contact, the command returns a negative value. <example id=rewriteuri> <title>Rewriting URIs Using User Location Database</title> <programlisting format="linespecific"># store user location if a REGISTER appearsif (method=="REGISTER") { save("mydomain1");} else {# try to use the previously registered contacts to# determine next hop if(lookup("mydomain1")) { # if found, forward there... t_relay(); } else { # ... if no contact on-line, tell it upstream sl_send_reply("404", "Not Found" ); };}; </programlisting> </example> </para> <para> External applications can be used to rewrite URI too. The "exec" module provides script actions, which start external programs and read new URI value from their output. <command moreinfo="none">exec_dset</command> both calls an external program, passes SIP request elements to it, waits until it completes, and eventually rewrites current destination set with its output. </para> <para> It is important to realize that <application moreinfo="none">ser</application> operates over <emphasis>current URI</emphasis> all the time. If an original URI is rewritten by a new one, the original will will be forgotten and the new one will be used in any further processing. In particular, the uri matching operand and the user location action <command moreinfo="none">lookup</command> always take current URI as input, regardless what the original URI was. </para> <para> <xref linkend="urirewritingexamples"> shows how URI-rewriting actions affect an example URI, sip:12345@foo.bar:6060. <table id="urirewritingexamples"> <title>URI-rewriting Using Built-In Actions</title> <tgroup cols="2"> <thead> <row> <entry> Example Action </entry> <entry> Resulting URI </entry> </row> </thead> <tbody> <row> <entry> <command moreinfo="none">rewritehost("192.168.0.10")</command> rewrites the hostname in URI, other parts (including port number) remain unaffected. </entry> <entry> sip:12345@192.168.10:6060 </entry> </row> <row> <entry> <command moreinfo="none">rewriteuri("sip:alice@foo.bar");</command> rewrites the whole URI completely. </entry> <entry> sip:alice@foo.bar </entry> </row> <row> <entry> <command moreinfo="none">rewritehostport("192.168.0.10:3040")</command>rewrites both hostname and port number in URI. </entry> <entry> sip:12345@192.168.0.10:3040 </entry> </row> <row> <entry> <command moreinfo="none">rewriteuser("alice")</command> rewrites user part of URI. </entry> <entry> sip:alice@foo.bar:6060 </entry> </row> <row> <entry> <command moreinfo="none">rewriteuserpass("alice:pw")</command> replaces the pair
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -