无法从 Asterisk 服务器获得 200 OK

Posted

技术标签:

【中文标题】无法从 Asterisk 服务器获得 200 OK【英文标题】:Unable to get 200 OK from Asterisk server 【发布时间】:2020-11-05 21:54:18 【问题描述】:

我正在 Eclipse 中开发一个 SIP 客户端应用程序。我正在尝试注册到 Asterisk Server,但每次我得到 401 Unauthorized。在收到第一条 401 消息后,我还包含了 Authorization 标头。

REGISTER sip:xx.xx.xx.xx SIP/2.0
Call-ID: ef0ef86022c9a70909dfe9d7315c2929@192.168.0.6
CSeq: 1 REGISTER
From: <sip:Santanu@xx.xx.xx.xx>;tag=textclientv1.0
To: <sip:Santanu@xx.xx.xx.xx>
Via: SIP/2.0/UDP 192.168.0.6:5060
Max-Forwards: 70
Expires: 180
Content-Length: 0


SIP/2.0 401 Unauthorized
Via: SIP/2.0/UDP 192.168.0.6:5060;branch=z9hG4bK-363031-07183c4bdcc67d2a427747d132335a51;received=115.187.33.88;rport=5060
From: <sip:Santanu@xx.xx.xx.xx>;tag=textclientv1.0
To: <sip:Santanu@xx.xx.xx.xx>;tag=as7fe2c61e
Call-ID: ef0ef86022c9a70909dfe9d7315c2929@192.168.0.6
CSeq: 1 REGISTER
Server: Asterisk PBX 16.7.0
Allow: INVITE,ACK,CANCEL,OPTIONS,BYE,REFER,SUBSCRIBE,NOTIFY,INFO,PUBLISH,MESSAGE
Supported: replaces,timer
WWW-Authenticate: Digest algorithm=MD5,realm="asterisk",nonce="75a0c702"
Content-Length: 0


REGISTER sip:xx.xx.xx.xx SIP/2.0
Call-ID: da592663fd88f0496380a3888844df95@192.168.0.6
CSeq: 1 REGISTER
From: <sip:Santanu@xx.xx.xx.xx>;tag=textclientv1.0
To: <sip:Santanu@xx.xx.xx.xx>
Via: SIP/2.0/UDP 192.168.0.6:5060
Max-Forwards: 70
Expires: 180
Authorization: Digest realm="asterisk",nonce="75a0c702",username="Santanu",uri="sip:xx.xx.xx.xx",algorithm=MD5,response="34c55995ca5bd9e5a1df9d21d1c8bd9e",cnonce="0a4f113b",nc=00000001,qop=auth
Content-Length: 0


SIP/2.0 401 Unauthorized
Via: SIP/2.0/UDP 192.168.0.6:5060;branch=z9hG4bK-363031-d081e9dc17d5bdaf73ecd2da30763b51;received=115.187.33.88;rport=5060
From: <sip:Santanu@xx.xx.xx.xx>;tag=textclientv1.0
To: <sip:Santanu@xx.xx.xx.xx>;tag=as2d43d078
Call-ID: da592663fd88f0496380a3888844df95@192.168.0.6
CSeq: 1 REGISTER
Server: Asterisk PBX 16.7.0
Allow: INVITE,ACK,CANCEL,OPTIONS,BYE,REFER,SUBSCRIBE,NOTIFY,INFO,PUBLISH,MESSAGE
Supported: replaces,timer
WWW-Authenticate: Digest algorithm=MD5,realm="asterisk",nonce="788c190c"
Content-Length: 0


