우당탕탕 개발일지
[RFC 3261] CHAPTER 8. General User Agent Behavior 본문
CHAPTER 8. General User Agent Behavior
챕터 8에서는 outside dialog에서 발생하는 request 처리에 대해 설명한다.
→ 메소드와 무관하게 적용되는 공통 동작 규칙
※ Dialog에는 Inside Dialog / Outside Dialog가 있다.
- UA (User Agent) : 단말(End System)
- UAC : 세션을 시작하는 역할
- request를 생성하고 보냄.
- UAC → proxy server → UAS 쪽으로 전달.
- UAS : 세션을 종료하는 역할
- request를 수신하면 response를 생성하고 보냄.
- UAS → proxy server → UAC를 향해 되돌아간다.
- UAC : 세션을 시작하는 역할
(8.1) UAC UAC Behavior
(8.1.1) Generating the Request
- UAC가 생성하는 request 메세지에는 필수적으로 Request Line + 최소한 To, From, Cseq, Call-ID, Max-Forwards, Via 6개의 헤더 필드가 포함
| To / From | 메세지 주소 지정 (수신자 / 발신자) |
| Call-ID | 트랜잭션 고유 식별자 |
| CSeq | 메세지 순서 제어 |
| Contact | 실제 접속 가능한 위치 (보통 IP) |
| Via | 라우팅 경로 |
| Max-Forwards | 최대 hop 수. 프록시를 몇 번 거칠 수 있는지 제한한다. |
(8.1.1.1) Request-URI
- Initial INVITE에서 Request-URI와 To 헤더의 URI는 보통 동일한 AOR을 사용하는 경우가 많다.
- 예외적으로 REGISTER request일 때는 다르게 설정해야 한다.
- UAC는 보통 AOR(논리적 대상)을 기준으로 Request-URI를 설정하지만, Proxy는 Location Service 결과를 반영하면서 Request-URI를 다르게 설정할 수도 있다.
- pre-existing route set(= 미리 구성된 라우팅 경로)이 존재하는 경우, 실제 라우팅은 Route 헤더에 의해 제어되지만 Request-URI 자체가 변경되는 것은 아니다.
(8.1.1.2) To
To: <Display Name> <sip:username@domain>
ex) To: "Bob" <sip:bob@example.com>
- To 헤더는 request을 받는 수신자의 AOR를 지정하며, display name 을 사용할 수 있다.
- AOR은 누구에게 보낸 요청인지를 나타내는 논리적 식별자 이기에 최종 수신자(= 단말)라고는 할 수 없다.
- 모든 SIP 구현체는 SIP URI 형식을 반드시 지원해야 한다.
- 사용자가 bob 처럼 짧은 문자열을 입력한 경우, UA는 이를 SIP URI의 user-part로 사용하여 sip:bob@도메인 형식으로 구성한다.
- @의 오른쪽(RHS) 도메인 부분은 보통 사용자의 홈 도메인이 사용된다.
- 해당 도메인은 bob을 실제 SIP URI로 변환하거나 라우팅 할 수 있다.
To 헤더 주의사항
- outside dialog request에는 To 헤더에 tag를 포함하면 안된다.
- dialog가 없는 초기 request에서는 tag가 존재하면 안됨.
19.3. tag
- tag 파라미터는 To/From 헤더 필드에서 사용된다.
- dialog는 Call-ID + From tag + To tag로 구성
- SIP forking → 하나의 INVITE로 여러 dialog가 생성될 수 있다.
- 수신자가 tag를 안 주면, 송신자는 누가 response했는지 구별 불가
- 장애 발생 후 다른 서버에서 세션 복원 시, tag를 통해 기존 dialog 식별 가능
Tag 생성 규칙
- 전역적으로 유일해야 하고, 암호학적으로 안전한 난수로 생성되어야 함
- 같은 UA가 INVITE를 보내고 response할 때도 From tag와 To tag는 서로 달라야 함
- 스스로를 호출하는 상황에서 필요
- → hairpinning : 자기 자신에게 다시 돌아오는 경로의 통화
(8.1.1.3) From
From: "Bob" <sips:bob@biloxi.com>;tag=a48s
From: sip:+12125551212@phone2net.com;tag=887s
From: Anonymous <sip:c8oqz84zk7z@privacy.org>;tag=hyh8
- From 헤더는 request을 보내는 사용자의 AOR을 지정하며, display name 을 사용할 수 있다.
- UAC가 신원을 숨기고 싶다면, display name을 Anonymous로 설정하고, 의미 없는 URI(예: sip:thisis@anonymous.invalid)를 넣어야 한다. (SHOULD)
- 보통 UA가 보내는 From 값은 사용자(= UA) 또는 로컬 도메인 관리자(= 해당 SIP 도메인 운영자)에 의해 사전에 설정된다.
- 여러 사용자가 함께 사용하는 UA인 경우,
- 사용자별 프로파일을 선택할 수 있고, 프로파일에는 해당 사용자에 해당하는 URI(From 주소)가 포함되어 있다.
- request 수신자는 인증을 통해 From 헤더에 표시된 사람이 본인인지 확인할 수 있다. (22절 참고)
주의사항
- From URI에 IP 주소 또는 FQDN를 포함하면 안된다. → 물리적 주소가 아닌 논리적인 이름을 써야 함.
- From 필드는 반드시 tag를 포함해야 한다.(19.3절 참고)
(8.1.1.3) Call-ID
Call-ID: f81d4fae-7dec-11d0-a765-00a0c91e6bf6@foo.bar.com
- dialog 및 세션을 구분하기 위한 고유 식별자
- 동일한 dialog 내에서는 모든 request과 response의 Call-ID가 동일해야 한다.
- REGISTER request에서도 같은 UA가 여러 번 registration 할 경우, Call-ID를 동일하게 유지하는 것이 좋다. (SHOULD)
- 대/소문자를 구분하며 byte 단위로 비교된다.
- outside dialog에서 새 request를 생성할 경우,
- Call-ID는 시간/공간상 전 세계에서 유일해야 하며, UAC가 생성해야 한다.
- 모든 SIP UA는 자신이 만든 Call-ID가 다른 UA와 중복되지 않게 고유성을 보장할 방법을 가져야 한다.
- Call-ID를 생성할 때는 암호학적으로 무작위 값(RFC 1750 기준)을 사용하는 것이 바람직하다.
- 수정을 요청하는 특정 failure response(예: 401(Unauthorized) response) 이후, request를 재전송할 때, 새로운 request로 간주되지 않기 때문에 새로운 Call-ID를 바꾸면 안된다.
(8.1.1.5) CSeq
CSeq: <sequence-number> <method>
- 트랜잭션을 식별하고 순서를 관리하기 위한 수단
- CSeq는 sequence-number, method 두 부분으로 구성된다.
- 메소드는 request 메소드와 동일해야 한다.
- outside dialog에서 보내는 request(단, REGISTER 제외)의 CSeq 번호는 임의값으로 설정해도 된다.
- CSeq 번호는 반드시 unsigned int로 표현 가능해야 하며, 2^31보다 작아야 한다. (12.2.1.1절 참고)
(8.1.1.6) Max-Forwards
- request이 목적지까지 도달하기 위해 거칠 수 있는 최대 경유지(= 프록시) 수를 제한한다.
- 경유지를 지날 때마다 1씩 감소하며, 목적지에 도달하기 전에 값이 0이 되면 488(Too Many Hops) 오류 response이 발생
- UAC는 request에 반드시 Max-Forwards 헤더를 삽입해야 하며, 초깃값은 70으로 권장된다. (SHOULD)
- 70보다 더 낮게 설정하는 경우, 주의가 필요하다.
(8.1.1.7) Via
- Via 헤더는 request에 사용된 전송 프로토콜 + response가 되돌아올 주소 정보를 포함한다. → 경유지 추적
- Via 헤더 값은 다음 hjop 으로 전달할 전송 경로가 결정된 이후에 추가된다.
- UAC는 반드시 Via 헤더를 포함시켜야 한다. (MUST)
- Via 헤더의 프로토콜명과 버전은 각각 SIP, 2.0 이어야 한다 (MUST)
- 반드시 고유한 branch 파라미터가 포함되어야 한다.(MUST) → 트랜잭션을 식별하는 데 사용됨
- 단, 다음 두 가지의 경우 기존 request의 branch 값과 동일한 값 사용
- CANCEL request는 취소 대상(= INVITE)의 Via 헤더 내 branch 값
- 2xx 이외의 response에 대한 ACK request는 INVITE request의 branch 값
- 다음 요소들은 전송 계층 처리 중에 설정된다. (18절 참고)
- maddr: 멀티캐스트 주소
- ttl: 생존 시간 (Time-to-Live)
- sent-by: 요청을 보낸 호스트의 주소/포트
주의 사항
- branch 값은 반드시 전역적으로 고유해야 하며, z9hG4bK로 시작해야 한다.
(8.1.1.8) Contact
- request을 보낸 사용자의 실제 위치로, dialog 외부에서도 사용 가능한 유효한 주소여야 한다.
- INVITE request에서는 Contact 헤더가 반드시 존재해야 하며, 하나의 URI만 포함해야 한다.
- INVITE에 포함된 Contact URI는 전역 유효성을 가져야 한다.
- Request-URI 또는 Route 헤더가 SIPS URI인 경우, Contact 헤더도 반드시 SIPS URI를 사용해야 한다.(MUST)
(8.1.1.9) Supported and Require
Supported (옵션)
- UAC가 extension을 지원하고 서버가 생성하는 response에 적용될 수 있다면, UAC는 request에 Supported 헤더를 포함시켜야 한다. (SHOULD)
- Supported 헤더에 extension을 나타내는 option tag를 나열한다. (19.2절 참고)
- option tag는 반드시 RFC에 정의된 확장 기능만 참조해야 한다.(MUST)
Require (강제)
- UAC가 request를 처리할 때 반드시 적용하고, UAS도 지원해야 한다고 extension을 요구하려면,
- UAC는 반드시 Require 헤더에 해당 option tag를 포함시켜야 한다. (MUST)
- 프록시에 요구할 경우, Proxy-Require 헤더에 해당 option tag를 포함시켜야 한다. (MUST)
(8.1.1.10) Additional Message Components
(8.1.2) Sending the Request - request 처리
request를 생성하면 해당 request를 전송할 목적지를 결정한다.
- 로컬 정책이 없다면, 반드시 DNS 절차를 적용해서 목적지를 결정해야 한다. (MUST).
목적지 결정 방법
- route set의 첫 URI가 strict routing인 경우,
- 목적지는 Request-URI로 설정해야 한다. (MUST) (12.2.1.1 절 참고)
- strict routing이 아닌 경우,
- Route 헤더가 있는 경우, Route의 첫 번째 URI를 목적지로 사용한다.
- Route 헤더가 없는 경우, Request-URI를 목적지로 사용한다.
이러한 절차는 주소, 포트, 전송 방식의 우선순위 목록을 반환한다.
주의사항
- Request-URI에 SIPS URI가 포함된 경우, TLS(암호화)를 사용하여 연결해야 한다.
- route set 없이도 outbound proxy를 설정할 수 있는 방법이 있지만, 하나의 URI만 있는 pre-existing route set 을 사용하는 것이 바람직하다. (SHOULD)
- UAC는 request할 때마다 새로운 Via 헤더와 branch ID를 생성해야 한다.
request에 Route 헤더가 있으면, 맨 위 URI를 기준으로 목적지를 설정하여 request를 보내야 한다. (SHOULD)
- UAC가 outbound proxy를 사용하더라도
- 모든 request를 무조건 outbound proxy로 보내는 것이 아닌,
- 첫 번째 Route 헤더의 첫 번째 URI를 목적지로 사용하는 것이 권장된다. (SHOULD)
UAC는 서버에 도달할 때까지 계속 시도해야 한다. (SHOULD)
- 각 시도는 별개의 트랜잭션으로, request할 때마다 새로운 Via 헤더와 branch ID를 생성해야 한다.
- Via 헤더에는 전송 프로토콜이 명시되어야 한다.
(8.1.3) Processing Responses - response 처리
Transport Layer(전송 계층) → Transaction Layer → Transaction User(TU)
(8.1.3.1) Transaction Layer Errors
- 트랜잭션 계층에서 timeout 오류가 발생한 경우, 408(Request Timeout) response를 받은 것처럼 동작해야 한다. (MUST)
- TU는 성공/실패 response를 받아야 로직을 계속 수행할 수 있다.
- 408 response로 명확히 실패를 전달한다.
- 전송 계층에서 치명적인 전송 오류(fetal transport error)가 보고된 경우, 503(Service Unavailable) 로 간주해야 한다. (MUST)
(8.1.3.2) Unrecognized Responses
- UAC는 알아볼 수 없는 final response를 받았을 때, (1xx~6xx) 코드와 동일한 의미로 간주해야 한다. (MUST)
- ex) 431 → 모를 경우 → 400으로 간주
- 알수 없는 provisional response (1xx)을 받은 경우, UAC는 반드시 183(Session Progress)로 처리해야 한다. (MUST)
- UAC는 100(Trying)과 183(Session Progress) response를 처리할 수 있어야 한다.
(8.1.3.3) Vias
- 응답에 Via 헤더가 2개 이상일 경우 → 메세지를 버려야함. (SHOULD)
- response는 Via 헤더를 역순으로 제거하면서 돌아오기 때문에 UAC가 받은 response는 자신의 Via만 남아있어야 정상이다.
(8.1.3.4) Processing 3xx response
3xx response를 받으면 Contact 헤더에 있는 URI를사용해 새 요청을 생성해야 한다. (SHOULD)
- 3xx response은 다른 URI로 새 request을 보내라는 의미이다.
SIP/2.0 302 Moved Temporarily
Via: SIP/2.0/UDP client.example.com;branch=z9hG4bK-1234
From: Alice <sip:alice@client.example.com>;tag=1928301774
To: Bob <sip:bob@example.com>;tag=abcd1234
Call-ID: 314159@client.example.com
CSeq: 1 INVITE
Contact: <sip:bob@office.example.com>;q=1.0
Contact: <sip:bob@mobile.example.com>;q=0.5
Content-Length: 0
- 리디렉션에 따라 새 요청을 시도하려면, target set에 새 URI를 추가한다.
- 동일한 URI를 두 번 이상 target set에 넣어서는 안된다. (MUST NOT) → 무한 리디렉션 루프 방지
target_set = [
sip:bob@office.example.com (q=1.0),
sip:bob@mobile.example.com (q=0.5)
]
- q 값(우선순위)를 기준으로 정렬 → (q = 1.0)이 가장 높은 우선순위
- 연결 실패 시 다음 URI를 시도하고, 모두 실패하면 최종적으로 request도 실패한다. (SHOULD)
- 실패는 보통 4xx response로 감지된다. (SHOULD)
- 트랜잭션 계층은 전송 계층 오류(예: TCP 연결 끊김)를 감지하면, TU에게 알려야 한다.
- 새 request 생성 시 원래 request의 To, From, Call-ID를 그대로 써야 dialog 추적이 가능하다.
주의사항
- 새 request 생성 시, UAC는 Contact URI를 Request-URI에 복사해야 한다. (MUST) (19.1.1 참조)
- 단, method-param과 header 파라미터는 제외한다.
- 새 request 생성 시 원래 request의 To, From, Call-ID를 그대로 써야 dialog 추적이 가능하다.
- 새 request는 반드시 새로운 클라이언트 트랜잭션으로 전송되며, Via 헤더의 branch ID도 새 값이어야 한다. (MUST)
- 기존 request에 SIPS URI가 있는 경우
- SIPS가 아닌 URI로 재귀할 수 있지만, 사용자에게 안전하지 않음을 알려야 한다.
(8.1.3.5) 4xx response 처리
재시도 요청은 새로운 트랜잭션으로 간주되며, Call-ID, To, From 값은 이전과 같아야 하고, CSeq는 반드시 1 증가한 값이어야 한다. (SHOULD)
- 401(Unauthorized), 407(Proxy Authentication Required): 인증 오류가 발생했을 경우
- 사용자 인증 정보(자격 정보)를 포함한 새 request을 보내야 한다. (SHOULD)
- 일반적으로는 WWW-Authenticate 또는 Proxy-Authenticate 헤더와 함께 오며, Authorization 또는 Proxy-Authorization 헤더를 새 요청에 포함시켜 재시도한다.
- 413(Request Entity Too Large)
- 본문을 생량하거나 더 작은 크기로 줄여서 요청을 다시 시도해야 한다. (SHOULD)
- 415(Unsupported Media Type)
- 재시도시 응답 메세지에 포함된 Accept, Accept-Encoding, Accept-Language 헤더에 명시된 타입/인코딩/언어만 사용해야 한다. (SHOULD)
- 416(Unsupported URI Scheme)
- SIP URI를 사용하여 재시도해야 한다. (SHOULD)
- 420(Bad Extension): 서버가 지원하지 않는 기능이 명시된 경우
- response의 Unsupported 헤더에 명시된 확장 기능을 제거한 후 재시도해야 한다.
(8.2) UAS 동작 방식
request 처리 과정은 원자적으로 이루어진다.request가 수락되면, 그에 따른 모든 상태 변경이 반드시 수행되어야 한다. (MUST)request 가 거부되면, 그에 따른 모든 상태 변경은 절대 수행되서는 안된다. (MUST NOT)
처리 단계
- 시작: 인증(Authentication)
- 다음: 메서드 검사(Method validation)
- 이후: 헤더 필드 확인(Header checks)
- 기타: Require/Supported 검사, URI 검증, 응답 전송 등
(8.2.1) Method Inspection
- request가 인증 정차를 거친 후, UAS는 해당 request의 메소드를 반드시 확인해야 한다. (MUST)
- UAS가 해당 메소드를 지원하지 않는다면 405(Method Not Allowed) response 을 생성해야 한다.
- UAS는 405 response에 반드시 Allow 헤더 필드를 추가해야 한다. (MUST)
- Allow 헤더에는 UAS가 지원하는 메소드 목록을 나열해야 한다. (MUST)
(8.2.2) Header Inspection
- request 메시지에 UAS가 모르는 헤더 필드가 있다면, 해당 헤더 필드는 무시하고 나머지 메시지를 계속 처리해야 한다. (MUST)
- 필요하지 않은 헤더가 잘못된 형식이라면 무시하는 것이 좋다. (SHOULD)
(8.2.2.1) To and Request-URI
To 헤더 처리
- To 헤더의 URI scheme을 모르거나, 등록된 주소가 아니더라도 request를 수락하는 것이 권장된다.
- To 헤더는 논리적인 수신자일 뿐, 실제 전달은 Request-URI에 따라 이뤄진다.
- UAS가 request 거부할 때는 403(Forbidden) response을 보내야 한다. (SHOULD)
Request URI 처리
- Request URI는 해당 request를 실제로 처리해야 할 UAS를 식별하는 데 사용된다.
- 일반적으로 REGISTER request시 등록되었던 Contact URI가 Request-URI 로 들어온다.
- Request URI가 미지원 scheme을 사용할 경우 → 416(Unsupported URI Scheme)
- UAS가 수락하지 않는 주소가 Request URI에 있을 경우 → 404(Not Found)
(8.2.2.2) Merged Requests - 병합 요청
- To 헤더 필드에 tag가 없는 경우(= 초기 request), 해당 request가 기존에 처리 중인 트랜잭션과 겹치는지 확인해야 한다. (MUST)
- from-tag, Call-ID, CSeq 값이 현재 처리 중인 트랜잭션과 일치하지만, 비교 규칙(17.2.3 절)에 따라 동일 트랜잭션으로 판단되지 않는다면 → 중복 request으로 간주하고 482(Loop Detected) response 을 생성해야 한다.
- UAS는 첫 번째 request만 처리하고, 나머지는 482(Loop Detected) response로 응답
(8.2.2.3) Require - Require 헤더 검사
- Require 헤더에는 UAC가 요청을 처리하기 위해 UAS에게 필수적으로 요구하는 확장 기능이 담겨 있다.
UAC -> UAS: INVITE sip:watson@bell-telephone.com SIP/2.0
Require: 100rel
UAS -> UAC: SIP/2.0 420 Bad Extension
Unsupported: 100rel
- UAS가 지원하지 않는 확장 기능이라면, 반드시 420(Bad Extension) response을 보내야 한다. (MUST)
- 420 response에는 Unsupported 헤더를 반드시 추가해야 하며, 지원하지 않는 확장 기능만 나열한다. (MUST)
- Require, Proxy-Require 헤더는 CANCEL이나, 2xx가 아닌 response에 대한 ACK에서는 사용해서는 안 된다 (MUST NOT).
- 즉, request가 위 경우에 해당한다면, 반드시 무시해야 한다. (MUST)
- 2xx response에 대한 ACK라면, 초기에 사용된 Require, Proxy-Require 항목만 포함해야 한다 (MUST).
(8.2.3) Content Processing - Content 처리
본문의 미디어 타입(Content-Type), 인코딩(Content-Encoding), 언어(Content-Language) 중 하나라도 이해할 수 없다면, 415 Unsupported Media Type response로 request를 거부해야 한다.
- 415 response에는 UAS가 지원하는 타입을 Accept 헤더에 반드시 포함해야 한다. (MUST)
| 원하지 않는 미디어 유형 | 415 Unsupported Media Type |
| 지원하지 않는 언어 | 415 + Accept-Language 헤더 포함 |
| 인코딩 방식 불일치 | 415 + Accept-Encoding 포함 |
(8.2.4) Applying Extensions - Extension 검사
UAS가 response를 생성할 때 특정 확장 기능을 적용하고 싶다면, request Supported 헤더에 포함되어 있어야 한다.
- 해당 확장 기능이 포함되어 있지 않다면, 절대 그 확장을 사용하면 안된다. (MUST NOT)
421(Extension Required): 해당 확장 기능 없이는 response 생성이 불가능하다.
- 420 response에는 반드시 Require 헤더에 필요한 확장을 명시해야 한다. (MUST)
- 그러나 상호운용성을 해치기에 권장되지 않는다.
(8.2.5) Processing the Request - 요청 처리
모든 유효성 검사를 통과하면 request 메소드 종류에 따라 분기되어 처리된다.
- REGISTER: Section 10
- OPTIONS: Section 11
- INVITE: Section 13
- BYE: Section 15
(8.2.6) response 생성
response가 생성되면, UAS는 request를 전달했던 서버 트랜잭션에게 response를 반환한다.
(8.2.6.1) Sending a Provisional Response
- INVITE 이외의 요청에는 provisional response를 보내지 않는 것이 권장된다. (SHOULD NOT)
→ final response를 보내야 한다.
- INVITE request에만 provisional response이 필요하다.
- 100 Trying response를 생성하는 경우,
- request에 Timestamp 헤더가 있다면, 반드시 response에서도 Timestamp 헤더를 복사해서 넣어야 한다. (MUST)
- response 생성 지연시, UAS는 response Timestamp 헤더에 delay 정보를 추가하는 것이 권장된다. (SHOULD)
- delay 값은 response를 전송한 시점과 request를 수신한 시점의 차이(초 단위)를 나타내야 한다. (MUST)
(8.2.6.2) Header and Tags
- response의 From, Call ID, CSeq, Via는 request와 그대로 일치해야 한다. (MUST)
- Via 헤더는 순서까지 완전히 동일해야 한다. (MUST)
- Via는 경로 추적용으로, 같은 경로로 역전송되어야 하기 때문에
- From, Call ID, CSeq, Via → request과 그대로 일치
- To tag의 경우, 없으면 생성하고 있으면 그대로 사용한다.
(8.2.7) Stateless UAS Behavior
- 트랜잭션 상태를 저장하지 않는 UAS → provisional response X
- DoS 방지용 인증 처리에 유용하다. → 401 / 407 response
(8.3) Redirect Server
- Contact 헤더에 대체 URI를 포함해야 한다.
- 위치 서비스 조회한 후, 3xx 최종 response을 반환
- CANCEL request인 경우 → 2xx response으로 종료
주의 사항
- Request-URI와 동일한 URI로 리디렉션해서는 안 됨 → 무한 루프 방지
'Network > SIP' 카테고리의 다른 글
| [RFC 3261] CHAPTER 13. Initiating a Session (2) | 2026.02.08 |
|---|---|
| [RFC 3261] CHAPTER 12. Dialogs (0) | 2026.02.01 |
| [RFC 3261] CHAPTER 9. Canceling a Request (0) | 2026.01.27 |
| [RFC 3261] CHAPTER 7. SIP Messages (0) | 2026.01.25 |
