From 0b0929e8fcb0069a1821996b26ba92632c07245e Mon Sep 17 00:00:00 2001 From: Luca Krawczyk Date: Tue, 16 Jul 2024 00:54:54 +0200 Subject: [PATCH 1/9] added dependencies axios and cheerio --- backend/package.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backend/package.json b/backend/package.json index b938c9a9..3ff0c321 100644 --- a/backend/package.json +++ b/backend/package.json @@ -6,9 +6,11 @@ "dependencies": { "ajv": "^6.12.0", "archiver": "^5.3.0", + "axios": "^1.7.2", "batchflow": "^0.4.0", "bcrypt": "^5.0.0", "body-parser": "^1.19.0", + "cheerio": "^1.0.0-rc.12", "compression": "^1.7.4", "express": "^4.19.2", "express-fileupload": "^1.1.9", From 7c5ae8e4fb5ffd7f24cf439cb066388f688ecd19 Mon Sep 17 00:00:00 2001 From: Luca Krawczyk Date: Tue, 16 Jul 2024 00:55:29 +0200 Subject: [PATCH 2/9] added PiHoleDNSPlugin.js --- backend/internal/PiHoleDNSPlugin.js | 85 +++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 backend/internal/PiHoleDNSPlugin.js diff --git a/backend/internal/PiHoleDNSPlugin.js b/backend/internal/PiHoleDNSPlugin.js new file mode 100644 index 00000000..54f66e30 --- /dev/null +++ b/backend/internal/PiHoleDNSPlugin.js @@ -0,0 +1,85 @@ +const axios = require('axios'); +const cheerio = require('cheerio'); +const qs = require('querystring'); + + +const PIHOLE_PASSWORD = process.env.PIHOLE_PASSWORD; +const PIHOLE_LOGIN_URL = 'http://'+process.env.PIHOLE_IP+'/admin/index.php'; +const PIHOLE_CUSTOMDNS_URL = 'http://'+process.env.PIHOLE_IP+'/admin/scripts/pi-hole/php/customdns.php'; + +// Function to update Pi-hole with domain and IP +async function updatePihole(domain, ip) { + try { + // Step 1: Login to Pi-hole to get session cookie + const loginResponse = await axios.post(PIHOLE_LOGIN_URL, qs.stringify({ + pw: PIHOLE_PASSWORD, + }), { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + 'User-Agent': 'Mozilla/5.0' // Pretend to be a browser + }, + withCredentials: true // Send cookies with the request + }); + + if (loginResponse.status === 200) { + console.log('Login successful'); + // Extract session cookie (PHPSESSID) + const cookies = loginResponse.headers['set-cookie']; + const sessionCookie = cookies.find((cookie) => cookie.startsWith('PHPSESSID')); + + if (!sessionCookie) { + throw new Error('PHP session cookie not found'); + } + + // Step 2: Fetch HTML content of index.php after login + const indexHtmlResponse = await axios.get(PIHOLE_LOGIN_URL, { + headers: { + Cookie: sessionCookie.split(';')[0] // Send only the PHPSESSID part of the cookie + } + }); + + // Load HTML content into cheerio for DOM manipulation + const $ = cheerio.load(indexHtmlResponse.data); + + // Extract token value from element with ID "token" + const token = $('#token').text().trim(); + + console.log('Token retrieved:', token); + + // Step 3: Add custom DNS record with explicit session cookie and token + const headers = { + 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', + 'Pragma': 'no-cache', + 'Accept': 'application/json, text/javascript, */*; q=0.01', + 'Accept-Language': 'en-GB,en;q=0.9', + 'Accept-Encoding': 'gzip, deflate', + 'Connection': 'keep-alive', + 'X-Requested-With': 'XMLHttpRequest', + 'Cookie': sessionCookie.split(';')[0] // Send only the PHPSESSID part of the cookie + }; + + // Request data including token + const requestData = { + action: 'add', + ip: ip, + domain: domain, + token: token // Use the token retrieved from the HTML page + }; + + // Make the POST request to add custom DNS record + const addRecordResponse = await axios.post(PIHOLE_CUSTOMDNS_URL, qs.stringify(requestData), { + headers: headers + }); + + console.log('Custom DNS record added:', addRecordResponse.data); + } else { + console.error('Login failed:', loginResponse.statusText); + } + } catch (error) { + console.error('Error logging in or adding custom DNS record:', error.message); + } +} + +module.exports = { + updatePihole: updatePihole +}; From 7e7e077ce1bb9fc324c650d478b069099b13ccdb Mon Sep 17 00:00:00 2001 From: Luca Krawczyk Date: Tue, 16 Jul 2024 00:56:10 +0200 Subject: [PATCH 3/9] execute pihole DNS setter --- backend/internal/proxy-host.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/backend/internal/proxy-host.js b/backend/internal/proxy-host.js index dbff1147..0b6cfec1 100644 --- a/backend/internal/proxy-host.js +++ b/backend/internal/proxy-host.js @@ -6,6 +6,7 @@ const internalHost = require('./host'); const internalNginx = require('./nginx'); const internalAuditLog = require('./audit-log'); const internalCertificate = require('./certificate'); +const piHole = require('./PiHoleDNSPlugin'); function omissions () { return ['is_deleted']; @@ -64,9 +65,21 @@ const internalProxyHost = { }); }) .then(() => { + + // Update PiHole + for (let i = 0; i < row.domain_names.length; i++) { + piHole.updatePihole(row.domain_names[i], row.forward_host); + } + return row; }); } else { + + // Update PiHole + for (let i = 0; i < row.domain_names.length; i++) { + piHole.updatePihole(row.domain_names[i], row.forward_host); + } + return row; } }) From 392d1f02772c9f367b847186c35e9e08b0e3c998 Mon Sep 17 00:00:00 2001 From: Luca Krawczyk Date: Tue, 16 Jul 2024 22:19:07 +0200 Subject: [PATCH 4/9] implemented update and delete methods --- backend/internal/PiHoleDNSPlugin.js | 8 +++----- backend/internal/proxy-host.js | 23 +++++++++++++++++++++-- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/backend/internal/PiHoleDNSPlugin.js b/backend/internal/PiHoleDNSPlugin.js index 54f66e30..d4109f4d 100644 --- a/backend/internal/PiHoleDNSPlugin.js +++ b/backend/internal/PiHoleDNSPlugin.js @@ -8,7 +8,7 @@ const PIHOLE_LOGIN_URL = 'http://'+process.env.PIHOLE_IP+'/admin/index.php'; const PIHOLE_CUSTOMDNS_URL = 'http://'+process.env.PIHOLE_IP+'/admin/scripts/pi-hole/php/customdns.php'; // Function to update Pi-hole with domain and IP -async function updatePihole(domain, ip) { +async function updatePihole(domain, ip,action) { try { // Step 1: Login to Pi-hole to get session cookie const loginResponse = await axios.post(PIHOLE_LOGIN_URL, qs.stringify({ @@ -22,7 +22,6 @@ async function updatePihole(domain, ip) { }); if (loginResponse.status === 200) { - console.log('Login successful'); // Extract session cookie (PHPSESSID) const cookies = loginResponse.headers['set-cookie']; const sessionCookie = cookies.find((cookie) => cookie.startsWith('PHPSESSID')); @@ -44,7 +43,6 @@ async function updatePihole(domain, ip) { // Extract token value from element with ID "token" const token = $('#token').text().trim(); - console.log('Token retrieved:', token); // Step 3: Add custom DNS record with explicit session cookie and token const headers = { @@ -60,7 +58,7 @@ async function updatePihole(domain, ip) { // Request data including token const requestData = { - action: 'add', + action: action, ip: ip, domain: domain, token: token // Use the token retrieved from the HTML page @@ -71,7 +69,7 @@ async function updatePihole(domain, ip) { headers: headers }); - console.log('Custom DNS record added:', addRecordResponse.data); + console.log('PiHole API:', addRecordResponse.data); } else { console.error('Login failed:', loginResponse.statusText); } diff --git a/backend/internal/proxy-host.js b/backend/internal/proxy-host.js index 0b6cfec1..1d86460a 100644 --- a/backend/internal/proxy-host.js +++ b/backend/internal/proxy-host.js @@ -68,7 +68,7 @@ const internalProxyHost = { // Update PiHole for (let i = 0; i < row.domain_names.length; i++) { - piHole.updatePihole(row.domain_names[i], row.forward_host); + piHole.updatePihole(row.domain_names[i], row.forward_host, 'add'); } return row; @@ -77,7 +77,7 @@ const internalProxyHost = { // Update PiHole for (let i = 0; i < row.domain_names.length; i++) { - piHole.updatePihole(row.domain_names[i], row.forward_host); + piHole.updatePihole(row.domain_names[i], row.forward_host, 'add'); } return row; @@ -166,9 +166,18 @@ const internalProxyHost = { data.certificate_id = cert.id; }) .then(() => { + // Update PiHole + for (let i = 0; i < row.domain_names.length; i++) { + piHole.updatePihole(row.domain_names[i], row.forward_host, 'delete'); + } return row; }); } else { + // Update PiHole + for (let i = 0; i < row.domain_names.length; i++) { + piHole.updatePihole(row.domain_names[i], row.forward_host, 'delete'); + + } return row; } }) @@ -194,6 +203,7 @@ const internalProxyHost = { meta: data }) .then(() => { + return saved_row; }); }); @@ -213,6 +223,9 @@ const internalProxyHost = { .then((new_meta) => { row.meta = new_meta; row = internalHost.cleanRowCertificateMeta(row); + for (let i = 0; i < row.domain_names.length; i++) { + piHole.updatePihole(row.domain_names[i], row.forward_host, 'add'); + } return _.omit(row, omissions()); }); }); @@ -288,6 +301,12 @@ const internalProxyHost = { is_deleted: 1 }) .then(() => { + // Update PiHole + + for (let i = 0; i < row.domain_names.length; i++) { + piHole.updatePihole(row.domain_names[i], row.forward_host, 'delete').then(); + console.log('Deleted from PiHole: ' + row.domain_names[i]); + } // Delete Nginx Config return internalNginx.deleteConfig('proxy_host', row) .then(() => { From 2fb1daab99f86e9c2bd17373a7390a877968ca4f Mon Sep 17 00:00:00 2001 From: Luca Krawczyk Date: Tue, 16 Jul 2024 22:33:51 +0200 Subject: [PATCH 5/9] added then() --- backend/internal/proxy-host.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/backend/internal/proxy-host.js b/backend/internal/proxy-host.js index 1d86460a..e1676692 100644 --- a/backend/internal/proxy-host.js +++ b/backend/internal/proxy-host.js @@ -68,7 +68,7 @@ const internalProxyHost = { // Update PiHole for (let i = 0; i < row.domain_names.length; i++) { - piHole.updatePihole(row.domain_names[i], row.forward_host, 'add'); + piHole.updatePihole(row.domain_names[i], row.forward_host, 'add').then(); } return row; @@ -77,7 +77,7 @@ const internalProxyHost = { // Update PiHole for (let i = 0; i < row.domain_names.length; i++) { - piHole.updatePihole(row.domain_names[i], row.forward_host, 'add'); + piHole.updatePihole(row.domain_names[i], row.forward_host, 'add').then(); } return row; @@ -168,14 +168,14 @@ const internalProxyHost = { .then(() => { // Update PiHole for (let i = 0; i < row.domain_names.length; i++) { - piHole.updatePihole(row.domain_names[i], row.forward_host, 'delete'); + piHole.updatePihole(row.domain_names[i], row.forward_host, 'delete').then(); } return row; }); } else { // Update PiHole for (let i = 0; i < row.domain_names.length; i++) { - piHole.updatePihole(row.domain_names[i], row.forward_host, 'delete'); + piHole.updatePihole(row.domain_names[i], row.forward_host, 'delete').then(); } return row; @@ -224,7 +224,7 @@ const internalProxyHost = { row.meta = new_meta; row = internalHost.cleanRowCertificateMeta(row); for (let i = 0; i < row.domain_names.length; i++) { - piHole.updatePihole(row.domain_names[i], row.forward_host, 'add'); + piHole.updatePihole(row.domain_names[i], row.forward_host, 'add').then(); } return _.omit(row, omissions()); }); @@ -305,7 +305,6 @@ const internalProxyHost = { for (let i = 0; i < row.domain_names.length; i++) { piHole.updatePihole(row.domain_names[i], row.forward_host, 'delete').then(); - console.log('Deleted from PiHole: ' + row.domain_names[i]); } // Delete Nginx Config return internalNginx.deleteConfig('proxy_host', row) From 95c6c0e1e19f61759694a1d1c4e97f3eb1dec04f Mon Sep 17 00:00:00 2001 From: Luca Krawczyk Date: Tue, 16 Jul 2024 22:34:17 +0200 Subject: [PATCH 6/9] added flag for enabling --- backend/internal/PiHoleDNSPlugin.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/backend/internal/PiHoleDNSPlugin.js b/backend/internal/PiHoleDNSPlugin.js index d4109f4d..fb3b95c1 100644 --- a/backend/internal/PiHoleDNSPlugin.js +++ b/backend/internal/PiHoleDNSPlugin.js @@ -2,13 +2,17 @@ const axios = require('axios'); const cheerio = require('cheerio'); const qs = require('querystring'); - -const PIHOLE_PASSWORD = process.env.PIHOLE_PASSWORD; -const PIHOLE_LOGIN_URL = 'http://'+process.env.PIHOLE_IP+'/admin/index.php'; -const PIHOLE_CUSTOMDNS_URL = 'http://'+process.env.PIHOLE_IP+'/admin/scripts/pi-hole/php/customdns.php'; +const PIHOLE_PLUGIN_ENABLED = process.env.PIHOLE_PLUGIN_ENABLED === 'true'; +const PIHOLE_PASSWORD = process.env.PIHOLE_PASSWORD; +const PIHOLE_LOGIN_URL = 'http://'+process.env.PIHOLE_IP+'/admin/index.php'; +const PIHOLE_CUSTOMDNS_URL = 'http://'+process.env.PIHOLE_IP+'/admin/scripts/pi-hole/php/customdns.php'; // Function to update Pi-hole with domain and IP async function updatePihole(domain, ip,action) { + // Check if the Pi-hole plugin is enabled + if (!PIHOLE_PLUGIN_ENABLED) { + return; + } try { // Step 1: Login to Pi-hole to get session cookie const loginResponse = await axios.post(PIHOLE_LOGIN_URL, qs.stringify({ From 407cee1d7098ee97e47d63aafc1c753f20ee3fcf Mon Sep 17 00:00:00 2001 From: Luca Krawczyk Date: Tue, 16 Jul 2024 22:34:41 +0200 Subject: [PATCH 7/9] compose comments --- docker/docker-compose.dev.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.dev.yml index 14ca2f7a..3590fb59 100644 --- a/docker/docker-compose.dev.yml +++ b/docker/docker-compose.dev.yml @@ -29,6 +29,11 @@ services: DB_MYSQL_NAME: 'npm' # DB_SQLITE_FILE: "/data/database.sqlite" # DISABLE_IPV6: "true" + # pihole: + # PIHOLE_PLUGIN_ENABLED: 'true' + # PIHOLE_PASSWORD: 'password' + # PIHOLE_IP: '192.168.10.2' + volumes: - npm_data:/data - le_data:/etc/letsencrypt From c0598c582740d103751b8b65854ff57311708143 Mon Sep 17 00:00:00 2001 From: Luca Krawczyk Date: Tue, 16 Jul 2024 22:41:25 +0200 Subject: [PATCH 8/9] fuck eslint --- backend/internal/PiHoleDNSPlugin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/internal/PiHoleDNSPlugin.js b/backend/internal/PiHoleDNSPlugin.js index fb3b95c1..833146c9 100644 --- a/backend/internal/PiHoleDNSPlugin.js +++ b/backend/internal/PiHoleDNSPlugin.js @@ -8,7 +8,7 @@ const PIHOLE_LOGIN_URL = 'http://'+process.env.PIHOLE_IP+'/admin/index.php' const PIHOLE_CUSTOMDNS_URL = 'http://'+process.env.PIHOLE_IP+'/admin/scripts/pi-hole/php/customdns.php'; // Function to update Pi-hole with domain and IP -async function updatePihole(domain, ip,action) { +async function updatePihole(domain, ip, action) { // Check if the Pi-hole plugin is enabled if (!PIHOLE_PLUGIN_ENABLED) { return; From 05c4c0470eceecf6ee231a8990d552c640de50c4 Mon Sep 17 00:00:00 2001 From: Luca Krawczyk Date: Thu, 18 Jul 2024 00:17:52 +0200 Subject: [PATCH 9/9] fixed ip in dns table --- backend/internal/PiHoleDNSPlugin.js | 7 +++++-- backend/internal/proxy-host.js | 12 ++++++------ docker/docker-compose.dev.yml | 1 + 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/backend/internal/PiHoleDNSPlugin.js b/backend/internal/PiHoleDNSPlugin.js index 833146c9..2aac300d 100644 --- a/backend/internal/PiHoleDNSPlugin.js +++ b/backend/internal/PiHoleDNSPlugin.js @@ -7,8 +7,11 @@ const PIHOLE_PASSWORD = process.env.PIHOLE_PASSWORD; const PIHOLE_LOGIN_URL = 'http://'+process.env.PIHOLE_IP+'/admin/index.php'; const PIHOLE_CUSTOMDNS_URL = 'http://'+process.env.PIHOLE_IP+'/admin/scripts/pi-hole/php/customdns.php'; +// IP to entry in pihole dns table +const DNS_TABLE_IP = process.env.DNS_TABLE_IP; + // Function to update Pi-hole with domain and IP -async function updatePihole(domain, ip, action) { +async function updatePihole(domain, action) { // Check if the Pi-hole plugin is enabled if (!PIHOLE_PLUGIN_ENABLED) { return; @@ -63,7 +66,7 @@ async function updatePihole(domain, ip, action) { // Request data including token const requestData = { action: action, - ip: ip, + ip: DNS_TABLE_IP, domain: domain, token: token // Use the token retrieved from the HTML page }; diff --git a/backend/internal/proxy-host.js b/backend/internal/proxy-host.js index e1676692..8324e0dd 100644 --- a/backend/internal/proxy-host.js +++ b/backend/internal/proxy-host.js @@ -68,7 +68,7 @@ const internalProxyHost = { // Update PiHole for (let i = 0; i < row.domain_names.length; i++) { - piHole.updatePihole(row.domain_names[i], row.forward_host, 'add').then(); + piHole.updatePihole(row.domain_names[i], 'add').then(); } return row; @@ -77,7 +77,7 @@ const internalProxyHost = { // Update PiHole for (let i = 0; i < row.domain_names.length; i++) { - piHole.updatePihole(row.domain_names[i], row.forward_host, 'add').then(); + piHole.updatePihole(row.domain_names[i], 'add').then(); } return row; @@ -168,14 +168,14 @@ const internalProxyHost = { .then(() => { // Update PiHole for (let i = 0; i < row.domain_names.length; i++) { - piHole.updatePihole(row.domain_names[i], row.forward_host, 'delete').then(); + piHole.updatePihole(row.domain_names[i], 'delete').then(); } return row; }); } else { // Update PiHole for (let i = 0; i < row.domain_names.length; i++) { - piHole.updatePihole(row.domain_names[i], row.forward_host, 'delete').then(); + piHole.updatePihole(row.domain_names[i], 'delete').then(); } return row; @@ -224,7 +224,7 @@ const internalProxyHost = { row.meta = new_meta; row = internalHost.cleanRowCertificateMeta(row); for (let i = 0; i < row.domain_names.length; i++) { - piHole.updatePihole(row.domain_names[i], row.forward_host, 'add').then(); + piHole.updatePihole(row.domain_names[i], 'add').then(); } return _.omit(row, omissions()); }); @@ -304,7 +304,7 @@ const internalProxyHost = { // Update PiHole for (let i = 0; i < row.domain_names.length; i++) { - piHole.updatePihole(row.domain_names[i], row.forward_host, 'delete').then(); + piHole.updatePihole(row.domain_names[i], 'delete').then(); } // Delete Nginx Config return internalNginx.deleteConfig('proxy_host', row) diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.dev.yml index 3590fb59..6621ce7a 100644 --- a/docker/docker-compose.dev.yml +++ b/docker/docker-compose.dev.yml @@ -30,6 +30,7 @@ services: # DB_SQLITE_FILE: "/data/database.sqlite" # DISABLE_IPV6: "true" # pihole: + # DNS_TABLE_IP: '192.168.10.10' # PIHOLE_PLUGIN_ENABLED: 'true' # PIHOLE_PASSWORD: 'password' # PIHOLE_IP: '192.168.10.2'