OpenSIPS+FreeSWITCH负载均衡+NAT+黑名单

原文出处:https://freeswitch.org/confluence/display/FREESWITCH/OpenSIPS+configuration+for+2+or+more+FreeSWITCH+installs

About

After much searching and experimentation, I've found an opensips.cfg that distributes calls to two or more FreeSWITCH boxes. This guide assumes you have a MySQL server setup on the same machine you are installing. Special thanks to the guys at 2600hz for this opensips.cfg

Please note that you should add this line to sofia.conf in FreeSWITCH for presence:

TODO: Fix script to send all "parking" and "conference" calls to a single FS server.

Tested on CentOS 6.X with OpenSIPS 1.7.1

Install and configure pre-requisites

Create 'opensips' user

useradd -d /usr/local/etc/opensips -s /sbin/nologin opensips

Create and configure opensips.log

Create the log

touch /var/log/opensips.log

chown opensips:opensips /var/log/opensips.log

Add the log to rsyslog.conf

vi /etc/rsyslog.conf

Add this line to the file:

local0.*                                                /var/log/opensips.log


Restart rsyslog

/etc/init.d/rsyslog restart


Install dependencies

yum install gcc-c++ bison lynx subversion flex curl-devel libxslt libxml2-devel

libxml2 pcre-devel mysql-devel wget make

Download and compile OpenSIPS 1.7.1

Download the source

cd /usr/src

wgethttp://opensips.org/pub/opensips/1.7.1/src/opensips-1.7.1_src.tar.gz

tar zxvf opensips-1.7.1_src.tar.gz

cd opensips-1.7.1-tls

 

Compile with MySQL support

make all include_modules="db_mysql"


Install OpenSIPS

make include_modules="db_mysql" prefix="/usr/local" install


Configure OpenSIPS

Create the MySQL database

Edit the opensipsctlrc file

vi /usr/local/etc/opensips/opensipsctlrc

 

Uncomment the following lines:

DBENGINE=MYSQL

DBHOST=localhost

DBNAME=opensips

DBRWUSER=opensips

DBRWPW="opensipsrw"

 

Run opensipsdbctl

You'll need to enter the MySQL root password when prompted

opensipsdbctl create
MySQL password for root: 

Create the start-up script

cp /usr/src/opensips-1.7.1-tls/packaging/rpm/opensips.init /etc/init.d/opensips

sed -i "s/\/usr\/sbin\/opensips/\/usr\/local\/sbin\/opensips/g" /etc/init.d/opensips

sed -i "s/\/etc\/opensips/\/usr\/local\/etc\/opensips/g" /etc/init.d/opensips

sed -i "s/\/etc\/default\/opensips/\/usr\/local\/etc\/opensips/g" /etc/init.d/opensips

sed -i "s/RUN_OPENSIPS=no/RUN_OPENSIPS=yes/g" /etc/init.d/opensips

chmod +x /etc/init.d/opensips

chkconfig opensips on

 

Edit opensips.cfg

Create new opensips.cfg

mv /usr/local/etc/opensips/opensips.cfg /usr/local/etc/opensips/opensips.cfg.noload

vi /usr/local/etc/opensips/opensips.cfg


Copy and paste

Make sure you replace "ext.ip.addr" with the public IP address of your OpenSIPS server.

######################################################################

## Core Parameters

######################################################################

# chroot=

# group="opensips"

# user="opensips"

# dbversion_table=

disable_core_dump=no

max_while_loops=100

maxbuffer=262144

memdump=3

memlog=2

# open_files_limit=2048

server_signature=no

server_header="Server: OpenSIPS"

user_agent_header="User-Agent: OpenSIPS"

 

######################################################################

## Core Fork Parameters

######################################################################

fork=yes

children=8

tcp_children=8

 

######################################################################

## Core Logging Parameters

######################################################################

debug=3

sip_warning=0

log_stderror=no

log_facility=LOG_LOCAL0

log_name="opensips"

 

######################################################################

## Aliases

######################################################################

auto_aliases=yes

alias=localhost

alias=localhost.localdomain

 

######################################################################

## Connectivity

######################################################################

#listen=udp:eth0:5060

listen=udp:eth0:5060

listen=tcp:eth0:5060

listen=udp:eth0:7000

listen=tcp:eth0:7000

#listen=udp:eth0:7000

#listen=tcp:eth0:7000

# listen=udp:eth1:5060

tos=IPTOS_LOWDELAY

# advertised_address=174.129.131.38

# advertised_port=5060

mcast_loopback=no

mcast_ttl=1

mhomed=0

# tcp_accept_aliases

tcp_connect_timeout=3

tcp_connection_lifetime=120

tcp_max_connections=2048

# tcp_poll_method=select

 

######################################################################

## DNS

######################################################################

dns=no

dns_retr_time=1

dns_retr_no=3

# dns_servers_no=2

dns_try_ipv6=no

disable_dns_blacklist=yes

disable_dns_failover=no

dns_use_search_list=no

rev_dns=no

 

######################################################################

## SIP

######################################################################

check_via=0

#! disable_503_translation=no

disable_stateless_fwd=no

disable_tcp=no

# disable_tls=no

#! reply_to_via=1

 

######################################################################

## TLS

######################################################################

# disable_tls=no

# listen=tls:your_IP:5061

# tls_verify_server=1

# tls_verify_client=1

# tls_require_client_certificate=0

# tls_method=TLSv1

# tls_certificate="/usr/local/etc/opensips/tls/user/user-cert.pem"

# tls_private_key="/usr/local/etc/opensips/tls/user/user-privkey.pem"

# tls_ca_list="/usr/local/etc/opensips/tls/user/user-calist.pem"

 

######################################################################

## Destination Blacklist

######################################################################

# dst_blacklist=gw:{( tcp , 192.168.2.100 , 5060 , "" ),( any , 192.168.2.101 , 0 , "" )}

# dst_blacklist=net_filter2:{ !( any , 192.168.30.0/255.255.255.0 , 0 , "" )}

 

######################################################################

## Attribute Value Pairs

######################################################################

# avp_aliases="uuid=I:660;email=s:email_addr;fwd=i:753"

 

######################################################################

## Module Loading

######################################################################

mpath="/usr/local/lib64/opensips/modules/"

 

loadmodule "db_mysql.so"

loadmodule "localcache.so"

loadmodule "signaling.so"

loadmodule "sl.so"

loadmodule "tm.so"

loadmodule "dialog.so"

loadmodule "maxfwd.so"

loadmodule "rr.so"

loadmodule "path.so"

loadmodule "uri.so"

loadmodule "textops.so"

loadmodule "usrloc.so"

loadmodule "nathelper.so"

loadmodule "nat_traversal.so"

loadmodule "uac_redirect.so"

loadmodule "dispatcher.so"

loadmodule "mi_fifo.so"

# loadmodule "mi_datagram.so"

 

######################################################################

## Localcache Module Parameters

######################################################################

modparam("localcache", "cache_table_size", 10)

modparam("localcache", "cache_clean_period", 120)

 

######################################################################

## Stateless UA Module Parameters

######################################################################

modparam("sl", "enable_stats", 1)

 

######################################################################

## SIP Transaction UA Module Parameters

######################################################################

modparam("tm", "fr_timer", 2)

modparam("tm", "fr_inv_timer", 120)

# modparam("tm", "wt_timer", 5)

# modparam("tm", "delete_timer", 2)

# modparam("tm", "T1_timer", 500)

# modparam("tm", "T2_timer", 4000)

# modparam("tm", "ruri_matching", 1)

# modparam("tm", "via1_matching", 1)

# modparam("tm", "unix_tx_timeout", 2)

# modparam("tm", "restart_fr_on_each_reply", 1)

modparam("tm", "fr_timer_avp", "$avp(final_reply_timer)")

# modparam("tm", "fr_inv_timer_avp", "$avp(25)")

# modparam("tm", "tw_append",

#    "test: ua=$hdr(User-Agent) ;avp=$avp(i:10);$rb;time=$Ts")

modparam("tm", "pass_provisional_replies", 1)

# modparam("tm", "syn_branch", 1)

# modparam("tm", "onreply_avp_mode", 0)

# modparam("tm", "disable_6xx_block", 0)

# modparam("tm", "enable_stats", 1)

# modparam("tm", "minor_branch_flag", 3)

 

######################################################################

## Max Forward Module Parameters

######################################################################

modparam("maxfwd", "max_limit", 30)

 

######################################################################

## Record Route Module Parameters

######################################################################

#modparam("rr", "enable_full_lr", 1)

modparam("rr", "append_fromtag", 1)

modparam("rr", "enable_double_rr", 0)

modparam("rr", "add_username", 0)

 

######################################################################

## Path Module Parameters

######################################################################

modparam("path", "use_received", 1)

 

######################################################################

## URI Module Parameters

######################################################################

# modparam("uri", "aaa_url", "radius:/etc/radiusclient-ng/radiusclient.conf")

modparam("uri", "use_sip_uri_host", 0)

modparam("uri", "use_uri_table", 0)

modparam("uri", "service_type", 10)

modparam("uri", "use_domain", 1)

modparam("uri", "use_uri_table", 0)

# modparam("uri", "db_url", "mysql://username:password@localhost/opensips")

# modparam("uri", "db_table", "uri")

# modparam("uri", "user_column", "username")

# modparam("uri", "domain_column", "domain")

# modparam("uri", "uriuser_column", "uri_user")

 

######################################################################

## User Location Module Parameters

######################################################################

modparam("usrloc", "nat_bflag", 6)

modparam("usrloc", "use_domain", 1)

modparam("usrloc", "desc_time_order", 0)

modparam("usrloc", "timer_interval", 60)

modparam("usrloc", "matching_mode", 0)

modparam("usrloc", "cseq_delay", 20)

modparam("usrloc", "hash_size", 9)

modparam("usrloc", "db_mode", 0)

# modparam("usrloc", "db_url", "dbdriver://username:password@dbhost/dbname")

#modparam("usrloc", "fetch_rows", 2000)

modparam("usrloc", "user_column", "username")

modparam("usrloc", "domain_column", "domain")

modparam("usrloc", "contact_column", "contact")

modparam("usrloc", "expires_column", "expires")

modparam("usrloc", "q_column", "q")

modparam("usrloc", "callid_column", "callid")

modparam("usrloc", "cseq_column", "cseq")

modparam("usrloc", "methods_column", "methods")

modparam("usrloc", "flags_column", "flags")

modparam("usrloc", "cflags_column", "cflags")

modparam("usrloc", "user_agent_column", "user_agent")

modparam("usrloc", "received_column", "received")

modparam("usrloc", "socket_column", "socket")

modparam("usrloc", "path_column", "path")

 

######################################################################

## Nathelper Module Parameters

######################################################################

# modparam("nathelper", "rtpproxy_sock", "udp:127.0.0.1:7890")

# modparam("nathelper", "natping_interval", 30)

# modparam("nathelper", "ping_nated_only", 1)

# modparam("nathelper", "natping_processes", 3)

# modparam("nathelper", "sipping_bflag", 7)

# modparam("nathelper", "sipping_from", "sip:[email protected]")

# modparam("nathelper", "sipping_method", "INFO")

 

######################################################################

## NAT Traversal Module Parameters

######################################################################

modparam("nat_traversal", "keepalive_interval", 60)

modparam("nat_traversal", "keepalive_method", "OPTIONS")

modparam("nat_traversal", "keepalive_from", "sip:[email protected]:5060")

modparam("nat_traversal", "keepalive_state_file", "/tmp/opensips_keepalive_state")

 

######################################################################

## UAC Redirect Module Parameters

######################################################################

modparam("uac_redirect", "default_filter", "accept")

# modparam("uac_redirect", "deny_filter", NULL)

# modparam("uac_redirect", "accept_filter", NULL)

# modparam("uac_redirect", "acc_function", "acc_log_request")

# modparam("uac_redirect", "acc_db_table", "acc")

 

######################################################################

## Dispatcher Module Parameters

######################################################################

#modparam("dispatcher", "list_file", "/etc/opensips/dispatcher.list")

modparam("dispatcher", "db_url", "mysql://opensips:opensipsrw@localhost/opensips")

modparam("dispatcher", "flags", 2)

modparam("dispatcher", "use_default", 0)

modparam("dispatcher", "force_dst", 1)

modparam("dispatcher", "dst_avp", "$avp(271)")

modparam("dispatcher", "attrs_avp", "$avp(272)")

modparam("dispatcher", "grp_avp", "$avp(273)")

modparam("dispatcher", "cnt_avp", "$avp(274)")

modparam("dispatcher", "hash_pvar", "$avp(273)")

# modparam("dispatcher", "setid_pvar", "$var(setid)")

modparam("dispatcher", "ds_ping_method", "OPTIONS")

modparam("dispatcher", "ds_ping_from", "sip:[email protected]:5060")

modparam("dispatcher", "ds_ping_interval", 10)

# modparam("dispatcher", "ds_ping_sock", "udp:ext.ip.addr:5060")

modparam("dispatcher", "ds_probing_threshhold", 3)

modparam("dispatcher", "ds_probing_mode", 1)

modparam("dispatcher", "options_reply_codes", "501,403,404,400,200")

 

######################################################################

## MI-FIFO Module Parameters

######################################################################

modparam("mi_fifo", "fifo_name", "/tmp/opensips_fifo")

 

######################################################################

## MI-Datagram Module Parameters

