handler: Custom prefix length

This commit is contained in:
LittleChest 2025-08-13 09:14:41 +08:00
parent f16c3164fe
commit 0c3cb5e6aa
5 changed files with 37 additions and 13 deletions

View File

@ -20,9 +20,11 @@ Read [Dohna NS Documentation](https://dohna.ovh/) to learn how to install Dohna
## Environment Variables ## Environment Variables
| Key | Default | Description | | Key | Default | Description |
| --- | ---------------------------- | ------------------------------------------------ | | ----------- | ---------------------------- | -------------------------------------------------- |
| DNS | https://dns.google/dns-query | Specify a DNS over HTTPS server as the upstream. | | DNS | https://dns.google/dns-query | Specify a DNS over HTTPS server as the upstream. |
| API | https://dns.google/resolve | Specify a JSON API server as the upstream. | | API | https://dns.google/resolve | Specify a JSON API server as the upstream. |
| IPV4_PREFIX | 32 | Specify the EDNS client subnet IPv4 prefix length. |
| IPV6_PREFIX | 128 | Specify the EDNS client subnet IPv6 prefix length. |
## Self-hosted ## Self-hosted

View File

@ -2,5 +2,12 @@ import handler from "./common";
export default { export default {
fetch: async (request, env) => fetch: async (request, env) =>
handler(request, env.DNS, env.API, request.headers.get("cf-connecting-ip")), handler(
request,
env.DNS,
env.API,
env.IPV4_PREFIX,
env.IPV6_PREFIX,
request.headers.get("cf-connecting-ip")
),
}; };

View File

@ -2,6 +2,8 @@ export default async function handler(
request, request,
dns = "https://dns.google/dns-query", dns = "https://dns.google/dns-query",
api = "https://dns.google/resolve", api = "https://dns.google/resolve",
ipv4Prefix = 32,
ipv6Prefix = 128,
rawIP rawIP
) { ) {
const { method, headers, url } = request; const { method, headers, url } = request;
@ -75,14 +77,14 @@ export default async function handler(
} }
if (queryData !== undefined) { if (queryData !== undefined) {
res = await queryDns(queryData, ip, dns); res = await queryDns(queryData, ip, dns, ipv4Prefix, ipv6Prefix);
} }
} }
return res; return res;
} }
async function queryDns(queryData, ip, dns) { async function queryDns(queryData, ip, dns, ipv4Prefix, ipv6Prefix) {
const hasOptRecord = checkForOptRecord(queryData); const hasOptRecord = checkForOptRecord(queryData);
let newQueryData = queryData; let newQueryData = queryData;
if (!hasOptRecord && ip) { if (!hasOptRecord && ip) {
@ -90,7 +92,7 @@ async function queryDns(queryData, ip, dns) {
const [headerAndQuestion] = extractHeaderAndQuestion(queryData); const [headerAndQuestion] = extractHeaderAndQuestion(queryData);
// Construct a new OPT record with ECS option // Construct a new OPT record with ECS option
const optRecord = createOptRecord(ip); const optRecord = createOptRecord(ip, ipv4Prefix, ipv6Prefix);
// Combine the header, question, and new OPT record to create a new query // Combine the header, question, and new OPT record to create a new query
newQueryData = combineQueryData(headerAndQuestion, optRecord); newQueryData = combineQueryData(headerAndQuestion, optRecord);
@ -172,21 +174,21 @@ function extractHeaderAndQuestion(data) {
return [headerAndQuestion, offset]; return [headerAndQuestion, offset];
} }
function createOptRecord(ip) { function createOptRecord(ip, ipv4Prefix, ipv6Prefix) {
let ecsData; let ecsData;
let family; let family;
if (isIPv4(ip)) { if (isIPv4(ip)) {
const prefixLength = ipv4Prefix
// Convert client IP to bytes // Convert client IP to bytes
const ipParts = ip.split(".").map((part) => parseInt(part, 10)); const ipParts = ip.split(".").map((part) => parseInt(part, 10));
family = 1; // IPv4 family = 1; // IPv4
const prefixLength = 32; // Adjust the prefix length as needed
ecsData = [0, 8, 0, 8, 0, family, prefixLength, 0, ...ipParts]; ecsData = [0, 8, 0, 8, 0, family, prefixLength, 0, ...ipParts];
} else if (isIPv6(ip)) { } else if (isIPv6(ip)) {
const prefixLength = ipv6Prefix
// Convert client IP to bytes // Convert client IP to bytes
const ipParts = ipv6ToBytes(ip); const ipParts = ipv6ToBytes(ip);
family = 2; // IPv6 family = 2; // IPv6
const prefixLength = 128; // Adjust the prefix length as needed
ecsData = [0, 8, 0, 20, 0, family, prefixLength, 0, ...ipParts]; ecsData = [0, 8, 0, 20, 0, family, prefixLength, 0, ...ipParts];
} else { } else {
throw new Error("Invalid IP address"); throw new Error("Invalid IP address");

View File

@ -1,5 +1,11 @@
import handler from "./common"; import handler from "./common";
export default middleware = async (request) => { export default middleware = async (request) => {
return handler(request, process.env.DNS, process.env.API); return handler(
request,
process.env.DNS,
process.env.API,
process.env.IPV4_PREFIX,
process.env.IPV6_PREFIX
);
}; };

View File

@ -1,4 +1,11 @@
import handler from "../../common.js"; import handler from "../../common.js";
export default async (request) => export default async (request) =>
handler(request, Netlify.env.get("DNS"), Netlify.env.get("API"), Netlify.context.ip); handler(
request,
Netlify.env.get("DNS"),
Netlify.env.get("API"),
Netlify.env.get("IPV4_PREFIX"),
Netlify.env.get("IPV6_PREFIX"),
Netlify.context.ip
);
export const config = { path: "*" }; export const config = { path: "*" };