Sorry for the long delay on this topic. Personal matters
prevented me from investigating for a while and the original
occurrence of the problem went away for the first client
(because they changed something on their end), but now I
have another apparently-identical problem with calls
originating from a big-iron switch who isn't willing to
change their settings like the first client did.
The problem is easily reproducible for those of you who
wish to hear (or not hear) it themselves. (instructions below)
To recap, the problem is that per rtpproxys own documentation
rtpproxy won't pass a packet in either direction for a given session
until it has received audio from both sides of a given session.
The README says:
[0]- after the session has been created, the proxy listens on the port
it has
[0] allocated for that session and waits for receiving at least one UDP
[0] packet from each of two parties participating in the call. Once such
[0] packet is received, the proxy fills one of two ip:port structures
[0] associated with each call with source ip:port of that packet. When both
[0] structures are filled in, the proxy starts relaying UDP packets between
[0] parties;
This is exactly the behavior I am experiencing, but it is causing
interoperability problems and really needs to change.
In my case, there is a new calling switch/SBC that won't send rtpproxy any
audio packets when it places a call to us until it receives audio
for that call from us first. I can see the switch on my side sending the
RTP to the port that rtpproxy stipulated (following a 183 or 200 message),
and absolutely none of that audio being sent out of rtpproxy and onto
the calling switch/SBC. In other words, it is behaving exactly like
what the README statement says.
Meanwhile, the equipment at other clients that send me calls usually
send at least one RTP packet to rtpproxy shortly after receiving the
183 message (certainly by the time the 200 message shows up), and
so two-way audio commences for that call. We have always noted
a slight truncation of initial audio, but apparently no one is
upset by that, but I suspect that was a result of rtpproxy behavior.
This noted behavior also supports the statement in the README that
audio must come from both directions before audio is sent in any
direction by rtpproxy.
So, the original question was (and now still is), is there a way to
disable this "both sides must send" criteria of rtpproxy? I don't see
a technical reason for it, and I have a client with a NexTone or a Sonus
(or perhaps both) and when they send us calls, there is no audio.
Now, there may be some knob they can turn on their system to
not wait to send audio to the called party (of which our rtpproxy is
in the middle somewhere) until audio is received from the called
party (as is happening now), but some of these companies see no
need to alter their settings in such a way. It would be better
if I could fix this behavior in rtpproxy to allow audio
in both directions from the moment that it selects the ports to
listen to for a given call and hands those back to SER.
NOTE: We do run rtpproxy with two interfaces, and did have to
alter SER* to actually pay attention to passed address parameters
passed to force_rtp_proxy(), as the stock logic in SER quietly
ignored a provided IP address if two interfaces are in use.
I also had to change fix_nated_contact() to accept and use an IP
address provided if one was passed as a parameter because the
value SER came up with was always wrong for our environment.
We've had those two fixes in SER for eight months and it works
fine with numerous clients. Rtpproxy is handed the right IP address
for each interface and customer, along with desired settings to
force_send_socket(), rewritehost() and fix_nated_contact(), and
everybody gets the IP addresses that are correct for their network.
It works, although I will admit ser.cfg is a bit klunky due to
the lack of a way in SER to pass non-constants, eg "variables" to
functions, but we manage. *These alterations were all in SER
nathelper and rtpproxy is untouched. SER nathelper patches
available on request.
However, we have this condition that rtpproxy (as claimed
by its own documentation), won't pass traffic unless it
receives at least one packet from both parties, which probably
isn't going to happen in this situation because the maker of
that equipment says they aren't doing anything that violates RFC
in waiting to receive audio from the called system before
sending audio to the called system and so see no need to change
their stuff.
Let's see, someone asked earlier which rtpproxy interface is which?
Well we ended up with "e" being the side facing our equipment and "i"
being the side facing the rest of the world. That seemed backwards, but
it worked first and the more logical combination did not for some
reason that was never investigated. I suspect either way would work
because interfaces are different netblocks in the 10.x.x.x space.
The interface details are:
(internal/trusted side - no further NAT conversions to reach in-house
switches))
em4: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
options=1b<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING>
inet 10.33.168.18 netmask 0xffffffc0 broadcast 10.33.168.63
(external/untrusted side)
em5: flags=8943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 1500
options=1b<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING>
inet 10.83.168.2 netmask 0xffffffc0 broadcast 10.83.168.63
Destination Gateway Flags Refs Use Netif Expire
default 10.83.168.1 UGS 0 6480075550 em5
(causes packets with public IPaddrs destinations to flow to router
and out to Internet. (On outbound packets, Router replaces source
IP with a matched public IP addr but destination is not altered,
nor is packet content.)
/usr/local/bin/rtpproxy -l 10.33.168.18/10.83.168.20
As you see, the external/untrusted interface is also where the default
route is, so that public IPaddrs will flow to the directly-connected
router. Inbound rtp is NATed from a public address to an internal one
on the rtpproxy interface em5. Again, all that has been passing
millions of calls for months now, but now I've got one customer
who won't send audio until we send audio, and apparently rtpproxy
won't do this for some reason. All IP addresses check out as being
reachable, it's just that nothing comes out of rtpproxy. Since the packet
doesn't even come out of rtpproxy, the lack of audio can't be blamed
on NAT, since there are no packets being emitted in first place that
a NAT conversion might mess up. That isn't it. The problem appears
to be rtpproxy, and the documentation says it is supposed to behave
like this. The question is, why?
I am able to easily replicate the problem using an Asterisk box
as the PBX for a Cisco SIP phone, by having the router immediately
in front of the SER/rtpproxy server block all incoming UDP but
port 5060 for packets coming from the asterisk server. Allow
outgoing everything.
Remove the port block/access-list rule and the phone works fine.
Add the block of RTP and calls set up and answer, but both parties
hear nothing, not even 183 ring-back, even though the caller should
be able to hear the called party. (All other calls occuring
simultaneously are unaffected since I only blocked incoming RTP
from one call source.) tcpdump running on all the interfaces
on the SER/rtpproxy server also show that audio coming in on the
one side to rtpproxy but is not emitted by the other side.
Now, wait ten seconds or so after you know the called party
has answered (so far no audio of for either party), and remove
the incoming RTP block and ding! You now have two-way audio, even
though you should have had one-way audio up until the moment the
inbound RTP block was removed. This basically emulates
the behavior of the switch that won't send audio unless it
receives audio and how this puts the calling switch and rtpproxy
in a deadly embrace.
So that seems to demonstrate that rtpproxy is behaving exactly
as documented, but that this is terrible behavior. What can
be done to fix this?
(tcpdumps of the sample calls available on request)
Thanks in advance for staying awake and bonus points for
suggesting a fix or coming up with one!