Maybe there's a simpler fix - Apparently Go can be forced to use the
libc-based (or musl-based) resolver by setting the environment variable.
GODEBUG=netdns=cgo
Perhaps this is something we can set in our localized Go package instead?
Google's default DNS servers won't work for anyone that needs local DNS for
their systems to function - like AWS users. (And I'll note that this would
fix Go by setting reasonable defaults, but not Erlang or any other package
that depends on /etc/resolv.conf to exist.) I still like the idea of
providing an option to behave like a standard UNIX DHCP client for software
that is ancient and depends on that. But are there any other packages like
that? I'm not about to try booting Oracle under OSv ;)
I'll suggest an additional patch that will enable this by default; It
checks for /etc/resolv.conf's existence and falls back to Cgo if it cannot
be found. Tested on this end and seems to work in both cases (with and
without resolv file). As for the kernel flag, I'm a fan of short, easily
explainable flags. I only picked --resolv since --resolv_conf was too much
typing. Happy to defer to you guys on what the "right" kernel flag for it
would be.
I'll work on revising the dhcp.cc patch to check for errors (running on
ROFS) more thoroughly, and post that as soon as it's better. Thanks for
your patience with me! :)
Go patch follows:
--- ./modules/golang/go.cc~ 2019-02-06 10:21:39.769962944 -0500
+++ ./modules/golang/go.cc 2019-02-06 10:39:55.050571909 -0500
@@ -33,6 +33,19 @@
extern "C"
int main(int argc, char **argv)
{
+ // On environments that do not have a /etc/resolv.conf file, Go's
native
+ // DNS resolver will be broken. Therefore, we need to instruct Go to
use
+ // the OSv-native resolver instead.
+ //
+ if( access( "/etc/resolv.conf", F_OK ) < 0 )
+ {
+ //
+ // File does not exist or is not readable. Revert to Cgo.
+ //
+ setenv( "GODEBUG", "netdns=cgo", 1 );
+ printf( "go: /etc/resolv.conf could not be found, using native
resolver\n" );
+ }
+
const std::string go_program(argv[1]);
std::vector<std::string> go_program_arguments;
On Tuesday, February 5, 2019 at 11:35:25 AM UTC-5, Waldek Kozaczuk wrote:
>
> Hi,
>
> Sorry for the long delay.
>
> Let me recap couple of things at least for my own sake of having better
> understanding of the problem. So there are two aspects around resolv.conf -
> (1) how the file is used and (2) how it constructed. As far as 1) goes
> normally apps rely on libc to resolve host names which hides existence of
> the file. In OSv case which uses musl you can see details here -
> https://wiki.musl-libc.org/functional-differences-from-glibc.html (see
> 'Names Resolver/DNS section'). Golang (and probably Erlang) are different
> and they directly use resolve.conf - I think this golang source code has
> details of the logic -
> https://github.com/golang/go/blob/9ff11b026089791c4d2bc14c17647f3cb4f4aa22/src/net/conf.go#L100
>
> <https://www.google.com/url?q=https%3A%2F%2Fgithub.com%2Fgolang%2Fgo%2Fblob%2F9ff11b026089791c4d2bc14c17647f3cb4f4aa22%2Fsrc%2Fnet%2Fconf.go%23L100&sa=D&sntz=1&usg=AFQjCNEUFbFa_Kg259aQ2qNjJryAmtSPQg>
> .
>
> I have also found article of how resolv.conf is constructed -
> https://www.ctrl.blog/entry/resolvconf-tutorial
> <https://www.google.com/url?q=https%3A%2F%2Fwww.ctrl.blog%2Fentry%2Fresolvconf-tutorial&sa=D&sntz=1&usg=AFQjCNGCnE8q82MgWIT4b0JxMncw_KS1XQ>
> .
>
> So here is what I propose:
> 1. Make simple change to golang module to add the default resolv.conf (see
> https://github.com/cloudius-systems/osv-apps/blob/master/erlang/default/resolv.conf
>
> for example) which points to Google public DNS server. This would make all
> Golang apps work out of the box as far as making outgoing HTTP calls which
> we discover does not work unless resolv.conf is present. This fix is super
> trivial.
> 2. For efficiency reasons to make Golang apps use DNS server that is
> resolved as part of DHCP lookup. I agree with Brian's approach that this
> should be optional.
>
> I wonder what others think?
>
> Waldek
>
> PS. Please see my patch comments below.
>
> On Friday, January 25, 2019 at 11:27:37 AM UTC-5, Brian Ledbetter wrote:
>>
>> Here's my first stab at solving this problem in a backwards-compatible
>> way, let me know what you think. I've added a --resolv flag to the loader
>> to enable this behavior.
>>
>> Please see
> https://github.com/cloudius-systems/osv/wiki/Formatting-and-sending-patches
> for how to format and send patches to the group. Thanks.
>
>> patch-dhcp.cc:
>>
>> --- ./core/dhcp.cc~ 2019-01-25 11:18:29.173860626 -0500
>> +++ ./core/dhcp.cc 2019-01-25 11:17:19.546083373 -0500
>>
> I agree that dhcp.cc is the right place for this logic.
>
>> @@ -29,6 +29,12 @@
>> #include <libc/network/__dns.hh>
>>
>> using namespace boost::asio;
>> +bool generate_resolv_conf = false;
>> +
>> +void enable_resolv_conf()
>> +{
>> + generate_resolv_conf = true;
>> +}
>>
>> dhcp::dhcp_worker net_dhcp_worker;
>>
>> @@ -720,6 +726,31 @@
>> });
>>
>> osv::set_dns_config(dm.get_dns_ips(),
>> std::vector<std::string>());
>> +
>> + // Some linux applications (go, erlang) depend on
>> /etc/resolv.conf to be
>> + // populated with DNS server information in order to
>> function. The --resolv
>> + // option has been added to the kernel loader, which will
>> enable this
>> + // feature.
>> + //
>> + // TODO: It's possible that the /etc directory does not exist
>> at this time.
>> + // We should ideally check and create it if necessary. What's
>> the right
>> + // way to do that?
>>
> Probably. What if the filesystem is read-only\?
>
>> + //
>> + // TODO: We are currently ignoring DHCP-provided default
>> domain
>> + // names. I'll have to dig further into the code to see if I
>> can ingest
>> + // those.
>> + //
>> + if( generate_resolv_conf )
>> + {
>> + FILE *f = fopen("/etc/resolv.conf", "w+");
>>
> Should we be appending if file already exists rather than overwrite it?
>
>> + if( f ) {
>> + fprintf( f, "## Autoconfigured by DHCP\n" );
>>
> I think this fprintf is redundant - you are printing the result below
> anyway.
>
>> + for( auto &ip : dm.get_dns_ips() )
>> + {
>> + fprintf( f, "server %s\n",
>> ip.to_string().c_str() );
>> + dhcp_i( "Added DNS server: %s\n",
>> ip.to_string().c_str() );
>> + }
>> + fclose( f );
>> + dhcp_i( "Generated /etc/resolv.conf" );
>>
> You could refine this message that it was generated from DHCP.
>
>> + }
>>
> Should we be handling the error of opening file and warn user that we
> could not generate the file?
>
>> + }
>> +
>> if (dm.get_hostname().size()) {
>> sethostname(dm.get_hostname().c_str(),
>> dm.get_hostname().size());
>> dhcp_i("Set hostname to: %s", dm.get_hostname().c_str());
>>
>>
>> patch-loader.cc:
>>
>> --- ./loader.cc~ 2019-01-25 11:10:40.091359718 -0500
>> +++ ./loader.cc 2019-01-25 11:11:40.243167695 -0500
>> @@ -144,10 +144,13 @@
>> bool opt_assign_net = false;
>> bool opt_maxnic = false;
>> int maxnic;
>> +static bool opt_resolv_conf = false;
>>
>> static int sampler_frequency;
>> static bool opt_enable_sampler = false;
>>
>> +void enable_resolv_conf();
>> +
>> void parse_options(int loader_argc, char** loader_argv)
>> {
>> namespace bpo = boost::program_options;
>> @@ -182,6 +185,7 @@
>> ("delay", bpo::value<float>()->default_value(0), "delay in
>> seconds before boot")
>> ("redirect", bpo::value<std::string>(), "redirect stdout and
>> stderr to file")
>> ("disable_rofs_cache", "disable ROFS memory cache")
>> + ("resolv", "generate an /etc/resolv.conf file with DHCP DNS
>> values (for Linux compatibility)")
>> ;
>> bpo::variables_map vars;
>> // don't allow --foo bar (require --foo=bar) so we can find the
>> first non-option
>> @@ -234,6 +238,11 @@
>> enable_verbose();
>> }
>>
>> + if (vars.count("resolv")) {
>> + opt_resolv_conf = true;
>> + enable_resolv_conf();
>> + }
>> +
>> if (vars.count("sampler")) {
>> sampler_frequency = vars["sampler"].as<int>();
>> opt_enable_sampler = true;
>>
>>
>> patch-run.py:
>>
>> --- ./scripts/run.py~ 2019-01-25 11:14:20.858654652 -0500
>> +++ ./scripts/run.py 2019-01-25 11:14:52.406553829 -0500
>> @@ -43,6 +43,8 @@
>> execute = cmdline.read()
>> if options.verbose:
>> execute = "--verbose " + execute
>> + if options.resolv:
>> + execute = "--resolv " + execute
>>
> Maybe resolve_DNS?
>
>>
>> if options.jvm_debug or options.jvm_suspend:
>> if '-agentlib:jdwp' in execute:
>> @@ -461,6 +463,8 @@
>> help="Enable graphics mode.")
>> parser.add_argument("-V", "--verbose", action="store_true",
>> help="pass --verbose to OSv, to display more
>> debugging information on the console")
>> + parser.add_argument("--resolv", action="store_true",
>> + help="pass --resolv to OSv, to generate an
>> /etc/resolv.conf file for Linux compatibility")
>> parser.add_argument("--forward", metavar="RULE", action="append",
>> default=[],
>> help="add network forwarding RULE (QEMU syntax)")
>> parser.add_argument("--dry-run", action="store_true",
>>
>>
>>
--
You received this message because you are subscribed to the Google Groups "OSv
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.