}
}
-static pair<int, bool> doYamlConfig(Logr::log_t /* startupLog */, int argc, char* argv[]) // NOLINT: Posix API
+static pair<int, bool> doYamlConfig(Logr::log_t startupLog, int argc, char* argv[]) // NOLINT: Posix API
{
if (!::arg().mustDo("config")) {
return {0, false};
::arg().parse(argc, argv);
pdns::rust::settings::rec::Recursorsettings settings;
pdns::settings::rec::oldStyleSettingsToBridgeStruct(settings);
+ luaConfigDelayedThreads delayedLuaThreads;
+ try {
+ ProxyMapping proxyMapping;
+ loadRecursorLuaConfig(::arg()["lua-config-file"], delayedLuaThreads, proxyMapping);
+ }
+ catch (PDNSException& e) {
+ SLOG(g_log << Logger::Error << "Cannot load Lua configuration: " << e.reason << endl,
+ startupLog->error(Logr::Error, e.reason, "Cannot load Lua configuration"));
+ }
+ auto luaConfig = g_luaconfs.getLocal();
+ settings.dnssec.trustanchorfile = luaConfig->trustAnchorFileInfo.fname;
+ settings.dnssec.trustanchorfile_interval = luaConfig->trustAnchorFileInfo.interval;
+ for (const auto& anchors : luaConfig->dsAnchors) {
+ rust::Vec<rust::String> dsRecords;
+ for (const auto& dsRecord : anchors.second) {
+ dsRecords.emplace_back(dsRecord.getZoneRepresentation());
+ }
+ pdns::rust::settings::rec::TrustAnchor trustAnchor{anchors.first.toString(), dsRecords};
+ settings.dnssec.trustanchors.emplace_back(trustAnchor);
+ }
+ for (const auto& anchors : luaConfig->negAnchors) {
+ pdns::rust::settings::rec::NegativeTrustAnchor negtrustAnchor{anchors.first.toString(), anchors.second};
+ settings.dnssec.negative_trustanchors.emplace_back(negtrustAnchor);
+ }
+
auto yaml = settings.to_yaml_string();
cout << yaml << endl;
}
::rust::String section;
::rust::String fieldname;
::rust::String type_name;
- pdns::rust::settings::rec::Value rustvalue = {false, 0, 0.0, "", {}, {}, {}};
+ pdns::rust::settings::rec::Value rustvalue = {false, 0, 0.0, "", {}, {}, {}, {}, {}};
if (pdns::settings::rec::oldKVToBridgeStruct(var, val, section, fieldname, type_name, rustvalue)) {
auto overriding = !mainFile && !incremental && !simpleRustType(type_name);
auto [existing, inserted] = map.emplace(std::pair{std::pair{section, fieldname}, pdns::rust::settings::rec::OldStyle{section, fieldname, var, std::move(type_name), rustvalue, overriding}});
::rust::String section;
::rust::String fieldname;
::rust::String type_name;
- pdns::rust::settings::rec::Value rustvalue{false, 0, 0.0, "", {}, {}, {}};
+ pdns::rust::settings::rec::Value rustvalue{false, 0, 0.0, "", {}, {}, {}, {}, {}};
string name = var;
string val = arg().getDefault(var);
if (pdns::settings::rec::oldKVToBridgeStruct(name, val, section, fieldname, type_name, rustvalue)) {
# default: default value, use 'true' and 'false' for Booleans
# help: short help text
# doc: the docs text will be put here
-# doc-rst: optional .rst annotations, typically used for ..version_added/changed::
+# doc-rst: optional .rst annotations
# doc-new: optional docs text specific to YAML format, e.g. not talking about comma separated
# lists and giving YAML examples. (optional)
-# skip-yamL: optional if this key is present, the field wil be skipped in the new style settings.
+# skip-yaml: optional if this key is present, the field will be skipped in the new style settings.
# Use for deprecated settings, the generated code will use deprecated map from arg()
# to handle old names when converting .conf to .yml
+# skip-old: optional if this key is present, the field will be skipped in the old style settings.
# versionadded: string or list of strings
#
# The above struct will generate in cxxsettings-generated.cc:
Command = auto()
Double = auto()
ListAuthZones = auto()
+ ListForwardZones = auto()
+ ListNegativeTrustAnchors = auto()
ListSocketAddresses = auto()
ListStrings = auto()
ListSubnets = auto()
- ListForwardZones = auto()
+ ListTrustAnchors = auto()
String = auto()
Uint64 = auto()
+listOfStringTypes = (LType.ListSocketAddresses, LType.ListStrings, LType.ListSubnets)
+listOfStructuredTypes = (LType.ListAuthZones, LType.ListForwardZones, LType.ListTrustAnchors, LType.ListNegativeTrustAnchors)
+
def get_olddoc_typename(typ):
"""Given a type from table.py, return the old-style type name"""
if typ == LType.Bool:
return 'Sequence of `Forward Zone`_'
if typ == LType.ListAuthZones:
return 'Sequence of `Auth Zone`_'
+ if typ == LType.ListTrustAnchors:
+ return 'Sequence of `TrustAnchors`_'
+ if typ == LType.ListNegativeTrustAnchors:
+ return 'Sequence of `NegativeTrustAnchors`_'
return 'Unknown' + str(typ)
def get_default_olddoc_value(typ, val):
ret = ''
return '``[' + ret + ']``'
+def list_to_base_type(typ):
+ typeName = typ.name
+ if typeName.startswith('List') and typeName.endswith('s'):
+ baseName = typeName[4:len(typeName) - 1]
+ return baseName
+ return 'Unknown: ' + typeName
+
def get_rust_type(typ):
"""Determine which Rust type is used for a logical type"""
if typ == LType.Bool:
return 'f64'
if typ == LType.String:
return 'String'
+ # These vectors map to Vec<String>
if typ == LType.ListSocketAddresses:
return 'Vec<String>'
if typ == LType.ListSubnets:
return 'Vec<String>'
if typ == LType.ListStrings:
return 'Vec<String>'
- if typ == LType.ListForwardZones:
- return 'Vec<ForwardZone>'
- if typ == LType.ListAuthZones:
- return 'Vec<AuthZone>'
- return 'Unknown' + str(typ)
+ # These vectors map to Vec<Type>
+ return 'Vec<' + list_to_base_type(typ) + '>'
def quote(arg):
"""Return a quoted string"""
continue
if 'skip-yaml' in entry:
continue
+ if 'skip-old' in entry:
+ continue
rust_type = get_rust_type(entry['type'])
name = entry['name']
oldname = entry['oldname']
continue
if 'skip-yaml' in entry:
continue
+ if 'skip-old' in entry:
+ continue
rust_type = get_rust_type(entry['type'])
extra = ''
if entry['oldname'] == 'forward-zones-recurse':
continue
if 'skip-yaml' in entry:
continue
+ if 'skip-old' in entry:
+ continue
section = entry['section'].lower()
name = entry['name']
oldname = entry['oldname']
return value == ''
return False
-def gen_rust_forwardzonevec_default_functions(name):
- """Generate Rust code for the default handling of a vector for ForwardZones"""
- ret = f'// DEFAULT HANDLING for {name}\n'
- ret += f'fn default_value_{name}() -> Vec<recsettings::ForwardZone> {{\n'
- ret += ' Vec::new()\n'
- ret += '}\n'
- ret += f'fn default_value_equal_{name}(value: &Vec<recsettings::ForwardZone>)'
- ret += '-> bool {\n'
- ret += f' let def = default_value_{name}();\n'
- ret += ' &def == value\n'
- ret += '}\n\n'
- return ret
-
-def gen_rust_authzonevec_default_functions(name):
- """Generate Rust code for the default handling of a vector for AuthZones"""
+def gen_rust_vec_default_functions(name, typeName):
+ """Generate Rust code for the default handling of a vector for typeName"""
ret = f'// DEFAULT HANDLING for {name}\n'
- ret += f'fn default_value_{name}() -> Vec<recsettings::AuthZone> {{\n'
+ ret += f'fn default_value_{name}() -> Vec<recsettings::{typeName}> {{\n'
ret += ' Vec::new()\n'
ret += '}\n'
- ret += f'fn default_value_equal_{name}(value: &Vec<recsettings::AuthZone>)'
+ ret += f'fn default_value_equal_{name}(value: &Vec<recsettings::{typeName}>)'
ret += '-> bool {\n'
ret += f' let def = default_value_{name}();\n'
ret += ' &def == value\n'
parts = re.split('[ \t,]+', entry['default'])
if len(parts) > 0:
ret += ' vec![\n'
- for part in parts:
+ for part in parts:
if part == '':
continue
ret += f' String::from({quote(part)}),\n'
def gen_rust_default_functions(entry, name, rust_type):
"""Generate Rust code for the default handling"""
- if entry['type'] in (LType.ListSocketAddresses, LType.ListSubnets, LType.ListStrings):
+ if entry['type'] in listOfStringTypes:
return gen_rust_stringvec_default_functions(entry, name)
- if entry['type'] == LType.ListForwardZones:
- return gen_rust_forwardzonevec_default_functions(name)
- if entry['type'] == LType.ListAuthZones:
- return gen_rust_authzonevec_default_functions(name)
+ if entry['type'] in listOfStructuredTypes:
+ baseName = list_to_base_type(entry['type'])
+ return gen_rust_vec_default_functions(name, baseName)
ret = f'// DEFAULT HANDLING for {name}\n'
ret += f'fn default_value_{name}() -> {rust_type} {{\n'
defvalue = entry['default']
validator = 'validate_subnet'
elif typ == LType.ListSocketAddresses:
validator = 'validate_socket_address'
- elif typ == LType.ListForwardZones:
- validator = '|field, element| element.validate(field)'
- elif typ == LType.ListAuthZones:
+ elif typ in listOfStructuredTypes:
validator = '|field, element| element.validate(field)'
else:
continue
continue
if entry['doc'].strip() == 'SKIP':
continue
+ if 'skip-old' in entry:
+ continue
oldname = entry['oldname']
section = entry['section']
file.write(f'.. _setting-{oldname}:\n\n')
file: String,
}
+// A single trust anchor
+#[derive(Deserialize, Serialize, Debug, PartialEq)]
+#[serde(deny_unknown_fields)]
+pub struct TrustAnchor {
+ #[serde(default, skip_serializing_if = "crate::is_default")]
+ name: String,
+ #[serde(default, skip_serializing_if = "crate::is_default")]
+ dsrecords: Vec<String>,
+}
+
+// A single negative trust anchor
+#[derive(Deserialize, Serialize, Debug, PartialEq)]
+#[serde(deny_unknown_fields)]
+pub struct NegativeTrustAnchor {
+ #[serde(default, skip_serializing_if = "crate::is_default")]
+ name: String,
+ #[serde(default, skip_serializing_if = "crate::is_default")]
+ reason: String,
+}
+
// A struct holding bot a vector of forward zones and a vector o auth zones, used by REST API code
#[derive(Deserialize, Serialize, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
vec_string_val: Vec<String>,
vec_forwardzone_val: Vec<ForwardZone>,
vec_authzone_val: Vec<AuthZone>,
+ vec_trustanchor_val: Vec<TrustAnchor>,
+ vec_negativetrustanchor_val: Vec<NegativeTrustAnchor>,
}
struct OldStyle {
// The validate function bewlo are "hand-crafted" as their structs afre mnot generated
fn validate(self: &AuthZone, field: &str) -> Result<()>;
fn validate(self: &ForwardZone, field: &str) -> Result<()>;
+ fn validate(self: &TrustAnchor, field: &str) -> Result<()>;
+ fn validate(self: &NegativeTrustAnchor, field: &str) -> Result<()>;
fn validate(self: &ApiZones, field: &str) -> Result<()>;
// Helper functions to call the proper validate function on vectors of various kinds
fn api_add_auth_zone(file: &str, authzone: AuthZone) -> Result<()>;
fn api_add_forward_zone(file: &str, forwardzone: ForwardZone) -> Result<()>;
fn api_add_forward_zones(file: &str, forwardzones: &mut Vec<ForwardZone>) -> Result<()>;
+ fn validate_trustanchors(field: &str, vec: &Vec<TrustAnchor>) -> Result<()>;
+ fn validate_negativetrustanchors(field: &str, vec: &Vec<NegativeTrustAnchor>) -> Result<()>;
fn api_delete_zone(file: &str, zone: &str) -> Result<()>;
}
}
}
+impl Default for TrustAnchor {
+ fn default() -> Self {
+ let deserialized: TrustAnchor = serde_yaml::from_str("").unwrap();
+ deserialized
+ }
+}
+
+impl Default for NegativeTrustAnchor {
+ fn default() -> Self {
+ let deserialized: NegativeTrustAnchor = serde_yaml::from_str("").unwrap();
+ deserialized
+ }
+}
+
+
impl Default for ApiZones {
fn default() -> Self {
let deserialized: ApiZones = serde_yaml::from_str("").unwrap();
}
}
+impl TrustAnchor {
+ pub fn validate(&self, _field: &str) -> Result<(), ValidationError> {
+ Ok(())
+ }
+
+ fn to_yaml_map(&self) -> serde_yaml::Value {
+ let mut seq = serde_yaml::Sequence::new();
+ for entry in &self.dsrecords {
+ seq.push(serde_yaml::Value::String(entry.to_owned()));
+ }
+ let mut map = serde_yaml::Mapping::new();
+ map.insert(
+ serde_yaml::Value::String("name".to_owned()),
+ serde_yaml::Value::String(self.name.to_owned()),
+ );
+ map.insert(
+ serde_yaml::Value::String("dsrecord".to_owned()),
+ serde_yaml::Value::Sequence(seq),
+ );
+ serde_yaml::Value::Mapping(map)
+ }
+}
+
+impl NegativeTrustAnchor {
+ pub fn validate(&self, _field: &str) -> Result<(), ValidationError> {
+ Ok(())
+ }
+
+ fn to_yaml_map(&self) -> serde_yaml::Value {
+ let mut map = serde_yaml::Mapping::new();
+ map.insert(
+ serde_yaml::Value::String("name".to_owned()),
+ serde_yaml::Value::String(self.name.to_owned()),
+ );
+ map.insert(
+ serde_yaml::Value::String("reason".to_owned()),
+ serde_yaml::Value::String(self.reason.to_owned()),
+ );
+ serde_yaml::Value::Mapping(map)
+ }
+}
+
#[allow(clippy::ptr_arg)] //# Avoids creating a rust::Slice object on the C++ side.
pub fn validate_auth_zones(field: &str, vec: &Vec<AuthZone>) -> Result<(), ValidationError> {
validate_vec(field, vec, |field, element| element.validate(field))
validate_vec(field, vec, |field, element| element.validate(field))
}
+#[allow(clippy::ptr_arg)] //# Avoids creating a rust::Slice object on the C++ side.
+pub fn validate_trustanchors(
+ field: &str,
+ vec: &Vec<TrustAnchor>,
+) -> Result<(), ValidationError> {
+ validate_vec(field, vec, |field, element| element.validate(field))
+}
+
+#[allow(clippy::ptr_arg)] //# Avoids creating a rust::Slice object on the C++ side.
+pub fn validate_negativetrustanchors(
+ field: &str,
+ vec: &Vec<NegativeTrustAnchor>,
+) -> Result<(), ValidationError> {
+ validate_vec(field, vec, |field, element| element.validate(field))
+}
+
pub fn allow_from_to_yaml_string(vec: &Vec<String>) -> Result<String, serde_yaml::Error> {
let mut seq = serde_yaml::Sequence::new();
for entry in vec {
}
serde_yaml::Value::Sequence(seq)
}
- other => serde_yaml::Value::String(
- "map_to_yaml_string: Unknown type: ".to_owned() + other,
- ),
+ "Vec<TrustAnchor>" => {
+ let mut seq = serde_yaml::Sequence::new();
+ for element in &entry.value.vec_trustanchor_val {
+ seq.push(element.to_yaml_map());
+ }
+ serde_yaml::Value::Sequence(seq)
+ }
+ "Vec<NegativeTrustAnchor>" => {
+ let mut seq = serde_yaml::Sequence::new();
+ for element in &entry.value.vec_negativetrustanchor_val {
+ seq.push(element.to_yaml_map());
+ }
+ serde_yaml::Value::Sequence(seq)
+ }
+ other => serde_yaml::Value::String("map_to_yaml_string: Unknown type: ".to_owned() + other),
};
if entry.overriding {
let tagged_value = Box::new(serde_yaml::value::TaggedValue {
Warn on potential self-resolve.
If this check draws the wrong conclusion, you can disable it.
''',
- 'versionadded': '5.1.0'
+ 'versionadded': '5.1.0'
+ },
+ {
+ 'name' : 'trustanchors',
+ 'section' : 'dnssec',
+ 'type' : LType.ListTrustAnchors,
+ 'default' : '',
+ 'help' : 'XXX',
+ 'doc' : ''',
+XXX
+ ''',
+ 'skip-old' : True,
+ 'versionadded': '5.1.0',
+ },
+ {
+ 'name' : 'negative_trustanchors',
+ 'section' : 'dnssec',
+ 'type' : LType.ListNegativeTrustAnchors,
+ 'default' : '',
+ 'help' : 'XXX',
+ 'doc' : ''',
+XXX
+ ''',
+ 'skip-old' : True,
+ 'versionadded': '5.1.0',
+ },
+ {
+ 'name' : 'trustanchorfile',
+ 'section' : 'dnssec',
+ 'type' : LType.String,
+ 'default' : '',
+ 'help' : 'XXX',
+ 'doc' : ''',
+ XXX
+ ''',
+ 'skip-old' : True,
+ 'versionadded': '5.1.0',
+ },
+ {
+ 'name' : 'trustanchorfile_interval',
+ 'section' : 'dnssec',
+ 'type' : LType.Uint64,
+ 'default' : '24',
+ 'help' : 'XXX',
+ 'doc' : ''',
+XXX
+ ''',
+ 'skip-old' : True,
+ 'versionadded': '5.1.0',
},
]