Category: Asterisk

How to use Google Voice with FreePBX and Asterisk without using XMPP or buying new hardware

This post has been edited to include new and changed information.

In mid-July, 2018 Google Voice shut down XMPP access. The problem is that if you have been using the Google Voice module in FreePBX, it used the XMPP protocol to connect to Google Voice, and that’s what no longer works.

Various possible solutions are being offered, including buying a new VoIP device and using it as a bridge between Asterisk and Google Voice. Unfortunately, at the time of this writing such devices are made by only one manufacturer, Obihai, a company I could not possibly have a lower opinion of. I used to like and support Obihai, but they have nuked any warm and fuzzy feelings I had for them in the past, several times over. My opinion now is that if you buy a new Obihai device, then P.T. Barnum was right when he said that there’s a sucker born every minute, and when you were born you fulfilled the quota for that minute! But, this is not intended to be a rant about Obihai (you can find those all over the VoIP forums, except in Obihai’s own heavily censored forum), but rather a way to keep using Google Voice with FreePBX and Asterisk, so you don’t need to buy any new hardware.

Many FreePBX users like to “do it themselves” and it appears there are a couple of ways to keep FreePBX working with Google Voice. For now the FreePBX Google Voice module has become useless, so either of these methods may be a bit more “hands on” than you are used to. The best way is to use naf’s Asterisk patches as discussed in this thread at DSLreports (this page of Google Voice SIP Information might also be useful to some readers).  If you are a Raspberry Pi user, you could install RonR’s FreePBX for the Raspberry Pi but be sure to select Asterisk version 13-GVSIP when prompted. Or as of September 2018, it may be possible to use Pbxes.com as a gateway to Google Voice, see this thread at DSLreports for information. But not everyone is comfortable with patching Asterisk or using someone else’s gateway, so this article discusses an alternative.  I do NOT recommend this alternative – using naf’s Asterisk patches is definitely the better way to go, because calls will complete much faster, but installing it requires a level of technical expertise that some users may not possess.  I have not attempted to use Pbxes.com (don’t want to pay the 15 bucks for something I can do myself, and probably do better) so cannot speak to how well their setup works.

To cut to the chase, the basic technique can be found in one of RonR’s posts in the above-mentioned DSLReports thread. Go ahead and open that up in another tab in your browser, because I’ll be referencing it throughout this article. But, that post only provides some basic configuration information, and makes some assumptions that are not clearly stated, such as that you are using FreePBX and that you already know how to perform basic administrative tasks such as creating a SIP trunk. While the general technique shown will also work with bare Asterisk (no FreePBX) or with other Asterisk-based GUI’s, you’re pretty much on your own in making the necessary dialplan modifications, or you could try following Twinclouds’ instructions (as mentioned in his comment on this article), which use a mostly similar but slightly different technique. I should probably warn you here that this technique could potentially stop working at any time, but it does not use the XMPP protocol, so it’s not affected by the removal of XMPP support by Google Voice (and if anyone tells you differently, they’re wrong). It’s worked for years now, but when dealing with Google that doesn’t necessarily mean anything. Also, by publishing this I am explicitly NOT commenting on whether Google would approve of its use – I don’t work for Google, and I’m not a lawyer. If you suspect that using this technique may violate Google’s Terms of Service or some such thing, then please don’t use it until you consult with your own attorney. If you try anything shown in this post you are doing so of your own volition and at your own risk. I will not be responsible for any consequences that may occur. With that in mind, if you still want to try this technique, here’s what you need to do.

First, you must have a number coming into your system that is NOT a Google Voice number. This is sometimes referred to as a DID (and will be called that in this article), and if you don’t already have one, it is possible to get free DID’s from Callcentric and/or TelecomsXChange. You need to have at least one DID coming into your Asterisk server, and you need to configure it as a destination (forwarding number) in your Google Voice account. So get your DID working first, and make sure you can make incoming calls to it using its assigned number. Then go into your Google Voice account(s) and set it/them up to forward calls to the DID. If you have already set up a forwarding number at some point in the past, you may still want to log in to Google Voice and check to make sure it doesn’t need to be re-validated – if you have let it lapse into an unvalidated state, Google Voice won’t forward calls to it until you re-validate it. If you tell Google Voice that the number is a “Work” number (you may need to go into “Legacy Google Voice” to do that), it can be used as a forwarding destination for at least two Google Voice accounts, and RonR’s post shows how to use one DID with two Google Voice accounts. So once you have your DID set up, you should be able to call your Google Voice number, and it will forward the call to your DID, and then the DID will send the call on to your Asterisk server. Note: If you decide to use Callcentric, you may wish to refer to this post: How to receive incoming Callcentric calls in FreePBX without creating multiple trunks.

Assuming you have your incoming DID working and Google Voice configured to use it as a destination, and you have tested it to make sure that the forwarding to your DID works when you call your Google Voice number, the next thing to do is is make a test call using pygooglevoice. But first you should determine whether it is installed on your system. From a Linux command prompt, enter which gvoice – if it returns a path such as /usr/bin/gvoice then it is already installed. If no path is returned, then install it using the instructions in RonR’s post mentioned above. Once it is installed, from a Linux command prompt, enter gvoice – it should prompt you for your Google Voice email address and password. If it connects successfully, you will see a prompt that looks like this: gvoice>. If you see a bunch of error messages (this is not unusual on the first run), refer to this DSLReports post by Cam_, which shows some of the things you may need to do to get it working. In addition, you may also need to let less secure apps access your Google account. (EDIT: Also see this DSLReports post by AllThumbs which notes that in addition to allowing less secure apps using this link, while logged into your Google Voice account and just prior to running pygooglevoice you may also need to visit this “Allow access to your Google account” link to get it working. Immediately after you click the “Continue” button, run pygooglevoice so that Google knows which “new device or application” you are trying to allow access from. Then, log into Gmail using your Google Voice account and check the Inbox – there will probably be an email from Google asking you to confirm that it was really you that just logged in, if so, do whatever the email tells you to do to confirm it. AllThumbs’ DSLReports post implies that you may have to do this again from time to time, and that will be particularly true if you don’t respond to any email Google may send asking for confirmation that it was really you, so save notes on this process. Yes, Google’s ultra-paranoid security can be a real pain in the butt sometimes).

If you think you may have a bad or old version of pygooglevoice, prior to reinstalling remove the following files from the /usr/bin directory: asterisk-gvoice-setup, gvi, and gvoice, and also check any /user/lib/python*/site-packages directories you may have for a directory called googlevoice and/or a file that starts with “pygooglevoice” and if you find either of those, remove those as well. Otherwise you may wind up with a mixture of files from the old and new versions, and that usually won’t work (also, do not run asterisk-gvoice-setup, it’s not meant for what we’re doing here).  Note that there is a current version of pygooglevoice included in a download link in RonR’s post.

If you do get the gvoice> prompt, then enter the word call, and then it should prompt you for the outgoing number, which can be almost any valid 10 digit number in the USA or Canada. After that, it will prompt you for “Forwarding number [optional]:” but it really isn’t optional. What it is wanting here is one of your validated Google Voice destination numbers, such as your DID – NOT your Google Voice number! – and it wants it in the format +1 plus the ten digit number. If you try using just the ten digit number alone, it won’t work (at least not in my tests), it has to be in the form +1XXXXXXXXXX. Finally it will ask for the phone type; if you specified the number as a “work” number in the Google Voice interface then use 3. If you don’t remember how you specified it, try all three of the digits 1 through 3, one at a time – one of those should work. It may not actually matter if this number is correct in some cases; I’ve seen “1” work when the number had been specified as a “Work” number, for which the code should be “3”, but that’s not always the case.

If you entered everything correctly, you should not see any error messages, and in second or two a call should come in on your DID (hopefully you have created an Inbound Route, and made a nearby extension the temporary destination), and when you answer it you should hear the destination number start ringing. This part MUST work before you go any further – if you can’t get this to work then there is no point in doing any further configuration, because it won’t work either.

If it does work, you have a choice at this point. You can follow RonR’s instructions verbatim, which are probably fine if you are only dealing with one or two Google Voice accounts. But if you are dealing with a higher number of accounts, or if you just don’t like the fact that he hardcodes Parking Lot extension numbers, you should know that I have made some modifications to his method, which I have added at the bottom of this article. For now you can do it either way, but the notes that follow were written based on his original instructions, and you may want to follow them and get his method working with a Google Voice account or two first. Just be aware that because he hardcodes Parking Lot extensions, it will be impossible to place two calls on the same Google Voice account at the same time. However it may be impossible to do that anyway, if Google limits the number of simultaneous connections per account to three or fewer. Remember that with this method, there are actually two calls being placed from your account for each call you make – one to call your DID, and one to connect your call through to the called party.

So, here are some additional hints and information regarding RonR’s instructions. RonR shows two contexts, pgv-out-1 and pgv-out-2. First of all, I like to rename those to the Google Voice account names (the part of the email address before the @gmail.com) followed by -out, but if you are going to do that, you need to change those strings in all the other places where they appear in his instructions. If you have several accounts, using more meaningful context names could make it easier to know which account you are dealing with (I do this in my revisions below). And, you don’t need the second context (pgv-out-2) unless you are using the same DID as the forwarding destination for two Google Voice accounts. In the contexts themselves, you need to replace Usernamen@gmail.com and Passwordn with the actual login username and password for the account, and you must replace Callback Number with the actual 11 digit number of your DID (you do use the leading “1” here, but in this case the “+” character is added for you). The Callback Number is NOT your Google Voice number!

Also, the CALLPARK numbers must be unique in each context. You can see (and change) the allowable range of Parking Lot numbers by going into Applications | Parking. If you can’t find that selection, you may need to install the FreePBX Parking Lot module. Note that if you actually use the Parking Lot feature for something other than Google Voice, then make sure you use the highest available Parking Lot numbers in these contexts. If, probably like many users, you’re asking “What’s a Parking Lot doing in my PBX?” and have never used it and can’t imagine why you would, then you can use any of the allowable range of parking lot numbers (71 through 78 by default) in the CALLPARK settings.

In the pgv-out-common context there is a line that begins with exten => _X.,n,Park … and the line shown there is correct for the newest version of Asterisk, but the older ones used a much different syntax. For example, exten => _X.,n,Park(15000,pgv-error,s,1,rs) would be the correct equivalent in somewhat older versions. You may need to consult the Asterisk Wiki to figure out the proper syntax – in the left hand column, select your version of Asterisk’s Documentation, then Command Reference, then Dialplan Applications, and then Application_Park to see the proper syntax and the command options in your Asterisk version. By the way, the “r” option (in the “rs” string in the example) controls whether you hear a fake ringing tone while waiting for the callback from Google Voice – if you omit that “r”, you’ll hear the Music on Hold specified in the Parking Lot configuration for that (hopefully brief) period. I mention this only because some people may prefer not to hear a ringing tone until the called phone has actually started ringing.

Finally, the pgv-in-common context is another I like to rename, replacing pgv with something more meaningful (again you could use the Google Voice username, but that might not be appropriate if your DID is shared by two Google Voice accounts – I use the ten digit DID number in my revisions below). But again, if you change that string then you need to make the same change everywhere it appears in RonR’s instructions. In the first lines of the context, the “Google Voice Number n” strings must be replaced by the actual 10-digit Google Voice numbers, and if there’s only one Google Voice account associated with the DID then you can comment out (or remove) the line with “Google Voice Number 2” in it, and also the line with the (cb2) label. Also note that the ParkedCall(nn) statements must contain the correct parking lot numbers as set in the corresponding -out contexts. So each Parking Lot number should appear twice (and only twice), once in a -out context (or pgv-out-n if you use RonR’s naming system), and then again in a line with the (cbn) label in a -in-common context.

In the middle of the context there is a line, “exten => s,n,Goto(from-trunk,Callback Number*,1)” – here you replace “Callback Number” with the DID number that Google Voice is sending your incoming calls to, but in this case you’ll probably want it to be in 10-digit format (no leading + or 1). Do leave the * character, it’s not a typo. The purpose of this line is to handle calls that come in where someone has called your Google Voice number or your Callback Number (DID) directly, in other words when someone is calling you and the call is not a callback from Google Voice as a result of you placing an outgoing call. This line is why you’ll need a separate -in-common context for each of your DID’s used with Google Voice.

If you have multiple Google Voice accounts, then the general rule is that there has to be one -out (or pgv-out-n) context, and an associated Custom Trunk and Outbound Route for each Google Voice account. And, there must be one pgv-in-common context (if there is more than one context, each must have a unique name) for each DID that is used as a destination number by one of your Google Voice accounts, along with an associated Custom Destination. As for Inbound Routes, you’ll need two of those for each DID used by Google Voice, but one of them will have the * character appended to the phone number, as shown in RonR’s instructions. When you create the Inbound Routes, if you want to enable Caller ID Superfecta or any other type of local Caller ID lookup, do it only in the route with the * character at the end of the number. The use of any kind of Caller ID lookup on the non-starred number is pointless, and will slow down the connection time for your outgoing calls.

I also like to end all my contexts with a line of the form
exten => h,1,Macro(hangupcall,)
So just on the off chance the caller hangs up while in that part of the context, the hangup is correctly handled. But that is up to you.

It bothers me just a little that there appears to be no good way to cancel the call if the caller hangs up before the callback is received, but if that happens it appears that when the call comes in from Google the PBX will play a very short message about the parking lot number being invalid and then disconnect. So just be aware that if you call a number and then after dialing the last digit quickly change your mind and hang up, the called party’s phone may still ring once.

Up near the top of RonR’s post he shows how to set up the Outbound Routes (“Connectivity -> Outbound Routes -> Add Route”) and shows a Dial Pattern of NXXNXXXXXX which is correct for 10-digit dialing, but obviously you may need to add additional patterns if your system supports 7 or 11 digit dialing. You can limit the use of any particular Outbound Route to one or more specific extensions using Asterisk’s “ex-girlfriend logic” if you like.

Hopefully all that should get you going, but there is a caveat here. If Google changes their authentication protocols, this method could stop working until a pygooglevoice maintainer comes up with a patch. It’s happened before, though rarely, and it could happen again. If it does, incoming calls would still work, but outgoing calls would fail until the pygooglevoice code is modified to account for the change.

One other possible drawback to this method is that because pygooglevoice is considered a “less secure” app, Google may nag you with a “Security Alert” email every single time you place a call! One would hope that after you’ve confirmed that it was really you a few times, the emails would at some point stop, but if they don’t there is a way to turn them off – however in that case you won’t be notified if someone else really does try to hack your account. This is the method, according to Google:

We strongly advise leaving alerts on so you can hear about suspicious activity on your account. If you still want to disable alerts, follow the steps below.

Note: It takes about a week for alerts to get turned off. This is because Gmail wants to confirm it’s you that’s turning them off, and not someone else who might have access to your account.

  1. On your computer, open Gmail.
  2. In the bottom right, click Details.
  3. At the bottom of the page next to “Alert preference,” click Change.
  4. Select Never show an alert for unusual activity.

I have discovered that you don’t see the “Details” link unless you switch to the “basic HTML” view.



Here is my revision of RonR’s method – this more gracefully deals with a larger number of Google Voice accounts because it assigns Parking Lot extensions starting with the highest available and working its way down until it finds one not in use. It’s set to start with extension 78 and work its way down to 71. If you think there might ever be more than eight simultaneous outgoing Google Voice calls then you may need to extend the range of available Parking Lot extensions, but I think this will work for most people. (EDIT June 7, 2018: If you don’t have the FreePBX Parking Lot module installed or just don’t care to use the Parking Lot for this purpose, I have added instructions to use the alternative “Bridge” method at the end of this article, so you may want to read to the end of the article before you begin making configuration changes. I personally recommend the “Bridge” method over the use of the Parking Lot.) The instructions for installing PyGoogleVoice are the same (so refer to his post for that), but here’s how I configured it – note that values that you must change are in bold type:


Connectivity -> Trunks -> Add Custom Trunk

Trunk Name : username
Custom Dial String : LOCAL/$OUTNUM$@custom-username-out

Trunk Name : user2name
Custom Dial String : LOCAL/$OUTNUM$@custom-user2name-out

… and so on …

To help you keep the accounts straight, the user names should be the the same as the part of the Google Voice login names before the @ symbol. So if the login name is foo@gmail.com, the username would be just foo. This will be the case wherever you see “username” or “user2name” in bold.


Connectivity -> Outbound Routes -> Add Route

Route Name : username
Dial Pattern : see discussion below
Trunk Seq : username

Route Name : user2name
Dial Pattern : see discussion below
Trunk Seq : user2name

… and so on …

RonR only showed the dial pattern NXXNXXXXXX but that is only valid if your system only allows 10 digit dialing, and it doesn’t restrict a route to use by a particular extension. Possible patterns you might want to use include, but are not limited to:

NXXNXXXXXX/eee (where eee is a specific extension number that can use this route, and you can use patterns here such as 10X for all extensions in the range 100 to 109, or multiple instances of this line if needed for non-contiguous extensions).
1|NXXNXXXXXX/eee (same as above except allows dialing calls with a leading “1”, in case you allow 11 digit dialing)
aaa+NXXXXXX/eee (same as above except allows 7 digit calls to a particular area code, in case you allow 7 digit dialing – replace aaa with the area code)

The basic point here is that Google Voice expects to receive the called number as 10 digits, with no leading 1.


Admin -> Custom Destinations -> Add Custom Destination

Custom Destination : custom-NXXNXXXXXX-in,s,1
Description : Incoming calls NXXNXXXXXX

You need one Custom Destination for each DID you have coming into your system that is used by Google Voice. Replace “NXXNXXXXXX” with the 10 digit DID number, NOT your Google Voice number. Again, this change is just for your convenience in keeping everything straight.


Connectivity -> Inbound Route -> Callback Number
DID Number : NXXNXXXXXX
Destination : Custom Destination -> Incoming calls NXXNXXXXXX

Here you are making an Inbound Route for your DID, and sending it to the Custom Destination that contains the phone number of the DID, that was created in the previous step. So again, you need one of these Inbound Routes for each DID you have coming into your system that is used by Google Voice. In this case the Description can be anything you find meaningful. Leave ALL the other settings at the default – in particular do not enable “Detect Faxes” or “CID Superfecta”, or anything that might slow processing of the incoming call. If you need any of those features in incoming calls, you can enable them in the next section:


Connectivity -> Inbound Route -> Add Incoming Route

DID Number : NXXNXXXXXX*
Destination : Normal destination for this number

Here the DID number is the same as in the previous step except there is an added * character at the end. This is the Inbound Route for your DID that is used when it is NOT a Google Voice callback that arrives because you are making an outgoing call. In other words, if someone other than Google Voice calls your Google Voice number, or calls the DID that your Google Voice number is forwarded to directly, the call will wind up here, so normally you’d want the destination to be an Extension, Ring Group, IVR, or whatever. Since by the time the call gets here you know it’s NOT a Google Voice callback, you can enable features like Detect Faxes or CID Superfecta if you like. Again, the Description can be anything you find meaningful.


Additions to /etc/asterisk/extensions_custom.conf – first, the common contexts used by all accounts – these two contexts are only added once, no matter how many Google Voice accounts or DID’s you have:

[custom-gv-out-common]
exten => _X.,1,Set(PARKINGEXTEN=79)
exten => _X.,n(parkloop),Set(PARKINGEXTEN=$[${PARKINGEXTEN} - 1])
exten => _X.,n,GotoIf($["${EXTENSION_STATE(${PARKINGEXTEN}@park-hints)}" != "NOT_INUSE"]?parkloop)
exten => _X.,n,GotoIf($["${PARKINGEXTEN}" < "71"]?custom-gv-error,s,1)
exten => _X.,n,Set(DB(gv_dialout_${CUT(ACCTUSER,@,1)}/parkslot)=${PARKINGEXTEN})
exten => _X.,n,System(gvoice -b -e ${ACCTUSER} -p ${ACCTPASS} call ${EXTEN} +${RINGBACK} 1 &)
exten => _X.,n,Park(default,t(15)c(custom-gv-error,s,1)rs)
;exten => _X.,n,Park(15000,custom-gv-error,s,1,rs)
exten => h,1,Macro(hangupcall,)

This is the custom-gv-out-common context as used in the “Parking Lot” method.  To use the alternative “Bridge” method, scroll down to find another version of this context, then come back here and add the custom-gv-error and custom-username-out contexts shown below, and continue from there.

In the first line, 79 is one greater than the highest numbered Parking Lot extension (by default the Parking Lot uses parking extensions 71-78). You may need to change that if you increase the number of Parking Lot extensions. Also, I may be wrong but I believe that for the “${EXTENSION_STATE(${PARKINGEXTEN}@park-hints)}” function to work correctly, the “BLF Capabilities” setting in the FreePBX Parking module must be set to Enabled. While you’re in the Parking configuration, you may wish to set the “Pickup Courtesy Tone” option to None if you don’t want the beep tone when the callback arrives.

If you have an older version of Asterisk you might need to switch which of the “Park” lines is commented out – the one that is uncommented now is for newer versions of Asterisk. Also in the Park lines, the “r” in the “rs” signifies that you want fake ringing generated while waiting for the callback – if you omit it, it will play Music on Hold as specified in the “Parked Music Class” option in the FreePBX Parking module.

[custom-gv-error]
exten => s,1,Playback(silence/1&cannot-complete-as-dialed)
exten => s,n,Wait(1)
exten => s,n,Playtones(congestion)
exten => s,n,Wait(10)
exten => s,n,StopPlaytones
exten => s,n,Hangup()
exten => h,1,Macro(hangupcall,)

The above is straight from RonR’s original instructions except for the hangup handler at the end; other than that only the context name is changed. When everything is working as it should, this context should rarely be used.


More additions to /etc/asterisk/extensions_custom.conf – You must create these contexts for each user account or DID, as explained below:

[custom-username-out]
exten => _X.,1,Set(ACCTUSER=username@gmail.com)
exten => _X.,n,Set(ACCTPASS=password)
exten => _X.,n,Set(RINGBACK=1NXXNXXXXXX)
exten => _X.,n,Goto(custom-gv-out-common,${EXTEN},1)
exten => h,1,Macro(hangupcall,)

You need one of the above for each Google Voice account, and you must change the username value in both places (don’t skip the context name) and the password value, and set the RINGBACK setting to the 11-digit DID number associated with this account (NOT your Google Voice number). “username” is just the part of the Google Voice login name before the @ symbol, same as in the Custom Trunks. If you are one of the very few people who has a Google Voice account where the login name doesn’t end in @gmail.com, then change that in the ACCTUSER setting as well.

[custom-NXXNXXXXXX-in]
exten => s,1,GotoIf($["${CALLERID(number)}" = "Google Voice Number"]?cb1)
;exten => s,n,GotoIf($["${CALLERID(number)}" = "Google Voice Number 2"]?cb2);
exten => s,n,Goto(from-trunk,NXXNXXXXXX*,1)
exten => s,n(cb1),ParkedCall(default,${DB_DELETE(gv_dialout_username/parkslot)})
;exten => s,n(cb2),ParkedCall(default,${DB_DELETE(gv_dialout_user2name/parkslot)})
exten => h,1,Macro(hangupcall,)

This is the custom-NXXNXXXXXX-in context as used in the “Parking Lot” method.  To use the alternative “Bridge” method, scroll down to find another version of this context  If using the “Bridge” method, be sure to also add the custom-gv-cancel context .

You need one of the above for each of your DID’s that Google Voice sends calls to. You can have one or two Google Voice accounts coming to a DID if you have specified the DID as a “Work” phone in both accounts. If you have two, then uncomment the two commented-out lines. As usual, replace both instances of NXXNXXXXXX with the DID number (don’t skip the context name, and don’t lose the * character at the end of the number in the Goto line). “Google Voice Number” and (optionally) “Google Voice Number 2” should be replaced by the Google Voice numbers associated with your accounts in 10-digit format (no leading +1 here). “username” and “user2name” are once again just the part of the Google Voice login names before the @ symbol. In the last two lines, in the ParkedCall options, you may need to omit the string “default,” if you are using an older version of Asterisk, because at some point prior to the current version the order of the items was flipped. In current versions the Parking Lot name is specified first, followed by the Parking Lot extension (which in this case is retrieved from a temporary database location), but in older versions the Parking Lot extension was given first, and then optionally the Parking Lot name.


(ADDED June 7, 2018): USING THE BRIDGE METHOD INSTEAD OF THE PARKING LOT METHOD

There is an alternative to using the Asterisk Parking Lot, that instead uses Asterisk’s Bridge application. The advantage of using Bridge is that you don’t have to deal with the Parking Lot at all (you don’t even need to have the FreePBX Parking Lot module installed), and therefore the number of simultaneous calls is not limited to the number of available Parking Lot slots. Also you don’t have to worry about the changes in the “Park” application syntax between Asterisk versions. And, this method is better about cleaning up after itself, by removing database entries it has created after they are no longer needed.  The disadvantage is that the custom dialplan is slightly more complex. Use the instructions for setting up the Parking Lot version above, with these exceptions:

Replace the custom-gv-out-common context with this:

[custom-gv-out-common]
exten => _X.,1,System(gvoice -b -e ${ACCTUSER} -p ${ACCTPASS} call ${EXTEN} +${RINGBACK} 1 &)
exten => _X.,n,Set(DB(gv_dialout_${CUT(ACCTUSER,@,1)}/channel)=${CHANNEL})
exten => _X.,n,Wait(20)
; The following Noop lines are NOT optional, do not delete them
exten => _X.,n,Noop(Never received callback from Google Voice on channel ${DB_DELETE(gv_dialout_${CUT(ACCTUSER,@,1)}/channel)} – exiting)
exten => _X.,n,Goto(custom-gv-error,s,1)
exten => h,1,Noop(User hung up while waiting for callback from Google Voice on channel ${DB_DELETE(gv_dialout_${CUT(ACCTUSER,@,1)}/channel)})
exten => h,n,Macro(hangupcall,)

Do NOT remove the Noop lines, they contain the function that deletes the unused database item if for some reason the returned call from Google is never received, or if the user hangs up before the callback is received. If you want your callers to hear Music on Hold rather than silence while waiting for the callback, replace

exten => _X.,n,Wait(20)

with

exten => _X.,n,Answer
exten => _X.,n,MusicOnHold(default,20)

You do have to “answer” the call or the music will not be heard. You can optionally replace “default” with any other valid Music on Hold context you have created.

Replace each custom-NXXNXXXXXX-in context with this:

[custom-NXXNXXXXXX-in]
exten => s,1,GotoIf($["${CALLERID(number)}" = "Google Voice Number"]?cb1)
;exten => s,n,GotoIf($["${CALLERID(number)}" = "Google Voice Number 2"]?cb2);
exten => s,n,Goto(from-trunk,NXXNXXXXXX*,1)
exten => s,n(cb1),NoCDR()
exten => s,n,GotoIf($[${ISNULL(${DB(gv_dialout_username/channel)})}]?custom-gv-cancel,s,1)
exten => s,n,Bridge(${DB_DELETE(gv_dialout_username/channel)})
exten => s,n,Hangup()
;exten => s,n(cb2),NoCDR()
;exten => s,n,GotoIf($[${ISNULL(${DB(gv_dialout_user2name/channel)})}]?custom-gv-cancel,s,1)
;exten => s,n,Bridge(${DB_DELETE(gv_dialout_user2name/channel)})
;exten => s,n,Hangup()
exten => h,1,Macro(hangupcall,)

As in the Parking Lot method, you need one of the above for each of your DID’s that Google Voice sends calls to. You can have one or two Google Voice accounts coming to a DID if you have specified the DID as a “Work” phone in both accounts. If you have two, then uncomment the five commented-out lines. As usual, replace both instances of NXXNXXXXXX with the DID number (don’t skip the context name, and don’t lose the * character at the end of the number in the Goto line). “Google Voice Number” and (optionally) “Google Voice Number 2” should be replaced by the Google Voice numbers associated with your accounts in 10-digit format (no leading +1 here). “username” and (optionally) “user2name” are once again just the part of the Google Voice login names before the @ symbol – make sure to change them in both lines where they appear.

Add the following context:

[custom-gv-cancel]
exten => s,1,Answer
exten => s,n,Wait(1)
exten => s,n,Hangup()

The only real drawback of the “Bridge” method is that if a user changes their mind about placing a call, and hangs up before the callback is received from Google Voice, Asterisk doesn’t know what to do with the callback unless you explicitly tell it what to do. So this answers the call and then hangs up, after a one second delay. In previous incarnations of this method there was a “cancel” option in pygooglevoice that could be used to cancel a call. The “cancel” function still seems to exist in pygooglevoice, but in testing it doesn’t seem to actually do anything, at least not for several seconds. I watched as Asterisk repeatedly sent the pygooglevoice cancel, only to see the call come right back in, and that loop lasted several seconds! So, it appears that the only reliable way to cancel the callback is to answer it and then hang up. If you want to experiment with the pygooglevoice cancel option, the syntax is simply:

exten => s,n,System(gvoice -b -e username@gmail.com -p password cancel &)

But if you can get it to work, you are having better luck than I did.

Don’t forget that even if you are using the “Bridge” method, you still need to add the custom-gv-error and custom-username-out contexts, as shown in the “Parking Lot” method instructions.


That’s pretty much it. If you spot any errors, including any typos I haven’t yet caught, or know of a better way to do this, please leave a comment. This article may be updated if new information is received.

Why your game console or home VoIP PBX won’t work with OPNsense or pfSense, and how to fix it

If you have been using a standard router and decide to upgrade to OPNsense or pfSense (I personally recommend OPNsense, solely because of the heavy-handed moderation in the pfSense user forum, where a user can apparently get banned for life for even a small inadvertent infraction), you may find that making a game console or a VoIP PBX work isn’t as simple as just forwarding some ports. The other thing you have to do is shown in this video:

Although the video specifically mentions the PS4 and XBOX, the advice shown is equally valid for other types of game consoles and for home PBX servers. Note the section starting at 3:20 in the video, where the “Static Port” checkbox is checked – this is the key to making it work!

The OPNsense user interface will look a bit different than the one in pfSense but the principle is the same; you still need to make sure the “Static Port” checkbox is checked. And in either case, you may still need to do port forwarding, the same as you did on your previous router, but generally speaking port forwarding alone will not work until the additional configuration shown in the video is applied. Here’s an example of setting up a static port rule in OPNsense (note that the source address field refers to a previously-set alias for the IP address of the Asterisk PBX):

VoIP PBX users, there is one other thing you may need to do, at least in OPNsense, particularly if you find that you have a non-local extension that is unable to connect to your PBX. If you are using a Dynamic DNS address, make sure you go to System: Settings: Administration and put that dynamic DNS address in the “Alternate Hostnames” field.

A Bash script to rewrite the "static" IP address in the FreePBX Asterisk SIP Settings when it is changed by your ISP

 

Important
This is a revision of the post, A Perl script to rewrite the "static" IP address in the FreePBX Asterisk SIP Settings when it is changed by your ISP, but modified to use a Bash script. Much of the explanatory text is directly copied, or in some cases heavily modified, from the earlier article, which in turn was taken (with permission) from the old Michigan Telephone blog after it went defunct. THIS SCRIPT IS STILL CONSIDERED EXPERIMENTAL – USE AT YOUR OWN RISK!!!

This post is going to be a bit long because I first need to explain the “why” behind this script, then the script itself and how to test it after installation. Please note that the screenshots below are from earlier versions of FreePBX, and you probably will be using a more modern GUI interface, but the settings shown should still appear.

If you are using a recent version of Asterisk and FreePBX you may be using the Asterisk SIP Settings module (under the “Settings” tab) to automatically set various SIP parameters.  This module is a great help to those who don’t know what they are doing, but there is a trap for the unwary (and in this case it’s NOT the fault of FreePBX – it’s a longstanding bug in Asterisk that’s the problem).

At the top of the Asterisk SIP Settings configuration page, in the NAT Settings section, there are two options that can be set.  The first is NAT and there are four possible choices:

  • yes = Always ignore info and assume NAT
  • no = Use NAT mode only according to RFC3581
  • never = Never attempt NAT mode or RFC3581
  • route = Assume NAT, don’t send rport

In theory, if you have a fixed IP address AND your Asterisk server is not behind an external router that does NAT translation, you should use “no” (and most of the rest of this article will not be relevant to you).  This article is intended more for home and SOHO users that both have their Asterisk server behind a hardware router of some kind, and that get their broadband service from a company that occasionally changes their IP address without warning.  For such users, the preferred setting is “yes”.  I’m not enough of a networking guru to tell you under what circumstances one of the other settings might be appropriate (if you understand this stuff, feel free to leave a comment and enlighten us).

FreePBX: Asterisk SIP Settings page, Chan SIP Settings tab, NAT Settings (Public IP Option)

It’s the next set of settings that can get us into trouble.  This is the IP Configuration and there are three possible choices:

  • Public IP
  • Static IP
  • Dynamic IP

If your IP address never changes AND you aren’t behind a hardware firewall then you can usually just set this to “Public IP” and let it go at that.  You will not be asked to fill in any other values.  But most users that are not in that situation will pick one of the other two choices, and this is where the problem arises.  Conventional wisdom has it that if your ISP ever changes your IP address without advance warning (which is the case for most cable broadband and DSL users), you should use the Dynamic IP setting.  In this case there is an auto-configure button that will fill out the fields for you, although you may need to fill in the Dynamic Host field yourself.  This is the “External FQDN as seen on the WAN side of the router and updated dynamically, e.g. mydomain.dyndns.com” (as explained if you mouse over the words “Dynamic Host”).  You can use a DynDNS address (or an address from a similar service) or an address you have purchased.  But the problem is that for some users, THIS METHOD SIMPLY DOES NOT WORK.

FreePBX: Asterisk SIP Settings page, Chan SIP Settings tab, NAT Settings (Dynamic IP Option)

If you try to use Dynamic IP and it won’t work for you, what happens is you will get all sorts of weird errors.  You may get one way audio, some calls may disconnect for no apparent reason after about five seconds, and you will see other weird errors in your CLI.  If you change this setting to “Static IP” and click the auto-configure button and then submit the changes, the problems magically go away – UNTIL your ISP changes your IP address, at which point you suddenly have no connectivity to the outside world.  If you ask for help, everybody and their brother will tell you to use the Dynamic IP setting, and the minute you try that you’ll get all the weird errors again.

FreePBX: Asterisk SIP Settings page, Chan SIP Settings tab, NAT Settings (Static IP Option)
FreePBX: Asterisk SIP Settings page, General SIP Settings tab, NAT Settings, showing static external IP address

So if that’s your situation, you need set a Static IP address as shown in the above two screenshots (this used to be all on one page, but now it’s under two separate tabs in the new interface), and you need this Bash script.  Coupled with a cron job, it goes out and checks your IP address every five minutes and if it notices it has changed, it changes it in the MySQL database (same as if you entered it into the External IP text box on the Asterisk SIP Settings configuration page) and then reloads Asterisk.  Therefore, you can use the Static IP method and it hopefully it will work reliably.  If and when your IP address changes, you should only be down for about five to ten minutes at most (hopefully your broadband provider usually does such changes in the middle of the night!).

A word to the wise, do NOT enter anything into the “Override External IP” field under the “Chan SIP Settings” tab unless you are certain that you know what you are doing, or you may have “no audio” issues. You should only put your external IP address in the “External Address” field under the “General SIP Settings” tab.

Prerequisites:

You will need to use a Dynamic DNS service to keep track of your IP address if you want external extensions to be able to find your server on the Internet.  It’s not required for this script to work, though, so I won’t say any more about that except to note that if you use a recent vintage hardware router, it probably has DDNS support built in.

The Script:

Note that WordPress MAY change apostrophes and quotes into “prettified” versions, and if it does that will totally mess up Bash.  I’m going to put this in a preformatted text block so hopefully WordPress won’t change anything (it doesn’t appear that it has), but you never know.  Also, don’t confuse backticks (`) with apostrophes (‘) – backticks are used around the word `key` in the script below.

This script was written for use with FreePBX 14; there are some minor changes that need to be made for earlier versions (for example, you may need to use kvstore in place of kvstore_Sipsettings where it appears in the script). If you are running an earlier version you can either use the Perl version of this script from A Perl script to rewrite the "static" IP address in the FreePBX Asterisk SIP Settings when it is changed by your ISP, or at least see that article to see an explanation of the changes.

There are long lines in this script that overflow the allotted display area, so you will probably want to copy and paste the entire script (except for the final three commented out lines if you don’t need it to update a Dynamic DNS; see below) into a text editor such as nano. Make sure you do copy the last line, which contains only “fi”, or it won’t work.

#!/bin/bash
# This program gets the current IP address (as assigned by the ISP) from
# OpenDNS and modifies the FreePBX Asterisk SIP settings if the external IP
# address has changed. Invoke it as cron job that runs every 5 minutes.
# THIS SCRIPT IS STILL CONSIDERED EXPERIMENTAL - USE AT YOUR OWN RISK!!!
user="user"
pass="pw"
check=$(dig +short myip.opendns.com @resolver1.opendns.com) || { echo "Problem getting current IP address"; exit 1; }
if [[ ! $check =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
  echo "Invalid IP address"; exit 1;
fi
readip=$(mysql asterisk -u $user -p$pass -se 'SELECT val FROM kvstore_Sipsettings where `key` = "externip"') || { echo "Can't read externip from MySQL asterisk database"; exit 1; }
if [ "$check" != "$readip" ]; then
# IP address has changed
# Send email
# echo "This is an automated message - please do not reply. It appears that our external IP address has been changed to $check" | mail -s "External IP address may have been changed" you@someaddress.com
# Save new IP address to Asterisk SIP settings
mysql_response=$(mysql asterisk -u $user -p$pass -se 'update kvstore_Sipsettings set val='\"$check\"' where `key`="externip" ')
# Reload Asterisk
/var/lib/asterisk/bin/module_admin reload
# Update freedns
# date > /tmp/freedns_uodate.log
# /bin/sleep 21 ; /usr/bin/wget --no-check-certificate -O - https://freedns.afraid.org/dynamic/update.php?uniqueupdatestring== >> /tmp/freedns_update.log 2>&1 &
fi

NOTES on the above script, including THINGS YOU MUST CHANGE:

Note the two bolded variables user and pw. These must be changed to the correct values for YOUR system. You will usually find these in one of two places. You can look in /etc/amportal.conf and look for the variables AMPDBUSER and AMPDBPASS — these will usually be near the bottom of the file in newer installs, in a “— CATEGORY: Bootstrapped or Legacy Settings —” section, but they can be anywhere in the file.

Another place they may be found is in the file /etc/freepbx.conf — in that file, look for lines similar to:

$amp_conf[‘AMPDBUSER’] = ‘freepbxuser’;
$amp_conf[‘AMPDBPASS’] = ‘password’;

Those will give you the values to insert into the user and pw variables in the script. YOU MUST INSERT THE CORRECT VALUES OR THE SCRIPT WILL NOT WORK! By the way, if you have both of the above-mentioned files, make sure that the AMPDBUSER and AMPDBPASS variables are set to the same respective values in both files, otherwise your CDR Reports page may not work.

If you want an e-mail notification when your IP address has changed (which is recommended), uncomment the next line under “# Send email” and modify the email address appropriately (make sure you use one or more valid e-mail addresses; you use a comma to separate addresses if you use more than one). Note this will only work if your system is already configured to send outgoing email.

You can also use this script to update a Dynamic DNS; if you use freedns.afraid.org as your Dynamic DNS then you could uncomment the two lines under “# Update freedns” and change the update URL to the unique one for your account. Don’t uncomment those lines unless and until you have the correct update URL for YOUR freedns account!. If you don’t want this script to update a Dymanic DNS account (as might be the case if you have your router set to perform this function) then you can just omit the final three commented out lines of the script – make sure you DO include the “fi” at the end of the script, though!

Note that in two places in the script (the lines that access MySQL) the word `key` appears within backtick quotes. If you leave out the backticks, or change them to something else such as apostrophes, IT WILL NOT WORK. Backticks and apostrophes are NOT the same character!

Save your script to either the /root directory or the /var/lib/asterisk/agi-bin directory, or to another location of your choosing. I named it checkip.sh. You must make the script executable, for example:

chmod u+rx /var/lib/asterisk/agi-bin/checkip.sh

Of course you will specify the correct filename and directory. Now it’s time to test the script. From the Linux command prompt, navigate to the directory where you stored the script:

cd /var/lib/asterisk/agi-bin

Now run the script from the command prompt:

./checkip.sh

Hopefully you won’t see any error messages. Remember it’s going out to do a query to get your external IP address, so don’t get concerned if it takes a second or two. If you had an incorrect address stored in your FreePBX Asterisk SIP Settings configuration, it will take longer because it will reload the FreePBX configuration. The script has a check to make sure it only stores a real IP address (and not something invalid like an error message) in the database, so if it appears to not be working, make sure the underlying call to the dig command is returning a valid IP address. By the way, that IP address check is rather rudimentary, and really only checks that the address only contains four sets of numbers separated by three dots, so if the dig command were to somehow return a totally bogus, but valid looking IP address, it might not get caught, however that’s highly unlikely to happen. That said, if you know of a better way to validate an IP address (or for that matter, see a better way to do anything in this script), please leave a comment!

If you do get an error, check that you copied the entire script correctly (including the ending “fi” statement), and that you made all the necessary changes as indicated above. Also check to make sure that you made the script executable.

Setting up a cron job

Once it runs without errors, you will want to create a cron job so it runs automatically every five minutes. Do NOT run it more often than that, or the lookup service may ban your IP address, and you don’t want that to happen, and besides, it’s not polite to hog the resources of someone else’s server! And if you are running it on multiple servers at the same IP address, then adjust the polling speed so that the total polling from all servers doesn’t exceed once every five minutes. An occasional additional test is probably not an issue, but if you try to poll every minute you just might get banned!

The usual way to add a cron job is to run this command:

crontab -e

(If you’re not currently running as root use sudo crontab -e instead)

This will open a text editor showing your current cron jobs. Just add a new line to the bottom of the file with your new cron job. To run the script every five minutes, you could use something like this:

*/5 * * * * /var/lib/asterisk/agi-bin/checkip.sh

Or to be more specific as to when the script runs (this will run it exactly on the hour, at five minutes after the hour, at ten minutes after the hour, and so on):

0,5,10,15,20,25,30,35,40,45,50,55 * * * * /var/lib/asterisk/agi-bin/checkip.pl

Just save the changed file when you are finished. The alternate method is to use Webmin’s System | Scheduled Cron Jobs module to set up your cron job.

Final testing:

The easiest way to test to make sure this is all working is to wait until a time that there are no active calls on the system, then go to the Asterisk SIP Settings configuration page and change the External IP address to something invalid (just change the last digit of the current address and Submit Changes, then do the usual configuration reload). On the next five minute interval, the script should detect that the external IP address doesn’t match the one stored in the database, and it will write the correct value to the database and reload the FreePBX configuration. If you watch the Asterisk CLI during this time, you should actually see the reload take place. After that, if you go back to the Asterisk SIP Settings configuration page, the correct IP address should be there. To be extra safe, you should also view the contents of the file /etc/asterisk/sip_general_additional.conf and make sure that the externip= line shows the correct IP address.

Now you don’t have to worry about frantic calls from users at inopportune times because your ISP changed your IP address and none of the phones are working, and you also won’t have any of the problems associated with the Dynamic IP method!

NOTE: Again, this script should be considered experimental, and as usual, there are no warranties — we’re experimenters here, and sometimes we don’t catch all the bugs, especially on the first go around! However, I would assume that anyone who is running a “professional” installation would pay their ISP for a true static IP address (one that never changes), and therefore wouldn’t need this type of script.

OAuth 2.0 Support for Asterisk 13, so XMPP connections to Google Voice can be made using the more secure oAuth authentication

If you are running Asterisk 13 (or are ready to upgrade to Asterisk 13) and are using it to connect to one or more Google Voice accounts, you can now use oAuth authentication instead of the problematic username/password, without resorting to the use of a pre-built distribution that may contain features you don’t need and don’t want. The details are here:

OAuth 2.0 Support for Asterisk 13

Also, if you have a Raspberry Pi and would like to make a clean build of Asterisk and FreePBX, the same author (RonR) has provided instructions here. Just be sure to select Asterisk 13 when installing if you want to use the oAuth 2.0 support:

FreePBX for the Raspberry Pi

Or, if you’re sick of FreePBX and are ready to try a new interface to Asterisk, he has you covered there as well:

XiVO PBX for the Raspberry Pi

All of the above links are to threads at DSLReports. Note that the install scripts in the last two links can take some time to run, especially on an older model Raspberry Pi where they could take a few hours to complete (I believe you must have a Raspberry Pi 2 at a minimum to use the XiVO build). But when you are through, you’ll have a nice clean install, without the extraneous and mostly non-useful stuff found in a certain pre-built image.

How to hack the FreePBX blacklist for better call blocking capability, take 2 – adding TrueCNAM scoring

This article is mostly a repeat of the article How to hack the FreePBX blacklist for better call blocking capability, the only difference being that this article adds the ability to use TrueCNAM to help determine if an incoming call is from a telemarketer or robo-caller. It’s not foolproof, of course, and some spam calls may still slip through, but this will help you deal with the majority of them. BE AWARE THAT THERE MAY BE FALSE POSITIVES, where numbers that are NOT associated with telemarketers or spammers nevertheless show up with a high score. This is probably a rare occurrence, but not totally outside the realm of possibility. Therefore:

BY USING THIS METHOD YOU AGREE THAT IMPORTANT CALLS COULD BE BLOCKED. YOU ALONE ARE RESPONSIBLE FOR DETERMINING WHICH CALLS ARE BLOCKED. WE ASSUME NO RESPONSIBILITY IF YOU MISS AN IMPORTANT CALL DUE TO USE OF THIS METHOD. IF YOU DO NOT AGREE WITH THIS, DO NOT USE ANY OF THE INFORMATION IN THIS ARTICLE!!!

You will need to have an account with TrueCNAM, so go here to create one. If you are just a home user the free plan should be sufficient, particularly if you add the numbers of your most frequent callers to the Asterisk phonebook so that they are not sent to TrueCNAM for scoring (in effect the Asterisk Phonebook serves as a “whitelist” in this setup). The only “price” for this service is that you will have to submit one of your phone numbers and provide a Caller ID name to associate with it. They will call you to verify it’s your number, so make sure you can answer the verification call while you create the account.

You will also need an API Key and Password, so after you have created the account go to the API Keys page and click the “Add API Key” button to generate an API Key and Password. Keep this page open during the next steps because you will need to plug these into the script below.

Next, on your FreePBX server create a file named /var/lib/asterisk/agi-bin/truecnam.agi, and change the ownership and permissions so that Asterisk can use it (you will need to be root to do this, or use sudo in front of each of the following commands):

touch /var/lib/asterisk/agi-bin/truecnam.agi
chown asterisk:asterisk /var/lib/asterisk/agi-bin/truecnam.agi
chmod 754 /var/lib/asterisk/agi-bin/truecnam.agi

Next use a text editor such as nano to open the file:

nano /var/lib/asterisk/agi-bin/truecnam.agi

Paste in the following lines, changing the API Key and Password values to the ones shown on the API Keys page:

#!/bin/bash
declare -a array
while read -e ARG && [ "$ARG" ] ; do
        array=(` echo $ARG | sed -e 's/://'`)
        export ${array[0]}=${array[1]}
done

APIKEY="APIKey"
APIPASS="APIPassword"
RESULT=""
SPAMSCORE=0
RESULT=$(curl -s -k -m 2 --connect-timeout 2 "https://api.truecnam.net/api/v1?username=$APIKEY&password=$APIPASS&resp_type=extended&resp_format=csv&calling_number=$agi_callerid&call_party=terminating")
SPAMSCORE=`echo $RESULT | cut -d , -f 9`

if [[ $SPAMSCORE == "" ]]
then
  SPAMSCORE=0
fi

echo "SET VARIABLE SPAMSCORE ${SPAMSCORE}"

(The above script was modified from scripts posted in this thread at DSLReports)

In case you missed it above, THIS SCRIPT WILL NOT WORK UNLESS YOU PASTE IN YOUR API KEY AND PASSWORD IN THE APPROPRIATE LOCATIONS.

What follows next is the original article How to hack the FreePBX blacklist for better call blocking capability, but with the modifications to use the above script:

Have you ever wished that you could blacklist calls in FreePBX using criteria other than just the exact phone number? It’s quite possible, and here’s an explanation of how it can be accomplished.

First, using a text editor such as nano, go into the file /etc/asterisk/extensions_additional.conf and find the context headed [app-blacklist-check]. It will probably look like this:

[app-blacklist-check] include => app-blacklist-check-custom
exten => s,1(check),GotoIf($["${BLACKLIST()}"="1"]?blacklisted)
exten => s,n,Set(CALLED_BLACKLIST=1)
exten => s,n,Return()
exten => s,n(blacklisted),Answer
exten => s,n,Wait(1)
exten => s,n,Zapateller()
exten => s,n,Playback(ss-noservice)
exten => s,n,Hangup

Note that this is a pretty simple macro context. The first line checks to see if a caller ID number appears in the Asterisk blacklist, and if so, it shuffles the call off to a “number not in service” recording.

If you copy and paste this entire context into the file /etc/asterisk/extensions_override_freepbx.conf and remove the “include” line at the start of the macro, you can then modify it to do what you want. Let’s look at that same context again, but with a few added lines, as it might appear in /etc/asterisk/extensions_override_freepbx.conf

[app-blacklist-check]

;Make sure CDR DID field is set on blacklisted calls
exten => s,1(check),Set(CDR(did)=${FROM_DID})
;Next line is from the original blacklist context but moved higher
exten => s,n,Set(CALLED_BLACKLIST=1)
;Special CallerID name lookup; uses Asterisk Phonebook which also acts as whitelist
exten => s,n,GotoIf($["${DB_EXISTS(cidname/${CALLERID(num)})}"!="1"]?blcheck)
exten => s,n,Set(CALLERID(name)=${DB(cidname/${CALLERID(num)})})
exten => s,n,Set(__SKIPCIDLOOKUP=1)
exten => s,n,Return()
;Original first line of context with line number changed and blcheck label added
exten => s,n(blcheck),GotoIf($["${BLACKLIST()}"="1"]?blacklisted)
;Blacklist Caller ID names found in custom Asterisk database blistname if used
exten => s,n,GotoIf($["${DB_EXISTS(blistname/${TOUPPER(${CALLERID(name)})})}"="1"]?blacklisted)
;Blacklist Caller ID names of single letter followed by 9 or more digits
exten => s,n,Set(regx=^[A-Z][0-9]{9}[0-9]* *$)
exten => s,n,GotoIf($[${REGEX("${regx}" ${CALLERID(name)})} = 1]?blacklisted)
;Blacklist numbers where first digit of 7 digit local number is 0 or 1
exten => s,n,Set(regx=^[+]?1?[0-9]{3}[01][0-9]{6}$)
exten => s,n,GotoIf($[${REGEX("${regx}" ${CALLERID(num)})} = 1]?blacklisted)
;Blacklist numbers where first digit of area code is 0 or 1
exten => s,n,Set(regx=^[+]?1?[01][0-9]{9}$)
exten => s,n,GotoIf($[${REGEX("${regx}" ${CALLERID(num)})} = 1]?blacklisted)
;Blacklist numbers where first three digits of 7 digit local number are 555
exten => s,n,Set(regx=^[+]?1?[0-9]{3}555[0-9]{4}$)
exten => s,n,GotoIf($[${REGEX("${regx}" ${CALLERID(num)})} = 1]?blacklisted)
;Blacklist numbers that start with 1 but are longer than 11 digits total
exten => s,n,Set(regx=^[+]?1[0-9]{11}[0-9]*$)
exten => s,n,GotoIf($[${REGEX("${regx}" ${CALLERID(num)})} = 1]?blacklisted)
;Blacklist numbers of less than 7 digits in length
exten => s,n,GotoIf($[${LEN(${CALLERID(num)})} < 7]?blacklisted)
;Blacklist numbers of 8 digits in length
exten => s,n,GotoIf($[${LEN(${CALLERID(num)})} = 8]?blacklisted)
;Query TrueCNAM
exten => s,n,AGI(truecnam.agi)
exten => s,n,Noop(TrueCNAM SPAMSCORE: ${SPAMSCORE})
;Show non-zero spam score in Userfield of Call Detail Record
exten => s,n,ExecIf($[${SPAMSCORE} > 0]?Set(CDR(userfield)="Spam Score ${SPAMSCORE}"))
exten => s,n,ExecIf($[${SPAMSCORE} > 39]?Set(CALLERID(name)=SPAM:${CALLERID(name)}))
exten => s,n,GotoIf($[${SPAMSCORE} > 99]?highscore)
;More original blacklist context
exten => s,n,Return()
;Set Call Detail Record Userfield to Blacklisted (splits statement from original blacklist context)
exten => s,n(blacklisted),Set(CDR(userfield)=Blacklisted)
exten => s,n(highscore),Answer
;More original blacklist context
exten => s,n,Wait(1)
exten => s,n,Zapateller()
exten => s,n,Playback(ss-noservice)
exten => s,n,Hangup

;--== end of [app-blacklist-check] ==--;

The lines in blue are from the original context that was copied from /etc/asterisk/extensions_additional.conf. We should mention here that not all the ideas in the new lines are original with us; some are adaptations of things we’ve read over many months in various forums.

EDIT: Also please note that in recent versions of FreePBX the last four dialplan lines have been changed. Instead of

exten => s,n,Wait(1)
exten => s,n,Zapateller()
exten => s,n,Playback(ss-noservice)
exten => s,n,Hangup

It now uses

exten => s,n,Set(BLDEST=${DB(blacklist/dest)})
exten => s,n,GotoIf(${LEN(${BLDEST})}?${BLDEST}:app-blackhole,zapateller,1)

Or in even newer versions:

exten => s,n,Set(BLDEST=${DB(blacklist/dest)})
exten => s,n,GotoIf($["${returnhere}"="1"]?returnto)
exten => s,n,GotoIf(${LEN(${BLDEST})}?${BLDEST}:app-blackhole,zapateller,1)
exten => s,n(returnto),Return()

This underscores the importance of starting with the original [app-blacklist-check] context in your FreePBX application, and not just blindly copying the example dialplan shown here. (End of edit.)

You don’t need to use all of these added lines shown. On the other hand, you can add your own customizations. Here is what each added line (or set of lines) means:

The change to line 1 (moving the original line 1 down a few lines) adds Set(CDR(did)=${FROM_DID}), which causes the call detail record to show the DID the call came in on for blacklisted calls.

The next added section consists of these lines:

;Special CallerID name lookup; uses Asterisk Phonebook which also acts as whitelist
exten => s,n,GotoIf($["${DB_EXISTS(cidname/${CALLERID(num)})}"!="1"]?blcheck)
exten => s,n,Set(CALLERID(name)=${DB(cidname/${CALLERID(num)})})
exten => s,n,Set(__SKIPCIDLOOKUP=1)
exten => s,n,Return()

What this does is checks the Asterisk Phonebook to see if the calling number appears there, and if it does, it sets the Caller ID name to the name associated with that number in the Phonebook. It also allows the Asterisk Phonebook to act as a “whitelist”, so that numbers in the Phonebook are not sent to TrueCNAM for spam scoring or subjected to any further blacklist tests. If a number appears in both the Asterisk Phonebook and the Blacklist, the Asterisk Phonebook will “win” and the call will be allowed through, so don’t put any number from which you want to block calls in the Asterisk Phonebook! Originally I had put this section lower in the context but then I realized that if a number appears in the whitelist, no further blacklist checking is necessary or desirable.

There is one issue with doing this, and that is that if you have the FreePBX CallerID Lookup module installed and enabled, and you use another Caller ID lookup source it will override the Asterisk Phonebook lookup. To avoid that, you can either uninstall or remove the CallerID Lookup module, OR you can copy the [cidlookup] context from /etc/asterisk/extensions_additional.conf to /etc/asterisk/extensions_override_freepbx.conf and change the first line to a test for the SKIPCIDLOOKUP variable. For example, if the first line is:

exten => cidlookup_return,1,ExecIf($["${DB(cidname/${CALLERID(num)})}" != ""]?Set(CALLERID(name)=${DB(cidname/${CALLERID(num)})}))

You could change it to:

exten => cidlookup_return,1,,ExecIf($["${SKIPCIDLOOKUP}"="1"]?Return())
exten => cidlookup_return,n,ExecIf($["${DB(cidname/${CALLERID(num)})}" != ""]?Set(CALLERID(name)=${DB(cidname/${CALLERID(num)})}))

Don’t forget to change the line number 1 to n in the original first line, since it’s no longer line 1.  If you do not have the [cidlookup] context in /etc/asterisk/extensions_additional.conf then you probably have not installed or enabled the CallerID Lookup module, and in that case you don’t need to make these changes, and you can also omit the line that contains exten => s,n,Set(__SKIPCIDLOOKUP=1) from the added section under discussion.

Also, if you have the CID Superfecta module installed and enabled, then you should not enable the Asterisk Phonebook data source (since you would be doing the same lookup twice), but you should enable the Trunk Provided data source (so that CID Superfecta will see that there is already a Caller ID name associated with the call, and not further attempt to find a name to associate with the number).

Getting back to the additions to the app-blacklist-check context…

;Blacklist Caller ID names found in custom Asterisk database blistname if used
exten => s,n,GotoIf($["${DB_EXISTS(blistname/${TOUPPER(${CALLERID(name)})})}"="1"]?blacklisted)

This addition allows you to blacklist by exact Caller ID name. To add a name to the blacklist-by-name database, go into the Asterisk CLI and enter this:

database put blistname NAME 1

Where NAME is the name you want to add – enclose it in quotation marks if it contains spaces:

database put blistname "SOME NAME" 1

You can use a descriptive word if you like in place of the number 1 at the end of the line. To delete an already entered name:

database del blistname NAME

And to see what’s already in the blacklist-by-name database:

database show blistname

Next we come to:

;Blacklist Caller ID names of single letter followed by 9 or more digits
exten => s,n,Set(regx=^[A-Z][0-9]{9}[0-9]* *$)
exten => s,n,GotoIf($[${REGEX("${regx}" ${CALLERID(name)})} = 1]?blacklisted)

These lines are an example of blacklisting a Caller ID name using a regular expression. This will catch any Caller ID name that starts with a single letter and is followed by 9 or more digits, and any number of spaces at the end. This particular example will get rid of those irritating Vnnnnnnnnn… name calls, even if they change the starting letter to something other than “V”.

;Blacklist numbers where first digit of 7 digit local number is 0 or 1
exten => s,n,Set(regx=^[+]?1?[0-9]{3}[01][0-9]{6}$)
exten => s,n,GotoIf($[${REGEX("${regx}" ${CALLERID(num)})} = 1]?blacklisted)

;Blacklist numbers where first digit of area code is 0 or 1
exten => s,n,Set(regx=^[+]?1?[01][0-9]{9}$)
exten => s,n,GotoIf($[${REGEX("${regx}" ${CALLERID(num)})} = 1]?blacklisted)

;Blacklist numbers where first three digits of 7 digit local number are 555
exten => s,n,Set(regx=^[+]?1?[0-9]{3}555[0-9]{4}$)
exten => s,n,GotoIf($[${REGEX("${regx}" ${CALLERID(num)})} = 1]?blacklisted)

These are three examples of blacklisting numbers by regular expression patterns. The first example blacklists numbers that have an invalid exchange (where the 7-digit part of the number starts with 0 or 1), while the second blacklists numbers that come in with an area code starting with 0 or 1, which is invalid. The third blocks numbers that appear to come from the “directory assistance” exchange 555 in any area code. In all cases, it does not matter if the number starts with a leading + and/or 1. Note that Asterisk has a fairly restrictive syntax for regular expressions, so you can’t do many of the substitutions that would be possible in other computer languages. See the article, Did you know that Asterisk has the ability to evaluate Regular Expressions, though not in the same way as Perl or FreeSWITCH? for more information.

You can always add additional blacklist patterns by duplicating an appropriate pair of lines (for blacklisting by name or number pattern) and then modifying the regular expression. For example, to block calls from certain specific area codes, you could use a regular expression of the form ^[+]?1?(xxx|yyy|zzz)[0-9]{7}$ where xxx, yyy, and zzz are the area codes you want to block. You can include as many area codes as you need, separated by the | character.

;Blacklist numbers of 8 digits in length
exten => s,n,GotoIf($[${LEN(${CALLERID(num)})} = 8]?blacklisted)

This is an example of blocking numbers of a specific length. If you have a bad caller that sends numbers that are exactly 8 characters in length, this will catch them. You can, of course, change the “8” to catch other bad length numbers, but be careful not to inadvertently block wanted international or other valid calls with non-standard number lengths.

The next section is where the TrueCNAM scoring is performed:

;Query TrueCNAM
exten => s,n,AGI(truecnam.agi)
exten => s,n,Noop(TrueCNAM SPAMSCORE: ${SPAMSCORE})

The above calls the bash script to get the TrueCNAM spam score for the number (from 0 to 100).

;Show non-zero spam score in Userfield of Call Detail Record
exten => s,n,ExecIf($[${SPAMSCORE} > 0]?Set(CDR(userfield)="Spam Score ${SPAMSCORE}"))

Newer versions of FreePBX have a “Userfield” in the call detail records (CDR), and here we are placing the spam score (if it is higher than zero) in the CDR so that when you review the call detail you can determine how a call scored.  For example if a calling number had a relatively high score, but not quite high enough to get it blocked, you could review it using an online lookup source such as 800notes to see if it’s a number you want to add to the Blacklist.

exten => s,n,ExecIf($[${SPAMSCORE} > 39]?Set(CALLERID(name)=SPAM:${CALLERID(name)}))
exten => s,n,GotoIf($[${SPAMSCORE} > 99]?highscore)
exten => s,n,Return()

The above section is where we act on the spam score. In this example, if the spam score is 40 or higher, the word “SPAM:” is prepended to the existing caller ID name.  This does not mean that the call is unequivocally from a telemarketer or robocaller, but that you probably should be suspicious of that caller.  You can change the value but be careful, because in our experience calls from some perfectly valid numbers can have a score of 30 (it’s rare but it happens).  If the spam score is 100 (the highest possible score), then it basically treats the call as if you had blacklisted it.  You can change this to a lower value (TrueCNAM recommends 80 or higher, so you could change > 99 to > 79) but that is entirely up to you.  We didn’t want anyone blaming us for missing that all important call that would have awarded them the vacation of a lifetime (but only after sending gift cards to some Nigerian prince to cover “fees”), so in this example we set it to only block the call outright if it scores a solid 100.

;Set Call Detail Record Userfield to Blacklisted (splits statement from original blacklist context)
exten => s,n(blacklisted),Set(CDR(userfield)=Blacklisted)

This is where calls that fail the other tests (not TrueCNAM) land. We don’t recall where we first saw this, but it is a great idea. Here the “Userfield” in the call detail record is set to the word “Blacklisted”. When you are looking at your call records, this tells you instantly if a problem caller is already being blacklisted, so you don’t need to wonder if you should add them to the blacklist. Note that if you see a Spam Score, the call is NOT blacklisted, so if you want to blacklist that number you will need to do that separately. You might want to do that for a repeat problem caller, so you’re not reaching your TrueCNAM daily limit prematurely by looking up what you already know is a bad caller.

exten => s,n(highscore),Answer

The above line is where calls that scored above the “highscore” limit in TrueCNAM land. So they are treated like any other blacklisted call, except the spam score appears in the CDR “Userfield” instead of the word “Blacklisted”.

Keep in mind that any time you replace a context in /etc/asterisk/extensions_override_freepbx.conf, it is your responsibility to make sure it “tracks” any changes to the original context in /etc/asterisk/extensions_additional.conf. So, after any major FreePBX upgrade, you should take a look at the original [app-blacklist-check] context (and the [cidlookup] context, if you have modified that) and make sure that they have not changed, and if they have, that you make the same changes to your replacement contexts.

One additional point – at the top of each of the original contexts, there is an “include” statement that we suggest you remove when you copy the context to /etc/asterisk/extensions_override_freepbx.conf, for example, “include => app-blacklist-check-custom“. You might wonder if you could create a context named app-blacklist-check-custom in /etc/asterisk/extensions_custom.conf and copy the original context there. But, for whatever reason, that just doesn’t seem to work, and there’s no real advantage to putting the copied context there anyway.

Related articles:
How to hack the FreePBX blacklist for better call blocking capability
Link: Asterisk: Blacklisting For Multiple Users
Forum thread: User-specific Caller ID/whitelist/blacklist in Asterisk/FreePBX

How to use a custom SIP header to pass the DID (or other data) between two Asterisk servers that jointly handle extensions

NOTE: This post has been edited to show a newer method that should work with both PJSIP and Chan_SIP trunks.

If you have multiple Asterisk or FreePBX servers at different locations that pass Intra-Company traffic between each other using SIP trunks, you may have wished for a way to pass the Calling DID number (or some other bit of data stored in an Asterisk variable) from one server to another. For example, let’s suppose that all extensions in your company are four digits in length, and that the extensions on server A are numbered 1000-1099, and on server B they are numbered 1100-1199, and when a call comes in on system A that goes to an extension on system B, you want to pass the original DID that the call arrived on to system B so that it will be included in the call detail for that call.  It’s easy to do this; I’ll first show what you’d need to do on a server A that is running FreePBX.

In /etc/asterisk/extensions_custom.conf, you should find a context named [macro-dialout-trunk-predial-hook], and if you’ve not previously modified it then you should only need to add these four lines to that context (the last two of which may already be present):

exten => s,1,Set(regx=^11[0-9]{2}$)
exten => s,n,ExecIf($[${REGEX("${regx}" ${OUTNUM})} = 1]?Set(HASH(__SIPHEADERS,X-DID)=${CDR(did)}))
exten => s,n,MacroExit()
exten => h,1,Macro(hangupcall,)

The above has been modified to show the new way to do this in more recent versions of FreePBX. It is the only way that will work (without adding a lot more dialplan) if you are using a PJSIP trunk. If you are curious as to why this works, it turns out that in recent FreePBX versions, at the time the Asterisk Dial statement is executed a context named func-apply-sipheaders is executed, and the purpose of the context is to create additional SIP headers that have been set using a statement similar to the one we have used here. So, that works out rather well for our intended usage.

The previous method was to use this line as the second line of the context, which may still work for Chan SIP trunks:

exten => s,n,ExecIf($[${REGEX("${regx}" ${OUTNUM})} = 1]?SIPAddHeader(X-DID: ${CDR(did)}))

Anyway, to explain the context above, the first line sets a regular expression to match the digits 11XX – if you also do this on server B you would of course change the 11 to 10. There is probably a way to do this without using a regular expression but I just wanted to show this method because if offers the most flexibility in matching numbers (although Asterisk has a somewhat unique way of implementing regular expressions; that’s why I have to use [0-9] rather than d to indicate “any digit” in the expression). In the second line, if the regular expression matches the called number (the destination extension), the statement Set(HASH(__SIPHEADERS,X-DID)=${CDR(did)}) (formerly SIPAddHeader(X-DID: ${CDR(did)}) ) is executed, which takes the contents of the CDR(did) variable and puts it into a custom SIP header named X-DID, which follows the standard convention of adding X- to the start of a user-created SIP header. This is then transmitted to server B as part of the first INVITE message in the channel. In raw Asterisk (no FreePBX), you just need to make sure that something similar to the statements in the first two lines come before whatever statement sends the call to the other system (usually a Dial statement of some kind).

Now when the call comes into server B, we need a way to do the opposite, which is to get the content of the X-DID SIP header and place it into the CDR(did) variable.  So in the trunk, instead of making the context=from-internal, we can make it something like context=custom-from-server-A, and then in /etc/asterisk/extensions_custom.conf we add that context, which simply contains this:

[custom-from-server-A]
exten => _X!,1,Set(CDR(did)=${SIP_HEADER(X-DID)})
exten => _X!,n,Goto(from-internal,${EXTEN},1)

On Server A, you’d use custom-from-server-B in place of custom-from-server-A.

You can transmit the contents of any Asterisk variable in this manner, but of course you’d probably want to change the custom SIP header name to something that more closely matches the original variable name.  I wouldn’t recommend going hog wild with adding custom SIP headers, but they are a valid technique for passing a few variables or other bits of data between your servers.

Forum thread: User-specific Caller ID/whitelist/blacklist in Asterisk/FreePBX

Occasionally I see a forum thread that contains enough interesting material that it could be the start of an article, but because it’s stretched through a number of posts, I can only link to the thread. And also, because I’m not the author of any of the original posts, I can’t just copy and paste without possibly violating someone’s copyright. This is one such thread, which discusses the possibility of creating user-specific whitelists or blacklists, or Caller ID name lookup sources in FreePBX or Asterisk. The Caller ID name lookup would be most useful to Google Voice users, since Google Voice doesn’t provide a Caller ID name on incoming calls, just a number. Since there is no way that a user can add or change such listings in the FreePBX interface at present, the trick seems to be to use Google Contacts as the user’s web interface, and then import the data from the user’s Google Contacts list into the Asterisk database at periodic intervals using a cron job.

The interesting thing about this is that it appears that users can have their own individual lists, since each user would apparently have their own Google Contacts, which means that a user could blacklist a caller without blacklisting that caller for all users on the system. It may be a bit tricky to figure out what’s being done from the posts shown, but still it looks like a possibly interesting technique.

Even though FreePBX 12 now offers a contact list in the User Control Panel, there are limitations on how it can be used. What is discussed in this thread apparently does not share those limitations, but does have the limitation that any changes made will not be seen by Asterisk until the next time the Google Contacts database is imported into Asterisk’s database, which is done using some downloadable software, a python script, and a cron job.

Thread here:
User-specific Caller ID/whitelist/blacklist in Asterisk/FreePBX (DSLReports.com)

Stop SOME SipVicious attacks from reaching your Asterisk, FreeSwitch, YATE, etc. PBX server

This tip was posted by user “infotek” on the FreePBX site but applies to all software PBX systems that use the iptables firewall. “infotek” wrote:

By default the SipVicious scanner uses the ua : “friendly-scanner”. To block this ua, you can have iptables search the packet for that text.

add the following line to /etc/sysconfig/iptables

-A INPUT -p udp -m udp –dport 5060 -m string –string “friendly-scanner” –algo bm –to 500 -j DROP

Now the thing to keep in mind about this is that it only works if you know the string that will be sent as the user agent, and some hackers using SipVicious may take the trouble to change that default string, but some protection is better than none.  However this same technique can be used to block any attack that constantly sends the same string as the user agent, if you know what that string contains.

For those that use Webmin to manage iptables, here are the settings to use.  This should come BEFORE any other rules applicable to port 5060 – I made it the very first rule on the page “Incoming packets (INPUT) – Only applies to packets addressed to this host“:

Rule comment: Stop SipVicious
Action to take: Drop
Network protocol: Equals UDP
Destination TCP or UDP port: Equals Port(s) 5060
Additional IPtables modules: string
Additional parameters: –string “friendly-scanner” –algo bm –to 500

All other settings on the Webmin “Add Rule” page should be left at the default value (usually <ignored>).

To stop the hackers clever enough to change the default user agent string, consider also using this technique.

How to set up an alternate SIP port (other than 5060) using Webmin

One problem that some VoIP users are experiencing these days is that they have trouble connecting to their home Asterisk, FreeSWITCH, YATE, or other software PBX server, but only when using certain ISP’s.  One suspicion is that certain ISP’s that offer their own VoIP or traditional landline service attempt to mess with packets using the common SIP port 5060, hoping customers will think that VoIP is unreliable and will subscribe to the company’s overpriced offering instead (see this thread at BroadbandReports.com).

There are various ways to enable an alternate SIP port on the server (in addition to the usual port 5060) but if you are using Webmin to manage your firewall, here’s an easy way, in just three steps:

Step 1:

If you use Webmin to manage your firewall, then you already know how to get to the Linux Firewall page.  So go there and select the Network Address Translation (nat) table in the dropdown at the top of the page.  Then when the page changes, click the topmost Add Rule button (in the Packets before routing (PREROUTING) section):

SIP Port Forwarding 1

Step 2:

Now you should see this page. The items you need to change are indicated by the red ovals.  The Destination TCP or UDP port is set to 7654 in this example, but don’t use that.  Pick your own unique port; just make sure that it’s not used by anything else on the server already.  And yes, you really do put the alternate SIP port you want to use in the Destination setting; it may not make intuitive sense but that’s just how it is.  Avoid using ports in the range 10000 through 20000 because those are used for RTP traffic, and avoid ports below 1024 because those are protected ports that are reserved by the system.  There are also other ports you should avoid (those used by other software on your system) but if you don’t know how to find ports in use on your system, a bit of time with a search engine will lead you to several pages that show you how to detect already active ports.  It can vary a bit depending on your operating system, and it’s beyond the scope of this article.

SIP traffic is UDP only, not TCP (there may be rare exceptions but most software PBX’s use UDP by default).  If by some very odd chance you are using TCP for SIP traffic (why?!?) then you will need to specify that under the Network Protocol item.  Also, note that the incoming interface is set to eth0 in this example – Webmin will usually show the correct one by default, but you want to select the interface used by incoming SIP traffic if you happen to have more than one.  Don’t forget to click Save when you’re finished.

SIP Port Forwarding 2

Step 3:

After you have saved the page you should be back at the page you came from, and it should now show your new forwarding rule.  If it does, just click Apply Configuration at the bottom of the page to make it active:

SIP Port Forwarding 3One other thing you might need to to is add a rule on the main Linux Firewall page allowing incoming traffic on your selected alternate port, if you have a restrictive firewall that blocks most traffic by default.  Try it first without doing that, but if your clients can’t connect on the alternate port, just be aware that you may need to do that before they will be able to connect.  For more security, you can enable access to your SIP ports only from specific IP addresses, if your remote clients are at fixed IP addresses.

Now you should be able to change the port number on your SIP endpoints from the default 5060 to your alternate port.  Of course I can’t guarantee it will always work, but if you try it and suddenly find that your SIP connections become far more reliable, you might want to leave a comment, and mention the ISP that you suspect might be messing with SIP traffic.

By the way, if you are NOT using Webmin to manage your firewall, and have iptables installed, then all you should need to do is enter these two lines from a command prompt (replace 7654 with your chosen alternate port).  But I strongly caution you NOT to do this if you are using Webmin to manage your firewall:

iptables -t nat -A PREROUTING -i eth0 -p udp --dport 7654 -j REDIRECT --to-ports 5060
/etc/init.d/iptables save

Featured Article:

Recent Posts

Recent Comments

Archives

Categories

Meta

GiottoPress by Enrique Chavez

%d bloggers like this: