From 3a21ee6b31a2b23d7eaf3d033950c14cafd31d39 Mon Sep 17 00:00:00 2001 From: Michael Franzl Date: Sat, 13 Jan 2018 10:04:23 +0100 Subject: [PATCH] detect multicast IP addresses and set IP_MULTICAST_TTL to 0 as a security precaution --- README.md | 8 ++++++-- janus_rtpforward.c | 40 +++++++++++++++++++++++++++++++--------- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 7f1dff3..ebcdcd2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Janus rtpforward plugin -This plugin for the [Janus WebRTC gateway](https://github.com/meetecho/janus-gateway) takes RTP and RTCP packets from a WebRTC connection (Janus Session) and forwards/sends them to UDP ports for further processing or display by an external receiver/decoder (e.g. a GStreamer pipeline). UDP broadcast and multicast is implicitly supported by setting the `sendipv4` to broadcast or multicast IP addresses. +This plugin for the [Janus WebRTC gateway](https://github.com/meetecho/janus-gateway) takes RTP and RTCP packets from a WebRTC connection (Janus Session) and forwards/sends them to UDP ports for further processing or display by an external receiver/decoder (e.g. a GStreamer pipeline). Four destination UDP addresses/ports are used: @@ -56,10 +56,14 @@ These packet loss simulations are perhaps too simple. They are no replacement fo This plugin only accepts VP8 and OPUS in RECVONLY mode. This is hardcoded via arguments to the `janus_sdp_generate_answer()` function, but can be changed easily (see comments there). +# UDP broadcast/multicast + +UDP broadcast and multicast is implicitly supported by configuring the `sendipv4` to broadcast or multicast IP addresses (strictly speaking, this is just a feature of the socket or OS, not a feature of this plugin). If a multicast IP address is detected, as a security precaution, the plugin will set the `IP_MULTICAST_TTL` option of the sending socket to 0 (zero) which SHOULD cause at least the first router (the Linux kernel) to NOT forward the UDP packets to any other network (the packets SHOULD be accessible only on the same machine). This behavior is however OS-specific. **When configuring a multicast IP address, you SHOULD verify that the UDP packets are not inadvertenly forwarded into networks where the security/privacy of the packets could be compromised, or into networks where congestion or bandwidth need to be observed. If in doubt, do NOT configure this plugin with multicast IP addresses!** + # Use cases -Note: The following two use cases use the UDP multicast IP address 225.0.0.37 (which is in a group of multicast addresses not routed, i.e. only working on the same machine). This enables multiple subscribers to the same RTP stream, for maximum flexibility. +Note: The following two use cases use the UDP multicast IP address 225.0.0.37. This enables multiple subscribers to the same RTP stream, for maximum flexibility. ## GStreamer display diff --git a/janus_rtpforward.c b/janus_rtpforward.c index b391536..2ec195c 100644 --- a/janus_rtpforward.c +++ b/janus_rtpforward.c @@ -25,6 +25,9 @@ #include #include +#include +#include + #include #include "debug.h" @@ -39,7 +42,7 @@ #include "utils.h" #define RTPFORWARD_VERSION 1 -#define RTPFORWARD_VERSION_STRING "0.2.1" +#define RTPFORWARD_VERSION_STRING "0.2.2" #define RTPFORWARD_DESCRIPTION "Forwards RTP and RTCP to an external UDP receiver/decoder" #define RTPFORWARD_NAME "rtpforward" #define RTPFORWARD_AUTHOR "Michael Karl Franzl" @@ -504,14 +507,33 @@ struct janus_plugin_result *rtpforward_handle_message(janus_plugin_session *hand } // create the SEND socket - if (session->sendsockfd < 0) { - session->sendsockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (session->sendsockfd < 0) { // still? + if (session->sendsockfd < 0) { // only once + session->sendsockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (session->sendsockfd < 0) { // error JANUS_LOG(LOG_ERR, "%s Could not create sending socket\n", RTPFORWARD_NAME); - error_code = 99; // TODO define + error_code = 99; // TODO: define this g_snprintf(error_cause, 512, "Could not create sending socket"); goto respond; } + + if (IN_MULTICAST(ntohl(inet_addr(sendipv4)))) { + u_int ttl = 0; // do not route UDP packets outside of local host + setsockopt(session->sendsockfd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)); + + struct in_addr mcast_iface_addr; + mcast_iface_addr.s_addr = htonl(INADDR_LOOPBACK); // same as inet_addr("127.0.0.1"); + + JANUS_LOG(LOG_WARN, "%s: This rtpforward session will multicast to IP multicast address %s " + "because you specified it. The IP_MULTICAST_TTL option has been set to 0 (zero), which " + "SHOULD cause at least the first router (the Linux kernel) to NOT forward the UDP packets. " + "The behavior is is however OS-specific. You SHOULD verify that the UDP packets " + "are not inadvertenly forwarded into network zones where the security/privacy of the packets " + "could be compromised.\n", RTPFORWARD_NAME, inet_ntoa(session->sendsockaddr.sin_addr)); + + JANUS_LOG(LOG_WARN, "%s: Will multicast from network interface with IP %s\n", RTPFORWARD_NAME, inet_ntoa(mcast_iface_addr)); + + setsockopt(session->sendsockfd, IPPROTO_IP, IP_MULTICAST_IF, &mcast_iface_addr, sizeof(mcast_iface_addr)); + } } #ifdef FORWARD_FEEDBACK @@ -539,7 +561,7 @@ struct janus_plugin_result *rtpforward_handle_message(janus_plugin_session *hand // create the RECEIVE socket for audio RTCP if (session->recvsockfd_audio_rtcp < 0) { - session->recvsockfd_audio_rtcp = socket(AF_INET, SOCK_DGRAM, 0); // TODO: IPPROTO_UDP??? + session->recvsockfd_audio_rtcp = socket(AF_INET, SOCK_DGRAM, 0); if(session->recvsockfd_audio_rtcp < 0) { // still? JANUS_LOG(LOG_ERR, "%s Could create listening socket for audio RTCP...\n", RTPFORWARD_NAME); error_code = 99; // TODO define @@ -550,7 +572,7 @@ struct janus_plugin_result *rtpforward_handle_message(janus_plugin_session *hand // create the RECEIVE socket for video RTCP if (session->recvsockfd_video_rtcp < 0) { - session->recvsockfd_video_rtcp = socket(AF_INET, SOCK_DGRAM, 0); // TODO: IPPROTO_UDP??? + session->recvsockfd_video_rtcp = socket(AF_INET, SOCK_DGRAM, 0); if(session->recvsockfd_video_rtcp < 0) { // still? JANUS_LOG(LOG_ERR, "%s Could create listening socket for video RTCP...\n", RTPFORWARD_NAME); error_code = 99; // TODO define @@ -559,10 +581,10 @@ struct janus_plugin_result *rtpforward_handle_message(janus_plugin_session *hand } } - session->recvsockaddr_audio_rtcp.sin_addr.s_addr = INADDR_ANY; // inet_addr("127.0.0.1"); // htonl(INADDR_ANY) + session->recvsockaddr_audio_rtcp.sin_addr.s_addr = INADDR_ANY; session->recvsockaddr_audio_rtcp.sin_port = htons(session->recvport_audio_rtcp); - session->recvsockaddr_video_rtcp.sin_addr.s_addr = INADDR_ANY; //inet_addr("127.0.0.1"); + session->recvsockaddr_video_rtcp.sin_addr.s_addr = INADDR_ANY; session->recvsockaddr_video_rtcp.sin_port = htons(session->recvport_video_rtcp); // TODO: protect against multiple runs of configure