Generate URLs for Libravatar and Gravatar avatars
1# SPDX-FileCopyrightText: 2024 Łukasz Niemier <#@hauleth.dev>
2#
3# SPDX-License-Identifier: MPL-2.0
4
5defmodule AwwTest.Dns do
6 use GenServer
7
8 @callback handle_query(
9 String.t(),
10 :inet_req.dns_class(),
11 :inet_req.dns_rr_type()
12 ) :: map()
13
14 def start_link(module: mod) do
15 with {:ok, pid} <- GenServer.start_link(__MODULE__, mod) do
16 {:ok, pid, ns(pid)}
17 end
18 end
19
20 def ns(pid), do: GenServer.call(pid, :name)
21
22 def init(mod) do
23 {:ok, sock} = :gen_udp.open(0, mode: :binary)
24
25 {:ok, %{sock: sock, mod: mod}}
26 end
27
28 def handle_call(:name, _ref, state) do
29 {:ok, name} = :inet.sockname(state.sock)
30
31 {:reply, name, state}
32 end
33
34 def handle_info({:udp, sock, from_ip, from_port, data}, %{sock: sock} = state) do
35 with {:ok, req} <- :inet_dns.decode(data) do
36 req = :inet_dns.msg(req)
37 header = :inet_dns.header(req[:header])
38 questions = req[:qdlist]
39
40 answers =
41 for q <- questions,
42 query = :inet_dns.dns_query(q),
43 answer <- handle(state, query) do
44 :inet_dns.make_rr(answer)
45 end
46
47 resp_header =
48 :inet_dns.make_header(
49 id: header[:id],
50 aa: false,
51 qr: true,
52 rd: true,
53 ra: true,
54 opcode: :query,
55 rcode: 0
56 )
57
58 resp =
59 :inet_dns.make_msg(
60 header: resp_header,
61 qdlist: questions,
62 anlist: answers
63 )
64
65 :gen_udp.send(sock, from_ip, from_port, :inet_dns.encode(resp))
66 end
67
68 {:noreply, state}
69 end
70
71 defp handle(%{mod: mod}, query) do
72 domain = query[:domain]
73 class = query[:class]
74 type = query[:type]
75
76 resp =
77 try do
78 mod.handle_query(List.to_string(domain), class, type)
79 catch
80 _, _ -> []
81 end
82
83 for %{ttl: ttl, data: data} <- List.wrap(resp) do
84 [domain: domain, type: type, class: class, ttl: ttl, data: data]
85 end
86 end
87end