SIP Peers: Exemplary dual-stack SIP

The future for SIP lies with its use over IPv6. It saves lots of problems piercing through NAT. Furthermore, it enables peer-to-peer media links over the Internet, rather than the more dependent client-server setup.

Instantly switching to IPv6-only mode would be ideal, but is hardly realistic. IPv4-only phones and IPv6-only phones cannot reach each other, so there is going to be a (hopefully short) dual-stack period.

Making a phone behave well on IPv4 and IPv6 is difficult. I've seen a lot of mistakes being made, and this work on the well-structured SIP Peers soft phone sheds some light on how it should best be done. In my opinion, of course.


Why having IPv6 anywhere is important

It is useful to be able to use IPv6 every now and then, but it is much more useful to be able to rely on IPv6 anywhere -- as that means that you could stop using IPv4 and NAT traversal altogether. Furthermore, it suddenly becomes realistic to use SIP to setup direct media streams between online users, without any influence on the call quality beyond the quality of the Internet between those users.

It is unpleasantly common in the SIP world to sit back and wait for others to accept new developments. This is probably caused by the fact that devices need to communicate with compatible ones, so being the first to implement a feature is not going to be generally useful. As a result, the SIP world is hardly moving, and we are still using a mere simulation of analog telephony.

This is why 6bed4 was invented. It ensures that IPv6 is going to work, regardless of the ISP used by a customer and regardless of their (non-)choice of router, so this lets-wait-and-see debate is avoided for at least the move to IPv6. As a matter of fact, manufacturers who do not implement IPv6 because they expect that the IPv6-only demand is so small yet are likely to see their market share vanish and be absorbed by those who understand that IPv6 can be everywhere, possibly through this tunnel mechanism.

Once we have all moved over to IPv6, we can flush lots and lots of dramatic techniques dealing with NAT traversal. STUN, ICE and many other clever kludges can go. And this adaption to SIP Peers was made to show the way ;-)

Problems found in other implementations

First, there are proposals and standards in which SIP offers to do things over both kinds of transport. In my experience, the parsers of SIP and SDP are so unreliable that I hardly expect all phones to treat this well; given that IPv4-only phones respond to an IPv6 SDP offer with an IPv4 response is a clear example of parsing less than is strictly required. So extending the syntax does not sound like the right solution to me.

Second, if seen dual-stack implementations that are in fact switchable single-stack implementations; the end user has to make the choice whether to use IPv4 or IPv6. This means that support over both protocols is not possible. Sometimes it's even so bad that all accounts are treated in the same way, so it is not even possible to have an IPv4-only account as well as an IPv6-only account. Clearly, infant solutions.

The solution built into SIP Peers

The general adagio be conservative in what you offer, yet liberal in what you accept is a perfect style to solve this problem. The dual-stack code in SIP Peers therefore accepts incoming traffic over IPv4 and/or IPv6, but it makes a deliberate choice when sending. It will not offer choices to the remote peer, but make a single choice and stick to it.

Well, stick to it... that is for the duration of one SIP transaction, or one media flow as setup with SIP/SDP. Transactions in SIP are not a complete call (those are called dialogs) but rather the exchange of messages to change the media connection that SIP negotiates. An example of a transaction is an INVITE to setup a call, including the responses that say that remote phones are ringing, and either one is picked up or some ringing timeout expired. Another example of a SIP transaction is hangup. Or the addition of a media stream such as video.

SIP Peers sticks to one protocol stack per SIP transaction. When spoken to over an address family, it will respond over that same address family. This is in line with the way SIP messages are processed anyway; the top Via: header implies the address family and is used when sending responses.

When initiating a SIP transaction, SIP Peers has a choice. It will figure out what address family to use based on the target host. If it is a domain name, it will be looked up in DNS (possibly using SRV records) and then resolve the hostname of the target through A and AAAA DNS queries. If it finds AAAA records and it has a local IPv6 address, it will prefer that. If it only finds A records or if it only has a local IPv4 address, it will stick with that.

Media descriptions are negoatiated with SDP, transported as SIP attachments. Here the same approach is used. When responding to an SDP offer, SIP Peers will try to follow the suggested address family in the offer; when initiating an SDP offer it will try to follow what SIP already does. Note that SIP messages can pass through numerous proxies, but that media streams are intended to be point-to-point. So, when the remote SIP endpoint is known (as is the case when responding), then its address family will be tried first.

Interestingly, when talking to an IPv4-only remote peer, SIP Peers will behave like an IPv4-only soft phone. And when talking to an IPv6-only remote peer, SIP Peers will behave like an IPv6-only soft phone. This ought to reduce confusion dramatically. Any intermediate proxies that translate between IPv4 and IPv6 would be wise to not only do this for SIP, but also for media streams, for example through the use of SIPproxy64.

