1/*
2* Conditions Of Use
3*
4* This software was developed by employees of the National Institute of
5* Standards and Technology (NIST), an agency of the Federal Government.
6* Pursuant to title 15 Untied States Code Section 105, works of NIST
7* employees are not subject to copyright protection in the United States
8* and are considered to be in the public domain.  As a result, a formal
9* license is not needed to use the software.
10*
11* This software is provided by NIST as a service and is expressly
12* provided "AS IS."  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
13* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
14* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
15* AND DATA ACCURACY.  NIST does not warrant or make any representations
16* regarding the use of the software or the results thereof, including but
17* not limited to the correctness, accuracy, reliability or usefulness of
18* the software.
19*
20* Permission to use this software is contingent upon your acceptance
21* of the terms of this agreement
22*
23* .
24*
25*/
26/***************************************************************************
27 * Product of NIST/ITL Advanced Networking Technologies Division(ANTD).   *
28 **************************************************************************/
29package gov.nist.core;
30
31import java.net.*;
32
33/*
34 * IPv6 Support added by Emil Ivov (emil_ivov@yahoo.com)<br/>
35 * Network Research Team (http://www-r2.u-strasbg.fr))<br/>
36 * Louis Pasteur University - Strasbourg - France<br/>
37 *
38 * Frank Feif reported a bug.
39 *
40 *
41 */
42/**
43 * Stores hostname.
44 * @version 1.2
45 *
46 * @author M. Ranganathan
47 * @author Emil Ivov <emil_ivov@yahoo.com> IPV6 Support. <br/>
48 *
49 *
50 *
51
52 * Marc Bednarek <bednarek@nist.gov> (Bugfixes).<br/>
53 *
54 */
55public class Host extends GenericObject {
56
57    /**
58     * Determines whether or not we should tolerate and strip address scope
59     * zones from IPv6 addresses. Address scope zones are sometimes returned
60     * at the end of IPv6 addresses generated by InetAddress.getHostAddress().
61     * They are however not part of the SIP semantics so basically this method
62     * determines whether or not the parser should be stripping them (as
63     * opposed simply being blunt and throwing an exception).
64     */
65    private boolean stripAddressScopeZones = false;
66
67    private static final long serialVersionUID = -7233564517978323344L;
68    protected static final int HOSTNAME = 1;
69    protected static final int IPV4ADDRESS = 2;
70    protected static final int IPV6ADDRESS = 3;
71
72    /** hostName field
73     */
74    protected String hostname;
75
76    /** address field
77     */
78
79    protected int addressType;
80
81    private InetAddress inetAddress;
82
83    /** default constructor
84     */
85    public Host() {
86        addressType = HOSTNAME;
87
88        stripAddressScopeZones
89            = Boolean.getBoolean("gov.nist.core.STRIP_ADDR_SCOPES");
90    }
91
92    /** Constructor given host name or IP address.
93     */
94    public Host(String hostName) throws IllegalArgumentException {
95        if (hostName == null)
96            throw new IllegalArgumentException("null host name");
97
98        stripAddressScopeZones
99            = Boolean.getBoolean("gov.nist.core.STRIP_ADDR_SCOPES");
100
101        setHost(hostName, IPV4ADDRESS);
102    }
103
104    /** constructor
105     * @param name String to set
106     * @param addrType int to set
107     */
108    public Host(String name, int addrType) {
109        stripAddressScopeZones
110            = Boolean.getBoolean("gov.nist.core.STRIP_ADDR_SCOPES");
111
112        setHost(name, addrType);
113    }
114
115    /**
116     * Return the host name in encoded form.
117     * @return String
118     */
119    public String encode() {
120        return encode(new StringBuffer()).toString();
121    }
122
123    public StringBuffer encode(StringBuffer buffer) {
124        if (addressType == IPV6ADDRESS && !isIPv6Reference(hostname)) {
125            buffer.append('[').append(hostname).append(']');
126        } else {
127            buffer.append(hostname);
128        }
129        return buffer;
130    }
131
132    /**
133     * Compare for equality of hosts.
134     * Host names are compared by textual equality. No dns lookup
135     * is performed.
136     * @param obj Object to set
137     * @return boolean
138     */
139    public boolean equals(Object obj) {
140        if ( obj == null ) return false;
141        if (!this.getClass().equals(obj.getClass())) {
142            return false;
143        }
144        Host otherHost = (Host) obj;
145        return otherHost.hostname.equals(hostname);
146
147    }
148
149    /** get the HostName field
150     * @return String
151     */
152    public String getHostname() {
153        return hostname;
154    }
155
156    /** get the Address field
157     * @return String
158     */
159    public String getAddress() {
160        return hostname;
161    }
162
163    /**
164     * Convenience function to get the raw IP destination address
165     * of a SIP message as a String.
166     * @return String
167     */
168    public String getIpAddress() {
169        String rawIpAddress = null;
170        if (hostname == null)
171            return null;
172        if (addressType == HOSTNAME) {
173            try {
174                if (inetAddress == null)
175                    inetAddress = InetAddress.getByName(hostname);
176                rawIpAddress = inetAddress.getHostAddress();
177            } catch (UnknownHostException ex) {
178                dbgPrint("Could not resolve hostname " + ex);
179            }
180        } else {
181            rawIpAddress = hostname;
182        }
183        return rawIpAddress;
184    }
185
186    /**
187     * Set the hostname member.
188     * @param h String to set
189     */
190    public void setHostname(String h) {
191        setHost(h, HOSTNAME);
192    }
193
194    /** Set the IP Address.
195     *@param address is the address string to set.
196     */
197    public void setHostAddress(String address) {
198        setHost(address, IPV4ADDRESS);
199    }
200
201    /**
202     * Sets the host address or name of this object.
203     *
204     * @param host that host address/name value
205     * @param type determines whether host is an address or a host name
206     */
207    private void setHost(String host, int type){
208        //set inetAddress to null so that it would be reinited
209        //upon next call to getInetAddress()
210        inetAddress = null;
211
212        if (isIPv6Address(host))
213            addressType = IPV6ADDRESS;
214        else
215            addressType = type;
216
217        // Null check bug fix sent in by jpaulo@ipb.pt
218        if (host != null){
219            hostname = host.trim();
220
221            //if this is an FQDN, make it lowercase to simplify processing
222            if(addressType == HOSTNAME)
223                hostname = hostname.toLowerCase();
224
225            //remove address scope zones if this is an IPv6 address as they
226            //are not allowed by the RFC
227            int zoneStart = -1;
228            if(addressType == IPV6ADDRESS
229                && stripAddressScopeZones
230                && (zoneStart = hostname.indexOf('%'))!= -1){
231
232                hostname = hostname.substring(0, zoneStart);
233            }
234        }
235    }
236
237    /**
238     * Set the address member
239     * @param address address String to set
240     */
241    public void setAddress(String address) {
242        this.setHostAddress(address);
243    }
244
245    /** Return true if the address is a DNS host name
246     *  (and not an IPV4 address)
247     *@return true if the hostname is a DNS name
248     */
249    public boolean isHostname() {
250        return addressType == HOSTNAME;
251    }
252
253    /** Return true if the address is a DNS host name
254     *  (and not an IPV4 address)
255     *@return true if the hostname is host address.
256     */
257    public boolean isIPAddress() {
258        return addressType != HOSTNAME;
259    }
260
261    /** Get the inet address from this host.
262     * Caches the inet address returned from dns lookup to avoid
263     * lookup delays.
264     *
265     *@throws UnkownHostexception when the host name cannot be resolved.
266     */
267    public InetAddress getInetAddress() throws java.net.UnknownHostException {
268        if (hostname == null)
269            return null;
270        if (inetAddress != null)
271            return inetAddress;
272        inetAddress = InetAddress.getByName(hostname);
273        return inetAddress;
274
275    }
276
277    //----- IPv6
278    /**
279     * Verifies whether the <code>address</code> could
280     * be an IPv6 address
281     */
282    private boolean isIPv6Address(String address) {
283        return (address != null && address.indexOf(':') != -1);
284    }
285
286    /**
287     * Verifies whether the ipv6reference, i.e. whether it enclosed in
288     * square brackets
289     */
290    public static boolean isIPv6Reference(String address) {
291        return address.charAt(0) == '['
292            && address.charAt(address.length() - 1) == ']';
293    }
294
295    @Override
296    public int hashCode() {
297        return this.getHostname().hashCode();
298
299    }
300}
301