Allowlist module - wrong logic or wrong processing order?

Hi,

I’m currently implementing an Antispam system with FreePBX which basically should do (in more or less this order):

  • Well-known numbers in a list should bypass all checks and directly be forwarded to the final destination
  • Anonymous callers shall enter their number (Privacy feature)
  • Number at this point is checked online for Spam with Superfecta → Special route in case of Spamscore
  • Call will be routed to a virtual extension doing caller screening
  • Screened call will be forwarded to the final destination

All this independently for three different incoming DIDs.

I’ve learned a lot about the capabilities of FreePBX in the last days and everything is working great - with the exeption of the bypass of well-known numbers. I’m really completely desperated with the allowlist module as in my opinion it has a wrong logic (or at least a wrong position in the call processing).

The allowlist processes well-known “friendly” numbers. In my understanding this should work by “extracting” these numbers in the module from further processing which means they can be immediately forwarded to the next destination (Dynamic routes, queue, ring group, extension etc.). There is no need that a well-known number does any further processing by the privacy feature or superfecta - the number is already approved by the fact it’s in the allowlist.

Unfortunately Allowlist exactly behaves the opposite. It extracts all unknown callers from the inbound processing, completely killing the ability to be further checked by privacy and superfecta. While well-known and approved numbers continue being processed by Privacy and Superfecta.

I’m sure there is a reason for this inverted logic, because @mitchmitchell must have had a reason to implement it like this … so I guess it’s me who does not understand why it was done this way. However, I don’t see a proper way to complete my project with this behavior.

Even the inverse logic would be something that can be dealt with - if the allowlist “order” would not be this extremely high in the call processing. I’m not sure if this can be influenced in FreePBX in any way, but allowlist unfortunately catches all the interesting “unknown” callers quite at the beginning of the process. It “steals” Privacy and Superfecta the ability to get their hands on the call.

Finally I still would really love a solution for this dilemma. I did not look that deep how modules are linked in FreePBX of if they are in a language which allows modification. Thinking about the ability of a “dirty hack” to work around this issue like:

  • Maybe finding how to invert the logic in a way that allowed numbers take the exception route instead of non-allowed
  • Maybe shifting the point where allowlist is processed in a route to a point behind the Privacy and Superfecta processing

Both would solve the issue, with the first one being be much more clear and elegant in my opinion.

Any other ideas how to make allowlist work with Privacy and Superfecta are highly welcome

PS: Privacy can be worked around by catching anonymous callers with a second inbound route and send them to an IVR with following voicemail box. Not that elegant, but at least a solution. But for Superfecta I don’t have a solution right now.

What allowlist module are you speaking of? There isn’t one in FreePBX.

This one:

image

Which is part of the Blacklist module…just needed to make sure you’re not using something that is 3rd party so the code could be looked at properly.

Edit: Scratch that…it’s in the unsupported repo…never a good sign.

Oh I guess the next question is…how do we get access to the unsupported repo and those modules/code. They aren’t on GitHub or is there a different GitHub for it?

There is a Github repo, yes: GitHub - mitchmitchell/allowlist: Module of FreePBX (Allowlist) :: This module is used to manage a system wide list of allowed callers

I’m currently staring at the code … it should be possible to “reverse” the logic in the dialplan. I just need to “learn” the Asterisk dialplan commands while staring :wink:

Important section seems to be in Allowlist.class.php from line 303:

        $id = 'app-allowlist-check';
        $ext->add($id, $c, '', new \ext_gosubif('$[${DIALPLAN_EXISTS(app-allowlist-check-predial-hook,s,1)}]', 'app-allowlist-check-predial-hook,s,1'));
        $ext->add($id, $c, '', new \ext_gotoif('$["${callerallowed}"="1"]', 'returnto'));

	    // check pause time and exit if pause is enabled
        $ext->add($id, $c, '', new \ext_gosub('app-allowlist-pause-check,s,1'));
	    $ext->add($id, $c, '', new \ext_gotoif('$["${DB_EXISTS(allowlist/pause)}"="1"]', 'returnto'));

        $ext->add($id, $c, 'check-list', new \ext_gotoif('$["${DB_EXISTS(allowlist/${CALLERID(num)})}"="0"]', 'check-contacts'));
        $ext->add($id, $c, '', new \ext_setvar('CALLED_ALLOWLIST', '1'));
        $ext->add($id, $c, '', new \ext_return(''));

        $ext->add($id, $c, 'check-contacts', new \ext_gotoif('$["${DB_EXISTS(allowlist/knowncallers)}" = "0"]', 'nonallowlisted'));
        $ext->add($id, $c, '', new \ext_agi('allowlist-check.agi,"allowlisted"'));
        $ext->add($id, $c, '', new \ext_gotoif('$["${allowlisted}"="false"]', 'nonallowlisted'));
        $ext->add($id, $c, '', new \ext_setvar('CALLED_ALLOWLIST', '1'));
        $ext->add($id, $c, '', new \ext_return(''));

        $ext->add($id, $c, 'nonallowlisted', new \ext_answer(''));
        $ext->add($id, $c, '', new \ext_set('ALDEST', '${DB(allowlist/dest)}'));

        $ext->add($id, $c, '', new \ext_execif('$["${ALDEST}"=""]', 'Set', 'ALDEST=app-blackhole,hangup,1'));
        $ext->add($id, $c, '', new \ext_gotoif('$["${alreturnhere}"="1"]', 'returnto'));
        $ext->add($id, $c, '', new \ext_gotoif('${LEN(${ALDEST})}', '${ALDEST}', 'app-blackhole,zapateller,1'));

        //		$ext->add($id, $c, '', new \ext_gotoif('$["${alreturnhere}"="1"]', 'returnto'));
        //		$ext->add($id, $c, '', new \ext_gotoif('${LEN(${ALDEST})}', '${ALDEST}', 'returnto'));
        $ext->add($id, $c, 'returnto', new \ext_return());

Looks my attempt to reverse the logic was successful. I’d be happy if one of the experts here can have a look if I made a mistake, at least it seems to work now as expected and I don’t see error messages in the log:

        $id = 'app-allowlist-check';
        $ext->add($id, $c, '', new \ext_gosubif('$[${DIALPLAN_EXISTS(app-allowlist-check-predial-hook,s,1)}]', 'app-allowlist-check-predial-hook,s,1'));
        $ext->add($id, $c, '', new \ext_gotoif('$["${callerallowed}"="1"]', 'returnto'));

	    // check pause time and exit if pause is enabled
        $ext->add($id, $c, '', new \ext_gosub('app-allowlist-pause-check,s,1'));
	    $ext->add($id, $c, '', new \ext_gotoif('$["${DB_EXISTS(allowlist/pause)}"="1"]', 'returnto'));

        $ext->add($id, $c, 'check-list', new \ext_gotoif('$["${DB_EXISTS(allowlist/${CALLERID(num)})}"="0"]', 'check-contacts', 'allowlisted'));

        $ext->add($id, $c, 'check-contacts', new \ext_gotoif('$["${DB_EXISTS(allowlist/knowncallers)}" = "1"]', 'allowlisted'));
        $ext->add($id, $c, '', new \ext_agi('allowlist-check.agi,"allowlisted"'));
        $ext->add($id, $c, '', new \ext_gotoif('$["${allowlisted}"="true"]', 'allowlisted'));
        $ext->add($id, $c, '', new \ext_setvar('CALLED_ALLOWLIST', '1'));
        $ext->add($id, $c, '', new \ext_return(''));

        $ext->add($id, $c, 'allowlisted', new \ext_answer(''));
        $ext->add($id, $c, '', new \ext_set('ALDEST', '${DB(allowlist/dest)}'));

        $ext->add($id, $c, '', new \ext_execif('$["${ALDEST}"=""]', 'Set', 'ALDEST=app-blackhole,hangup,1'));
        $ext->add($id, $c, '', new \ext_gotoif('$["${alreturnhere}"="1"]', 'returnto'));
        $ext->add($id, $c, '', new \ext_gotoif('${LEN(${ALDEST})}', '${ALDEST}', 'app-blackhole,zapateller,1'));

        //		$ext->add($id, $c, '', new \ext_gotoif('$["${alreturnhere}"="1"]', 'returnto'));
        //		$ext->add($id, $c, '', new \ext_gotoif('${LEN(${ALDEST})}', '${ALDEST}', 'returnto'));
        $ext->add($id, $c, 'returnto', new \ext_return());

I need to live with that security warning that a module code has been altered now :wink:

I’ve created a GitHub fork with my changes: GitHub - jacotec/freepbx-allowlist: Module of FreePBX (Allowlist) :: This module is used to manage a system wide list of allowed callers

Back in the day things would go to FreePBX Contributed Modules · GitHub

These were community maintained but still packaged and put on the mirrors. It seems now if it’s not official you get to figure it out.

@jfinstrom I’m not getting the point, what do you mean? It’s more or less a “dirty hack” of an existing module to get it working the way I need it and I think it’s better. It can’t be contributed back to the original module as the changed behavior would kill all applications using the current behavior.

Elegant would be a switch in the app (default to the old behavior) to select the behavior. Otherwise a different module name (like Allowlist-NG) would be needed.

But that’s nothing I can do. My FreePBX/Asterisk knowledge is, let’s say 5%. PHP is lots of googling (my knowledge is embedded C). But I simply want to open my hack to the community because FreePBX is OpenSource and I can imagine that there might be people who may need this way as well.

But if you or someone else have the knowledge to implement this (with a behavior switch) into the original app or to do a “NG” official app out of it - I’d be happy.

I finally have created an unsigned “release” in my Github repo which I can install via Module Admin and which lists as “Allowlist NG”, so I know what version I’ve installed. :grimacing:

Mainly this is to avoid that my modification is destroyed by scheduled module updates which would seriously kill my call flows.

I’ll mark this as solved now. Whoever has the same problem and reads this thread, feel free to use my modification. If someone has the knowledge and wants to create an official signed version of this - feel free!

@lgaetz Where can modules like this get uploaded? Is the contribute repo still being used?

We don’t have a full plan yet for dealing with contributed modules, but we’ve been discussing it and have included it as one of the final roadmap items for the migration away from Atlassian.

Future note you could also mark your version number absurdly high like 16.99.9 and that should make it newer than the online version. You still would have to contend with unsigned warnings unless you self signed.

1 Like

Offtopic: I know how you feel, need to deal with that as well since the end of Jira Server. Currently migrating to OpenProject :smirk:

1 Like

@jfinstrom The best way would be a switch in the original module to select the logic you want. I think the current logic is totally wrong. But it can’t be changed hardcoded without selector because it’s in the field.

Hi guys,

I’ve had another look and I indeed managed it to implement a switch to the settings, so the behavior of Allowlist can be controlled, defaulting to the “known” logic:

So, it’s not a special solution anymore but an universal one :smile:

@lgaetz @jfinstrom I’d like to make a PR for this (as I’ve already signed the CLI yesterday for the Superfecta source :wink: ), but I’m not able to find the repo in your Github. How can we proceed here?

Just out of curiosity, you are aware that this logic breaks things in the Inbound Routes right? By jumping when there is a match, it will result in the following (that I’ve found so far)

  • Any CallerID prefix set in Inbound Route to be ignored.
  • Any changes in Music on Hold (anything other than Default) to not be applied.
  • Any Distinctive Ring/Alert Info to not be applied either.

I haven’t fully tested all the other changes that could by applied and where they are applied but those three things are widely used by people inside Inbound Routes and these Allowlist changes break all that.

When adding features like this you must always check off more than the “It does the one thing I want box”. You need to make sure it also doesn’t cause regression (i.e. bring back old problems) or that it doesn’t break current logic that is being used overall.

So right now, as it is…it should be rejected as a PR to be added until these other issues are resolved and more testing is done to make sure other features, when enabled or changed, are also not impacted/broken by this update.

Hi @BlazeStudios ,

Exactly what you’ve listed was my problem with the original module as well. Apart from your points, also Privacy and Superfecta are ignored for calls which match (and jump). In the original version this have been the calls which are not on the allowlist which broke everything for me (no ability to spamcheck them with Superfecta).

I could not solve this, but my switch now allows to have this “incomplete behavior” for the allowed numbers which will jump at this point. More easy to live with allowed friendly numbers not being further processed (Superfecta etc.) than for all unknowns.

So, it’s not my PR which breaks these things, they have been broken for matching/jumping callers before.

From my understanding, this module in general should “link” much later into the call flow - directly before the inbound route makes it’s final jump to the configured destination and after all parts of the inbound route are processed. This would also solve the points you’re listing. But I’m not sure if a module can influence it’s linking point in the inbound route processing. Maybe @lgaetz knows this?

The original allowlist code doesn’t jump anywhere unless there is no match. A match just returns back to normal call routing flow. So what exactly where you having a problem with on the old version? We really haven’t seen a lot of debugging/troubleshooting data.