On Tue, Feb 5, 2019 at 6:35 PM Waldek Kozaczuk <jwkozac...@gmail.com> wrote:
> > 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 > . > > I have also found article of how resolv.conf is constructed - > https://www.ctrl.blog/entry/resolvconf-tutorial. > > 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 think the easiest and perhaps best approach would be to have the DHCP client write a file /etc/resolv.conf when it discovers the DNS server? This is what happens in my Linux system - the /etc/resolv.conf on my laptop has: # Generated by NetworkManager nameserver 192.168.0.1 To support the case where the /etc filesystem is read-only, we can do the following: In the read-only filesystem, put in /etc/resolv.conf a symbolic link to /tmp/resolv.conf, assuming we always mount a writable /tmp. Then, when dhcp.cc will write to "/etc/resolv.conf" (overwritten, e.g., open() with O_TRUNC), it will actually write to that file on /tmp and succeed. > 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 osv-dev+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -- 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 osv-dev+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.