REGISTER sip:xx.xx.xx.xx SIP/2.0
Call-ID: 1e89a6010565507d291a10a7412fdf7d@192.168.0.6
CSeq: 1 REGISTER
From: <sip:Santanu@xx.xx.xx.xx>;tag=textclientv1.0
To: <sip:Santanu@xx.xx.xx.xx>
Via: SIP/2.0/UDP 192.168.0.6:5060
Max-Forwards: 70
Expires: 180
Authorization: Digest realm="asterisk",nonce="788c190c",username="Santanu",uri="sip:xx.xx.xx.xx",algorithm=MD5,response="6e1abc053061344d38dfb25211e4af49",cnonce="0a4f113b",nc=00000001,qop=auth
Content-Length: 0


SIP/2.0 401 Unauthorized
Via: SIP/2.0/UDP 192.168.0.6:5060;branch=z9hG4bK-363031-e1b94f1f52aa39e35c662fc3ae261d16;received=115.187.33.88;rport=5060
From: <sip:Santanu@xx.xx.xx.xx>;tag=textclientv1.0
To: <sip:Santanu@xx.xx.xx.xx>;tag=as58c8d6ed
Call-ID: 1e89a6010565507d291a10a7412fdf7d@192.168.0.6
CSeq: 1 REGISTER
Server: Asterisk PBX 16.7.0
Allow: INVITE,ACK,CANCEL,OPTIONS,BYE,REFER,SUBSCRIBE,NOTIFY,INFO,PUBLISH,MESSAGE
Supported: replaces,timer
WWW-Authenticate: Digest algorithm=MD5,realm="asterisk",nonce="33185dc4"
Content-Length: 0

我的代码如下:

public class SipInit implements SipListener 


    private String ip;
    private SipFactory sipFactory;
    private Properties properties;
    private SipStack sipStack;
    @SuppressWarnings("unused")
    private MessageFactory messageFactory;
    private HeaderFactory headerFactory;
    private AddressFactory addressFactory;
    private ListeningPoint listeningPoint;
    private int port;
    private String protocol;
    private SipProvider sipProvider;
    private String username1;
    private String username2;
    private Address contactAddress;
    @SuppressWarnings("unused")
    private ContactHeader contactHeader;
    private String server;
    private char[] tag;
    private Request request;
    private String password;
    private ClientTransaction inviteTid;
    private Dialog dialog;
    private Response resp;
    int cseq = 0;

    public void init() throws ParseException 
        try 
            // Get the local IP address.
            this.ip = "192.168.0.6";//InetAddress.getLocalHost().getHostAddress();
            //this.tag=" ".toCharArray();
            // Create the SIP factory and set the path name.
            this.sipFactory = SipFactory.getInstance();
            this.port=5060;
            this.protocol="udp";
            this.server="178.63.254.99";
            this.username1="Santanu";
            this.username2="Arijit";
            this.password="voip123";
            
            this.sipFactory.setPathName("gov.nist");
            // Create and set the SIP stack properties.
            this.properties = new Properties();
            this.properties.setProperty("javax.sip.STACK_NAME", "stack");
            this.properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "32");



            this.properties.setProperty(
                    "gov.nist.javax.sip.LOG_MESSAGE_CONTENT", "true");
            this.properties.setProperty("gov.nist.javax.sip.DEBUG_LOG",
                    "mss-jsip-debuglog.txt");
            this.properties.setProperty("gov.nist.javax.sip.SERVER_LOG",
                    "mss-jsip-messages.xml");
            // Create the SIP stack.
            this.sipStack = this.sipFactory.createSipStack(this.properties);
            // Create the SIP message factory.
            this.messageFactory = this.sipFactory.createMessageFactory();
            // Create the SIP header factory.
            this.headerFactory = this.sipFactory.createHeaderFactory();
            // Create the SIP address factory.
            this.addressFactory = this.sipFactory.createAddressFactory();
            // Create the SIP listening point and bind it to the local IP
            // address, port and protocol.
            this.listeningPoint = this.sipStack.createListeningPoint(this.ip,
                    this.port, this.protocol);
            // Create the SIP provider.
            this.sipProvider = this.sipStack
                    .createSipProvider(this.listeningPoint);
            // Add our application as a SIP listener.
            this.sipProvider.addSipListener(this);
            // Create the contact address used for all SIP messages.
            this.contactAddress = this.addressFactory.createAddress("sip:" + this.username1 + "@"
                    + this.ip + ";transport=udp");
            // Create the contact header used for all SIP messages.
            this.contactHeader = this.headerFactory
                    .createContactHeader(contactAddress);
            // Display the local IP address and port in the text area.
         catch (Exception e) 
            e.printStackTrace();
            // If an error occurs, display an error message box and exit.
            System.exit(-1);
        
        
        
        //r.setStatusCode(200);
        register();
    


    public void register() throws NullPointerException
        
        Object logger;
        try 
        
        cseq++;
        
        ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
        ViaHeader viaHeader = this.headerFactory.createViaHeader(this.ip,
        this.port, "udp", "abcd");
        viaHeaders.add(viaHeader);
        // The "Max-Forwards" header.
        MaxForwardsHeader maxForwardsHeader = this.headerFactory
        .createMaxForwardsHeader(70);
        // The "Call-Id" header.
        CallIdHeader callIdHeader = this.sipProvider.getNewCallId();
        // The "CSeq" header.
        @SuppressWarnings("deprecation")
        CSeqHeader cSeqHeader = this.headerFactory.createCSeqHeader(cseq,
        "REGISTER");

        Address fromAddress = addressFactory.createAddress("sip:"
        + username1 + '@' + server);

        FromHeader fromHeader = this.headerFactory.createFromHeader(
        fromAddress, "textclientv1.0");//String.valueOf(this.tag)//Integer.toString(hashCode())
        // The "To" header.
        ToHeader toHeader = this.headerFactory.createToHeader(fromAddress,
        null);

        // this.contactHeader = this.headerFactory
        // .createContactHeader(contactAddress);

        request = this.messageFactory.createRequest("REGISTER sip:"
        + server + " SIP/2.0\r\n\r\n");
        
        request.addHeader(viaHeader);
        request.addHeader(maxForwardsHeader);
        request.addHeader(fromHeader);
        request.addHeader(toHeader);
        request.addHeader(callIdHeader);
        request.addHeader(cSeqHeader);
        
        request.addHeader(contactHeader);
        /*URI requestURI = addressFactory.createURI("sip:" + server);
        
        Request request = messageFactory.createRequest(requestURI,
                Request.REGISTER, callIdHeader, cSeqHeader, fromHeader,
                toHeader, viaHeaders, maxForwardsHeader);
        request.addHeader(contactHeader);*/
        /*Request request = messageFactory.createRequest(requestURI,
                Request.REGISTER, callIdHeader, cSeqHeader, fromHeader,
                toHeader, viaHeaders, maxForwardsHeader);*/
        
        
        //Response response=this.messageFactory.createResponse(200, request);
        HeaderFactory header=this.sipFactory.createHeaderFactory();
        ExpiresHeader eh = header.createExpiresHeader(3060);
        request.addHeader(eh);
        
        if (resp != null) 
        boolean retry = true;
        AuthorizationHeader authHeader = makeAuthHeader(headerFactory, resp,
        request, username1, password);
        request.addHeader(authHeader);
        
        System.out.println(""+ request);
        inviteTid = sipProvider.getNewClientTransaction(request);
        // send the request out.
        inviteTid.sendRequest();
        this.dialog = inviteTid.getDialog();
        // Send the request statelessly through the SIP provider.
//                  this.sipProvider.sendRequest(request);

        // Display the message in the text area.
        //debug("Request sent:\n" + request.toString() + "\n\n");
         catch (Exception e) 
        // If an error occurred, display the error.
        e.printStackTrace();
        //debug("Request sent failed: " + e.getMessage() + "\n");
        
        

    @Override
    public void processDialogTerminated(DialogTerminatedEvent arg0) 
        // TODO Auto-generated method stub

    

    @Override
    public void processIOException(IOExceptionEvent arg0) 
        // TODO Auto-generated method stub

    

    @Override
    public void processRequest(RequestEvent arg0) 
        // TODO Auto-generated method stub

    

    @Override
    public void processResponse(ResponseEvent arg0) 
        // TODO Auto-generated method stub
        resp=arg0.getResponse();
        //CSeqHeader cseq = (CSeqHeader) resp.getHeader(CSeqHeader.NAME);  
        
        try 
            Thread.sleep(1000);
         catch (InterruptedException e) 
            // TODO Auto-generated catch block
            e.printStackTrace();
        
        System.out.println(resp);
        //if(cseq<=2)
            register();
    

    @Override
    public void processTimeout(TimeoutEvent arg0) 
        // TODO Auto-generated method stub

    

    @Override
    public void processTransactionTerminated(TransactionTerminatedEvent arg0) 
        // TODO Auto-generated method stub

    
    
    private AuthorizationHeader makeAuthHeader(HeaderFactory headerFactory2,  Response response, Request request, String username2,
            String password2) throws ParseException 
        // TODO Auto-generated method stub
        // Authenticate header with challenge we need to reply to
        WWWAuthenticateHeader ah_c =  (WWWAuthenticateHeader)response.getHeader(WWWAuthenticateHeader.NAME);

        // Authorization header we will build with response to challenge
        AuthorizationHeader ah_r =    headerFactory.createAuthorizationHeader(ah_c.getScheme());

        // assemble data we need to create response string
        URI request_uri = request.getRequestURI();
        String request_method = request.getMethod();
        String nonce  = ah_c.getNonce();
        String algrm  = ah_c.getAlgorithm();
        String realm  = ah_c.getRealm();
        

        MessageDigest mdigest;
        try 
            mdigest = MessageDigest.getInstance(algrm);

             // A1
            String A1 = username2 + ":" + realm + ":" + password2;
            String HA1 = toHexString(mdigest.digest(A1.getBytes()));

            // A2
            String A2 = request_method.toUpperCase() + ":" + request_uri ;
            String HA2 = toHexString(mdigest.digest(A2.getBytes()));

            // KD
            String KD = HA1 + ":" + nonce + ":" + HA2;
            String responsenew = toHexString(mdigest.digest(KD.getBytes()));
            
            
            ah_r.setUsername(username2);
            ah_r.setRealm(realm);
            ah_r.setNonce(nonce);
            ah_r.setURI(request_uri);
            ah_r.setAlgorithm(algrm);
            ah_r.setResponse(responsenew);


         catch (NoSuchAlgorithmException e) 
            // TODO Auto-generated catch block
            e.printStackTrace();
        
        return ah_r;

    

    private static final char[] toHex =  '0', '1', '2', '3', '4', '5', '6',
            '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' ;
    
    static String toHexString(byte b[]) 
        int pos = 0;
        char[] c = new char[b.length * 2];
        for (int i = 0; i < b.length; i++) 
            c[pos++] = toHex[(b[i] >> 4) & 0x0F];
            c[pos++] = toHex[b[i] & 0x0f];
        
        return new String(c);
    

请指教。

【问题讨论】:

【参考方案1】:

你好

第一个 401 在“WWW-Authenticate:”中用“nonce”回答,客户端必须在下一次 REGISTER 时用“Authorization:”中的正确“response”回答

找出服务器不接受“响应”的原因。 ( 密码错误? ) 具有有效“响应”的第二个 REGISTER 看起来像...

[Jul 16 14:54:48] REGISTER sip:osmc SIP/2.0
[Jul 16 14:54:48] Via: SIP/2.0/UDP 192.168.178.1:5060;rport;branch=z9hG4bK0F70B6BAE0059522
[Jul 16 14:54:48] Route: <sip:192.168.178.22:5070;lr>
[Jul 16 14:54:48] From: <sip:1001@osmc>;tag=2183661807
[Jul 16 14:54:48] To: <sip:1001@osmc>
[Jul 16 14:54:48] Call-ID: C001CA03F6BF2794@192.168.178.1
[Jul 16 14:54:48] CSeq: 1704 REGISTER
[Jul 16 14:54:48] Contact: <sip:1001@192.168.178.1;uniq=0FA6428E93F9F1194B723E54CA22B>
[Jul 16 14:54:48] Authorization: Digest username="1001", realm="asterisk", nonce="4b2486f6", uri="sip:osmc", response="00c53b8da7d68da98a56bcd00f153f33", algorithm=MD5
[Jul 16 14:54:48] Max-Forwards: 70
[Jul 16 14:54:48] Expires: 1800
[Jul 16 14:54:48] User-Agent: AVM FRITZ!Box 7560 149.07.12 (Jul 3 2019)
[Jul 16 14:54:48] Supported: 100rel,replaces
[Jul 16 14:54:48] Allow-Events: telephone-event,refer,reg
[Jul 16 14:54:48] Allow: INVITE,ACK,OPTIONS,CANCEL,BYE,UPDATE,PRACK,INFO,SUBSCRIBE,NOTIFY,REFER,MESSAGE,PUBLISH
[Jul 16 14:54:48] Accept: application/sdp, multipart/mixed
[Jul 16 14:54:48] Accept-Encoding: identity
[Jul 16 14:54:48] Content-Length: 0
[Jul 16 14:54:48]
[Jul 16 14:54:48] <------------->
[Jul 16 14:54:48] --- (18 headers 0 lines) ---
[Jul 16 14:54:48] Sending to 192.168.178.1:5060 (no NAT)
[Jul 16 14:54:48]
[Jul 16 14:54:48] <--- Transmitting (no NAT) to 192.168.178.1:5060 --->
[Jul 16 14:54:48] SIP/2.0 200 OK
[Jul 16 14:54:48] Via: SIP/2.0/UDP 192.168.178.1:5060;branch=z9hG4bK0F70B6BAE0059522;received=192.168.178.1;rport=5060
[Jul 16 14:54:48] From: <sip:1001@osmc>;tag=2183661807
[Jul 16 14:54:48] To: <sip:1001@osmc>;tag=as793919e9
[Jul 16 14:54:48] Call-ID: C001CA03F6BF2794@192.168.178.1
[Jul 16 14:54:48] CSeq: 1704 REGISTER
[Jul 16 14:54:48] Server: PiBX
[Jul 16 14:54:48] Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO, PUBLISH, MESSAGE
[Jul 16 14:54:48] Supported: replaces, timer
[Jul 16 14:54:48] Expires: 1800
[Jul 16 14:54:48] Contact: <sip:1001@192.168.178.1;uniq=0FA6428E93F9F1194B723E54CA22B>;expires=1800
[Jul 16 14:54:48] Date: Thu, 16 Jul 2020 12:54:48 GMT
[Jul 16 14:54:48] Content-Length: 0

编辑-我认为您忘记了联系人: * 完全接受并使用 ;expires=1800 扩展它,例如客户必须遵循。不管客户要求什么。服务器有关于到期的最后一句话。不规则:来自客户端的Expires: 0 表示:取消注册我

【讨论】:

以上是关于无法从 Asterisk 服务器获得 200 OK的主要内容,如果未能解决你的问题,请参考以下文章

具有标题和数据的POST请求导致200 ok响应但未添加用户

状态 200 OK(),角度承诺抛出错误——没有“访问控制允许来源”

Fine Uploader 无法从亚马逊 S3 绘制缩略图

PhoneRTC Signal and Turn 服务器与 Asterisk 服务器

关于Asterisk无法加载chan_dahdi.so的问题

从 Fetch 中捕获 200 OK 以外的响应