diff --git a/CHANGELOG b/CHANGELOG index 532d529..f4d7a8b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -40,6 +40,11 @@ version 2.60 Fix shell-scripting bug in bld/pkg-wrapper. Thanks to Mark Mitchell for the patch. + Allow the TFP server or boot server in --pxe-service, to + be a domain name instead of an IP address. This allows for + round-robin to multiple servers, in the same way as + --dhcp-boot. A good suggestion from Cristiano Cumer. + version 2.59 Fix regression in 2.58 which caused failure to start up diff --git a/man/dnsmasq.8 b/man/dnsmasq.8 index 7dc7842..474b9f6 100644 --- a/man/dnsmasq.8 +++ b/man/dnsmasq.8 @@ -888,7 +888,7 @@ address, and setting this flag enables this mode. Note that in the sequential mode, clients which allow a lease to expire are much more likely to move IP address; for this reason it should not be generally used. .TP -.B --pxe-service=[tag:,],[,|][,] +.B --pxe-service=[tag:,],[,|][,|] Most uses of PXE boot-ROMS simply allow the PXE system to obtain an IP address and then download the file specified by .B dhcp-boot @@ -904,17 +904,19 @@ parameter after the menu text may be a file name, in which case dnsmasq acts as boot server and directs the PXE client to download the file by TFTP, either from itself ( .B enable-tftp -must be set for this to work) or another TFTP server if the final IP -address is given. +must be set for this to work) or another TFTP server if the final server +address/name is given. Note that the "layer" suffix (normally ".0") is supplied by PXE, and should not be added to the basename. If an integer boot service type, rather than a basename is given, then the PXE client will search for a suitable boot service for that type on the network. This search may be done -by broadcast, or direct to a server if its IP address is provided. +by broadcast, or direct to a server if its IP address/name is provided. If no boot service type or filename is provided (or a boot service type of 0 is specified) then the menu entry will abort the net boot procedure and -continue booting from local media. +continue booting from local media. The server address can be given as a domain +name which is looked up in /etc/hosts. This name can be associated in +/etc/hosts with multiple IP addresses, which are used round-robin. .TP .B --pxe-prompt=[tag:,][,] Setting this provides a prompt to be displayed after PXE boot. If the diff --git a/src/dnsmasq.h b/src/dnsmasq.h index bd18296..ec71e93 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -547,7 +547,7 @@ struct dhcp_boot { struct pxe_service { unsigned short CSA, type; - char *menu, *basename; + char *menu, *basename, *sname; struct in_addr server; struct dhcp_netid *netid; struct pxe_service *next; diff --git a/src/option.c b/src/option.c index b0ae1e8..5ac8d3c 100644 --- a/src/option.c +++ b/src/option.c @@ -2384,6 +2384,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line) static int boottype = 32768; new->netid = NULL; + new->sname = NULL; new->server.s_addr = 0; while (is_tag_prefix(arg)) @@ -2430,10 +2431,17 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line) new->basename = opt_string_alloc(arg); } - if (comma && (new->server.s_addr = inet_addr(comma)) == (in_addr_t)-1) - option = '?'; + if (comma) + { + if (!inet_pton(AF_INET, comma, &new->server)) + { + new->server.s_addr = 0; + new->sname = opt_string_alloc(comma); + } + + } } - + /* Order matters */ new->next = NULL; if (!daemon->pxe_services) diff --git a/src/rfc2131.c b/src/rfc2131.c index 0e075f9..673ca36 100644 --- a/src/rfc2131.c +++ b/src/rfc2131.c @@ -63,7 +63,7 @@ static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt); static int do_encap_opts(struct dhcp_opt *opts, int encap, int flag, struct dhcp_packet *mess, unsigned char *end, int null_term); static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid); static int prune_vendor_opts(struct dhcp_netid *netid); -static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local); +static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local, time_t now); struct dhcp_boot *find_boot(struct dhcp_netid *netid); @@ -799,7 +799,9 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index, mess->yiaddr = mess->ciaddr; mess->ciaddr.s_addr = 0; - if (service->server.s_addr != 0) + if (service->sname) + mess->siaddr = a_record_from_hosts(service->sname, now); + else if (service->server.s_addr != 0) mess->siaddr = service->server; else mess->siaddr = context->local; @@ -868,7 +870,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index, option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr)); pxe_misc(mess, end, uuid); prune_vendor_opts(tagif_netid); - do_encap_opts(pxe_opts(pxearch, tagif_netid, context->local), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0); + do_encap_opts(pxe_opts(pxearch, tagif_netid, context->local, now), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0); log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", mess->xid); log_tags(tagif_netid, mess); @@ -2048,7 +2050,7 @@ static int prune_vendor_opts(struct dhcp_netid *netid) return force; } -static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local) +static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local, time_t now) { #define NUM_OPTS 4 @@ -2105,8 +2107,9 @@ static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct return daemon->dhcp_opts; } - boot_server = service->basename ? local : service->server; - + boot_server = service->basename ? local : + (service->sname ? a_record_from_hosts(service->sname, now) : service->server); + if (boot_server.s_addr != 0) { if (q - (unsigned char *)daemon->dhcp_buff3 + 3 + INADDRSZ >= 253) @@ -2579,7 +2582,7 @@ static void do_options(struct dhcp_context *context, if (context && pxe_arch != -1) { pxe_misc(mess, end, uuid); - config_opts = pxe_opts(pxe_arch, tagif, context->local); + config_opts = pxe_opts(pxe_arch, tagif, context->local, now); } if ((force_encap || in_list(req_options, OPTION_VENDOR_CLASS_OPT)) &&