######################################################################

# modparam("mi_datagram", "socket_name", "udp:127.0.0.1:8889")

# modparam("mi_datagram", "children_count", 1)

# modparam("mi_datagram", "unix_socket_mode", 0600)

# modparam("mi_datagram", "unix_socket_group", "root")

# modparam("mi_datagram", "unix_socket_user", "root")

# modparam("mi_datagram", "socket_timeout", 2000)

# modparam("mi_datagram", "reply_indent", "\t")

 

######################################################################

## XLog Module Parameters

######################################################################

# modparam("xlog", "buf_size", 4096)

# modparam("xlog", "force_color", 0)

 

######################################################################

## Multiple Module Parameters

######################################################################

 

######################################################################

## Main Request Routing

######################################################################

route

{

    # log the basic info regarding this call

    xlog("L_INFO", "$ci|start|recieved $oP request $rm $ou");

    xlog("L_INFO", "$ci|log|source $si:$sp");

    xlog("L_INFO", "$ci|log|from $fu");

    xlog("L_INFO", "$ci|log|to $tu");

 

    # check that hop cound for this request and make sure it is under 10

    # to prevent endless loops

    if (!mf_process_maxfwd_header("10"))

    {

        xlog("L_WARN", "$ci|end|to many hops");

 

        sl_send_reply("483", "We refuse to process this endless imbroglio");

 

        exit;

    }

 

    # this check detemines if the opensips has routed the request to itself,

    # this happens because the server is the destination of the request but

    # we mangle it to send it else where. When that mangeling fails and we

    # still relay it then it just comes right back to us...

    if (src_ip==myself)

    {

        xlog("L_WARN", "$ci|end|sourced from this server");

 

        exit;

    }

 

    # currently we dont support subscribe so to keep the noise down

    # just end the request here. For options just end the request here as well.

    if (is_method("OPTIONS"))

    {

        xlog("L_NOTICE", "$ci|end|unsupported method");

 

        sl_send_reply("503", "Rawr!!");

 

        exit;

    }

 

    # if the source IP/port are in one of the server dispatch lists

    # then this request originated from one of our media servers, mark it

    # as such by setting flag 26

    if (ds_is_in_list("$si", "", "1"))

    {

        xlog("L_INFO", "$ci|log|originated from internal sources");

 

        # Flag 26 marks the source as a on-net server

        setflag(26);

 

        setbflag(26);

    }

    # if the request source IP/port was not in any dispatcher lists

    # this this originated outside our equipment (carrier, client, ect)

    else

    {

        xlog("L_INFO", "$ci|log|originated from external sources");

    }

 

    # if the to header has a tag attached then it implies this request

    # has been processed by us before (IE: a media server has added

    # its tag on the to header in prior messages)

    if (has_totag())

    {

        # sequential request within a dialog should

        # take the path determined by record-routing

        if (loose_route())

        {

            append_hf("P-hint: rr-enforced\r\n");

 

            # if we have locked this call to a media server then

            # maintain that association

            if (cache_fetch("local", "$ci", $avp(55)))

            {

                if (is_method("BYE"))

                {

                    # remove the association between the call-id and the media server (if one)

                    # but leave the contact user and server to support transfers

                    cache_remove("local", "$ci");

 

                    xlog("L_INFO", "$ci|log|cleaned up call id from cache");

                }

                else if (isflagset(26))

                {

                    cache_store("local", "$tU", "$avp(55)", 3600);

 

                    xlog("L_INFO", "$ci|log|maintaining associated $tU with media server $avp(55)");

                }

                else if ($ct.fields(uri))

                {

                    cache_store("local", "$(ct.fields(uri){uri.user})", "$avp(55)", 3600);

 

                    xlog("L_INFO", "$ci|log|maintaining associated $(ct.fields(uri){uri.user}) with media server $avp(55)");

                }

 

                cache_store("local", "$ci", "$avp(55)", 3600);

            }

 

            xlog("L_INFO", "$ci|log|forwarding based on the route set");

 

            if (isflagset(26))

            {

                route(internal_to_external_relay);

            }

            else

            {

                route(external_to_internal_relay);

            }

 

            exit();

        }

        else if ( is_method("ACK") )

        {

            if ( t_check_trans() )

            {

                # non loose-route, but stateful ACK; must be an ACK after

                # a 487 or e.g. 404 from upstream server

                xlog("L_INFO", "$ci|log|in dialog request belongs to a known transaction");

 

                route(logged_relay);

            }

            else

            {

                # ACK without matching transaction ->

                # ignore and discard

                xlog("L_NOTICE", "$ci|end|no matching transaction");

            }

 

            exit();

        }

        else if ( is_method("NOTIFY") )

        {

            route(logged_relay);

 

            exit();

        }

 

        # request with a to tag that cant be routed loosly and is not an ACK

        # ignor eand discard

        xlog("L_WARN", "$ci|end|could not route in dialog");

 

        sl_send_reply("486", "PC Load Letter");

 

        exit();

    }

 

    # if the request is to cancel a transaction process it now

    if (is_method("CANCEL"))

    {

        # If this cancel is part of a transaction

        # then pass it along to concerned parties

        if (t_check_trans())

        {

            xlog("L_INFO", "$ci|log|request belogs to a known transaction");

 

            route(logged_relay);

        }

        # if the cancel does not belong to a known transaction or a

        # request that has not progressed outside this server dont relay it

        else

        {

            xlog("L_NOTICE", "$ci|end|no matching transaction");

        }

 

        # remove the association between the call-id and the media server (if one)

        # but leave the contact user and server to support transfers

        cache_remove("local", "$ci");

 

        xlog("L_INFO", "$ci|log|cleaned up call id from cache");

 

        exit;

    }

 

    # If this is a retransmission it will break/stop the script

    # and do standard processing of the message

    t_check_trans();

 

    # Except for an ACK no request should have a route set with no to tag, this would

    # indicate that the intial request has the Route headers and is likely someone trying

    # to get us to send the request were they want

    if (loose_route())

    {

        if (!is_method("ACK"))

        {

            xlog("L_WARN", "$ci|end|initial request contained a preloaded route set");

 

            sl_send_reply("403", "The only winning move it not to play");

 

            exit;

        }

    }

 

    # If the request is a register we will pass it along but we need

    # to add the path header (along with the received IP/port info)

    if (is_method("REGISTER"))

    {

        # if we fail to add the path header then dont let it

        # register because it will cause issues later...

        if (!add_path_received())

        {

            xlog("L_ERR", "$ci|log|unable to add path");

 

            sl_send_reply("503", "Internal path befuddlement");

 

            # remove the association between the call-id and the media server (if one)

            # but leave the contact user and server to support transfers

            cache_remove("local", "$ci");

 

            xlog("L_INFO", "$ci|end|cleaned up call id from cache");

 

            exit;

        }

 

        xlog("L_INFO", "$ci|log|added path");

    }

 

    # for all initial request (not having been processed above in the has_totag)

    # that are not a register or message add this sever to the route set on the

    # request so subsequent messages come through this server

    if (!is_method("REGISTER|MESSAGE"))

    {

        # Record the route that this request has taken

        # so we remain in the signaling path

        record_route();

 

        xlog("L_INFO", "$ci|log|added this server to the route set");

    }

 

    # if the request is from a media server send it out

    if (isflagset(26))

    {

        route(internal_to_external_relay);

 

        exit();

    }

 

    # if the request is not from a media server it must be for one,

    # there is much work to do!

 

    # load a list of currently active media servers

    # if no media server could be set with ds_select_domain then there are no

    # active servers, no need to conitnue

    if (!ds_select_domain("1", "4"))

    {

        xlog("L_ERR", "$ci|end|no servers avaliable");

 

        sl_send_reply("480", "The cake is a lie!");

 

        exit;

    }

 

    if (cache_fetch("local", "$ou", $avp(55)))

    {

        xlog("L_INFO", "$ci|log|request $ou is associated with media server $avp(55)");

 

        cache_remove("local", "$ou");

 

        cache_store("local", "$ci", "$avp(55)", 3600);

    }

    # if the request is not from our media severs but has a call-id in localcache

    # then change the routing to go to the server previously associated with it.

    else if (cache_fetch("local", "$ci", $avp(55)))

    {

        cache_store("local", "$ci", "$avp(55)", 3600);

 

        xlog("L_INFO", "$ci|log|call-id is associated with media server $avp(55)");

    }

    # if the request is not from our media severs but has a contact uri in localcache

    # then change the routing to go to the server previously associated with it.

    else if ($ct.fields(uri) && cache_fetch("local", "$(ct.fields(uri){uri.user})", $avp(55)))

    {

        cache_store("local", "$(ct.fields(uri){uri.user})", "$avp(55)", 3600);

 

        xlog("L_INFO", "$ci|log|contact $(ct.fields(uri){uri.user}) is associated with media server $avp(55)");

    }

    # if the request is not from our media servers and no associations in localcache

    # then use the distribute list as is

    else

    {

        xlog("L_INFO", "$ci|log|routing call to arbitrary media server $rd:$rp");

    }

 

    # if the dispatcher list (in 271) does not start with

    # the request domain/port that we are sending this call

    # to, re-order the list so that it does

    if($avp(55) && $(avp(271)[0]) != $avp(55))

    {

        # create a index var for our loop (arrays are start at 0 and this is a count)

        $var(i) = $avp(274) - 1;

 

        # loop over the dispatcher list

        while($var(i) > 0)

        {

            # if this element in the dispatch list is the same

            # as the call destination

            if($(avp(271)[$var(i)]) == $avp(55))

            {

                # replace it with the first element of the list

                $(avp(271)[$(var(i))]) = $(avp(271)[0]);

 

                # break out of the loop

                $var(i) = -1;

            }

 

            $var(i) = $var(i) - 1;

        }

 

        # handles the case were we only have two servers

        # and the one that we are locked to has failed

        if ($var(i) >= 0)

        {

 

            xlog("L_INFO", "$ci|log|associated media server is inactive, moving to $rd");

 

            if ($ct.fields(uri) && cache_fetch("local", "$ci", $avp(56)))

            {

                cache_store("local", "$(ct.fields(uri){uri.user})", "sip:$rd:$rp", 3600);

 

                xlog("L_INFO", "$ci|log|associated contact $(ct.fields(uri){uri.user}) with media server sip:$rd:$rp");

            }

 

            # update the callid cache

            cache_store("local", "$ci", "sip:$rd:$rp", 3600);

        }

        # the server we are locked to is in the active server list from then

        # dispatcher so re-arrange the list to try it first

        else

        {

            xlog("L_INFO", "$ci|log|re-ordering the dispatcher list to keep associated server first");

 

            # set the first element of the list to the destination

            $(avp(271)[0]) = $avp(55);

 

            # set the domain for this request (server IP to route to)

            $rd = $(avp(55){uri.host});

 

            # set the port for this request (server IP to route to)

            $rp = $(avp(55){uri.port});

        }

    }

 

    route(external_to_internal_relay);

}

 

route[external_to_internal_relay]

{

    # 1. correct any nat issues

    # 2. remove any X-AUTH-IP headers so we will be the only one to set it

    # 3. set the X-AUTH-IP header for freeswitch ACLs

    # 4. set the final reply timer to two seconds, so we failover faster

    # 5. arm a logging branch for replies

    # 6. arm a failure branch that will try another one of our media servers when possible

 

    route("nat_test_and_correct");

 

    remove_hf("X-AUTH-IP");

 

    append_hf("X-AUTH-IP: $si\r\n");

 

    xlog("L_INFO", "$ci|log|X-AUTH-IP: $si");

 

    $avp(final_reply_timer) = 2;

 

    t_on_reply("internal_reply");

 

    t_on_failure("internal_fault");

 

    route("logged_relay");

 

    exit;

}

 

route[internal_to_external_relay]

{

    # if the request is from a media server then assume it is going somewhere

    # outside our control and give that equipment longer to respond.

    # Also arm a branch to log the replies

 

    $avp(final_reply_timer) = 6;

 

    t_on_reply("external_reply");

 

    route("logged_relay");

 

    exit;

}

 

route[logged_relay]

{

    # try to send the request on its way, if it fails send back a

    # stateless error to the requestor

    if (t_relay())

    {

        xlog("L_INFO", "$ci|pass|$rd:$rp");

    }

    else

    {

        xlog("L_ERR", "$ci|end|unable to relay message");

 

        sl_reply_error();

    }

}

 

