diff -Nru dnsmasq-2.75/bld/Android.mk dnsmasq-2.76/bld/Android.mk --- dnsmasq-2.75/bld/Android.mk 2015-07-30 20:00:40.000000000 +0000 +++ dnsmasq-2.76/bld/Android.mk 2016-05-18 14:58:28.000000000 +0000 @@ -10,7 +10,7 @@ dhcp6.c rfc3315.c dhcp-common.c outpacket.c \ radv.c slaac.c auth.c ipset.c domain.c \ dnssec.c dnssec-openssl.c blockdata.c tables.c \ - loop.c inotify.c poll.c + loop.c inotify.c poll.c rrfilter.c edns0.c arp.c LOCAL_MODULE := dnsmasq diff -Nru dnsmasq-2.75/CHANGELOG dnsmasq-2.76/CHANGELOG --- dnsmasq-2.75/CHANGELOG 2015-07-30 20:00:40.000000000 +0000 +++ dnsmasq-2.76/CHANGELOG 2016-05-18 14:58:28.000000000 +0000 @@ -1,3 +1,123 @@ +version 2.76 + Include 0.0.0.0/8 in DNS rebind checks. This range + translates to hosts on the local network, or, at + least, 0.0.0.0 accesses the local host, so could + be targets for DNS rebinding. See RFC 5735 section 3 + for details. Thanks to Stephen Röttger for the bug report. + + Enhance --add-subnet to allow arbitrary subnet addresses. + Thanks to Ed Barsley for the patch. + + Respect the --no-resolv flag in inotify code. Fixes bug + which caused dnsmasq to fail to start if a resolv-file + was a dangling symbolic link, even of --no-resolv set. + Thanks to Alexander Kurtz for spotting the problem. + + Fix crash when an A or AAAA record is defined locally, + in a hosts file, and an upstream server sends a reply + that the same name is empty. Thanks to Edwin Török for + the patch. + + Fix failure to correctly calculate cache-size when + reading a hosts-file fails. Thanks to André Glüpker + for the patch. + + Fix wrong answer to simple name query when --domain-needed + set, but no upstream servers configured. Dnsmasq returned + REFUSED, in this case, when it should be the same as when + upstream servers are configured - NOERROR. Thanks to + Allain Legacy for spotting the problem. + + Return REFUSED when running out of forwarding table slots, + not SERVFAIL. + + Add --max-port configuration. Thanks to Hans Dedecker for + the patch. + + Add --script-arp and two new functions for the dhcp-script. + These are "arp" and "arp-old" which announce the arrival and + removal of entries in the ARP or nieghbour tables. + + Extend --add-mac to allow a new encoding of the MAC address + as base64, by configurting --add-mac=base64 + + Add --add-cpe-id option. + + Don't crash with divide-by-zero if an IPv6 dhcp-range + is declared as a whole /64. + (ie xx::0 to xx::ffff:ffff:ffff:ffff) + Thanks to Laurent Bendel for spotting this problem. + + Add support for a TTL parameter in --host-record and + --cname. + + Add --dhcp-ttl option. + + Add --tftp-mtu option. Thanks to Patrick McLean for the + initial patch. + + Check return-code of inet_pton() when parsing dhcp-option. + Bad addresses could fail to generate errors and result in + garbage dhcp-options being sent. Thanks to Marc Branchaud + for spotting this. + + Fix wrong value for EDNS UDP packet size when using + --servers-file to define upstream DNS servers. Thanks to + Scott Bonar for the bug report. + + Move the dhcp_release and dhcp_lease_time tools from + contrib/wrt to contrib/lease-tools. + + Add dhcp_release6 to contrib/lease-tools. Many thanks + to Sergey Nechaev for this code. + + To avoid filling logs in configurations which define + many upstream nameservers, don't log more that 30 servers. + The number to be logged can be changed as SERVERS_LOGGED + in src/config.h. + + Swap the values if BC_EFI and x86-64_EFI in --pxe-service. + These were previously wrong due to an error in RFC 4578. + If you're using BC_EFI to boot 64-bit EFI machines, you + will need to update your config. + + Add ARM32_EFI and ARM64_EFI as valid architectures in + --pxe-service. + + Fix PXE booting for UEFI architectures. Modify PXE boot + sequence in this case to force the client to talk to dnsmasq + over port 4011. This makes PXE and especially proxy-DHCP PXE + work with these archictectures. + + Workaround problems with UEFI PXE clients. There exist + in the wild PXE clients which have problems with PXE + boot menus. To work around this, when there's a single + --pxe-service which applies to client, then that target + will be booted directly, rather then sending a + single-item boot menu. + + Many thanks to Jarek Polok, Michael Kuron and Dreamcat4 + for their work on the long-standing UEFI PXE problem. + + Subtle change in the semantics of "basename" in + --pxe-service. The historical behaviour has always been + that the actual filename downloaded from the TFTP server + is . where is an integer which + corresponds to the layer parameter supplied by the client. + It's not clear what the function of the "layer" + actually is in the PXE protocol, and in practise layer + is always zero, so the filename is .0 + The new behaviour is the same as the old, except when + includes a file suffix, in which case + the layer suffix is no longer added. This allows + sensible suffices to be used, rather then the + meaningless ".0". Only in the unlikely event that you + have a config with a basename which already has a + suffix, is this an incompatible change, since the file + downloaded will change from name.suffix.0 to just + name.suffix + + version 2.75 Fix reversion on 2.74 which caused 100% CPU use when a dhcp-script is configured. Thanks to Adrian Davey for diff -Nru dnsmasq-2.75/contrib/lease-tools/dhcp_lease_time.1 dnsmasq-2.76/contrib/lease-tools/dhcp_lease_time.1 --- dnsmasq-2.75/contrib/lease-tools/dhcp_lease_time.1 1970-01-01 00:00:00.000000000 +0000 +++ dnsmasq-2.76/contrib/lease-tools/dhcp_lease_time.1 2016-05-18 14:58:28.000000000 +0000 @@ -0,0 +1,25 @@ +.TH DHCP_LEASE_TIME 1 +.SH NAME +dhcp_lease_time \- Query remaining time of a lease on a the local dnsmasq DHCP server. +.SH SYNOPSIS +.B dhcp_lease_time
+.SH "DESCRIPTION" +Send a DHCPINFORM message to a dnsmasq server running on the local host +and print (to stdout) the time remaining in any lease for the given +address. The time is given as string printed to stdout. + +If an error occurs or no lease exists for the given address, +nothing is sent to stdout a message is sent to stderr and a +non-zero error code is returned. + +Requires dnsmasq 2.67 or later and may not work with other DHCP servers. + +The address argument is a dotted-quad IP addresses and mandatory. +.SH LIMITATIONS +Only works with IPv4 addresses and DHCP leases. +.SH SEE ALSO +.BR dnsmasq (8) +.SH AUTHOR +This manual page was written by Simon Kelley . + + diff -Nru dnsmasq-2.75/contrib/lease-tools/dhcp_lease_time.c dnsmasq-2.76/contrib/lease-tools/dhcp_lease_time.c --- dnsmasq-2.75/contrib/lease-tools/dhcp_lease_time.c 1970-01-01 00:00:00.000000000 +0000 +++ dnsmasq-2.76/contrib/lease-tools/dhcp_lease_time.c 2016-05-18 14:58:28.000000000 +0000 @@ -0,0 +1,221 @@ +/* Copyright (c) 2007 Simon Kelley + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 dated June, 1991. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +*/ + +/* dhcp_lease_time
*/ + +/* Send a DHCPINFORM message to a dnsmasq server running on the local host + and print (to stdout) the time remaining in any lease for the given + address. The time is given as string printed to stdout. + + If an error occurs or no lease exists for the given address, + nothing is sent to stdout a message is sent to stderr and a + non-zero error code is returned. + + This version requires dnsmasq 2.67 or later. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DHCP_CHADDR_MAX 16 +#define BOOTREQUEST 1 +#define DHCP_COOKIE 0x63825363 +#define OPTION_PAD 0 +#define OPTION_LEASE_TIME 51 +#define OPTION_OVERLOAD 52 +#define OPTION_MESSAGE_TYPE 53 +#define OPTION_REQUESTED_OPTIONS 55 +#define OPTION_END 255 +#define DHCPINFORM 8 +#define DHCP_SERVER_PORT 67 + +#define option_len(opt) ((int)(((unsigned char *)(opt))[1])) +#define option_ptr(opt) ((void *)&(((unsigned char *)(opt))[2])) + + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; + +struct dhcp_packet { + u8 op, htype, hlen, hops; + u32 xid; + u16 secs, flags; + struct in_addr ciaddr, yiaddr, siaddr, giaddr; + u8 chaddr[DHCP_CHADDR_MAX], sname[64], file[128]; + u32 cookie; + unsigned char options[308]; +}; + +static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize) +{ + while (*p != OPTION_END) + { + if (p >= end) + return NULL; /* malformed packet */ + else if (*p == OPTION_PAD) + p++; + else + { + int opt_len; + if (p >= end - 2) + return NULL; /* malformed packet */ + opt_len = option_len(p); + if (p >= end - (2 + opt_len)) + return NULL; /* malformed packet */ + if (*p == opt && opt_len >= minsize) + return p; + p += opt_len + 2; + } + } + + return opt == OPTION_END ? p : NULL; +} + +static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize) +{ + unsigned char *ret, *overload; + + /* skip over DHCP cookie; */ + if ((ret = option_find1(&mess->options[0], ((unsigned char *)mess) + size, opt_type, minsize))) + return ret; + + /* look for overload option. */ + if (!(overload = option_find1(&mess->options[0], ((unsigned char *)mess) + size, OPTION_OVERLOAD, 1))) + return NULL; + + /* Can we look in filename area ? */ + if ((overload[2] & 1) && + (ret = option_find1(&mess->file[0], &mess->file[128], opt_type, minsize))) + return ret; + + /* finally try sname area */ + if ((overload[2] & 2) && + (ret = option_find1(&mess->sname[0], &mess->sname[64], opt_type, minsize))) + return ret; + + return NULL; +} + +static unsigned int option_uint(unsigned char *opt, int size) +{ + /* this worries about unaligned data and byte order */ + unsigned int ret = 0; + int i; + unsigned char *p = option_ptr(opt); + + for (i = 0; i < size; i++) + ret = (ret << 8) | *p++; + + return ret; +} + +int main(int argc, char **argv) +{ + struct in_addr lease; + struct dhcp_packet packet; + unsigned char *p = packet.options; + struct sockaddr_in dest; + int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + ssize_t rc; + + if (argc < 2) + { + fprintf(stderr, "usage: dhcp_lease_time
\n"); + exit(1); + } + + if (fd == -1) + { + perror("cannot create socket"); + exit(1); + } + + lease.s_addr = inet_addr(argv[1]); + + memset(&packet, 0, sizeof(packet)); + + packet.hlen = 0; + packet.htype = 0; + + packet.op = BOOTREQUEST; + packet.ciaddr = lease; + packet.cookie = htonl(DHCP_COOKIE); + + *(p++) = OPTION_MESSAGE_TYPE; + *(p++) = 1; + *(p++) = DHCPINFORM; + + /* Explicity request the lease time, it won't be sent otherwise: + this is a dnsmasq extension, not standard. */ + *(p++) = OPTION_REQUESTED_OPTIONS; + *(p++) = 1; + *(p++) = OPTION_LEASE_TIME; + + *(p++) = OPTION_END; + + dest.sin_family = AF_INET; + dest.sin_addr.s_addr = inet_addr("127.0.0.1"); + dest.sin_port = ntohs(DHCP_SERVER_PORT); + + if (sendto(fd, &packet, sizeof(packet), 0, + (struct sockaddr *)&dest, sizeof(dest)) == -1) + { + perror("sendto failed"); + exit(1); + } + + alarm(3); /* noddy timeout. */ + + rc = recv(fd, &packet, sizeof(packet), 0); + + if (rc < (ssize_t)(sizeof(packet) - sizeof(packet.options))) + { + perror("recv failed"); + exit(1); + } + + if ((p = option_find(&packet, (size_t)rc, OPTION_LEASE_TIME, 4))) + { + unsigned int t = option_uint(p, 4); + if (t == 0xffffffff) + printf("infinite"); + else + { + unsigned int x; + if ((x = t/86400)) + printf("%dd", x); + if ((x = (t/3600)%24)) + printf("%dh", x); + if ((x = (t/60)%60)) + printf("%dm", x); + if ((x = t%60)) + printf("%ds", x); + } + return 0; + } + + return 1; /* no lease */ +} diff -Nru dnsmasq-2.75/contrib/lease-tools/dhcp_release.1 dnsmasq-2.76/contrib/lease-tools/dhcp_release.1 --- dnsmasq-2.75/contrib/lease-tools/dhcp_release.1 1970-01-01 00:00:00.000000000 +0000 +++ dnsmasq-2.76/contrib/lease-tools/dhcp_release.1 2016-05-18 14:58:28.000000000 +0000 @@ -0,0 +1,37 @@ +.TH DHCP_RELEASE 1 +.SH NAME +dhcp_release \- Release a DHCP lease on a the local dnsmasq DHCP server. +.SH SYNOPSIS +.B dhcp_release
+.SH "DESCRIPTION" +A utility which forces the DHCP server running on this machine to release a +DHCP lease. +.PP +Send a DHCPRELEASE message via the specified interface to tell the +local DHCP server to delete a particular lease. + +The interface argument is the interface in which a DHCP +request _would_ be received if it was coming from the client, +rather than being faked up here. + +The address argument is a dotted-quad IP addresses and mandatory. + +The MAC address is colon separated hex, and is mandatory. It may be +prefixed by an address-type byte followed by -, eg + +10-11:22:33:44:55:66 + +but if the address-type byte is missing it is assumed to be 1, the type +for ethernet. This encoding is the one used in dnsmasq lease files. + +The client-id is optional. If it is "*" then it treated as being missing. +.SH NOTES +MUST be run as root - will fail otherwise. +.SH LIMITATIONS +Only usable on IPv4 DHCP leases. +.SH SEE ALSO +.BR dnsmasq (8) +.SH AUTHOR +This manual page was written by Simon Kelley . + + diff -Nru dnsmasq-2.75/contrib/lease-tools/dhcp_release6.1 dnsmasq-2.76/contrib/lease-tools/dhcp_release6.1 --- dnsmasq-2.75/contrib/lease-tools/dhcp_release6.1 1970-01-01 00:00:00.000000000 +0000 +++ dnsmasq-2.76/contrib/lease-tools/dhcp_release6.1 2016-05-18 14:58:28.000000000 +0000 @@ -0,0 +1,38 @@ +.TH DHCP_RELEASE 1 +.SH NAME +dhcp_release6 \- Release a DHCPv6 lease on a the local dnsmasq DHCP server. +.SH SYNOPSIS +.B dhcp_release6 --iface --client-id --server-id +server-id --iaid --ip [--dry-run] [--help] +.SH "DESCRIPTION" +A utility which forces the DHCP server running on this machine to release a +DHCPv6 lease. +.SS OPTIONS +.IP "-a, --ip" +IPv6 address to release. +.IP "-c, --client-id" +Colon-separated hex string representing DHCPv6 client id. Normally +it can be found in leases file both on client and server. +.IP "-d, --dry-run" +Print hexadecimal representation of generated DHCPv6 release packet to standard +output and exit. +.IP "-h, --help" +print usage information to standard output and exit. +.IP "-i, --iaid" +Decimal representation of DHCPv6 IAID. Normally it can be found in leases file +both on client and server. +.IP "-n, --iface" +Network interface to send a DHCPv6 release packet from. +.IP "-s, --server-id" +Colon-separated hex string representing DHCPv6 server id. Normally +it can be found in leases file both on client and server. +.SH NOTES +MUST be run as root - will fail otherwise. +.SH LIMITATIONS +Only usable on IPv6 DHCP leases. +.SH SEE ALSO +.BR dnsmasq (8) +.SH AUTHOR +This manual page was written by Simon Kelley . + + diff -Nru dnsmasq-2.75/contrib/lease-tools/dhcp_release6.c dnsmasq-2.76/contrib/lease-tools/dhcp_release6.c --- dnsmasq-2.75/contrib/lease-tools/dhcp_release6.c 1970-01-01 00:00:00.000000000 +0000 +++ dnsmasq-2.76/contrib/lease-tools/dhcp_release6.c 2016-05-18 14:58:28.000000000 +0000 @@ -0,0 +1,445 @@ +/* + dhcp_release6 --iface --client-id --server-id + server-id --iaid --ip [--dry-run] [--help] + MUST be run as root - will fail othewise + */ + +/* Send a DHCPRELEASE message to IPv6 multicast address via the specified interface + to tell the local DHCP server to delete a particular lease. + + The interface argument is the interface in which a DHCP + request _would_ be received if it was coming from the client, + rather than being faked up here. + + The client-id argument is colon-separated hex string and mandatory. Normally + it can be found in leases file both on client and server + + The server-id argument is colon-separated hex string and mandatory. Normally + it can be found in leases file both on client and server. + + The iaid argument is numeric string and mandatory. Normally + it can be found in leases file both on client and server. + + IP is an IPv6 adress to release + + If --dry-run is specified, dhcp_release6 just prints hexadecimal represantation of + packet to send to stdout and exits. + + If --help is specified, dhcp_release6 print usage information to stdout and exits + + + + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NOT_REPLY_CODE 115 +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; + +enum DHCP6_TYPES{ + SOLICIT = 1, + ADVERTISE = 2, + REQUEST = 3, + CONFIRM = 4, + RENEW = 5, + REBIND = 6, + REPLY = 7, + RELEASE = 8, + DECLINE = 9, + RECONFIGURE = 10, + INFORMATION_REQUEST = 11, + RELAY_FORW = 12, + RELAY_REPL = 13 + +}; +enum DHCP6_OPTIONS{ + CLIENTID = 1, + SERVERID = 2, + IA_NA = 3, + IA_TA = 4, + IAADDR = 5, + ORO = 6, + PREFERENCE = 7, + ELAPSED_TIME = 8, + RELAY_MSG = 9, + AUTH = 11, + UNICAST = 12, + STATUS_CODE = 13, + RAPID_COMMIT = 14, + USER_CLASS = 15, + VENDOR_CLASS = 16, + VENDOR_OPTS = 17, + INTERFACE_ID = 18, + RECONF_MSG = 19, + RECONF_ACCEPT = 20, +}; + +enum DHCP6_STATUSES{ + SUCCESS = 0, + UNSPEC_FAIL = 1, + NOADDR_AVAIL=2, + NO_BINDING = 3, + NOT_ON_LINK = 4, + USE_MULTICAST =5 +}; +static struct option longopts[] = { + {"ip", required_argument, 0, 'a'}, + {"server-id", required_argument, 0, 's'}, + {"client-id", required_argument, 0, 'c'}, + {"iface", required_argument, 0, 'n'}, + {"iaid", required_argument, 0, 'i'}, + {"dry-run", no_argument, 0, 'd'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0} +}; + +const short DHCP6_CLIENT_PORT = 546; +const short DHCP6_SERVER_PORT = 547; + +const char* DHCP6_MULTICAST_ADDRESS = "ff02::1:2"; + +struct dhcp6_option{ + uint16_t type; + uint16_t len; + char value[1024]; +}; + +struct dhcp6_iaaddr_option{ + uint16_t type; + uint16_t len; + struct in6_addr ip; + uint32_t preferred_lifetime; + uint32_t valid_lifetime; + + +}; + +struct dhcp6_iana_option{ + uint16_t type; + uint16_t len; + uint32_t iaid; + uint32_t t1; + uint32_t t2; + char options[1024]; +}; + + +struct dhcp6_packet{ + size_t len; + char buf[2048]; + +} ; + +size_t pack_duid(const char* str, char* dst){ + + char* tmp = strdup(str); + char* tmp_to_free = tmp; + char *ptr; + uint8_t write_pos = 0; + while ((ptr = strtok (tmp, ":"))) { + dst[write_pos] = (uint8_t) strtol(ptr, NULL, 16); + write_pos += 1; + tmp = NULL; + + } + free(tmp_to_free); + return write_pos; +} + +struct dhcp6_option create_client_id_option(const char* duid){ + struct dhcp6_option option; + option.type = htons(CLIENTID); + bzero(option.value, sizeof(option.value)); + option.len = htons(pack_duid(duid, option.value)); + return option; +} + +struct dhcp6_option create_server_id_option(const char* duid){ + struct dhcp6_option option; + option.type = htons(SERVERID); + bzero(option.value, sizeof(option.value)); + option.len = htons(pack_duid(duid, option.value)); + return option; +} + +struct dhcp6_iaaddr_option create_iaadr_option(const char* ip){ + struct dhcp6_iaaddr_option result; + result.type =htons(IAADDR); + /* no suboptions needed here, so length is 24 */ + result.len = htons(24); + result.preferred_lifetime = 0; + result.valid_lifetime = 0; + int s = inet_pton(AF_INET6, ip, &(result.ip)); + if (s <= 0) { + if (s == 0) + fprintf(stderr, "Not in presentation format"); + else + perror("inet_pton"); + exit(EXIT_FAILURE); + } + return result; +} +struct dhcp6_iana_option create_iana_option(const char * iaid, struct dhcp6_iaaddr_option ia_addr){ + struct dhcp6_iana_option result; + result.type = htons(IA_NA); + result.iaid = htonl(atoi(iaid)); + result.t1 = 0; + result.t2 = 0; + result.len = htons(12 + ntohs(ia_addr.len) + 2 * sizeof(uint16_t)); + memcpy(result.options, &ia_addr, ntohs(ia_addr.len) + 2 * sizeof(uint16_t)); + return result; +} + +struct dhcp6_packet create_release_packet(const char* iaid, const char* ip, const char* client_id, const char* server_id){ + struct dhcp6_packet result; + bzero(result.buf, sizeof(result.buf)); + /* message_type */ + result.buf[0] = RELEASE; + /* tx_id */ + bzero(result.buf+1, 3); + + struct dhcp6_option client_option = create_client_id_option(client_id); + struct dhcp6_option server_option = create_server_id_option(server_id); + struct dhcp6_iaaddr_option iaaddr_option = create_iaadr_option(ip); + struct dhcp6_iana_option iana_option = create_iana_option(iaid, iaaddr_option); + int offset = 4; + memcpy(result.buf + offset, &client_option, ntohs(client_option.len) + 2*sizeof(uint16_t)); + offset += (ntohs(client_option.len)+ 2 *sizeof(uint16_t) ); + memcpy(result.buf + offset, &server_option, ntohs(server_option.len) + 2*sizeof(uint16_t) ); + offset += (ntohs(server_option.len)+ 2* sizeof(uint16_t)); + memcpy(result.buf + offset, &iana_option, ntohs(iana_option.len) + 2*sizeof(uint16_t) ); + offset += (ntohs(iana_option.len)+ 2* sizeof(uint16_t)); + result.len = offset; + return result; +} + +uint16_t parse_iana_suboption(char* buf, size_t len){ + size_t current_pos = 0; + char option_value[1024]; + while (current_pos < len) { + uint16_t option_type, option_len; + memcpy(&option_type,buf + current_pos, sizeof(uint16_t)); + memcpy(&option_len,buf + current_pos + sizeof(uint16_t), sizeof(uint16_t)); + option_type = ntohs(option_type); + option_len = ntohs(option_len); + current_pos += 2 * sizeof(uint16_t); + if (option_type == STATUS_CODE){ + uint16_t status; + memcpy(&status, buf + current_pos, sizeof(uint16_t)); + status = ntohs(status); + if (status != SUCCESS){ + memcpy(option_value, buf + current_pos + sizeof(uint16_t) , option_len - sizeof(uint16_t)); + option_value[option_len-sizeof(uint16_t)] ='\0'; + fprintf(stderr, "Error: %s\n", option_value); + } + return status; + } + } + return -2; +} + +int16_t parse_packet(char* buf, size_t len){ + uint8_t type = buf[0]; + /*skipping tx id. you need it, uncomment following line + uint16_t tx_id = ntohs((buf[1] <<16) + (buf[2] <<8) + buf[3]); + */ + size_t current_pos = 4; + if (type != REPLY ){ + return NOT_REPLY_CODE; + } + char option_value[1024]; + while (current_pos < len) { + uint16_t option_type, option_len; + memcpy(&option_type,buf + current_pos, sizeof(uint16_t)); + memcpy(&option_len,buf + current_pos + sizeof(uint16_t), sizeof(uint16_t)); + option_type = ntohs(option_type); + option_len = ntohs(option_len); + current_pos += 2 * sizeof(uint16_t); + if (option_type == STATUS_CODE){ + uint16_t status; + memcpy(&status, buf + current_pos, sizeof(uint16_t)); + status = ntohs(status); + if (status != SUCCESS){ + memcpy(option_value, buf + current_pos +sizeof(uint16_t) , option_len -sizeof(uint16_t)); + fprintf(stderr, "Error: %d %s\n", status, option_value); + return status; + } + + } + if (option_type == IA_NA ){ + uint16_t result = parse_iana_suboption(buf + current_pos +24, option_len -24); + if (result){ + return result; + } + } + current_pos += option_len; + + } + return -1; +} + +void usage(const char* arg, FILE* stream){ + const char* usage_string ="--ip IPv6 --iface IFACE --server-id SERVER_ID --client-id CLIENT_ID --iaid IAID [--dry-run] | --help"; + fprintf (stream, "Usage: %s %s\n", arg, usage_string); + +} + +int send_release_packet(const char* iface, struct dhcp6_packet* packet){ + + struct sockaddr_in6 server_addr, client_addr; + char response[1400]; + int sock = socket(PF_INET6, SOCK_DGRAM, 0); + int i = 0; + if (sock < 0) { + perror("creating socket"); + return -1; + } + if (setsockopt(sock, SOL_SOCKET, 25, iface, strlen(iface)) == -1) { + perror("SO_BINDTODEVICE"); + close(sock); + return -1; + } + memset(&server_addr, 0, sizeof(server_addr)); + server_addr.sin6_family = AF_INET6; + client_addr.sin6_family = AF_INET6; + client_addr.sin6_port = htons(DHCP6_CLIENT_PORT); + client_addr.sin6_flowinfo = 0; + client_addr.sin6_scope_id =0; + inet_pton(AF_INET6, "::", &client_addr.sin6_addr); + bind(sock, (struct sockaddr*)&client_addr, sizeof(struct sockaddr_in6)); + inet_pton(AF_INET6, DHCP6_MULTICAST_ADDRESS, &server_addr.sin6_addr); + server_addr.sin6_port = htons(DHCP6_SERVER_PORT); + int16_t recv_size = 0; + for (i = 0; i < 5; i++) { + if (sendto(sock, packet->buf, packet->len, 0, + (struct sockaddr *)&server_addr, + sizeof(server_addr)) < 0) { + perror("sendto failed"); + exit(4); + } + recv_size = recvfrom(sock, response, sizeof(response), MSG_DONTWAIT, NULL, 0); + if (recv_size == -1){ + if (errno == EAGAIN){ + sleep(1); + continue; + }else { + perror("recvfrom"); + } + } + int16_t result = parse_packet(response, recv_size); + if (result == NOT_REPLY_CODE){ + sleep(1); + continue; + } + return result; + } + fprintf(stderr, "Response timed out\n"); + return -1; + +} + + +int main(int argc, char * const argv[]) { + const char* UNINITIALIZED = ""; + const char* iface = UNINITIALIZED; + const char* ip = UNINITIALIZED; + const char* client_id = UNINITIALIZED; + const char* server_id = UNINITIALIZED; + const char* iaid = UNINITIALIZED; + int dry_run = 0; + while (1) { + int option_index = 0; + int c = getopt_long(argc, argv, "a:s:c:n:i:hd", longopts, &option_index); + if (c == -1){ + break; + } + switch(c){ + case 0: + if (longopts[option_index].flag !=0){ + break; + } + printf ("option %s", longopts[option_index].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\n"); + break; + case 'i': + iaid = optarg; + break; + case 'n': + iface = optarg; + break; + case 'a': + ip = optarg; + break; + case 'c': + client_id = optarg; + break; + case 'd': + dry_run = 1; + break; + case 's': + server_id = optarg; + break; + case 'h': + usage(argv[0], stdout); + return 0; + case '?': + usage(argv[0], stderr); + return -1; + default: + abort(); + + } + + } + if (iaid == UNINITIALIZED){ + fprintf(stderr, "Missing required iaid parameter\n"); + usage(argv[0], stderr); + return -1; + } + if (server_id == UNINITIALIZED){ + fprintf(stderr, "Missing required server-id parameter\n"); + usage(argv[0], stderr); + return -1; + } + if (client_id == UNINITIALIZED){ + fprintf(stderr, "Missing required client-id parameter\n"); + usage(argv[0], stderr); + return -1; + } + if (ip == UNINITIALIZED){ + fprintf(stderr, "Missing required ip parameter\n"); + usage(argv[0], stderr); + return -1; + } + if (iface == UNINITIALIZED){ + fprintf(stderr, "Missing required iface parameter\n"); + usage(argv[0], stderr); + return -1; + } + + + + struct dhcp6_packet packet = create_release_packet(iaid, ip, client_id, server_id); + if (dry_run){ + uint16_t i; + for(i=0;i
+ MUST be run as root - will fail otherwise. */ + +/* Send a DHCPRELEASE message via the specified interface + to tell the local DHCP server to delete a particular lease. + + The interface argument is the interface in which a DHCP + request _would_ be received if it was coming from the client, + rather than being faked up here. + + The address argument is a dotted-quad IP addresses and mandatory. + + The MAC address is colon separated hex, and is mandatory. It may be + prefixed by an address-type byte followed by -, eg + + 10-11:22:33:44:55:66 + + but if the address-type byte is missing it is assumed to be 1, the type + for ethernet. This encoding is the one used in dnsmasq lease files. + + The client-id is optional. If it is "*" then it treated as being missing. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DHCP_CHADDR_MAX 16 +#define BOOTREQUEST 1 +#define DHCP_COOKIE 0x63825363 +#define OPTION_SERVER_IDENTIFIER 54 +#define OPTION_CLIENT_ID 61 +#define OPTION_MESSAGE_TYPE 53 +#define OPTION_END 255 +#define DHCPRELEASE 7 +#define DHCP_SERVER_PORT 67 + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; + +struct dhcp_packet { + u8 op, htype, hlen, hops; + u32 xid; + u16 secs, flags; + struct in_addr ciaddr, yiaddr, siaddr, giaddr; + u8 chaddr[DHCP_CHADDR_MAX], sname[64], file[128]; + u32 cookie; + unsigned char options[308]; +}; + +static struct iovec iov; + +static int expand_buf(struct iovec *iov, size_t size) +{ + void *new; + + if (size <= iov->iov_len) + return 1; + + if (!(new = malloc(size))) + { + errno = ENOMEM; + return 0; + } + + if (iov->iov_base) + { + memcpy(new, iov->iov_base, iov->iov_len); + free(iov->iov_base); + } + + iov->iov_base = new; + iov->iov_len = size; + + return 1; +} + +static ssize_t netlink_recv(int fd) +{ + struct msghdr msg; + ssize_t rc; + + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + while (1) + { + msg.msg_flags = 0; + while ((rc = recvmsg(fd, &msg, MSG_PEEK)) == -1 && errno == EINTR); + + /* 2.2.x doesn't suport MSG_PEEK at all, returning EOPNOTSUPP, so we just grab a + big buffer and pray in that case. */ + if (rc == -1 && errno == EOPNOTSUPP) + { + if (!expand_buf(&iov, 2000)) + return -1; + break; + } + + if (rc == -1 || !(msg.msg_flags & MSG_TRUNC)) + break; + + if (!expand_buf(&iov, iov.iov_len + 100)) + return -1; + } + + /* finally, read it for real */ + while ((rc = recvmsg(fd, &msg, 0)) == -1 && errno == EINTR); + + return rc; +} + +static int parse_hex(char *in, unsigned char *out, int maxlen, int *mac_type) +{ + int i = 0; + char *r; + + if (mac_type) + *mac_type = 0; + + while (maxlen == -1 || i < maxlen) + { + for (r = in; *r != 0 && *r != ':' && *r != '-'; r++); + if (*r == 0) + maxlen = i; + + if (r != in ) + { + if (*r == '-' && i == 0 && mac_type) + { + *r = 0; + *mac_type = strtol(in, NULL, 16); + mac_type = NULL; + } + else + { + *r = 0; + out[i] = strtol(in, NULL, 16); + i++; + } + } + in = r+1; + } + return i; +} + +static int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask) +{ + return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr); +} + +static struct in_addr find_interface(struct in_addr client, int fd, unsigned int index) +{ + struct sockaddr_nl addr; + struct nlmsghdr *h; + ssize_t len; + + struct { + struct nlmsghdr nlh; + struct rtgenmsg g; + } req; + + addr.nl_family = AF_NETLINK; + addr.nl_pad = 0; + addr.nl_groups = 0; + addr.nl_pid = 0; /* address to kernel */ + + req.nlh.nlmsg_len = sizeof(req); + req.nlh.nlmsg_type = RTM_GETADDR; + req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST | NLM_F_ACK; + req.nlh.nlmsg_pid = 0; + req.nlh.nlmsg_seq = 1; + req.g.rtgen_family = AF_INET; + + if (sendto(fd, (void *)&req, sizeof(req), 0, + (struct sockaddr *)&addr, sizeof(addr)) == -1) + { + perror("sendto failed"); + exit(1); + } + + while (1) + { + if ((len = netlink_recv(fd)) == -1) + { + perror("netlink"); + exit(1); + } + + for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len)) + if (h->nlmsg_type == NLMSG_DONE) + exit(0); + else if (h->nlmsg_type == RTM_NEWADDR) + { + struct ifaddrmsg *ifa = NLMSG_DATA(h); + struct rtattr *rta; + unsigned int len1 = h->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)); + + if (ifa->ifa_index == index && ifa->ifa_family == AF_INET) + { + struct in_addr netmask, addr; + + netmask.s_addr = htonl(0xffffffff << (32 - ifa->ifa_prefixlen)); + addr.s_addr = 0; + + for (rta = IFA_RTA(ifa); RTA_OK(rta, len1); rta = RTA_NEXT(rta, len1)) + if (rta->rta_type == IFA_LOCAL) + addr = *((struct in_addr *)(rta+1)); + + if (addr.s_addr && is_same_net(addr, client, netmask)) + return addr; + } + } + } + + exit(0); +} + +int main(int argc, char **argv) +{ + struct in_addr server, lease; + int mac_type; + struct dhcp_packet packet; + unsigned char *p = packet.options; + struct sockaddr_in dest; + struct ifreq ifr; + int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + int nl = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + + if (argc < 4 || argc > 5) + { + fprintf(stderr, "usage: dhcp_release []\n"); + exit(1); + } + + if (fd == -1 || nl == -1) + { + perror("cannot create socket"); + exit(1); + } + + /* This voodoo fakes up a packet coming from the correct interface, which really matters for + a DHCP server */ + strcpy(ifr.ifr_name, argv[1]); + if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) == -1) + { + perror("cannot setup interface"); + exit(1); + } + + if (inet_addr(argv[2]) == INADDR_NONE) + { + perror("invalid ip address"); + exit(1); + } + + lease.s_addr = inet_addr(argv[2]); + server = find_interface(lease, nl, if_nametoindex(argv[1])); + + memset(&packet, 0, sizeof(packet)); + + packet.hlen = parse_hex(argv[3], packet.chaddr, DHCP_CHADDR_MAX, &mac_type); + if (mac_type == 0) + packet.htype = ARPHRD_ETHER; + else + packet.htype = mac_type; + + packet.op = BOOTREQUEST; + packet.ciaddr = lease; + packet.cookie = htonl(DHCP_COOKIE); + + *(p++) = OPTION_MESSAGE_TYPE; + *(p++) = 1; + *(p++) = DHCPRELEASE; + + *(p++) = OPTION_SERVER_IDENTIFIER; + *(p++) = sizeof(server); + memcpy(p, &server, sizeof(server)); + p += sizeof(server); + + if (argc == 5 && strcmp(argv[4], "*") != 0) + { + unsigned int clid_len = parse_hex(argv[4], p+2, 255, NULL); + *(p++) = OPTION_CLIENT_ID; + *(p++) = clid_len; + p += clid_len; + } + + *(p++) = OPTION_END; + + dest.sin_family = AF_INET; + dest.sin_port = ntohs(DHCP_SERVER_PORT); + dest.sin_addr = server; + + if (sendto(fd, &packet, sizeof(packet), 0, + (struct sockaddr *)&dest, sizeof(dest)) == -1) + { + perror("sendto failed"); + exit(1); + } + + return 0; +} diff -Nru dnsmasq-2.75/contrib/lease-tools/Makefile dnsmasq-2.76/contrib/lease-tools/Makefile --- dnsmasq-2.75/contrib/lease-tools/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ dnsmasq-2.76/contrib/lease-tools/Makefile 2016-05-18 14:58:28.000000000 +0000 @@ -0,0 +1,6 @@ +CFLAGS?= -O2 -Wall -W + +all: dhcp_release dhcp_release6 dhcp_lease_time + +clean: + rm -f *~ *.o core dhcp_release dhcp_release6 dhcp_lease_time diff -Nru dnsmasq-2.75/contrib/wrt/dhcp_lease_time.1 dnsmasq-2.76/contrib/wrt/dhcp_lease_time.1 --- dnsmasq-2.75/contrib/wrt/dhcp_lease_time.1 2015-07-30 20:00:40.000000000 +0000 +++ dnsmasq-2.76/contrib/wrt/dhcp_lease_time.1 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -.TH DHCP_LEASE_TIME 1 -.SH NAME -dhcp_lease_time \- Query remaining time of a lease on a the local dnsmasq DHCP server. -.SH SYNOPSIS -.B dhcp_lease_time
-.SH "DESCRIPTION" -Send a DHCPINFORM message to a dnsmasq server running on the local host -and print (to stdout) the time remaining in any lease for the given -address. The time is given as string printed to stdout. - -If an error occurs or no lease exists for the given address, -nothing is sent to stdout a message is sent to stderr and a -non-zero error code is returned. - -Requires dnsmasq 2.67 or later and may not work with other DHCP servers. - -The address argument is a dotted-quad IP addresses and mandatory. -.SH LIMITATIONS -Only works with IPv4 addresses and DHCP leases. -.SH SEE ALSO -.BR dnsmasq (8) -.SH AUTHOR -This manual page was written by Simon Kelley . - - diff -Nru dnsmasq-2.75/contrib/wrt/dhcp_lease_time.c dnsmasq-2.76/contrib/wrt/dhcp_lease_time.c --- dnsmasq-2.75/contrib/wrt/dhcp_lease_time.c 2015-07-30 20:00:40.000000000 +0000 +++ dnsmasq-2.76/contrib/wrt/dhcp_lease_time.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,221 +0,0 @@ -/* Copyright (c) 2007 Simon Kelley - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 dated June, 1991. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ - -/* dhcp_lease_time
*/ - -/* Send a DHCPINFORM message to a dnsmasq server running on the local host - and print (to stdout) the time remaining in any lease for the given - address. The time is given as string printed to stdout. - - If an error occurs or no lease exists for the given address, - nothing is sent to stdout a message is sent to stderr and a - non-zero error code is returned. - - This version requires dnsmasq 2.67 or later. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DHCP_CHADDR_MAX 16 -#define BOOTREQUEST 1 -#define DHCP_COOKIE 0x63825363 -#define OPTION_PAD 0 -#define OPTION_LEASE_TIME 51 -#define OPTION_OVERLOAD 52 -#define OPTION_MESSAGE_TYPE 53 -#define OPTION_REQUESTED_OPTIONS 55 -#define OPTION_END 255 -#define DHCPINFORM 8 -#define DHCP_SERVER_PORT 67 - -#define option_len(opt) ((int)(((unsigned char *)(opt))[1])) -#define option_ptr(opt) ((void *)&(((unsigned char *)(opt))[2])) - - -typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned int u32; - -struct dhcp_packet { - u8 op, htype, hlen, hops; - u32 xid; - u16 secs, flags; - struct in_addr ciaddr, yiaddr, siaddr, giaddr; - u8 chaddr[DHCP_CHADDR_MAX], sname[64], file[128]; - u32 cookie; - unsigned char options[308]; -}; - -static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize) -{ - while (*p != OPTION_END) - { - if (p >= end) - return NULL; /* malformed packet */ - else if (*p == OPTION_PAD) - p++; - else - { - int opt_len; - if (p >= end - 2) - return NULL; /* malformed packet */ - opt_len = option_len(p); - if (p >= end - (2 + opt_len)) - return NULL; /* malformed packet */ - if (*p == opt && opt_len >= minsize) - return p; - p += opt_len + 2; - } - } - - return opt == OPTION_END ? p : NULL; -} - -static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize) -{ - unsigned char *ret, *overload; - - /* skip over DHCP cookie; */ - if ((ret = option_find1(&mess->options[0], ((unsigned char *)mess) + size, opt_type, minsize))) - return ret; - - /* look for overload option. */ - if (!(overload = option_find1(&mess->options[0], ((unsigned char *)mess) + size, OPTION_OVERLOAD, 1))) - return NULL; - - /* Can we look in filename area ? */ - if ((overload[2] & 1) && - (ret = option_find1(&mess->file[0], &mess->file[128], opt_type, minsize))) - return ret; - - /* finally try sname area */ - if ((overload[2] & 2) && - (ret = option_find1(&mess->sname[0], &mess->sname[64], opt_type, minsize))) - return ret; - - return NULL; -} - -static unsigned int option_uint(unsigned char *opt, int size) -{ - /* this worries about unaligned data and byte order */ - unsigned int ret = 0; - int i; - unsigned char *p = option_ptr(opt); - - for (i = 0; i < size; i++) - ret = (ret << 8) | *p++; - - return ret; -} - -int main(int argc, char **argv) -{ - struct in_addr lease; - struct dhcp_packet packet; - unsigned char *p = packet.options; - struct sockaddr_in dest; - int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); - ssize_t rc; - - if (argc < 2) - { - fprintf(stderr, "usage: dhcp_lease_time
\n"); - exit(1); - } - - if (fd == -1) - { - perror("cannot create socket"); - exit(1); - } - - lease.s_addr = inet_addr(argv[1]); - - memset(&packet, 0, sizeof(packet)); - - packet.hlen = 0; - packet.htype = 0; - - packet.op = BOOTREQUEST; - packet.ciaddr = lease; - packet.cookie = htonl(DHCP_COOKIE); - - *(p++) = OPTION_MESSAGE_TYPE; - *(p++) = 1; - *(p++) = DHCPINFORM; - - /* Explicity request the lease time, it won't be sent otherwise: - this is a dnsmasq extension, not standard. */ - *(p++) = OPTION_REQUESTED_OPTIONS; - *(p++) = 1; - *(p++) = OPTION_LEASE_TIME; - - *(p++) = OPTION_END; - - dest.sin_family = AF_INET; - dest.sin_addr.s_addr = inet_addr("127.0.0.1"); - dest.sin_port = ntohs(DHCP_SERVER_PORT); - - if (sendto(fd, &packet, sizeof(packet), 0, - (struct sockaddr *)&dest, sizeof(dest)) == -1) - { - perror("sendto failed"); - exit(1); - } - - alarm(3); /* noddy timeout. */ - - rc = recv(fd, &packet, sizeof(packet), 0); - - if (rc < (ssize_t)(sizeof(packet) - sizeof(packet.options))) - { - perror("recv failed"); - exit(1); - } - - if ((p = option_find(&packet, (size_t)rc, OPTION_LEASE_TIME, 4))) - { - unsigned int t = option_uint(p, 4); - if (t == 0xffffffff) - printf("infinite"); - else - { - unsigned int x; - if ((x = t/86400)) - printf("%dd", x); - if ((x = (t/3600)%24)) - printf("%dh", x); - if ((x = (t/60)%60)) - printf("%dm", x); - if ((x = t%60)) - printf("%ds", x); - } - return 0; - } - - return 1; /* no lease */ -} diff -Nru dnsmasq-2.75/contrib/wrt/dhcp_release.1 dnsmasq-2.76/contrib/wrt/dhcp_release.1 --- dnsmasq-2.75/contrib/wrt/dhcp_release.1 2015-07-30 20:00:40.000000000 +0000 +++ dnsmasq-2.76/contrib/wrt/dhcp_release.1 1970-01-01 00:00:00.000000000 +0000 @@ -1,37 +0,0 @@ -.TH DHCP_RELEASE 1 -.SH NAME -dhcp_release \- Release a DHCP lease on a the local dnsmasq DHCP server. -.SH SYNOPSIS -.B dhcp_release
-.SH "DESCRIPTION" -A utility which forces the DHCP server running on this machine to release a -DHCP lease. -.PP -Send a DHCPRELEASE message via the specified interface to tell the -local DHCP server to delete a particular lease. - -The interface argument is the interface in which a DHCP -request _would_ be received if it was coming from the client, -rather than being faked up here. - -The address argument is a dotted-quad IP addresses and mandatory. - -The MAC address is colon separated hex, and is mandatory. It may be -prefixed by an address-type byte followed by -, eg - -10-11:22:33:44:55:66 - -but if the address-type byte is missing it is assumed to be 1, the type -for ethernet. This encoding is the one used in dnsmasq lease files. - -The client-id is optional. If it is "*" then it treated as being missing. -.SH NOTES -MUST be run as root - will fail otherwise. -.SH LIMITATIONS -Only usable on IPv4 DHCP leases. -.SH SEE ALSO -.BR dnsmasq (8) -.SH AUTHOR -This manual page was written by Simon Kelley . - - diff -Nru dnsmasq-2.75/contrib/wrt/dhcp_release.c dnsmasq-2.76/contrib/wrt/dhcp_release.c --- dnsmasq-2.75/contrib/wrt/dhcp_release.c 2015-07-30 20:00:40.000000000 +0000 +++ dnsmasq-2.76/contrib/wrt/dhcp_release.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,332 +0,0 @@ -/* Copyright (c) 2006 Simon Kelley - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 dated June, 1991. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ - -/* dhcp_release
- MUST be run as root - will fail otherwise. */ - -/* Send a DHCPRELEASE message via the specified interface - to tell the local DHCP server to delete a particular lease. - - The interface argument is the interface in which a DHCP - request _would_ be received if it was coming from the client, - rather than being faked up here. - - The address argument is a dotted-quad IP addresses and mandatory. - - The MAC address is colon separated hex, and is mandatory. It may be - prefixed by an address-type byte followed by -, eg - - 10-11:22:33:44:55:66 - - but if the address-type byte is missing it is assumed to be 1, the type - for ethernet. This encoding is the one used in dnsmasq lease files. - - The client-id is optional. If it is "*" then it treated as being missing. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DHCP_CHADDR_MAX 16 -#define BOOTREQUEST 1 -#define DHCP_COOKIE 0x63825363 -#define OPTION_SERVER_IDENTIFIER 54 -#define OPTION_CLIENT_ID 61 -#define OPTION_MESSAGE_TYPE 53 -#define OPTION_END 255 -#define DHCPRELEASE 7 -#define DHCP_SERVER_PORT 67 - -typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned int u32; - -struct dhcp_packet { - u8 op, htype, hlen, hops; - u32 xid; - u16 secs, flags; - struct in_addr ciaddr, yiaddr, siaddr, giaddr; - u8 chaddr[DHCP_CHADDR_MAX], sname[64], file[128]; - u32 cookie; - unsigned char options[308]; -}; - -static struct iovec iov; - -static int expand_buf(struct iovec *iov, size_t size) -{ - void *new; - - if (size <= iov->iov_len) - return 1; - - if (!(new = malloc(size))) - { - errno = ENOMEM; - return 0; - } - - if (iov->iov_base) - { - memcpy(new, iov->iov_base, iov->iov_len); - free(iov->iov_base); - } - - iov->iov_base = new; - iov->iov_len = size; - - return 1; -} - -static ssize_t netlink_recv(int fd) -{ - struct msghdr msg; - ssize_t rc; - - msg.msg_control = NULL; - msg.msg_controllen = 0; - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - - while (1) - { - msg.msg_flags = 0; - while ((rc = recvmsg(fd, &msg, MSG_PEEK)) == -1 && errno == EINTR); - - /* 2.2.x doesn't suport MSG_PEEK at all, returning EOPNOTSUPP, so we just grab a - big buffer and pray in that case. */ - if (rc == -1 && errno == EOPNOTSUPP) - { - if (!expand_buf(&iov, 2000)) - return -1; - break; - } - - if (rc == -1 || !(msg.msg_flags & MSG_TRUNC)) - break; - - if (!expand_buf(&iov, iov.iov_len + 100)) - return -1; - } - - /* finally, read it for real */ - while ((rc = recvmsg(fd, &msg, 0)) == -1 && errno == EINTR); - - return rc; -} - -static int parse_hex(char *in, unsigned char *out, int maxlen, int *mac_type) -{ - int i = 0; - char *r; - - if (mac_type) - *mac_type = 0; - - while (maxlen == -1 || i < maxlen) - { - for (r = in; *r != 0 && *r != ':' && *r != '-'; r++); - if (*r == 0) - maxlen = i; - - if (r != in ) - { - if (*r == '-' && i == 0 && mac_type) - { - *r = 0; - *mac_type = strtol(in, NULL, 16); - mac_type = NULL; - } - else - { - *r = 0; - out[i] = strtol(in, NULL, 16); - i++; - } - } - in = r+1; - } - return i; -} - -static int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask) -{ - return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr); -} - -static struct in_addr find_interface(struct in_addr client, int fd, unsigned int index) -{ - struct sockaddr_nl addr; - struct nlmsghdr *h; - ssize_t len; - - struct { - struct nlmsghdr nlh; - struct rtgenmsg g; - } req; - - addr.nl_family = AF_NETLINK; - addr.nl_pad = 0; - addr.nl_groups = 0; - addr.nl_pid = 0; /* address to kernel */ - - req.nlh.nlmsg_len = sizeof(req); - req.nlh.nlmsg_type = RTM_GETADDR; - req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST | NLM_F_ACK; - req.nlh.nlmsg_pid = 0; - req.nlh.nlmsg_seq = 1; - req.g.rtgen_family = AF_INET; - - if (sendto(fd, (void *)&req, sizeof(req), 0, - (struct sockaddr *)&addr, sizeof(addr)) == -1) - { - perror("sendto failed"); - exit(1); - } - - while (1) - { - if ((len = netlink_recv(fd)) == -1) - { - perror("netlink"); - exit(1); - } - - for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len)) - if (h->nlmsg_type == NLMSG_DONE) - exit(0); - else if (h->nlmsg_type == RTM_NEWADDR) - { - struct ifaddrmsg *ifa = NLMSG_DATA(h); - struct rtattr *rta; - unsigned int len1 = h->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)); - - if (ifa->ifa_index == index && ifa->ifa_family == AF_INET) - { - struct in_addr netmask, addr; - - netmask.s_addr = htonl(0xffffffff << (32 - ifa->ifa_prefixlen)); - addr.s_addr = 0; - - for (rta = IFA_RTA(ifa); RTA_OK(rta, len1); rta = RTA_NEXT(rta, len1)) - if (rta->rta_type == IFA_LOCAL) - addr = *((struct in_addr *)(rta+1)); - - if (addr.s_addr && is_same_net(addr, client, netmask)) - return addr; - } - } - } - - exit(0); -} - -int main(int argc, char **argv) -{ - struct in_addr server, lease; - int mac_type; - struct dhcp_packet packet; - unsigned char *p = packet.options; - struct sockaddr_in dest; - struct ifreq ifr; - int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); - int nl = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - - if (argc < 4 || argc > 5) - { - fprintf(stderr, "usage: dhcp_release []\n"); - exit(1); - } - - if (fd == -1 || nl == -1) - { - perror("cannot create socket"); - exit(1); - } - - /* This voodoo fakes up a packet coming from the correct interface, which really matters for - a DHCP server */ - strcpy(ifr.ifr_name, argv[1]); - if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) == -1) - { - perror("cannot setup interface"); - exit(1); - } - - if (inet_addr(argv[2]) == INADDR_NONE) - { - perror("invalid ip address"); - exit(1); - } - - lease.s_addr = inet_addr(argv[2]); - server = find_interface(lease, nl, if_nametoindex(argv[1])); - - memset(&packet, 0, sizeof(packet)); - - packet.hlen = parse_hex(argv[3], packet.chaddr, DHCP_CHADDR_MAX, &mac_type); - if (mac_type == 0) - packet.htype = ARPHRD_ETHER; - else - packet.htype = mac_type; - - packet.op = BOOTREQUEST; - packet.ciaddr = lease; - packet.cookie = htonl(DHCP_COOKIE); - - *(p++) = OPTION_MESSAGE_TYPE; - *(p++) = 1; - *(p++) = DHCPRELEASE; - - *(p++) = OPTION_SERVER_IDENTIFIER; - *(p++) = sizeof(server); - memcpy(p, &server, sizeof(server)); - p += sizeof(server); - - if (argc == 5 && strcmp(argv[4], "*") != 0) - { - unsigned int clid_len = parse_hex(argv[4], p+2, 255, NULL); - *(p++) = OPTION_CLIENT_ID; - *(p++) = clid_len; - p += clid_len; - } - - *(p++) = OPTION_END; - - dest.sin_family = AF_INET; - dest.sin_port = ntohs(DHCP_SERVER_PORT); - dest.sin_addr = server; - - if (sendto(fd, &packet, sizeof(packet), 0, - (struct sockaddr *)&dest, sizeof(dest)) == -1) - { - perror("sendto failed"); - exit(1); - } - - return 0; -} diff -Nru dnsmasq-2.75/contrib/wrt/Makefile dnsmasq-2.76/contrib/wrt/Makefile --- dnsmasq-2.75/contrib/wrt/Makefile 2015-07-30 20:00:40.000000000 +0000 +++ dnsmasq-2.76/contrib/wrt/Makefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ -CFLAGS?= -O2 -Wall -W - -all: dhcp_release dhcp_lease_time - -clean: - rm -f *~ *.o core dhcp_release dhcp_lease_time diff -Nru dnsmasq-2.75/debian/changelog dnsmasq-2.76/debian/changelog --- dnsmasq-2.75/debian/changelog 2016-05-20 08:41:26.000000000 +0000 +++ dnsmasq-2.76/debian/changelog 2016-05-20 08:41:26.000000000 +0000 @@ -1,13 +1,24 @@ +dnsmasq (2.76-1) unstable; urgency=low + + * New upstream. (closes: #798586) + * Use /run/dnsmasq directly, rather than relying on link from /var/run + to avoid problems before /var is mounted. (closes: #800351) + * Test for the existance of /usr/share/doc/dnsmasq rather then + /etc/dnsmasq.d/README in the daemon startup script. (closes: #819856) + * Add --help to manpage and mention dhcp6 in summary. (closes: #821226) + + -- Simon Kelley Thu, 10 Sep 2015 23:07:21 +0000 + dnsmasq (2.75-1) unstable; urgency=low * New upstream. (closes: #794095) - - -- Simon Kelley Thur, 30 Jul 2015 20:58:31 +0000 + + -- Simon Kelley Thu, 30 Jul 2015 20:58:31 +0000 dnsmasq (2.74-1) unstable; urgency=low * New upstream. (LP: #1468611) - + -- Simon Kelley Wed, 15 Jul 2015 21:54:11 +0000 dnsmasq (2.73-2) unstable; urgency=low diff -Nru dnsmasq-2.75/debian/copyright dnsmasq-2.76/debian/copyright --- dnsmasq-2.75/debian/copyright 2016-05-20 08:41:26.000000000 +0000 +++ dnsmasq-2.76/debian/copyright 2016-05-20 08:41:26.000000000 +0000 @@ -1,4 +1,4 @@ -dnsmasq is Copyright (c) 2000-2015 Simon Kelley +dnsmasq is Copyright (c) 2000-2016 Simon Kelley It was downloaded from: http://www.thekelleys.org.uk/dnsmasq/ diff -Nru dnsmasq-2.75/debian/dnsmasq-base.postinst dnsmasq-2.76/debian/dnsmasq-base.postinst --- dnsmasq-2.75/debian/dnsmasq-base.postinst 2016-05-20 08:41:26.000000000 +0000 +++ dnsmasq-2.76/debian/dnsmasq-base.postinst 2016-05-20 08:41:26.000000000 +0000 @@ -17,8 +17,8 @@ # dnsmasq-base, but it's much easier to create it here so that # we don't have synchronisation issues with the creation of the # dnsmasq user. - if [ ! -d /var/run/dnsmasq ]; then - mkdir /var/run/dnsmasq - chown dnsmasq:nogroup /var/run/dnsmasq + if [ ! -d /run/dnsmasq ]; then + mkdir /run/dnsmasq + chown dnsmasq:nogroup /run/dnsmasq fi fi diff -Nru dnsmasq-2.75/debian/dnsmasq-base.postrm dnsmasq-2.76/debian/dnsmasq-base.postrm --- dnsmasq-2.75/debian/dnsmasq-base.postrm 2016-05-20 08:41:26.000000000 +0000 +++ dnsmasq-2.76/debian/dnsmasq-base.postrm 2016-05-20 08:41:26.000000000 +0000 @@ -7,5 +7,5 @@ else echo >&2 "not removing dnsmasq system account because deluser command was not found" fi - rm -rf /var/run/dnsmasq + rm -rf /run/dnsmasq fi diff -Nru dnsmasq-2.75/debian/init dnsmasq-2.76/debian/init --- dnsmasq-2.75/debian/init 2016-05-20 08:41:26.000000000 +0000 +++ dnsmasq-2.76/debian/init 2016-05-20 08:41:26.000000000 +0000 @@ -8,7 +8,8 @@ # Description: DHCP and DNS server ### END INIT INFO -set +e # Don't exit on error status +# Don't exit on error status +set +e PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin DAEMON=/usr/sbin/dnsmasq @@ -29,12 +30,11 @@ export LANG fi -# /etc/dnsmasq.d/README is a non-conffile installed by the dnsmasq package. -# Should the dnsmasq package be removed, the following test ensures that -# the daemon is no longer started, even if the dnsmasq-base package is -# still in place. -test -e /etc/dnsmasq.d/README || exit 0 - +# The following test ensures the dnsmasq service is not started, when the +# package 'dnsmasq' is removed but not purged, even if the dnsmasq-base +# package is still in place. +test -d /usr/share/doc/dnsmasq || exit 0 + test -x $DAEMON || exit 0 # Provide skeleton LSB log functions for backports which don't have LSB functions. @@ -81,7 +81,7 @@ [ "$IGNORE_RESOLVCONF" != "yes" ] && [ -x /sbin/resolvconf ] then - RESOLV_CONF=/var/run/dnsmasq/resolv.conf + RESOLV_CONF=/run/dnsmasq/resolv.conf fi for INTERFACE in $DNSMASQ_INTERFACE; do @@ -121,16 +121,16 @@ # 1 if daemon was already running # 2 if daemon could not be started - # /var/run may be volatile, so we need to ensure that - # /var/run/dnsmasq exists here as well as in postinst - if [ ! -d /var/run/dnsmasq ]; then - mkdir /var/run/dnsmasq || return 2 - chown dnsmasq:nogroup /var/run/dnsmasq || return 2 + # /run may be volatile, so we need to ensure that + # /run/dnsmasq exists here as well as in postinst + if [ ! -d /run/dnsmasq ]; then + mkdir /run/dnsmasq || return 2 + chown dnsmasq:nogroup /run/dnsmasq || return 2 fi - start-stop-daemon --start --quiet --pidfile /var/run/dnsmasq/$NAME.pid --exec $DAEMON --test > /dev/null || return 1 - start-stop-daemon --start --quiet --pidfile /var/run/dnsmasq/$NAME.pid --exec $DAEMON -- \ - -x /var/run/dnsmasq/$NAME.pid \ + start-stop-daemon --start --quiet --pidfile /run/dnsmasq/$NAME.pid --exec $DAEMON --test > /dev/null || return 1 + start-stop-daemon --start --quiet --pidfile /run/dnsmasq/$NAME.pid --exec $DAEMON -- \ + -x /run/dnsmasq/$NAME.pid \ ${MAILHOSTNAME:+ -m $MAILHOSTNAME} \ ${MAILTARGET:+ -t $MAILTARGET} \ ${DNSMASQ_USER:+ -u $DNSMASQ_USER} \ @@ -167,7 +167,7 @@ # 1 if daemon was already stopped # 2 if daemon could not be stopped # other if a failure occurred - start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile /var/run/dnsmasq/$NAME.pid --name $NAME + start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile /run/dnsmasq/$NAME.pid --name $NAME } stop_resolvconf() @@ -185,9 +185,9 @@ # 1 if daemon is dead and pid file exists # 3 if daemon is not running # 4 if daemon status is unknown - start-stop-daemon --start --quiet --pidfile /var/run/dnsmasq/$NAME.pid --exec $DAEMON --test > /dev/null + start-stop-daemon --start --quiet --pidfile /run/dnsmasq/$NAME.pid --exec $DAEMON --test > /dev/null case "$?" in - 0) [ -e "/var/run/dnsmasq/$NAME.pid" ] && return 1 ; return 3 ;; + 0) [ -e "/run/dnsmasq/$NAME.pid" ] && return 1 ; return 3 ;; 1) return 0 ;; *) return 4 ;; esac @@ -278,7 +278,7 @@ esac ;; dump-stats) - kill -s USR1 `cat /var/run/dnsmasq/$NAME.pid` + kill -s USR1 `cat /run/dnsmasq/$NAME.pid` ;; systemd-start-resolvconf) start_resolvconf @@ -287,13 +287,13 @@ stop_resolvconf ;; systemd-exec) -# /var/run may be volatile, so we need to ensure that - # /var/run/dnsmasq exists here as well as in postinst - if [ ! -d /var/run/dnsmasq ]; then - mkdir /var/run/dnsmasq || return 2 - chown dnsmasq:nogroup /var/run/dnsmasq || return 2 +# /run may be volatile, so we need to ensure that + # /run/dnsmasq exists here as well as in postinst + if [ ! -d /run/dnsmasq ]; then + mkdir /run/dnsmasq || return 2 + chown dnsmasq:nogroup /run/dnsmasq || return 2 fi - exec $DAEMON -x /var/run/dnsmasq/$NAME.pid \ + exec $DAEMON -x /run/dnsmasq/$NAME.pid \ ${MAILHOSTNAME:+ -m $MAILHOSTNAME} \ ${MAILTARGET:+ -t $MAILTARGET} \ ${DNSMASQ_USER:+ -u $DNSMASQ_USER} \ diff -Nru dnsmasq-2.75/debian/postinst dnsmasq-2.76/debian/postinst --- dnsmasq-2.75/debian/postinst 2016-05-20 08:41:26.000000000 +0000 +++ dnsmasq-2.76/debian/postinst 2016-05-20 08:41:26.000000000 +0000 @@ -21,7 +21,7 @@ update-rc.d dnsmasq defaults 15 85 >/dev/null if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ]; then - if [ -e /var/run/dnsmasq/dnsmasq.pid ]; then + if [ -e /run/dnsmasq/dnsmasq.pid ]; then ACTION=restart else ACTION=start diff -Nru dnsmasq-2.75/debian/resolvconf dnsmasq-2.76/debian/resolvconf --- dnsmasq-2.75/debian/resolvconf 2016-05-20 08:41:26.000000000 +0000 +++ dnsmasq-2.76/debian/resolvconf 2016-05-20 08:41:26.000000000 +0000 @@ -13,7 +13,7 @@ set -e -RUN_DIR="/var/run/dnsmasq" +RUN_DIR="/run/dnsmasq" RSLVRLIST_FILE="${RUN_DIR}/resolv.conf" TMP_FILE="${RSLVRLIST_FILE}_new.$$" MY_NAME_FOR_RESOLVCONF="dnsmasq" diff -Nru dnsmasq-2.75/debian/rules dnsmasq-2.76/debian/rules --- dnsmasq-2.75/debian/rules 2016-05-20 08:41:26.000000000 +0000 +++ dnsmasq-2.76/debian/rules 2016-05-20 08:41:26.000000000 +0000 @@ -93,7 +93,7 @@ $(checkdir) rm -rf debian/daemon debian/base debian/utils debian/*~ debian/files debian/substvars debian/utils-substvars make clean - make -C contrib/wrt clean + make -C contrib/lease-tools clean binary-indep: checkroot $(checkdir) @@ -134,7 +134,6 @@ -d debian/base/etc/dbus-1/system.d \ -d debian/base/usr/share/doc/$(package) \ -d debian/base/usr/share/doc/$(package)/examples \ - -d debian/base/var/run \ -d debian/base/usr/share/$(package) \ -d debian/base/var/lib/misc make $(TARGET) PREFIX=/usr DESTDIR=`pwd`/debian/base CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=gcc @@ -185,12 +184,15 @@ -d debian/utils/usr/share/man/man1 \ -d debian/utils/usr/bin \ -d debian/utils/usr/share/doc/dnsmasq-utils - make -C contrib/wrt PREFIX=/usr DESTDIR=`pwd`/debian/utils CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=gcc - install -m 755 contrib/wrt/dhcp_release debian/utils/usr/bin/dhcp_release - install -m 644 contrib/wrt/dhcp_release.1 debian/utils/usr/share/man/man1/dhcp_release.1 + make -C contrib/lease-tools PREFIX=/usr DESTDIR=`pwd`/debian/utils CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=gcc + install -m 755 contrib/lease-tools/dhcp_release debian/utils/usr/bin/dhcp_release + install -m 644 contrib/lease-tools/dhcp_release.1 debian/utils/usr/share/man/man1/dhcp_release.1 gzip -9n debian/utils/usr/share/man/man1/dhcp_release.1 - install -m 755 contrib/wrt/dhcp_lease_time debian/utils/usr/bin/dhcp_lease_time - install -m 644 contrib/wrt/dhcp_lease_time.1 debian/utils/usr/share/man/man1/dhcp_lease_time.1 + install -m 755 contrib/lease-tools/dhcp_release6 debian/utils/usr/bin/dhcp_release6 + install -m 644 contrib/lease-tools/dhcp_release6.1 debian/utils/usr/share/man/man1/dhcp_release6.1 + gzip -9n debian/utils/usr/share/man/man1/dhcp_release6.1 + install -m 755 contrib/lease-tools/dhcp_lease_time debian/utils/usr/bin/dhcp_lease_time + install -m 644 contrib/lease-tools/dhcp_lease_time.1 debian/utils/usr/share/man/man1/dhcp_lease_time.1 install -m 644 debian/copyright debian/utils/usr/share/doc/dnsmasq-utils/copyright install -m 644 debian/changelog debian/utils/usr/share/doc/dnsmasq-utils/changelog.Debian gzip -9n debian/utils/usr/share/doc/dnsmasq-utils/changelog.Debian diff -Nru dnsmasq-2.75/debian/systemd.service dnsmasq-2.76/debian/systemd.service --- dnsmasq-2.75/debian/systemd.service 2016-05-20 08:41:26.000000000 +0000 +++ dnsmasq-2.76/debian/systemd.service 2016-05-20 08:41:26.000000000 +0000 @@ -4,7 +4,7 @@ [Service] Type=forking -PIDFile=/var/run/dnsmasq/dnsmasq.pid +PIDFile=/run/dnsmasq/dnsmasq.pid # Test the config file and refuse starting if it is not valid. ExecStartPre=/usr/sbin/dnsmasq --test diff -Nru dnsmasq-2.75/Makefile dnsmasq-2.76/Makefile --- dnsmasq-2.75/Makefile 2015-07-30 20:00:40.000000000 +0000 +++ dnsmasq-2.76/Makefile 2016-05-18 14:58:28.000000000 +0000 @@ -1,4 +1,4 @@ -# dnsmasq is Copyright (c) 2000-2015 Simon Kelley +# dnsmasq is Copyright (c) 2000-2016 Simon Kelley # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -73,7 +73,8 @@ dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \ helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \ dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \ - domain.o dnssec.o blockdata.o tables.o loop.o inotify.o poll.o + domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \ + poll.o rrfilter.o edns0.o arp.o hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \ dns-protocol.h radv-protocol.h ip6addr.h diff -Nru dnsmasq-2.75/man/dnsmasq.8 dnsmasq-2.76/man/dnsmasq.8 --- dnsmasq-2.75/man/dnsmasq.8 2015-07-30 20:00:40.000000000 +0000 +++ dnsmasq-2.76/man/dnsmasq.8 2016-05-18 14:58:28.000000000 +0000 @@ -42,6 +42,13 @@ Read and syntax check configuration file(s). Exit with code 0 if all is OK, or a non-zero code otherwise. Do not start up dnsmasq. .TP +.B \-w, --help +Display all command-line options. +.B --help dhcp +will display known DHCPv4 configuration options, and +.B --help dhcp6 +will display DHCPv6 options. +.TP .B \-h, --no-hosts Don't read the hostnames in /etc/hosts. .TP @@ -60,7 +67,7 @@ apply to domain names in cnames, PTR records, TXT records etc. .TP .B \-T, --local-ttl=