CreateBranchId() public static méthode

public static CreateBranchId ( ) : string
Résultat string
        /// <summary>
        /// New transaction ACK requests are for 2xx responses, i.e. INVITE accepted and dialogue being created.
        /// </summary>
        /// <remarks>
        /// From RFC 3261 Chapter 17.1.1.3 - ACK for non-2xx final responses
        ///
        /// IMPORTANT:
        /// an ACK for a non-2xx response will also have the same branch ID as the INVITE whose response it acknowledges.
        ///
        /// The ACK request constructed by the client transaction MUST contain
        /// values for the Call-ID, From, and Request-URI that are equal to the
        /// values of those header fields in the request passed to the transport
        /// by the client transaction (call this the "original request").  The To
        /// header field in the ACK MUST equal the To header field in the
        /// response being acknowledged, and therefore will usually differ from
        /// the To header field in the original request by the addition of the
        /// tag parameter.  The ACK MUST contain a single Via header field, and
        /// this MUST be equal to the top Via header field of the original
        /// request.  The CSeq header field in the ACK MUST contain the same
        /// value for the sequence number as was present in the original request,
        /// but the method parameter MUST be equal to "ACK".
        ///
        /// If the INVITE request whose response is being acknowledged had Route
        /// header fields, those header fields MUST appear in the ACK.  This is
        /// to ensure that the ACK can be routed properly through any downstream
        /// stateless proxies.
        ///
        /// From RFC 3261 Chapter 13.2.2.4 - ACK for 2xx final responses
        ///
        /// IMPORTANT:
        /// an ACK for a 2xx final response is a new transaction and has a new branch ID.
        ///
        /// The UAC core MUST generate an ACK request for each 2xx received from
        /// the transaction layer.  The header fields of the ACK are constructed
        /// in the same way as for any request sent within a dialog (see Section
        /// 12) with the exception of the CSeq and the header fields related to
        /// authentication.  The sequence number of the CSeq header field MUST be
        /// the same as the INVITE being acknowledged, but the CSeq method MUST
        /// be ACK.  The ACK MUST contain the same credentials as the INVITE.  If
        /// the 2xx contains an offer (based on the rules above), the ACK MUST
        /// carry an answer in its body.  If the offer in the 2xx response is not
        /// acceptable, the UAC core MUST generate a valid answer in the ACK and
        /// then send a BYE immediately.
        /// </remarks>
        private SIPRequest GetNewTransactionACKRequest(SIPResponse sipResponse, SIPURI ackURI, SIPEndPoint localSIPEndPoint)
        {
            SIPRequest ackRequest = new SIPRequest(SIPMethodsEnum.ACK, ackURI.ToString());

            ackRequest.LocalSIPEndPoint = localSIPEndPoint;

            SIPHeader header = new SIPHeader(TransactionRequest.Header.From, sipResponse.Header.To, sipResponse.Header.CSeq, sipResponse.Header.CallId);

            header.CSeqMethod           = SIPMethodsEnum.ACK;
            header.AuthenticationHeader = TransactionRequest.Header.AuthenticationHeader;
            header.ProxySendFrom        = base.TransactionRequest.Header.ProxySendFrom;

            // If the UAS supplies a desired Record-Route list use that first. Otherwise fall back to any Route list used in the original transaction.
            if (sipResponse.Header.RecordRoutes != null)
            {
                header.Routes = sipResponse.Header.RecordRoutes.Reversed();
            }
            else if (base.TransactionRequest.Header.Routes != null)
            {
                header.Routes = base.TransactionRequest.Header.Routes;
            }

            ackRequest.Header = header;

            SIPViaHeader viaHeader = new SIPViaHeader(localSIPEndPoint, CallProperties.CreateBranchId());

            ackRequest.Header.Vias.PushViaHeader(viaHeader);

            return(ackRequest);
        }
