Skip to content

get_destination() fails when SIP message contains domain name in Via/URI host  #94

@midy177

Description

@midy177

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions