ACC SHELL
/**
* File: modules/DNS.ycp
* Package: Network configuration
* Summary: Hostname and DNS data
* Authors: Michal Svec <msvec@suse.cz>
*
* $Id: DNS.ycp 61734 2010-04-16 13:15:42Z kmachalkova $
*
* Manages resolv.conf and (fully qualified) hostname, also
* respecting DHCP.
*/
{
module "DNS";
textdomain "network";
import "NetHwDetection";
import "Hostname";
import "IP";
import "NetworkInterfaces";
import "ProductFeatures";
import "Progress";
import "Service";
import "String";
include "network/routines.ycp";
include "network/runtime.ycp";
/**
* Should the hostname be proposed? #152218
*/
global boolean proposal_valid = false;
/**
* Short Hostname
*/
global string hostname = "";
/**
* Domain Name (not including the host part)
*/
global string domain = "";
global list<string> nameservers = [];
global list<string> searchlist = [];
global boolean dhcp_hostname = false;
global boolean write_hostname = false;
global string resolv_conf_policy = "";
// fully qualified
string oldhostname = "";
/**
* Data was modified?
*/
global boolean modified = false;
/**
* Use the parameter, coming usually from install.inf, if it is defined.
* Used when there is nothing better.
* @param ns ip of the nameserver
* @return true if success
*/
global define boolean ReadNameserver (string ns) {
if (ns == "" || ns == nil)
return false;
nameservers = [ ns ];
//modified = true;
return true;
}
/**
* Use this host and domain name, if they are defined
* @param hn hostname
* @param dn domain name
* @return true if the hostname has been assigned
*/
global define boolean ReadHostDomain (string hn, string dn) {
if (hn == "" || hn == nil || dn == nil)
return false;
hostname = hn;
domain = dn;
//modified = true;
return true;
}
/*
* Get current hostname and IP Address
* if these are set by DHCP
* @return map with ip, hostname_short and hostname_fq keys
*/
global define map <string, string> GetDHCPHostnameIP () {
map <string, string> ret = $[];
map output = (map) SCR::Execute(.target.bash_output, "hostname -i");
ret["ip"] = deletechars(output["stdout"]:"", " \n");
output = (map) SCR::Execute(.target.bash_output, "hostname");
ret["hostname_short"] = deletechars(output["stdout"]:"", " \n");
output = (map) SCR::Execute(.target.bash_output, "hostname -f");
ret["hostname_fq"] = deletechars(output["stdout"]:"", " \n");
return ret;
}
//Copied from former Detection.ycp
/**
* Resolve IP to hostname
* @param ip given IP address
* @return resolved host
*/
string ResolveIP(string ip) {
string command = "/usr/bin/getent hosts \"%1\" | sed \"s/^[0-9.: \t]\\+//g\"";
map getent = (map) SCR::Execute(.target.bash_output, sformat(command, ip));
string hnent = getent["stdout"]:"";
y2debug("%1", hnent);
hnent = String::FirstChunk (hnent, " \t\n");
if(hnent == nil) hnent = "";
y2debug("'%1'", hnent);
return String::CutBlanks(hnent);
}
global boolean DefaultWriteHostname() {
// FaTe#303875: Introduce a switch regarding 127.0.0.2 entry in /etc/hosts
boolean whth = ProductFeatures::GetBooleanFeature ("globals", "write_hostname_to_hosts");
y2milestone("write_hostname_to_hosts default value: %1", whth);
return whth;
}
global void ReadHostname() {
string fqhostname = "";
// In installation (standard, or AutoYaST one), prefer /etc/install.inf
// (because HOSTNAME comes with netcfg.rpm already, #144687)
if( (Mode::installation() || Mode::autoinst()) &&
SCR::Read(.target.size, "/etc/install.inf") > 0) {
string install_inf_hostname = (string) SCR::Read(.etc.install_inf.Hostname);
y2milestone("Got %1 from install.inf", install_inf_hostname);
if ( size(install_inf_hostname) > 0) {
//if the name is actually IP, try to resolve it (bnc#556613, bnc#435649)
if ( IP::Check(install_inf_hostname) ) {
fqhostname = ResolveIP( install_inf_hostname );
y2milestone("Got %1 after resolving IP from install.inf", fqhostname);
}
else
fqhostname = install_inf_hostname;
}
}
// We have non-empty hostname by now => we must set DNS modified flag
// in order to get the setting actually written (bnc#588938)
if (size(fqhostname) > 0)
DNS::modified = true;
// /etc/HOSTNAME
// the usual location
if (fqhostname == "")
{
if (SCR::Read (.target.size, "/etc/HOSTNAME") > 0)
{
fqhostname = (string) SCR::Read (.target.string, "/etc/HOSTNAME");
//avoid passing nil argument when we get non-\n-terminated string (#445531)
fqhostname = String::FirstChunk( fqhostname, "\n" );
y2milestone("Got %1 from /etc/HOSTNAME", fqhostname);
}
}
list<string> split = Hostname::SplitFQ (fqhostname);
hostname = split[0]:"";
domain = split[1]:"";
// last resort
if (hostname == "")
{
hostname = "linux";
domain = "site";
}
}
global void ProposeHostname() {
if (hostname == "linux")
{
srandom ();
hostname = "linux-" + String::Random (4); // #157107
}
}
/**
* resolver config file location
*/
string resolv_conf = "/etc/resolv.conf";
/**
* True if DNS is already read
*/
boolean initialized = false;
/**
* Reads current DNS and hostname settings
* Includes Host,NetworkConfig::Read
* @return true if success
*/
global define boolean Read() {
if(initialized == true) return true;
string tmp1 = (string) SCR::Read(.sysconfig.network.dhcp.DHCLIENT_SET_HOSTNAME);
dhcp_hostname = ( tmp1 == "yes");
string tmp2 = (string) SCR::Read(.sysconfig.network.dhcp.WRITE_HOSTNAME_TO_HOSTS);
write_hostname = ( tmp2 == "yes");
resolv_conf_policy = (string)SCR::Read(.sysconfig.network.config.NETCONFIG_DNS_POLICY);
list<string> resolvlist = splitstring((string)SCR::Read(.sysconfig.network.config.NETCONFIG_DNS_STATIC_SERVERS), " ");
if( size(resolvlist) > 0)
nameservers = resolvlist;
searchlist = splitstring((string)SCR::Read(.sysconfig.network.config.NETCONFIG_DNS_STATIC_SEARCHLIST), " ");
/* hostname and domain */
ReadHostname();
oldhostname = Hostname::MergeFQ (hostname, domain);
y2milestone("nameservers=%1", nameservers);
y2milestone("searchlist=%1", searchlist);
y2milestone("hostname=%1", hostname);
y2milestone("domain=%1", domain);
initialized = true;
return true;
}
/**
* Write new DNS and hostname settings
* Includes Host,NetworkConfig::Write
* @return true if success
*/
global define boolean Write() {
/* build FQ hostname */
string fqhostname = Hostname::MergeFQ(hostname, domain);
//We do not collect static IP addresses here, as hostnames
//are defined for each static IP separately in address dialog
//FaTE #2202
oldhostname = fqhostname; // #49634
SCR::Write(.sysconfig.network.dhcp.DHCLIENT_SET_HOSTNAME, dhcp_hostname ? "yes" : "no");
SCR::Write(.sysconfig.network.dhcp.WRITE_HOSTNAME_TO_HOSTS, write_hostname ? "yes" : "no");
SCR::Write(.sysconfig.network.dhcp, nil);
y2milestone("Writing configuration");
if(!modified) {
y2milestone("No changes to DNS -> nothing to write");
return true;
}
y2milestone("nameservers=%1", nameservers);
y2milestone("searchlist=%1", searchlist);
y2milestone("hostname=%1", hostname);
y2milestone("domain=%1", domain);
y2milestone("dhcp_hostname=%1, write_hostname=%2", dhcp_hostname, write_hostname);
list <string> steps = [
/* Progress stage 1 */
_("Write hostname"),
/* Progress stage 2 */
_("Run SuSEconfig"),
/* Progress stage 3 */
_("Update /etc/resolv.conf")
];
/* Write dialog caption */
string caption = _("Saving Hostname and DNS Configuration");
integer sl = 0; //100; for testing
Progress::New(caption, " ", size(steps), steps, [], "");
/* Allow to set hostname even if it's modified by DHCP (#13427)
if(NetworkConfig::DHCP["DHCLIENT_SET_HOSTNAME"]:false != true) { */
/* Progress step 1/3 */
ProgressNextStage(_("Writing hostname..."));
/* change the hostname */
SCR::Execute(.target.bash, "/bin/hostname " + hostname);
/* write hostname */
SCR::Write(.target.string, "/etc/HOSTNAME", fqhostname + "\n");
sleep(sl);
/* Progress step 2/3 */
ProgressNextStage(_("Running SuSEconfig..."));
/* Finish him */
RunSuSEconfig();
sleep(sl);
/*
if(SCR::Read(.target.size, resolv_conf) < 0)
SCR::Write(.target.string, resolv_conf, "");
*/
/* Progress step 3/3 */
ProgressNextStage(_("Updating /etc/resolv.conf ..."));
SCR::Write(.sysconfig.network.config.NETCONFIG_DNS_POLICY, resolv_conf_policy);
SCR::Write(.sysconfig.network.config.NETCONFIG_DNS_STATIC_SEARCHLIST, mergestring(searchlist, " "));
SCR::Write(.sysconfig.network.config.NETCONFIG_DNS_STATIC_SERVERS, mergestring(nameservers, " "));
SCR::Write(.sysconfig.network.config, nil);
SCR::Execute(.target.bash, "/sbin/netconfig update");
sleep(sl);
Progress::NextStage();
modified = false;
return true;
}
/**
* Get all the DNS configuration from a map.
* When called by dns_auto (preparing autoinstallation data)
* the map may be empty.
* @param settings autoinstallation settings
* @return true if success
*/
global define boolean Import(map settings) {
dhcp_hostname = settings["dhcp_hostname"]:false;
//if not defined, set to 'auto'
resolv_conf_policy = settings["resolv_conf_policy"]:"auto";
// user-defined value has higher priority - FaTE#305281
if ( haskey(settings, "write_hostname") )
write_hostname = settings["write_hostname"]:false;
// otherwise, use control.xml default
else
write_hostname = DefaultWriteHostname();
// user-defined <hostname>
if ( haskey(settings, "hostname") && haskey(settings, "domain")) {
hostname = settings["hostname"]:"";
domain = settings["domain"]:"site";
}
else {
// otherwise, check 1) install.inf 2) /etc/HOSTNAME
ReadHostname();
// if nothing is found, generate a random one
ProposeHostname();
}
nameservers = (list<string>) eval(settings["nameservers"]:[]);
searchlist = (list<string>) eval(settings["searchlist"]:[]);
modified = true;
// empty settings means that we're probably resetting the config
// thus, setup is not initialized anymore
initialized = ( settings != $[] );
y2milestone("DNS Import:");
y2milestone("nameservers=%1", nameservers);
y2milestone("searchlist=%1", searchlist);
y2milestone("hostname=%1", hostname);
y2milestone("domain=%1", domain);
y2milestone("dhcp_hostname=%1, write_hostname=%2", dhcp_hostname, write_hostname);
return true;
}
/**
* Dump the DNS settings to a map, for autoinstallation use.
* @return autoinstallation settings
*/
global define map Export() {
map<string, any> expdns = $[];
if (size(hostname)>0)
expdns["hostname"] = hostname;
if (size(domain)>0)
expdns["domain"] = domain;
if (size(nameservers)>0)
expdns["nameservers"] = eval(nameservers);
if (size(searchlist) >0)
expdns["searchlist"] = eval(searchlist);
expdns["dhcp_hostname"] = dhcp_hostname;
//TODO: test if it really works with empty string
expdns["resolv_conf_policy"] = resolv_conf_policy;
//bnc#576495, FaTE#305281 - clone write_hostname, too
expdns["write_hostname"] = write_hostname;
return expdns;
}
/**
* Create DNS text summary
* @return summary text
*/
global define string Summary() {
import "Summary";
string summary = "";
boolean has_dhcp = size (NetworkInterfaces::Locate ("BOOTPROTO", "dhcp")) > 0;
if (has_dhcp && dhcp_hostname)
/* Summary text */
summary = Summary::AddListItem(summary, _("Hostname: Set by DHCP"));
else if(size(hostname) > 0)
/* Summary text */
summary = Summary::AddListItem(summary, sformat(_("Hostname: %1"), Hostname::MergeFQ(hostname, domain)));
if ( !write_hostname )
summary = Summary::AddListItem(summary, _("Hostname will not be written to /etc/hosts"));
/*if (has_dhcp && NetworkConfig::DHCP["DHCLIENT_MODIFY_RESOLV_CONF"]:false) {*/
/* Summary text */
/*summary = Summary::AddListItem(summary, _("Name Servers: Set by DHCP")); */
/* Summary text */
/*summary = Summary::AddListItem(summary, _("Search List: Set by DHCP")); */
/*}*/
/*else {*/
list<string> nslist = maplist(string ns, nameservers, {
string nss = NetHwDetection::ResolveIP(ns);
return (nss == "") ? ns : (ns + " (" + nss + ")");
});
if(size(nslist) > 0)
/* Summary text */
summary = Summary::AddListItem(summary, sformat(_("Name Servers: %1"), mergestring(nslist, ", ")));
if(size(searchlist) > 0)
/* Summary text */
summary = Summary::AddListItem(summary, sformat(_("Search List: %1"), mergestring(searchlist, ", ")));
/*}*/
if(size(summary) < 1) return "";
return "<ul>" + summary + "</ul>";
}
/**
* Check if hostname or IP address is local computer
* Used to determine if LDAP server is local (and it should be checked if
* required schemes are included
* Calls Read () function before querying any data
* @param check_host string hostname or IP address to check
* @return boolean true if hostname is local host
*/
global define boolean IsHostLocal (string check_host) {
Read ();
NetworkInterfaces::Read ();
map <string, string> dhcp_data = $[];
if ( (size( NetworkInterfaces::Locate("BOOTPROTO", "dhcp") ) > 0) ||
dhcp_hostname ) {
dhcp_data = GetDHCPHostnameIP();
y2milestone("Got DHCP-configured data: %1", dhcp_data);
}
/* FIXME: May not work properly in following situations:
- multiple addresses per interface
- aliases in /etc/hosts
- IPADDR=IP/24
*/
// loopback interface
if (check_host == "127.0.0.1" || check_host == "::1")
return true;
// localhost hostname
if (check_host == "localhost" || check_host == "localhost.localdomain")
return true;
// IPv4 address
if (IP::Check4 (check_host))
{
if ( (size (NetworkInterfaces::Locate ("IPADDR", check_host)) > 0)
|| dhcp_data["ip"]:"" == check_host)
return true;
}
// IPv6 address
else if (IP::Check6 (check_host))
{
y2debug ("TODO make it similar to IPv4 after other code adapted to IPv6");
}
// short hostname
else if (findfirstof (check_host, ".") == nil)
{
if ( (tolower (check_host) == tolower (hostname))
|| dhcp_data["hostname_short"]:"" == check_host)
return true;
}
// fully qualified hostname
else
{
if ( (tolower (check_host) == tolower (hostname + "." + domain))
|| dhcp_data["hostname_fq"]:"" == check_host )
return true;
}
return false;
}
/* EOF */
}
ACC SHELL 2018