[OpenSIPS-Users] OpenSIPS + OpenIMS + NAT issues

Olivier Dugeon Olivier.Dugeon at orange-ftgroup.com
Fri Jul 10 17:44:49 CEST 2009


Hello all,

I have some problems with OpenSIPS and OpenIMS due to NAT configuration.

My setup is a follow:

UA <--> HGW (embedded both OpenSIPS and NAT stuff) <--> P-CSCF (OpenIMS)

I used different UA (mainly Twinkle and X-Lite). The HGW (Home GateWay)
is running under OpenWRT on which I compile and install OpenSIPS. The
P-CSCF, S-CSCF and I-CSCF are all running on the same PC (standard
configuration from OpenIMS installation).

My OpenSIPS is just used to manage local message (perform some security
check) and manage the NAT configuration of the HGW.

My problem come from the fact that the P-CSCF (and subsequently the
S-CSCF) is registered my UA with its private @IP address and not the
public @IP address of the HGW. So, each time I sent a SIP message to the
IMS Core, the P-CSCF  reject my messages with a 403 "Forbidden. You must
registered first in the P-CSCF". This come from that the P-CSCF check
who is sending the SIP message based on the source @IP. In my case, the
source @IP address is the public one (i.e. the HGW public one). However,
this public @IP address is not know by the P-CSCF i.e. it doesn't
correspond to a registered UA. So, Outgoing call are not working.
Fortunately, Incoming call (i.e. from a UA which is directly connected
to the IMS Core) are working well.

I try several configuration using nathelper module, but I just got a
negative reply from the S-CSCF instead of the P-CSCF (I.e. I pass the
P-CSCF check by using force_rport in register and invite message)).

I fact, the problem come from the fix_nated_contact() and
fix_nated_register() function which don't do the job I want. They
rewrite the contact field with the source IP and Port of the original
message i.e. the @IP address and port of the UA.

So, what I'm looking for, is a way to hide the private @IP address and
the possibility to rewrite the Contact field with the public @IP of the
HGW in order for the P-CSCF thinks that the UA is registered with the
public @IP address and not the private one.

Is it possible and how ?

Thanks a lot for your help.

Olivier

PS: Here it is my opensips configuration:

# ----------- global configuration parameters ------------------------

debug=3                  # debug level (cmd line: -dddddddddd)
log_stderror=yes             # (cmd line: -E)
log_facility=LOG_LOCAL1

fork=yes
sip_warning=0

check_via=no    # (cmd. line: -v)
#dns=yes           # (cmd. line: -r)
dns=no           # (cmd. line: -r)
#rev_dns=yes      # (cmd. line: -R)
rev_dns=no      # (cmd. line: -R)
disable_tcp=yes
disable_dns_blacklist=yes
disable_dns_failover=yes

listen=udp:192.168.1.1:5060
listen=udp:217.70.81.211:5060

children=1

auto_aliases=no
alias="zpna.systerminal.eu:5060"

# ------------------ module loading ----------------------------------

mpath="/usr/lib/opensips/modules"
loadmodule "db_text.so"
loadmodule "sl.so"
loadmodule "tm.so"
loadmodule "rr.so"
loadmodule "xlog.so"
loadmodule "mi_fifo.so"
loadmodule "maxfwd.so"
loadmodule "uac.so"
loadmodule "usrloc.so"
loadmodule "registrar.so"
loadmodule "auth.so"
loadmodule "auth_db.so"
loadmodule "alias_db.so"
loadmodule "uri.so"
loadmodule "uri_db.so"
loadmodule "domain.so"
loadmodule "nathelper.so"
loadmodule "textops.so"
loadmodule "avpops.so"
loadmodule "permissions.so"
loadmodule "presence.so"
loadmodule "presence_xml.so"
loadmodule "pua.so"
loadmodule "rls.so"
loadmodule "xcap_client.so"

# ----------------- setting module-specific parameters ---------------
# -- multi-modules params --
modparam("usrloc|permissions|auth_db|uri_db|domain|presence|presence_xml|rls|pua|xcap_client|alias_db",
          "db_url", "text:///etc/opensips/opensipsdb")
modparam("auth_db|alias_db|uri_db|usrloc", "use_domain", 1)

# -- mi_fifo params --
modparam("mi_fifo", "fifo_name", "/tmp/opensips_fifo")
modparam("mi_fifo", "fifo_mode", 0666)

# -- rr params --
# add value to ;lr param to make some broken UAs happy
modparam("rr", "enable_full_lr", 1)

# -- nathelper --
modparam("nathelper", "rtpproxy_sock", "unix:/var/run/rtpproxy.sock")
modparam("nathelper", "natping_interval", 60)
modparam("nathelper", "ping_nated_only", 1)
modparam("nathelper", "received_avp", "$avp(i:9)")

# -- timer params --
modparam("tm", "fr_timer", 5)
modparam("tm", "fr_inv_timer", 100)
modparam("tm", "wt_timer", 10)

# -- usrloc params --
modparam("usrloc", "db_mode", 1)
modparam("usrloc", "timer_interval", 10)
modparam("usrloc", "nat_bflag", 6)
modparam("usrloc", "desc_time_order", 1)

# -- auth params --
modparam("auth", "nonce_expire",  300)
modparam("auth", "realm_prefix", "sip.")
# modparam("auth", "rpid_avp", "$avp(rpid)")

# -- auth_db params --
modparam("auth_db", "password_column", "password")
modparam("auth_db", "calculate_ha1", 1)

# -- registrar params --
modparam("registrar", "max_contacts", 2)
modparam("registrar", "received_avp", "$avp(i:9)")
modparam("registrar", "sock_flag", 12)
modparam("registrar", "sock_hdr_name", "Local-Sock")
modparam("registrar", "max_expires", 3600)

# -- permissions params --
modparam("permissions", "db_mode", 1)
modparam("permissions", "trusted_table", "trusted")

# -- presence params --
modparam("presence", "server_address", "sip:192.168.1.1:5060")
modparam("presence_xml", "force_active", 1)
modparam("presence_xml", "integrated_xcap_server", 0)
modparam("presence_xml", "xcap_server", "192.168.1.8")

# -- rls parameters --
modparam("rls", "xcap_root", "http://192.168.1.8/xcap-root:8000")
modparam("rls", "server_address", "sip:192.168.1.1:5060")
modparam("rls", "integrated_xcap_server", 0)
modparam("rls", "presence_server", "sip:192.168.1.1:5060")
modparam("rls", "to_presence_code", 10)

# ---- flags
#  6 - do NAT
# 10 - to P-CSCF

# -------------------------  request routing logic -------------------

# Main routing logic
route {

    # initial sanity checks -- messages with
    # max_forwards==0, or excessively long requests
    if (!mf_process_maxfwd_header("10")) {
        sl_send_reply("483","Too Many Hops");
        exit;
    };
    if ( msg:len > 16384 ) {
        sl_send_reply("513", "Message too big");
        exit;
    };

    # Sanity Check: Accept only messages from local hosts and P-CSCF
    if (!(allow_address("1", "$si", "$sp") || allow_trusted())) {
      xlog("L_WARN", "Received SIP message from unkown host: $si:$sp\n");
      sl_send_reply("403", "Forbidden");
      exit;
    };

    # Record Route Section
    if (!is_method("REGISTER")) {
        record_route();
    };

    # Call Tear down Section
    if (is_method("BYE") || is_method("CANCEL")) {
        unforce_rtp_proxy();
    };

    # Loose Route Section
    if (loose_route()) {

        xlog("L_INFO", "Start loose_route() statement\n");

        if (is_method("INVITE|REFER") && !has_totag()) {
            sl_send_reply("403", "Forbidden");
            exit;
        };

        if (is_method("INVITE|REFER")) {
            if (nat_uac_test("19")) {
                setflag(6);
                force_rport();
                fix_nated_contact();
            }
            force_rtp_proxy("l");
        };

        route(1);

    exit;
    };

    # Call Processing Section
    xlog("L_INFO", "Start Call Processing Section\n");

    if (is_method("ACK|CANCEL")) {
        xlog("L_INFO", "Process ACK & CANCEL\n");
        route(1);
        exit;
    } else if (is_method("INVITE|REFER")) {
        xlog("L_INFO", "Process INVITE & REFER\n");
        route(3);
        exit;
    } else if( is_method("PUBLISH|SUBSCRIBE|NOTIFY")) {
        # xlog("L_INFO", "Process PRESENCE\n");
        route(5);
        exit;
    } else if (is_method("REGISTER")) {
        xlog("L_INFO", "Process REGISTER\n");
        route(2);
        exit;
    };

    lookup("aliases");
    if (uri!=myself) {
        route(4);
        route(1);
        exit;
    };

    if (!lookup("location")) {
        sl_send_reply("404", "User Not Found");
        exit;
    };
    route(1);
}

# Default Message Handler
route[1] {

    xlog("L_INFO", "Ready to route the message\n");

    t_on_reply("1");

    # Route packet accordingly the WAN flag i.e. via P-CSCF or directly
    if (isflagset(10)) {
        if (!t_relay("udp:217.70.81.197:4060")) {
            if (is_method("INVITE|REFER") && isflagset(6)) {
                unforce_rtp_proxy();
            };
            sl_reply_error();
        };
    } else {
        if (!t_relay()) {
            if (is_method("INVITE|REFER") && isflagset(6)) {
                unforce_rtp_proxy();
            };
            sl_reply_error();
        };
    };
}

# IMS REGISTER Handler
route[6] {
    xlog("L_INFO", "Handle IMS register\n");

    if (!($rd=~"^ims.systerminal.eu")) {
        sl_send_reply("403", "Your are only authorize to register in
ims.systerminal.eu domain\n");
        exit;
    }

    if (has_totag()) {
        xlog("L_INFO", "Spoofed To-URI detected - M=$rm RURI=$ru F=$fu
T=$tu IP=$si ID=$ci\n");
        sl_send_reply("403", "Spoofed To-URI Detected");
        exit;
    }

    # Record Route to tell IMS Core that I'm behind the HGW
    record_route();

    # Fix NAT
    if (!search("^Contact:[ ]*\*") && nat_uac_test("19")) {
        xlog("L_INFO", "Request NAT for REGISTER of contact $ct for $fu\n");
        setflag(6);
        fix_nated_contact();
        force_rport();
    }

    # Send message to P-CSCF
    if (!t_relay("udp:217.70.81.197:4060")) {
        if (!t_relay()) {
        xlog("L_WARN", "Failed to send REGISTER message to IMS\n");
    }
}

# INVITE & REFER Message Handler
route[3] {

    xlog("L_INFO", "Start Processing INVITE & REFER Messages\n");

    if (nat_uac_test("19")) {
        xlog("L_INFO", "Request NAT for INVITE of $fu to $ru [$tu]\n");
        setflag(6);
    }

    lookup("location");
    switch ($retcode) {
        case 1:        # LAN Session
            xlog("L_INFO", "LAN Session\n");
            route(1);
            exit;
        case -1:    # WAN Session
            xlog("L_INFO", "WAN Session\n");
            setflag(10);
            route(4);
            route(1);
            exit;
        case -3:
            sl_send_reply("404", "Not Found");
            exit;
        case -2:
            sl_send_reply("405", "Not Found");
            exit;
    };

}

# NAT Traversal Section
route[4] {
    if (isflagset(6)) {
        xlog("L_INFO", "Performe NAT of $ct for $fu\n");
        force_rport();
        fix_nated_contact();
        force_rtp_proxy();
    }
}

# Presence routing handler
route[5] {

    # Test if PRESENCE is for IMS CORE
    if ($rd=~"^ims.systerminal.eu") {
        # xlog("L_INFO", "Send Presence message to P-CSCF\n");
        setflag(10);
        setflag(6);
        route(4);
        route(1);
        exit;
    };

    if (!t_newtran()) {
        sl_reply_error();
        exit;
    };

    if (is_method("PUBLISH")) {
        # xlog("L_INFO", "Process PRESENCE PUBLISH message\n");
        handle_publish();
        t_release();
        exit;
    }

    if (is_method("NOTIFY")) {
        # xlog("L_INFO", "Process PRESENCE NOTIFY message\n");
        rls_handle_notify();
        switch ($retcode) {
        case 1:
            # Notify processed by rls
            xlog("L_INFO", "$rm processed by RLS\n");
            t_release();
            break;
        case -1:
            # Error
            xlog("L_INFO", "$rm processed by RLS but has error\n");
            t_reply("500", "Server error while processing RLS NOTIFY");
            break;
        default:
            if (uri == "sip:rls at 192.168.1.1") {
                xlog("L_ERR", "$rm should be processed by RLS but was
not recognized\n");
                xlog("L_INFO", "Dropping $rm because it will loop\n");
                t_reply("500", "Server error while processing RLS NOTIFY");
            } else {
                xlog("L_INFO", "$rm handled by presence\n");
                t_release();
            }
        }
        exit;
    }

    if (is_method("SUBSCRIBE")) {
        # Internal presence handling
        # xlog("L_INFO", "Process PRESENCE SUBSCRIBE message\n");
        rls_handle_subscribe();

        switch ($retcode) {
        case 10:
            # RLS indicated that message should be processed by presence
            if (is_uri_host_local()) {
                if (does_uri_exist()) {
                    handle_subscribe();
                    t_release();
                } else {
                    t_reply("404", "User not found");
                }
                exit;
            }
            break;
        default:
            t_release();
            exit;
        }
    }
}

# NAT for ACK, BYE, CANCEL & co.
onreply_route[1] {

    xlog("L_INFO", "Process ACK, BYE & CANCEL Messages\n");

    if (isflagset(6) && status=~"(180)|(183)|2[0-9][0-9]") {
        if (!search("^Content-Length:[ ]*0")) {
            xlog("L_INFO", "Check NAT for reply route\n");
            force_rtp_proxy();
        };
    };

    if (nat_uac_test("1")) {
        xlog("L_INFO", "Fix NAT on reply route\n");
        fix_nated_contact();
    };
}



-- 

Olivier Dugeon





More information about the Users mailing list