]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-3588 --resolve thanks drk
authorJeff Lenk <jeff@jefflenk.com>
Mon, 24 Feb 2014 05:47:49 +0000 (23:47 -0600)
committerJeff Lenk <jeff@jefflenk.com>
Mon, 24 Feb 2014 05:48:31 +0000 (23:48 -0600)
Freeswitch.2012.sln
src/mod/languages/mod_managed/managed/examples/winFailToBan/BanTracker.cs [new file with mode: 0644]
src/mod/languages/mod_managed/managed/examples/winFailToBan/EventLoop.cs [new file with mode: 0644]
src/mod/languages/mod_managed/managed/examples/winFailToBan/Fail2Ban.cs [new file with mode: 0644]
src/mod/languages/mod_managed/managed/examples/winFailToBan/Internal/ConfigHandler.cs [new file with mode: 0644]
src/mod/languages/mod_managed/managed/examples/winFailToBan/Internal/ConfigHelper.cs [new file with mode: 0644]
src/mod/languages/mod_managed/managed/examples/winFailToBan/Properties/AssemblyInfo.cs [new file with mode: 0644]
src/mod/languages/mod_managed/managed/examples/winFailToBan/packages.config [new file with mode: 0644]
src/mod/languages/mod_managed/managed/examples/winFailToBan/skel.cs [new file with mode: 0644]
src/mod/languages/mod_managed/managed/examples/winFailToBan/winFailToBan.csproj [new file with mode: 0644]

index fb5771a136e133d18cd697c07297515d10dd308b..7223a3dc9d05fe4c72192f88698ae7b94c06ab23 100644 (file)
@@ -604,6 +604,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_opus", "src\mod\codecs\
 EndProject\r
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "make_t43_gray_code_tables", "libs\spandsp\src\msvc\make_t43_gray_code_tables.2012.vcxproj", "{EDDB8AB9-C53E-44C0-A620-0E86C2CBD5D5}"\r
 EndProject\r
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "winFailToBan", "src\mod\languages\mod_managed\managed\examples\winFailToBan\winFailToBan.csproj", "{5BA0D5BD-330D-4EE2-B959-CAFEA04E50E0}"\r
+EndProject\r
 Global\r
        GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
                All|Win32 = All|Win32\r
@@ -4056,6 +4058,18 @@ Global
                {EDDB8AB9-C53E-44C0-A620-0E86C2CBD5D5}.Release|x64.Build.0 = All|Win32\r
                {EDDB8AB9-C53E-44C0-A620-0E86C2CBD5D5}.Release|x64 Setup.ActiveCfg = All|Win32\r
                {EDDB8AB9-C53E-44C0-A620-0E86C2CBD5D5}.Release|x86 Setup.ActiveCfg = All|Win32\r
+               {5BA0D5BD-330D-4EE2-B959-CAFEA04E50E0}.All|Win32.ActiveCfg = Release|Any CPU\r
+               {5BA0D5BD-330D-4EE2-B959-CAFEA04E50E0}.All|x64.ActiveCfg = Release|Any CPU\r
+               {5BA0D5BD-330D-4EE2-B959-CAFEA04E50E0}.All|x64 Setup.ActiveCfg = Release|Any CPU\r
+               {5BA0D5BD-330D-4EE2-B959-CAFEA04E50E0}.All|x86 Setup.ActiveCfg = Release|Any CPU\r
+               {5BA0D5BD-330D-4EE2-B959-CAFEA04E50E0}.Debug|Win32.ActiveCfg = Debug|Any CPU\r
+               {5BA0D5BD-330D-4EE2-B959-CAFEA04E50E0}.Debug|x64.ActiveCfg = Debug|Any CPU\r
+               {5BA0D5BD-330D-4EE2-B959-CAFEA04E50E0}.Debug|x64 Setup.ActiveCfg = Debug|Any CPU\r
+               {5BA0D5BD-330D-4EE2-B959-CAFEA04E50E0}.Debug|x86 Setup.ActiveCfg = Debug|Any CPU\r
+               {5BA0D5BD-330D-4EE2-B959-CAFEA04E50E0}.Release|Win32.ActiveCfg = Release|Any CPU\r
+               {5BA0D5BD-330D-4EE2-B959-CAFEA04E50E0}.Release|x64.ActiveCfg = Release|Any CPU\r
+               {5BA0D5BD-330D-4EE2-B959-CAFEA04E50E0}.Release|x64 Setup.ActiveCfg = Release|Any CPU\r
+               {5BA0D5BD-330D-4EE2-B959-CAFEA04E50E0}.Release|x86 Setup.ActiveCfg = Release|Any CPU\r
        EndGlobalSection\r
        GlobalSection(SolutionProperties) = preSolution\r
                HideSolutionNode = FALSE\r
@@ -4188,6 +4202,7 @@ Global
                {7B077E7F-1BE7-4291-AB86-55E527B25CAC} = {0C808854-54D1-4230-BFF5-77B5FD905000}\r
                {7B42BDA1-72C0-4378-A9B6-5C530F8CD61E} = {0C808854-54D1-4230-BFF5-77B5FD905000}\r
                {834E2B2F-5483-4B80-8FE3-FE48FF76E5C0} = {0C808854-54D1-4230-BFF5-77B5FD905000}\r
+               {5BA0D5BD-330D-4EE2-B959-CAFEA04E50E0} = {0C808854-54D1-4230-BFF5-77B5FD905000}\r
                {692F6330-4D87-4C82-81DF-40DB5892636E} = {4CF6A6AC-07DE-4B9E-ABE1-7F98B64E0BB0}\r
                {2286DA73-9FC5-45BC-A508-85994C3317AB} = {4CF6A6AC-07DE-4B9E-ABE1-7F98B64E0BB0}\r
                {66444AEE-554C-11DD-A9F0-8C5D56D89593} = {4CF6A6AC-07DE-4B9E-ABE1-7F98B64E0BB0}\r
diff --git a/src/mod/languages/mod_managed/managed/examples/winFailToBan/BanTracker.cs b/src/mod/languages/mod_managed/managed/examples/winFailToBan/BanTracker.cs
new file mode 100644 (file)
index 0000000..dd5c950
--- /dev/null
@@ -0,0 +1,143 @@
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using FreeSWITCH;\r
+using FreeSWITCH.Native;\r
+\r
+namespace winFailToBan\r
+{\r
+    public static class BanTracker\r
+    {\r
+        public static int MaxFails = 3;\r
+        public static int FailMinutes = 1;\r
+        public static int BanMinutes = 1;\r
+        public static String BanApi = @"system netsh adv fire add rule name={0} dir=in action=block remoteip={1}";\r
+        public static String UnBanApi = @"system netsh adv fire delete rule name={0}";\r
+\r
+        // Tracker object\r
+        public static Dictionary<String, List<DateTime>> MainTracker =\r
+            new Dictionary<string, List<DateTime>>();\r
+\r
+        // Active Ban list Key=IP val=baninfo\r
+        public static Dictionary<String, BanInfo> ActiveBans =\r
+            new Dictionary<string, BanInfo>();\r
+\r
+\r
+        public static void Startup()\r
+        {\r
+            LoadSettings();\r
+        }\r
+\r
+        private static void LoadSettings()\r
+        {\r
+            using (var a = new Api(null))\r
+            {\r
+                var setting = a.ExecuteString("global_getvar ban_maxfails");\r
+                if (!String.IsNullOrEmpty(setting))\r
+                    MaxFails = int.Parse(setting);\r
+\r
+                setting = a.ExecuteString("global_getvar ban_failminutes");\r
+                if (!String.IsNullOrEmpty(setting))\r
+                    FailMinutes = int.Parse(setting);\r
+\r
+                setting = a.ExecuteString("global_getvar ban_banminutes");\r
+                if (!String.IsNullOrEmpty(setting))\r
+                    BanMinutes = int.Parse(setting);\r
+            }\r
+        }\r
+\r
+        private static void CleanOld(List<DateTime> l)\r
+        {\r
+            var expiretime = DateTime.Now.Subtract(new TimeSpan(0, FailMinutes, 0));\r
+            var expired = l.Where(x => x < expiretime).ToList();\r
+            expired.ForEach(x => l.Remove(x));\r
+        }\r
+\r
+        public static void CleanUp()\r
+        {\r
+            var templist = new List<String>();\r
+            foreach (var kvp in MainTracker)\r
+            {\r
+                CleanOld(kvp.Value);\r
+                if (kvp.Value.Count == 0)\r
+                    templist.Add(kvp.Key);\r
+            }\r
+\r
+            templist.ForEach(i =>\r
+            {\r
+                MainTracker.Remove(i);\r
+                Log.WriteLine(LogLevel.Critical, "FTB: Removed tracker entry for {0}", i);\r
+            }); // remove all the dictinoary entries that are old\r
+\r
+            templist.Clear();\r
+\r
+            // now unban the expired bans\r
+            templist.AddRange(from kvp in ActiveBans where kvp.Value.Expires < DateTime.Now select kvp.Key);\r
+            templist.ForEach(Unban);\r
+        }\r
+\r
+        public static void TrackFailure(String ipAddress)\r
+        {\r
+            LoadSettings(); // just in case they've changed... \r
+            if (ActiveBans.ContainsKey(ipAddress))\r
+                return; // don't process again, some delay may happen between the ban, and it taking effect by external system\r
+\r
+            if (!MainTracker.ContainsKey(ipAddress))\r
+                MainTracker.Add(ipAddress, new List<DateTime>());\r
+            var l = MainTracker[ipAddress];\r
+            CleanOld(l);  // clean out the old ones\r
+            l.Add(DateTime.Now); // add the failure to the list\r
+            Log.WriteLine(LogLevel.Critical, "Fail to ban logging attempt from {0} count is {1}", ipAddress, l.Count);\r
+            if (l.Count > MaxFails)\r
+            {\r
+                // do the ban here\r
+                l.Clear();\r
+                MainTracker.Remove(ipAddress);\r
+                Ban(ipAddress);\r
+            }\r
+        }\r
+\r
+        public static void Ban(String ipAddress)\r
+        {\r
+            Log.WriteLine(LogLevel.Critical, "FTP Banning IP Address {0}", ipAddress);\r
+            if (ActiveBans.ContainsKey(ipAddress))\r
+                return; // it's already banned so f-it\r
+\r
+            var bi = new BanInfo();\r
+            ActiveBans.Add(ipAddress, bi);\r
+            // Execute the ban API callback here\r
+            var acmd = String.Format(BanApi, bi.FirewallRuleName, ipAddress);\r
+            Log.WriteLine(LogLevel.Critical, "FTB: api command: {0}", acmd);\r
+            using (var a = new Api(null))\r
+                a.ExecuteString(acmd);\r
+        }\r
+\r
+        public static void Unban(String ipAddress)\r
+        {\r
+            Log.WriteLine(LogLevel.Critical, "FTB: Unbanning ip address {0}", ipAddress);\r
+            if (!ActiveBans.ContainsKey(ipAddress))\r
+                return; // nothing to do, it's not banned\r
+\r
+            var bi = ActiveBans[ipAddress]; // get the ban info\r
+            // Execute the unban API\r
+            var acmd = String.Format(UnBanApi, bi.FirewallRuleName);\r
+            Log.WriteLine(LogLevel.Critical, "FTB: api command: {0}", acmd);\r
+            using (var a = new Api(null))\r
+                a.ExecuteString(acmd);\r
+\r
+            ActiveBans.Remove(ipAddress);\r
+        }\r
+    }\r
+\r
+    public class BanInfo\r
+    {\r
+        public String FirewallRuleName { get; set; }\r
+        public DateTime Expires { get; set; }\r
+\r
+        public BanInfo()\r
+        {\r
+            FirewallRuleName = "ftb-" + Guid.NewGuid().ToString("N");\r
+            Expires = DateTime.Now.AddMinutes(BanTracker.BanMinutes);\r
+        }\r
+    }\r
+}\r
diff --git a/src/mod/languages/mod_managed/managed/examples/winFailToBan/EventLoop.cs b/src/mod/languages/mod_managed/managed/examples/winFailToBan/EventLoop.cs
new file mode 100644 (file)
index 0000000..7f96f4a
--- /dev/null
@@ -0,0 +1,87 @@
+using System;\r
+using System.Threading;\r
+using FreeSWITCH.Native;\r
+using winFailToBan.Internal;\r
+using FreeSWITCH;\r
+\r
+namespace winFailToBan\r
+{\r
+    public static class EventLoop\r
+    {\r
+        public static Boolean Running = true;\r
+        private static Thread _eventThread;\r
+\r
+        public static void StartEvents()\r
+        {\r
+            if (_eventThread != null)\r
+                return;\r
+            _eventThread = new Thread(EventMainLoop);\r
+            Running = true;\r
+            _eventThread.Start();\r
+        }\r
+\r
+        public static void StopEvents()\r
+        {\r
+            Running = false;\r
+        }\r
+\r
+        public static void EventMainLoop()\r
+        {\r
+            EventConsumer ec = null;\r
+            try\r
+            {\r
+\r
+                ec = new EventConsumer("CUSTOM", "sofia::register_attempt", 100);\r
+                ec.bind("SHUTDOWN", String.Empty);\r
+                ec.bind("HEARTBEAT", String.Empty);\r
+                while (Running)\r
+                {\r
+                    var evt = ec.pop(0, 0);\r
+                    if (evt == null)\r
+                        continue;\r
+\r
+                    var en = evt.InternalEvent.GetValueOfHeader("Event-Name");\r
+                    if (en == "CUSTOM")\r
+                        en = evt.InternalEvent.GetValueOfHeader("Event-SubClass");\r
+                    switch (en)\r
+                    {\r
+                        case @"sofia::register_attempt":\r
+                            {\r
+                                var iev = evt.InternalEvent;\r
+                                var ar = iev.GetValueOfHeader("auth-result");  // get the value of the result to see if it's the case we want\r
+                                var ip = iev.GetValueOfHeader("network-ip");  // and the ip address the register came from\r
+                                \r
+                                if (ar == "FORBIDDEN")\r
+                                {\r
+                                    BanTracker.TrackFailure(ip);\r
+                                }\r
+                            }\r
+                            break;\r
+\r
+                        case "SHUTDOWN":\r
+                            Log.WriteLine(LogLevel.Critical,"FTB: Processing Shutdown event");\r
+                            Running = false;\r
+                            break;\r
+\r
+                        case "HEARTBEAT":\r
+                            BanTracker.CleanUp();\r
+                            break;\r
+\r
+                        default:\r
+                            break;\r
+                    }\r
+                }\r
+            }\r
+            catch (Exception exx)\r
+            {\r
+                Log.WriteLine(LogLevel.Critical, "FailToBan -- Exception in event loop {0}", exx.Message);\r
+            }\r
+            finally\r
+            {\r
+                if(ec != null)\r
+                    ec.Dispose();\r
+                _eventThread = null;\r
+            }\r
+        }\r
+    }\r
+}\r
diff --git a/src/mod/languages/mod_managed/managed/examples/winFailToBan/Fail2Ban.cs b/src/mod/languages/mod_managed/managed/examples/winFailToBan/Fail2Ban.cs
new file mode 100644 (file)
index 0000000..789fec1
--- /dev/null
@@ -0,0 +1,45 @@
+using FreeSWITCH;\r
+\r
+namespace winFailToBan\r
+{\r
+    public class Fail2Ban : IApiPlugin , ILoadNotificationPlugin\r
+    {\r
+        public void Execute(ApiContext context)\r
+        {\r
+            var cmds = context.Arguments.Split(" ".ToCharArray());\r
+            var cmd = cmds[0].ToLower();\r
+            switch (cmd)\r
+            {\r
+                case "shutdown":\r
+                    Shutdown();\r
+                    break;\r
+\r
+                default:\r
+                    context.Stream.Write("\n\nInvalid Command\n\n");\r
+                    break;\r
+            }\r
+        }\r
+\r
+        public void ExecuteBackground(ApiBackgroundContext context)\r
+        {\r
+            return;\r
+        }\r
+\r
+        public static void Startup()\r
+        {\r
+            BanTracker.Startup();\r
+            EventLoop.StartEvents();\r
+        }\r
+\r
+        public static void Shutdown()\r
+        {\r
+            EventLoop.StopEvents();\r
+        }\r
+\r
+        public bool Load()\r
+        {\r
+            Startup();\r
+            return true;\r
+        }\r
+    }\r
+}\r
diff --git a/src/mod/languages/mod_managed/managed/examples/winFailToBan/Internal/ConfigHandler.cs b/src/mod/languages/mod_managed/managed/examples/winFailToBan/Internal/ConfigHandler.cs
new file mode 100644 (file)
index 0000000..65da297
--- /dev/null
@@ -0,0 +1,83 @@
+using System;\r
+using FreeSWITCH;\r
+using FreeSWITCH.Native;\r
+\r
+namespace winFailToBan.Internal\r
+{\r
+\r
+    public class ConfigurationEventArgs : EventArgs\r
+    {\r
+        public SwitchXmlSearchBinding.XmlBindingArgs FsArgs { get; private set; }\r
+        public fsConfigDocument Result { get; set; }\r
+        public Boolean DontProcess { get; set; }\r
+\r
+        public ConfigurationEventArgs(SwitchXmlSearchBinding.XmlBindingArgs args)\r
+        {\r
+            DontProcess = false;\r
+            FsArgs = args;\r
+            Result = null;\r
+        }\r
+    }\r
+    \r
+    // Bind XML search function turned into CLR events for ease use\r
+    public class ConfigHandler : IDisposable\r
+    {\r
+        public event EventHandler<ConfigurationEventArgs> DirectoryRequest;\r
+        public event EventHandler<ConfigurationEventArgs> DialPlanRequest;\r
+\r
+        private IDisposable _binder; // object to bind to\r
+\r
+        public void Dispose()\r
+        {\r
+            if(_binder != null)\r
+                _binder.Dispose();\r
+            _binder = null;\r
+        }\r
+\r
+        public String XmlCallback(SwitchXmlSearchBinding.XmlBindingArgs args)\r
+        {\r
+            String rv = null; // return value\r
+            switch (args.Section.ToLower())\r
+            {\r
+                case "directory":\r
+                    var dargs = new ConfigurationEventArgs(args);\r
+                    if (DirectoryRequest != null)\r
+                    {\r
+                        var temp = DirectoryRequest;\r
+                        temp(this, dargs);\r
+                        if (dargs.DontProcess)\r
+                            return null;\r
+                        if (dargs.Result != null)\r
+                            rv = dargs.Result.ToXMLString();\r
+                    }\r
+                    break;\r
+\r
+                case "dialplan":\r
+                    var dialargs = new ConfigurationEventArgs(args);\r
+                    if(DialPlanRequest != null)\r
+                    {\r
+                        var temp = DialPlanRequest;\r
+                        temp(this, dialargs);\r
+                        if (dialargs.Result != null)\r
+                            rv = dialargs.Result.ToXMLString();\r
+                    }\r
+                    break;\r
+            }\r
+\r
+            return rv ?? new fsNotFoundDocument().ToXMLString();\r
+        }\r
+\r
+        ~ConfigHandler()\r
+        {\r
+            Dispose();\r
+        }\r
+\r
+        public ConfigHandler()\r
+        {\r
+            _binder = SwitchXmlSearchBinding.Bind(XmlCallback,\r
+                switch_xml_section_enum_t.SWITCH_XML_SECTION_DIRECTORY |\r
+                switch_xml_section_enum_t.SWITCH_XML_SECTION_DIALPLAN);\r
+            \r
+        }\r
+    }\r
+}\r
diff --git a/src/mod/languages/mod_managed/managed/examples/winFailToBan/Internal/ConfigHelper.cs b/src/mod/languages/mod_managed/managed/examples/winFailToBan/Internal/ConfigHelper.cs
new file mode 100644 (file)
index 0000000..bc0e039
--- /dev/null
@@ -0,0 +1,327 @@
+using System;\r
+using System.Collections.Generic;\r
+using System.IO;\r
+using System.Linq;\r
+using System.Xml.Linq;\r
+using FreeSWITCH.Native;\r
+using Stream = System.IO.Stream;\r
+\r
+namespace winFailToBan.Internal\r
+{\r
+    public abstract class fsConfigDocument\r
+    {\r
+        public XElement xmldoc;\r
+        public XElement main;\r
+\r
+        protected fsConfigDocument(String SectionName)\r
+        {\r
+            main = new XElement("wtf",\r
+                                  new XElement("document",\r
+                                               new XAttribute("type", "freeswitch/xml"),\r
+                                               new XElement("section",\r
+                                                            new XAttribute("name", SectionName),\r
+                                                            new XAttribute("description", "Auto generated")\r
+                                                   )));\r
+            xmldoc = main.Descendants("document").Single();\r
+        }\r
+\r
+        public Int64 Length()\r
+        {\r
+            return xmldoc.ToString().Length + 2;\r
+        }\r
+\r
+        public String ToXMLString()\r
+        {\r
+            return xmldoc.ToString();\r
+        }\r
+\r
+        public Int64 WriteXML(Stream outStream)\r
+        {\r
+            var wr = new StreamWriter(outStream);\r
+            wr.WriteLine(xmldoc.ToString());\r
+            wr.Flush();\r
+            return xmldoc.ToString().Length + 2;\r
+        }\r
+\r
+        public void WriteXML(TextWriter outText)\r
+        {\r
+            outText.Write(xmldoc.ToString());\r
+        }\r
+\r
+\r
+        protected void SectionChild(XElement Node)\r
+        {\r
+            // ReSharper disable PossibleNullReferenceException\r
+            if (xmldoc != null) xmldoc.Element("section").Add(Node);\r
+            // ReSharper restore PossibleNullReferenceException\r
+        }\r
+    }\r
+\r
+    public class fsNotFoundDocument : fsConfigDocument\r
+    {\r
+        public fsNotFoundDocument()\r
+            : base("result")\r
+        {\r
+            SectionChild(new XElement("result",\r
+                                      new XAttribute("status", "not found")));\r
+        }\r
+    }\r
+\r
+    public class fsDomainGatewayDirectoryDocument : fsConfigDocument\r
+    {\r
+        public fsDomainGatewayDirectoryDocument(Dictionary<String, Dictionary<String, Dictionary<String, String>>> domainGatewayList)\r
+            : base("directory")\r
+        {\r
+            if (xmldoc == null)\r
+                return;\r
+            foreach (var v in\r
+                    (from d in domainGatewayList\r
+                     select new XElement("domain",\r
+                                         new XAttribute("name", d.Key),\r
+                                         new XElement("user",\r
+                                             new XAttribute("id", "gatewaydummyser"),\r
+                                               new XElement("gateways",\r
+                                                      from g in d.Value\r
+                                                      select new XElement("gateway",\r
+                                                                          new XAttribute("name", g.Key),\r
+                                                                          from p in g.Value\r
+                                                                          select new XElement("param",\r
+                                                                                              new XAttribute(\r
+                                                                                                  "name", p.Key),\r
+                                                                                              new XAttribute(\r
+                                                                                                  "value", p.Value))))))))\r
+                xmldoc.Element("section").Add(v);\r
+        }\r
+    }\r
+\r
+    public class fsDirectoryDocument : fsConfigDocument\r
+    {\r
+        public fsDirectoryDocument(String Domain, String User, String Password)\r
+            : base("directory")\r
+        {\r
+            SectionChild(new XElement("domain",\r
+                                      new XAttribute("name", Domain),\r
+                                      new XElement("user",\r
+                                                   new XAttribute("id", User),\r
+                                                   new XElement("params",\r
+                                                                new XElement("param",\r
+                                                                             new XAttribute("name", "password"),\r
+                                                                             new XAttribute("value", Password)\r
+                                                                    )\r
+                                                       )\r
+                                          )\r
+                             ));\r
+        }\r
+        public fsDirectoryDocument(String Domain, String User, String Password, Dictionary<String, String> Params)\r
+            : this(Domain, User, Password)\r
+        {\r
+            if (Params == null)\r
+                return;\r
+            // ReSharper disable PossibleNullReferenceException\r
+            xmldoc.Element("section").Element("domain").Element("user").Element("params").Add(\r
+                // ReSharper restore PossibleNullReferenceException\r
+                from par in Params\r
+                select new XElement("param",\r
+                                    new XAttribute("name", par.Key),\r
+                                    new XAttribute("value", par.Value)));\r
+        }\r
+\r
+        public fsDirectoryDocument(String Domain, String User, String Password, Dictionary<String, String> Params, Dictionary<String, String> Variables)\r
+            : this(Domain, User, Password, Params)\r
+        {\r
+            if (Variables == null)\r
+                return;\r
+            // ReSharper disable PossibleNullReferenceException\r
+            xmldoc.Element("section").Element("domain").Element("user").Add(\r
+                // ReSharper restore PossibleNullReferenceException\r
+                new XElement("variables", from v in Variables\r
+                                          select new XElement("variable",\r
+                                                              new XAttribute("name", v.Key),\r
+                                                              new XAttribute("value", v.Value))));\r
+        }\r
+    }\r
+\r
+    public class fsDialPlanDocument : fsConfigDocument\r
+    {\r
+\r
+        private static XElement MakeActionNode(String ActionString)\r
+        {\r
+            var p = ActionString.Split(",".ToCharArray(), 2);\r
+            var rv = new XElement("action",\r
+                                  new XAttribute("application", p[0]));\r
+            if (p.Length > 1)\r
+                rv.Add(new XAttribute("data", p[1]));\r
+            return rv;\r
+        }\r
+\r
+        public fsDialPlanDocument(String Context, IEnumerable<String> Actions)\r
+            : base("dialplan")\r
+        {\r
+            SectionChild(new XElement("context",\r
+                                      new XAttribute("name", Context),\r
+                                      new XElement("extension",\r
+                                                   new XAttribute("name", "extension"),\r
+                                                   new XElement("condition",\r
+                                                                from act in Actions\r
+                                                                select MakeActionNode(act)))));\r
+        }\r
+    }\r
+\r
+    public static class ConfigExtensions\r
+    {\r
+        public static switch_event_header GetHeader(this switch_event e, String HeaderName)\r
+        {\r
+            for (var x = e.headers; x != null; x = x.next)\r
+            {\r
+                if (HeaderName.ToLower() == x.name.ToLower())\r
+                    return x;\r
+            }\r
+            return null;\r
+        }\r
+\r
+        public static String GetValueOfHeader(this switch_event e, String headerName, String defaultValue = "")\r
+        {\r
+            var head = e.GetHeader(headerName);\r
+            return (head == null ? defaultValue : head.value);\r
+        }\r
+\r
+        public static Boolean GetBooleanHeader(this switch_event e, String headerName)\r
+        {\r
+            var hv = e.GetValueOfHeader(headerName);\r
+            hv = (String.IsNullOrEmpty(hv) ? "false" : hv);\r
+            Boolean rv = false;\r
+            Boolean.TryParse(hv, out rv);\r
+            return rv;\r
+        }\r
+\r
+        public static Guid GetUUID(this Event e)\r
+        {\r
+            var idfld = e.GetHeader("Unique-ID");\r
+            return String.IsNullOrEmpty(idfld) ? Guid.Empty : new Guid(idfld);\r
+        }\r
+\r
+        public static void ForEach(this switch_event e, Action<String, String> action)\r
+        {\r
+            for (var x = e.headers; x != null; x = x.next)\r
+            {\r
+                action(x.name, x.value);\r
+            }\r
+        }\r
+\r
+        public static Guid GetGuid(this switch_event e)\r
+        {\r
+            return e.GetHeader("Unique-ID") == null ? Guid.Empty : Guid.Parse(e.GetHeader("Unique-ID").value);\r
+        }\r
+\r
+        public static void Dump(this switch_event e)\r
+        {\r
+            e.ForEach((n, v) => Console.WriteLine("{0}={1}", n, v));\r
+        }\r
+\r
+        public static Dictionary<String, String> ExtractVars(this switch_event e)\r
+        {\r
+            var r = new Dictionary<String, String>();\r
+            for (var x = e.headers; x != null; x = x.next)\r
+            {\r
+                if (x.name.StartsWith("variable_"))\r
+                {\r
+                    r.Add(x.name.ToLower().Replace("variable_", String.Empty),\r
+                          x.value);\r
+                }\r
+            }\r
+            return r;\r
+        }\r
+\r
+        public static String ModDigits(this String Orig, int qdel, String Prefix)\r
+        {\r
+            var rv = Orig;\r
+            rv = qdel > Orig.Length ? String.Empty : rv.Substring(qdel);\r
+            if (!String.IsNullOrEmpty(Prefix))\r
+                rv = Prefix + rv;\r
+            return rv;\r
+        }\r
+\r
+        //public static String RoutingReplace(this String Orig, String Orignal, String Modified)\r
+        //{\r
+        //    var rv = Orig;\r
+        //    rv = rv.Replace("%d", Modified);\r
+        //    rv = rv.Replace("%o", Orignal);\r
+        //    return rv;\r
+        //}\r
+\r
+        public static void MergeFrom<TKey, TValue>(\r
+            this Dictionary<TKey, TValue> dict,\r
+            Dictionary<TKey, TValue> src\r
+            )\r
+        {\r
+            foreach (var entry in src)\r
+            {\r
+                if (!dict.ContainsKey(entry.Key))\r
+                    dict.Add(entry.Key, entry.Value);\r
+            }\r
+        }\r
+\r
+        public static void RemoveKeysIn<TKey, TValue>(\r
+            this Dictionary<TKey, TValue> dict,\r
+            IEnumerable<TKey> keys\r
+            )\r
+        {\r
+            foreach (var k in keys)\r
+                if (dict.ContainsKey(k))\r
+                    dict.Remove(k);\r
+        }\r
+\r
+        public static void AddVariableTextList(this Dictionary<String, String> d, String varslist)\r
+        {\r
+            if (d == null || String.IsNullOrEmpty(varslist))\r
+                return;\r
+            foreach (var vardef in varslist.Split(",".ToCharArray()))\r
+            {\r
+                var args = vardef.Split("=".ToCharArray(), 2);\r
+                if (!d.ContainsKey(args[0]))\r
+                {\r
+                    d.Add(args[0], args[1]);\r
+                }\r
+                else\r
+                {\r
+                    d[args[0]] = args[1];\r
+                }\r
+            }\r
+        }\r
+\r
+        public static String ToParamString(this Dictionary<String, String> d)\r
+        {\r
+            var firstPart = new List<String>();\r
+            foreach (var e in d)\r
+            {\r
+                firstPart.Add(String.Format("{0}={1}", e.Key, e.Value));\r
+            }\r
+            var rv = String.Join(",", firstPart.ToArray());\r
+            return rv;\r
+        }\r
+\r
+        public static String ToChannelVars(this Dictionary<String, String> d, Boolean bLocal)\r
+        {\r
+            if (d == null || d.Count == 0)\r
+                return String.Empty;\r
+            String fmt;\r
+            if (bLocal)\r
+                fmt = "[{0}]";\r
+            else\r
+                fmt = "{{{0}}}";\r
+            return String.Format(fmt, d.ToParamString());\r
+        }\r
+\r
+        public static void AddActions(this List<String> l, params String[] strings)\r
+        {\r
+            String seperator = "^";\r
+            foreach (var s in strings)\r
+            {\r
+                if (String.IsNullOrEmpty(s))\r
+                    continue;\r
+                l.AddRange(s.Split(seperator.ToCharArray()));\r
+            }\r
+        }\r
+    }\r
+\r
+}\r
diff --git a/src/mod/languages/mod_managed/managed/examples/winFailToBan/Properties/AssemblyInfo.cs b/src/mod/languages/mod_managed/managed/examples/winFailToBan/Properties/AssemblyInfo.cs
new file mode 100644 (file)
index 0000000..6036cbd
--- /dev/null
@@ -0,0 +1,36 @@
+using System.Reflection;\r
+using System.Runtime.CompilerServices;\r
+using System.Runtime.InteropServices;\r
+\r
+// General Information about an assembly is controlled through the following \r
+// set of attributes. Change these attribute values to modify the information\r
+// associated with an assembly.\r
+[assembly: AssemblyTitle("winFailToBan")]\r
+[assembly: AssemblyDescription("")]\r
+[assembly: AssemblyConfiguration("")]\r
+[assembly: AssemblyCompany("")]\r
+[assembly: AssemblyProduct("winFailToBan")]\r
+[assembly: AssemblyCopyright("Copyright ©  2012")]\r
+[assembly: AssemblyTrademark("")]\r
+[assembly: AssemblyCulture("")]\r
+\r
+// Setting ComVisible to false makes the types in this assembly not visible \r
+// to COM components.  If you need to access a type in this assembly from \r
+// COM, set the ComVisible attribute to true on that type.\r
+[assembly: ComVisible(false)]\r
+\r
+// The following GUID is for the ID of the typelib if this project is exposed to COM\r
+[assembly: Guid("a171cab9-d773-4070-9993-26a581c6f243")]\r
+\r
+// Version information for an assembly consists of the following four values:\r
+//\r
+//      Major Version\r
+//      Minor Version \r
+//      Build Number\r
+//      Revision\r
+//\r
+// You can specify all the values or you can default the Build and Revision Numbers \r
+// by using the '*' as shown below:\r
+// [assembly: AssemblyVersion("1.0.*")]\r
+[assembly: AssemblyVersion("1.0.0.0")]\r
+[assembly: AssemblyFileVersion("1.0.0.0")]\r
diff --git a/src/mod/languages/mod_managed/managed/examples/winFailToBan/packages.config b/src/mod/languages/mod_managed/managed/examples/winFailToBan/packages.config
new file mode 100644 (file)
index 0000000..8412e63
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<packages>\r
+  <package id="FreeSWITCHManaged.LibCS" version="1.0.1.10" targetFramework="net40" />\r
+</packages>
\ No newline at end of file
diff --git a/src/mod/languages/mod_managed/managed/examples/winFailToBan/skel.cs b/src/mod/languages/mod_managed/managed/examples/winFailToBan/skel.cs
new file mode 100644 (file)
index 0000000..ca622b7
--- /dev/null
@@ -0,0 +1,166 @@
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using FreeSWITCH;\r
+using winFailToBan.Internal;\r
+\r
+namespace winFailToBan\r
+{\r
+    public class SampleApp : IAppPlugin\r
+    {\r
+        // example class for a dialplan APP just implment the run method\r
+        public void Run(AppContext context)\r
+        {\r
+            var s = context.Session;\r
+            var args = context.Arguments;\r
+            // Do something with them here\r
+        }\r
+    }\r
+\r
+    // Example class to implment an API command\r
+    public class SampleApi : IApiPlugin\r
+    {\r
+        public void Execute(ApiContext context)\r
+        {\r
+            throw new NotImplementedException();\r
+        }\r
+\r
+        public void ExecuteBackground(ApiBackgroundContext context)\r
+        {\r
+            throw new NotImplementedException();\r
+        }\r
+    }\r
+\r
+    // This examle class can be used to handle XML config lookups for dialplan and directory\r
+\r
+    public class SampleConfigHandler : ILoadNotificationPlugin\r
+    {\r
+        private static ConfigHandler MyConfigHandler;\r
+\r
+        static void HandleDirectoryLookups(Object sender, ConfigurationEventArgs e)\r
+        {\r
+            e.Result = null; // not found example just return after this\r
+            // return;  // uncomment to just return not-fouond\r
+\r
+            // return a directory object that will work\r
+            var evt = e.FsArgs.Parameters; // Get the raw event that generated the userDir lookup\r
+            var eventName = evt.GetHeader("Event-Name").value; // Find the event name\r
+\r
+            // If your module handles voicemail authorization then implment the following\r
+            // to update the voicemail password, when they change their voicemail password using TUI\r
+            if (eventName == "CUSTOM")\r
+            {\r
+                var subClass = evt.GetValueOfHeader("Event-Subclass");\r
+                if (subClass == "vm::maintenance")\r
+                {\r
+                    var vmaction = evt.GetValueOfHeader("VM-Actoun");\r
+                    var username = evt.GetValueOfHeader("VM-User");\r
+                    var newPassword = evt.GetValueOfHeader("VM-User-Password");\r
+                    if (vmaction == "change-password" && !string.IsNullOrEmpty(username) &&\r
+                        !String.IsNullOrEmpty(newPassword))\r
+                    {\r
+                        // implment your code to update the users vm password in your database\r
+                        return; // No more processing we don't actually do an auth just a notification\r
+                    }\r
+                }\r
+            }\r
+\r
+            // to make sure we don't have some future events messing us up...\r
+            if (eventName != "REQUEST_PARAMS" && eventName != "GENERAL")\r
+                return;\r
+\r
+            // implment the following if you want to handle gateway lookup from directory when a profile loads\r
+            if (evt.GetValueOfHeader("purpose") == "gateways")\r
+            {\r
+                var profileName = evt.GetValueOfHeader("profile");\r
+                // implment your gateway lookup\r
+                //e.Result = new fsDomainGatewayDirectoryDocument(myGwStructure);\r
+                return;\r
+            }\r
+\r
+            var action = evt.GetValueOfHeader("action", "none"); // get the action\r
+\r
+            // If you want to handle ESL Logins implment the following\r
+            if (action == "event_socket_auth")\r
+            {\r
+                // preform your stuff here\r
+                // e.result = ...\r
+                return;\r
+            }\r
+\r
+            // Normal lookup processing\r
+            if (evt.GetHeader("user") == null || evt.GetHeader("domain") == null)\r
+                return; // does't have required fields\r
+            var method = evt.GetValueOfHeader("sip_auth_method", "unknown");\r
+            var user = evt.GetValueOfHeader("user");\r
+            var domain = evt.GetValueOfHeader("domain");\r
+\r
+            // Some variables to return the params and variables section of the user record\r
+            var variables = new Dictionary<String, String>();\r
+            var uparams = new Dictionary<String, String>();\r
+\r
+\r
+            // if you're implmenting reverse-auth of devices\r
+            if (action == "reverse-auth-lookup")\r
+            {\r
+                // lookup stuff in your db\r
+                uparams.Add("reverse-auth-user", "device uername");\r
+                uparams.Add("reverse-auth-pass", "device password");\r
+            }\r
+\r
+            // if you handle voicemail passwords ...\r
+            if (true /*check for voicemail box */)\r
+            {\r
+                uparams.Add("vm-password", "theirvmpassword");\r
+                // the following is optional\r
+                uparams.Add("MWI-Account", "registrationstring");\r
+            }\r
+            // add more parameters here\r
+            uparams.Add("anyotherparameters", "value");\r
+\r
+            // add variables here for example\r
+            variables.Add("user_context", "theuserscontext");\r
+\r
+            e.Result = new fsDirectoryDocument(\r
+                domain,\r
+                user,\r
+                "theirpassword",\r
+                uparams,\r
+                variables);\r
+\r
+            return;\r
+        }\r
+\r
+        // Example dialplan handler\r
+        static void HandleDialPlanRequest(object sender, ConfigurationEventArgs e)\r
+        {\r
+            var evt = e.FsArgs.Parameters; // get the native event that caused this dialplan lookup\r
+\r
+            // extract the minimum variables you will need\r
+            var context = evt.GetValueOfHeader("Hunt-Context"); // the context\r
+            var destination = evt.GetValueOfHeader("Hunt-Destination-Number"); // the dialed number or "DID"\r
+            var ani = evt.GetValueOfHeader("Hunt-ANI"); // The ANI/CallerID number\r
+\r
+            // A place to return the dialplan actions you want\r
+            var actions = new List<String>(); // format is "app,data"\r
+\r
+            // add the actions for your code they shouldn't be static this is just an example\r
+            actions.Add("set,continue_on_fail=true");\r
+            actions.Add("brige,sofia/mygateway/" + destination);\r
+            actions.Add("transfer,fialedDest XML failedcontext");\r
+            e.Result = new fsDialPlanDocument(context, actions);\r
+            return; // Isn't this easy?\r
+        }\r
+\r
+        public bool Load()\r
+        {\r
+            // Start any threads doing event consumer loops\r
+            MyConfigHandler = new ConfigHandler(); // init a config handler\r
+            MyConfigHandler.DirectoryRequest += HandleDirectoryLookups;\r
+            MyConfigHandler.DialPlanRequest += HandleDialPlanRequest;\r
+            return true;\r
+        }\r
+    }\r
+\r
+}\r
diff --git a/src/mod/languages/mod_managed/managed/examples/winFailToBan/winFailToBan.csproj b/src/mod/languages/mod_managed/managed/examples/winFailToBan/winFailToBan.csproj
new file mode 100644 (file)
index 0000000..664b221
--- /dev/null
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <PropertyGroup>\r
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>\r
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>\r
+    <ProductVersion>8.0.30703</ProductVersion>\r
+    <SchemaVersion>2.0</SchemaVersion>\r
+    <ProjectGuid>{5BA0D5BD-330D-4EE2-B959-CAFEA04E50E0}</ProjectGuid>\r
+    <OutputType>Library</OutputType>\r
+    <AppDesignerFolder>Properties</AppDesignerFolder>\r
+    <RootNamespace>winFailToBan</RootNamespace>\r
+    <AssemblyName>winFailToBan</AssemblyName>\r
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>\r
+    <FileAlignment>512</FileAlignment>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">\r
+    <DebugSymbols>true</DebugSymbols>\r
+    <DebugType>full</DebugType>\r
+    <Optimize>false</Optimize>\r
+    <OutputPath>bin\Debug\</OutputPath>\r
+    <DefineConstants>DEBUG;TRACE</DefineConstants>\r
+    <ErrorReport>prompt</ErrorReport>\r
+    <WarningLevel>4</WarningLevel>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">\r
+    <DebugType>pdbonly</DebugType>\r
+    <Optimize>true</Optimize>\r
+    <OutputPath>bin\Release\</OutputPath>\r
+    <DefineConstants>TRACE</DefineConstants>\r
+    <ErrorReport>prompt</ErrorReport>\r
+    <WarningLevel>4</WarningLevel>\r
+  </PropertyGroup>\r
+  <ItemGroup>\r
+    <Reference Include="System" />\r
+    <Reference Include="System.Core" />\r
+    <Reference Include="System.Xml.Linq" />\r
+    <Reference Include="System.Data.DataSetExtensions" />\r
+    <Reference Include="Microsoft.CSharp" />\r
+    <Reference Include="System.Data" />\r
+    <Reference Include="System.Xml" />\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <Compile Include="BanTracker.cs" />\r
+    <Compile Include="EventLoop.cs" />\r
+    <Compile Include="Fail2Ban.cs" />\r
+    <Compile Include="Internal\ConfigHandler.cs" />\r
+    <Compile Include="Internal\ConfigHelper.cs" />\r
+    <Compile Include="Properties\AssemblyInfo.cs" />\r
+    <None Include="skel.cs" />\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <None Include="packages.config" />\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ProjectReference Include="..\..\FreeSWITCH.Managed.2012.csproj">\r
+      <Project>{834e2b2f-5483-4b80-8fe3-fe48ff76e5c0}</Project>\r
+      <Name>FreeSWITCH.Managed.2012</Name>\r
+    </ProjectReference>\r
+  </ItemGroup>\r
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />\r
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. \r
+       Other similar extension points exist, see Microsoft.Common.targets.\r
+  <Target Name="BeforeBuild">\r
+  </Target>\r
+  <Target Name="AfterBuild">\r
+  </Target>\r
+  -->\r
+</Project>
\ No newline at end of file