Created
August 6, 2025 15:17
-
-
Save shaltielshmid/6a9e2a67b6c28e0ce5cf1917326e5aa6 to your computer and use it in GitHub Desktop.
Reproduction of LLM-over-DNS in C# 10
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #:package ARSoft.Tools.Net@3.6.1 | |
| #:package LLMTornado@3.7.25 | |
| using ARSoft.Tools.Net; | |
| using ARSoft.Tools.Net.Dns; | |
| using LlmTornado.Code; | |
| using LlmTornado; | |
| using LlmTornado.Chat; | |
| (string EnvKey, LLmProviders Provider)[] Providers = [ | |
| ("GOOGLE_API_KEY", LLmProviders.Google), | |
| ("OAI_API_KEY", LLmProviders.OpenAi), | |
| ("ANTHROPIC_API_KEY", LLmProviders.Anthropic), | |
| ("OPENROUTER_API_KEY", LLmProviders.OpenRouter), | |
| ("COHERE_API_KEY", LLmProviders.Cohere), | |
| ("GROQ_API_KEY", LLmProviders.Groq), | |
| ("DEEPSEEK_API_KEY", LLmProviders.DeepSeek), | |
| ("MISTRAL_API_KEY", LLmProviders.Mistral), | |
| ("XAI_API_KEY", LLmProviders.XAi), | |
| ("PERPLEXITY_API_KEY", LLmProviders.Perplexity) | |
| ]; | |
| // Get the model | |
| string? model = Environment.GetEnvironmentVariable("LLM_MODEL"); | |
| if (string.IsNullOrWhiteSpace(model)) | |
| throw new ArgumentException("LLM_MODEL configuration is required."); | |
| // Get the configured provider (Will throw error if not found) | |
| var provider = Providers.First(p => !string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable(p.EnvKey))); | |
| var api = new TornadoApi(Environment.GetEnvironmentVariable(provider.EnvKey)!, provider.Provider); | |
| var server = new DnsServer(); | |
| server.QueryReceived += async (object sender, QueryReceivedEventArgs e) => { | |
| try { | |
| var query = e.Query as DnsMessage ?? throw new ArgumentException("Query is not a valid DNS message."); | |
| if (query.Questions.Count != 1 || query.Questions[0].RecordType != RecordType.Txt) | |
| return; | |
| var response = query.CreateResponseInstance(); | |
| e.Response = response; | |
| var domain = query.Questions[0].Name; | |
| var llmResult = await api.Chat.CreateConversation(model) | |
| .AppendAssistantMessage("You are a helpful assistant who responds very very concisely.") | |
| .AppendUserInput(domain.ToString()) | |
| .GetResponseRich(); | |
| // Break it up into chunks of 250 chars (TODO: handle bytes) | |
| int offset = 0; | |
| while (offset < llmResult.Text.Length) { | |
| response.AnswerRecords.Add(new TxtRecord(domain, 3600, llmResult.Text[offset..Math.Min(llmResult.Text.Length, offset + 250)])); | |
| offset += 250; | |
| } | |
| response.ReturnCode = ReturnCode.NoError; | |
| } | |
| catch (Exception ex) { | |
| Console.WriteLine("Error processing DNS query: " + ex.Message); | |
| } | |
| }; | |
| server.Start(); | |
| Console.WriteLine("DNS server started on port 53"); | |
| try { | |
| await Task.Delay(Timeout.Infinite, CancellationToken.None); | |
| } | |
| finally { | |
| server.Stop(); | |
| Console.WriteLine("DNS server stopped"); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment