From 55ceea9e231d7bcd2b9c45493d7987a1af66a2aa Mon Sep 17 00:00:00 2001 From: Steve Davies Date: Wed, 19 Nov 2008 12:56:47 +0000 Subject: [PATCH] Add AutoFilter=unique option for better ActionID tracking (Steve Davies) Add more_events option for users to get more "noise" (Steve Davies) --- Makefile | 2 +- README | 42 ++++++++++++++++++++++++----- VERSIONS | 6 ++++- configs/astmanproxy.users | 4 +-- src/astmanproxy.c | 37 ++++++++++++++++++++------ src/config.c | 11 +++++--- src/config_perms.c | 7 +++-- src/include/astmanproxy.h | 1 + src/proxyfunc.c | 56 +++++++++++++++++++++++++++++---------- 9 files changed, 129 insertions(+), 37 deletions(-) diff --git a/Makefile b/Makefile index 6c322d3..106754c 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ OSARCH=$(shell uname -s) OSREV=$(shell uname -r) -VERSION := 1.22pre081111 +VERSION := 1.22pre081119 DESTDIR ?= CONFDIR:=/etc/asterisk CONFDIR_REAL := $(DESTDIR)/etc/asterisk diff --git a/README b/README index fd593a0..39f58a2 100644 --- a/README +++ b/README @@ -93,7 +93,7 @@ OutputFormat: (standard|xml) Sets the output format on a per-client basis ProxyAction: SetAutoFilter -AutoFilter: (on|off) +AutoFilter: (on|off|unique) Sets the AutoFilter property on a per-client basis (See autofiltering section below) @@ -167,10 +167,10 @@ AstManProxy Autofiltering Functionality One of the most powerful features of AstManProxy is its ability to automatically filter output on a per-client basis. It can do this -with its Autofilter capability, which can be set 'on' in the config -file or enabled via the ProxyAction: SetAutoFilter function. +with its Autofilter capability, which can be set 'on'/'unique' in +the config file or enabled via the ProxyAction: SetAutoFilter function. -With autofiltering enabled, each client only receives output containing +With autofiltering 'on', each client only receives output containing the "ActionID" parameter it has set most recently. This is useful for single atomic requests into asterisk from a client, such as when creating a simple UI to inject a command. @@ -193,6 +193,32 @@ how this same mechanism can be used to quickly query asterisk box(es), initiate calls, etc, without your client having to worry with filtering a lot of unrelated output. +A more advanced verion of this facility is to set autofiltering to +'unique'. This causes astmanproxy to alter the ActionID on the way +to Asterisk, and undo that change on the way back. + +For example the exchange: + +> Action: Ping +> ActionID: foo +> + +< Response: Pong +< ActionID: foo +< + +Might be seen by Asterisk as: + +> Action: Ping +> ActionID: amp7-foo +> + +< Response: Pong +< ActionID: amp7-foo +< + +and the "amp7-" prefix is created uniquely for each client connection. + =================================================================== On the astmanproxy.users output filtering functionality @@ -216,10 +242,14 @@ force the Account: header to be overwritten for all commands to/from this client. If the Action is "Originate", then a missing Account: header will be added. -Lastly, a "server" header will cause the proxy to behave as if the +A "server" option will cause the proxy to behave as if the client has included a "Server:" header in each request packet. -user=secret,channel,out_context (to Asterisk),in_context (From Asterisk),accountcode,server +Any non-empty string provided in "more_events" will allow the passing +of non-filterable events to all clients. The default behaviour is to +block these packets if any form of filtering is requested. + +user=secret,channel,out_context (to Asterisk),in_context (From Asterisk),accountcode,server,more_events e.g.: steve=steve,SIP/snom190,local, diff --git a/VERSIONS b/VERSIONS index d01e3e3..de57b26 100644 --- a/VERSIONS +++ b/VERSIONS @@ -1,4 +1,8 @@ -1.22fork2 - Refresh of GIT fork by Steve Davies +1.22pre081119 - Refresh of GIT fork by Steve Davies + Add AutoFilter=unique option for better ActionID tracking (Steve Davies) + Add more_events option for users to get more "noise" (Steve Davies) + +1.22pre081111 - Refresh of GIT fork by Steve Davies Segfault amd SIGPIPE fixes (Steve Davies) Several fixes to UniqueID header tracking (Steve Davies) Ensure that Response: headers are not filtered out. Assumes ActionID is sent (Steve Davies) diff --git a/configs/astmanproxy.users b/configs/astmanproxy.users index 7e740be..10923a1 100644 --- a/configs/astmanproxy.users +++ b/configs/astmanproxy.users @@ -11,8 +11,8 @@ ; sending commands. It must be an exact match to the hostname/ip address ; in the .conf configuration file. ; -; user=secret,[channel],[out_context (to Asterisk)],[in_context (From Asterisk)],[accountcode],[server] +; user=secret,[channel],[out_context (to Asterisk)],[in_context (From Asterisk)],[accountcode],[server],[more_events] ; ; steve=steve,SIP/snom190,local, -; dave=securepass,SIP/1002,,,davesaccount +; dave=securepass,SIP/1002,,,davesaccount,,y ; bill=pass diff --git a/src/astmanproxy.c b/src/astmanproxy.c index dbd8207..fb6bff6 100644 --- a/src/astmanproxy.c +++ b/src/astmanproxy.c @@ -197,26 +197,33 @@ int WriteClients(struct message *m) { // If VALRET > 1, then we may want to send a retrospective NewChannel before // writing out this event... // Send the retrospective Newchannel from the cache (m->session->cache) to this client (c)... - if( (valret & ATS_SRCUNIQUE) && m->session ) { + if( (valret & ATS_SRCUNIQUE) && m->session ) { struct message m_temp; memset(&m_temp, 0, sizeof(struct message) ); uniqueid = astman_get_header(m, "SrcUniqueID"); ResendFromStack(uniqueid, m->session, &m_temp); m_temp.session = m->session; c->output->write(c, &m_temp); - } - if( (valret & ATS_DSTUNIQUE) && m->session ) { + } + if( (valret & ATS_DSTUNIQUE) && m->session ) { struct message m_temp; memset(&m_temp, 0, sizeof(struct message) ); uniqueid = astman_get_header(m, "DestUniqueID"); ResendFromStack(uniqueid, m->session, &m_temp); m_temp.session = m->session; c->output->write(c, &m_temp); - } + } if (c->autofilter && c->actionid) { actionid = astman_get_header(m, ACTION_ID); - if ( !strcmp(actionid, c->actionid) ) + if ( c->autofilter == 1 && !strcmp(actionid, c->actionid) ) +// Original AutoFilter c->output->write(c, m); + else if ( c->autofilter == 2 && !strncmp(actionid, c->actionid, strlen(c->actionid)) ) { +// New AutoFilter, actionid like "ast123-XX" + memmove( actionid, actionid+strlen(c->actionid), strlen(actionid)+1-strlen(c->actionid)); + c->output->write(c, m); + } else if (debug > 5) + debugmsg("ActionID Filtered a message to a client\n"); } else c->output->write(c, m); @@ -225,7 +232,8 @@ int WriteClients(struct message *m) { c->outputcomplete = 1; pthread_mutex_unlock(&c->lock); } - } + } else if ( !c->server && m->hdrcount>1 && !valret && debug > 5) + debugmsg("Validate Filtered a message to a client"); c = c->next; } if( !strcasecmp( event, "Hangup" ) ) { @@ -285,7 +293,12 @@ int WriteAsterisk(struct message *m) { void *setactionid(char *actionid, struct message *m, struct mansession *s) { pthread_mutex_lock(&s->lock); - strncpy(s->actionid, actionid, MAX_LEN); + if( s->autofilter < 2 ) { // Either save ActionID + strncpy(s->actionid, actionid, MAX_LEN); + } else if( strlen(s->actionid) + strlen(actionid) < MAX_LEN ) { // Or modify it + memmove(actionid+strlen(s->actionid), actionid, strlen(actionid)+strlen(s->actionid)); + strncpy(actionid, s->actionid, strlen(s->actionid)); + } pthread_mutex_unlock(&s->lock); return 0; @@ -300,12 +313,20 @@ void *session_do(struct mansession *s) if (s->input->onconnect) s->input->onconnect(s, &m); + if (s->autofilter == 2) { + pthread_mutex_lock(&s->lock); + snprintf(s->actionid, MAX_LEN - 20, "amp%d-", s->fd); + if (debug > 3) + debugmsg("Setting actionID root to %s for new connection", s->actionid); + pthread_mutex_unlock(&s->lock); + } // Signal settings are not always inherited by threads, so ensure we ignore this one + // as it is handled through error returns (void) signal(SIGPIPE, SIG_IGN); for (;;) { /* Get a complete message block from input handler */ - memset(&m, 0, sizeof(struct message) ); + memset( &m, 0, sizeof(struct message) ); if (debug > 3) debugmsg("calling %s_read...", s->input->formatname); res = s->input->read(s, &m); diff --git a/src/config.c b/src/config.c index fa11e34..6287706 100644 --- a/src/config.c +++ b/src/config.c @@ -134,9 +134,14 @@ void *processline(char *s) { strcpy(pc.proc_group, value); else if (!strcmp(name,"logfile") ) strcpy(pc.logfile, value); - else if (!strcmp(name,"autofilter") ) - pc.autofilter = strcmp(value,"on") ? 0 : 1; - else if (!strcmp(name,"outputformat") ) + else if (!strcmp(name,"autofilter") ) { + if( ! strcmp(value,"on") ) + pc.autofilter = 1; + else if( ! strcmp(value,"unique") ) + pc.autofilter = 2; + else + pc.autofilter = 0; + } else if (!strcmp(name,"outputformat") ) strcpy(pc.outputformat, value); else if (!strcmp(name,"inputformat") ) strcpy(pc.inputformat, value); diff --git a/src/config_perms.c b/src/config_perms.c index bb7d356..665a4a4 100644 --- a/src/config_perms.c +++ b/src/config_perms.c @@ -65,6 +65,9 @@ void *add_userperm(char* username, char *userspec, struct proxy_user **pu) { case 5: strncat(user->server, s, 1); break; + case 6: + user->more_events[0] = 'y'; // Any non-null entry + break; } } while (*(s++)); @@ -91,9 +94,9 @@ void *processperm(char *s, struct proxy_user **pu) { nvstate = 1; continue; } - if (!nvstate) { + if (!nvstate) strncat(name, s, 1); - } else + else strncat(value, s, 1); } while (*(s++)); diff --git a/src/include/astmanproxy.h b/src/include/astmanproxy.h index 235cd63..93fcdff 100644 --- a/src/include/astmanproxy.h +++ b/src/include/astmanproxy.h @@ -59,6 +59,7 @@ struct proxy_user { char ocontext[80]; char account[80]; char server[80]; + char more_events[2]; struct proxy_user *next; }; diff --git a/src/proxyfunc.c b/src/proxyfunc.c index 7f35d2a..a742762 100644 --- a/src/proxyfunc.c +++ b/src/proxyfunc.c @@ -105,10 +105,16 @@ void *ProxySetAutoFilter(struct mansession *s, struct message *m) { value = astman_get_header(m, "AutoFilter"); if ( !strcasecmp(value, "on") ) i = 1; + else if ( !strcasecmp(value, "unique") ) + i = 2; else i = 0; pthread_mutex_lock(&s->lock); s->autofilter = i; + if( i == 2 ) + snprintf(s->actionid, MAX_LEN - 20, "amp%d-", s->fd); + else + s->actionid[0] = '\0'; pthread_mutex_unlock(&s->lock); memset(&mo, 0, sizeof(struct message)); @@ -167,7 +173,7 @@ void *ProxyLogin(struct mansession *s, struct message *m) { pthread_mutex_lock(&userslock); pu = pc.userlist; while( pu ) { - if ( !strcmp(user, pu->username) ) { + if ( !strcmp(user, pu->username) ) { if (!AuthMD5(key, s->challenge, pu->secret) || !strcmp(secret, pu->secret) ) { AddHeader(&mo, "Response: Success"); AddHeader(&mo, "Message: Authentication accepted"); @@ -179,6 +185,7 @@ void *ProxyLogin(struct mansession *s, struct message *m) { strcpy(s->user.ocontext, pu->ocontext); strcpy(s->user.account, pu->account); strcpy(s->user.server, pu->server); + strcpy(s->user.more_events, pu->more_events); pthread_mutex_unlock(&s->lock); if( debug ) debugmsg("Login as: %s", user); @@ -351,7 +358,7 @@ int proxyerror_do(struct mansession *s, char *err) } /* [do_]AddToStack - Stores an event in a stack for later repetition. - indexted on UniqueID. + indexed on UniqueID. If SrcUniqueID / DestUniqueID are present, store against both. If a record already exists, do nothing. withbody = 1, saves a copy of whole message (server). @@ -420,25 +427,37 @@ int do_AddToStack(char *uniqueid, struct message *m, struct mansession *s, int w pthread_mutex_unlock(&s->lock); return 1; } - int AddToStack(struct message *m, struct mansession *s, int withbody) { char *uniqueid; - int ret; + int ret, absent; ret=0; + absent=0; + uniqueid = astman_get_header(m, "Uniqueid"); - if( uniqueid[0] != '\0' ) + if( uniqueid[0] != '\0' ) { if( do_AddToStack(uniqueid, m, s, withbody) ) ret |= ATS_UNIQUE; + } else + absent++; + uniqueid = astman_get_header(m, "SrcUniqueID"); - if( uniqueid[0] != '\0' ) + if( uniqueid[0] != '\0' ) { if( do_AddToStack(uniqueid, m, s, withbody) ) ret |= ATS_SRCUNIQUE; + } else + absent++; + uniqueid = astman_get_header(m, "DestUniqueID"); - if( uniqueid[0] != '\0' ) + if( uniqueid[0] != '\0' ) { if( do_AddToStack(uniqueid, m, s, withbody) ) ret |= ATS_DSTUNIQUE; + } else + absent++; + + if( s->user.more_events[0] != '\0' && absent == 3 ) + return 1; // Want more/anonymous events return ret; } @@ -494,14 +513,14 @@ void FreeStack(struct mansession *s) if( t->message ) free( t->message ); free( t ); - s->depth--; t = n; + s->depth--; } + s->stack = NULL; if( debug && s->depth > 0 ) debugmsg("ALERT! Stack may have leaked %d slots!!!", s->depth); if( debug ) debugmsg("Freed entire stack."); - s->stack = NULL; pthread_mutex_unlock(&s->lock); } @@ -535,6 +554,7 @@ void ResendFromStack(char* uniqueid, struct mansession *s, struct message *m) if( !m ) return; + if( debug ) debugmsg("ResendFromStack: %s", uniqueid); @@ -621,9 +641,12 @@ int ValidateAction(struct message *m, struct mansession *s, int inbound) { // we will return a response if the ActionID matches our last known ActionID response = astman_get_header(m, "Response"); actionid = astman_get_header(m, ACTION_ID); - if( response[0] != '\0' && actionid[0] != '\0' && !strcmp(actionid, s->actionid) ) - return 1; - + if( response[0] != '\0' && actionid[0] != '\0' && !strcmp(actionid, s->actionid) ) { + if (s->autofilter < 2 && !strcmp(actionid, s->actionid)) + return 1; + else if ( !strncmp(actionid, s->actionid, strlen(s->actionid)) ) + return 1; + } if( uchannel[0] != '\0' ) { channel = astman_get_header(m, "Channel"); @@ -683,8 +706,13 @@ int ValidateAction(struct message *m, struct mansession *s, int inbound) { } } - if( inbound ) - return AddToStack(m, s, 0); + if( inbound ) { + int res; + res = AddToStack(m, s, 0); + if( debug > 5 ) + debugmsg("AddToStack returned %d", res); + return res; + } return 1; }