doh_server.js (3338B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 /* globals require, __dirname, global, Buffer, process */ 8 9 const fs = require("fs"); 10 const options = { 11 key: fs.readFileSync(__dirname + "/http2-cert.key.pem"), 12 cert: fs.readFileSync(__dirname + "/http2-cert.pem"), 13 }; 14 const http2 = require("http2"); 15 const http = require("http"); 16 const url = require("url"); 17 18 const path = require("path"); 19 20 let dnsPacket; 21 let libPath = path.join(__dirname, "../../xpcshell/dns-packet"); 22 if (fs.existsSync(libPath)) { 23 // This is the path of dns-packet when running mochitest locally. 24 dnsPacket = require(libPath); 25 } else { 26 // This path is for running mochitest on try. 27 dnsPacket = require(path.join(__dirname, "./dns_packet")); 28 } 29 30 let serverPort = parseInt(process.argv[2].split("=")[1]); 31 let listeningPort = parseInt(process.argv[3].split("=")[1]); 32 let alpn = process.argv[4].split("=")[1]; 33 34 let server = http2.createSecureServer( 35 options, 36 function handleRequest(req, res) { 37 let method = req.headers[http2.constants.HTTP2_HEADER_METHOD]; 38 if (method == "GET") { 39 let searchParams = new URL(req.url, "http://example.com").searchParams; 40 if (!searchParams.get("dns")) { 41 res.writeHead(400); 42 res.end("Missing dns parameter"); 43 return; 44 } 45 46 let requestBody = Buffer.from(searchParams.get("dns"), "base64"); 47 processRequest(req, res, requestBody); 48 return; 49 } 50 51 let u = ""; 52 if (req.url != undefined) { 53 u = url.parse(req.url, true); 54 } 55 56 if (u.pathname === "/dns-query") { 57 let payload = Buffer.from(""); 58 req.on("data", function receiveData(chunk) { 59 payload = Buffer.concat([payload, chunk]); 60 }); 61 req.on("end", function finishedData() { 62 processRequest(req, res, payload); 63 }); 64 } 65 66 function processRequest(req, res, payload) { 67 let packet = dnsPacket.decode(payload); 68 let answers = []; 69 // Return the HTTPS RR to let Firefox connect to the HTTP/3 server 70 if (packet.questions[0].type === "HTTPS") { 71 answers.push({ 72 name: packet.questions[0].name, 73 type: "HTTPS", 74 ttl: 55, 75 class: "IN", 76 flush: false, 77 data: { 78 priority: 1, 79 name: packet.questions[0].name, 80 values: [ 81 { key: "alpn", value: [alpn] }, 82 { key: "port", value: serverPort }, 83 ], 84 }, 85 }); 86 } else if (packet.questions[0].type === "A") { 87 answers.push({ 88 name: packet.questions[0].name, 89 type: "A", 90 ttl: 55, 91 flush: false, 92 data: "127.0.0.1", 93 }); 94 } 95 96 let buf = dnsPacket.encode({ 97 type: "response", 98 id: packet.id, 99 flags: dnsPacket.RECURSION_DESIRED, 100 questions: packet.questions, 101 answers, 102 }); 103 104 res.setHeader("Content-Type", "application/dns-message"); 105 res.setHeader("Content-Length", buf.length); 106 res.writeHead(200); 107 res.write(buf); 108 res.end(""); 109 } 110 } 111 ); 112 113 server.listen(listeningPort); 114 115 console.log(`DoH server listening on ports ${server.address().port}`);