📄 intro.sgml
字号:
<chapter> <title>Introduction to SER</title> <section id="requestrouting"> <title>Request Routing and SER Scripts</title> <para> The most important concept of every SIP server is that of request routing. The request routing logic determines the next hop of a request. It can be for example used to implement user location service or enforce static routing to a gateway. Real-world deployments actually ask for quite complex routing logic, which needs to reflect static routes to PSTN gateways, dynamic routes to registered users, authentication policy, capabilities of SIP devices, etc. </para> <para> SER's answer to this need for routing flexibility is a routing language, which allows administrators to define the SIP request processing logic in a detailed manner. They can for example easily split SIP traffic by method or destination, perform user location, trigger authentication, verify access permissions, and so on. </para> <para> The primary building block of the routing language are <emphasis>actions</emphasis>. There are built-in actions (like <command>forward</command> for stateless forwarding or <command>strip</command> for stripping URIs) as well as external actions imported from shared library modules. All actions can be combined in compound actions by enclosing them in braces, e.g. <command>{a1(); a2();}</command>. Actions are aggregated in one or more <emphasis>route blocks</emphasis>. Initially, only the default routing block denoted by <command>route[0]</command> is called. Other routing blocks can be called by the action <command>route(blocknumber)</command>, recursion is permitted. The language includes <emphasis>conditional statements</emphasis>. </para> <para> The routing script is executed for every received request in sequential order. Actions may return positive/negative/zero value. Positive values are considered success and evaluated as TRUE in conditional expressions. Negative values are considered FALSE. Zero value means error and leaves execution of currently processed route block. The route block is left too, if <command>break</command> is explicitly called from it. </para> <para> The easiest and still very useful way for <application>ser</application> users to affect request routing logic is to determine next hop statically. An example is routing to a PSTN gateway whose static IP address is well known. To configure static routing, simply use the action <command>forward( IP_address, port_number)</command>. This action forwards an incoming request "as is" to the destination described in action's parameters. </para> <example> <title>Static Forwarding</title> <programlisting format="linespecific"># if requests URI is numerical and starts with# zero, forward statelessly to a static destinationif (uri=~"^sip:0[0-9]*@iptel.org") { forward( 192.168.99.3, 5080 );} </programlisting> </example> <para> However, static forwarding is not sufficient in many cases. Users desire mobility and change their location frequently. Lowering costs for termination of calls in PSTN requires locating a least-cost gateway. Which next-hop is taken may depend on user's preferences. These and many other scenarios need the routing logic to be more dynamic. We describe in <xref linkend="conditions"> how to make request processing subject to various conditions and in <xref linkend="urirewriting"> how to determine next SIP hop. </para> </section> <section id="conditions"> <title>Conditional Statements</title> <para> A very useful feature is the ability to make routing logic depend on a condition. A script condition may for example distinguish between request processing for served and foreign domains, IP and PSTN routes, it may split traffic by method or username, it may determine whether a request should be authenticated or not, etc. <application moreinfo="none">ser</application> allows administrators to form conditions based on properties of processed request, such as method or uri, as well as on virtually any piece of data on the Internet. </para> <example> <title>Conditional Statement</title> <para> This example shows how a conditional statement is used to split incoming requests between a PSTN gateway and a user location server based on request URI. </para> <programlisting format="linespecific"># if request URI is numerical, forward the request to PSTN gateway...if (uri=~"^sip:[0-9]+@foo.bar") { # match using a regular expression forward( gateway.foo.bar, 5060 );} else { # ... forward the request to user location server otherwise forward( userloc.foo.bar, 5060 );}; </programlisting> </example> <para> Conditional statements in <application>ser</application> scripts may depend on a variety of expressions. The simplest expressions are action calls. They return true if they completed successfully or false otherwise. An example of an action frequently used in conditional statements is <command moreinfo="none">search</command> imported from textops module. <command moreinfo="none">search</command> action leverages textual nature of SIP and compares SIP requests against a regular expression. The action returns true if the expression matched, false otherwise. <example> <title>Use of <command>search</command> Action in Conditional Expression</title> <programlisting format="linespecific"># prevent strangers from claiming to belong to our domain;# if sender claims to be in our domain in From header field,# better authenticate him if (search("(f|From): .*@mydomain.com)) { if (!(proxy_authorize("mydomain.com" /* realm */,"subscriber" /* table name */ ))) { proxy_challenge("mydomain.com /* ream */, "1" /* use qop */ ); break; }} </programlisting> </example> </para> <para> As modules may be created, which export new functions, there is virtually no limitation on what functionality <application moreinfo="none">ser</application> conditions are based on. Implementers may introduce new actions whose return status depends on request content or any external data as well. Such actions can query SQL, web, local file systems or any other place which can provide information wanted for request processing. </para> <para> Furthermore, many request properties may be examined using existing built-in operands and operators. Available left-hand-side operands and legal combination with operators and right-hand-side operands are described in <xref linkend="logicalexpr">. Expressions may be grouped together using logical operators: negation (<command>!</command>), AND (<command>&&</command>), OR (<command moreinfo="none"> ||</command> and precedence parentheses (<command>()</command>). </para> <section id="operators"> <title>Operators and Operands</title> <para> There is a set of predefined operators and operands in ser, which in addition to actions may be evaluated in conditional expressions. </para> <para> Left hand-side operands, which <application>ser</application> understands are the following: <itemizedlist> <listitem> <para> <emphasis>method</emphasis>, which refers to request method such as REGISTER or INVITE </para> </listitem> <listitem> <para> <emphasis>uri</emphasis>, which refers to current request URI, such as "sip:john.doe@foo.bar" <note> <para> Note that "uri" always refers to current value of URI, which is subject to change be uri-rewriting actions. </para> </note> </para> </listitem> <listitem> <para> <emphasis>src_ip</emphasis>, which refers to IP address from which a request came. </para> </listitem> <listitem> <para> <emphasis>dst_ip</emphasis> refers to server's IP address at which a request was received </para> </listitem> <listitem> <para> <emphasis>src_port</emphasis> port number from which a SIP request came </para> </listitem> </itemizedlist> </para> <para> ser understands the following operators: <itemizedlist> <listitem> <para> == stands for equity </para> </listitem> <listitem> <para> =~ stands for regular expression matching </para> </listitem> <listitem> <para> logical operators: and, or, negation, parentheses (C-notation for the operators may be used too) </para> </listitem> </itemizedlist> </para> <table id="logicalexpr"> <title>Valid Combinations of Operands and Operators in Expressions</title> <tgroup cols="4"> <thead> <row> <entry> left-hand-side operand </entry> <entry> valid operators </entry> <entry> valid right-hand side operators </entry> <entry> examples/comments </entry> </row> </thead> <tbody> <row> <entry> method </entry> <entry> == (exact match), =~ (regular expression matching) </entry> <entry> string </entry> <entry> method=="INVITE" || method=="ACK" || method=="CANCEL" </entry> </row> <row> <entry> uri </entry> <entry> == (exact match), =~ (regular expression matching) </entry> <entry> string </entry> <entry> uri=="sip:foo@bar.com" matches only if exactly this uri is in request URI </entry> </row> <row> <entry> </entry> <entry> == (exact match) </entry> <entry> myself </entry> <entry> the expression uri==myself is true if the host part in request URI equals a server name or a server alias (set using the alias option in configuration file) </entry> </row> <row> <entry> src_ip </entry> <entry> == (match) </entry> <entry> IP, IP/mask_length, IP/mask, hostname, myself </entry> <entry> src_ip==192.168.0.0/16 matches requests coming from a private network </entry> </row> <row> <entry> dst_ip </entry> <entry> == (match) </entry> <entry> IP, IP/mask_length, IP/mask, hostname, myself </entry> <entry> dst_ip==127.0.0.1 matches if a request was received via loopback interface </entry> </row> <row> <entry> src_port </entry> <entry> == (match) </entry> <entry> port number </entry> <entry> port number from which a request was sent, e.g. src_port==5060 </entry> </row> </tbody> </tgroup> </table> <example> <title> More examples of use of <application>ser</application> operators and operands in conditional statements </title> <programlisting format="linespecific"># using an action as condition input; in this# case, an actions 'search' looks for Contacts
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -