Skip to content

Commit

Permalink
dnsproxy: Add DNS proxying functionality.
Browse files Browse the repository at this point in the history
There are services that don't use the libc resolver
in their service containers (for example some Go-based
services). This addition installs dnsmasq into the
MDNS services which can be enabled by an envvar.

Change-type: minor
Signed-off-by: Heds Simons <[email protected]>
  • Loading branch information
Heds Simons committed Aug 27, 2019
1 parent 796e108 commit 88db097
Show file tree
Hide file tree
Showing 9 changed files with 292 additions and 104 deletions.
2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ FROM balena/open-balena-base:v8.0.3 as base
RUN apt-get update && \
apt-get install -yq --no-install-recommends \
libdbus-glib-1-dev \
dnsmasq \
&& apt-get clean && rm -rf /var/lib/apt/lists/*

WORKDIR /usr/src/app
Expand All @@ -15,6 +16,7 @@ RUN JOBS=MAX npm ci --unsafe-perm --production && npm cache clean --force && rm

# Copy and enable the service
COPY config/services /etc/systemd/system
RUN systemctl disable dnsmasq.service
RUN systemctl enable balena-mdns-publisher.service

# Build service
Expand Down
2 changes: 1 addition & 1 deletion bin/balena-mdns-publisher
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#!/usr/bin/env node
require('../build/app');
require('../build/mdns-publisher');
3 changes: 2 additions & 1 deletion config/confd_env_backend/conf.d/env.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ keys = [
"DBUS_SESSION_BUS_ADDRESS",
"BALENA_SUPERVISOR_ADDRESS",
"BALENA_SUPERVISOR_API_KEY",
"MDNS_API_TOKEN"
"MDNS_API_TOKEN",
"PROXY_DNS",
]
1 change: 1 addition & 0 deletions config/confd_env_backend/templates/env.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ DBUS_SESSION_BUS_ADDRESS={{getenv "DBUS_SESSION_BUS_ADDRESS"}}
BALENA_SUPERVISOR_ADDRESS={{getenv "BALENA_SUPERVISOR_ADDRESS"}}
BALENA_SUPERVISOR_API_KEY={{getenv "BALENA_SUPERVISOR_API_KEY"}}
MDNS_API_TOKEN={{getenv "MDNS_API_TOKEN"}}
PROXY_DNS={{getenv "PROXY_DNS"}}
NODE_EXTRA_CA_CERTS={{if getenv "BALENA_ROOT_CA"}}/etc/ssl/certs/balenaRootCA.pem{{end}}
43 changes: 41 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@
"bluebird": "^3.5.1",
"dbus-native": "^0.4.0",
"lodash": "^4.17.15",
"mz": "^2.7.0",
"request": "^2.88.0",
"request-promise": "^4.2.4"
},
"devDependencies": {
"@types/lodash": "^4.14.134",
"@types/mz": "0.0.32",
"@types/node": "^10.14.4",
"@types/request-promise": "^4.1.42",
"husky": "^1.3.1",
Expand Down
83 changes: 83 additions & 0 deletions src/dns-proxy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/**
* @license
* Copyright (C) 2018-2019 Balena Ltd.
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { spawn } from 'child_process';
import * as _ from 'lodash';
import * as fs from 'mz/fs';

import { getFullHostnames, getHostAddress } from './utils';

/**
* Creates the dnsmasq config from the subdomains.
*
* @param hosts The subdomains to provide DNS for.
* @param ipAddr The IP address to point DNS records to.
* @returns void promise.
*/
const configureDnsmasq = async (
hosts: string[],
ipAddr: string,
): Promise<void> => {
// Write all the host entries to a new dnsmasq configuration
let config = 'log-queries\n';

_.map(hosts, host => {
config += `address=/${host}/${ipAddr}`;
});

await fs.writeFile('/etc/dnsmasq.conf', config);
};

/**
* Start the dnsmasq process in debug mode for DNS proxying.
*
* @returns Void promise.
*/
export async function startDnsProxy(): Promise<void> {
// Configure the dnsmasq config
// Get the list of hostnames to DNS proxy for
const hosts = getFullHostnames();

try {
const ipAddr = await getHostAddress(process.env.INTERFACE);

// For each address, publish the interface IP address.
await configureDnsmasq(hosts, ipAddr);
} catch (err) {
console.log(`balena DNS proxier configuration error:\n${err}`);
}

// Start dnsmasq, log output to console
try {
const dnsmasq = spawn('/usr/sbin/dnsmasq', [
'-d',
'-x',
'/run/dnsmasq.pid',
]);

dnsmasq.stdout.on('data', data => {
console.log(`dnsmasq: ${data.toString()}`);
});
dnsmasq.stderr.on('data', data => {
console.error(`dnsmasq: Error - ${data}`);
});
dnsmasq.on('close', code => {
if (code !== 0) {
console.log(`dnsmasq: process exited with code ${code}`);
}
});
} catch (err) {
console.log(`dnsmasq: Could not launch daemon - ${err}`);
}
}
Loading

0 comments on commit 88db097

Please sign in to comment.