Re: [Dnsmasq-discuss] [PATCH v2] Add --dhcp-reply-delay option to delay DHCP replies

2017-04-09 Thread Simon Kelley
On 30/03/17 12:38, Floris Bos wrote:
> Adds option to delay replying to DHCP packets by one or more seconds.
> This provides a workaround for a PXE boot firmware implementation
> that has a bug causing it to fail if it receives a (proxy) DHCP
> reply instantly.
> 
> On Linux it looks up the exact receive time of the UDP packet with
> the SIOCGSTAMP ioctl to prevent multiple delays if multiple packets
> come in around the same time.
> 
> Signed-off-by: Floris Bos 

Committed, with a minor change for logging.

Cheers,

Simon.


___
Dnsmasq-discuss mailing list
Dnsmasq-discuss@lists.thekelleys.org.uk
http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss


Re: [Dnsmasq-discuss] [PATCH v2] Add --dhcp-reply-delay option to delay DHCP replies

2017-04-07 Thread Simon Kelley
On 30/03/17 12:38, Floris Bos wrote:
> Adds option to delay replying to DHCP packets by one or more seconds.
> This provides a workaround for a PXE boot firmware implementation
> that has a bug causing it to fail if it receives a (proxy) DHCP
> reply instantly.
> 
> On Linux it looks up the exact receive time of the UDP packet with
> the SIOCGSTAMP ioctl to prevent multiple delays if multiple packets
> come in around the same time.
> 

Apologies for going silent on this. My house move is over and I'm
working through my email backlog. Fortunately, you (collectively) have
reached a good solution without my input :) I'm happy with the principle
of this patch, and will eyeball it in detail and commit in the next day
or two.


Cheers,

Simon.





signature.asc
Description: OpenPGP digital signature
___
Dnsmasq-discuss mailing list
Dnsmasq-discuss@lists.thekelleys.org.uk
http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss


[Dnsmasq-discuss] [PATCH v2] Add --dhcp-reply-delay option to delay DHCP replies

2017-03-30 Thread Floris Bos
Adds option to delay replying to DHCP packets by one or more seconds.
This provides a workaround for a PXE boot firmware implementation
that has a bug causing it to fail if it receives a (proxy) DHCP
reply instantly.

On Linux it looks up the exact receive time of the UDP packet with
the SIOCGSTAMP ioctl to prevent multiple delays if multiple packets
come in around the same time.

Signed-off-by: Floris Bos 
---

v1 -> v2:

- adds support for tags
- only delay DHCPOFFER and proxydhcp replies
- ping check now uses same delay function
---
 man/dnsmasq.8 |   6 
 src/dhcp.c|   9 --
 src/dnsmasq.c | 102 +++---
 src/dnsmasq.h |  10 +-
 src/option.c  |  35 
 src/rfc2131.c |  29 +++--
 6 files changed, 144 insertions(+), 47 deletions(-)

diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
index 2e5ef21..05f800c 100644
--- a/man/dnsmasq.8
+++ b/man/dnsmasq.8
@@ -1790,6 +1790,12 @@ a router to advertise prefixes but not a route via 
itself.
 .B --ra-param=low,60,1200
 The interface field may include a wildcard.
 .TP
+.B --dhcp-reply-delay=[tag:,]
+Delays sending DHCPOFFER and proxydhcp replies for at least the specified 
number of seconds.
+This can be used as workaround for bugs in PXE boot firmware that does not 
function properly when
+receiving an instant reply.
+This option takes into account the time already spent waiting (e.g. performing 
ping check) if any.
+.TP
 .B --enable-tftp[=[,]]
 Enable the TFTP server function. This is deliberately limited to that
 needed to net-boot a client. Only reading is allowed; the tsize and
diff --git a/src/dhcp.c b/src/dhcp.c
index 08952c8..ada1be8 100644
--- a/src/dhcp.c
+++ b/src/dhcp.c
@@ -149,8 +149,10 @@ void dhcp_packet(time_t now, int pxe_fd)
   int rcvd_iface_index;
   struct in_addr iface_addr;
   struct iface_param parm;
+  time_t recvtime = now;
 #ifdef HAVE_LINUX_NETWORK
   struct arpreq arp_req;
+  struct timeval tv;
 #endif
   
   union {
@@ -177,6 +179,9 @@ void dhcp_packet(time_t now, int pxe_fd)
 return;
 
   #if defined (HAVE_LINUX_NETWORK)
+  if (ioctl(fd, SIOCGSTAMP, ) == 0)
+recvtime = tv.tv_sec;
+
   if (msg.msg_controllen >= sizeof(struct cmsghdr))
 for (cmptr = CMSG_FIRSTHDR(); cmptr; cmptr = CMSG_NXTHDR(, cmptr))
   if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
@@ -335,14 +340,14 @@ void dhcp_packet(time_t now, int pxe_fd)
 
   lease_prune(NULL, now); /* lose any expired leases */
   iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, 
(size_t)sz, 
-  now, unicast_dest, _inform, pxe_fd, 
iface_addr);
+  now, unicast_dest, _inform, pxe_fd, 
iface_addr, recvtime);
   lease_update_file(now);
   lease_update_dns(0);
   
   if (iov.iov_len == 0)
return;
 }
-  
+
   msg.msg_name = 
   msg.msg_namelen = sizeof(dest);
   msg.msg_control = NULL;
diff --git a/src/dnsmasq.c b/src/dnsmasq.c
index d2cc7cc..6ae8296 100644
--- a/src/dnsmasq.c
+++ b/src/dnsmasq.c
@@ -1747,29 +1747,15 @@ int icmp_ping(struct in_addr addr)
 {
   /* Try and get an ICMP echo from a machine. */
 
-  /* Note that whilst in the three second wait, we check for 
- (and service) events on the DNS and TFTP  sockets, (so doing that
- better not use any resources our caller has in use...)
- but we remain deaf to signals or further DHCP packets. */
-
-  /* There can be a problem using dnsmasq_time() to end the loop, since
- it's not monotonic, and can go backwards if the system clock is
- tweaked, leading to the code getting stuck in this loop and
- ignoring DHCP requests. To fix this, we check to see if select returned
- as a result of a timeout rather than a socket becoming available. We
- only allow this to happen as many times as it takes to get to the wait 
time
- in quarter-second chunks. This provides a fallback way to end loop. */ 
-
-  int fd, rc;
+  int fd;
   struct sockaddr_in saddr;
   struct { 
 struct ip ip;
 struct icmp icmp;
   } packet;
   unsigned short id = rand16();
-  unsigned int i, j, timeout_count;
+  unsigned int i, j;
   int gotreply = 0;
-  time_t start, now;
 
 #if defined(HAVE_LINUX_NETWORK) || defined (HAVE_SOLARIS_NETWORK)
   if ((fd = make_icmp_sock()) == -1)
@@ -1799,14 +1785,46 @@ int icmp_ping(struct in_addr addr)
   while (retry_send(sendto(fd, (char *), sizeof(struct icmp), 0, 
   (struct sockaddr *), sizeof(saddr;
   
-  for (now = start = dnsmasq_time(), timeout_count = 0; 
-   (difftime(now, start) < (float)PING_WAIT) && (timeout_count < PING_WAIT 
* 4);)
+  gotreply = delay_dhcp(dnsmasq_time(), PING_WAIT, fd, addr.s_addr, id);
+
+#if defined(HAVE_LINUX_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
+  while (retry_send(close(fd)));
+#else
+  opt = 1;
+  setsockopt(fd, SOL_SOCKET, SO_RCVBUF, , sizeof(opt));
+#endif
+
+