We're working in a heavily-controlled network environment (in production) where we need to lock down ports used for certain things.
We currently have a need to open an RTSP stream to some camera and we route return traffic based on the ports being used (since the IP addresses of each instance of production can vary wildly).
The router rules work fine currently but the final rule is to route all traffic (not already caught by earlier rules) to a default box A
. The router appears too care little about IP addresses, it instead routes packets to specific connectors that the machines are attached to. So, when I say A
or B
, that's really the physical connector on the back of the router.
We, however, want to be able to route the GStreamer camera feeds initiated from a different box B
, back to that box.
Currently, when I do netstat -na
on B
(in a non-locked-down development environment), I can see the that the RTSP streams use various client ports from 35100
through 58712
. This gels with the contents of /proc/sys/net/ipv4/ip_local_port_range
which shows 32768 60999
.
For example (with .20.20
being machine B
and .30.30
being the camera:
tcp 0 0 172.24.20.20:36250 172.24.30.30:8091 ESTABLISHED
I thought it would be enough to set the port-range
in the props
structure used when creating the rtspsrc
element. However, setting this to 4500-4999
still results in the netstat
output showing use of client ports above 30000.
Is port-range
supposed to control these ports used for camera streaming back or is it for something else?
If the latter, how can we restrict the ports used for the streaming?
As extra information if needed, this is the properties dictionary and code used to set the properties of the rtspsrc
element:
props = {
"protocols": "tcp",
"drop-on-latency": True,
"do-retransmission": False,
"latency": 100,
"port-range": "4500-4999",
"buffer-mode": 1,
}
elem = self.gstreamer.ElementFactory.make("rtspsrc", "source")
for name, prop in props.items():
elem.set_property(name, prop)
Okay, many hours of thoroughly looking through the source code for RTSP and RTP elements, along with a better education on how it all works under the covers, has turned up the fact that port restriction only works for when you use the UDP protocol, not TCP as I have.
I noticed that, when I used Wireshark to monitor VLC connecting to the camera, it contained a client_port=58100-58101
clause in the SETUP
string passed to the camera. That clause, which specifies the RTP and RTCP ports to be used by the server, was not there when my application ran.
The port restriction is stored in the element regardless of protocol but, when it comes time to form the SETUP
message, the gst_rtspsrc_create_transports_string()
function constructs it as follows (reformatted for readability):
if (protocols & GST_RTSP_LOWER_TRANS_UDP) {
GST_DEBUG_OBJECT(src, "adding UDP unicast");
if (add_udp_str) {
g_string_append(result, "/UDP");
}
g_string_append(result, ";unicast;client_port=%%u1-%%u2"); // HERE.
} else if (protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST) {
GST_DEBUG_OBJECT(src, "adding UDP multicast");
if (add_udp_str) {
g_string_append(result, "/UDP");
}
g_string_append(result, ";multicast");
if (src->next_port_num != 0) {
if ((src->client_port_range.max > 0)
&& (src->next_port_num >= src->client_port_range.max)) {
goto no_ports;
}
g_string_append_printf(result, ";client_port=%d-%d", // HERE.
src->next_port_num, src->next_port_num + 1);
}
} else if (protocols & GST_RTSP_LOWER_TRANS_TCP) {
GST_DEBUG_OBJECT(src, "adding TCP");
g_string_append(result, "/TCP;unicast;interleaved=%%i1-%%i2"); // NOT HERE.
}
You can see there that the all-important client_port=<low>-<high>
clause is only added for UDP unicast and multicast, not TCP.
It's that clause that controls what ports the RTSP server should connect to for return traffic.
And, indeed, changing the protocols
property to be udp
solves the issue, ensuring that only the desired ports are used.