Inbound calls fail to authenticate and drop



I am trying to connect my ITSP’s IMS service to my Asterisk instance at home. I managed to get outbound working but inbound doesn’t want to cooperate. When I call my home phone [HOME-PHONE], my call immideately gets dropped.

The error in question:

[May 11 17:02:01] NOTICE[29723][C-00000001] chan_sip.c: From address missing 'sip:', using it anyway
[May 11 17:02:01] ERROR[29723][C-00000001] chan_sip.c: Empty domain name in FROM header
[May 11 17:02:01] NOTICE[29723][C-00000001] chan_sip.c: Failed to authenticate device <tel:[REDACTED]>;tag=ztesip[REDACTED]

Verbose output:

[May 11 17:18:44] VERBOSE[29723] chan_sip.c: 
<--- SIP read from UDP: --->
INVITE sip:s@ SIP/2.0
Via: SIP/2.0/UDP;branch=[REDACTED]
To: <tel:+90[HOME-PHONE]>
From: <tel:[CELLPHONE]>;tag=ztesip[REDACTED]
Call-ID: [REDACTED]@zteims
CSeq: 1000 INVITE
Max-Forwards: 43
Contact: <sip:[CELLPHONE]@;zte-did=[REDACTED]>
Record-Route: <sip:;lr>
P-Called-Party-ID: <sip:+90[HOME-PHONE];user=phone>
Supported: 100rel,timer
P-Early-Media: supported
P-Asserted-Identity: <tel:[CELLPHONE]>
User-Agent: ZTE Softswitch/1.0.0
Privacy: none
Min-SE: 90
Session-Expires: 600;refresher=uac
Content-Type: application/sdp
Content-Length: 171
Content-Disposition: session

o=- 77 935547305 IN IP4
c=IN IP4
t=0 0
m=audio 21132 RTP/AVP 8 0 18 4 97
a=rtpmap:97 telephone-event/8000
a=fmtp:97 0-15
[May 11 17:18:44] VERBOSE[29723] chan_sip.c: --- (22 headers 9 lines) ---
[May 11 17:18:44] VERBOSE[29723] chan_sip.c: Sending to (NAT)
[May 11 17:18:44] VERBOSE[29723][C-00000003] chan_sip.c: Sending to (NAT)
[May 11 17:18:44] VERBOSE[29723][C-00000003] chan_sip.c: Using INVITE request as basis request - [REDACTED]@zteims
[May 11 17:18:44] NOTICE[29723][C-00000003] chan_sip.c: From address missing 'sip:', using it anyway
[May 11 17:18:44] ERROR[29723][C-00000003] chan_sip.c: Empty domain name in FROM header
[May 11 17:18:44] NOTICE[29723][C-00000003] chan_sip.c: Failed to authenticate device <tel:[CELLPHONE]>;tag=ztesip[REDACTED]
[May 11 17:18:44] VERBOSE[29723][C-00000003] chan_sip.c: 
<--- Reliably Transmitting (NAT) to --->
SIP/2.0 403 Forbidden
Via: SIP/2.0/UDP;branch=[REDACTED];received=;rport=5060
From: <tel:[CELLPHONE]>;tag=ztesip[REDACTED]
To: <tel:+90[HOME-PHONE]>;tag=[REDACTED]
Call-ID: [REDACTED]@zteims
CSeq: 1000 INVITE
Server: Asterisk PBX 16.3.0
Supported: replaces, timer
Content-Length: 0

[May 11 17:18:44] VERBOSE[29723][C-00000003] chan_sip.c: Scheduling destruction of SIP dialog '[REDACTED]@zteims' in 32000 ms (Method: INVITE)
[May 11 17:18:44] VERBOSE[29723] chan_sip.c: 
<--- SIP read from UDP: --->
ACK sip:s@ SIP/2.0
Via: SIP/2.0/UDP;rport=5060;branch=[REDACTED]
To: <tel:+90[HOME-PHONE]>;tag=[REDACTED]
From: <tel:[CELLPHONE]>;tag=ztesip[REDACTED]
Call-ID: [REDACTED]@zteims
CSeq: 1000 ACK
Max-Forwards: 70
User-Agent: ZTE-SBC
Content-Length: 0

[May 11 17:18:44] VERBOSE[29723] chan_sip.c: --- (9 headers 0 lines) ---
[May 11 17:18:44] VERBOSE[29723] chan_sip.c: Really destroying SIP dialog '[REDACTED]@zteims' Method: ACK

chan_sip configuration

register => +90[HOME-PHONE][PASS]:"+90[HOME-PHONE]"@ttkom




exten => s,1,Dial(SIP/6970)

exten => _X.,1,Dial(SIP/ttkom/${EXTEN})

Running Asterisk 16.3.0 on Ubuntu 16.04.


chan_sip doesn’t support tel: URIs. Support for them is not required of a compliant SIP server.

I don’t know whether chan_pjsip does.


chan_pjsip doesn’t support it either.

I have seen posts about a chan_sip patch which has been merged in 2014 that gives support to tel: URIs. But I couldn’t find any detailed information.


The second possibilty is that the request is not coming from the first address to which the domain in host= parameter resolves.

Which is quite true as no public domain name should resolve to a 10/8, private, address.

#5 is not a public domain, as it resides in a VLAN network.


Does the full domain name resolve to and only to that?


Not the root but the [region].[province] endpoint does.


Maybe the tel: patch only supports request URIs and the parse error on the From is preventing authentication, even though From isn’t needed to authenticate. It certainly seems to be struggling with the From header tel: URI.

I don’t have a current source tree to hand to look at how the code actually handles tel:

1 Like

I had to take a look at the latest chan_sip code on Gerrit. And I think I found the function where tel: is handled.

/*! \brief  Check if matching user or peer is defined
 	Match user on From: user name and peer on IP/port
	This is used on first invite (not re-invites) and subscribe requests
    \return 0 on success, non-zero on failure
static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_request *req,
					      int sipmethod, const char *uri, enum xmittype reliable,
					      struct ast_sockaddr *addr, struct sip_peer **authpeer)
	char *of, *name, *unused_password, *domain;
	RAII_VAR(char *, ofbuf, NULL, ast_free); /* beware, everyone starts pointing to this */
	RAII_VAR(char *, namebuf, NULL, ast_free);
	enum check_auth_result res = AUTH_DONT_KNOW;
	char calleridname[256];
	char *uri2 = ast_strdupa(uri);

	terminate_uri(uri2);	/* trim extra stuff */

	ofbuf = ast_strdup(sip_get_header(req, "From"));
	/* XXX here tries to map the username for invite things */

	/* strip the display-name portion off the beginning of the FROM header. */
	if (!(of = (char *) get_calleridname(ofbuf, calleridname, sizeof(calleridname)))) {
		ast_log(LOG_ERROR, "FROM header can not be parsed\n");
		return res;

	if (calleridname[0]) {
		ast_string_field_set(p, cid_name, calleridname);

	if (ast_strlen_zero(p->exten)) {
		char *t = uri2;
		if (!strncasecmp(t, "sip:", 4)) {
			t += 4;
		} else if (!strncasecmp(t, "sips:", 5)) {
			t += 5;
		} else if (!strncasecmp(t, "tel:", 4)) {	/* TEL URI INVITE */
			t += 4;
		ast_string_field_set(p, exten, t);
		t = strchr(p->exten, '@');
		if (t)
			*t = '\0';

		if (ast_strlen_zero(p->our_contact)) {
			build_contact(p, req, 1);

	of = get_in_brackets(of);

	/* save the URI part of the From header */
	ast_string_field_set(p, from, of);

	if (parse_uri_legacy_check(of, "sip:,sips:,tel:", &name, &unused_password, &domain, NULL)) {
		ast_log(LOG_NOTICE, "From address missing 'sip:', using it anyway\n");



	if (ast_strlen_zero(domain)) {
		/* <sip:name@[EMPTY]>, never good */
		ast_log(LOG_ERROR, "Empty domain name in FROM header\n");
		return res;

	if (ast_strlen_zero(name)) {
		/* <sip:[EMPTY][@]hostport>. Asterisk 1.4 and 1.6 have always
		 * treated that as a username, so we continue the tradition:
		 * uri is now <sip:host@hostport>. */
		name = domain;
	} else {
		/* Non-empty name, try to get caller id from it */
		char *tmp = ast_strdupa(name);
		/* We need to be able to handle from-headers looking like
		tmp = strsep(&tmp, ";");
		if (global_shrinkcallerid && ast_is_shrinkable_phonenumber(tmp)) {
		ast_string_field_set(p, cid_num, tmp);

	if (global_match_auth_username) {
		 * XXX This is experimental code to grab the search key from the
		 * Auth header's username instead of the 'From' name, if available.
		 * Do not enable this block unless you understand the side effects (if any!)
		 * Note, the search for "username" should be done in a more robust way.
		 * Note2, at the moment we check both fields, though maybe we should
		 * pick one or another depending on the request ? XXX
		const char *hdr = sip_get_header(req, "Authorization");
		if (ast_strlen_zero(hdr)) {
			hdr = sip_get_header(req, "Proxy-Authorization");

		if (!ast_strlen_zero(hdr) && (hdr = strstr(hdr, "username=\""))) {
			namebuf = name = ast_strdup(hdr + strlen("username=\""));
			name = strsep(&name, "\"");

	res = check_peer_ok(p, name, req, sipmethod, addr,
			authpeer, reliable, calleridname, uri2);
	if (res != AUTH_DONT_KNOW) {
		return res;

	/* Finally, apply the guest policy */
	if (sip_cfg.allowguest) {
		/* Ignore check_return warning from Coverity for get_rpid below. */
		get_rpid(p, req);
		p->rtptimeout = global_rtptimeout;
		p->rtpholdtimeout = global_rtpholdtimeout;
		p->rtpkeepalive = global_rtpkeepalive;
		if (!dialog_initialize_rtp(p)) {
		} else {
	} else {
		res = AUTH_SECRET_FAILED; /* we don't want any guests, authentication will fail */

	if (ast_test_flag(&p->flags[1], SIP_PAGE2_RPORT_PRESENT)) {
		ast_set_flag(&p->flags[0], SIP_NAT_RPORT_PRESENT);

	return res;

I’m wondering why there is a log notice about missing sip: when also using tel: to check the uri.

Late edit: I think I found the culprit.

        if (ast_strlen_zero(domain)) {
                /* <sip:name@[EMPTY]>, never good */
                ast_log(LOG_ERROR, "Empty domain name in FROM header\n");
                return res;

Since res is still set to AUTH_DONT_KNOW, it is probably rejected.


It appears to be failing to parse out the bit in angle brackets, which means it is trying to match the scheme against “<tel:”, rather than “tel:”, and everything else falls to pieces after that. However I cannot see how that would happen, from the code you have extracted.


The angle brackers are redundant in this case, but without looking at the current code, I couldn’t see why that would casue it to mis-parse.