Skip to content

Commit

Permalink
When we receive a full frame that is supposed to contain our call num…
Browse files Browse the repository at this point in the history
…ber,

ensure that it has the correct one.
(closes issue #10078)
(AST-2008-006)
  • Loading branch information
russell committed Apr 22, 2008
1 parent bc1db65 commit 10da3da
Showing 1 changed file with 38 additions and 22 deletions.
60 changes: 38 additions & 22 deletions channels/chan_iax2.c
Expand Up @@ -1239,13 +1239,13 @@ static struct iax_frame *iaxfrdup2(struct iax_frame *fr)
#define NEW_ALLOW 1
#define NEW_FORCE 2

static int match(struct sockaddr_in *sin, unsigned short callno, unsigned short dcallno, struct chan_iax2_pvt *cur)
static int match(struct sockaddr_in *sin, unsigned short callno, unsigned short dcallno, struct chan_iax2_pvt *cur, int full_frame)
{
if ((cur->addr.sin_addr.s_addr == sin->sin_addr.s_addr) &&
(cur->addr.sin_port == sin->sin_port)) {
/* This is the main host */
if ((cur->peercallno == callno) ||
((dcallno == cur->callno) && !cur->peercallno)) {
if ( (cur->peercallno == 0 || cur->peercallno == callno) &&
(full_frame ? dcallno == cur->callno : 1) ) {
/* That's us. Be sure we keep track of the peer call number */
return 1;
}
Expand Down Expand Up @@ -1336,7 +1336,7 @@ static int make_trunk(unsigned short callno, int locked)
/*!
* \note Calling this function while holding another pvt lock can cause a deadlock.
*/
static int __find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd, int return_locked)
static int __find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd, int return_locked, int full_frame)
{
int res = 0;
int x;
Expand All @@ -1349,7 +1349,7 @@ static int __find_callno(unsigned short callno, unsigned short dcallno, struct s
ast_mutex_lock(&iaxsl[x]);
if (iaxs[x]) {
/* Look for an exact match */
if (match(sin, callno, dcallno, iaxs[x])) {
if (match(sin, callno, dcallno, iaxs[x], full_frame)) {
res = x;
}
}
Expand All @@ -1359,14 +1359,16 @@ static int __find_callno(unsigned short callno, unsigned short dcallno, struct s
ast_mutex_lock(&iaxsl[x]);
if (iaxs[x]) {
/* Look for an exact match */
if (match(sin, callno, dcallno, iaxs[x])) {
if (match(sin, callno, dcallno, iaxs[x], full_frame)) {
res = x;
}
}
ast_mutex_unlock(&iaxsl[x]);
}
}
if ((res < 1) && (new >= NEW_ALLOW)) {
int start, found = 0;

/* It may seem odd that we look through the peer list for a name for
* this *incoming* call. Well, it is weird. However, users don't
* have an IP address/port number that we can match against. So,
Expand All @@ -1375,15 +1377,29 @@ static int __find_callno(unsigned short callno, unsigned short dcallno, struct s
* correct, but it will be changed if needed after authentication. */
if (!iax2_getpeername(*sin, host, sizeof(host)))
snprintf(host, sizeof(host), "%s:%d", ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
gettimeofday(&now, NULL);
for (x=1;x<TRUNK_CALL_START;x++) {

now = ast_tvnow();
start = 1 + (ast_random() % (TRUNK_CALL_START - 1));
for (x = start; 1; x++) {
if (x == TRUNK_CALL_START) {
x = 0;
continue;
}

/* Find first unused call number that hasn't been used in a while */
ast_mutex_lock(&iaxsl[x]);
if (!iaxs[x] && ((now.tv_sec - lastused[x].tv_sec) > MIN_REUSE_TIME)) break;
if (!iaxs[x] && ((now.tv_sec - lastused[x].tv_sec) > MIN_REUSE_TIME)) {
found = 1;
break;
}
ast_mutex_unlock(&iaxsl[x]);

if (x == start - 1) {
break;
}
}
/* We've still got lock held if we found a spot */
if (x >= TRUNK_CALL_START) {
if (x == start - 1 && !found) {
ast_log(LOG_WARNING, "No more space\n");
return 0;
}
Expand Down Expand Up @@ -1420,14 +1436,14 @@ static int __find_callno(unsigned short callno, unsigned short dcallno, struct s
return res;
}

static int find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd) {
static int find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd, int full_frame) {

return __find_callno(callno, dcallno, sin, new, sockfd, 0);
return __find_callno(callno, dcallno, sin, new, sockfd, 0, full_frame);
}

static int find_callno_locked(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd) {
static int find_callno_locked(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd, int full_frame) {

return __find_callno(callno, dcallno, sin, new, sockfd, 1);
return __find_callno(callno, dcallno, sin, new, sockfd, 1, full_frame);
}

static void iax2_frame_free(struct iax_frame *fr)
Expand Down Expand Up @@ -6871,7 +6887,7 @@ static int socket_process(struct iax2_thread *thread)
}

/* This is a video frame, get call number */
fr->callno = find_callno(ntohs(vh->callno) & ~0x8000, dcallno, &sin, new, fd);
fr->callno = find_callno(ntohs(vh->callno) & ~0x8000, dcallno, &sin, new, fd, 0);
minivid = 1;
} else if ((meta->zeros == 0) && !(ntohs(meta->metacmd) & 0x8000)) {
unsigned char metatype;
Expand Down Expand Up @@ -6929,7 +6945,7 @@ static int socket_process(struct iax2_thread *thread)
/* Stop if we don't have enough data */
if (len > res)
break;
fr->callno = find_callno_locked(callno & ~IAX_FLAG_FULL, 0, &sin, NEW_PREVENT, fd);
fr->callno = find_callno_locked(callno & ~IAX_FLAG_FULL, 0, &sin, NEW_PREVENT, fd, 0);
if (fr->callno) {
/* If it's a valid call, deliver the contents. If not, we
drop it, since we don't have a scallno to use for an INVAL */
Expand Down Expand Up @@ -7015,7 +7031,7 @@ static int socket_process(struct iax2_thread *thread)
}

if (!fr->callno)
fr->callno = find_callno(ntohs(mh->callno) & ~IAX_FLAG_FULL, dcallno, &sin, new, fd);
fr->callno = find_callno(ntohs(mh->callno) & ~IAX_FLAG_FULL, dcallno, &sin, new, fd, ntohs(mh->callno) & IAX_FLAG_FULL);

if (fr->callno > 0)
ast_mutex_lock(&iaxsl[fr->callno]);
Expand Down Expand Up @@ -8510,7 +8526,7 @@ static int iax2_do_register(struct iax2_registry *reg)
if (!reg->callno) {
if (option_debug)
ast_log(LOG_DEBUG, "Allocate call number\n");
reg->callno = find_callno_locked(0, 0, &reg->addr, NEW_FORCE, defaultsockfd);
reg->callno = find_callno_locked(0, 0, &reg->addr, NEW_FORCE, defaultsockfd, 0);
if (reg->callno < 1) {
ast_log(LOG_WARNING, "Unable to create call for registration\n");
return -1;
Expand Down Expand Up @@ -8571,7 +8587,7 @@ static int iax2_provision(struct sockaddr_in *end, int sockfd, char *dest, const
memset(&ied, 0, sizeof(ied));
iax_ie_append_raw(&ied, IAX_IE_PROVISIONING, provdata.buf, provdata.pos);

callno = find_callno_locked(0, 0, &sin, NEW_FORCE, cai.sockfd);
callno = find_callno_locked(0, 0, &sin, NEW_FORCE, cai.sockfd, 0);
if (!callno)
return -1;

Expand Down Expand Up @@ -8712,7 +8728,7 @@ static int iax2_poke_peer(struct iax2_peer *peer, int heldcall)
}
if (heldcall)
ast_mutex_unlock(&iaxsl[heldcall]);
peer->callno = find_callno(0, 0, &peer->addr, NEW_FORCE, peer->sockfd);
peer->callno = find_callno(0, 0, &peer->addr, NEW_FORCE, peer->sockfd, 0);
if (heldcall)
ast_mutex_lock(&iaxsl[heldcall]);
if (peer->callno < 1) {
Expand Down Expand Up @@ -8792,7 +8808,7 @@ static struct ast_channel *iax2_request(const char *type, int format, void *data
if (pds.port)
sin.sin_port = htons(atoi(pds.port));

callno = find_callno_locked(0, 0, &sin, NEW_FORCE, cai.sockfd);
callno = find_callno_locked(0, 0, &sin, NEW_FORCE, cai.sockfd, 0);
if (callno < 1) {
ast_log(LOG_WARNING, "Unable to create call\n");
*cause = AST_CAUSE_CONGESTION;
Expand Down Expand Up @@ -10106,7 +10122,7 @@ static int cache_get_callno_locked(const char *data)
ast_log(LOG_DEBUG, "peer: %s, username: %s, password: %s, context: %s\n",
pds.peer, pds.username, pds.password, pds.context);

callno = find_callno_locked(0, 0, &sin, NEW_FORCE, cai.sockfd);
callno = find_callno_locked(0, 0, &sin, NEW_FORCE, cai.sockfd, 0);
if (callno < 1) {
ast_log(LOG_WARNING, "Unable to create call\n");
return -1;
Expand Down

0 comments on commit 10da3da

Please sign in to comment.