diff options
-rw-r--r-- | channels/chan_iax2.c | 159 | ||||
-rw-r--r-- | configs/iax.conf.sample | 20 | ||||
-rw-r--r-- | include/asterisk/frame.h | 26 |
3 files changed, 184 insertions, 21 deletions
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index bb8c9eb5b..abeade87a 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -1332,6 +1332,103 @@ static void iax2_lock_owner(int callno) } } +/*! + * \internal + * \brief Check if a control subtype is allowed on the wire. + * + * \param subtype Control frame subtype to check if allowed to/from the wire. + * + * \retval non-zero if allowed. + */ +static int iax2_is_control_frame_allowed(int subtype) +{ + enum ast_control_frame_type control = subtype; + int is_allowed; + + /* + * Note: If we compare the enumeration type, which does not have any + * negative constants, the compiler may optimize this code away. + * Therefore, we must perform an integer comparison here. + */ + if (subtype == -1) { + return -1; + } + + /* Default to not allowing control frames to pass. */ + is_allowed = 0; + + /* + * The switch default is not present in order to take advantage + * of the compiler complaining of a missing enum case. + */ + switch (control) { + /* + * These control frames make sense to send/receive across the link. + */ + case AST_CONTROL_HANGUP: + case AST_CONTROL_RING: + case AST_CONTROL_RINGING: + case AST_CONTROL_ANSWER: + case AST_CONTROL_BUSY: + case AST_CONTROL_TAKEOFFHOOK: + case AST_CONTROL_OFFHOOK: + case AST_CONTROL_CONGESTION: + case AST_CONTROL_FLASH: + case AST_CONTROL_WINK: + case AST_CONTROL_OPTION: + case AST_CONTROL_RADIO_KEY: + case AST_CONTROL_RADIO_UNKEY: + case AST_CONTROL_PROGRESS: + case AST_CONTROL_PROCEEDING: + case AST_CONTROL_HOLD: + case AST_CONTROL_UNHOLD: + case AST_CONTROL_VIDUPDATE: + case AST_CONTROL_CONNECTED_LINE: + case AST_CONTROL_REDIRECTING: + case AST_CONTROL_T38_PARAMETERS: + case AST_CONTROL_AOC: + case AST_CONTROL_INCOMPLETE: + case AST_CONTROL_MCID: + is_allowed = -1; + break; + + /* + * These control frames do not make sense to send/receive across the link. + */ + case _XXX_AST_CONTROL_T38: + /* The control value is deprecated in favor of AST_CONTROL_T38_PARAMETERS. */ + case AST_CONTROL_SRCUPDATE: + /* Across an IAX link the source is still the same. */ + case AST_CONTROL_TRANSFER: + /* A success/fail status report from calling ast_transfer() on this machine. */ + case AST_CONTROL_CC: + /* The payload contains pointers that are valid for the sending machine only. */ + case AST_CONTROL_SRCCHANGE: + /* Across an IAX link the source is still the same. */ + case AST_CONTROL_READ_ACTION: + /* The action can only be done by the sending machine. */ + case AST_CONTROL_END_OF_Q: + /* This frame would cause the call to unexpectedly hangup. */ + case AST_CONTROL_UPDATE_RTP_PEER: + /* Only meaningful across a bridge on this machine for direct-media exchange. */ + case AST_CONTROL_PVT_CAUSE_CODE: + /* Intended only for the sending machine's local channel structure. */ + case AST_CONTROL_STREAM_STOP: + case AST_CONTROL_STREAM_SUSPEND: + case AST_CONTROL_STREAM_RESTART: + case AST_CONTROL_STREAM_REVERSE: + case AST_CONTROL_STREAM_FORWARD: + /* None of these playback stream control frames should go across the link. */ + case AST_CONTROL_RECORD_CANCEL: + case AST_CONTROL_RECORD_STOP: + case AST_CONTROL_RECORD_SUSPEND: + case AST_CONTROL_RECORD_MUTE: + /* None of these media recording control frames should go across the link. */ + break; + } + return is_allowed; +} + static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg) { /* The MWI subscriptions exist just so the core knows we care about those @@ -5615,8 +5712,13 @@ static int iax2_indicate(struct ast_channel *c, int condition, const void *data, } break; case AST_CONTROL_CONNECTED_LINE: - if (!ast_test_flag64(pvt, IAX_SENDCONNECTEDLINE)) + case AST_CONTROL_REDIRECTING: + if (!ast_test_flag64(pvt, IAX_SENDCONNECTEDLINE)) { + /* We are not configured to allow sending these updates. */ + ast_debug(2, "Callno %u: Config blocked sending control frame %d.\n", + callno, condition); goto done; + } break; case AST_CONTROL_PVT_CAUSE_CODE: res = -1; @@ -7557,6 +7659,12 @@ static int __send_command(struct chan_iax2_pvt *i, char type, int command, unsig static int send_command(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const unsigned char *data, int datalen, int seqno) { + if (type == AST_FRAME_CONTROL && !iax2_is_control_frame_allowed(command)) { + /* Control frame should not go out on the wire. */ + ast_debug(2, "Callno %u: Blocked sending control frame %d.\n", + i->callno, command); + return 0; + } return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 0); } @@ -10417,13 +10525,6 @@ static int socket_process_helper(struct iax2_thread *thread) iaxs[fr->callno]->videoformat = ast_format_to_old_bitfield(&f.subclass.format); } } - if (f.frametype == AST_FRAME_CONTROL && iaxs[fr->callno]->owner) { - if (f.subclass.integer == AST_CONTROL_BUSY) { - ast_channel_hangupcause_set(iaxs[fr->callno]->owner, AST_CAUSE_BUSY); - } else if (f.subclass.integer == AST_CONTROL_CONGESTION) { - ast_channel_hangupcause_set(iaxs[fr->callno]->owner, AST_CAUSE_CONGESTION); - } - } if (f.frametype == AST_FRAME_IAX) { AST_SCHED_DEL(sched, iaxs[fr->callno]->initid); /* Handle the IAX pseudo frame itself */ @@ -11607,17 +11708,48 @@ immediatedial: ast_mutex_unlock(&iaxsl[fr->callno]); return 1; } - /* Don't allow connected line updates unless we are configured to */ - if (f.frametype == AST_FRAME_CONTROL && f.subclass.integer == AST_CONTROL_CONNECTED_LINE) { - struct ast_party_connected_line connected; - if (!ast_test_flag64(iaxs[fr->callno], IAX_RECVCONNECTEDLINE)) { + if (f.frametype == AST_FRAME_CONTROL) { + if (!iax2_is_control_frame_allowed(f.subclass.integer)) { + /* Control frame not allowed to come from the wire. */ + ast_debug(2, "Callno %u: Blocked receiving control frame %d.\n", + fr->callno, f.subclass.integer); ast_variables_destroy(ies.vars); ast_mutex_unlock(&iaxsl[fr->callno]); return 1; } + if (f.subclass.integer == AST_CONTROL_CONNECTED_LINE + || f.subclass.integer == AST_CONTROL_REDIRECTING) { + if (!ast_test_flag64(iaxs[fr->callno], IAX_RECVCONNECTEDLINE)) { + /* We are not configured to allow receiving these updates. */ + ast_debug(2, "Callno %u: Config blocked receiving control frame %d.\n", + fr->callno, f.subclass.integer); + ast_variables_destroy(ies.vars); + ast_mutex_unlock(&iaxsl[fr->callno]); + return 1; + } + } + + iax2_lock_owner(fr->callno); + if (iaxs[fr->callno] && iaxs[fr->callno]->owner) { + if (f.subclass.integer == AST_CONTROL_BUSY) { + ast_channel_hangupcause_set(iaxs[fr->callno]->owner, AST_CAUSE_BUSY); + } else if (f.subclass.integer == AST_CONTROL_CONGESTION) { + ast_channel_hangupcause_set(iaxs[fr->callno]->owner, AST_CAUSE_CONGESTION); + } + ast_channel_unlock(iaxs[fr->callno]->owner); + } + } + + if (f.frametype == AST_FRAME_CONTROL + && f.subclass.integer == AST_CONTROL_CONNECTED_LINE) { + struct ast_party_connected_line connected; - /* Initialize defaults */ + /* + * Process a received connected line update. + * + * Initialize defaults. + */ ast_party_connected_line_init(&connected); connected.id.number.presentation = iaxs[fr->callno]->calling_pres; connected.id.name.presentation = iaxs[fr->callno]->calling_pres; @@ -11640,6 +11772,7 @@ immediatedial: } ast_party_connected_line_free(&connected); } + /* Common things */ f.src = "IAX2"; f.mallocd = 0; diff --git a/configs/iax.conf.sample b/configs/iax.conf.sample index a9841f0da..e17c7dfeb 100644 --- a/configs/iax.conf.sample +++ b/configs/iax.conf.sample @@ -610,14 +610,18 @@ description=Demo System At Digium ; Description of this peer, as listed by ; IPs can also optionally be given but are not required. Caller*ID can be ; suggested to the other side as well if it is for example a phone instead of ; another PBX. -;connectedline=yes ; Set how connected line information is handled for this -; ; peer. If set to "yes", both sending and receiving -; ; connected line information will be enabled. If set to -; ; "send", this peer will send connected line information -; ; but will not process connected line updates. If set to -; ; "receive", connected line updates will be processed -; ; but not sent. If set to "no", connected line updates -; ; will be disabled. Default is "no". +;connectedline=yes ; Set if connected line and redirecting information updates +; ; are passed between Asterisk servers for this peer. +; ; yes - Sending and receiving updates are enabled. +; ; send - Only send updates. +; ; receive - Only process received updates. +; ; no - Sending and receiving updates are disabled. +; ; Default is "no". +; ; +; ; Note: Because of an incompatibility between Asterisk v1.4 +; ; and Asterisk v1.8 or later, this option must be set +; ; to "no" toward the Asterisk v1.4 peer. A symptom of the +; ; incompatibility is the call gets disconnected unexpectedly. ;[dynamichost] diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h index 14491aed8..53383834f 100644 --- a/include/asterisk/frame.h +++ b/include/asterisk/frame.h @@ -235,6 +235,18 @@ extern struct ast_frame ast_null_frame; /*! Reject link request */ #define AST_HTML_LINKREJECT 20 +/*! + * \brief Internal control frame subtype field values. + * + * \warning + * IAX2 sends these values out over the wire. To prevent future + * incompatibilities, pick the next value in the enum from whatever + * is on the current trunk. If you lose the merge race you need to + * fix the previous branches to match what is on trunk. In addition + * you need to change chan_iax2 to explicitly allow the control + * frame over the wire if it makes sense for the frame to be passed + * to another Asterisk instance. + */ enum ast_control_frame_type { AST_CONTROL_HANGUP = 1, /*!< Other end has hungup */ AST_CONTROL_RING = 2, /*!< Local ring */ @@ -270,6 +282,20 @@ enum ast_control_frame_type { AST_CONTROL_UPDATE_RTP_PEER = 32, /*!< Interrupt the bridge and have it update the peer */ AST_CONTROL_PVT_CAUSE_CODE = 33, /*!< Contains an update to the protocol-specific cause-code stored for branching dials */ + /* + * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING + * + * IAX2 sends these values out over the wire. To prevent future + * incompatibilities, pick the next value in the enum from whatever + * is on the current trunk. If you lose the merge race you need to + * fix the previous branches to match what is on trunk. In addition + * you need to change chan_iax2 to explicitly allow the control + * frame over the wire if it makes sense for the frame to be passed + * to another Asterisk instance. + * + * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING + */ + /* Control frames used to manipulate a stream on a channel. The values for these * must be greater than the allowed value for a 8-bit char, so that they avoid * conflicts with DTMF values. */ |