mirror of
https://github.com/rsmarples/dhcpcd.git
synced 2024-11-24 02:24:35 +08:00
Add DHPCv6 FQDN support (RFC4704)
Improve hostname support in general, so we are aware of hostname changes. When setting the hostname, prefer the FQDN name or append a domain.
This commit is contained in:
parent
be2a8dac4e
commit
cc3c3560f6
14
common.c
14
common.c
@ -60,6 +60,7 @@
|
||||
# define _PATH_DEVNULL "/dev/null"
|
||||
#endif
|
||||
|
||||
static char hostname_buffer[HOSTNAME_MAX_LEN];
|
||||
int clock_monotonic;
|
||||
static char *lbuf;
|
||||
static size_t lbuf_len;
|
||||
@ -134,6 +135,19 @@ set_nonblock(int fd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *
|
||||
get_hostname(void)
|
||||
{
|
||||
|
||||
gethostname(hostname_buffer, sizeof(hostname_buffer));
|
||||
if (strcmp(hostname_buffer, "(none)") == 0 ||
|
||||
strcmp(hostname_buffer, "localhost") == 0 ||
|
||||
strncmp(hostname_buffer, "localhost.", strlen("localhost.")) == 0 ||
|
||||
hostname_buffer[0] == '.')
|
||||
return NULL;
|
||||
return hostname_buffer;
|
||||
}
|
||||
|
||||
/* Handy function to get the time.
|
||||
* We only care about time advancements, not the actual time itself
|
||||
* Which is why we use CLOCK_MONOTONIC, but it is not available on all
|
||||
|
5
common.h
5
common.h
@ -34,6 +34,10 @@
|
||||
#include "config.h"
|
||||
#include "defs.h"
|
||||
|
||||
#ifndef HOSTNAME_MAX_LEN
|
||||
#define HOSTNAME_MAX_LEN 250 /* 255 - 3 (FQDN) - 2 (DNS enc) */
|
||||
#endif
|
||||
|
||||
#define UNCONST(a) ((void *)(unsigned long)(const void *)(a))
|
||||
|
||||
#define timeval_to_double(tv) ((tv)->tv_sec * 1.0 + (tv)->tv_usec * 1.0e-6)
|
||||
@ -96,6 +100,7 @@
|
||||
int set_cloexec(int);
|
||||
int set_nonblock(int);
|
||||
char *get_line(FILE * __restrict);
|
||||
const char *get_hostname(void);
|
||||
extern int clock_monotonic;
|
||||
int get_monotonic(struct timeval *);
|
||||
ssize_t setvar(char ***, const char *, const char *, const char *);
|
||||
|
@ -89,6 +89,50 @@ int make_option_mask(const struct dhcp_opt *dopts,
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t
|
||||
encode_rfc1035(const char *src, uint8_t *dst)
|
||||
{
|
||||
uint8_t *p;
|
||||
uint8_t *lp;
|
||||
size_t len;
|
||||
uint8_t has_dot;
|
||||
|
||||
if (src == NULL || *src == '\0')
|
||||
return 0;
|
||||
if (dst) {
|
||||
p = dst;
|
||||
lp = p++;
|
||||
}
|
||||
len = 1;
|
||||
has_dot = 0;
|
||||
for (; *src; src++) {
|
||||
if (*src == '\0')
|
||||
break;
|
||||
if (*src == '.') {
|
||||
/* Skip the trailing . */
|
||||
if (src[1] == '\0')
|
||||
break;
|
||||
has_dot = 1;
|
||||
if (dst) {
|
||||
*lp = p - lp - 1;
|
||||
if (*lp == '\0')
|
||||
return len;
|
||||
lp = p++;
|
||||
}
|
||||
} else if (dst)
|
||||
*p++ = (uint8_t)*src;
|
||||
len++;
|
||||
}
|
||||
if (dst) {
|
||||
*lp = p - lp - 1;
|
||||
if (has_dot)
|
||||
*p++ = '\0';
|
||||
}
|
||||
if (has_dot)
|
||||
len++;
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Decode an RFC3397 DNS search order option into a space
|
||||
* separated string. Returns length of string (including
|
||||
* terminating zero) or zero on error. out may be NULL
|
||||
|
@ -67,6 +67,7 @@ struct dhcp_opt {
|
||||
#define del_option_mask(var, val) (var[val >> 3] &= ~(1 << (val & 7)))
|
||||
#define has_option_mask(var, val) (var[val >> 3] & (1 << (val & 7)))
|
||||
int make_option_mask(const struct dhcp_opt *,uint8_t *, const char *, int);
|
||||
size_t encode_rfc1035(const char *src, uint8_t *dst);
|
||||
ssize_t decode_rfc3397(char *, ssize_t, int, const uint8_t *);
|
||||
ssize_t print_string(char *, ssize_t, int, const uint8_t *);
|
||||
ssize_t print_option(char *, ssize_t, int, int, const uint8_t *, const char *);
|
||||
|
57
dhcp.c
57
dhcp.c
@ -801,33 +801,6 @@ get_option_routes(struct interface *ifp, const struct dhcp_message *dhcp)
|
||||
return routes;
|
||||
}
|
||||
|
||||
static size_t
|
||||
encode_rfc1035(const char *src, uint8_t *dst)
|
||||
{
|
||||
uint8_t *p = dst;
|
||||
uint8_t *lp = p++;
|
||||
|
||||
if (*src == '\0')
|
||||
return 0;
|
||||
for (; *src; src++) {
|
||||
if (*src == '\0')
|
||||
break;
|
||||
if (*src == '.') {
|
||||
/* Skip the trailing . */
|
||||
if (src[1] == '\0')
|
||||
break;
|
||||
*lp = p - lp - 1;
|
||||
if (*lp == '\0')
|
||||
return p - dst;
|
||||
lp = p++;
|
||||
} else
|
||||
*p++ = (uint8_t)*src;
|
||||
}
|
||||
*lp = p - lp - 1;
|
||||
*p++ = '\0';
|
||||
return p - dst;
|
||||
}
|
||||
|
||||
#define PUTADDR(_type, _val) \
|
||||
{ \
|
||||
*p++ = _type; \
|
||||
@ -877,6 +850,7 @@ make_message(struct dhcp_message **message,
|
||||
const struct dhcp_state *state = D_CSTATE(iface);
|
||||
const struct dhcp_lease *lease = &state->lease;
|
||||
time_t up = uptime() - state->start_uptime;
|
||||
const char *hostname;
|
||||
|
||||
dhcp = calloc(1, sizeof (*dhcp));
|
||||
if (dhcp == NULL)
|
||||
@ -1006,18 +980,22 @@ make_message(struct dhcp_message **message,
|
||||
* upto the first dot (the short hostname) as otherwise
|
||||
* confuses some DHCP servers when updating DNS.
|
||||
* The FQDN option should be used if a FQDN is required. */
|
||||
if (ifo->options & DHCPCD_HOSTNAME && ifo->hostname[0]) {
|
||||
if (ifo->hostname[0] == '\0')
|
||||
hostname = get_hostname();
|
||||
else
|
||||
hostname = ifo->hostname;
|
||||
if (ifo->options & DHCPCD_HOSTNAME && hostname) {
|
||||
*p++ = DHO_HOSTNAME;
|
||||
hp = strchr(ifo->hostname, '.');
|
||||
hp = strchr(hostname, '.');
|
||||
if (hp)
|
||||
len = hp - ifo->hostname;
|
||||
len = hp - hostname;
|
||||
else
|
||||
len = strlen(ifo->hostname);
|
||||
len = strlen(hostname);
|
||||
*p++ = len;
|
||||
memcpy(p, ifo->hostname, len);
|
||||
memcpy(p, hostname, len);
|
||||
p += len;
|
||||
}
|
||||
if (ifo->fqdn != FQDN_DISABLE && ifo->hostname[0]) {
|
||||
if (ifo->fqdn != FQDN_DISABLE) {
|
||||
/* IETF DHC-FQDN option (81), RFC4702 */
|
||||
*p++ = DHO_FQDN;
|
||||
lp = p;
|
||||
@ -1032,12 +1010,17 @@ make_message(struct dhcp_message **message,
|
||||
* N: 1 => Client requests Server to not
|
||||
* update DNS
|
||||
*/
|
||||
*p++ = (ifo->fqdn & 0x09) | 0x04;
|
||||
if (hostname)
|
||||
*p++ = (ifo->fqdn & 0x09) | 0x04;
|
||||
else
|
||||
*p++ = (FQDN_NONE & 0x09) | 0x04;
|
||||
*p++ = 0; /* from server for PTR RR */
|
||||
*p++ = 0; /* from server for A RR if S=1 */
|
||||
ul = encode_rfc1035(ifo->hostname, p);
|
||||
*lp += ul;
|
||||
p += ul;
|
||||
if (hostname) {
|
||||
ul = encode_rfc1035(hostname, p);
|
||||
*lp += ul;
|
||||
p += ul;
|
||||
}
|
||||
}
|
||||
|
||||
/* vendor is already encoded correctly, so just add it */
|
||||
|
37
dhcp6.c
37
dhcp6.c
@ -126,6 +126,7 @@ const struct dhcp_opt dhcp6_opts[] = {
|
||||
{ D6_OPTION_BCMS_SERVER_A, IPV6A, "bcms_server_a" },
|
||||
{ D6_OPTION_POSIX_TIMEZONE, STRING, "posix_timezone" },
|
||||
{ D6_OPTION_TZDB_TIMEZONE, STRING, "tzdb_timezone" },
|
||||
{ D6_OPTION_FQDN, RFC3397, "fqdn" },
|
||||
{ 0, 0, NULL }
|
||||
};
|
||||
|
||||
@ -361,6 +362,7 @@ dhcp6_makemessage(struct interface *ifp)
|
||||
uint8_t IA, *p;
|
||||
uint32_t u32;
|
||||
const struct ipv6_addr *ap;
|
||||
const char *hostname;
|
||||
|
||||
state = D6_STATE(ifp);
|
||||
if (state->send) {
|
||||
@ -379,8 +381,16 @@ dhcp6_makemessage(struct interface *ifp)
|
||||
len += sizeof(*u16);
|
||||
}
|
||||
if (len == 0)
|
||||
len = sizeof(*u16) * 3;
|
||||
len = sizeof(*u16) * 4;
|
||||
len += sizeof(*o);
|
||||
|
||||
if (ifo->fqdn != FQDN_DISABLE) {
|
||||
if (ifo->hostname[0] == '\0')
|
||||
hostname = get_hostname();
|
||||
else
|
||||
hostname = ifo->hostname;
|
||||
len += sizeof(*o) + 1 + encode_rfc1035(hostname, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
len += sizeof(*state->send);
|
||||
@ -568,6 +578,26 @@ dhcp6_makemessage(struct interface *ifp)
|
||||
}
|
||||
|
||||
if (state->send->type != DHCP6_RELEASE) {
|
||||
if (ifo->fqdn != FQDN_DISABLE) {
|
||||
o = D6_NEXT_OPTION(o);
|
||||
o->code = htons(D6_OPTION_FQDN);
|
||||
p = D6_OPTION_DATA(o);
|
||||
switch (ifo->fqdn) {
|
||||
case FQDN_BOTH:
|
||||
*p = 0x01;
|
||||
break;
|
||||
case FQDN_PTR:
|
||||
*p = 0x00;
|
||||
break;
|
||||
default:
|
||||
*p = 0x04;
|
||||
break;
|
||||
}
|
||||
o->len = encode_rfc1035(hostname, p + 1);
|
||||
if (o->len == 0)
|
||||
*p = 0x04;
|
||||
o->len = htons(++o->len);
|
||||
}
|
||||
o = D6_NEXT_OPTION(o);
|
||||
o->code = htons(D6_OPTION_ORO);
|
||||
o->len = 0;
|
||||
@ -581,10 +611,11 @@ dhcp6_makemessage(struct interface *ifp)
|
||||
}
|
||||
}
|
||||
if (o->len == 0) {
|
||||
*u16++ = htons(D6_OPTION_UNICAST);
|
||||
*u16++ = htons(D6_OPTION_DNS_SERVERS);
|
||||
*u16++ = htons(D6_OPTION_DOMAIN_LIST);
|
||||
*u16++ = htons(D6_OPTION_UNICAST);
|
||||
o->len = sizeof(*u16) * 3;
|
||||
*u16++ = htons(D6_OPTION_FQDN);
|
||||
o->len = sizeof(*u16) * 4;
|
||||
}
|
||||
o->len = htons(o->len);
|
||||
}
|
||||
|
1
dhcp6.h
1
dhcp6.h
@ -79,6 +79,7 @@
|
||||
#define D6_OPTION_INFO_REFRESH_TIME 32
|
||||
#define D6_OPTION_BCMS_SERVER_D 33
|
||||
#define D6_OPTION_BCMS_SERVER_A 34
|
||||
#define D6_OPTION_FQDN 39
|
||||
#define D6_OPTION_POSIX_TIMEZONE 41
|
||||
#define D6_OPTION_TZDB_TIMEZONE 42
|
||||
|
||||
|
@ -65,15 +65,27 @@ try_hostname()
|
||||
|
||||
set_hostname()
|
||||
{
|
||||
if need_hostname; then
|
||||
if [ -n "$new_host_name" ]; then
|
||||
|
||||
need_hostname || return
|
||||
|
||||
if [ -n "$new_fqdn_name" ]; then
|
||||
try_hostname "$new_fqdn_name"
|
||||
elif [ -n "$new_host_name" ]; then
|
||||
if [ -n "$new_domain_name" ]; then
|
||||
try_hostname "$new_host_name.$new_domain_name"
|
||||
else
|
||||
try_hostname "$new_host_name"
|
||||
elif [ -n "$new_fqdn_name" ]; then
|
||||
try_hostname "$new_fqdn_name"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# For ease of use, map DHCP6 names onto our DHCP4 names
|
||||
case "$reason" in
|
||||
BOUND6|RENEW6|REBIND6|REBOOT6|INFORM6)
|
||||
new_fqdn_name="$new_dhcp6_fqdn"
|
||||
;;
|
||||
esac
|
||||
|
||||
if $if_up; then
|
||||
set_hostname
|
||||
fi
|
||||
|
@ -22,7 +22,7 @@
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd May 3, 2013
|
||||
.Dd June 5, 2013
|
||||
.Dt DHCPCD 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -604,8 +604,8 @@ running on the
|
||||
.Xr resolvconf 8
|
||||
.Sh STANDARDS
|
||||
RFC 951, RFC 1534, RFC 2131, RFC 2132, RFC 2855, RFC 3004, RFC 3315,RFC 3361,
|
||||
RFC 3633, RFC 3396, RFC 3397, RFC 3442, RFC 3927, RFC 4361, RFC 4390, RFC 4702,
|
||||
RFC 4861, RFC 4833, RFC 5227, RFC 5969, RFC 6106.
|
||||
RFC 3633, RFC 3396, RFC 3397, RFC 3442, RFC 3927, RFC 4361, RFC 4390, RFC 4702,
|
||||
RFC 4704, RFC 4861, RFC 4833, RFC 5227, RFC 5969, RFC 6106.
|
||||
.Sh AUTHORS
|
||||
.An Roy Marples Aq roy@marples.name
|
||||
.Sh BUGS
|
||||
|
@ -180,9 +180,11 @@ IPv6RS should be disabled globally when requesting a Prefix Delegation like so:
|
||||
Only configure IPv4.
|
||||
.It Ic ipv6only
|
||||
Only confgiure IPv6.
|
||||
.It Ic fqdn Op none | ptr | both
|
||||
none disables FQDN encoding, ptr just asks the DHCP server to update the PTR
|
||||
.It Ic fqdn Op disable | ptr | both
|
||||
ptr just asks the DHCP server to update the PTR
|
||||
record of the host in DNS whereas both also updates the A record.
|
||||
disable will disable the FQDN option.
|
||||
The default is both.
|
||||
.Nm dhcpcd
|
||||
itself never does any DNS updates.
|
||||
.Nm dhcpcd
|
||||
|
32
if-options.c
32
if-options.c
@ -459,20 +459,20 @@ parse_option(struct if_options *ifo, int opt, const char *arg)
|
||||
add_environ(ifo, arg, 1);
|
||||
break;
|
||||
case 'h':
|
||||
if (arg) {
|
||||
s = parse_string(ifo->hostname,
|
||||
HOSTNAME_MAX_LEN, arg);
|
||||
if (s == -1) {
|
||||
syslog(LOG_ERR, "hostname: %m");
|
||||
return -1;
|
||||
}
|
||||
if (s != 0 && ifo->hostname[0] == '.') {
|
||||
syslog(LOG_ERR,
|
||||
"hostname cannot begin with .");
|
||||
return -1;
|
||||
}
|
||||
ifo->hostname[s] = '\0';
|
||||
if (!arg) {
|
||||
ifo->options |= DHCPCD_HOSTNAME;
|
||||
break;
|
||||
}
|
||||
s = parse_string(ifo->hostname, HOSTNAME_MAX_LEN, arg);
|
||||
if (s == -1) {
|
||||
syslog(LOG_ERR, "hostname: %m");
|
||||
return -1;
|
||||
}
|
||||
if (s != 0 && ifo->hostname[0] == '.') {
|
||||
syslog(LOG_ERR, "hostname cannot begin with .");
|
||||
return -1;
|
||||
}
|
||||
ifo->hostname[s] = '\0';
|
||||
if (ifo->hostname[0] == '\0')
|
||||
ifo->options &= ~DHCPCD_HOSTNAME;
|
||||
else
|
||||
@ -1131,12 +1131,6 @@ read_config(const char *file,
|
||||
ifo->reboot = DEFAULT_REBOOT;
|
||||
ifo->metric = -1;
|
||||
strlcpy(ifo->script, SCRIPT, sizeof(ifo->script));
|
||||
gethostname(ifo->hostname, HOSTNAME_MAX_LEN);
|
||||
/* Ensure that the hostname is NULL terminated */
|
||||
ifo->hostname[HOSTNAME_MAX_LEN] = '\0';
|
||||
if (strcmp(ifo->hostname, "(none)") == 0 ||
|
||||
strcmp(ifo->hostname, "localhost") == 0)
|
||||
ifo->hostname[0] = '\0';
|
||||
|
||||
ifo->vendorclassid[0] = strlen(vendor);
|
||||
memcpy(ifo->vendorclassid + 1, vendor, ifo->vendorclassid[0]);
|
||||
|
@ -45,7 +45,9 @@
|
||||
#define DEFAULT_TIMEOUT 30
|
||||
#define DEFAULT_REBOOT 5
|
||||
|
||||
#ifndef HOSTNAME_MAX_LEN
|
||||
#define HOSTNAME_MAX_LEN 250 /* 255 - 3 (FQDN) - 2 (DNS enc) */
|
||||
#endif
|
||||
#define VENDORCLASSID_MAX_LEN 255
|
||||
#define CLIENTID_MAX_LEN 48
|
||||
#define USERCLASS_MAX_LEN 255
|
||||
|
Loading…
Reference in New Issue
Block a user