2017-09-16 01:12:09 +08:00
|
|
|
'use strict';
|
2016-08-23 08:31:50 +08:00
|
|
|
|
2020-07-10 00:52:49 +08:00
|
|
|
// If you edit this file, you must run `go generate` to embed this
|
|
|
|
// file in the source code.
|
|
|
|
// If you are heavily debugging this code, the "-dev" flag will
|
|
|
|
// read this file directly instead of using the output of
|
|
|
|
// `go generate`. You'll still need to run `go generate` before
|
|
|
|
// you commit the changes.
|
|
|
|
|
2016-08-23 08:31:50 +08:00
|
|
|
var conf = {
|
|
|
|
registrars: [],
|
2016-12-17 04:10:27 +08:00
|
|
|
dns_providers: [],
|
2017-09-16 01:12:09 +08:00
|
|
|
domains: [],
|
2017-11-15 12:14:45 +08:00
|
|
|
domain_names: [],
|
2016-08-23 08:31:50 +08:00
|
|
|
};
|
|
|
|
|
2016-12-17 04:10:27 +08:00
|
|
|
var defaultArgs = [];
|
2016-08-23 08:31:50 +08:00
|
|
|
|
2017-09-16 01:12:09 +08:00
|
|
|
function initialize() {
|
2016-08-23 08:31:50 +08:00
|
|
|
conf = {
|
|
|
|
registrars: [],
|
2016-12-17 04:10:27 +08:00
|
|
|
dns_providers: [],
|
2017-09-16 01:12:09 +08:00
|
|
|
domains: [],
|
2016-08-23 08:31:50 +08:00
|
|
|
};
|
2016-12-17 04:10:27 +08:00
|
|
|
defaultArgs = [];
|
2016-08-23 08:31:50 +08:00
|
|
|
}
|
|
|
|
|
2020-08-04 21:43:02 +08:00
|
|
|
// Returns an array of domains which were registered so far during runtime
|
|
|
|
// Own function for compatibility reasons or if some day special processing would be required.
|
|
|
|
function getConfiguredDomains() {
|
|
|
|
return conf.domain_names;
|
|
|
|
}
|
|
|
|
|
2017-09-16 01:12:09 +08:00
|
|
|
function NewRegistrar(name, type, meta) {
|
2016-08-23 08:31:50 +08:00
|
|
|
if (type) {
|
2017-09-16 01:12:09 +08:00
|
|
|
type == 'MANUAL';
|
2016-08-23 08:31:50 +08:00
|
|
|
}
|
2017-09-16 01:12:09 +08:00
|
|
|
var reg = { name: name, type: type, meta: meta };
|
2016-08-23 08:31:50 +08:00
|
|
|
conf.registrars.push(reg);
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
2016-12-17 04:10:27 +08:00
|
|
|
function NewDnsProvider(name, type, meta) {
|
2017-09-16 01:12:09 +08:00
|
|
|
if (typeof meta === 'object' && 'ip_conversions' in meta) {
|
|
|
|
meta.ip_conversions = format_tt(meta.ip_conversions);
|
2016-08-23 08:31:50 +08:00
|
|
|
}
|
2017-09-16 01:12:09 +08:00
|
|
|
var dsp = { name: name, type: type, meta: meta };
|
2016-12-17 04:10:27 +08:00
|
|
|
conf.dns_providers.push(dsp);
|
2016-08-23 08:31:50 +08:00
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
2017-09-16 01:12:09 +08:00
|
|
|
function newDomain(name, registrar) {
|
|
|
|
return {
|
|
|
|
name: name,
|
|
|
|
registrar: registrar,
|
|
|
|
meta: {},
|
|
|
|
records: [],
|
|
|
|
dnsProviders: {},
|
|
|
|
defaultTTL: 0,
|
|
|
|
nameservers: [],
|
2020-08-18 23:14:34 +08:00
|
|
|
ignored_names: [],
|
|
|
|
ignored_targets: [],
|
2017-09-16 01:12:09 +08:00
|
|
|
};
|
2016-08-23 08:31:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
function processDargs(m, domain) {
|
2017-09-16 01:12:09 +08:00
|
|
|
// for each modifier, if it is a...
|
|
|
|
// function: call it with domain
|
|
|
|
// array: process recursively
|
|
|
|
// object: merge it into metadata
|
|
|
|
if (_.isFunction(m)) {
|
|
|
|
m(domain);
|
|
|
|
} else if (_.isArray(m)) {
|
|
|
|
for (var j in m) {
|
|
|
|
processDargs(m[j], domain);
|
2016-08-23 08:31:50 +08:00
|
|
|
}
|
2017-09-16 01:12:09 +08:00
|
|
|
} else if (_.isObject(m)) {
|
|
|
|
_.extend(domain.meta, m);
|
|
|
|
} else {
|
|
|
|
throw 'WARNING: domain modifier type unsupported: ' +
|
|
|
|
typeof m +
|
|
|
|
' Domain: ' +
|
|
|
|
domain.name;
|
|
|
|
}
|
2016-08-23 08:31:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// D(name,registrar): Create a DNS Domain. Use the parameters as records and mods.
|
2017-09-16 01:12:09 +08:00
|
|
|
function D(name, registrar) {
|
|
|
|
var domain = newDomain(name, registrar);
|
|
|
|
for (var i = 0; i < defaultArgs.length; i++) {
|
|
|
|
processDargs(defaultArgs[i], domain);
|
|
|
|
}
|
|
|
|
for (var i = 2; i < arguments.length; i++) {
|
2016-08-23 08:31:50 +08:00
|
|
|
var m = arguments[i];
|
2017-09-16 01:12:09 +08:00
|
|
|
processDargs(m, domain);
|
2016-08-23 08:31:50 +08:00
|
|
|
}
|
2017-12-07 04:56:57 +08:00
|
|
|
if (conf.domain_names.indexOf(name) !== -1) {
|
|
|
|
throw name + ' is declared more than once';
|
2017-11-15 12:14:45 +08:00
|
|
|
}
|
2017-09-16 01:12:09 +08:00
|
|
|
conf.domains.push(domain);
|
2017-11-15 12:14:45 +08:00
|
|
|
conf.domain_names.push(name);
|
2016-08-23 08:31:50 +08:00
|
|
|
}
|
|
|
|
|
2020-08-04 21:43:02 +08:00
|
|
|
// DU(name): Update an already added DNS Domain with D().
|
|
|
|
function D_EXTEND(name) {
|
|
|
|
var domain = _getDomainObject(name);
|
|
|
|
if (domain == null) {
|
|
|
|
throw name + ' was not declared yet and therefore cannot be updated. Use D() before.';
|
|
|
|
}
|
|
|
|
for (var i = 0; i < defaultArgs.length; i++) {
|
|
|
|
processDargs(defaultArgs[i], domain.obj);
|
|
|
|
}
|
|
|
|
for (var i = 1; i < arguments.length; i++) {
|
|
|
|
var m = arguments[i];
|
|
|
|
processDargs(m, domain.obj);
|
|
|
|
}
|
|
|
|
conf.domains[domain.id] = domain.obj; // let's overwrite the object.
|
|
|
|
}
|
|
|
|
|
|
|
|
// _getDomainObject(name): This is a small helper function to get the domain JS object returned.
|
|
|
|
function _getDomainObject(name) {
|
|
|
|
for(var i = 0; i < conf.domains.length; i++) {
|
|
|
|
if (conf.domains[i]['name'] == name) {
|
|
|
|
return {'id': i, 'obj': conf.domains[i]};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2016-12-17 04:10:27 +08:00
|
|
|
// DEFAULTS provides a set of default arguments to apply to all future domains.
|
|
|
|
// Each call to DEFAULTS will clear any previous values set.
|
2017-09-16 01:12:09 +08:00
|
|
|
function DEFAULTS() {
|
2016-12-17 04:10:27 +08:00
|
|
|
defaultArgs = [];
|
2017-09-16 01:12:09 +08:00
|
|
|
for (var i = 0; i < arguments.length; i++) {
|
2016-12-17 04:10:27 +08:00
|
|
|
defaultArgs.push(arguments[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-23 08:31:50 +08:00
|
|
|
// TTL(v): Set the TTL for a DNS record.
|
|
|
|
function TTL(v) {
|
2017-09-16 01:12:09 +08:00
|
|
|
if (_.isString(v)) {
|
2017-06-08 21:15:14 +08:00
|
|
|
v = stringToDuration(v);
|
|
|
|
}
|
2016-08-23 08:31:50 +08:00
|
|
|
return function(r) {
|
|
|
|
r.ttl = v;
|
2017-09-16 01:12:09 +08:00
|
|
|
};
|
2016-08-23 08:31:50 +08:00
|
|
|
}
|
|
|
|
|
2017-09-16 01:12:09 +08:00
|
|
|
function stringToDuration(v) {
|
2017-06-08 21:15:14 +08:00
|
|
|
var matches = v.match(/^(\d+)([smhdwny]?)$/);
|
2017-09-16 01:12:09 +08:00
|
|
|
if (matches == null) {
|
|
|
|
throw v + ' is not a valid duration string';
|
2017-06-08 21:15:14 +08:00
|
|
|
}
|
2017-09-16 01:12:09 +08:00
|
|
|
unit = 's';
|
|
|
|
if (matches[2]) {
|
|
|
|
unit = matches[2];
|
2017-06-08 21:15:14 +08:00
|
|
|
}
|
2017-09-16 01:12:09 +08:00
|
|
|
v = parseInt(matches[1]);
|
|
|
|
var u = { s: 1, m: 60, h: 3600 };
|
|
|
|
u['d'] = u.h * 24;
|
|
|
|
u['w'] = u.d * 7;
|
|
|
|
u['n'] = u.d * 30;
|
|
|
|
u['y'] = u.d * 365;
|
2017-06-08 21:15:14 +08:00
|
|
|
v *= u[unit];
|
2017-09-16 01:12:09 +08:00
|
|
|
return v;
|
2017-06-08 21:15:14 +08:00
|
|
|
}
|
|
|
|
|
2016-08-23 08:31:50 +08:00
|
|
|
// DefaultTTL(v): Set the default TTL for the domain.
|
|
|
|
function DefaultTTL(v) {
|
2017-09-16 01:12:09 +08:00
|
|
|
if (_.isString(v)) {
|
2017-06-08 21:15:14 +08:00
|
|
|
v = stringToDuration(v);
|
|
|
|
}
|
2016-08-23 08:31:50 +08:00
|
|
|
return function(d) {
|
|
|
|
d.defaultTTL = v;
|
2017-09-16 01:12:09 +08:00
|
|
|
};
|
2016-08-23 08:31:50 +08:00
|
|
|
}
|
|
|
|
|
2017-09-16 01:12:09 +08:00
|
|
|
function makeCAAFlag(value) {
|
|
|
|
return function(record) {
|
2017-08-12 02:48:43 +08:00
|
|
|
record.caaflag |= value;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2017-07-26 02:59:40 +08:00
|
|
|
// CAA_CRITICAL: Critical CAA flag
|
2018-02-10 03:03:40 +08:00
|
|
|
var CAA_CRITICAL = makeCAAFlag(1 << 7);
|
2016-12-17 04:10:27 +08:00
|
|
|
|
2017-09-16 01:12:09 +08:00
|
|
|
// DnsProvider("providerName", 0)
|
2016-12-17 04:10:27 +08:00
|
|
|
// nsCount of 0 means don't use or register any nameservers.
|
|
|
|
// nsCount not provider means use all.
|
2017-09-16 01:12:09 +08:00
|
|
|
function DnsProvider(name, nsCount) {
|
|
|
|
if (typeof nsCount === 'undefined') {
|
2016-12-17 04:10:27 +08:00
|
|
|
nsCount = -1;
|
|
|
|
}
|
|
|
|
return function(d) {
|
|
|
|
d.dnsProviders[name] = nsCount;
|
2017-09-16 01:12:09 +08:00
|
|
|
};
|
2016-12-17 04:10:27 +08:00
|
|
|
}
|
|
|
|
|
2016-08-23 08:31:50 +08:00
|
|
|
// A(name,ip, recordModifiers...)
|
2017-08-12 02:48:43 +08:00
|
|
|
var A = recordBuilder('A');
|
2016-08-23 08:31:50 +08:00
|
|
|
|
|
|
|
// AAAA(name,ip, recordModifiers...)
|
2017-08-12 02:48:43 +08:00
|
|
|
var AAAA = recordBuilder('AAAA');
|
2016-08-23 08:31:50 +08:00
|
|
|
|
2017-04-20 03:13:28 +08:00
|
|
|
// ALIAS(name,target, recordModifiers...)
|
2017-08-12 02:48:43 +08:00
|
|
|
var ALIAS = recordBuilder('ALIAS');
|
2017-04-20 03:13:28 +08:00
|
|
|
|
2020-03-03 00:25:42 +08:00
|
|
|
// AZURE_ALIAS(name, type, target, recordModifiers...)
|
|
|
|
var AZURE_ALIAS = recordBuilder('AZURE_ALIAS', {
|
|
|
|
args: [
|
|
|
|
['name', _.isString],
|
|
|
|
['type', validateAzureAliasType],
|
|
|
|
['target', _.isString],
|
|
|
|
],
|
|
|
|
transform: function(record, args, modifier) {
|
|
|
|
record.name = args.name;
|
|
|
|
record.target = args.target;
|
|
|
|
if (_.isObject(record.azure_alias)) {
|
|
|
|
record.azure_alias['type'] = args.type;
|
|
|
|
} else {
|
|
|
|
record.azure_alias = { type: args.type };
|
|
|
|
}
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
function validateAzureAliasType(value) {
|
|
|
|
if (!_.isString(value)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return ['A', 'AAAA', 'CNAME'].indexOf(value) !== -1;
|
|
|
|
}
|
|
|
|
|
ROUTE53: Support Route53's ALIAS record type (#239) (#301)
* Stable comparison of metadata (#239)
Iterating over a map in Go never produces twice the same ordering.
Thus when comparing two metadata map with more than one key, the
`differ` is always finding differences.
To properly compare records metadata, we need to iterate the maps
in a deterministic way.
Signed-off-by: Brice Figureau <brice@daysofwonder.com>
* Support for Route53 ALIAS record type (#239)
Route53 ALIAS doesn't behave like a regular ALIAS, and is much more
limited as its target can only be some specific AWS resources or
another record in the same zone.
According to #239, this change adds a new directive R53_ALIAS which
implements this specific alias. This record type can only be used
with the Route53 provider.
This directive usage looks like this:
```js
D("example.com", REGISTRAR, DnsProvider("ROUTE53"),
R53_ALIAS("foo1", "A", "bar") // record in same zone
R53_ALIAS("foo2", "A",
"blahblah.elasticloadbalancing.us-west-1.amazonaws.com",
R53_ZONE('Z368ELLRRE2KJ0')) // ELB in us-west-1
```
Unfortunately, Route53 requires indicating the hosted zone id
where the target is defined (those are listed in AWS documentation,
see the R53_ALIAS documentation for links).
2018-01-16 18:53:12 +08:00
|
|
|
// R53_ALIAS(name, target, type, recordModifiers...)
|
|
|
|
var R53_ALIAS = recordBuilder('R53_ALIAS', {
|
2020-02-23 01:07:10 +08:00
|
|
|
args: [
|
|
|
|
['name', _.isString],
|
|
|
|
['type', validateR53AliasType],
|
|
|
|
['target', _.isString],
|
|
|
|
],
|
|
|
|
transform: function(record, args, modifiers) {
|
ROUTE53: Support Route53's ALIAS record type (#239) (#301)
* Stable comparison of metadata (#239)
Iterating over a map in Go never produces twice the same ordering.
Thus when comparing two metadata map with more than one key, the
`differ` is always finding differences.
To properly compare records metadata, we need to iterate the maps
in a deterministic way.
Signed-off-by: Brice Figureau <brice@daysofwonder.com>
* Support for Route53 ALIAS record type (#239)
Route53 ALIAS doesn't behave like a regular ALIAS, and is much more
limited as its target can only be some specific AWS resources or
another record in the same zone.
According to #239, this change adds a new directive R53_ALIAS which
implements this specific alias. This record type can only be used
with the Route53 provider.
This directive usage looks like this:
```js
D("example.com", REGISTRAR, DnsProvider("ROUTE53"),
R53_ALIAS("foo1", "A", "bar") // record in same zone
R53_ALIAS("foo2", "A",
"blahblah.elasticloadbalancing.us-west-1.amazonaws.com",
R53_ZONE('Z368ELLRRE2KJ0')) // ELB in us-west-1
```
Unfortunately, Route53 requires indicating the hosted zone id
where the target is defined (those are listed in AWS documentation,
see the R53_ALIAS documentation for links).
2018-01-16 18:53:12 +08:00
|
|
|
record.name = args.name;
|
|
|
|
record.target = args.target;
|
|
|
|
if (_.isObject(record.r53_alias)) {
|
|
|
|
record.r53_alias['type'] = args.type;
|
|
|
|
} else {
|
2020-02-23 01:07:10 +08:00
|
|
|
record.r53_alias = { type: args.type };
|
ROUTE53: Support Route53's ALIAS record type (#239) (#301)
* Stable comparison of metadata (#239)
Iterating over a map in Go never produces twice the same ordering.
Thus when comparing two metadata map with more than one key, the
`differ` is always finding differences.
To properly compare records metadata, we need to iterate the maps
in a deterministic way.
Signed-off-by: Brice Figureau <brice@daysofwonder.com>
* Support for Route53 ALIAS record type (#239)
Route53 ALIAS doesn't behave like a regular ALIAS, and is much more
limited as its target can only be some specific AWS resources or
another record in the same zone.
According to #239, this change adds a new directive R53_ALIAS which
implements this specific alias. This record type can only be used
with the Route53 provider.
This directive usage looks like this:
```js
D("example.com", REGISTRAR, DnsProvider("ROUTE53"),
R53_ALIAS("foo1", "A", "bar") // record in same zone
R53_ALIAS("foo2", "A",
"blahblah.elasticloadbalancing.us-west-1.amazonaws.com",
R53_ZONE('Z368ELLRRE2KJ0')) // ELB in us-west-1
```
Unfortunately, Route53 requires indicating the hosted zone id
where the target is defined (those are listed in AWS documentation,
see the R53_ALIAS documentation for links).
2018-01-16 18:53:12 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
// R53_ZONE(zone_id)
|
|
|
|
function R53_ZONE(zone_id) {
|
2020-02-23 01:07:10 +08:00
|
|
|
return function(r) {
|
ROUTE53: Support Route53's ALIAS record type (#239) (#301)
* Stable comparison of metadata (#239)
Iterating over a map in Go never produces twice the same ordering.
Thus when comparing two metadata map with more than one key, the
`differ` is always finding differences.
To properly compare records metadata, we need to iterate the maps
in a deterministic way.
Signed-off-by: Brice Figureau <brice@daysofwonder.com>
* Support for Route53 ALIAS record type (#239)
Route53 ALIAS doesn't behave like a regular ALIAS, and is much more
limited as its target can only be some specific AWS resources or
another record in the same zone.
According to #239, this change adds a new directive R53_ALIAS which
implements this specific alias. This record type can only be used
with the Route53 provider.
This directive usage looks like this:
```js
D("example.com", REGISTRAR, DnsProvider("ROUTE53"),
R53_ALIAS("foo1", "A", "bar") // record in same zone
R53_ALIAS("foo2", "A",
"blahblah.elasticloadbalancing.us-west-1.amazonaws.com",
R53_ZONE('Z368ELLRRE2KJ0')) // ELB in us-west-1
```
Unfortunately, Route53 requires indicating the hosted zone id
where the target is defined (those are listed in AWS documentation,
see the R53_ALIAS documentation for links).
2018-01-16 18:53:12 +08:00
|
|
|
if (_.isObject(r.r53_alias)) {
|
|
|
|
r.r53_alias['zone_id'] = zone_id;
|
|
|
|
} else {
|
2020-02-23 01:07:10 +08:00
|
|
|
r.r53_alias = { zone_id: zone_id };
|
ROUTE53: Support Route53's ALIAS record type (#239) (#301)
* Stable comparison of metadata (#239)
Iterating over a map in Go never produces twice the same ordering.
Thus when comparing two metadata map with more than one key, the
`differ` is always finding differences.
To properly compare records metadata, we need to iterate the maps
in a deterministic way.
Signed-off-by: Brice Figureau <brice@daysofwonder.com>
* Support for Route53 ALIAS record type (#239)
Route53 ALIAS doesn't behave like a regular ALIAS, and is much more
limited as its target can only be some specific AWS resources or
another record in the same zone.
According to #239, this change adds a new directive R53_ALIAS which
implements this specific alias. This record type can only be used
with the Route53 provider.
This directive usage looks like this:
```js
D("example.com", REGISTRAR, DnsProvider("ROUTE53"),
R53_ALIAS("foo1", "A", "bar") // record in same zone
R53_ALIAS("foo2", "A",
"blahblah.elasticloadbalancing.us-west-1.amazonaws.com",
R53_ZONE('Z368ELLRRE2KJ0')) // ELB in us-west-1
```
Unfortunately, Route53 requires indicating the hosted zone id
where the target is defined (those are listed in AWS documentation,
see the R53_ALIAS documentation for links).
2018-01-16 18:53:12 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
function validateR53AliasType(value) {
|
|
|
|
if (!_.isString(value)) {
|
|
|
|
return false;
|
|
|
|
}
|
2020-02-23 01:07:10 +08:00
|
|
|
return (
|
|
|
|
[
|
|
|
|
'A',
|
|
|
|
'AAAA',
|
|
|
|
'CNAME',
|
|
|
|
'CAA',
|
|
|
|
'MX',
|
|
|
|
'TXT',
|
|
|
|
'PTR',
|
|
|
|
'SPF',
|
|
|
|
'SRV',
|
|
|
|
'NAPTR',
|
2020-03-03 00:25:42 +08:00
|
|
|
].indexOf(value) !== -1
|
2020-02-23 01:07:10 +08:00
|
|
|
);
|
ROUTE53: Support Route53's ALIAS record type (#239) (#301)
* Stable comparison of metadata (#239)
Iterating over a map in Go never produces twice the same ordering.
Thus when comparing two metadata map with more than one key, the
`differ` is always finding differences.
To properly compare records metadata, we need to iterate the maps
in a deterministic way.
Signed-off-by: Brice Figureau <brice@daysofwonder.com>
* Support for Route53 ALIAS record type (#239)
Route53 ALIAS doesn't behave like a regular ALIAS, and is much more
limited as its target can only be some specific AWS resources or
another record in the same zone.
According to #239, this change adds a new directive R53_ALIAS which
implements this specific alias. This record type can only be used
with the Route53 provider.
This directive usage looks like this:
```js
D("example.com", REGISTRAR, DnsProvider("ROUTE53"),
R53_ALIAS("foo1", "A", "bar") // record in same zone
R53_ALIAS("foo2", "A",
"blahblah.elasticloadbalancing.us-west-1.amazonaws.com",
R53_ZONE('Z368ELLRRE2KJ0')) // ELB in us-west-1
```
Unfortunately, Route53 requires indicating the hosted zone id
where the target is defined (those are listed in AWS documentation,
see the R53_ALIAS documentation for links).
2018-01-16 18:53:12 +08:00
|
|
|
}
|
|
|
|
|
2017-07-26 02:59:40 +08:00
|
|
|
// CAA(name,tag,value, recordModifiers...)
|
2017-08-12 02:48:43 +08:00
|
|
|
var CAA = recordBuilder('CAA', {
|
2017-09-16 01:12:09 +08:00
|
|
|
// TODO(tlim): It should be an error if value is not 0 or 128.
|
2020-02-23 01:07:10 +08:00
|
|
|
args: [
|
|
|
|
['name', _.isString],
|
|
|
|
['tag', _.isString],
|
|
|
|
['value', _.isString],
|
|
|
|
],
|
2017-09-16 01:12:09 +08:00
|
|
|
transform: function(record, args, modifiers) {
|
2017-08-12 02:48:43 +08:00
|
|
|
record.name = args.name;
|
|
|
|
record.caatag = args.tag;
|
|
|
|
record.target = args.value;
|
|
|
|
},
|
2017-09-16 01:12:09 +08:00
|
|
|
modifierNumber: function(record, value) {
|
2017-08-12 02:48:43 +08:00
|
|
|
record.caaflags |= value;
|
|
|
|
},
|
|
|
|
});
|
2017-04-20 03:13:28 +08:00
|
|
|
|
2016-08-23 08:31:50 +08:00
|
|
|
// CNAME(name,target, recordModifiers...)
|
2017-08-12 02:48:43 +08:00
|
|
|
var CNAME = recordBuilder('CNAME');
|
2016-08-23 08:31:50 +08:00
|
|
|
|
2020-05-30 22:40:21 +08:00
|
|
|
// DS(name, keytag, algorithm, digestype, digest)
|
|
|
|
var DS = recordBuilder("DS", {
|
|
|
|
args: [
|
|
|
|
['name', _.isString],
|
|
|
|
['keytag', _.isNumber],
|
|
|
|
['algorithm', _.isNumber],
|
|
|
|
['digesttype', _.isNumber],
|
|
|
|
['digest', _.isString]
|
|
|
|
],
|
|
|
|
transform: function(record, args, modifiers) {
|
|
|
|
record.name = args.name;
|
|
|
|
record.dskeytag = args.keytag;
|
|
|
|
record.dsalgorithm = args.algorithm;
|
|
|
|
record.dsdigesttype = args.digesttype;
|
|
|
|
record.dsdigest = args.digest;
|
|
|
|
record.target = args.target;
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
2017-07-06 22:18:15 +08:00
|
|
|
// PTR(name,target, recordModifiers...)
|
2017-08-12 02:48:43 +08:00
|
|
|
var PTR = recordBuilder('PTR');
|
2017-07-06 22:18:15 +08:00
|
|
|
|
2019-03-28 22:40:13 +08:00
|
|
|
// NAPTR(name,order,preference,flags,service,regexp,target, recordModifiers...)
|
|
|
|
var NAPTR = recordBuilder('NAPTR', {
|
|
|
|
args: [
|
|
|
|
['name', _.isString],
|
|
|
|
['order', _.isNumber],
|
|
|
|
['preference', _.isNumber],
|
|
|
|
['flags', _.isString],
|
|
|
|
['service', _.isString],
|
|
|
|
['regexp', _.isString],
|
|
|
|
['target', _.isString],
|
|
|
|
],
|
|
|
|
transform: function(record, args, modifiers) {
|
|
|
|
record.name = args.name;
|
|
|
|
record.naptrorder = args.order;
|
|
|
|
record.naptrpreference = args.preference;
|
|
|
|
record.naptrflags = args.flags;
|
|
|
|
record.naptrservice = args.service;
|
|
|
|
record.naptrregexp = args.regexp;
|
|
|
|
record.target = args.target;
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
2017-07-20 03:53:40 +08:00
|
|
|
// SRV(name,priority,weight,port,target, recordModifiers...)
|
2017-08-12 02:48:43 +08:00
|
|
|
var SRV = recordBuilder('SRV', {
|
|
|
|
args: [
|
|
|
|
['name', _.isString],
|
|
|
|
['priority', _.isNumber],
|
|
|
|
['weight', _.isNumber],
|
|
|
|
['port', _.isNumber],
|
|
|
|
['target', _.isString],
|
|
|
|
],
|
2017-09-16 01:12:09 +08:00
|
|
|
transform: function(record, args, modifiers) {
|
2017-08-12 02:48:43 +08:00
|
|
|
record.name = args.name;
|
|
|
|
record.srvpriority = args.priority;
|
|
|
|
record.srvweight = args.weight;
|
|
|
|
record.srvport = args.port;
|
|
|
|
record.target = args.target;
|
|
|
|
},
|
|
|
|
});
|
2017-07-20 03:53:40 +08:00
|
|
|
|
2019-01-29 06:26:20 +08:00
|
|
|
// SSHFP(name,algorithm,type,value, recordModifiers...)
|
|
|
|
var SSHFP = recordBuilder('SSHFP', {
|
|
|
|
args: [
|
|
|
|
['name', _.isString],
|
|
|
|
['algorithm', _.isNumber],
|
|
|
|
['fingerprint', _.isNumber],
|
|
|
|
['value', _.isString],
|
|
|
|
],
|
|
|
|
transform: function(record, args, modifiers) {
|
|
|
|
record.name = args.name;
|
|
|
|
record.sshfpalgorithm = args.algorithm;
|
|
|
|
record.sshfpfingerprint = args.fingerprint;
|
|
|
|
record.target = args.value;
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
2017-09-15 21:03:29 +08:00
|
|
|
// name, usage, selector, matchingtype, certificate
|
|
|
|
var TLSA = recordBuilder('TLSA', {
|
|
|
|
args: [
|
|
|
|
['name', _.isString],
|
|
|
|
['usage', _.isNumber],
|
|
|
|
['selector', _.isNumber],
|
|
|
|
['matchingtype', _.isNumber],
|
2018-01-10 01:53:16 +08:00
|
|
|
['target', _.isString], // recordBuilder needs a "target" argument
|
2017-09-15 21:03:29 +08:00
|
|
|
],
|
2017-09-16 01:12:09 +08:00
|
|
|
transform: function(record, args, modifiers) {
|
2017-09-15 21:03:29 +08:00
|
|
|
record.name = args.name;
|
|
|
|
record.tlsausage = args.usage;
|
|
|
|
record.tlsaselector = args.selector;
|
|
|
|
record.tlsamatchingtype = args.matchingtype;
|
|
|
|
record.target = args.target;
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
2018-01-05 08:19:35 +08:00
|
|
|
function isStringOrArray(x) {
|
2018-01-07 04:13:22 +08:00
|
|
|
return _.isString(x) || _.isArray(x);
|
2018-01-05 08:19:35 +08:00
|
|
|
}
|
|
|
|
|
2016-08-23 08:31:50 +08:00
|
|
|
// TXT(name,target, recordModifiers...)
|
2018-01-07 04:13:22 +08:00
|
|
|
var TXT = recordBuilder('TXT', {
|
2020-02-23 01:07:10 +08:00
|
|
|
args: [
|
|
|
|
['name', _.isString],
|
|
|
|
['target', isStringOrArray],
|
|
|
|
],
|
2018-01-07 04:13:22 +08:00
|
|
|
transform: function(record, args, modifiers) {
|
|
|
|
record.name = args.name;
|
|
|
|
// Store the strings twice:
|
|
|
|
// .target is the first string
|
|
|
|
// .txtstrings is the individual strings.
|
|
|
|
// NOTE: If there are more than 1 string, providers should only access
|
|
|
|
// .txtstrings, thus it doesn't matter what we store in .target.
|
|
|
|
// However, by storing the first string there, it improves backwards
|
|
|
|
// compatibility when the len(array) == 1 and (intentionally) breaks
|
|
|
|
// broken providers early in the integration tests.
|
|
|
|
if (_.isString(args.target)) {
|
|
|
|
record.target = args.target;
|
|
|
|
record.txtstrings = [args.target];
|
|
|
|
} else {
|
|
|
|
record.target = args.target[0];
|
|
|
|
record.txtstrings = args.target;
|
|
|
|
}
|
|
|
|
},
|
2018-01-05 08:19:35 +08:00
|
|
|
});
|
2016-08-23 08:31:50 +08:00
|
|
|
|
|
|
|
// MX(name,priority,target, recordModifiers...)
|
2017-08-12 02:48:43 +08:00
|
|
|
var MX = recordBuilder('MX', {
|
|
|
|
args: [
|
|
|
|
['name', _.isString],
|
|
|
|
['priority', _.isNumber],
|
|
|
|
['target', _.isString],
|
|
|
|
],
|
2017-09-16 01:12:09 +08:00
|
|
|
transform: function(record, args, modifiers) {
|
2017-08-12 02:48:43 +08:00
|
|
|
record.name = args.name;
|
|
|
|
record.mxpreference = args.priority;
|
|
|
|
record.target = args.target;
|
|
|
|
},
|
|
|
|
});
|
2016-08-23 08:31:50 +08:00
|
|
|
|
|
|
|
// NS(name,target, recordModifiers...)
|
2017-08-12 02:48:43 +08:00
|
|
|
var NS = recordBuilder('NS');
|
2016-08-23 08:31:50 +08:00
|
|
|
|
|
|
|
// NAMESERVER(name,target)
|
2018-03-22 23:52:52 +08:00
|
|
|
function NAMESERVER(name) {
|
2020-02-23 01:07:10 +08:00
|
|
|
if (arguments.length != 1) {
|
|
|
|
throw 'NAMESERVER only accepts one argument for name.';
|
2018-03-22 23:52:52 +08:00
|
|
|
}
|
2016-08-23 08:31:50 +08:00
|
|
|
return function(d) {
|
2018-03-22 23:52:52 +08:00
|
|
|
d.nameservers.push({ name: name });
|
2017-09-16 01:12:09 +08:00
|
|
|
};
|
2016-08-23 08:31:50 +08:00
|
|
|
}
|
|
|
|
|
2018-09-04 22:57:11 +08:00
|
|
|
// NAMESERVER_TTL(v): Set the TTL for NAMESERVER records.
|
|
|
|
function NAMESERVER_TTL(v) {
|
|
|
|
if (_.isString(v)) {
|
|
|
|
v = stringToDuration(v);
|
|
|
|
}
|
2020-02-23 01:07:10 +08:00
|
|
|
return { ns_ttl: v.toString() };
|
2018-09-04 22:57:11 +08:00
|
|
|
}
|
|
|
|
|
2016-08-23 08:31:50 +08:00
|
|
|
function format_tt(transform_table) {
|
2017-09-16 01:12:09 +08:00
|
|
|
// Turn [[low: 1, high: 2, newBase: 3], [low: 4, high: 5, newIP: 6]]
|
|
|
|
// into "1 ~ 2 ~ 3 ~; 4 ~ 5 ~ ~ 6"
|
|
|
|
var lines = [];
|
|
|
|
for (var i = 0; i < transform_table.length; i++) {
|
|
|
|
var ip = transform_table[i];
|
|
|
|
var newIP = ip.newIP;
|
|
|
|
if (newIP) {
|
|
|
|
if (_.isArray(newIP)) {
|
|
|
|
newIP = _.map(newIP, function(i) {
|
|
|
|
return num2dot(i);
|
|
|
|
}).join(',');
|
|
|
|
} else {
|
|
|
|
newIP = num2dot(newIP);
|
|
|
|
}
|
2016-08-23 08:31:50 +08:00
|
|
|
}
|
2017-09-16 01:12:09 +08:00
|
|
|
var newBase = ip.newBase;
|
|
|
|
if (newBase) {
|
|
|
|
if (_.isArray(newBase)) {
|
|
|
|
newBase = _.map(newBase, function(i) {
|
|
|
|
return num2dot(i);
|
|
|
|
}).join(',');
|
|
|
|
} else {
|
|
|
|
newBase = num2dot(newBase);
|
|
|
|
}
|
2016-09-28 01:35:28 +08:00
|
|
|
}
|
2017-09-16 01:12:09 +08:00
|
|
|
var row = [num2dot(ip.low), num2dot(ip.high), newBase, newIP];
|
|
|
|
lines.push(row.join(' ~ '));
|
2016-09-28 01:35:28 +08:00
|
|
|
}
|
2017-09-16 01:12:09 +08:00
|
|
|
return lines.join(' ; ');
|
2016-08-23 08:31:50 +08:00
|
|
|
}
|
|
|
|
|
2018-01-16 04:39:29 +08:00
|
|
|
// IGNORE(name)
|
|
|
|
function IGNORE(name) {
|
2020-08-18 23:14:34 +08:00
|
|
|
// deprecated, use IGNORE_NAME
|
|
|
|
return IGNORE_NAME(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
// IGNORE_NAME(name)
|
|
|
|
function IGNORE_NAME(name) {
|
2020-02-23 01:07:10 +08:00
|
|
|
return function(d) {
|
2020-08-18 23:14:34 +08:00
|
|
|
d.ignored_names.push(name);
|
2018-01-16 04:39:29 +08:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2020-08-18 23:14:34 +08:00
|
|
|
// IGNORE_TARGET(target)
|
|
|
|
function IGNORE_TARGET(target, rType) {
|
|
|
|
return function(d) {
|
|
|
|
d.ignored_targets.push({pattern: target, type: rType});
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-08-23 08:31:50 +08:00
|
|
|
// IMPORT_TRANSFORM(translation_table, domain)
|
2017-08-12 02:48:43 +08:00
|
|
|
var IMPORT_TRANSFORM = recordBuilder('IMPORT_TRANSFORM', {
|
2017-09-16 01:12:09 +08:00
|
|
|
args: [['translation_table'], ['domain'], ['ttl', _.isNumber]],
|
|
|
|
transform: function(record, args, modifiers) {
|
2017-08-12 02:48:43 +08:00
|
|
|
record.name = '@';
|
|
|
|
record.target = args.domain;
|
|
|
|
record.meta['transform_table'] = format_tt(args.translation_table);
|
|
|
|
record.ttl = args.ttl;
|
|
|
|
},
|
|
|
|
});
|
2016-08-23 08:31:50 +08:00
|
|
|
|
|
|
|
// PURGE()
|
|
|
|
function PURGE(d) {
|
2017-09-16 01:12:09 +08:00
|
|
|
d.KeepUnknown = false;
|
2016-08-23 08:31:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// NO_PURGE()
|
|
|
|
function NO_PURGE(d) {
|
2017-09-16 01:12:09 +08:00
|
|
|
d.KeepUnknown = true;
|
2016-08-23 08:31:50 +08:00
|
|
|
}
|
|
|
|
|
2020-02-22 20:09:31 +08:00
|
|
|
// AUTODNSSEC()
|
|
|
|
function AUTODNSSEC(d) {
|
|
|
|
d.auto_dnssec = true;
|
|
|
|
}
|
|
|
|
|
2017-08-12 02:48:43 +08:00
|
|
|
/**
|
|
|
|
* @deprecated
|
|
|
|
*/
|
2017-09-16 01:12:09 +08:00
|
|
|
function getModifiers(args, start) {
|
2016-08-23 08:31:50 +08:00
|
|
|
var mods = [];
|
2017-09-16 01:12:09 +08:00
|
|
|
for (var i = start; i < args.length; i++) {
|
|
|
|
mods.push(args[i]);
|
2016-08-23 08:31:50 +08:00
|
|
|
}
|
|
|
|
return mods;
|
|
|
|
}
|
|
|
|
|
2017-08-12 02:48:43 +08:00
|
|
|
/**
|
|
|
|
* Record type builder
|
|
|
|
* @param {string} type Record type
|
|
|
|
* @param {string} opts.args[][0] Argument name
|
|
|
|
* @param {function=} opts.args[][1] Optional validator
|
|
|
|
* @param {function=} opts.transform Function to apply arguments to record.
|
|
|
|
* Take (record, args, modifier) as arguments. Any modifiers will be
|
|
|
|
* applied before this function. It should mutate the given record.
|
|
|
|
* @param {function=} opts.applyModifier Function to apply modifiers to the record
|
|
|
|
*/
|
2017-09-16 01:12:09 +08:00
|
|
|
function recordBuilder(type, opts) {
|
2017-08-12 02:48:43 +08:00
|
|
|
opts = _.defaults({}, opts, {
|
2017-09-16 01:12:09 +08:00
|
|
|
args: [['name', _.isString], ['target']],
|
2017-08-12 02:48:43 +08:00
|
|
|
|
|
|
|
transform: function(record, args, modifiers) {
|
|
|
|
// record will have modifiers already applied
|
|
|
|
// args will be an object for parameters defined
|
|
|
|
record.name = args.name;
|
|
|
|
if (_.isNumber(args.target)) {
|
|
|
|
record.target = num2dot(args.target);
|
|
|
|
} else {
|
|
|
|
record.target = args.target;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
applyModifier: function(record, modifiers) {
|
|
|
|
for (var i = 0; i < modifiers.length; i++) {
|
|
|
|
var mod = modifiers[i];
|
|
|
|
|
|
|
|
if (_.isFunction(mod)) {
|
|
|
|
mod(record);
|
|
|
|
} else if (_.isObject(mod)) {
|
|
|
|
// convert transforms to strings
|
|
|
|
if (mod.transform && _.isArray(mod.transform)) {
|
|
|
|
mod.transform = format_tt(mod.transform);
|
|
|
|
}
|
|
|
|
_.extend(record.meta, mod);
|
|
|
|
} else {
|
2017-09-16 01:12:09 +08:00
|
|
|
throw 'ERROR: Unknown modifier type';
|
2017-08-12 02:48:43 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
2017-09-16 01:12:09 +08:00
|
|
|
return function() {
|
2017-08-12 02:48:43 +08:00
|
|
|
var parsedArgs = {};
|
|
|
|
var modifiers = [];
|
|
|
|
|
|
|
|
if (arguments.length < opts.args.length) {
|
2017-09-16 01:12:09 +08:00
|
|
|
var argumentsList = opts.args
|
|
|
|
.map(function(item) {
|
|
|
|
return item[0];
|
|
|
|
})
|
|
|
|
.join(', ');
|
|
|
|
throw type +
|
|
|
|
' record requires ' +
|
|
|
|
opts.args.length +
|
|
|
|
' arguments (' +
|
|
|
|
argumentsList +
|
|
|
|
'). Only ' +
|
|
|
|
arguments.length +
|
|
|
|
' were supplied';
|
2017-08-12 02:48:43 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// collect arguments
|
|
|
|
for (var i = 0; i < opts.args.length; i++) {
|
|
|
|
var argDefinition = opts.args[i];
|
|
|
|
var value = arguments[i];
|
|
|
|
if (argDefinition.length > 1) {
|
|
|
|
// run validator if supplied
|
2017-09-16 01:12:09 +08:00
|
|
|
if (!argDefinition[1](value)) {
|
|
|
|
throw type +
|
|
|
|
' record ' +
|
|
|
|
argDefinition[0] +
|
|
|
|
' argument validation failed';
|
2017-08-12 02:48:43 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
parsedArgs[argDefinition[0]] = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
// collect modifiers
|
|
|
|
for (var i = opts.args.length; i < arguments.length; i++) {
|
|
|
|
modifiers.push(arguments[i]);
|
|
|
|
}
|
|
|
|
|
2017-09-16 01:12:09 +08:00
|
|
|
return function(d) {
|
2017-08-12 02:48:43 +08:00
|
|
|
var record = {
|
|
|
|
type: type,
|
|
|
|
meta: {},
|
|
|
|
ttl: d.defaultTTL,
|
|
|
|
};
|
|
|
|
|
|
|
|
opts.applyModifier(record, modifiers);
|
|
|
|
opts.transform(record, parsedArgs, modifiers);
|
|
|
|
|
|
|
|
d.records.push(record);
|
|
|
|
return record;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @deprecated
|
|
|
|
*/
|
2017-09-16 01:12:09 +08:00
|
|
|
function addRecord(d, type, name, target, mods) {
|
2016-08-23 08:31:50 +08:00
|
|
|
// if target is number, assume ip address. convert it.
|
|
|
|
if (_.isNumber(target)) {
|
|
|
|
target = num2dot(target);
|
|
|
|
}
|
2017-09-16 01:12:09 +08:00
|
|
|
var rec = {
|
|
|
|
type: type,
|
|
|
|
name: name,
|
|
|
|
target: target,
|
|
|
|
ttl: d.defaultTTL,
|
|
|
|
priority: 0,
|
|
|
|
meta: {},
|
|
|
|
};
|
2016-08-23 08:31:50 +08:00
|
|
|
// for each modifier, decide based on type:
|
|
|
|
// - Function: call is with the record as the argument
|
|
|
|
// - Object: merge it into the metadata
|
|
|
|
// - Number: IF MX record assume it is priority
|
2017-07-20 03:53:40 +08:00
|
|
|
if (mods) {
|
2017-09-16 01:12:09 +08:00
|
|
|
for (var i = 0; i < mods.length; i++) {
|
|
|
|
var m = mods[i];
|
2017-07-20 03:53:40 +08:00
|
|
|
if (_.isFunction(m)) {
|
|
|
|
m(rec);
|
|
|
|
} else if (_.isObject(m)) {
|
2018-01-10 01:53:16 +08:00
|
|
|
// convert transforms to strings
|
2017-09-16 01:12:09 +08:00
|
|
|
if (m.transform && _.isArray(m.transform)) {
|
|
|
|
m.transform = format_tt(m.transform);
|
|
|
|
}
|
|
|
|
_.extend(rec.meta, m);
|
|
|
|
_.extend(rec.meta, m);
|
2017-07-20 03:53:40 +08:00
|
|
|
} else {
|
2017-09-16 01:12:09 +08:00
|
|
|
console.log(
|
|
|
|
'WARNING: Modifier type unsupported:',
|
|
|
|
typeof m,
|
|
|
|
'(Skipping!)'
|
|
|
|
);
|
2017-07-20 03:53:40 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
d.records.push(rec);
|
|
|
|
return rec;
|
|
|
|
}
|
|
|
|
|
2018-01-10 01:53:16 +08:00
|
|
|
// ip conversion functions from http://stackoverflow.com/a/8105740/121660
|
2016-08-23 08:31:50 +08:00
|
|
|
// via http://javascript.about.com/library/blipconvert.htm
|
2017-09-16 01:12:09 +08:00
|
|
|
function IP(dot) {
|
2016-08-23 08:31:50 +08:00
|
|
|
var d = dot.split('.');
|
2017-09-16 01:12:09 +08:00
|
|
|
// prettier-ignore
|
|
|
|
return ((((((+d[0]) * 256) + (+d[1])) * 256) + (+d[2])) * 256) + (+d[3]);
|
2016-08-23 08:31:50 +08:00
|
|
|
}
|
|
|
|
|
2017-09-16 01:12:09 +08:00
|
|
|
function num2dot(num) {
|
|
|
|
if (num === undefined) {
|
|
|
|
return '';
|
2016-08-23 08:31:50 +08:00
|
|
|
}
|
2017-09-16 01:12:09 +08:00
|
|
|
if (_.isString(num)) {
|
|
|
|
return num;
|
2016-08-23 08:31:50 +08:00
|
|
|
}
|
2017-09-16 01:12:09 +08:00
|
|
|
var d = num % 256;
|
|
|
|
for (var i = 3; i > 0; i--) {
|
|
|
|
num = Math.floor(num / 256);
|
2020-02-23 01:07:10 +08:00
|
|
|
d = (num % 256) + '.' + d;
|
2016-08-23 08:31:50 +08:00
|
|
|
}
|
|
|
|
return d;
|
|
|
|
}
|
2017-05-11 13:02:57 +08:00
|
|
|
|
|
|
|
// Cloudflare aliases:
|
2017-05-16 04:28:26 +08:00
|
|
|
|
|
|
|
// Meta settings for individual records.
|
2017-09-16 01:12:09 +08:00
|
|
|
var CF_PROXY_OFF = { cloudflare_proxy: 'off' }; // Proxy disabled.
|
|
|
|
var CF_PROXY_ON = { cloudflare_proxy: 'on' }; // Proxy enabled.
|
|
|
|
var CF_PROXY_FULL = { cloudflare_proxy: 'full' }; // Proxy+Railgun enabled.
|
2017-05-16 04:28:26 +08:00
|
|
|
// Per-domain meta settings:
|
|
|
|
// Proxy default off for entire domain (the default):
|
2017-09-16 01:12:09 +08:00
|
|
|
var CF_PROXY_DEFAULT_OFF = { cloudflare_proxy_default: 'off' };
|
2017-05-16 04:28:26 +08:00
|
|
|
// Proxy default on for entire domain:
|
2017-09-16 01:12:09 +08:00
|
|
|
var CF_PROXY_DEFAULT_ON = { cloudflare_proxy_default: 'on' };
|
2019-06-13 19:32:54 +08:00
|
|
|
// UniversalSSL off for entire domain:
|
|
|
|
var CF_UNIVERSALSSL_OFF = { cloudflare_universalssl: 'off' };
|
|
|
|
// UniversalSSL on for entire domain:
|
|
|
|
var CF_UNIVERSALSSL_ON = { cloudflare_universalssl: 'on' };
|
2017-05-26 08:38:48 +08:00
|
|
|
|
2017-05-20 02:15:57 +08:00
|
|
|
// CUSTOM, PROVIDER SPECIFIC RECORD TYPES
|
2017-08-12 02:48:43 +08:00
|
|
|
|
2019-05-23 21:29:21 +08:00
|
|
|
function _validateCloudflareRedirect(value) {
|
2017-09-16 01:12:09 +08:00
|
|
|
if (!_.isString(value)) {
|
2017-08-12 02:48:43 +08:00
|
|
|
return false;
|
|
|
|
}
|
2017-09-16 01:12:09 +08:00
|
|
|
return value.indexOf(',') === -1;
|
2017-08-12 02:48:43 +08:00
|
|
|
}
|
|
|
|
|
2017-09-16 01:12:09 +08:00
|
|
|
var CF_REDIRECT = recordBuilder('CF_REDIRECT', {
|
2017-08-12 02:48:43 +08:00
|
|
|
args: [
|
2019-05-23 21:29:21 +08:00
|
|
|
['source', _validateCloudflareRedirect],
|
|
|
|
['destination', _validateCloudflareRedirect],
|
2017-08-12 02:48:43 +08:00
|
|
|
],
|
2017-09-16 01:12:09 +08:00
|
|
|
transform: function(record, args, modifiers) {
|
|
|
|
record.name = '@';
|
|
|
|
record.target = args.source + ',' + args.destination;
|
2017-08-12 02:48:43 +08:00
|
|
|
},
|
|
|
|
});
|
|
|
|
|
2017-09-16 01:12:09 +08:00
|
|
|
var CF_TEMP_REDIRECT = recordBuilder('CF_TEMP_REDIRECT', {
|
2017-08-12 02:48:43 +08:00
|
|
|
args: [
|
2019-05-23 21:29:21 +08:00
|
|
|
['source', _validateCloudflareRedirect],
|
|
|
|
['destination', _validateCloudflareRedirect],
|
2017-08-12 02:48:43 +08:00
|
|
|
],
|
2017-09-16 01:12:09 +08:00
|
|
|
transform: function(record, args, modifiers) {
|
|
|
|
record.name = '@';
|
|
|
|
record.target = args.source + ',' + args.destination;
|
2017-08-12 02:48:43 +08:00
|
|
|
},
|
|
|
|
});
|
2017-10-24 00:54:31 +08:00
|
|
|
|
2017-12-07 04:56:57 +08:00
|
|
|
var URL = recordBuilder('URL');
|
|
|
|
var URL301 = recordBuilder('URL301');
|
|
|
|
var FRAME = recordBuilder('FRAME');
|
2017-12-07 04:50:21 +08:00
|
|
|
|
|
|
|
// SPF_BUILDER takes an object:
|
|
|
|
// parts: The parts of the SPF record (to be joined with ' ').
|
|
|
|
// label: The DNS label for the primary SPF record. (default: '@')
|
2017-12-07 04:56:57 +08:00
|
|
|
// raw: Where (which label) to store an unaltered version of the SPF settings.
|
2019-05-23 21:25:06 +08:00
|
|
|
// ttl: The time for TTL, integer or string. (default: not defined, using DefaultTTL)
|
2017-12-07 04:50:21 +08:00
|
|
|
// split: The template for additional records to be created (default: '_spf%d')
|
|
|
|
// flatten: A list of domains to be flattened.
|
2020-07-10 00:52:49 +08:00
|
|
|
// overhead1: Amout of "buffer room" to reserve on the first item in the spf chain.
|
2020-08-01 01:28:13 +08:00
|
|
|
// txtMaxSize: The maximum size for each TXT string. Values over 255 will result in multiple strings (default: '255')
|
2017-12-07 04:50:21 +08:00
|
|
|
|
|
|
|
function SPF_BUILDER(value) {
|
2017-12-07 04:56:57 +08:00
|
|
|
if (!value.parts || value.parts.length < 2) {
|
|
|
|
throw 'SPF_BUILDER requires at least 2 elements';
|
|
|
|
}
|
|
|
|
if (!value.label) {
|
|
|
|
value.label = '@';
|
|
|
|
}
|
2020-07-31 22:40:22 +08:00
|
|
|
if (!value.raw && value.raw !== '') {
|
2017-12-07 04:56:57 +08:00
|
|
|
value.raw = '_rawspf';
|
|
|
|
}
|
|
|
|
|
|
|
|
r = []; // The list of records to return.
|
|
|
|
p = {}; // The metaparameters to set on the main TXT record.
|
|
|
|
rawspf = value.parts.join(' '); // The unaltered SPF settings.
|
|
|
|
|
|
|
|
// If flattening is requested, generate a TXT record with the raw SPF settings.
|
|
|
|
if (value.flatten && value.flatten.length > 0) {
|
|
|
|
p.flatten = value.flatten.join(',');
|
2020-07-31 22:40:22 +08:00
|
|
|
// Only add the raw spf record if it isn't an empty string
|
|
|
|
if (value.raw !== '') {
|
|
|
|
if (value.ttl) {
|
|
|
|
r.push(TXT(value.raw, rawspf, TTL(value.ttl)));
|
|
|
|
} else {
|
|
|
|
r.push(TXT(value.raw, rawspf));
|
|
|
|
}
|
2019-05-23 21:25:06 +08:00
|
|
|
}
|
2017-12-07 04:56:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// If overflow is specified, enable splitting.
|
|
|
|
if (value.overflow) {
|
|
|
|
p.split = value.overflow;
|
|
|
|
}
|
|
|
|
|
2020-07-10 00:52:49 +08:00
|
|
|
if (value.overhead1) {
|
|
|
|
p.overhead1 = value.overhead1;
|
|
|
|
}
|
|
|
|
|
2020-08-01 01:28:13 +08:00
|
|
|
if (value.txtMaxSize) {
|
|
|
|
p.txtMaxSize = value.txtMaxSize;
|
|
|
|
}
|
|
|
|
|
2017-12-07 04:56:57 +08:00
|
|
|
// Generate a TXT record with the metaparameters.
|
2019-05-23 21:25:06 +08:00
|
|
|
if (value.ttl) {
|
|
|
|
r.push(TXT(value.label, rawspf, p, TTL(value.ttl)));
|
|
|
|
} else {
|
|
|
|
r.push(TXT(value.label, rawspf, p));
|
|
|
|
}
|
2017-12-07 04:56:57 +08:00
|
|
|
|
|
|
|
return r;
|
2017-12-07 04:50:21 +08:00
|
|
|
}
|
2018-01-05 10:17:08 +08:00
|
|
|
|
2019-05-18 23:10:18 +08:00
|
|
|
// CAA_BUILDER takes an object:
|
|
|
|
// label: The DNS label for the CAA record. (default: '@')
|
|
|
|
// iodef: The contact mail address. (optional)
|
|
|
|
// iodef_critical: Boolean if sending report is required/critical. If not supported, certificate should be refused. (optional)
|
|
|
|
// issue: List of CAs which are allowed to issue certificates for the domain (creates one record for each).
|
|
|
|
// issuewild: Allowed CAs which can issue wildcard certificates for this domain. (creates one record for each)
|
|
|
|
|
|
|
|
function CAA_BUILDER(value) {
|
|
|
|
if (!value.label) {
|
|
|
|
value.label = '@';
|
|
|
|
}
|
|
|
|
|
2020-02-23 01:07:10 +08:00
|
|
|
if (value.issue && value.issue == 'none') value.issue = [';'];
|
|
|
|
if (value.issuewild && value.issuewild == 'none') value.issuewild = [';'];
|
2019-05-18 23:10:18 +08:00
|
|
|
|
2020-02-23 01:07:10 +08:00
|
|
|
if (
|
|
|
|
(!value.issue && !value.issuewild) ||
|
|
|
|
(value.issue &&
|
|
|
|
value.issue.length == 0 &&
|
2020-03-03 00:25:42 +08:00
|
|
|
value.issuewild &&
|
|
|
|
value.issuewild.length == 0)
|
2020-02-23 01:07:10 +08:00
|
|
|
) {
|
2019-05-18 23:10:18 +08:00
|
|
|
throw 'CAA_BUILDER requires at least one entry at issue or issuewild';
|
|
|
|
}
|
|
|
|
|
|
|
|
r = []; // The list of records to return.
|
|
|
|
|
|
|
|
if (value.iodef) {
|
|
|
|
if (value.iodef_critical) {
|
2020-02-23 01:07:10 +08:00
|
|
|
r.push(CAA(value.label, 'iodef', value.iodef, CAA_CRITICAL));
|
2019-05-18 23:10:18 +08:00
|
|
|
} else {
|
2020-02-23 01:07:10 +08:00
|
|
|
r.push(CAA(value.label, 'iodef', value.iodef));
|
2019-05-18 23:10:18 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (value.issue)
|
|
|
|
for (var i = 0, len = value.issue.length; i < len; i++)
|
2020-02-23 01:07:10 +08:00
|
|
|
r.push(CAA(value.label, 'issue', value.issue[i]));
|
2019-05-18 23:10:18 +08:00
|
|
|
|
|
|
|
if (value.issuewild)
|
|
|
|
for (var i = 0, len = value.issuewild.length; i < len; i++)
|
2020-02-23 01:07:10 +08:00
|
|
|
r.push(CAA(value.label, 'issuewild', value.issuewild[i]));
|
2019-05-18 23:10:18 +08:00
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2018-01-05 10:17:08 +08:00
|
|
|
// Split a DKIM string if it is >254 bytes.
|
|
|
|
function DKIM(arr) {
|
2018-01-07 04:13:22 +08:00
|
|
|
chunkSize = 255;
|
|
|
|
var R = [];
|
|
|
|
for (var i = 0, len = arr.length; i < len; i += chunkSize)
|
|
|
|
R.push(arr.slice(i, i + chunkSize));
|
|
|
|
return R;
|
2018-01-05 10:17:08 +08:00
|
|
|
}
|
2020-08-20 02:00:40 +08:00
|
|
|
|
|
|
|
// Function wrapper for glob() for recursively loading files.
|
|
|
|
// As the main function (in Go) is in our control anyway, all the values here are already sanity-checked.
|
|
|
|
// Note: glob() is only an internal undocumented helper function. So use it on your own risk.
|
|
|
|
function require_glob() {
|
|
|
|
arguments[2] = "js"; // force to only include .js files.
|
|
|
|
var files = glob.apply(null, arguments);
|
|
|
|
for (i = 0; i < files.length; i++) {
|
|
|
|
require(files[i]);
|
|
|
|
}
|
|
|
|
return files
|
|
|
|
}
|