Oh - Here's the official path that the ISC-DHCP client takes when 
generating /etc/resolv.conf; It results in a new file with each DHCP 
reconfiguration.  We should definitely not be appending, since we want to 
defer to whatever server search order the DHCP server is sending to us:

https://source.isc.org/cgi-bin/gitweb.cgi?p=dhcp.git;a=blob;f=client/scripts/linux;h=0c42969744e4fd0ea513f9d5516183cef207c3b4;hb=HEAD

I will need to look at extending our DHCP client to import the domain name 
and domain search order parameters, and add those to our generated file as 
well - in order to be fully in tune with the official standard.  I'll try 
to get that into the next dhcp.cc patch I send, but we'll see how that 
goes.  :)






On Wednesday, February 6, 2019 at 10:44:04 AM UTC-5, Brian Ledbetter wrote:
>
> 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.

Reply via email to