All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javax.jmdns.impl.HostInfo Maven / Gradle / Ivy

Go to download

JmDNS is a Java implementation of multi-cast DNS and can be used for service registration and discovery in local area networks. JmDNS is fully compatible with Apple's Bonjour. The project was originally started in December 2002 by Arthur van Hoff at Strangeberry.

There is a newer version: 3.6.0
Show newest version
// Copyright 2003-2005 Arthur van Hoff, Rick Blair
// Licensed under Apache License version 2.0
// Original license LGPL

package javax.jmdns.impl;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jmdns.NetworkTopologyDiscovery;
import javax.jmdns.impl.constants.DNSConstants;
import javax.jmdns.impl.constants.DNSRecordClass;
import javax.jmdns.impl.constants.DNSRecordType;
import javax.jmdns.impl.constants.DNSState;
import javax.jmdns.impl.tasks.DNSTask;

/**
 * HostInfo information on the local host to be able to cope with change of addresses.
 *
 * @author Pierre Frisch, Werner Randelshofer
 */
public class HostInfo implements DNSStatefulObject {
    private static Logger       logger = LoggerFactory.getLogger(HostInfo.class);

    protected String            _name;

    protected InetAddress       _address;

    protected NetworkInterface  _interfaze;

    private final HostInfoState _state;

    private final static int    _labelLengthLimit = 0x3F;

    private final static class HostInfoState extends DNSStatefulObject.DefaultImplementation {

        private static final long serialVersionUID = -8191476803620402088L;

        /**
         * @param dns
         */
        public HostInfoState(JmDNSImpl dns) {
            super();
            this.setDns(dns);
        }

    }

    /**
     * @param address
     *            IP address to bind
     * @param dns
     *            JmDNS instance
     * @param jmdnsName
     *            JmDNS name
     * @return new HostInfo
     */
    public static HostInfo newHostInfo(InetAddress address, JmDNSImpl dns, String jmdnsName) {
        HostInfo localhost = null;
        String aName = (jmdnsName != null ? jmdnsName : "");
        InetAddress addr = address;
        try {
            if (addr == null) {
                String ip = System.getProperty("net.mdns.interface");
                if (ip != null) {
                    addr = InetAddress.getByName(ip);
                } else {
                    addr = InetAddress.getLocalHost();
                    if (addr.isLoopbackAddress()) {
                        // Find local address that isn't a loopback address
                        InetAddress[] addresses = NetworkTopologyDiscovery.Factory.getInstance().getInetAddresses();
                        if (addresses.length > 0) {
                            addr = addresses[0];
                        }
                    }
                }
                if (addr.isLoopbackAddress()) {
                    logger.warn("Could not find any address beside the loopback.");
                }
            }
            if (aName.length() == 0) {
                aName = addr.getHostName();
            }
            if (aName.contains("in-addr.arpa") || (aName.equals(addr.getHostAddress()))) {
                aName = ((jmdnsName != null) && (jmdnsName.length() > 0) ? jmdnsName : addr.getHostAddress());
            }
        } catch (final IOException e) {
            logger.warn("Could not initialize the host network interface on " + address + "because of an error: " + e.getMessage(), e);
            // This is only used for running unit test on Debian / Ubuntu
            addr = loopbackAddress();
            aName = ((jmdnsName != null) && (jmdnsName.length() > 0) ? jmdnsName : "computer");
        }
        // A host name with "." is illegal. so strip off everything and append .local.
        // We also need to be carefull that the .local may already be there
        int index = aName.indexOf(".local");
        if (index > 0) {
            aName = aName.substring(0, index);
        }
        if (aName.length() > _labelLengthLimit) {
            // Remove trailing labels which would make the combined label exceed 63 characters in length
            aName = aName.substring(0, _labelLengthLimit + 1);
            aName = aName.substring(0, aName.lastIndexOf('.'));
        }
        aName = aName.replaceAll("[:%\\.]", "-");
        aName += ".local.";
        localhost = new HostInfo(addr, aName, dns);
        return localhost;
    }

    private static InetAddress loopbackAddress() {
        try {
            return InetAddress.getByName(null);
        } catch (UnknownHostException exception) {
            return null;
        }
    }

    private HostInfo(final InetAddress address, final String name, final JmDNSImpl dns) {
        super();
        this._state = new HostInfoState(dns);
        this._address = address;
        this._name = name;
        if (address != null) {
            try {
                _interfaze = NetworkInterface.getByInetAddress(address);
            } catch (Exception exception) {
                logger.warn("LocalHostInfo() exception ", exception);
            }
        }
    }

    public String getName() {
        return _name;
    }

    public InetAddress getInetAddress() {
        return _address;
    }

    Inet4Address getInet4Address() {
        if (this.getInetAddress() instanceof Inet4Address) {
            return (Inet4Address) _address;
        }
        return null;
    }

    Inet6Address getInet6Address() {
        if (this.getInetAddress() instanceof Inet6Address) {
            return (Inet6Address) _address;
        }
        return null;
    }

    public NetworkInterface getInterface() {
        return _interfaze;
    }

    public boolean conflictWithRecord(DNSRecord.Address record) {
        DNSRecord.Address hostAddress = this.getDNSAddressRecord(record.getRecordType(), record.isUnique(), DNSConstants.DNS_TTL);
        if (hostAddress != null) {
            return hostAddress.sameType(record) && hostAddress.sameName(record) && (!hostAddress.sameValue(record));
        }
        return false;
    }

    synchronized String incrementHostName() {
        _name = NameRegister.Factory.getRegistry().incrementName(this.getInetAddress(), _name, NameRegister.NameType.HOST);
        return _name;
    }