Most interestingly however, is the ability of SIP Peers to change address families with the same flexibility as the SIP transports have been designed. So it has no limitations in what it can accept, which is good for compatibility with all sorts of phones and proxies.

How SIP Peers learnt from the past

Given the above, it should be clear that SIP Peers will not quickly break existing communication patterns, but that its utility greatly improves if it has IPv6 available. So it could use an instant-turn-on IPv6 setup. For those who already have native IPv6, nothing more needs doing, but for others some form of tunnel is required. The only suitable tunnel for IPv6 telephony would be 6bed4, and indeed that has been built into SIP Peers.

The 6bed4 approach permits manual configuration of a tunnel server to use, but it also provides a default server to permit zero-config operation. When communicating between 6bed4 end points, the mechanism will negotiate direct communication between the endpoints, so without passing the media streams through the tunnel server. The only situation in which this fails, is the rare condition where a symmetric NAT is in the communication path; in those cases, the tunnel server does serve as a fallback.

Note that the tunnel server is also needed when communicating between a tunnel server and a native IPv6 address, but that should be remedied in the upcoming version of the tunnel.

Structure of the implementation

SIP Peers is written in Java, and although it would be possible to copy another 6bed4 implementation to the code base for SIP Peers, it seemed better to provide a separate abstraction for 6bed4, and make minimal modifications to SIP Peers to integrate it.

This led to the creation of a general DatagramSocket6bed4 class, built into an independent package Socket6bed4. This code offers a subclass of the common DatagramSocket class used in Java, so it can be used as a drop-in replacement. Behind the well-known API hides a brutal piece of code that will obtain an IPv6 address on any network, even on the networks of retarded mobile operators, and figure out how to setup direct communication between endpoints. Most NATs can be your friend, if you use them well. This is precisely what 6bed4 knows how to do, and at a great success rate. You don't need to do anything to use it though.

Briefly said, SIP Peers has been changed only as follows:

  • Added support for SRV records
  • Added dual-stack support
  • Added 6bed4 server configuration options
  • Added automatic fallback to 6bed4 if native IPv6 is absent
  • Added choices whether to create a DatagramSocket or a DatagramSocket6bed4

By all means, have a look at Socket6bed4 as it probably makes it simple to add IPv6 to your networked application. But as with SIP Peers, the best way to do that is to first implement dual-stack support.

Guilty and charged

This work was done by Rick van Rein of OpenFortress. The work was funded by NLnet, SURFnet and OpenFortress. It would not have been possible without the splendid work that Yohann Martineau has done in his SIP Peers project.

Downloads and future development

The current patch version 1, relative to Peers tag 0.5-SNAPSHOT, is available for download.

In addition, a simple applet demonstration is available, which will run in the AppletViewer or, with proper security measures, in the browser. I call this a SIPlet (tm). Note that compression with tools like ProGuard and Pack200 are able to reduce the total package (SIPlet, Peers lib, dnsjava, socket6bed4) to about 75 kB!

Not perfect yet: Please note that this patch has shown to work, but is not perfect. I need interaction with Peers' author, Yohann Martineau, before further progress. Yohann has asked me to hold off until he has a bit more time on his hands, but he is generally happy with my work.

The issues that we need to solve together are:

  • Although the code is working, the UAC tests are failing. This is a warning flag to look into, but does not seem to represent any real problem, other than improper termination of the soft phone program. It is not clear yet if this needs fixing in the main program or in the test :-D
  • The SRV resolver is embedded in the URI parser, where it should not be. Moving it to a better place, such as createClientTransaction, would mean changing the APIs of SipUri (from getHost and getPort to String getHostPort()) and createClientTransaction (from ip1, port1, ip2, port2 to config,String hostport) and needs some discussion. After making this move, the SRV resolution process can actually benefit from alternative and fallback servers configured in DNS.
  • I introduced autoconfiguration to support running without any configuration file. This is something we need to discuss first.
  • I would like to block 2001:0::/32 addresses, which are for Teredo. As has been shown, Teredo is unreliable. Moreover, it is unsuitable for peer-to-peer connections and, specifically, SIP applications.

There are additional dependencies after this patch is applied:

  • On dnsjava for SRV resolution; when moving towards more elaborate resolution of these records it should also be possible to do A and AAAA queries with this library. This will be an advantage when IPv6 can be assumed to work anywhere; the habit of Windows to suppress AAAA queries would then be bypassed.
  • On socket6bed4 for guaranteed support for IPv6 anywhere. This is not yet part of the Central Repository, but we are working towards this as wel speak.