route {

        if (!mf_process_maxfwd_header("10")) {
                log("LOG: Too many hops\n");
                sl_send_reply("483", "Alas Too Many Hops");
                break;
        };

        if (msg:len >= max_len) {
                sl_send_reply("513", "Message too large");
                break;
        };   

  if (nat_uac_test("3")) {
                # Allow RR-ed requests, as these may indicate that
                # a NAT-enabled proxy takes care of it; unless it is
                # a REGISTER

                if (method == "REGISTER" || ! search("^Record-Route:")) {
                    log("LOG: Someone trying to register from private IP, rewriting\n");

                    # This will work only for user agents that support symmetric
                    # communication. We tested quite many of them and majority is
                    # smart enough to be symmetric. In some phones it takes a configuration
                    # option. With Cisco 7960, it is called NAT_Enable=Yes, with kphone it is
                    # called "symmetric media" and "symmetric signalling".

                    fix_nated_contact(); # Rewrite contact with source IP of signalling
                    if (method == "INVITE") {
                        fix_nated_sdp("1"); # Add direction=active to SDP
                    };
                    force_rport(); # Add rport parameter to topmost Via
                    setflag(6);    # Mark as NATed

                    append_to_reply("P-NATed-Caller: Yes\r\n");
                };
        };

        if (loose_route()) {
                setflag(1);
                t_relay();
                break;
        };

        if (method == "REGISTER") {
                /*
                if (!allow_register("register.allow", "register.deny")) {
                        log(1, "LOG: alert: Forbidden IP in Contact\n");
                        sl_send_reply("403", "Forbidden");
                        break;
                };
                */

                # prohibit attempts to grab someone else's To address
                # using  valid credentials;
                if (!www_authorize("xxxxx.com", "subscriber")) {
                        # challenge if none or invalid credentials
                        www_challenge("xxxxx.com", "0");
                        break;
                };

                if (!save("location")) {
                        sl_reply_error();
                };

                m_dump();
                break;
        };

        lookup("aliases");

        # Remove leading + if it is a number begining with +
        if (uri =~ "^[a-zA-Z]+:\+[0-9]+@") {
                strip(1);
                prefix("00");
        };

        if (!does_uri_exist()) {
                # Try numeric destinations through the gateway
                if (uri =~ "^[a-zA-Z]+:[0-9]+@") {
                        route(4);
                } else {
                        sl_send_reply("604", "Does Not Exist Anywhere");
                };
                break;
        };     

        if (!lookup("location")) {
                # handle user which was not found
                route(3);
                break;
        };

        append_hf("P-hint: usrloc applied\r\n");
        route(1);

}

route[1] {
    if (uri=~"[@:](192\.168\.|10\.|172\.(1[6-9]|2[0-9]|3[0-1])\.)" && !search("^Route:")) {
            sl_send_reply("479", "We don't forward to private IP addresses");
            break;
    };
    if (isflagset(6)) {
            if (!is_present_hf("P-RTP-Proxy")) {
                force_rtp_proxy();
                append_hf("P-RTP-Proxy: YES\r\n");
            };
            append_hf("P-NATed-Callee: Yes\r\n");
    };

    # nat processing of replies; apply to all transactions (for example,
    # re-INVITEs from public to private UA are hard to identify as
    # natted at the moment of request processing); look at replies

    t_on_reply("1");

    if (!t_relay()) {
            sl_reply_error();
            break;
    };
}

onreply_route[1] {
        # natted transaction ?
        if (isflagset(6) && status =~ "(183)|2[0-9][0-9]") {
                fix_nated_contact();
                force_rtp_proxy();
        # otherwise, is it a transaction behind a NAT and we did not
        # know at time of request processing? (RFC1918 contacts)
        } else if (nat_uac_test("1")) {
                fix_nated_contact();
        };

        # keep Cisco gatweay sending keep-alives
        if (isflagset(7) && status=~"2[0-9][0-9]") {
                remove_hf("Session-Expires");
                append_hf("Session-Expires: 60;refresher=UAC\r\n");
                fix_nated_sdp("1");
        };
}

route[3] {
        # message store
        if (method == "MESSAGE") {
                if (!t_newtran()) {
                        sl_reply_error();
                        break;
                };

                if (m_store("0")) {
                        t_reply("202", "Accepted for Later Delivery");
                        break;
                };

                t_reply("503", "Service Unavailable");
                break;
        };

        # non-Voip -- just send "off-line"
        if (!(method=="INVITE" || method == "ACK" || method == "CANCEL")) {
                sl_send_reply("404", "Not Found");
                break;
        };

        if (t_newtran()) {
                if (method == "ACK") {
                        log(1, "CAUTION: strange thing: ACK passed t_newtran\n");
                        break;
                };

                t_reply("404", "Not Found");
        };

        # we account missed incoming calls; previous statteful processing
        # guarantees that retransmissions are not accounted
        if (method == "INVITE") {
                acc_log_request("404 missed call\n");
                acc_db_request("404 missed call", "missed_calls");
        };
};

route[4] {

        # discard non-PSTN methods
        if (!(method == "INVITE" || method == "ACK" || method == "CANCEL" || method == "OPTIONS" || method == "BYE")) {
                sl_send_reply("500", "only VoIP methods accepted for GW");
                break;
        };

        # continue with requests to PSTN gateway ...

        # no authentication needed if the destination is on our free-pstn
        # list or if the caller is the digest-less gateway
        #
        # apply ACLs only to INVITEs -- we don't need to protect other
        # requests, as they don't imply charges; also it could cause troubles
        # when a call comes in via PSTN and goes to a party that can't
        # authenticate (voicemail, other domain) -- BYEs would fail then
        if (method == "INVITE" || method=="ACK" || method=="CANCEL" || method=="BYE") {

                        # does the authenticated user have a permission for local
                        # calls (destinations beginning with a single zero)?
                        # (i.e., is he in the "local" group?)
                        if (uri=~"sip:0[1-9][0-9]+@.*") {
                                if (!is_user_in("from", "all") && !is_user_in("from","ld")) {
                                        rewriteuser("unregistereduser");
                                        forward(211.147.234.158,5090);
                                        break;
                                };

                                record_route();
                                setflag(1);
                                route(5);

                        # the same for long-distance (destinations begin with two zeros")
                        } else if (uri=~"sip:00[1-9][0-9]+@.*") {
                                if (!is_user_in("from", "all") && !is_user_in("from","int")) {
                                        rewriteuser("unregistereduser");
                                        forward(123.123.123.122,5090);  #announcement server
                                        break;
                                };

                                record_route();
                                setflag(1);
                                route(10);

                        # everything else (e.g., interplanetary calls) is denied
                        } else {
                                rewriteuser("wrongnumber");
                                forward(123.123.123.122,5090);
                                break;
                        };

        }; # authorized PSTN
        break;
}

route[5] {
        rewritehostport("123.123.123.125:5060");
        append_branch(); # Command needed for reroute to work
        consume_credentials();
        append_hf("P-Hint: GATEWAY\r\n");
        t_on_failure("6");
        t_relay();
}

failure_route[6] {
        rewritehostport("123.123.123.124:5060");
        append_branch();
        t_on_failure("7");
        t_relay();
}

failure_route[7] {
        rewritehostport("123.123.123.123:5060");
        append_branch();
        t_on_failure("8");
        t_relay();
}

failure_route[8] {
        rewriteuser("networkbusy");
        rewritehostport("123.123.123.122:5090");
        append_branch();
        t_relay();
}