route[nat_test_and_correct]

{

    # 1. Contact header field is searched for occurrence of RFC1918 addresses

# if (nat_uac_test("1"))

# {

# xlog("L_INFO", "$ci|log|contact header field contains a RFC1918 address");

#

# fix_contact();

# }

 

    # 2 - the "received" test is used: address in Via is compared against source IP address of signaling

    if (nat_uac_test("2"))

    {

        xlog("L_INFO", "$ci|log|address in Via differs from source IP");

 

        # adds the rport parameter to the first Via header

        force_rport();

 

        fix_contact();

    }

 

    # if the request has a body see if it needs NAT corrections as well,

    # this check looks at:

    # 8. SDP is searched for occurrence of RFC1918 addresses

    if (has_body("application/sdp") && nat_uac_test("8"))

    {

        xlog("L_INFO", "$ci|log|SDP contains a RFC1918 address");

 

        # alters the SDP information in order to facilitate NAT traversal.

        # 2. rewrite media IP address (c=) with source IP

        # 8. rewrite IP from origin description (o=) with source IP

        fix_nated_sdp("10");

    }

}

 

onreply_route[external_reply]

{

    # this branch handles replies that are comming from equipment

    # outside our control

 

    xlog("L_INFO", "$ci|start|recieved external reply $rs $rr");

    xlog("L_INFO", "$ci|log|source $si:$sp");

 

    # This ensures that if a endpoint recieves a call they can properly

    # transfer that call

    # TODO: this will track calls made to carriers when we start sending carrier

    # traffic through opensips

    # Target: A endpoint answering a call made from one of our media

    # servers should lock that endpoint to the server

    if (t_check_status("200") && is_method("INVITE") && $(fd{ip.isip}) && ds_is_in_list("$fd", "", "1"))

    {

        $var(d) = $(fu{uri.host});

 

        if ($(fu{uri.port}) == 0)

        {

            $var(p) = 5060;

        }

        else

        {

            $var(p) = $(fu{uri.port});

        }

 

        if ($ct.fields(uri))

        {

            cache_store("local", "$(ct.fields(uri){uri.user})", "sip:$var(d):$var(p)", 3600);

 

            xlog("L_INFO", "$ci|log|associated $(ct.fields(uri){uri.user}) with media server sip:$var(d):$var(p)");

        }

 

        cache_store("local", "$ci", "sip:$var(d):$var(p)", 3600);

 

        xlog("L_INFO", "$ci|log|associated call-id with media server sip:$var(d):$var(p)");

    }

 

    if (is_method("BYE"))

    {

        # remove the association between the call-id and the media server (if one)

        # but leave the contact user and server to support transfers

        cache_remove("local", "$ci");

 

        xlog("L_INFO", "$ci|log|cleaned up call id from cache");

    }

 

    route("nat_test_and_correct");

 

    xlog("L_INFO", "$ci|pass|$(<request>si):$(<request>sp)");

 

    # if the reply is not dropped (only provisional replies can be),

    # it will be injected and processed by the transaction engine.

}

 

onreply_route[internal_reply]

{

    # this branch handles replies that are comming from our media server

    if(t_local_replied("last"))

    {

        xlog("L_INFO", "$ci|start|recieved local internal reply $T_reply_code $rr");

    }

    else

    {

        xlog("L_INFO", "$ci|start|recieved internal reply $T_reply_code $rr");

        xlog("L_INFO", "$ci|log|source $si:$sp");

    }

 

    # Ensure that if we challenge an endpoint its response is not round-robin'd

    # We have to do it in the reply so we have the correct call id

    # Target: Endpoint intiated a request that was challenged, lock that

    # call id to the challenging server so it recieves the reply

    if (t_check_status("(407)|(401)") && $(si{ip.isip}) && ds_is_in_list("$si", "", "1"))

    {

        cache_store("local", "$ci", "sip:$si:$sp", 3600);

 

        xlog("L_INFO", "$ci|log|associated call-id with media server sip:$si:$sp");

    }

 

    if (is_method("BYE"))

    {

        # remove the association between the call-id and the media server (if one)

        # but leave the contact user and server to support transfers

        cache_store("local", "$ci", "sip:$si:$sp", 360);

 

        xlog("L_INFO", "$ci|log|cleaned up call id from cache");

    }

 

    if ($rs < 300)

    {

        xlog("L_INFO", "$ci|pass|$(si):$(<request>sp)");

    }

 

    # if the reply is not dropped (only provisional replies can be),

    # it will be injected and processed by the transaction engine.

}

 

failure_route[internal_fault]

{

    # this branch handles failures (>=300) to our media servers,

    # which we can sometimes overcome by routing to another server

 

    # if the failure cause was due to the transaction being

    # cancelled then we are complete

    if (t_was_cancelled())

    {

        xlog("L_INFO", "$ci|log|transaction was cancelled");

 

        # remove the association between the call-id and the media server (if one)

        # but leave the contact user and server to support transfers

        cache_remove("local", "$ci");

 

        xlog("L_INFO", "$ci|end|cleaned up call id from cache");

 

        exit;

    }

 

    # if the failure case was soemthing that we should recover

    # from then try to find a new media server

    if (t_check_status("(401)|(407)|(403)"))

    {

        xlog("L_INFO", "$ci|log|failure route ignoring auth reply $T_reply_code $rr");

    }

    else if (t_check_status("402"))

    {

        send_reply("486", "More money please");

 

        exit();

    }

    else if (t_check_status("(4[0-9][0-9])|(5[0-9][0-9])"))

    {

        xlog("L_INFO", "$ci|start|received failure reply $T_reply_code $rr");

 

        if (cache_fetch("local", "$ci-failure", $avp(55)))

        {

            $avp(55) = $(avp(55){s.int});

        }

        else

        {

            $avp(55) = 0;

        }

 

        xlog("L_INFO", "$ci|log|attempting retry $avp(55) of failed request");

 

        # try to find a new media server to send the call to

        if($avp(55) < 3 && ds_next_domain())

        {

            xlog("L_INFO", "$ci|log|routing call to next media server $rd:$rp");

 

            # store the new callid association

            cache_store("local", "$ci", "sip:$rd:$rp", 3600);

 

            # if the request has a contact and is an INVITE then store the new

            # association

            if ($ct.fields(uri) && is_method("INVITE"))

            {

                cache_store("local", "$(ct.fields(uri){uri.user})", "sip:$rd:$rp", 3600);

 

                xlog("L_INFO", "$ci|log|associated contact $(ct.fields(uri){uri.user}) with media server sip:$rd:$rp");

            }

 

            # reset the final reply timer

            $avp(final_reply_timer) = 2;

 

            t_on_reply("internal_reply");

 

            t_on_failure("internal_fault");

 

            xlog("L_INFO", "$ci|pass|$rd:$rp");

 

            # relay the request to the new media server

            t_relay();

 

            $avp(55) = $avp(55) + 1;

 

            cache_store("local", "$ci-failure", "$avp(55)", 60);

 

            exit();

        }

        else

        {

            cache_remove("local", "$ci-failure");

 

            xlog("L_ERR", "$ci|log|no other media servers avaliable");

        }

    }

    else if (t_check_status("302"))

    {

        if( $(hdr(X-Redirect-Server)) && $(<reply>ct.fields(uri)) )

        {

            $var(redirect_host) = $(<reply>hdr(X-Redirect-Server){uri.host});

 

            $var(redirect_port) = $(<reply>hdr(X-Redirect-Server){uri.port});

 

            cache_store("local", "$(<reply>ct.fields(uri))", "sip:$var(redirect_host):$var(redirect_port)", 60);

 

            xlog("L_INFO", "$ci|log|stored redirect mapping for $(<reply>ct.fields(uri)) to sip:$var(redirect_host):$var(redirect_port)");

            xlog("L_INFO", "$ci|log|stored redirect mapping for $(<reply>ct.fields(uri)) to sip:$var(redirect_host):$var(redirect_port)");

 

            remove_hf("X-Redirect-Server");

        }

    }

    else

    {

        xlog("L_INFO", "$ci|log|failure route ignoring reply $T_reply_code $rr");

    }

 

    if (!t_check_status("(407)|(401)|(302)"))

    {

        # remove the association between the call-id and the media server (if one)

        # but leave the contact user and server to support transfers

        cache_remove("local", "$ci");

 

        xlog("L_INFO", "$ci|log|cleaned up call id from cache");

    }

 

    xlog("L_INFO", "$ci|pass|$(<request>si):$(<request>sp)");

 

    # if no new branch is generated or no reply is forced over, by default,

    # the winning reply will be sent back to UAC.

}

 

A potential correction to the above script:

  • With UDP only, everything was working fine, but iPhones registered via TCP/TLS could make calls, but not receive calls
  • Call diversion (320 Moved Temporarily) done by registered phones wan't working

So I made the following adjustments to the above script:

1) UDP<>TCP not working

modparam("rr", "enable_double_rr", 1) # instead of 0, 1 is default

modparam("path", "use_received", 0) # instead of 1, 0 is default

 

2) "302 Moved temporarily" not working

# in onreply_route[external_reply]:

# instead of calling nat_test_and_correct unconditionally, do it only for non 302's :

if (!t_check_status("302")) {

   route("nat_test_and_correct");

}

I'm not absolutely sure, that this won't have any nasty side effects, but at least for me, everything seems to work perfectly fine now. - JJJ

Start OpenSIPS

/etc/init.d/opensips start


Add FreeSWITCH servers to OpenSIPS dispatcher list

Replace fs1.ext.ip.addr and fs2.ext.ip.addr with the IP addresses of your FreeSWITCH servers:

opensipsctl dispatcher addgw 1 sip:fs1.ext.ip.addr:5060 0 'fs1'

opensipsctl dispatcher addgw 1 sip:fs2.ext.ip.addr:5060 0 'fs2'

 

Debugging

tail -f /var/log/opensips.log



你可能感兴趣的:(OpenSIPS+FreeSWITCH负载均衡+NAT+黑名单)