diff options
author | Kenneth R Westerback <krw@cvs.openbsd.org> | 2013-02-01 01:33:45 +0000 |
---|---|---|
committer | Kenneth R Westerback <krw@cvs.openbsd.org> | 2013-02-01 01:33:45 +0000 |
commit | 19a793606451fcc605c05ca20bbd8662b0ec2fd9 (patch) | |
tree | aaf459c9cb906b086c01cd38f0767035cb58c8d4 /sbin | |
parent | 8fb1ab30611285831c4c363f655a50adb5798f2f (diff) |
Write out resolv.conf only if the default route is under the control
of the process binding the lease. Re-check the default route whenever
a routing message arrives that might mean the default route has
changed, and write out resolv.conf if appropriate.
Reduces the chances that the name servers in resolv.conf are
unreachable.
Problem most eloquently explained, and solution suggested by beck@.
Diffstat (limited to 'sbin')
-rw-r--r-- | sbin/dhclient/dhclient.c | 28 | ||||
-rw-r--r-- | sbin/dhclient/kroute.c | 86 |
2 files changed, 104 insertions, 10 deletions
diff --git a/sbin/dhclient/dhclient.c b/sbin/dhclient/dhclient.c index e3779d07128..c2d0a5209e4 100644 --- a/sbin/dhclient/dhclient.c +++ b/sbin/dhclient/dhclient.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dhclient.c,v 1.217 2013/01/27 02:45:46 krw Exp $ */ +/* $OpenBSD: dhclient.c,v 1.218 2013/02/01 01:33:44 krw Exp $ */ /* * Copyright 2004 Henning Brauer <henning@openbsd.org> @@ -93,6 +93,7 @@ struct imsgbuf *unpriv_ibuf; void sighdlr(int); int findproto(char *, int); struct sockaddr *get_ifa(char *, int); +int resolv_conf_priority(int); void usage(void); int res_hnok(const char *dn); char *option_as_string(unsigned int code, unsigned char *data, int len); @@ -288,6 +289,15 @@ routehandler(void) default: break; } + + /* Something has happened. Try to write out the resolv.conf. */ + if (client->active && client->active->resolv_conf && + resolv_conf_priority(ifi->rdomain)) + write_file("/etc/resolv.conf", + O_WRONLY | O_CREAT | O_TRUNC | O_SYNC | O_EXLOCK, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, 0, 0, + client->new->resolv_conf, strlen(client->new->resolv_conf)); + return; die: @@ -783,14 +793,6 @@ bind_lease(void) if (nameservers == NULL) error("no memory for nameservers"); - client->new->resolv_conf = resolv_conf_contents( - &options[DHO_DOMAIN_NAME], &options[DHO_DOMAIN_NAME_SERVERS]); - if (client->new->resolv_conf) - write_file("/etc/resolv.conf", - O_WRONLY | O_CREAT | O_TRUNC | O_SYNC | O_EXLOCK, - S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, 0, 0, - client->new->resolv_conf, strlen(client->new->resolv_conf)); - /* * Add address and default route last, so we know when the binding * is done by the RTM_NEWADDR message being received. @@ -804,6 +806,14 @@ bind_lease(void) add_default_route(ifi->rdomain, client->new->address, gateway); } + client->new->resolv_conf = resolv_conf_contents( + &options[DHO_DOMAIN_NAME], &options[DHO_DOMAIN_NAME_SERVERS]); + if (client->new->resolv_conf) + write_file("/etc/resolv.conf", + O_WRONLY | O_CREAT | O_TRUNC | O_SYNC | O_EXLOCK, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, 0, 0, + client->new->resolv_conf, strlen(client->new->resolv_conf)); + free(domainname); free(nameservers); diff --git a/sbin/dhclient/kroute.c b/sbin/dhclient/kroute.c index 47b52503167..20bc4444633 100644 --- a/sbin/dhclient/kroute.c +++ b/sbin/dhclient/kroute.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kroute.c,v 1.28 2013/01/22 06:02:52 krw Exp $ */ +/* $OpenBSD: kroute.c,v 1.29 2013/02/01 01:33:44 krw Exp $ */ /* * Copyright 2012 Kenneth R Westerback <krw@openbsd.org> @@ -701,3 +701,87 @@ priv_cleanup(struct imsg_cleanup *imsg) dimsg.addr = imsg->addr; priv_delete_address(&dimsg); } + +int +resolv_conf_priority(int domain) +{ + struct sockaddr *rti_info[RTAX_MAX]; + int mib[7]; + size_t needed; + char *lim, *buf, *next, *routelabel; + struct rt_msghdr *rtm; + struct sockaddr *sa; + struct sockaddr_in *sa_in; + struct sockaddr_rtlabel *sa_rl; + int i, priority, mypriority; + + mib[0] = CTL_NET; + mib[1] = PF_ROUTE; + mib[2] = 0; + mib[3] = AF_INET; + mib[4] = NET_RT_FLAGS; + mib[5] = RTF_GATEWAY; + mib[6] = domain; + + if (sysctl(mib, 7, NULL, &needed, NULL, 0) == -1) { + if (domain != 0 && errno == EINVAL) + return (1); + error("sysctl size of routes: %s", strerror(errno)); + } + + if (needed == 0) + return (1); + + if ((buf = malloc(needed)) == NULL) + error("no memory for sysctl routes"); + + if (sysctl(mib, 7, buf, &needed, NULL, 0) == -1) + error("sysctl retrieval of routes: %s", strerror(errno)); + + if (asprintf(&routelabel, "DHCLIENT %d", (int)getpid()) == -1) + error("recreating route label: %s", strerror(errno)); + +#define ROUNDUP(a) \ + ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) + + priority = mypriority = INT_MAX; + lim = buf + needed; + for (next = buf; next < lim; next += rtm->rtm_msglen) { + rtm = (struct rt_msghdr *)next; + if (rtm->rtm_version != RTM_VERSION) + continue; + if ((rtm->rtm_flags & RTF_UP) == 0) + continue; + if (rtm->rtm_flags & RTF_REJECT) + continue; + + sa = (struct sockaddr *)(next + rtm->rtm_hdrlen); + memset(rti_info, 0, sizeof(rti_info)); + for (i = 0; i < RTAX_MAX; i++) { + if (rtm->rtm_addrs & (1 << i)) { + rti_info[i] = sa; + sa = (struct sockaddr *)((char *)(sa) + + ROUNDUP(sa->sa_len)); + } + } + + sa_in = (struct sockaddr_in *)rti_info[RTAX_DST]; + if (sa_in == NULL || sa_in->sin_addr.s_addr != INADDR_ANY) + continue; + sa_in = (struct sockaddr_in *)rti_info[RTAX_NETMASK]; + if (sa_in == NULL || sa_in->sin_addr.s_addr != INADDR_ANY) + continue; + + sa_rl = (struct sockaddr_rtlabel *)rti_info[RTAX_LABEL]; + if (sa_rl && strcmp(routelabel, sa_rl->sr_label) == 0) { + if (rtm->rtm_priority < mypriority) + mypriority = rtm->rtm_priority; + } else if (rtm->rtm_priority < priority) + priority = rtm->rtm_priority; + } + + free(buf); + free(routelabel); + + return (mypriority < priority); +} |