    boolean shouldIgnorePacket(DatagramPacket packet) {
        boolean result = false;
        if (this.getInetAddress() != null) {
            InetAddress from = packet.getAddress();
            if (from != null) {
                if ((this.getInetAddress().isLinkLocalAddress() || this.getInetAddress().isMCLinkLocal()) && (!from.isLinkLocalAddress())) {
                    // A host sending Multicast DNS queries to a link-local destination
                    // address (including the 224.0.0.251 and FF02::FB link-local multicast
                    // addresses) MUST only accept responses to that query that originate
                    // from the local link, and silently discard any other response packets.
                    // Without this check, it could be possible for remote rogue hosts to
                    // send spoof answer packets (perhaps unicast to the victim host) which
                    // the receiving machine could misinterpret as having originated on the
                    // local link.
                    result = true;
                }
                // if (from.isLinkLocalAddress() && (!this.getInetAddress().isLinkLocalAddress())) {
                // // Ignore linklocal packets on regular interfaces, unless this is
                // // also a linklocal interface. This is to avoid duplicates. This is
                // // a terrible hack caused by the lack of an API to get the address
                // // of the interface on which the packet was received.
                // result = true;
                // }
                if (from.isLoopbackAddress() && (!this.getInetAddress().isLoopbackAddress())) {
                    // Ignore loopback packets on a regular interface unless this is also a loopback interface.
                    result = true;
                }
            }
        }
        return result;
    }

    DNSRecord.Address getDNSAddressRecord(DNSRecordType type, boolean unique, int ttl) {
        switch (type) {
            case TYPE_A:
                return this.getDNS4AddressRecord(unique, ttl);
            case TYPE_A6:
            case TYPE_AAAA:
                return this.getDNS6AddressRecord(unique, ttl);
            default:
        }
        return null;
    }

    private DNSRecord.Address getDNS4AddressRecord(boolean unique, int ttl) {
        if (this.getInetAddress() instanceof Inet4Address) {
            return new DNSRecord.IPv4Address(this.getName(), DNSRecordClass.CLASS_IN, unique, ttl, this.getInetAddress());
        }
        return null;
    }

    private DNSRecord.Address getDNS6AddressRecord(boolean unique, int ttl) {
        if (this.getInetAddress() instanceof Inet6Address) {
            return new DNSRecord.IPv6Address(this.getName(), DNSRecordClass.CLASS_IN, unique, ttl, this.getInetAddress());
        }
        return null;
    }

    DNSRecord.Pointer getDNSReverseAddressRecord(DNSRecordType type, boolean unique, int ttl) {
        switch (type) {
            case TYPE_A:
                return this.getDNS4ReverseAddressRecord(unique, ttl);
            case TYPE_A6:
            case TYPE_AAAA:
                return this.getDNS6ReverseAddressRecord(unique, ttl);
            default:
        }
        return null;
    }

    private DNSRecord.Pointer getDNS4ReverseAddressRecord(boolean unique, int ttl) {
        if (this.getInetAddress() instanceof Inet4Address) {
            return new DNSRecord.Pointer(this.getInetAddress().getHostAddress() + ".in-addr.arpa.", DNSRecordClass.CLASS_IN, unique, ttl, this.getName());
        }
        return null;
    }

    private DNSRecord.Pointer getDNS6ReverseAddressRecord(boolean unique, int ttl) {
        if (this.getInetAddress() instanceof Inet6Address) {
            return new DNSRecord.Pointer(this.getInetAddress().getHostAddress() + ".ip6.arpa.", DNSRecordClass.CLASS_IN, unique, ttl, this.getName());
        }
        return null;
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder(1024);
        sb.append("local host info[");
        sb.append(getName() != null ? getName() : "no name");
        sb.append(", ");
        sb.append(getInterface() != null ? getInterface().getDisplayName() : "???");
        sb.append(":");
        sb.append(getInetAddress() != null ? getInetAddress().getHostAddress() : "no address");
        sb.append(", ");
        sb.append(_state);
        sb.append("]");
        return sb.toString();
    }

    public Collection answers(DNSRecordClass recordClass, boolean unique, int ttl) {
        List list = new ArrayList();
        DNSRecord answer = this.getDNS4AddressRecord(unique, ttl);
        if ((answer != null) && answer.matchRecordClass(recordClass)) {
            list.add(answer);
        }
        answer = this.getDNS6AddressRecord(unique, ttl);
        if ((answer != null) && answer.matchRecordClass(recordClass)) {
            list.add(answer);
        }
        return list;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public JmDNSImpl getDns() {
        return this._state.getDns();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean advanceState(DNSTask task) {
        return this._state.advanceState(task);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void removeAssociationWithTask(DNSTask task) {
        this._state.removeAssociationWithTask(task);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean revertState() {
        return this._state.revertState();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void associateWithTask(DNSTask task, DNSState state) {
        this._state.associateWithTask(task, state);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isAssociatedWithTask(DNSTask task, DNSState state) {
        return this._state.isAssociatedWithTask(task, state);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean cancelState() {
        return this._state.cancelState();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean closeState() {
        return this._state.closeState();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean recoverState() {
        return this._state.recoverState();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isProbing() {
        return this._state.isProbing();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isAnnouncing() {
        return this._state.isAnnouncing();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isAnnounced() {
        return this._state.isAnnounced();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isCanceling() {
        return this._state.isCanceling();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isCanceled() {
        return this._state.isCanceled();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isClosing() {
        return this._state.isClosing();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isClosed() {
        return this._state.isClosed();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean waitForAnnounced(long timeout) {
        return _state.waitForAnnounced(timeout);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean waitForCanceled(long timeout) {
        if (_address == null) {
            // No need to wait this was never announced.
            return true;
        }
        return _state.waitForCanceled(timeout);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy