Skip to content

api init #9

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,776 changes: 1,085 additions & 691 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,23 @@
"build": "tsc",
"start": "node dist/app.js",
"dev": "ts-node src/app.ts",
"api": "nodemon src/app.ts",
"format": "npx prettier --write ."
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"devDependencies": {
"@types/express": "^5.0.0",
"@types/node": "^22.7.5",
"nodemon": "^3.1.7",
"prettier": "^3.3.3",
"ts-node": "^10.9.2",
"typescript": "^5.6.3",
"vitest": "^2.1.3"
},
"dependencies": {
"express": "^4.21.1"
}
}
8 changes: 8 additions & 0 deletions src/api/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import express, { Express, Request, Response } from 'express';

export const server: Express = express();
export const PORT = 3000;

server.get('/test', (req: Request, res: Response) => {
res.send('API test running');
});
86 changes: 15 additions & 71 deletions src/app.ts
Original file line number Diff line number Diff line change
@@ -1,75 +1,19 @@
import { encodeHostname, createDNSMessageBuffer } from './encoding/main';
import { sendDNSMessageUDP } from './udp';
import { DNSMessage } from './encoding/types';
import express, { Express, Request, Response } from 'express';
import { testGoogle, testCloudFlare } from './dns';

interface serverInfo {
hostname: string;
ipAddress: string;
}
const server: Express = express();
const PORT = 3000;

// List of dns servers and hostnames for testing
const dnsServers: Record<string, serverInfo> = {
cloudflare: {
hostname: 'one.one.one.one',
ipAddress: '1.1.1.1',
},
google: {
hostname: 'dns.google.com',
ipAddress: '8.8.8.8',
},
opendns: {
hostname: 'resolver1.opendns.com',
ipAddress: '208.67.222.222',
},
quad9: {
hostname: 'dns.quad9.net',
ipAddress: '9.9.9.9',
},
verisign: {
hostname: 'public-dns-a.verisign.com',
ipAddress: '64.6.64.6',
},
comodo: {
hostname: 'recursive.resolver.comodo.net',
ipAddress: '8.26.56.26',
},
};
server.get('/test/dns/cloudflare', async (req: Request, res: Response) => {
res.status(200).json({ message: 'cloudflare DNS test running' });
await testCloudFlare();
});

const run = async () => {
console.log('DNS resolver running 👾\n');
server.get('/test/dns/google', async (req: Request, res: Response) => {
res.status(200).json({ message: 'google DNS test running' });
await testGoogle();
});

let googleTest: DNSMessage = {
id: 22,
flags: 0x0100,
numQuestions: 1,
ansCount: 0,
nscount: 0,
arcount: 0,
question: encodeHostname(dnsServers.google.hostname),
tquery: 1,
cquery: 1,
};

// NOTE: Test to bve able to query one of the root name servers
// so we can resolve any host and domain name, not just Google’s.
// Bit recusion must be 0, so flags are set to 0
// Testing with cloudfare DNS: one.one.one.one
let cloudflareTest: DNSMessage = {
id: 22,
flags: 0x0000,
numQuestions: 1,
ansCount: 0,
nscount: 0,
arcount: 0,
question: encodeHostname(dnsServers.cloudflare.hostname),
tquery: 2,
cquery: 1,
};

// const msg1 = createDNSMessageBuffer(googleTest);
// await sendDNSMessageUDP(msg1, dnsServers.cloudflare.ipAddress, 53);
const msg2 = createDNSMessageBuffer(cloudflareTest);
await sendDNSMessageUDP(msg2, dnsServers.cloudflare.ipAddress, 53);
};

run();
server.listen(PORT, () => {
console.log(`[server]: Server running at http://localhost:${PORT}`);
});
74 changes: 74 additions & 0 deletions src/dns.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { encodeHostname, createDNSMessageBuffer } from './encoding/main';
import { sendDNSMessageUDP } from './udp';
import { DNSMessage } from './encoding/types';

interface serverInfo {
hostname: string;
ipAddress: string;
}

// List of dns servers and hostnames for testing
const dnsServers: Record<string, serverInfo> = {
cloudflare: {
hostname: 'one.one.one.one',
ipAddress: '1.1.1.1',
},
google: {
hostname: 'dns.google.com',
ipAddress: '8.8.8.8',
},
opendns: {
hostname: 'resolver1.opendns.com',
ipAddress: '208.67.222.222',
},
quad9: {
hostname: 'dns.quad9.net',
ipAddress: '9.9.9.9',
},
verisign: {
hostname: 'public-dns-a.verisign.com',
ipAddress: '64.6.64.6',
},
comodo: {
hostname: 'recursive.resolver.comodo.net',
ipAddress: '8.26.56.26',
},
};

export const testGoogle = async () => {
let googleTest: DNSMessage = {
id: 22,
flags: 0x0100,
numQuestions: 1,
ansCount: 0,
nscount: 0,
arcount: 0,
question: encodeHostname(dnsServers.google.hostname),
tquery: 1,
cquery: 1,
};

const msg1 = createDNSMessageBuffer(googleTest);
await sendDNSMessageUDP(msg1, dnsServers.cloudflare.ipAddress, 53);
};

export const testCloudFlare = async () => {
// NOTE: Test to bve able to query one of the root name servers
// so we can resolve any host and domain name, not just Google’s.
// Bit recusion must be 0, so flags are set to 0
// Testing with cloudfare DNS: one.one.one.one
let cloudflareTest: DNSMessage = {
id: 22,
flags: 0x0000,
numQuestions: 1,
ansCount: 0,
nscount: 0,
arcount: 0,
question: encodeHostname(dnsServers.cloudflare.hostname),
tquery: 2,
cquery: 1,
};

const msg2 = createDNSMessageBuffer(cloudflareTest);
await sendDNSMessageUDP(msg2, dnsServers.cloudflare.ipAddress, 53);
};
22 changes: 13 additions & 9 deletions src/encoding/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import {
DNSHeaderSection,
DNSQuestionSection,
DNSResourceRecord,
DNSResponse
} from './types';
import { readNBytes, cleanResourceIP } from './utils'

import { readNBytes, cleanResourceIP, cleanNSrecord_ip } from './utils';

// NOTE: Creates a message buffer to store the DNS message being sent
// Allocates 12 bytes for the header plus the length of the question
Expand Down Expand Up @@ -43,7 +43,6 @@ export function encodeHostname(q: string): Buffer {
return Buffer.concat(parts);
}


// NOTE: Parses the header section of the DNS response, 12 bytes (0 - 11)
// For the flags we shift the bits based on the bit length for each field
// as per RFC 1035 4.1.1 and use the bitwise AND operation to extract
Expand Down Expand Up @@ -132,15 +131,21 @@ export function parseDNSResourceRecord(
// Switching through the DNS record type
switch (state.type) {
case 1:
const raw = response.subarray(state.pos, state.pos + rdlength);
const rawA = response.subarray(
state.pos,
state.pos + rdlength,
);
state.pos += rdlength;
return cleanResourceIP(raw);
return cleanResourceIP(rawA);
case 2:
const raw2 = response.subarray(state.pos, state.pos + rdlength);
const rawNS = response.subarray(
state.pos,
state.pos + rdlength,
);
state.pos += rdlength;
return cleanResourceIP(raw2);
return cleanNSrecord_ip(rawNS);
default:
return "";
return '';
}
})(),
currentPosition: state.pos,
Expand Down Expand Up @@ -215,4 +220,3 @@ export function parseServerResponse(response: Buffer) {
break;
}
}

7 changes: 7 additions & 0 deletions src/encoding/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,10 @@ export interface DNSResourceRecord {
rdata_ipAdd: string; // Variable length string that describes the resource
currentPosition: number; // Indicates the where we are in the bytes buffer after parsing
}

// NOTE: A structured DNS response from the server
interface DNSResponse {
header: DNSHeaderSection;
question: DNSQuestionSection;
records: DNSRecord[];
}
13 changes: 9 additions & 4 deletions src/encoding/utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { Buffer } from "buffer";
import { Buffer } from 'buffer';

// NOTE: Utility function for reading n bytes from the buffer, and increasing the position n bytes
export function readNBytes(n: number, buf: Buffer, state: { pos: number }): number {
export function readNBytes(
n: number,
buf: Buffer,
state: { pos: number },
): number {
const bRead = buf.readUIntBE(state.pos, n);
state.pos += n;
return bRead;
Expand All @@ -13,5 +17,6 @@ export function cleanResourceIP(buf: Buffer): string {
return ipAddress;
}



export function cleanNSrecord_ip(buf: Buffer): string {
return buf.toString('hex');
}
2 changes: 2 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"outDir": "./dist",
"rootDir": "./"
},
Expand Down