-
Notifications
You must be signed in to change notification settings - Fork 41
Description
Problem
When a PBX sends SIP messages with domain names (instead of IP addresses) in the Via header or Request-URI,
SipConnection::get_destination() fails with:
WARN rsipstack::transaction::endpoint:283 on_received_message error
addr=UDP 116.62.118.11:5060
error=SIP message error: rsip quite unexpected error: cannot convert Host to IpAddr
This occurs intermittently when the remote PBX uses its domain name in SIP headers, e.g.:
Via: SIP/2.0/UDP pbx.example.com:5060
Root Cause
SipConnection::get_destination() (connection.rs:390-396) calls host_with_port.try_into() which ultimately reaches
Host::try_into::() in rsip (host.rs:88-96):
impl TryInto for Host {
fn try_into(self) -> Result<IpAddr, Error> {
match self {
Self::Domain(_) => Err(Error::Unexpected("cannot convert Host to IpAddr".into())),
Self::IpAddr(ip_addr) => Ok(ip_addr),
}
}
}
For the Request branch, it directly uses req.uri().host_with_port which may contain a domain name:
pub fn get_destination(msg: &rsip::SipMessage) -> Result {
let host_with_port = match msg {
rsip::SipMessage::Request(req) => req.uri().host_with_port.clone(),
rsip::SipMessage::Response(res) => Self::parse_target_from_via(res.via_header()?)?.1,
};
host_with_port.try_into().map_err(Into::into) // fails when host is a domain
}
For the Response branch, parse_target_from_via() correctly handles the received parameter (which is always an IP). However, if
received is absent and the Via sent-by is a domain, it also fails.
Trigger Path
The error is triggered in on_received_message() when replaying cached responses for finished transactions:
// endpoint.rs:380, 425, 465
connection.send(last_message, None).await?;
When destination is None, UdpConnection::send() falls back to get_destination() to extract the target address from message
headers:
// udp.rs:185-188
let destination = match destination {
Some(addr) => addr.get_socketaddr(),
None => SipConnection::get_destination(&msg), // fails here
}?;
Notes
- The TargetLocator trait does not help here because get_destination() is synchronous and does not use the locator.
- Adding DNS resolution directly in get_destination() would introduce performance concerns (a DNS lookup per message) and is not
appropriate for a synchronous function. - The from: &SipAddr parameter (the actual source address of the received message) is available in on_received_message() but is
not passed through to connection.send().
Environment
- rsipstack: 0.4.7
- Transport: UDP
- PBX: Yeastar P-Series (cloud-hosted, uses domain names in SIP headers)
Suggested Approach
One possible direction: for the call sites in on_received_message() that replay cached messages (connection.send(last_message,
None)), consider passing the known from address as the destination instead of relying on header parsing. However, I'm not sure if
this fully aligns with RFC 3261 routing rules — you likely have better insight into the best fix.