/** * Constructor. Establishes a TCP socket connection with the DHCP client daemon on port 5818. * * @throws IOException if unable to establish the connection with the DHCP client daemon. */ private Poller(long timeout) throws IOException { DhcpdConfigFactory dcf = DhcpdConfigFactory.getInstance(); try { LOG.debug( "Poller.ctor: opening socket connection with DHCP client daemon on port {}", dcf.getPort()); m_connection = new Socket(InetAddressUtils.addr("127.0.0.1"), dcf.getPort()); LOG.debug("Poller.ctor: setting socket timeout to {}", timeout); m_connection.setSoTimeout((int) timeout); // Establish input/output object streams m_ins = new ObjectInputStream(m_connection.getInputStream()); m_outs = new ObjectOutputStream(m_connection.getOutputStream()); m_outs.reset(); m_outs.flush(); } catch (IOException ex) { LOG.error("IO Exception during socket connection establishment with DHCP client daemon.", ex); if (m_connection != null) { try { m_ins.close(); m_outs.close(); m_connection.close(); } catch (Throwable t) { } } throw ex; } catch (Throwable t) { LOG.error( "Unexpected exception during socket connection establishment with DHCP client daemon.", t); if (m_connection != null) { try { m_ins.close(); m_outs.close(); m_connection.close(); } catch (Throwable tx) { } } throw new UndeclaredThrowableException(t); } }
/** * This method actually tests the remote host to determine if it is running a functional DHCP * server. * * <p>Formats a DHCP query and encodes it in a client request message which is sent to the DHCP * daemon over the established TCP socket connection. If a matching DHCP response packet is not * received from the DHCP daemon within the specified timeout the client request message will be * re-sent up to the specified number of retries. * * <p>If a response is received from the DHCP daemon it is validated to ensure that: * * <ul> * <li>The DHCP response packet was sent from the remote host to which the original request * packet was directed. * <li>The XID of the DHCP response packet matches the XID of the original DHCP request packet. * </ul> * * <p>If the response validates 'true' is returned. Otherwise the request is resent until max * retry count is exceeded. * * <p>Before returning, a client disconnect message (remote host field set to zero) is sent to the * DHCP daemon. * * @return response time in milliseconds if the specified host responded with a valid DHCP offer * datagram within the context of the specified timeout and retry values or negative one (-1) * otherwise. */ static long isServer(InetAddress host, long timeout, int retries) throws IOException { boolean isDhcpServer = false; // List of DHCP queries to try. The default when extended // mode = false must be listed first. (DISCOVER) byte[] typeList = { (byte) DHCPMessage.DISCOVER, (byte) DHCPMessage.INFORM, (byte) DHCPMessage.REQUEST }; String[] typeName = {"DISCOVER", "INFORM", "REQUEST"}; DhcpdConfigFactory dcf = DhcpdConfigFactory.getInstance(); if (!paramsChecked) { String s_extendedMode = dcf.getExtendedMode(); if (s_extendedMode == null) { extendedMode = false; } else { extendedMode = Boolean.parseBoolean(s_extendedMode); } LOG.debug("isServer: DHCP extended mode is {}", extendedMode); String hwAddressStr = dcf.getMacAddress(); LOG.debug("isServer: DHCP query hardware/MAC address is {}", hwAddressStr); setHwAddress(hwAddressStr); String myIpStr = dcf.getMyIpAddress(); LOG.debug("isServer: DHCP relay agent address is {}", myIpStr); if (myIpStr == null || myIpStr.equals("") || myIpStr.equalsIgnoreCase("broadcast")) { // do nothing } else { try { InetAddressUtils.toIpAddrBytes(myIpStr); s_myIpAddress = setIpAddress(myIpStr); relayMode = true; } catch (IllegalArgumentException e) { LOG.warn("isServer: DHCP relay agent address is invalid: {}", myIpStr); } } if (extendedMode == true) { String requestStr = dcf.getRequestIpAddress(); LOG.debug("isServer: REQUEST query target is {}", requestStr); if (requestStr == null || requestStr.equals("") || requestStr.equalsIgnoreCase("targetSubnet")) { // do nothing } else if (requestStr.equalsIgnoreCase("targetHost")) { targetOffset = false; } else { try { InetAddressUtils.toIpAddrBytes(requestStr); s_requestIpAddress = setIpAddress(requestStr); reqTargetIp = false; targetOffset = false; } catch (IllegalArgumentException e) { LOG.warn("isServer: REQUEST query target is invalid: {}", requestStr); } } LOG.debug( "REQUEST query options are: reqTargetIp = {}, targetOffset = {}", reqTargetIp, targetOffset); } paramsChecked = true; } int j = 1; if (extendedMode == true) { j = typeList.length; } if (timeout < 500) { timeout = 500; } Poller p = new Poller(timeout); long responseTime = -1; try { pollit: for (int i = 0; i < j; i++) { Message ping = getPollingRequest(host, (byte) typeList[i]); int rt = retries; while (rt >= 0 && !isDhcpServer) { LOG.debug( "isServer: sending DHCP {} query to host {} with Xid: {}", typeName[i], InetAddressUtils.str(host), ping.getMessage().getXid()); long start = System.currentTimeMillis(); p.m_outs.writeObject(ping); long end; do { Message resp = null; try { resp = (Message) p.m_ins.readObject(); } catch (InterruptedIOException ex) { resp = null; } if (resp != null) { responseTime = System.currentTimeMillis() - start; // DEBUG only LOG.debug( "isServer: got a DHCP response from host {} with Xid: {}", InetAddressUtils.str(resp.getAddress()), resp.getMessage().getXid()); if (host.equals(resp.getAddress()) && ping.getMessage().getXid() == resp.getMessage().getXid()) { // Inspect response message to see if it is a valid DHCP response byte[] type = resp.getMessage().getOption(MESSAGE_TYPE); if (type[0] == DHCPMessage.OFFER) { LOG.debug("isServer: got a DHCP OFFER response, validating..."); } else if (type[0] == DHCPMessage.ACK) { LOG.debug("isServer: got a DHCP ACK response, validating..."); } else if (type[0] == DHCPMessage.NAK) { LOG.debug("isServer: got a DHCP NAK response, validating..."); } // accept offer or ACK or NAK if (type[0] == DHCPMessage.OFFER || (extendedMode == true && (type[0] == DHCPMessage.ACK || type[0] == DHCPMessage.NAK))) { LOG.debug( "isServer: got a valid DHCP response. responseTime= {}ms", responseTime); isDhcpServer = true; break pollit; } } } end = System.currentTimeMillis(); } while ((end - start) < timeout); if (!isDhcpServer) { LOG.debug("Timed out waiting for DHCP response, remaining retries: {}", rt); } --rt; } } LOG.debug("Sending disconnect request"); p.m_outs.writeObject(getDisconnectRequest()); LOG.debug("wait half a sec before closing connection"); Thread.sleep(500); p.close(); } catch (IOException ex) { LOG.error("IO Exception caught.", ex); p.close(); throw ex; } catch (Throwable t) { LOG.error("Unexpected Exception caught.", t); p.close(); throw new UndeclaredThrowableException(t); } // Return response time if the remote box IS a DHCP // server or -1 if the remote box is NOT a DHCP server. if (isDhcpServer) { return responseTime; } else { return -1; } }