Exemple #2
0
        /// <summary>
        /// Used to create a SIP response for a request when it was not possible to parse the incoming SIP request.
        /// The response generated by this method may or may not make it back to the requester. Because the SIP
        /// request could not be parsed there are no Via headers available and without those the return network
        /// path is missing. Instead a new Via header is generated that may get through if the requester is only
        /// one SIP hop away.
        /// </summary>
        /// <param name="localSIPEndPoint">The local SIP end point the request was received on.</param>
        /// <param name="remoteSIPEndPoint">The remote SIP end point the request was received on.</param>
        /// <param name="responseCode">The response code to set on the response.</param>
        /// <param name="reasonPhrase">Optional reason phrase to set on the response (keep short).</param>
        public static SIPResponse GetResponse(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteSIPEndPoint,
                                              SIPResponseStatusCodesEnum responseCode, string reasonPhrase)
        {
            try
            {
                SIPResponse response = new SIPResponse(responseCode, reasonPhrase);
                response.SetSendFromHints(localSIPEndPoint);
                SIPSchemesEnum sipScheme = (localSIPEndPoint.Protocol == SIPProtocolsEnum.tls)
                    ? SIPSchemesEnum.sips
                    : SIPSchemesEnum.sip;
                SIPFromHeader from   = new SIPFromHeader(null, new SIPURI(sipScheme, localSIPEndPoint), null);
                SIPToHeader   to     = new SIPToHeader(null, new SIPURI(sipScheme, localSIPEndPoint), null);
                int           cSeq   = 1;
                string        callId = CallProperties.CreateNewCallId();
                response.Header            = new SIPHeader(from, to, cSeq, callId);
                response.Header.CSeqMethod = SIPMethodsEnum.NONE;
                response.Header.Vias.PushViaHeader(new SIPViaHeader(
                                                       new SIPEndPoint(localSIPEndPoint.Protocol, remoteSIPEndPoint.GetIPEndPoint()),
                                                       CallProperties.CreateBranchId()));
                response.Header.MaxForwards = Int32.MinValue;
                response.Header.Allow       = m_allowedSIPMethods;

                return(response);
            }
            catch (Exception excp)
            {
                logger.LogError("Exception SIPResponse.GetResponse. " + excp.Message);
                throw;
            }
        }
Exemple #3
0
        /// <summary>
        /// Duplicates an existing SIP request, typically one that received an unauthorised response, to an
        /// authenticated version. The CSeq and Via branch ID are also incremented so
        /// that the request will not be flagged as a retransmit.
        /// </summary>
        /// <param name="authenticationChallenges">The challenges to authenticate the request against. Typically
        /// the challenges come from a SIP response.</param>
        /// <param name="username">The username to authenticate with.</param>
        /// <param name="password">The password to authenticate with.</param>
        /// <returns>A SIP request that is a duplicate of the original but with an authentication header added and
        /// the state header values updated so as not to be flagged as a retransmit.</returns>
        public SIPRequest DuplicateAndAuthenticate(List <SIPAuthenticationHeader> authenticationChallenges,
                                                   string username,
                                                   string password)
        {
            var dupRequest = this.Copy();

            dupRequest.Header.Vias.TopViaHeader.Branch = CallProperties.CreateBranchId();
            dupRequest.Header.CSeq = dupRequest.Header.CSeq + 1;

            dupRequest.Header.AuthenticationHeaders.Clear();

            // RFC8760 (which introduces SHA256/512 for SIP) states that multiple authentication headers with different digest algorithms
            // can be included in a SIP request. When testing this with the latest versions (Jul 2021) of Asterisk v18.5.0 and FreeSWITCH v1.10.6
            // request authentication failed if the MD5 digest was not first and it's almost certain the subsequent SHA256 digest was ignored.
            // As a consequence the logic below will only use a SHA256 digest IFF the UAS put an authentication challenge with the digest
            // algorithm explicitly set to SHA-256.
            // See https://github.com/sipsorcery-org/sipsorcery/issues/525.

            bool useSHA256 = authenticationChallenges.Any(x => x.SIPDigest.DigestAlgorithm == DigestAlgorithmsEnum.SHA256);

            if (useSHA256)
            {
                var sha256AuthHeader = SIPAuthChallenge.GetAuthenticationHeader(authenticationChallenges, this.URI, this.Method, username, password, DigestAlgorithmsEnum.SHA256);
                dupRequest.Header.AuthenticationHeaders.Add(sha256AuthHeader);
            }
            else
            {
                var md5AuthHeader = SIPAuthChallenge.GetAuthenticationHeader(authenticationChallenges, this.URI, this.Method, username, password);
                dupRequest.Header.AuthenticationHeaders.Add(md5AuthHeader);
            }

            return(dupRequest);
        }
Exemple #4
0
        /// <summary>
        /// New transaction ACK requests are for 2xx responses, i.e. INVITE accepted and dialogue being created.
        /// </summary>
        /// <remarks>
        /// From RFC 3261 Chapter 17.1.1.3 - ACK for non-2xx final responses
        ///
        /// IMPORTANT:
        /// an ACK for a non-2xx response will also have the same branch ID as the INVITE whose response it acknowledges.
        ///
        /// The ACK request constructed by the client transaction MUST contain
        /// values for the Call-ID, From, and Request-URI that are equal to the
        /// values of those header fields in the request passed to the transport
        /// by the client transaction (call this the "original request").  The To
        /// header field in the ACK MUST equal the To header field in the
        /// response being acknowledged, and therefore will usually differ from
        /// the To header field in the original request by the addition of the
        /// tag parameter.  The ACK MUST contain a single Via header field, and
        /// this MUST be equal to the top Via header field of the original
        /// request.  The CSeq header field in the ACK MUST contain the same
        /// value for the sequence number as was present in the original request,
        /// but the method parameter MUST be equal to "ACK".
        ///
        /// If the INVITE request whose response is being acknowledged had Route
        /// header fields, those header fields MUST appear in the ACK.  This is
        /// to ensure that the ACK can be routed properly through any downstream
        /// stateless proxies.
        ///
        /// From RFC 3261 Chapter 13.2.2.4 - ACK for 2xx final responses
        ///
        /// IMPORTANT:
        /// an ACK for a 2xx final response is a new transaction and has a new branch ID.
        ///
        /// The UAC core MUST generate an ACK request for each 2xx received from
        /// the transaction layer.  The header fields of the ACK are constructed
        /// in the same way as for any request sent within a dialog (see Section
        /// 12) with the exception of the CSeq and the header fields related to
        /// authentication.  The sequence number of the CSeq header field MUST be
        /// the same as the INVITE being acknowledged, but the CSeq method MUST
        /// be ACK.  The ACK MUST contain the same credentials as the INVITE.  If
        /// the 2xx contains an offer (based on the rules above), the ACK MUST
        /// carry an answer in its body.  If the offer in the 2xx response is not
        /// acceptable, the UAC core MUST generate a valid answer in the ACK and
        /// then send a BYE immediately.
        /// </remarks>
        private SIPRequest GetNewTransactionACKRequest(SIPResponse sipResponse, SIPURI ackURI, SIPEndPoint localSIPEndPoint)
        {
            SIPRequest ackRequest = new SIPRequest(SIPMethodsEnum.ACK, ackURI.ToString());

            ackRequest.LocalSIPEndPoint = localSIPEndPoint;

            SIPHeader header = new SIPHeader(TransactionRequest.Header.From, sipResponse.Header.To, sipResponse.Header.CSeq, sipResponse.Header.CallId);

            header.CSeqMethod           = SIPMethodsEnum.ACK;
            header.AuthenticationHeader = TransactionRequest.Header.AuthenticationHeader;
            header.ProxySendFrom        = base.TransactionRequest.Header.ProxySendFrom;

            if (sipResponse.Header.RecordRoutes != null)
            {
                header.Routes = sipResponse.Header.RecordRoutes.Reversed();
            }

            ackRequest.Header = header;

            SIPViaHeader viaHeader = new SIPViaHeader(localSIPEndPoint, CallProperties.CreateBranchId());

            ackRequest.Header.Vias.PushViaHeader(viaHeader);

            return(ackRequest);
        }
Exemple #5
0
        /// <summary>
        /// Helper method to create a SIP response for a SIP request. This method can be thought of as creating a
        /// vanilla (or no frills) response for a request. It's suitable for generating error responses. For requests that
        /// require an action such as creating a call or registering a contact the response will require additional
        /// information and this method will not be suitable.
        /// </summary>
        /// <param name="sipRequest">The SIP request to create the response for.</param>
        /// <param name="responseCode">The response code.</param>
        /// <param name="reasonPhrase">Optional reason phrase to set on the response (needs to be short).</param>
        /// <returns>A SIP response object.</returns>
        public static SIPResponse GetResponse(SIPRequest sipRequest, SIPResponseStatusCodesEnum responseCode,
                                              string reasonPhrase)
        {
            try
            {
                SIPResponse response = new SIPResponse(responseCode, reasonPhrase);
                response.SetSendFromHints(sipRequest.LocalSIPEndPoint);

                if (reasonPhrase != null)
                {
                    response.ReasonPhrase = reasonPhrase;
                }

                SIPHeader     requestHeader = sipRequest.Header;
                SIPFromHeader from          = (requestHeader == null || requestHeader.From != null)
                    ? requestHeader.From
                    : new SIPFromHeader(null, new SIPURI(sipRequest.URI.Scheme, sipRequest.LocalSIPEndPoint), null);
                SIPToHeader to = (requestHeader == null || requestHeader.To != null)
                    ? requestHeader.To
                    : new SIPToHeader(null, new SIPURI(sipRequest.URI.Scheme, sipRequest.LocalSIPEndPoint), null);
                int    cSeq   = (requestHeader == null || requestHeader.CSeq != -1) ? requestHeader.CSeq : 1;
                string callId = (requestHeader == null || requestHeader.CallId != null)
                    ? requestHeader.CallId
                    : CallProperties.CreateNewCallId();

                response.Header            = new SIPHeader(from, to, cSeq, callId);
                response.Header.CSeqMethod = (requestHeader != null) ? requestHeader.CSeqMethod : SIPMethodsEnum.NONE;

                if (requestHeader == null || requestHeader.Vias == null || requestHeader.Vias.Length == 0)
                {
                    response.Header.Vias.PushViaHeader(new SIPViaHeader(sipRequest.RemoteSIPEndPoint,
                                                                        CallProperties.CreateBranchId()));
                }
                else
                {
                    response.Header.Vias = requestHeader.Vias;
                }

                response.Header.MaxForwards = Int32.MinValue;
                response.Header.Allow       = m_allowedSIPMethods;

                return(response);
            }
            catch (Exception excp)
            {
                logger.LogError("Exception SIPResponse.GetResponse. " + excp.Message);
                throw excp;
            }
        }
Exemple #6
0
        public string CreateBranchId()
        {
            string routeStr   = (Header.Routes != null) ? Header.Routes.ToString() : null;
            string toTagStr   = (Header.To != null) ? Header.To.ToTag : null;
            string fromTagStr = (Header.From != null) ? Header.From.FromTag : null;
            string topViaStr  = (Header.Vias != null && Header.Vias.TopViaHeader != null) ? Header.Vias.TopViaHeader.ToString() : null;

            return(CallProperties.CreateBranchId(
                       SIPConstants.SIP_BRANCH_MAGICCOOKIE,
                       toTagStr,
                       fromTagStr,
                       Header.CallId,
                       URI.ToString(),
                       topViaStr,
                       Header.CSeq,
                       routeStr,
                       Header.ProxyRequire,
                       null));
        }
Exemple #7
0
        private SIPRequest GetByeRequest(SIPEndPoint localSIPEndPoint)
        {
            SIPRequest    byeRequest    = new SIPRequest(SIPMethodsEnum.BYE, RemoteTarget);
            SIPFromHeader byeFromHeader = SIPFromHeader.ParseFromHeader(LocalUserField.ToString());
            SIPToHeader   byeToHeader   = SIPToHeader.ParseToHeader(RemoteUserField.ToString());
            int           cseq          = CSeq + 1;

            SIPHeader byeHeader = new SIPHeader(byeFromHeader, byeToHeader, cseq, CallId);

            byeHeader.CSeqMethod            = SIPMethodsEnum.BYE;
            byeRequest.Header               = byeHeader;
            byeRequest.Header.Routes        = RouteSet;
            byeRequest.Header.ProxySendFrom = ProxySendFrom;

            SIPViaHeader viaHeader = new SIPViaHeader(localSIPEndPoint, CallProperties.CreateBranchId());

            byeRequest.Header.Vias.PushViaHeader(viaHeader);

            return(byeRequest);
        }
Exemple #8
0
            private SIPRequest GetDummyINVITERequest(SIPURI dummyURI)
            {
                string     dummyFrom     = "<sip:[email protected]>";
                string     dummyContact  = "sip:127.0.0.1:1234";
                SIPRequest inviteRequest = new SIPRequest(SIPMethodsEnum.INVITE, dummyURI);

                SIPHeader inviteHeader = new SIPHeader(SIPFromHeader.ParseFromHeader(dummyFrom), new SIPToHeader(null, dummyURI, null), 1, CallProperties.CreateNewCallId());

                inviteHeader.From.FromTag = CallProperties.CreateNewTag();
                inviteHeader.Contact      = SIPContactHeader.ParseContactHeader(dummyContact);
                inviteHeader.CSeqMethod   = SIPMethodsEnum.INVITE;
                inviteHeader.UserAgent    = "unittest";
                inviteRequest.Header      = inviteHeader;

                SIPViaHeader viaHeader = new SIPViaHeader("127.0.0.1", 1234, CallProperties.CreateBranchId(), SIPProtocolsEnum.udp);

                inviteRequest.Header.Vias.PushViaHeader(viaHeader);

                inviteRequest.Body = "dummy";
                inviteRequest.Header.ContentLength = inviteRequest.Body.Length;
                inviteRequest.Header.ContentType   = "application/sdp";

                return(inviteRequest);
            }