Spam Calls

mahe23

Customer
Mitglied seit
26. Januar 2015
Beiträge
19
Ich bekomme immer öfter "SPAM" Calls. Das sind Anrufe mit der Kenung "test" oder "hi'or‘x’='x'" oder auch andere Zeichen. bisher habe ich sie einfach in meine Blacklist aufgenommen. Leider paasiert das jetzt immer wieder und ich muss immer nach justieren.

Sie werden über meinen Provider signalisiert. Mein Provider(sipgate) hat aber keine Infos über diese Anrufe.

Wie kann man diese Anrufe komplett verhindern?
 
Hallo mahe23,

Bitte überprüfe, ob du kurze DID-Nummern verwenden: z. B. * 0, * 10, * 123
Dies kann dazu führen, dass die PBX eingehende Anrufe aus jeder Quelle blind vertraut.
Um dies zu beheben, bearbeite bitte jeden deiner DID mit Syntax * 123456 mit 6 Ziffern.

- in deiner Firewall den SIP-Port filtern, um nur vertrauenswürdige Quellen zuzulassen, zb. deine VoIP-Provider IP / Range und Remote-Nebenstellen (falls vorhanden).

Gruß
Ilias
 
Bei Asterisk habe ich eine Anbindung über Tellows gemacht d.h. wenn da nach einem Lookup der Nummer ein Score >5 rauskommt, klingelt es nicht. Sowas müsste man mal in 3CX machen.

Bzgl. Firewall ist auch nicht so einfach weil die Anbieter Load Balancer mit unbekannten IPs verwenden und die meisten Firewalls nur mit IP basierten Regeln umgehen können und keine Namensauflösung machen.

Kann man bei 3CX eigentlich einstellen ob direkte SIP Calls erlaubt sind? Oder werden die Default gar nicht angenommen wenn nichts in Inbound Rules definiert ist?
 
Ich habe angefangen ein Script zu schreiben, bin aber schnell an meine Grenzen gestoßen einiges ist bei 3CX sehr speziell. Ich hoffe das die Kollegen aus dem US Forum helfen können. Ich Poste das Script hier trozdem mal.
C#:
using CallFlow;
using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using System.Xml.Linq;
using TCX.Configuration;
using TCX.PBXAPI;

namespace dummy
{
    public class CallHandler : ScriptBase<CallHandler>
    {
        // Variables for Tellows API and spam forwarding
        private static string tellowsApiKey = "your_api_key";         // API key for Tellows
        private static string tellowsPartnerID = "your_partner_id";   // Partner ID for Tellows
        private static int tellowsThreshold = 7;                      // Threshold for spam detection (1-10)
        private static string spamDestinationNumber = "+1234567890";  // Destination number for spam calls

        PhoneSystem ps = null;

        public CallHandler()
        {
            ps = PhoneSystem.Root;

            if (ps == null)
            {
                Log("Error: Phone system not initialized");
            }
        }

        // Method for logging messages
        public static void Log(string text)
        {
            string fileName = "/var/lib/3cxpbx/Instance1/Data/Logs/tellows.log";

            string logMessage = String.Format("[{0}]: {1}", DateTime.Now.ToString(), text + Environment.NewLine);

            File.AppendAllText(fileName, logMessage);
        }

        // Example method to process an incoming call
        public async Task HandleIncomingCall(ICall myCall)
        {
            try
            {
                // Log the CallerID and check if it is valid
                string callerID = myCall.Caller?.CallerID;

                if (string.IsNullOrEmpty(callerID))
                {
                    Log("Error: CallerID is empty or invalid.");
                    return;
                }

                Log($"Incoming call from: {callerID}");

                // Use Tellows API to analyze the caller
                int spamScore = await GetSpamScore(callerID);

                // If the spam score is equal to or greater than the threshold, mark it as spam
                if (spamScore >= tellowsThreshold)
                {
                    Log($"Spam detected! Score: {spamScore}. Forwarding to spam destination.");
                    await RouteCallToSpamDestination(myCall);
                }
                else
                {
                    Log($"No spam detected. Score: {spamScore}. Processing call normally.");
                }
            }
            catch (Exception ex)
            {
                Log($"Error during call processing: {ex.Message}");
            }
        }

        // Method to fetch the spam score from Tellows (XML Parsing)
        private async Task<int> GetSpamScore(string callerID)
        {
            try
            {
                // Build the Tellows API URL with the relevant parameters
                string apiUrl = $"https://www.tellows.de/basic/num/{callerID}?xml=1&partner={tellowsPartnerID}&apikey={tellowsApiKey}";

                Log($"Making API request to Tellows: {apiUrl}");

                using (HttpClient client = new HttpClient())
                {
                    Log($"Sending API request to Tellows: {apiUrl}");
                    HttpResponseMessage response = await client.GetAsync(apiUrl);
                    Log($"API response status: {response.StatusCode}");
                    response.EnsureSuccessStatusCode();

                    string responseBody = await response.Content.ReadAsStringAsync();
                    Log($"Tellows API response: {responseBody}");

                    // Load the XML data and extract the spam score
                    XDocument xmlResponse = XDocument.Parse(responseBody);

                    // Extract the spam score from the XML response
                    XElement scoreElement = xmlResponse.Root.Element("score");

                    if (scoreElement != null)
                    {
                        int spamScore = int.Parse(scoreElement.Value);
                        Log($"Spam score from Tellows for {callerID}: {spamScore}");
                        return spamScore;
                    }
                    else
                    {
                        Log($"Spam score not found in response for {callerID}");
                        return 0; // Default to no spam if no score found
                    }
                }
            }
            catch (HttpRequestException httpEx)
            {
                Log($"HTTP error during spam score retrieval: {httpEx.Message}");
                return 0; // Default value if API request fails
            }
            catch (Exception ex)
            {
                Log($"General error during spam score retrieval: {ex.Message}");
                return 0; // Default value if an error occurs
            }
        }

        // Method to forward spam calls
        private async Task RouteCallToSpamDestination(ICall myCall)
        {
            try
            {
                // Convert the destination number into a DN object
                DN spamDestination = PhoneSystem.Root.GetDNByNumber(spamDestinationNumber);

                if (spamDestination == null)
                {
                    Log("Spam destination number could not be resolved.");
                    return;
                }

                // Use the ReplaceWithAsync method to forward the call
                CallControlResult result = await myCall.ReplaceWithAsync(new DestinationStruct(spamDestination));

                if (result != null)  // Check if the result is not null
                {
                    Log("Call successfully forwarded to spam destination.");
                }
                else
                {
                    Log("Failed to forward call to spam destination.");
                }
            }
            catch (Exception ex)
            {
                Log($"Error during call forwarding: {ex.Message}");
            }
        }
    }
}
 
Ich habe nochmal rumgespielt und das Script läuft so halb. Auch das logging geht.

Bei SPAM False bricht es leider den Call mit EndCall ab und ich weiß noch nicht wieso.
Bei SPAM True routet er nicht auf die gewünschte Nummer sondern arbeitet den Anruf ganz normal ab.

Vieleicht findet ja jemmand das Problem

C++:
using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using System.Xml.Linq;
using TCX.Configuration;
using TCX.PBXAPI;

namespace dummy
{
    public class CallHandler : ScriptBase<CallHandler>
    {
        // Tellows API variables
        private static string tellowsApiKey = "your_api_key";         // API key for Tellows
        private static string tellowsPartnerID = "your_partner_id";   // Partner ID for Tellows
        private static int tellowsThreshold = 5;                        // Spam threshold
        private static string spamDestinationNumber = "+4912345678";  // Destination number for spam calls
        private static string logFileName = "/var/lib/3cxpbx/Instance1/Data/Logs/tellows.log";  // Log file path

        PhoneSystem ps = null;

        public override async void Start()
        {
            // Start Logging
            Log("Starting the CallHandler script.");

            await Task.Run(async () =>
            {
                ps = MyCall.PS as PhoneSystem;

                if (ps == null)
                {
                    Log("Error: Phone system not initialized.");
                    return;  // Stop if the phone system is not initialized
                }

                string callerID = MyCall.Caller?.CallerID;

                if (string.IsNullOrEmpty(callerID))
                {
                    Log("Error: CallerID is empty or invalid. Ending call.");
                    MyCall.Return(false);  // End the call if CallerID is invalid
                    return;
                }

                Log($"Incoming call from: {callerID}");

                // Analyze call with Tellows API
                int spamScore = await GetSpamScore(callerID);

                if (spamScore >= tellowsThreshold)
                {
                    Log($"Spam detected with score: {spamScore}. Forwarding to spam destination.");
                    await ReplaceCallWithExternal(spamDestinationNumber);  // Forward call to spam destination
                    MyCall.Return(true);  // End the call after forwarding to spam
                }
                else
                {
                    Log($"No spam detected. Score: {spamScore}. Letting 3CX handle the call.");
                    return;  // Do nothing for non-spam calls, just let 3CX handle it
                }

                Log("Script execution completed.");
            });
        }

        // Method to get spam score from Tellows API
        private async Task<int> GetSpamScore(string callerID)
        {
            try
            {
                string apiUrl = $"https://www.tellows.de/basic/num/{callerID}?xml=1&partner={tellowsPartnerID}&apikey={tellowsApiKey}";
                Log($"Making API request to Tellows: {apiUrl}");

                using (HttpClient client = new HttpClient())
                {
                    HttpResponseMessage response = await client.GetAsync(apiUrl);
                    Log($"API response status: {response.StatusCode}");
                    response.EnsureSuccessStatusCode();

                    string responseBody = await response.Content.ReadAsStringAsync();
                    Log($"Tellows API response: {responseBody}");

                    XDocument xmlResponse = XDocument.Parse(responseBody);
                    XElement scoreElement = xmlResponse.Root.Element("score");

                    if (scoreElement != null)
                    {
                        int spamScore = int.Parse(scoreElement.Value);
                        Log($"Spam score for {callerID}: {spamScore}");
                        return spamScore;
                    }
                    else
                    {
                        Log($"No spam score found for {callerID}.");
                        return 0;  // Default to 0 (non-spam) if no score found
                    }
                }
            }
            catch (Exception ex)
            {
                Log($"Error during spam score retrieval: {ex.Message}");
                return 0;  // Default to 0 (non-spam) if an error occurs
            }
        }

        // Method to forward the call to the spam destination (spam case)
        private async Task ReplaceCallWithExternal(string externalNumber)
        {
            try
            {
                Log($"Attempting to forward call to spam destination: {externalNumber}");

                DestinationStruct destination = new DestinationStruct(DestinationType.External, null, externalNumber);

                CallControlResult result = await MyCall.ReplaceWithAsync(destination);

                if (result != null)
                {
                    Log($"Call successfully forwarded to spam destination: {externalNumber}");
                }
                else
                {
                    Log($"Failed to forward call to spam destination: {externalNumber}");
                }
            }
            catch (Exception ex)
            {
                Log($"Error during call forwarding to spam destination: {ex.Message}");
            }
        }

        // Method for logging messages with a 24-hour time format
        public static void Log(string text)
        {
            string logMessage = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}]: {text}{Environment.NewLine}";
            try
            {
                // Using StreamWriter to ensure immediate writing to the log file
                using (StreamWriter sw = new StreamWriter(logFileName, true))
                {
                    sw.Write(logMessage);
                    sw.Flush();  // Ensure that the log is immediately written to the file
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Failed to log message: {ex.Message}");
            }
        }
    }
}
 
Ohne mir das im Detail anzuschauen (speziell SPAM true oder false): der Rückgabewert deas return wg. Weiterbearbeitung ist ein boolean (wirklich true or false) und kein (int?) 0 oder 1. Das ist kein Assembler oder C sondern C#.
 
Seit dem hier ein IVR läuft ist ruhe mit dem Spam. Scheinbar wollen die keine Tasten drücken. ;)
 
da hast du recht darum die SPSAM Erkennung geht es geht lediglich um das anruf weiterleiten oder halt nicht was nicht geht
 
If you want the script it's running now tested with V20

C#:
using CallFlow;
using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using System.Xml.Linq;
using TCX.Configuration;
using TCX.PBXAPI;
using System.Linq;  // Required for string operations (like .Contains)

namespace dummy
{
    public class CallHandler : ScriptBase<CallHandler>
    {
        // Logging variables
        private static bool enableLogging = false;                                              // enable/disable logging      
        private static string logFileName = "/path/to/log/tellows.log";                         // Log file path

        // Tellows API variables
        private static string tellowsApiKey = "your-api-key";
        private static string tellowsPartnerID = "your-partner-id";
        private static string internalSpamExtension = "04";                                     // Internal extension for spam calls
        private static int tellowsThreshold = 5;                                                // Spam threshold
       
        // Whitelist and Blacklist of numbers, separated by commas
        private static string whitelist = "+49123456789,+49234567890";                          // Whitelisted numbers
        private static string blacklist = "+49345678901,+49456789012";                          // Blacklisted numbers

        // Timeout variable for routing calls
        private static TimeSpan routingTimeout = TimeSpan.FromSeconds(120);                     // Timeout for routing requests

        PhoneSystem ps = null;

        public override async void Start()
        {
            await Task.Run(async () =>
            {
                ps = MyCall.PS as PhoneSystem;

                if (ps == null)
                {
                    Log("Error: Phone system not initialized");
                    return;
                }

                string callerID = MyCall.Caller?.CallerID;
                string dialedNumber = MyCall.DN?.Number;  // Get the originally dialed number (DN number)

                if (string.IsNullOrEmpty(callerID))
                {
                    Log("CallerID is empty or invalid. Ending call.");
                    MyCall.Return(false);  // End call if no valid CallerID
                    return;
                }

                if (string.IsNullOrEmpty(dialedNumber))
                {
                    Log("Dialed number (DN) is empty or invalid. Ending call.");
                    MyCall.Return(false);  // End call if no valid dialed number
                    return;
                }

                Log($"Incoming call from: {callerID} to {dialedNumber}");

                // Check if the caller is in the blacklist
                if (IsBlacklisted(callerID))
                {
                    Log($"CallerID {callerID} is in the blacklist. Treating as spam.");
                    await RouteCallToInternalExtension(internalSpamExtension);  // Forward call to internal extension
                    MyCall.Return(true);  // End call after transferring to spam destination
                    return;
                }

                // Check if the caller is in the whitelist
                if (IsWhitelisted(callerID))
                {
                    Log($"CallerID {callerID} is in the whitelist. Treating as non-spam.");
                    await RouteCallToOriginalDestination(dialedNumber);  // Forward to the originally dialed number
                    return;
                }

                // Analyze call with Tellows API
                int spamScore = await GetSpamScore(callerID);

                if (spamScore >= tellowsThreshold)
                {
                    Log($"Spam detected with score: {spamScore}. Forwarding to internal extension {internalSpamExtension}.");
                    await RouteCallToInternalExtension(internalSpamExtension);  // Forward call to internal extension
                    MyCall.Return(true);  // End call after transferring to spam destination
                }
                else
                {
                    Log($"No spam detected. Score: {spamScore}. Forwarding to originally dialed number: {dialedNumber}");
                    await RouteCallToOriginalDestination(dialedNumber);  // Forward to the originally dialed number
                }
            });
        }

        // Method to check if the caller ID is in the whitelist
        private bool IsWhitelisted(string callerID)
        {
            // Split the whitelist by comma and check if the callerID is present
            var whitelistNumbers = whitelist.Split(',');
            return whitelistNumbers.Contains(callerID);
        }

        // Method to check if the caller ID is in the blacklist
        private bool IsBlacklisted(string callerID)
        {
            // Split the blacklist by comma and check if the callerID is present
            var blacklistNumbers = blacklist.Split(',');
            return blacklistNumbers.Contains(callerID);
        }

        // Method to get spam score from Tellows API
        private async Task<int> GetSpamScore(string callerID)
        {
            try
            {
                string apiUrl = $"https://www.tellows.de/basic/num/{callerID}?xml=1&partner={tellowsPartnerID}&apikey={tellowsApiKey}";
                Log($"Making API request to Tellows: {apiUrl}");

                using (HttpClient client = new HttpClient())
                {
                    HttpResponseMessage response = await client.GetAsync(apiUrl);
                    Log($"API response status: {response.StatusCode}");
                    response.EnsureSuccessStatusCode();

                    string responseBody = await response.Content.ReadAsStringAsync();
                    Log($"Tellows API response: {responseBody}");

                    XDocument xmlResponse = XDocument.Parse(responseBody);
                    XElement scoreElement = xmlResponse.Root.Element("score");

                    if (scoreElement != null)
                    {
                        int spamScore = int.Parse(scoreElement.Value);
                        Log($"Spam score for {callerID}: {spamScore}");
                        return spamScore;
                    }
                    else
                    {
                        Log($"No spam score found in the API response for {callerID}");
                        return 0; // Default value if score element is missing
                    }
                }
            }
            catch (Exception ex)
            {
                Log($"Error during spam score retrieval: {ex.Message}");
                return 0; // Default value on failure
            }
        }

        // Method to route the current call to the internal spam extension
        private async Task RouteCallToInternalExtension(string extension)
        {
            try
            {
                Log($"Attempting to route call to internal extension: {extension}");

                DN destination = PhoneSystem.Root.GetDNByNumber(extension);

                if (destination == null)
                {
                    Log($"Internal extension number {extension} could not be resolved. Ending call.");
                    MyCall.Return(false);  // End the call if the destination is invalid
                    return;
                }

                // Use RouteToAsync to direct the call to the internal extension
                CallControlResult result = await MyCall.RouteToAsync(new RouteRequest
                {
                    RouteTarget = new DestinationStruct(destination),
                    TimeOut = routingTimeout // Use the timeout variable
                });

                if (result != null)
                {
                    Log($"Call successfully routed to internal extension: {extension}");
                }
                else
                {
                    Log($"Failed to route call to internal extension: {extension}");
                    MyCall.Return(false);  // End the call if the routing fails
                }
            }
            catch (Exception ex)
            {
                Log($"Error during call routing to internal extension: {ex.Message}");
                MyCall.Return(false);  // End the call if an exception occurs
            }
        }

        // Method to forward the current call to the originally dialed number (destination)
        private async Task RouteCallToOriginalDestination(string dialedNumber)
        {
            try
            {
                Log($"Attempting to forward call to original destination: {dialedNumber}");

                // Forward the call to the original destination (internal or external number)
                DN originalDestination = PhoneSystem.Root.GetDNByNumber(dialedNumber);

                if (originalDestination == null)
                {
                    Log($"Original destination number {dialedNumber} could not be resolved. Ending call.");
                    MyCall.Return(false);  // End the call if the destination is invalid
                    return;
                }

                // Use RouteToAsync to direct the call to the originally dialed number
                CallControlResult result = await MyCall.RouteToAsync(new RouteRequest
                {
                    RouteTarget = new DestinationStruct(originalDestination),
                    TimeOut = routingTimeout // Use the timeout variable
                });

                if (result != null)
                {
                    Log($"Call successfully routed to original destination: {dialedNumber}");
                }
                else
                {
                    Log($"Failed to route call to original destination: {dialedNumber}");
                    MyCall.Return(false);  // End the call if the routing fails
                }
            }
            catch (Exception ex)
            {
                Log($"Error during call forwarding to original destination: {ex.Message}");
                MyCall.Return(false);  // End the call if an exception occurs
            }
        }

        // Method for logging messages with 24-hour time format
        public static void Log(string text)
        {
            if (enableLogging)  // Only log if logging is enabled
            {
                string logMessage = String.Format("[{0}]: {1}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), text + Environment.NewLine);
                File.AppendAllText(logFileName, logMessage);  // Append log to the file
            }
        }
    }
}
 
Zuletzt bearbeitet:
Einige Anmerkungen, ohne dass ich mir den Algorithmus angeschaut habe (wenn es bei dir funktioniert, dann wird der wohl grds. i.O. sein):

Wenn protokolliert wird, dann wird das separate Logfile absehbar sehr groß. Das wird im Programm nicht behandelt. MyCall.Info() o.ä. ist eine bessere Option oder du handhabst das mit der Größe der Datei / Umlaufprotokollierung selber. Das Logfile schreibt auch die individuelle Nummer des Call nicht mit. Wenn mehrere Anrufe eingehen wird das unlesbar.

Das mit dem MyCall.Return() und anschl. return im Code könnte man überdenken, eines (dafür richtig) reicht.

ps wird nirgends verwendet, kann entfallen.
 

Statistik des Forums

Themen
44.413
Beiträge
232.713
Mitglieder
78.328
Neuestes Mitglied
as7h