Wiki » Historique » Version 34
jonathan.certes, 29/04/2024 18:28
Modif du script de post_hook pour copier le certificat renouvelé sur pan2.
1 | 5 | sacha | {{>toc}} |
---|---|---|---|
2 | |||
3 | 9 | sacha | # DNS récursif Ouvert DoH DoT & haute disponibilité |
4 | 15 | sacha | **45.67.81.23 - dns.aquilenet.fr** |
5 | 14 | sacha | |
6 | 1 | sacha | |
7 | 16 | sacha | |
8 | 19 | sacha | On propos un DNS récursif ouvert cf https://www.aquilenet.fr/services/dns/ https://dns.aquilenet.fr/ |
9 | 18 | sacha | On a mis aussi un DNS ouvert sur l'IP 45.67.81.23 car facile à retenir, avec l'adresse de dns.aquilenet.fr (voir [http://dns.aquilenet.fr](http://dns.aquilenet.fr)) . Nous en avons profité pour ajouter [DoH](https://fr.wikipedia.org/wiki/DNS_over_HTTPS) et [DoT](https://fr.wikipedia.org/wiki/DNS_over_TLS) et d'avoir cette adresse en IP Virtuelle partagée entre pan1 et pan2. |
10 | Cette IP virtuelle est portée par Keepalived sur pan1 le primaire et pan2 le secondaire. Si le démon Keepalived est arrêté sur pan1, l'ip bascule sur pan2. Si on redémarre le démon sur pan1, ce dernier reprend l'IP: pratique pour les mises à jour, le service continue à fonctionner. |
||
11 | 1 | sacha | |
12 | 19 | sacha | Pan[1|2] portent l'ip 45.67.81.23 gracieusement offerte par les copains de https://yaal.coop/fr un vlan est dédié sur ce réseau de l'hyperviseur. |
13 | 6 | sacha | |
14 | 18 | sacha | ## Configurations communes à pan1 et pan2 |
15 | 1 | sacha | |
16 | 18 | sacha | ### Nginx |
17 | 1 | sacha | |
18 | 19 | sacha | * /etc/nginx/sites-enabled/default |
19 | 1 | sacha | |
20 | |||
21 | ~~~ |
||
22 | server { |
||
23 | 19 | sacha | listen 45.67.81.23:80 ; |
24 | 27 | sacha | listen [2a0c:e300::1337]:80 ; |
25 | 1 | sacha | |
26 | 19 | sacha | location ~ /.well-known/acme-challenge { |
27 | allow all; |
||
28 | root /var/www/letsencrypt; |
||
29 | } |
||
30 | location / { |
||
31 | return 301 https://dns.aquilenet.fr; |
||
32 | } |
||
33 | 1 | sacha | |
34 | 19 | sacha | server_name dns.aquilenet.fr; # managed by Certbot |
35 | 1 | sacha | |
36 | 19 | sacha | location ~ /.well-known/acme-challenge { |
37 | allow all; |
||
38 | root /var/www/letsencrypt; |
||
39 | } |
||
40 | } |
||
41 | server { |
||
42 | listen 45.67.81.23:443 ssl http2; |
||
43 | 27 | sacha | listen [2a0c:e300::1337]:443 ssl http2; |
44 | 19 | sacha | root /var/www/dns.aquilenet.fr; |
45 | index index.htm; |
||
46 | 1 | sacha | |
47 | 19 | sacha | ssl_certificate /etc/unbound/ssl/dns.aquilenet.fr/fullchain.pem; |
48 | ssl_certificate_key /etc/unbound/ssl/dns.aquilenet.fr/privkey.pem; |
||
49 | location /dns-query { |
||
50 | grpc_pass grpc://127.0.0.1:443; |
||
51 | } |
||
52 | } |
||
53 | |||
54 | 1 | sacha | ~~~ |
55 | |||
56 | ### Unbound |
||
57 | |||
58 | ~~~ |
||
59 | 19 | sacha | include-toplevel: "/etc/unbound/unbound.conf.d/*.conf" |
60 | |||
61 | server: |
||
62 | verbosity: 1 |
||
63 | |||
64 | 28 | sacha | access-control: 0.0.0.0/0 allow |
65 | access-control: ::/0 allow |
||
66 | 19 | sacha | interface: 45.67.81.23 |
67 | 28 | sacha | # interface: 45.67.81.23@443 # on nginx |
68 | 19 | sacha | interface: 45.67.81.23@853 |
69 | 28 | sacha | interface: 2a0c:e300::1337 |
70 | interface: 2a0c:e300::1337@853 |
||
71 | 19 | sacha | |
72 | http-notls-downstream: yes |
||
73 | interface: 127.0.0.1@443 |
||
74 | 28 | sacha | interface: ::1@443 |
75 | 19 | sacha | |
76 | port: 53 |
||
77 | tls-port: 853 |
||
78 | https-port: 443 |
||
79 | |||
80 | root-hints: "/usr/share/dns/root.hints" |
||
81 | 28 | sacha | |
82 | # ip-rate-limit: 10 |
||
83 | 19 | sacha | harden-glue: yes |
84 | harden-large-queries: yes |
||
85 | harden-dnssec-stripped: yes |
||
86 | harden-below-nxdomain: yes |
||
87 | harden-referral-path: yes |
||
88 | harden-algo-downgrade: no # false positives with improperly configured zones |
||
89 | use-caps-for-id: no # makes lots of queries fail |
||
90 | 1 | sacha | edns-buffer-size: 1232 |
91 | rrset-roundrobin: yes |
||
92 | 19 | sacha | cache-min-ttl: 300 |
93 | cache-max-ttl: 86400 |
||
94 | serve-expired: yes |
||
95 | harden-algo-downgrade: yes |
||
96 | harden-short-bufsize: yes |
||
97 | hide-identity: yes |
||
98 | identity: "dns.aquilenet.fr" |
||
99 | hide-version: yes |
||
100 | do-daemonize: no |
||
101 | neg-cache-size: 4m |
||
102 | qname-minimisation: yes |
||
103 | deny-any: yes |
||
104 | minimal-responses: yes |
||
105 | prefetch: yes |
||
106 | prefetch-key: yes |
||
107 | num-threads: 2 |
||
108 | msg-cache-size: 50m |
||
109 | rrset-cache-size: 100m |
||
110 | so-reuseport: yes |
||
111 | so-rcvbuf: 4m |
||
112 | so-sndbuf: 4m |
||
113 | unwanted-reply-threshold: 100000 |
||
114 | log-queries: no |
||
115 | log-replies: no |
||
116 | log-servfail: no |
||
117 | log-local-actions: no |
||
118 | logfile: /dev/null |
||
119 | |||
120 | # imposer la QNAME minimisation (RFC 7816) |
||
121 | qname-minimisation: yes |
||
122 | # même si le serveur faisant autorité ne le veut pas |
||
123 | # après discussion, il est possible que cette option ne soit |
||
124 | # pas recommandée dans le cadre d'un résolveur ouvert |
||
125 | qname-minimisation-strict: yes |
||
126 | |||
127 | # DoH |
||
128 | 28 | sacha | tls-service-key: "/etc/unbound/ssl/dns.aquilenet.fr/privkey.pem" |
129 | tls-service-pem: "/etc/unbound/ssl/dns.aquilenet.fr/cert.pem" |
||
130 | 19 | sacha | |
131 | 1 | sacha | ~~~ |
132 | |||
133 | ### AppArmor |
||
134 | |||
135 | * /etc/apparmor.d/usr.sbin.unbound |
||
136 | décomenter: |
||
137 | include <local/usr.sbin.unbound> |
||
138 | |||
139 | * /etc/apparmor.d/local/usr.sbin.unbound |
||
140 | ~~~ |
||
141 | /etc/letsencrypt/archive/** r, |
||
142 | /etc/letsencrypt/live/** r, |
||
143 | ~~~ |
||
144 | appliquer avec: `apparmor_parser -r /etc/apparmor.d/usr.sbin.unbound` |
||
145 | |||
146 | ### Iptables |
||
147 | |||
148 | 29 | sacha | * /etc/iptables/rules.v4 |
149 | |||
150 | 1 | sacha | ~~~ |
151 | 19 | sacha | *filter |
152 | :INPUT DROP |
||
153 | :FORWARD DROP |
||
154 | :OUTPUT ACCEPT |
||
155 | |||
156 | -A INPUT ! -i lo -s 127.0.0.0/8 -j DROP |
||
157 | -A INPUT -s 0.0.0.0 -i eth0 -j DROP |
||
158 | -A INPUT -d 0.0.0.0 -i eth0 -j DROP |
||
159 | -A INPUT -s 255.255.255.255 -i eth0 -j DROP |
||
160 | -A INPUT -d 255.255.255.255 -i eth0 -j DROP |
||
161 | -A INPUT -m conntrack --ctstate INVALID -j DROP |
||
162 | |||
163 | -A INPUT -p tcp -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT |
||
164 | -A INPUT -p udp ! --dport 53 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT |
||
165 | -A INPUT -i lo -j ACCEPT |
||
166 | -A OUTPUT -o lo -j ACCEPT |
||
167 | |||
168 | # SSH no more 10 attempts in 3 min |
||
169 | -A INPUT -i eth0 -p tcp --dport 55555 -m recent --name SSH --update --hitcount 10 --seconds 180 -j DROP |
||
170 | -A INPUT -i eth0 -p tcp --dport 55555 -m recent --name SSH --set -j ACCEPT |
||
171 | |||
172 | 1 | sacha | # Web |
173 | -A INPUT -p tcp --dport 80 -j ACCEPT |
||
174 | 19 | sacha | |
175 | # smtp |
||
176 | -A INPUT -i eth0 -p tcp --dport 25 -j ACCEPT |
||
177 | # smtps |
||
178 | -A INPUT -i eth0 -p tcp --dport 465 -j ACCEPT |
||
179 | # submission |
||
180 | -A INPUT -i eth0 -p tcp --dport 587 -j ACCEPT |
||
181 | |||
182 | # DNS |
||
183 | # récursif, lisible par nos abonnés seulement |
||
184 | -N dns_limit |
||
185 | -A dns_limit -s 185.233.100.0/22 -j ACCEPT |
||
186 | 7 | sacha | -A INPUT -d 45.67.81.23 -p tcp -m tcp --dport 53 -j dns_limit |
187 | -A INPUT -d 45.67.81.23 -p udp -m udp --dport 53 -j dns_limit |
||
188 | -A INPUT -d 45.67.81.23 -p tcp -m tcp --dport 443 -j dns_limit |
||
189 | -A INPUT -d 45.67.81.23 -p tcp -m tcp --dport 853 -j dns_limit |
||
190 | 19 | sacha | |
191 | # mais aussi par le reste d'Internet, mais en rate-limit |
||
192 | -A dns_limit -m string --algo bm --hex-string "|00 00 ff 00 01|" --from 28 -m hashlimit --hashlimit-above 1/sec --hashlimit-burst 2 --hashlimit-mode srcip --hashlimit-name RL-DNS-ANY-v4 --hashlimit-srcmask 28 -m comment --comment "RATE-LIMIT DNS ANY QTYPE 1/s burst 2" -j DROP |
||
193 | -A dns_limit -m string --algo bm --hex-string "|00 00 ff 00 01|" --from 28 -m hashlimit --hashlimit-above 20/min --hashlimit-mode srcip --hashlimit-name RL-DNS-ANY-v4-LOG --hashlimit-srcmask 28 -m comment --comment "RATE-LIMIT DNS ANY QTYPE 20/min" -j LOG --log-prefix "DNS-FLOOD " |
||
194 | -A dns_limit -m hashlimit --hashlimit-above 10/sec --hashlimit-burst 100 --hashlimit-mode srcip --hashlimit-name DNS --hashlimit-srcmask 28 -m comment --comment "RATE-LIMIT DNS 10/src burst 100" -j DROP |
||
195 | -A dns_limit -j ACCEPT |
||
196 | |||
197 | # ICMP |
||
198 | -A INPUT -p icmp -j ACCEPT |
||
199 | -A INPUT -p icmp --icmp-type echo-request -m limit --limit 1/s -j ACCEPT |
||
200 | |||
201 | # NRPE |
||
202 | -A INPUT -s 185.233.100.230 -p tcp --dport 5666 -j ACCEPT |
||
203 | |||
204 | # Keepalived |
||
205 | -A INPUT -s 45.67.81.0/24 -p vrrp -j ACCEPT |
||
206 | 29 | sacha | |
207 | COMMIT |
||
208 | ~~~ |
||
209 | |||
210 | * /etc/iptables/rules.v6 |
||
211 | |||
212 | ~~~ |
||
213 | *filter |
||
214 | :INPUT DROP |
||
215 | :FORWARD DROP |
||
216 | :OUTPUT ACCEPT |
||
217 | |||
218 | -A INPUT -m conntrack --ctstate INVALID -j DROP |
||
219 | |||
220 | -A INPUT -p tcp -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT |
||
221 | -A INPUT -p udp ! --dport 53 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT |
||
222 | -A INPUT -i lo -j ACCEPT |
||
223 | -A OUTPUT -o lo -j ACCEPT |
||
224 | |||
225 | # SSH no more 10 attempts in 3 min |
||
226 | -A INPUT -i enX1 -p tcp --dport 55555 -m recent --name SSH --update --hitcount 10 --seconds 180 -j DROP |
||
227 | -A INPUT -i enX1 -p tcp --dport 55555 -m recent --name SSH --set -j ACCEPT |
||
228 | |||
229 | # Web |
||
230 | -A INPUT -i enX1 -p tcp --dport 80 -j ACCEPT |
||
231 | # DNS |
||
232 | # Autorité, lisible par tout le monde |
||
233 | -A INPUT -d 2a0c:e300::2 -p tcp -m tcp --dport 53 -j ACCEPT |
||
234 | -A INPUT -d 2a0c:e300::2 -p udp -m udp --dport 53 -j ACCEPT |
||
235 | |||
236 | # récursif, lisible par nos abonnés seulement |
||
237 | -N dns_limit |
||
238 | -A INPUT -d 2a0c:e300::1337 -p tcp -m tcp --dport 53 -j dns_limit |
||
239 | -A INPUT -d 2a0c:e300::1337 -p udp -m udp --dport 53 -j dns_limit |
||
240 | -A INPUT -d 2a0c:e300::1337 -p tcp -m tcp --dport 443 -j dns_limit |
||
241 | -A INPUT -d 2a0c:e300::1337 -p tcp -m tcp --dport 853 -j dns_limit |
||
242 | |||
243 | -A dns_limit -s 2a0c:e300::/29 -j ACCEPT |
||
244 | |||
245 | # mais aussi par le reste d'Internet, mais en rate-limit |
||
246 | -A dns_limit -m string --algo bm --hex-string "|00 00 ff 00 01|" --from 48 -m hashlimit --hashlimit-above 1/sec --hashlimit-burst 2 --hashlimit-mode srcip --hashlimit-name RL-DNS-ANY-v6 --hashlimit-srcmask 56 -m comment --comment "RATE-LIMIT DNS ANY QTYPE 1/s burst 2" -j DROP |
||
247 | -A dns_limit -m string --algo bm --hex-string "|00 00 ff 00 01|" --from 48 -m hashlimit --hashlimit-above 20/min --hashlimit-mode srcip --hashlimit-name RL-DNS-ANY-v6-LOG --hashlimit-srcmask 56 -m comment --comment "RATE-LIMIT DNS ANY QTYPE 20/min LOG" -j LOG --log-prefix "DNS-FLOOD " |
||
248 | -A dns_limit -m hashlimit --hashlimit-above 10/sec --hashlimit-burst 100 --hashlimit-mode srcip --hashlimit-name DNS --hashlimit-srcmask 56 -m comment --comment "RATE-LIMIT DNS 10/s burst 100" -j DROP |
||
249 | -A dns_limit -j ACCEPT |
||
250 | |||
251 | # ICMP |
||
252 | -A INPUT -p icmpv6 -j ACCEPT |
||
253 | -A INPUT -p icmpv6 --icmpv6-type echo-request -m limit --limit 1/s -j ACCEPT |
||
254 | 19 | sacha | |
255 | COMMIT |
||
256 | 20 | sacha | ~~~ |
257 | 3 | sacha | |
258 | ## Configurations spécifiques |
||
259 | |||
260 | 31 | sacha | ### Génération du certificat SSL sur pan1 |
261 | 3 | sacha | |
262 | ~~~ |
||
263 | certbot --apache --agree-tos --email sysop@aquilenet.fr -d dns.aquilenet.fr |
||
264 | chgrp bind /etc/letsencrypt/live/dns.aquilenet.fr/privkey.pem |
||
265 | chmod 0640 /etc/letsencrypt/live/dns.aquilenet.fr/privkey.pem |
||
266 | 16 | sacha | openssl dhparam -out /etc/bind/dhparam.pem 4096 |
267 | ~~~ |
||
268 | |||
269 | Copie du certificat sur gaia |
||
270 | |||
271 | 21 | sacha | * /etc/letsencrypt/renewal/dns.aquilenet.fr.conf |
272 | 1 | sacha | |
273 | 21 | sacha | ~~~ |
274 | + post_hook = /root/certificats.sh |
||
275 | ~~~ |
||
276 | 20 | sacha | |
277 | 22 | sacha | * /root/certificats.sh |
278 | |||
279 | ~~~ |
||
280 | #!/bin/sh |
||
281 | cp -RL /etc/letsencrypt/live/dns.aquilenet.fr/ /etc/unbound/ssl/ |
||
282 | systemctl restart unbound |
||
283 | 34 | jonathan.certes | systemctl restart nginx |
284 | if [ $? -eq 0 ]; then |
||
285 | # make sure that the configuration is identical on pan2: |
||
286 | scp -qrP 55555 /etc/nginx/sites-available/default pan2.aquilenet.fr:"/etc/nginx/sites-available/" |
||
287 | |||
288 | # copy the new certificate to pan2: |
||
289 | ssh -p 55555 pan2.aquilenet.fr "mkdir -p /etc/letsencrypt/live/dns.aquilenet.fr/" |
||
290 | scp -qrP 55555 /etc/letsencrypt/live/dns.aquilenet.fr/fullchain.pem /etc/letsencrypt/live/dns.aquilenet.fr/privkey.pem pan2.aquilenet.fr:"/etc/letsencrypt/live/dns.aquilenet.fr/" |
||
291 | scp -qrP 55555 /etc/letsencrypt/options-ssl-nginx.conf /etc/letsencrypt/ssl-dhparams.pem pan2.aquilenet.fr:"/etc/letsencrypt/" |
||
292 | |||
293 | scp -qrP 55555 /etc/unbound/ssl/dns.aquilenet.fr pan2.aquilenet.fr:/etc/unbound/ssl/ |
||
294 | ssh -p 55555 pan2.aquilenet.fr "systemctl restart unbound && systemctl restart nginx" |
||
295 | fi |
||
296 | 16 | sacha | ~~~ |
297 | |||
298 | ### Clée sdns (auth par épinglage de la clé / key pining) |
||
299 | |||
300 | * A partir de la clé |
||
301 | 23 | sacha | |
302 | 16 | sacha | ~~~ |
303 | 31 | sacha | pan1|19:21:08|:~# openssl rsa -in /etc/letsencrypt/live/dns.aquilenet.fr/privkey.pem -outform der -pubout | openssl dgst -sha256 -binary | openssl enc -base64 |
304 | 3 | sacha | writing RSA key |
305 | lBk09CRIPJ+J4O9rmbvJkEiGYoH5r9rxOIQdxkYxyII= |
||
306 | ~~~ |
||
307 | 23 | sacha | |
308 | 3 | sacha | * ou à partir du certificat |
309 | 23 | sacha | |
310 | 3 | sacha | ~~~ |
311 | 31 | sacha | pan1|19:22:21|:~# openssl x509 -in /etc/letsencrypt/live/dns.aquilenet.fr/cert.pem -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64 |
312 | 3 | sacha | writing RSA key |
313 | lBk09CRIPJ+J4O9rmbvJkEiGYoH5r9rxOIQdxkYxyII= |
||
314 | ~~~ |
||
315 | |||
316 | ### Keepalived |
||
317 | |||
318 | 26 | sacha | #### pan1 Master |
319 | 3 | sacha | |
320 | * /etc/keepalived/keepalived.conf |
||
321 | |||
322 | ~~~ |
||
323 | global_defs { |
||
324 | notification_email { |
||
325 | sysop@aquilenet.fr |
||
326 | } |
||
327 | 24 | sacha | notification_email_from vrrp-dns@aquilenet.fr |
328 | smtp_server localhost |
||
329 | 3 | sacha | smtp_connect_timeout 30 |
330 | } |
||
331 | |||
332 | vrrp_instance DNS { |
||
333 | state MASTER |
||
334 | 24 | sacha | interface enX0 |
335 | virtual_router_id 101 |
||
336 | priority 100 |
||
337 | advert_int 5 |
||
338 | 1 | sacha | smtp_alert |
339 | 24 | sacha | unicast_src_ip 45.67.81.21 |
340 | 1 | sacha | unicast_peer { |
341 | 24 | sacha | 45.67.81.22 |
342 | 1 | sacha | } |
343 | 3 | sacha | virtual_ipaddress { |
344 | 24 | sacha | 45.67.81.23/32 dev enX0 scope global # VIP |
345 | 3 | sacha | } |
346 | 24 | sacha | virtual_ipaddress_excluded { |
347 | 2a0c:e300::1337/128 dev enX1 |
||
348 | } |
||
349 | |||
350 | 3 | sacha | } |
351 | 24 | sacha | |
352 | 3 | sacha | ~~~ |
353 | |||
354 | 25 | sacha | #### pan2 Slave |
355 | 3 | sacha | |
356 | * /etc/keepalived/keepalived.conf |
||
357 | |||
358 | ~~~ |
||
359 | global_defs { |
||
360 | notification_email { |
||
361 | sysop@aquilenet.fr |
||
362 | } |
||
363 | 25 | sacha | notification_email_from vrrp-dns@aquilenet.fr |
364 | 3 | sacha | smtp_server localhost |
365 | smtp_connect_timeout 30 |
||
366 | } |
||
367 | |||
368 | vrrp_instance DNS { |
||
369 | 25 | sacha | state SLAVE |
370 | interface enX0 |
||
371 | virtual_router_id 101 |
||
372 | priority 50 |
||
373 | advert_int 5 |
||
374 | 1 | sacha | smtp_alert |
375 | 25 | sacha | unicast_src_ip 45.67.81.22 |
376 | 1 | sacha | unicast_peer { |
377 | 25 | sacha | 45.67.81.21 |
378 | 4 | sacha | } |
379 | virtual_ipaddress { |
||
380 | 25 | sacha | 45.67.81.23/32 dev enX0 scope global # VIP |
381 | 4 | sacha | } |
382 | 25 | sacha | virtual_ipaddress_excluded { |
383 | 2a0c:e300::1337/128 dev enX1 |
||
384 | } |
||
385 | 13 | sacha | } |
386 | |||
387 | 8 | sacha | ~~~ |
388 | 4 | sacha | |
389 | ## Validation |
||
390 | |||
391 | 8 | sacha | * test du service |
392 | ~~~ |
||
393 | 1 | sacha | dig +short dns.aquilenet.fr @45.67.81.23 |
394 | 12 | sacha | 45.67.81.23 |
395 | 9 | sacha | dig +https +short dns.aquilenet.fr @45.67.81.23 |
396 | 45.67.81.23 |
||
397 | dig +tls +short dns.aquilenet.fr @45.67.81.23 |
||
398 | 45.67.81.23 |
||
399 | 10 | sacha | ~~~ |
400 | |||
401 | 9 | sacha | * bascule keepalived |
402 | 16 | sacha | |
403 | 31 | sacha | sur pan1: `systemctl stop keepalived` |
404 | sur pan2: `ip a |grep /32`doit donner "inet 45.67.81.23/32 scope global eth1" |
||
405 | https://dns.aquilenet.fr/hostname.txt permet de savoir quel est le serveur qui porte l'IP virtuelle |
||
406 | 16 | sacha | |
407 | ## Indexes de serveurs DNS ouverts: |
||
408 | 1 | sacha | |
409 | https://github.com/curl/curl/wiki/DNS-over-HTTPS#publicly-available-servers <= fait |
||
410 | https://diyisp.org/dokuwiki/doku.php?id=technical:dnsresolver <= fait |
||
411 | 33 | sacha | https://european-alternatives.eu/category/public-dns |
412 | |||
413 | 1 | sacha | https://dnsprivacy.org/public_resolvers/ |
414 | |||
415 | ## Ressources |
||
416 | |||
417 | https://www.bortzmeyer.org/doh-bortzmeyer-fr-policy.html |
||
418 | https://www.bortzmeyer.org/7858.html |
||
419 | https://kb.isc.org/docs/aa-01386 |
||
420 | 30 | sacha | https://dnscrypt.info/stamps-specifications/ |