Hello,

I'm setting up a Kamailio MSFT Teams SBC that is connected to our SIP trunk provider. This server is directly connected to the Internet and not behind a NAT routing. 

It is successfully processing invites from both sides (MSFT Teams and SIP trunk). Unfortunately the ACKs and CANCEL messages are not relaying to Teams. In the sipdump i can't find these messages. 

Does anyone see what I am doing wrong? Below you can find my config

#!KAMAILIO

####### Defined Values #########

#!define MULTIDOMAIN 0

# - flags
#   FLT_ - per transaction (message) flags
# FLB_ - per branch flags
#!define FLT_ACC 1
#!define FLT_ACCMISSED 2
#!define FLT_ACCFAILED 3
#!define FLT_NATS 5

#!define FLB_NATB 6
#!define FLB_NATSIPPING 7

#!define FROM_TEAMS 11
#!define FROM_PBX 12

######## Define Modules ###########
#!define WITH_RTPENGINE
#!define WITH_TLS
#!define WITH_SIPDUMP
#!define WITH_DISPATCH

####### Global Parameters #########

### LOG Levels: 3=DBG, 2=INFO, 1=NOTICE, 0=WARN, -1=ERR
debug=2
log_stderror=no

memdbg=5
memlog=5

log_facility=LOG_LOCAL0
log_prefix="{$mt $hdr(CSeq) $ci} "

/* number of SIP routing processes */
children=2

/* uncomment the next line to disable TCP (default on) */
# disable_tcp=yes

alias=SBC_FQDN

/* listen addresses */
listen=udp:PUBLIC_IP:5060 advertise SBC_FQDN:5060
#!ifdef WITH_TLS
listen=tls:PUBLIC_IP:5061 advertise SBC_FQDN:5061
#!endif

server_header= "Server: ABC SBC"
user_agent_header= "User-Agent: ABC SBC"


###### TLS Enable ######
#!ifdef WITH_TLS
enable_tls=yes
#tcp_connect_timeout=1000

tcp_accept_no_cl=yes
tcp_async = yes
tcp_connection_lifetime=600

/* upper limit for TLS connections */
tls_max_connections=2048
#!endif


####### Custom Parameters #########

/* These parameters can be modified runtime via RPC interface
 * - see the documentation of 'cfg_rpc' module.
 *
 * Format: group.id = value 'desc' description
 * Access: $sel(cfg_get.group.id) or @cfg_get.group.id */

####### Modules Section ########

/* set paths to location of modules */
loadmodule "jsonrpcs.so"
loadmodule "kex.so"
loadmodule "corex.so"
loadmodule "tm.so"
loadmodule "tmx.so"
loadmodule "sl.so"
loadmodule "rr.so"
loadmodule "pv.so"
loadmodule "maxfwd.so"
loadmodule "textops.so"
loadmodule "siputils.so"
loadmodule "xlog.so"
loadmodule "sanity.so"
loadmodule "ctl.so"
loadmodule "cfg_rpc.so"
loadmodule "acc.so"
loadmodule "counters.so"

#!ifdef WITH_RTPENGINE
loadmodule "rtpengine.so"
#!endif

#!ifdef WITH_TLS
loadmodule "tls.so"
#!endif

#!ifdef WITH_SIPDUMP
loadmodule "sipdump.so"
#!endif

#!ifdef WITH_DISPATCH
loadmodule "dispatcher.so"
#!endif

# ----------------- setting module-specific parameters ---------------

#!ifdef WITH_RTPENGINE
# ----- rtpengine params -----+
modparam("rtpengine", "rtpengine_sock", "udp:127.0.0.1:12222")
#!endif

#!ifdef WITH_TLS
# ----- tls params -----+
modparam("tls", "xavp_cfg", "tls")
modparam("tls", "config", "/etc/kamailio/tls.cfg")
modparam("tls", "connection_timeout", 10)
modparam("tls", "ssl_release_buffers", 1)
modparam("tls", "send_close_notify", 1)
modparam("tls", "session_cache", 0)

#!endif

#!ifdef WITH_SIPDUMP
modparam("sipdump", "enable", 1)
#!endif

#!ifdef WITH_DISPATCH
#---------- dispatch
modparam("dispatcher", "ds_probing_mode", 1)
modparam("dispatcher", "ds_ping_interval", 300)
#!endif


# ----- jsonrpcs params -----
modparam("jsonrpcs", "pretty_format", 1)
/* set the path to RPC fifo control file */
# modparam("jsonrpcs", "fifo_name", "/run/kamailio/kamailio_rpc.fifo")
/* set the path to RPC unix socket control file */
# modparam("jsonrpcs", "dgram_socket", "/run/kamailio/kamailio_rpc.sock")

# ----- ctl params -----
/* set the path to RPC unix socket control file */
# modparam("ctl", "binrpc", "unix:/run/kamailio/kamailio_ctl")

# ----- tm params -----
# auto-discard branches from previous serial forking leg
modparam("tm", "failure_reply_mode", 3)
# default retransmission timeout: 30sec
modparam("tm", "fr_timer", 30000)
# default invite retransmission timeout after 1xx: 120sec
modparam("tm", "fr_inv_timer", 120000)

# ----- rr params -----
# set next param to 1 to add value to ;lr param (helps with some UAs)
modparam("rr", "enable_full_lr", 0)
# do not append from tag to the RR (no need for this script)
modparam("rr", "append_fromtag", 0)

# ----- acc params -----
/* what special events should be accounted ? */
modparam("acc", "early_media", 0)
modparam("acc", "report_ack", 0)
modparam("acc", "report_cancels", 0)
/* by default ww do not adjust the direct of the sequential requests.
 * if you enable this parameter, be sure the enable "append_fromtag"
 * in "rr" module */
modparam("acc", "detect_direction", 0)
/* account triggers (flags) */
modparam("acc", "log_flag", FLT_ACC)
modparam("acc", "log_missed_flag", FLT_ACCMISSED)
modparam("acc", "log_extra",
  "src_user=$fU;src_domain=$fd;src_ip=$si;"
  "dst_ouser=$tU;dst_user=$rU;dst_domain=$rd")
modparam("acc", "failed_transaction_flag", FLT_ACCFAILED)

####### Routing Logic ########


/* Main SIP request routing logic
 * - processing of any incoming SIP request starts with this route
 * - note: this is the same as route { ... } */
request_route {
  # per request initial checks
  route(REQINIT);

  #check who is the sender
  route(INITCHECK);

  # CANCEL processing
  if (is_method("CANCEL")) {
    if (t_check_trans()) {
      route(RELAY);
    }
    exit;
  }

  # handle retransmissions
  if (!is_method("ACK")) {
    if(t_precheck_trans()) {
      t_check_trans();
      exit;
    }
    t_check_trans();
  }

  # handle requests within SIP dialogs
  route(WITHINDLG);

  ### only initial requests (no To tag)

  # record routing for dialog forming requests (in case they are routed)
  # - remove preloaded route headers
  remove_hf("Route");
  if (is_method("INVITE|SUBSCRIBE")) {
    record_route();
  }

  # account only INVITEs
  if (is_method("INVITE")) {
    setflag(FLT_ACC); # do accounting
  }

  if ($rU==$null) {
    # request with no Username in RURI
    sl_send_reply("484","Address Incomplete");
    exit;
  }

  # update $du to set the destination address for proxying
  #$du = "sip:" + $rd + ":9";
 
  route(RELAY);
  exit;
}

route[INITCHECK] {
  if(from_uri =~ ".*microsoft.com")
  {  
    setflag(FROM_TEAMS);
    $du = "sip:" + "PBX_IP";
    route(HANDLE_RTP_FROM_TEAMS);
  } else if(from_uri =~ ".*" + "PBX_IP")
  {
    setflag(FROM_PBX);
    $du="sip:sip.pstnhub.microsoft.com;transport=tls";
    route(HANDLE_RTP_FROM_PBX);
  } else {
    exit;
  }
}

#Manage RTP & transcoding comming from Teams to PBX
route[HANDLE_RTP_FROM_TEAMS] {
 
  if (has_body("application/sdp"))
  {
    t_on_reply("PBX_REPLY_TO_TEAMS");
    rtpengine_manage("RTP codec-mask=all codec-transcode=PCMA replace-origin replace-session-connection ICE=remove");
    record_route();
    t_relay_to_udp("PBX_IP","5060");
  }
 

}

#Manage RTP & transcoding comming from PBX to Teams
route[HANDLE_RTP_FROM_PBX] {
 
    if (has_body("application/sdp"))
    {
      t_on_reply("TEAMS_REPLY_TO_PBX");
     
      rtpengine_manage("SRTP codec-mask=all ICE=force codec-transcode=PCMA replace-origin replace-session-connection");
      record_route_preset("SBC_FQDN:5061;transport=tls");
      add_rr_param(";r2=on");

      $rd = "sip.pstnhub.microsoft.com";
      $td = "SBC_FQDN";
      $fd = "SBC_FQDN";


      #Set TLS SNI (server name & server id)
      $xavp(tls=>server_name) = "SBC_FQDN";
      $xavp(tls=>server_id) = "SBC_FQDN";

      t_relay();
    }
}


# Wrapper for relaying requests
route[RELAY] {

  # enable additional event routes for forwarded requests
  # - serial forking, RTP relaying handling, a.s.o.
  if (is_method("INVITE|BYE|SUBSCRIBE|UPDATE")) {
    if(!t_is_set("branch_route")) t_on_branch("MANAGE_BRANCH");
  }
  if (is_method("INVITE|SUBSCRIBE|UPDATE")) {
    if(!t_is_set("onreply_route")) t_on_reply("MANAGE_REPLY");
  }
  if (is_method("INVITE")) {
    if(!t_is_set("failure_route")) t_on_failure("MANAGE_FAILURE");
  }

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

# Per SIP request initial checks
route[REQINIT] {
  if($ua =~ "friendly-scanner|sipcli|VaxSIPUserAgent") {
    # silent drop for scanners - uncomment next line if want to reply
    # sl_send_reply("200", "OK");
    exit;
  }

  if (!mf_process_maxfwd_header("10")) {
    sl_send_reply("483","Too Many Hops");
    exit;
  }

  if(is_method("OPTIONS")) {
    sl_send_reply("200","Keepalive");
    exit;
  }

  if(!sanity_check("1511", "7")) {
    xlog("Malformed SIP message from $si:$sp\n");
    exit;
  }
}

# Handle requests within SIP dialogs
route[WITHINDLG] {
  if (!has_totag()) return;

  #Teams reINVITEs
  if(isflagset(FROM_TEAMS)) {
    t_relay_to_udp("PBX_IP","5060");
    exit;
  }

  # sequential request withing a dialog should
  # take the path determined by record-routing
  if (loose_route()) {
    if (is_method("BYE")) {
      setflag(FLT_ACC); # do accounting ...
      setflag(FLT_ACCFAILED); # ... even if the transaction fails

      #set coresponding cert on transactions
      if($fd == "SBC_FQDN") {
        $xavp(tls=>server_name) = "SBC_FQDN";
        $xavp(tls=>server_id) = "SBC_FQDN";
      }

    } else if ( is_method("NOTIFY") ) {
      # Add Record-Route for in-dialog NOTIFY as per RFC 6665.
      record_route();
    }

    route(RELAY);
    exit;
  }

  if ( is_method("ACK") ) {
    if ( t_check_trans() ) {
      # no loose-route, but stateful ACK;
      # must be an ACK after a 487
      # or e.g. 404 from upstream server
      route(RELAY);
      exit;
    } else {
      # ACK without matching transaction ... ignore and discard
      exit;
    }
  }
  sl_send_reply("404","Not here");
  exit;
}

# Manage outgoing branches
branch_route[MANAGE_BRANCH] {
  xdbg("new branch [$T_branch_idx] to $ru\n");
}

# Manage incoming replies
onreply_route[MANAGE_REPLY] {
  xdbg("incoming reply\n");
}

#PBX On Reply
onreply_route[PBX_REPLY_TO_TEAMS]
{
    if (has_body("application/sdp"))
  {
        rtpengine_manage("SRTP codec-mask=all codec-transcode=PCMA replace-origin replace-session-connection media-address=PUBLIC_IP");
  }
}


#From Teams On Reply
onreply_route[TEAMS_REPLY_TO_PBX]
{
    if (has_body("application/sdp"))
  {
        rtpengine_manage("RTP codec-mask=all codec-transcode=PCMA replace-origin replace-session-connection media-address=PUBLIC_IP");
  }
}

# Manage failure routing cases
failure_route[MANAGE_FAILURE] {
  if (t_is_canceled()) exit;
}

event_route[tm:local-request] {
        if(is_method("OPTIONS") && $ru =~ "pstnhub.microsoft.com") {
               append_hf("Contact: <sip:SBC_FQDN:5061;transport=tls>\r\n");
        }
        xlog("L_INFO", "Sent out tm request: $mb\n");
}