Previously:使用 nginx 代理 NextDNS 的 DoH 服務
使用 Cloudflare Worker 代理 NextDNS 的 DoH 服務
使用 tina-hello 的 doh-cf-workers 項目可以方便的建立一個 DoH 代理。由於只需要一個 index.js 文件,所以我這裡轉載一下。默認的示例是 Cloudflare 的 DoH,切換成 NextDNS 的話只需要修改 doh 和 dohjson 的網址,其他都不用動。
// SPDX-License-Identifier: 0BSD
const doh = 'https://dns.nextdns.io/YOUR_ID/YOUR_TAG'
const dohjson = 'https://dns.nextdns.io/YOUR_ID/YOUR_TAG'
const contype = 'application/dns-message'
const jstontype = 'application/dns-json'
const r404 = new Response(null, {status: 404});
// developers.cloudflare.com/workers/runtime-apis/fetch-event/#syntax-module-worker
export default {
async fetch(r, env, ctx) {
return handleRequest(r);
},
};
async function handleRequest(request) {
// when res is a Promise<Response>, it reduces billed wall-time
// blog.cloudflare.com/workers-optimization-reduces-your-bill
let res = r404;
const { method, headers, url } = request
const searchParams = new URL(url).searchParams
if (method == 'GET' && searchParams.has('dns')) {
res = fetch(doh + '?dns=' + searchParams.get('dns'), {
method: 'GET',
headers: {
'Accept': contype,
}
});
} else if (method === 'POST' && headers.get('content-type') === contype) {
// streaming out the request body is optimal than awaiting on it
const rostream = request.body;
res = fetch(doh, {
method: 'POST',
headers: {
'Accept': contype,
'Content-Type': contype,
},
body: rostream,
});
} else if (method === 'GET' && headers.get('Accept') === jstontype) {
const search = new URL(url).search
res = fetch(dohjson + search, {
method: 'GET',
headers: {
'Accept': jstontype,
}
});
}
return res;
}
#測試下 GET 請求
curl -H 'accept: application/dns-json' 'https://YOURPROJECT.YOURWORKER.workers.dev/dns-query?name=ft.shaman.eu.org&type=A'
#POST請求由於需要構造 DNS 參數,所以就不測了
使用 Python 代理 NextDNS 的 DoH 服務
輕量級的 API 框架我不熟悉,所以這裡還是用 Django。
#file:app1/views.py
from django.http import HttpResponse
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
import requests
@csrf_exempt
def forward_to_doh(request):
cloudflare_doh_url = "https://YOURPROJECT.YOURWORKER.workers.dev/"
contype = 'application/dns-message'
jstontype = 'application/dns-json'
try:
if request.method == 'GET':
if 'dns' in request.GET:
params = {'dns': request.GET['dns']}
headers = {'Accept': contype}
response = requests.get(cloudflare_doh_url, params=params, headers=headers)
return JsonResponse(response.json(), status=response.status_code)
elif request.headers.get('Accept') == jstontype:
response = requests.get(cloudflare_doh_url + '?' + request.GET.urlencode(), headers={'Accept': jstontype})
return JsonResponse(response.json(), status=response.status_code)
elif request.method == 'POST':
if request.headers.get('content-type') == contype:
headers = {'Accept': contype, 'Content-Type': contype}
data = request.body
response = requests.post(cloudflare_doh_url, data=data, headers=headers)
return HttpResponse(response.content, content_type=response.headers['Content-Type'], status=response.status_code)
else:
return JsonResponse({'error': 'Unsupported request method'}, status=405)
return JsonResponse({'error': 'Not Found'}, status=404)
except requests.exceptions.RequestException as e:
return JsonResponse({'error': str(e)}, status=500)
#file:mysite/urls.py
from django.urls import include,path
from app1 import views
urlpatterns = [
path('YourSecNextDns/', views.forward_to_doh, name='forward_to_doh'),
path('i/', include('i.urls')),
]
#測試下 GET 請求
curl -H 'accept: application/dns-json' 'https://YOUR_DOMAIN.LTD/YourSecNextDns/?name=ft.shaman.eu.org&type=A'
上面的請求經過三次請求,速度(高達秒級)自然是比不了直連。但是為了體驗 DoH,還是可以用用看。反正網速本身也不快,DNS 慢一點完全可以怪到網速上。