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
{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
{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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+<?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
--- /dev/null
+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
--- /dev/null
+<?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