diff --git a/CHANGES b/CHANGES index 381dbcc7a2aa655a1205f687bb4a6a36769f375e..c095f30dd26d04ec2f0d7189304737d161a67aac 100644 --- a/CHANGES +++ b/CHANGES @@ -500,3 +500,5 @@ Miscellaneous specifying which socket to use to connect to the running Asterisk daemon (-s) * Added logging to 'make update' command. See update.log + * Added strictrtp option to rtp.conf. If enabled this will drop RTP packets that + do not come from the remote party. diff --git a/configs/rtp.conf.sample b/configs/rtp.conf.sample index a96a0a09b083b57312a8436ce77261835d120763..cf3b141c5e70a6873a65f12710213f619e6e3fb4 100644 --- a/configs/rtp.conf.sample +++ b/configs/rtp.conf.sample @@ -20,3 +20,7 @@ rtpend=20000 ;dtmftimeout=3000 ; rtcpinterval = 5000 ; Milliseconds between rtcp reports ;(min 500, max 60000, default 5000) +; +; Enable strict RTP protection. This will drop RTP packets that +; do not come from the source of the RTP stream. +; strictrtp=yes diff --git a/main/rtp.c b/main/rtp.c index 874f8ddb2471c1f142001028865c3bd314cbe0f5..d59d29bb74c0bd2812d5a80832fb72212c4a8bc6 100644 --- a/main/rtp.c +++ b/main/rtp.c @@ -78,6 +78,13 @@ static struct sockaddr_in rtcpdebugaddr; /*!< Debug RTCP packets to/from this ho #ifdef SO_NO_CHECK static int nochecksums; #endif +static int strictrtp; + +enum strict_rtp_state { + STRICT_RTP_OPEN = 0, /*! No RTP packets should be dropped, all sources accepted */ + STRICT_RTP_LEARN, /*! Accept next packet as source */ + STRICT_RTP_CLOSED, /*! Drop all RTP packets not coming from source that was learned */ +}; /* Uncomment this to enable more intense native bridging, but note: this is currently buggy */ /* #define P2P_INTENSE */ @@ -165,6 +172,9 @@ struct ast_rtp { struct ast_rtcp *rtcp; struct ast_codec_pref pref; struct ast_rtp *bridged; /*!< Who we are Packet bridged to */ + + enum strict_rtp_state strict_rtp_state; /*!< Current state that strict RTP protection is in */ + struct sockaddr_in strict_rtp_address; /*!< Remote address information for strict RTP purposes */ }; /* Forward declarations */ @@ -1391,6 +1401,21 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp) res = recvfrom(rtp->s, rtp->rawdata + AST_FRIENDLY_OFFSET, sizeof(rtp->rawdata) - AST_FRIENDLY_OFFSET, 0, (struct sockaddr *)&sin, &len); + /* If strict RTP protection is enabled see if we need to learn this address or if the packet should be dropped */ + if (rtp->strict_rtp_state == STRICT_RTP_LEARN) { + /* Copy over address that this packet was received on */ + memcpy(&rtp->strict_rtp_address, &sin, sizeof(rtp->strict_rtp_address)); + /* Now move over to actually protecting the RTP port */ + rtp->strict_rtp_state = STRICT_RTP_CLOSED; + ast_debug(1, "Learned remote address is %s:%d for strict RTP purposes, now protecting the port.\n", ast_inet_ntoa(rtp->strict_rtp_address.sin_addr), ntohs(rtp->strict_rtp_address.sin_port)); + } else if (rtp->strict_rtp_state == STRICT_RTP_CLOSED) { + /* If the address we previously learned doesn't match the address this packet came in on simply drop it */ + if ((rtp->strict_rtp_address.sin_addr.s_addr != sin.sin_addr.s_addr) || (rtp->strict_rtp_address.sin_port != sin.sin_port)) { + ast_debug(1, "Received RTP packet from %s:%d, dropping due to strict RTP protection. Expected it to be from %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), ast_inet_ntoa(rtp->strict_rtp_address.sin_addr), ntohs(rtp->strict_rtp_address.sin_port)); + return &ast_null_frame; + } + } + rtpheader = (unsigned int *)(rtp->rawdata + AST_FRIENDLY_OFFSET); if (res < 0) { if (errno == EBADF) @@ -2191,6 +2216,7 @@ void ast_rtp_new_init(struct ast_rtp *rtp) rtp->ssrc = ast_random(); rtp->seqno = ast_random() & 0xffff; ast_set_flag(rtp, FLAG_HAS_DTMF); + rtp->strict_rtp_state = (strictrtp ? STRICT_RTP_LEARN : STRICT_RTP_OPEN); return; } @@ -2312,6 +2338,9 @@ void ast_rtp_set_peer(struct ast_rtp *rtp, struct sockaddr_in *them) rtp->rtcp->them.sin_addr = them->sin_addr; } rtp->rxseqno = 0; + /* If strict RTP protection is enabled switch back to the learn state so we don't drop packets from above */ + if (strictrtp) + rtp->strict_rtp_state = STRICT_RTP_LEARN; } int ast_rtp_get_peer(struct ast_rtp *rtp, struct sockaddr_in *them) @@ -4025,6 +4054,7 @@ static int __ast_rtp_reload(int reload) rtpstart = 5000; rtpend = 31000; dtmftimeout = DEFAULT_DTMF_TIMEOUT; + strictrtp = STRICT_RTP_OPEN; if (cfg) { if ((s = ast_variable_retrieve(cfg, "general", "rtpstart"))) { rtpstart = atoi(s); @@ -4068,6 +4098,9 @@ static int __ast_rtp_reload(int reload) dtmftimeout = DEFAULT_DTMF_TIMEOUT; }; } + if ((s = ast_variable_retrieve(cfg, "general", "strictrtp"))) { + strictrtp = ast_true(s); + } ast_config_destroy(cfg); } if (rtpstart >= rtpend) {