mirror of
https://github.com/paulmillr/encrypted-dns.git
synced 2026-10-01 05:29:59 +02:00
Update readme, add certs dir
This commit is contained in:
6 files changed
+109
-331
No files matched your search
@@ -0,0 +1,5 @@
|
|||||||
|
certs/cert.pem
|
||||||
|
certs/chain.pem
|
||||||
|
certs/fullchain.pem
|
||||||
|
certs/privkey.pem
|
||||||
|
certs/README
|
||||||
@@ -2,19 +2,7 @@ English | [简体中文](https://github.com/paulmillr/encrypted-dns/blob/master/
|
|||||||
|
|
||||||
# encrypted-dns-configs
|
# encrypted-dns-configs
|
||||||
|
|
||||||
Configuration profiles for [DNS over HTTPS](https://en.wikipedia.org/wiki/DNS_over_HTTPS) and [DNS over TLS](https://en.wikipedia.org/wiki/DNS_over_TLS). Check out the article for more info: [paulmillr.com/posts/encrypted-dns/](https://paulmillr.com/posts/encrypted-dns/). To add a new provider, or edit an existing one, edit json files in `src` directory.
|
Configuration profiles for [DNS over HTTPS](https://en.wikipedia.org/wiki/DNS_over_HTTPS) and [DNS over TLS](https://en.wikipedia.org/wiki/DNS_over_TLS). Check out the article for more info: [paulmillr.com/posts/encrypted-dns/](https://paulmillr.com/posts/encrypted-dns/). To add a new provider, or edit an existing one: see [#contributing](#contributing).
|
||||||
|
|
||||||
## Known issues
|
|
||||||
|
|
||||||
1. Some apps and protocols will ignore encrypted-dns:
|
|
||||||
- Firefox in specific regions, App Store in all regions. [More info](https://github.com/paulmillr/encrypted-dns/issues/22)
|
|
||||||
- iCloud Private Relay, VPN clients
|
|
||||||
- Little Snitch, LuLu
|
|
||||||
- DNS-related CLI tools: `host`, `dig`, `nslookup` etc.
|
|
||||||
2. [Wi-Fi captive portals](https://en.wikipedia.org/wiki/Captive_portal) in cafes, hotels, airports are exempted by Apple from eDNS rules; to simplify authentication - this is ok
|
|
||||||
3. TLS DNS is easier for providers to block, because it uses non-standard port 853.
|
|
||||||
[More info](https://security.googleblog.com/2022/07/dns-over-http3-in-android.html)
|
|
||||||
4. e-dns over TOR could be better privacy-wise, but we don't have this for now.
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
@@ -22,20 +10,20 @@ Install / download profile (`.mobileconfig` file) from a table below. After that
|
|||||||
|
|
||||||
iPhones, iPads:
|
iPhones, iPads:
|
||||||
|
|
||||||
1. Open the mobileconfig file in GitHub by using Safari (other browsers will just download the file and won't ask for installation)
|
1. Open the file by using Safari (other browsers will just download the file and won't ask for installation)
|
||||||
2. Tap on "Allow" button. The profile should download.
|
2. Tap on "Allow" button. The profile should download.
|
||||||
3. Go to **System Settings => General => VPN, DNS & Device Management**, select downloaded profile and tap the "Install" button.
|
3. Go to **System Settings => General => VPN, DNS & Device Management**, select downloaded profile and tap the "Install" button.
|
||||||
|
|
||||||
Mac:
|
Mac:
|
||||||
|
|
||||||
1. Ensure the downloaded file has proper extension: NAME.mobileconfig, not NAME.mobileconfig.txt.
|
1. Ensure the downloaded file has proper extension: NAME.mobileconfig, not NAME.mobileconfig.txt.
|
||||||
2. Choose Apple menu > System Settings, click Privacy and Security in the sidebar, then click Profiles on the right. (You may need to scroll down.)
|
2. Choose Apple menu > System Settings, click Privacy and Security in the sidebar, then click Profiles on the right.
|
||||||
3. You may be asked to supply your password or other information during installation.
|
You may need to scroll down. You may be asked to supply your password or other information during installation.
|
||||||
4. In the Downloaded section, double-click the profile. Review the profile contents then click Continue, Install or Enroll to install the profile. If an earlier version of a profile is already installed on your Mac, the settings in the updated version replace the previous ones.
|
3. In the Downloaded section, double-click the profile. Review the profile contents then click Continue, Install or Enroll to install the profile. If an earlier version of a profile is already installed on your Mac, the settings in the updated version replace the previous ones.
|
||||||
|
|
||||||
## Providers
|
## Providers
|
||||||
|
|
||||||
`Censorship=yes` (also known as "filtering") means the profile will not send true information about `hostname=IP` relation for some hosts.
|
Censorship (also known as "filtering") means the profile will not send true information about `hostname=IP` relation for some hosts.
|
||||||
|
|
||||||
| Name | Region | Censorship | Notes | Install | Install (unsigned) |
|
| Name | Region | Censorship | Notes | Install | Install (unsigned) |
|
||||||
| ------------------------------------------------------------------------------------ | ------ | ---------- | --------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
|
| ------------------------------------------------------------------------------------ | ------ | ---------- | --------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
|
||||||
@@ -77,17 +65,52 @@ Mac:
|
|||||||
| [Quad9 Unfiltered][quad9] | 🇨🇭 | No | Operated by Quad9 Foundation. | [HTTPS][quad9-profile-unfiltered-https-signed], [TLS][quad9-profile-unfiltered-tls-signed] | [HTTPS][quad9-profile-unfiltered-https], [TLS][quad9-profile-unfiltered-tls] |
|
| [Quad9 Unfiltered][quad9] | 🇨🇭 | No | Operated by Quad9 Foundation. | [HTTPS][quad9-profile-unfiltered-https-signed], [TLS][quad9-profile-unfiltered-tls-signed] | [HTTPS][quad9-profile-unfiltered-https], [TLS][quad9-profile-unfiltered-tls] |
|
||||||
| [Tiarap][tiarap] | 🇸🇬 🇺🇸 | Yes | Operated by Tiarap Inc. Blocks ads, tracking, phising & malware | [HTTPS][tiarap-profile-https-signed], [TLS][tiarap-profile-tls-signed] | [HTTPS][tiarap-profile-https], [TLS][tiarap-profile-tls] |
|
| [Tiarap][tiarap] | 🇸🇬 🇺🇸 | Yes | Operated by Tiarap Inc. Blocks ads, tracking, phising & malware | [HTTPS][tiarap-profile-https-signed], [TLS][tiarap-profile-tls-signed] | [HTTPS][tiarap-profile-https], [TLS][tiarap-profile-tls] |
|
||||||
|
|
||||||
## Signed Profiles
|
## Known issues
|
||||||
|
|
||||||
To verify resolver IPs and hostnames, compare mobileconfig files to their documentation URLs. Internal workings of the profiles are described on [developer.apple.com](https://developer.apple.com/documentation/devicemanagement/dnssettings). In order to verify signed mobileconfigs, you will need to download them to your computer and open them in a text editor, because signing profiles makes GitHub think that they are binary files.
|
1. Some apps and protocols will ignore encrypted-dns:
|
||||||
|
- Firefox in specific regions, App Store in all regions. [More info](https://github.com/paulmillr/encrypted-dns/issues/22)
|
||||||
|
- iCloud Private Relay, VPN clients
|
||||||
|
- Little Snitch, LuLu
|
||||||
|
- DNS-related CLI tools: `host`, `dig`, `nslookup` etc.
|
||||||
|
2. [Wi-Fi captive portals](https://en.wikipedia.org/wiki/Captive_portal) in cafes, hotels, airports are exempted by Apple from eDNS rules; to simplify authentication - this is ok
|
||||||
|
3. TLS DNS is easier for providers to block, because it uses non-standard port 853.
|
||||||
|
[More info](https://security.googleblog.com/2022/07/dns-over-http3-in-android.html)
|
||||||
|
4. e-dns over TOR could be better privacy-wise, but we don't have this for now.
|
||||||
|
|
||||||
## On demand activation
|
## Contributing
|
||||||
|
|
||||||
You can optionally exclude some trusted Wi-Fi networks where you don't want to use encrypted DNS. To do so, add your SSIDs in the [OnDemandRules](https://github.com/paulmillr/encrypted-dns/blob/master/profiles/template-on-demand.mobileconfig#L22-L38) section inside the `PayloadContent` dictionary of a profile. Note: you can't edit signed profiles.
|
- **To add / edit a profile:** edit json files in `src` directory.
|
||||||
|
- **To verify resolver IPs / hostnames:** compare mobileconfig files to their original websites (open files in a text editor).
|
||||||
|
- Check out [developer.apple.com](https://developer.apple.com/documentation/devicemanagement/dnssettings) for more docs.
|
||||||
|
- **On demand activation:** You can optionally exclude some trusted Wi-Fi networks where you don't want to use encrypted DNS. To do so, add your SSIDs in the [OnDemandRules](https://github.com/paulmillr/encrypted-dns/blob/master/profiles/template-on-demand.mobileconfig#L22-L38) section inside the `PayloadContent` dictionary of a profile.
|
||||||
|
|
||||||
## Contributing a new profile
|
### Scripts
|
||||||
|
|
||||||
To add a new provider, or edit an existing one, edit json files in `src` directory.
|
- `npm run build` - re-build profiles, signed profiles, READMEs
|
||||||
|
- `npm run sign` - re-sign all profiles (updates `signature` field) using an ECC SSL certificate.
|
||||||
|
- Signing is done using [key-producer](https://github.com/paulmillr/micro-key-producer)
|
||||||
|
- Let's Encrypt free certificates are OK, but [expire in 45 days](https://letsencrypt.org/2026/02/24/rate-limits-45-day-certs).
|
||||||
|
- Expects following files to be present in `certs` subdirectory:
|
||||||
|
|
||||||
|
```
|
||||||
|
`privkey.pem` : the private key for your certificate.
|
||||||
|
`fullchain.pem`: the certificate file used in most server software.
|
||||||
|
`chain.pem` : used for OCSP stapling in Nginx >=1.3.7.
|
||||||
|
`cert.pem`
|
||||||
|
```
|
||||||
|
|
||||||
|
- `npm run new` - interactively creates new profile from CLI options. Can also be ran with flags.
|
||||||
|
- `scripts/new.test.ts` includes CLI snapshot tests and a PTY interactive flow test.
|
||||||
|
- PTY test runs by default; set `NEW_TEST_PTY=0` to opt out.
|
||||||
|
- `node scripts/sign-single.ts --ca cert.pem --priv_key key.pem [--chain chain.pem] path.mobileconfig` - sings single mobileconfig
|
||||||
|
- `node scripts/sign-single-openssl.ts --ca cert.pem --priv_key key.pem [--chain chain.pem] path.mobileconfig` Sign one `.mobileconfig` using OpenSSL.
|
||||||
|
- Uses `-nosmimecap` to match local CMS signing policy.
|
||||||
|
- `node scripts/detach.ts signed.mobileconfig` - detach CMS signature from signed profile and print PEM to stdout.
|
||||||
|
- `node test/sign-single.test.ts` - Parity check for `sign-single.ts` vs `sign-single-openssl.sh`.
|
||||||
|
- Runs under `npm run test`.
|
||||||
|
- Generates temporary test root/signer certificates and keys via OpenSSL.
|
||||||
|
- Signs the same profile with `scripts/sign.ts` and `scripts/sign_openssl.sh`.
|
||||||
|
- Verifies detached content and embedded certificate set parity.
|
||||||
|
|
||||||
[360-dns]: https://sdns.360.net/dnsPublic.html
|
[360-dns]: https://sdns.360.net/dnsPublic.html
|
||||||
[360-dns-profile-https]: https://github.com/paulmillr/encrypted-dns/raw/master/profiles/360-https.mobileconfig
|
[360-dns-profile-https]: https://github.com/paulmillr/encrypted-dns/raw/master/profiles/360-https.mobileconfig
|
||||||
|
|||||||
Whitespace-only changes.
-275
@@ -1,275 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
const fs = require('node:fs');
|
|
||||||
const path = require('node:path');
|
|
||||||
|
|
||||||
const LANGUAGES_DIR = path.join(__dirname, 'src-languages');
|
|
||||||
const PROVIDERS_PATH = path.join(__dirname, 'src');
|
|
||||||
const DEFAULT_LANG = 'en';
|
|
||||||
const OUTPUT_DIR = __dirname;
|
|
||||||
const REPO_RAW = 'https://github.com/paulmillr/encrypted-dns/raw/master';
|
|
||||||
|
|
||||||
const REGIONS = {
|
|
||||||
US: '🇺🇸',
|
|
||||||
CN: '🇨🇳',
|
|
||||||
RU: '🇷🇺',
|
|
||||||
NL: '🇳🇱',
|
|
||||||
DE: '🇩🇪',
|
|
||||||
SG: '🇸🇬',
|
|
||||||
CA: '🇨🇦',
|
|
||||||
FR: '🇫🇷',
|
|
||||||
CH: '🇨🇭',
|
|
||||||
SE: '🇸🇪',
|
|
||||||
CZ: '🇨🇿',
|
|
||||||
};
|
|
||||||
|
|
||||||
const providerFile = (p, https, signed) => {
|
|
||||||
const postfix = (p, https) => {
|
|
||||||
if (https) {
|
|
||||||
if (p.doh && p.doh !== true) return `doh${p.doh}`;
|
|
||||||
if (p.doh) return 'doh';
|
|
||||||
return 'https';
|
|
||||||
} else {
|
|
||||||
if (p.doh && p.doh !== true) return `dot${p.doh}`;
|
|
||||||
if (p.doh) return 'dot';
|
|
||||||
return 'tls';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const name = p.name || p.id;
|
|
||||||
return `${signed ? 'signed' : 'profiles'}/${name}-${postfix(p, https)}.mobileconfig`;
|
|
||||||
};
|
|
||||||
|
|
||||||
const languages = fs
|
|
||||||
.readdirSync(LANGUAGES_DIR)
|
|
||||||
.filter((f) => f.endsWith('.json'))
|
|
||||||
.sort()
|
|
||||||
.map((f) => {
|
|
||||||
const p = path.join(LANGUAGES_DIR, f);
|
|
||||||
const data = JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
||||||
return {
|
|
||||||
code: data.code,
|
|
||||||
name: data.name,
|
|
||||||
mdFile: p.replace('.json', '.md'),
|
|
||||||
jsonFile: p,
|
|
||||||
data: data,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const providers = fs
|
|
||||||
.readdirSync(PROVIDERS_PATH)
|
|
||||||
.sort()
|
|
||||||
.map((i) => JSON.parse(fs.readFileSync(`${PROVIDERS_PATH}/${i}`)))
|
|
||||||
.map((i) => {
|
|
||||||
const unsigned = {
|
|
||||||
https: !!i.https || fs.existsSync(providerFile(i, true)),
|
|
||||||
tls: !!i.tls || fs.existsSync(providerFile(i, false)),
|
|
||||||
};
|
|
||||||
const signed = {
|
|
||||||
https: unsigned.https && fs.existsSync(providerFile(i, true, true)),
|
|
||||||
tls: unsigned.tls && fs.existsSync(providerFile(i, false, true)),
|
|
||||||
};
|
|
||||||
return { ...i, formats: { unsigned, signed } };
|
|
||||||
});
|
|
||||||
|
|
||||||
const FULLWIDTH_PATTERN =
|
|
||||||
/[\u1100-\u115F\u2329\u232A\u2E80-\u303E\u3040-\uA4CF\uAC00-\uD7A3\uF900-\uFAFF\uFE10-\uFE19\uFE30-\uFE6F\uFF00-\uFF60\uFFE0-\uFFE6]/u;
|
|
||||||
function chrWidth(str) {
|
|
||||||
let width = 0;
|
|
||||||
for (const char of str) width += FULLWIDTH_PATTERN.test(char) || REGIONS[char] ? 2 : 1;
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
const padEnd = (s, len, chr) => `${s}${chr.repeat(Math.max(0, len - chrWidth(s)))}`;
|
|
||||||
|
|
||||||
const genTable = (rows) => {
|
|
||||||
// first row is header
|
|
||||||
const widths = rows[0].map((i) => 0);
|
|
||||||
// Collect cell widths
|
|
||||||
for (const r of rows) {
|
|
||||||
for (let i = 0; i < r.length; i++) widths[i] = Math.max(widths[i], chrWidth(r[i]));
|
|
||||||
}
|
|
||||||
let table = '';
|
|
||||||
rows.forEach((r, i) => {
|
|
||||||
const cells = r.map((c, j) => padEnd(c, widths[j], ' ')).join(' | ');
|
|
||||||
table += `| ${cells} |\n`;
|
|
||||||
if (i === 0) table += `| ${r.map((c, j) => padEnd('', widths[j], '-')).join(' | ')} |\n`;
|
|
||||||
});
|
|
||||||
return table;
|
|
||||||
};
|
|
||||||
|
|
||||||
const TAGS = {
|
|
||||||
// Language selection header
|
|
||||||
LANGUAGES: (currentLang) => {
|
|
||||||
return languages
|
|
||||||
.map((lang) => {
|
|
||||||
if (lang.code === currentLang.code) return lang.name;
|
|
||||||
return `[${lang.name}](https://github.com/paulmillr/encrypted-dns/${
|
|
||||||
lang.code === DEFAULT_LANG ? '' : `blob/master/README.${lang.code}.md`
|
|
||||||
})`;
|
|
||||||
})
|
|
||||||
.join(' | ');
|
|
||||||
},
|
|
||||||
PROVIDERS_TABLE: (currentLang) => {
|
|
||||||
const rows = [
|
|
||||||
// header
|
|
||||||
[
|
|
||||||
currentLang.data.table_columns.name,
|
|
||||||
currentLang.data.table_columns.region,
|
|
||||||
currentLang.data.table_columns.censorship,
|
|
||||||
currentLang.data.table_columns.notes,
|
|
||||||
currentLang.data.table_columns.install_signed,
|
|
||||||
currentLang.data.table_columns.install_unsigned,
|
|
||||||
],
|
|
||||||
];
|
|
||||||
const sorted = Array.from(providers).sort((a, b) => a.id.localeCompare(b.id));
|
|
||||||
for (const provider of sorted) {
|
|
||||||
const name = provider.names[currentLang.code] || provider.names[DEFAULT_LANG];
|
|
||||||
const note = provider.notes[currentLang.code] || provider.notes[DEFAULT_LANG];
|
|
||||||
const censorship = provider.censorship ? currentLang.data.yes : currentLang.data.no;
|
|
||||||
const regionEmoji = (Array.isArray(provider.region) ? provider.region : [provider.region])
|
|
||||||
.map((r) => REGIONS[r])
|
|
||||||
.join(' ');
|
|
||||||
const unsignedLinks = [];
|
|
||||||
if (provider.formats.unsigned && provider.formats.unsigned.https)
|
|
||||||
unsignedLinks.push(`[HTTPS][${provider.profile}-https]`);
|
|
||||||
if (provider.formats.unsigned && provider.formats.unsigned.tls)
|
|
||||||
unsignedLinks.push(`[TLS][${provider.profile}-tls]`);
|
|
||||||
const signedLinks = [];
|
|
||||||
if (provider.formats.signed && provider.formats.signed.https)
|
|
||||||
signedLinks.push(`[HTTPS][${provider.profile}-https-signed]`);
|
|
||||||
if (provider.formats.signed && provider.formats.signed.tls)
|
|
||||||
signedLinks.push(`[TLS][${provider.profile}-tls-signed]`);
|
|
||||||
rows.push([
|
|
||||||
`[${name}][${provider.id}]`,
|
|
||||||
regionEmoji,
|
|
||||||
censorship,
|
|
||||||
note,
|
|
||||||
signedLinks.join(', '),
|
|
||||||
unsignedLinks.join(', '),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
return genTable(rows).trim();
|
|
||||||
},
|
|
||||||
PROVIDERS_LINKS: (currentLang) => {
|
|
||||||
let res = '';
|
|
||||||
const addLink = (p, https, signed) => {
|
|
||||||
const file = providerFile(p, https, signed);
|
|
||||||
if (!fs.existsSync(`./${file}`)) throw new Error('missing: ' + file);
|
|
||||||
res += `[${p.profile}-${https ? 'https' : 'tls'}${
|
|
||||||
signed ? '-signed' : ''
|
|
||||||
}]: ${REPO_RAW}/${file}\n`;
|
|
||||||
};
|
|
||||||
for (const p of providers) {
|
|
||||||
if (p.website) res += `[${p.id}]: ${p.website}\n`;
|
|
||||||
if (p.formats.unsigned.https) addLink(p, true);
|
|
||||||
if (p.formats.unsigned.tls) addLink(p, false);
|
|
||||||
}
|
|
||||||
// signed
|
|
||||||
for (const p of providers) {
|
|
||||||
if (p.formats.signed.https) addLink(p, true, true);
|
|
||||||
if (p.formats.signed.tls) addLink(p, false, true);
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
function processTemplate(templateContent, lang) {
|
|
||||||
let content = templateContent;
|
|
||||||
for (const [tag, handler] of Object.entries(TAGS)) {
|
|
||||||
const tagPattern = new RegExp(`<%${tag}%>`, 'g');
|
|
||||||
if (content.match(tagPattern)) content = content.replace(tagPattern, handler(lang));
|
|
||||||
}
|
|
||||||
return content;
|
|
||||||
}
|
|
||||||
|
|
||||||
function generateReadmes() {
|
|
||||||
for (const lang of languages) {
|
|
||||||
if (!fs.existsSync(lang.mdFile)) throw new Error(`Template file not found: ${lang.mdFile}`);
|
|
||||||
const tpl = fs.readFileSync(lang.mdFile, 'utf8');
|
|
||||||
const processed = processTemplate(tpl, lang);
|
|
||||||
const out = lang.code === DEFAULT_LANG ? 'README.md' : `README.${lang.code}.md`;
|
|
||||||
fs.writeFileSync(path.join(OUTPUT_DIR, out), processed, 'utf8');
|
|
||||||
console.log(`Generated ${out}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function generateSingle(x) {
|
|
||||||
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>PayloadContent</key>
|
|
||||||
<array>
|
|
||||||
<dict>
|
|
||||||
<key>DNSSettings</key>
|
|
||||||
<dict>
|
|
||||||
<key>DNSProtocol</key>
|
|
||||||
<string>${x.DNSProtocol}</string>
|
|
||||||
<key>ServerAddresses</key>
|
|
||||||
<array>
|
|
||||||
${x.ServerAddresses.map((i) => `\t\t\t\t\t<string>${i}</string>`).join('\n')}
|
|
||||||
</array>
|
|
||||||
<key>${!x.ServerURLOrName.startsWith('https://') ? 'ServerName' : 'ServerURL'}</key>
|
|
||||||
<string>${x.ServerURLOrName}</string>
|
|
||||||
</dict>
|
|
||||||
<key>PayloadDescription</key>
|
|
||||||
<string>Configures device to use ${x.name}</string>
|
|
||||||
<key>PayloadDisplayName</key>
|
|
||||||
<string>${x.PayloadDisplayName}</string>
|
|
||||||
<key>PayloadIdentifier</key>
|
|
||||||
<string>${x.PayloadIdentifier}</string>
|
|
||||||
<key>PayloadType</key>
|
|
||||||
<string>com.apple.dnsSettings.managed</string>
|
|
||||||
<key>PayloadUUID</key>
|
|
||||||
<string>${x.PayloadUUID}</string>
|
|
||||||
<key>PayloadVersion</key>
|
|
||||||
<integer>1</integer>
|
|
||||||
<key>ProhibitDisablement</key>
|
|
||||||
<false/>
|
|
||||||
</dict>
|
|
||||||
</array>
|
|
||||||
<key>PayloadDescription</key>
|
|
||||||
<string>Adds the ${x.fullName} to Big Sur and iOS 14 based systems</string>
|
|
||||||
<key>PayloadDisplayName</key>
|
|
||||||
<string>${x.topName}</string>
|
|
||||||
<key>PayloadIdentifier</key>
|
|
||||||
<string>com.paulmillr.apple-dns</string>
|
|
||||||
<key>PayloadRemovalDisallowed</key>
|
|
||||||
<false/>
|
|
||||||
<key>PayloadScope</key>
|
|
||||||
<string>System</string>
|
|
||||||
<key>PayloadType</key>
|
|
||||||
<string>Configuration</string>
|
|
||||||
<key>PayloadUUID</key>
|
|
||||||
<string>${x.TopPayloadUUID}</string>
|
|
||||||
<key>PayloadVersion</key>
|
|
||||||
<integer>1</integer>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function generateConfigs() {
|
|
||||||
function generate(file, parsed) {
|
|
||||||
if (!parsed) return;
|
|
||||||
fs.writeFileSync(file, generateSingle(parsed));
|
|
||||||
console.log(`Generated ${file}`);
|
|
||||||
}
|
|
||||||
for (const p of providers) {
|
|
||||||
if (p.formats.unsigned.https) generate(providerFile(p, true), p.https);
|
|
||||||
if (p.formats.unsigned.tls) generate(providerFile(p, false), p.tls);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Small utility to rewrite config structure
|
|
||||||
function patchConfigs() {
|
|
||||||
for (const f of fs.readdirSync(`./src/`)) {
|
|
||||||
const path = `./src/${f}`;
|
|
||||||
const json = JSON.parse(fs.readFileSync(path, 'utf8'));
|
|
||||||
fs.writeFileSync(path, JSON.stringify(json, null, 4));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function main() {
|
|
||||||
//patchConfigs();
|
|
||||||
generateReadmes();
|
|
||||||
generateConfigs();
|
|
||||||
}
|
|
||||||
main();
|
|
||||||
+4
-2
@@ -4,8 +4,10 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build:clean": "rm -f signed/*.mobileconfig profiles/*.mobileconfig README*.md",
|
"build:clean": "rm -f signed/*.mobileconfig profiles/*.mobileconfig README*.md",
|
||||||
"build": "npm run build:clean && node scripts/generate.ts",
|
"build": "npm run build:clean && node scripts/build.ts",
|
||||||
"test": "node --experimental-strip-types --test scripts/new.test.ts scripts/sign.test.ts",
|
"sign": "node scripts/sign.ts",
|
||||||
|
"new": "node scripts/new.ts",
|
||||||
|
"test": "node --experimental-strip-types --test scripts/new.test.ts scripts/sign-single.test.ts",
|
||||||
"format": "prettier --write \"src/*.json\" scripts/*.ts *.ts"
|
"format": "prettier --write \"src/*.json\" scripts/*.ts *.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
+53
-30
@@ -2,7 +2,30 @@
|
|||||||
|
|
||||||
# encrypted-dns-configs
|
# encrypted-dns-configs
|
||||||
|
|
||||||
Configuration profiles for [DNS over HTTPS](https://en.wikipedia.org/wiki/DNS_over_HTTPS) and [DNS over TLS](https://en.wikipedia.org/wiki/DNS_over_TLS). Check out the article for more info: [paulmillr.com/posts/encrypted-dns/](https://paulmillr.com/posts/encrypted-dns/). To add a new provider, or edit an existing one, edit json files in `src` directory.
|
Configuration profiles for [DNS over HTTPS](https://en.wikipedia.org/wiki/DNS_over_HTTPS) and [DNS over TLS](https://en.wikipedia.org/wiki/DNS_over_TLS). Check out the article for more info: [paulmillr.com/posts/encrypted-dns/](https://paulmillr.com/posts/encrypted-dns/). To add a new provider, or edit an existing one: see [#contributing](#contributing).
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Install / download profile (`.mobileconfig` file) from a table below. After that:
|
||||||
|
|
||||||
|
iPhones, iPads:
|
||||||
|
|
||||||
|
1. Open the file by using Safari (other browsers will just download the file and won't ask for installation)
|
||||||
|
2. Tap on "Allow" button. The profile should download.
|
||||||
|
3. Go to **System Settings => General => VPN, DNS & Device Management**, select downloaded profile and tap the "Install" button.
|
||||||
|
|
||||||
|
Mac:
|
||||||
|
|
||||||
|
1. Ensure the downloaded file has proper extension: NAME.mobileconfig, not NAME.mobileconfig.txt.
|
||||||
|
2. Choose Apple menu > System Settings, click Privacy and Security in the sidebar, then click Profiles on the right.
|
||||||
|
You may need to scroll down. You may be asked to supply your password or other information during installation.
|
||||||
|
3. In the Downloaded section, double-click the profile. Review the profile contents then click Continue, Install or Enroll to install the profile. If an earlier version of a profile is already installed on your Mac, the settings in the updated version replace the previous ones.
|
||||||
|
|
||||||
|
## Providers
|
||||||
|
|
||||||
|
Censorship (also known as "filtering") means the profile will not send true information about `hostname=IP` relation for some hosts.
|
||||||
|
|
||||||
|
<%PROVIDERS_TABLE%>
|
||||||
|
|
||||||
## Known issues
|
## Known issues
|
||||||
|
|
||||||
@@ -16,39 +39,39 @@ Configuration profiles for [DNS over HTTPS](https://en.wikipedia.org/wiki/DNS_ov
|
|||||||
[More info](https://security.googleblog.com/2022/07/dns-over-http3-in-android.html)
|
[More info](https://security.googleblog.com/2022/07/dns-over-http3-in-android.html)
|
||||||
4. e-dns over TOR could be better privacy-wise, but we don't have this for now.
|
4. e-dns over TOR could be better privacy-wise, but we don't have this for now.
|
||||||
|
|
||||||
## Usage
|
## Contributing
|
||||||
|
|
||||||
Install / download profile (`.mobileconfig` file) from a table below. After that:
|
- **To add / edit a profile:** edit json files in `src` directory.
|
||||||
|
- **To verify resolver IPs / hostnames:** compare mobileconfig files to their original websites (open files in a text editor).
|
||||||
|
- Check out [developer.apple.com](https://developer.apple.com/documentation/devicemanagement/dnssettings) for more docs.
|
||||||
|
- **On demand activation:** You can optionally exclude some trusted Wi-Fi networks where you don't want to use encrypted DNS. To do so, add your SSIDs in the [OnDemandRules](https://github.com/paulmillr/encrypted-dns/blob/master/profiles/template-on-demand.mobileconfig#L22-L38) section inside the `PayloadContent` dictionary of a profile.
|
||||||
|
|
||||||
iPhones, iPads:
|
### Scripts
|
||||||
|
|
||||||
1. Open the mobileconfig file in GitHub by using Safari (other browsers will just download the file and won't ask for installation)
|
- `npm run build` - re-build profiles, signed profiles, READMEs
|
||||||
2. Tap on "Allow" button. The profile should download.
|
- `npm run sign` - re-sign all profiles (updates `signature` field) using an ECC SSL certificate.
|
||||||
3. Go to **System Settings => General => VPN, DNS & Device Management**, select downloaded profile and tap the "Install" button.
|
- Signing is done using [key-producer](https://github.com/paulmillr/micro-key-producer)
|
||||||
|
- Let's Encrypt free certificates are OK, but [expire in 45 days](https://letsencrypt.org/2026/02/24/rate-limits-45-day-certs).
|
||||||
|
- Expects following files to be present in `certs` subdirectory:
|
||||||
|
|
||||||
Mac:
|
```
|
||||||
|
`privkey.pem` : the private key for your certificate.
|
||||||
|
`fullchain.pem`: the certificate file used in most server software.
|
||||||
|
`chain.pem` : used for OCSP stapling in Nginx >=1.3.7.
|
||||||
|
`cert.pem`
|
||||||
|
```
|
||||||
|
|
||||||
1. Ensure the downloaded file has proper extension: NAME.mobileconfig, not NAME.mobileconfig.txt.
|
- `npm run new` - interactively creates new profile from CLI options. Can also be ran with flags.
|
||||||
2. Choose Apple menu > System Settings, click Privacy and Security in the sidebar, then click Profiles on the right. (You may need to scroll down.)
|
- `scripts/new.test.ts` includes CLI snapshot tests and a PTY interactive flow test.
|
||||||
3. You may be asked to supply your password or other information during installation.
|
- PTY test runs by default; set `NEW_TEST_PTY=0` to opt out.
|
||||||
4. In the Downloaded section, double-click the profile. Review the profile contents then click Continue, Install or Enroll to install the profile. If an earlier version of a profile is already installed on your Mac, the settings in the updated version replace the previous ones.
|
- `node scripts/sign-single.ts --ca cert.pem --priv_key key.pem [--chain chain.pem] path.mobileconfig` - sings single mobileconfig
|
||||||
|
- `node scripts/sign-single-openssl.ts --ca cert.pem --priv_key key.pem [--chain chain.pem] path.mobileconfig` Sign one `.mobileconfig` using OpenSSL.
|
||||||
## Providers
|
- Uses `-nosmimecap` to match local CMS signing policy.
|
||||||
|
- `node scripts/detach.ts signed.mobileconfig` - detach CMS signature from signed profile and print PEM to stdout.
|
||||||
`Censorship=yes` (also known as "filtering") means the profile will not send true information about `hostname=IP` relation for some hosts.
|
- `node test/sign-single.test.ts` - Parity check for `sign-single.ts` vs `sign-single-openssl.sh`.
|
||||||
|
- Runs under `npm run test`.
|
||||||
<%PROVIDERS_TABLE%>
|
- Generates temporary test root/signer certificates and keys via OpenSSL.
|
||||||
|
- Signs the same profile with `scripts/sign.ts` and `scripts/sign_openssl.sh`.
|
||||||
## Signed Profiles
|
- Verifies detached content and embedded certificate set parity.
|
||||||
|
|
||||||
To verify resolver IPs and hostnames, compare mobileconfig files to their documentation URLs. Internal workings of the profiles are described on [developer.apple.com](https://developer.apple.com/documentation/devicemanagement/dnssettings). In order to verify signed mobileconfigs, you will need to download them to your computer and open them in a text editor, because signing profiles makes GitHub think that they are binary files.
|
|
||||||
|
|
||||||
## On demand activation
|
|
||||||
|
|
||||||
You can optionally exclude some trusted Wi-Fi networks where you don't want to use encrypted DNS. To do so, add your SSIDs in the [OnDemandRules](https://github.com/paulmillr/encrypted-dns/blob/master/profiles/template-on-demand.mobileconfig#L22-L38) section inside the `PayloadContent` dictionary of a profile. Note: you can't edit signed profiles.
|
|
||||||
|
|
||||||
## Contributing a new profile
|
|
||||||
|
|
||||||
To add a new provider, or edit an existing one, edit json files in `src` directory.
|
|
||||||
|
|
||||||
<%PROVIDERS_LINKS%>
|
<%PROVIDERS_LINKS%>
|
||||||
Reference in new issue
Block a user