In today's digital age, security is as important as performance. Unlike 50 years ago, where security was just a formality, now, due to unsocial elements in our society, the need to secure our data and stuff increases with the growing time.
The same can be said for the calls originating/terminating from our mobile. There can be a ton of servers that may be used for processing calls by different service providers. One such server which behaves like a private branch exchange (PBX) is the Asterisk.
If you know the basics of telecommunication, then you may skip on to Section 2. Section 1 is generally for the noob in the area of telecommunication.
RTP - Real-time transport protocol
Real-Time Transport Protocol (RTP) is an Internet Protocol standard that specifies the way programs manage the real-time transmission of multimedia data over unicast or multicast network services.
RTCP - Real-time transport control protocol
Real-Time Transport Control Protocol (RTCP) is a protocol that works with Real-Time Protocol (RTP) to monitor data delivery on large multicast networks. The purpose of monitoring delivery is to determine whether RTP is providing the necessary Quality of Service (QoS) and to compensate for delays if needed.
So, If A and B were to talk via Phones, then from a very basic point in the field of telecommunication, It can be divided into 2 planes -
2. Media - Think of the media plane as the space for sending packets (RTP) when we have found both originating and terminating destinations.
Based on encryption, there are 2 types of call -
Normal call - A call established between 2 ordinary individuals whose conversations in any way are not of significant importance, and there is no need to protect their conversations.
From a developer's point of view, think of it as sending normal RTP packets without encrypting them (with SRTP). These are prone to interception by a third party by certain methods.
Encrypted Call - A call established between 2 high-profile individuals whose conversations are of significant importance to them or their country, and any leakage of such information may result in an economic loss or political instability. The conversation, in this case, should not fall into the wrong hands, and hence, it is always better to encrypt them.
From a developer's point of view*, think of it as instead of sending RTP packets, we send SRTP [Secured RTP] packets which makes it difficult to intercept by the third party without the proper key.*
There are 3 types of network protocol for delivering audio and video over IP networks -
There is no need to learn these topics in detail. We have to know these terms to understand what I am about to tell you. So let's skip right into the issue for now.
In the digital age, let's say that Alice and Bob were talking via Phones every day. The conversation was smooth, and everyone was happy.
Now, Alice had some secrets that she wanted Bob to know. So, she insisted that we should switch to a secure line [enable the encryption on our phones].
Now, sometimes Call of Alice lands on the Phone Bob, but other times it does not. This behavior is totally random. Alice is confused.
A software developer observation might suggest after analyzing the traces that during the encrypted call between two clients through the asterisk server, the call sometimes fails, and the failure response message is received as 488 Not Acceptable here.
An asterisk server was used to establish the signaling between the 2 phones(Alice and Bob). When a session is established between 2 phones, the asterisk server tries to allocate a structure that will hold all the details of the media flow(RTP), including the socket, port, and other information.
This socket, after been created, needs to be bind to a particular port available in the system. Therefore, the server will attempt infinitely till it is successfully bound to that port.
RTCP is not mandatory for normal calls. However, we needed to check the quality of encrypted calls, and hence it was mandatory for encrypted calls. For a session of these encrypted calls to be successfully established, there is a need to bind both the port for RTCP and RTP to their respective sockets assigned by the server.
Generally, the port for RTP is successfully bound to its socket, but in the case of RTCP, the server attempts only one time to attempt the socket to be bound to the port. If the attempts fail because of any unforeseeable reason, then the server moves on and carries it with the rest of its tasks required for the successful establishment of the call. But as a result, the call will fail due to the above-mentioned reason.
Earlier, whenever a call arrived on an asterisk server, asterisks attempts infinitely to bind a port to a socket from a particular port range.
If the resulted message is a success, then, in that case, we have a socket that is successfully bound to a port, and then we can carry on with the further work.
If the resulted message is a failure, then, in that case, the algorithm written for that briefly summarizes into 5 points mentioned below.
In an encrypted call, instead of RTP, SRTP (Secured RTP) packets flows throughout the network in between the 2 clients through the server.
Now, as per asterisk, RTCP is mandatory for SRTP calls. So, to set up a property of RCTP, it tries to bind RTCP to another port that is just the next higher even number than the port allocated for the RTP. However, the catch is that it just tries to bind to the port only once, and it does not bother itself whether the binding is a success or a failure.
Since the possibility of binding of a port to any particular socket is completely random (because we do not know what is happening at OS level) and there is no way to predict the failure of socket binding, it would appear that sometimes the calls were working smoothly and sometimes, they were failing with the message listed above as 488 Not Acceptable Here.
Since the message received from the UAS is 488 Not Acceptable Here, one may feel that it is a problem regarding the Codecs. [probably mismatching of the codecs.] but in truth, the structure for RTCP has not been allocated.
One may say that this is system-dependent since we cannot handle the ports that other applications are taking. But it is not proper to say that the other applications take nearly 30000 ports out of 60000 ports.
RTCP contains information regarding the quality of RTP. Therefore, the port of RTCP will be 1 higher even number than the port of RTCP. Now, in most networks, generally, SRTP messages are not observed, so this type of problem will not be observed.
As mentioned earlier, in the earlier code of asterisk, RTCP was not checked during the RTP calls. RTCP instance is allocated during the SRTP calls when the RTCP property is activated for any call.
Design implementation has a flaw. After getting a port for RTP, asterisk tries to get a port for RTCP. But it doesn't matter whether the port of RTCP is bound properly or not. Asterisk will try to bind the port using the bind function and not do anything with the return code.
As a result, sometimes, the encryption calls generated by the asterisk were working fine since RTCP was set up properly, but other times, they were failing.
Core reason - Bind was not able to bind the port with the socket; there were multiple errors with numbers -101, 4, 0, 1, 10, etc. One of them is the port is already being used.
Asterisk uses the different ports for RTP for every different call, and hence there may be a chance that the port was already in use.
During the normal call, an asterisk registers a socket for RTP. Then it tries to register another socket for RTCP. If the socket for registration of RTCP is failed, then it carries on does nothing to fix it. This is because RTCP is not used for any RTP calls.
During the call of normal call, only RTP flows through it. This RTP can be easily decoded through tools like Wireshark.
Wireshark is a free and open-source packet analyzer. It is used for network troubleshooting, analysis, software and communications protocol development, and education.
If this binding of RTCP is a success, encrypted calls work like a charm, and proper voice was communicated both ways.
In case this binding of RTCP is a failure, encrypted calls do not work, and the server returns with a message as 488 Not Acceptable.
1- SO_REUSEADDR allows your server to bind to an address that is in a TIME_WAIT state. If a particular application has freed a port, it takes some time to be available again for another application. This socket option tells the kernel that even if this port is busy (in the TIME_WAIT state), go ahead and reuse it anyway. If it is busy but with another state, you will still get an address already in use error. It is useful if your server has been shut down and then restarted right away while sockets are still active on its port. const int reuseFlag = 1; setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuseFlag,
sizeof reuseFlag);
2- A configurable range of ports was increased to be used for RTP ports from [10,000–30,000] to [5000–50000]
in the rtp.conf.
This was done because the number of ports will increase after increasing the range, and the problem will also decrease.
3- The internal design for allocation of the structure remains the same. RTCP will not be enabled for RTP calls. So, pseudocode for the same would follow as:
However, In the case of an Encrypted call, then if the RTP socket is bounded to port X, then:
Section RTCP :
If everything fails, we send a failure response to the Client from the Server.
E.g., if the bind to port 8001 for RTP is successful, we are binding 8002 for RTCP. On the other hand, if that bind fails, we try binding for it consecutively 3 times in a row after a 10-microsecond pause for each. However, after the 3rd time, we are changing the increasing the port of RTP by 2 and then repeat the same process mentioned above again.
4 - Each Encrypted call will have a header "Crypto header" in its SDP. As soon as the message is received at the socket and parsed at the server in the form of headers and SDP, we will check if there is any presence of the Crypto header. If any presence is there, we will enable the RTCP for that particular call; otherwise, we will not try to bind the RTCP. In this way, we will identify the difference between Encrypted and non-encrypted calls.
In this way, we ensure that both the port for RTP and RTCP are bound every time, asterisk originates a call.
Design flaws are very hard to solve for open-source software. This is because we need to preserve the essence that was kept while the function was being written down. Therefore, the design flaw should be solved with the minimum possible changes and without altering the structures, if possible, thus removing future ramifications and allowing smooth working of the code.