1/* 2 * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26/* 27 * 28 * (C) Copyright IBM Corp. 1999 All Rights Reserved. 29 * Copyright 1997 The Open Group Research Institute. All rights reserved. 30 */ 31 32package sun.security.krb5.internal; 33 34import sun.security.krb5.Config; 35import sun.security.krb5.PrincipalName; 36import sun.security.krb5.KrbException; 37import sun.security.krb5.Asn1Exception; 38import sun.security.util.*; 39 40import java.net.*; 41import java.util.*; 42import java.io.IOException; 43import sun.security.krb5.internal.ccache.CCacheOutputStream; 44 45/** 46 * Implements the ASN.1 HostAddresses type. 47 * 48 * <pre>{@code 49 * HostAddresses -- NOTE: subtly different from rfc1510, 50 * -- but has a value mapping and encodes the same 51 * ::= SEQUENCE OF HostAddress 52 * 53 * HostAddress ::= SEQUENCE { 54 * addr-type [0] Int32, 55 * address [1] OCTET STRING 56 * } 57 * }</pre> 58 * 59 * <p> 60 * This definition reflects the Network Working Group RFC 4120 61 * specification available at 62 * <a href="http://www.ietf.org/rfc/rfc4120.txt"> 63 * http://www.ietf.org/rfc/rfc4120.txt</a>. 64 */ 65 66public class HostAddresses implements Cloneable { 67 private static boolean DEBUG = sun.security.krb5.internal.Krb5.DEBUG; 68 private HostAddress[] addresses = null; 69 private volatile int hashCode = 0; 70 71 public HostAddresses(HostAddress[] new_addresses) throws IOException { 72 if (new_addresses != null) { 73 addresses = new HostAddress[new_addresses.length]; 74 for (int i = 0; i < new_addresses.length; i++) { 75 if (new_addresses[i] == null) { 76 throw new IOException("Cannot create a HostAddress"); 77 } else { 78 addresses[i] = (HostAddress)new_addresses[i].clone(); 79 } 80 } 81 } 82 } 83 84 public HostAddresses() throws UnknownHostException { 85 addresses = new HostAddress[1]; 86 addresses[0] = new HostAddress(); 87 } 88 89 private HostAddresses(int dummy) {} 90 91 public HostAddresses(PrincipalName serverPrincipal) 92 throws UnknownHostException, KrbException { 93 94 String[] components = serverPrincipal.getNameStrings(); 95 96 if (serverPrincipal.getNameType() != PrincipalName.KRB_NT_SRV_HST || 97 components.length < 2) 98 throw new KrbException(Krb5.KRB_ERR_GENERIC, "Bad name"); 99 100 String host = components[1]; 101 InetAddress[] addr = InetAddress.getAllByName(host); 102 HostAddress[] hAddrs = new HostAddress[addr.length]; 103 104 for (int i = 0; i < addr.length; i++) { 105 hAddrs[i] = new HostAddress(addr[i]); 106 } 107 108 addresses = hAddrs; 109 } 110 111 public Object clone() { 112 HostAddresses new_hostAddresses = new HostAddresses(0); 113 if (addresses != null) { 114 new_hostAddresses.addresses = new HostAddress[addresses.length]; 115 for (int i = 0; i < addresses.length; i++) { 116 new_hostAddresses.addresses[i] = 117 (HostAddress)addresses[i].clone(); 118 } 119 } 120 return new_hostAddresses; 121 } 122 123 public boolean inList(HostAddress addr) { 124 if (addresses != null) { 125 for (int i = 0; i < addresses.length; i++) 126 if (addresses[i].equals(addr)) 127 return true; 128 } 129 return false; 130 } 131 132 public int hashCode() { 133 if (hashCode == 0) { 134 int result = 17; 135 if (addresses != null) { 136 for (int i=0; i < addresses.length; i++) { 137 result = 37*result + addresses[i].hashCode(); 138 } 139 } 140 hashCode = result; 141 } 142 return hashCode; 143 144 } 145 146 147 public boolean equals(Object obj) { 148 if (this == obj) { 149 return true; 150 } 151 152 if (!(obj instanceof HostAddresses)) { 153 return false; 154 } 155 156 HostAddresses addrs = (HostAddresses)obj; 157 if ((addresses == null && addrs.addresses != null) || 158 (addresses != null && addrs.addresses == null)) 159 return false; 160 if (addresses != null && addrs.addresses != null) { 161 if (addresses.length != addrs.addresses.length) 162 return false; 163 for (int i = 0; i < addresses.length; i++) 164 if (!addresses[i].equals(addrs.addresses[i])) 165 return false; 166 } 167 return true; 168 } 169 170 /** 171 * Constructs a new <code>HostAddresses</code> object. 172 * @param encoding a single DER-encoded value. 173 * @exception Asn1Exception if an error occurs while decoding an 174 * ASN1 encoded data. 175 * @exception IOException if an I/O error occurs while reading 176 * encoded data. 177 */ 178 public HostAddresses(DerValue encoding) 179 throws Asn1Exception, IOException { 180 Vector<HostAddress> tempAddresses = new Vector<>(); 181 DerValue der = null; 182 while (encoding.getData().available() > 0) { 183 der = encoding.getData().getDerValue(); 184 tempAddresses.addElement(new HostAddress(der)); 185 } 186 if (tempAddresses.size() > 0) { 187 addresses = new HostAddress[tempAddresses.size()]; 188 tempAddresses.copyInto(addresses); 189 } 190 } 191 192 193 /** 194 * Encodes a <code>HostAddresses</code> object. 195 * @return byte array of encoded <code>HostAddresses</code> object. 196 * @exception Asn1Exception if an error occurs while decoding an 197 * ASN1 encoded data. 198 * @exception IOException if an I/O error occurs while reading 199 * encoded data. 200 */ 201 public byte[] asn1Encode() throws Asn1Exception, IOException { 202 DerOutputStream bytes = new DerOutputStream(); 203 DerOutputStream temp = new DerOutputStream(); 204 205 if (addresses != null && addresses.length > 0) { 206 for (int i = 0; i < addresses.length; i++) 207 bytes.write(addresses[i].asn1Encode()); 208 } 209 temp.write(DerValue.tag_Sequence, bytes); 210 return temp.toByteArray(); 211 } 212 213 /** 214 * Parse (unmarshal) a <code>HostAddresses</code> from a DER input stream. 215 * This form 216 * parsing might be used when expanding a value which is part of 217 * a constructed sequence and uses explicitly tagged type. 218 * 219 * @exception Asn1Exception if an Asn1Exception occurs. 220 * @param data the Der input stream value, which contains one or more 221 * marshaled value. 222 * @param explicitTag tag number. 223 * @param optional indicates if this data field is optional. 224 * @return an instance of <code>HostAddresses</code>. 225 */ 226 public static HostAddresses parse(DerInputStream data, 227 byte explicitTag, boolean optional) 228 throws Asn1Exception, IOException { 229 if ((optional) && 230 (((byte)data.peekByte() & (byte)0x1F) != explicitTag)) 231 return null; 232 DerValue der = data.getDerValue(); 233 if (explicitTag != (der.getTag() & (byte)0x1F)) { 234 throw new Asn1Exception(Krb5.ASN1_BAD_ID); 235 } else { 236 DerValue subDer = der.getData().getDerValue(); 237 return new HostAddresses(subDer); 238 } 239 } 240 241 /** 242 * Writes data field values in <code>HostAddresses</code> in FCC 243 * format to a <code>CCacheOutputStream</code>. 244 * 245 * @param cos a <code>CCacheOutputStream</code> to be written to. 246 * @exception IOException if an I/O exception occurs. 247 * @see sun.security.krb5.internal.ccache.CCacheOutputStream 248 */ 249 250 public void writeAddrs(CCacheOutputStream cos) throws IOException { 251 if (addresses == null || addresses.length == 0) { 252 cos.write32(0); 253 return; 254 } 255 cos.write32(addresses.length); 256 for (int i = 0; i < addresses.length; i++) { 257 cos.write16(addresses[i].addrType); 258 cos.write32(addresses[i].address.length); 259 cos.write(addresses[i].address, 0, 260 addresses[i].address.length); 261 } 262 } 263 264 265 public InetAddress[] getInetAddresses() { 266 267 if (addresses == null || addresses.length == 0) 268 return null; 269 270 ArrayList<InetAddress> ipAddrs = new ArrayList<>(addresses.length); 271 272 for (int i = 0; i < addresses.length; i++) { 273 try { 274 if ((addresses[i].addrType == Krb5.ADDRTYPE_INET) || 275 (addresses[i].addrType == Krb5.ADDRTYPE_INET6)) { 276 ipAddrs.add(addresses[i].getInetAddress()); 277 } 278 } catch (java.net.UnknownHostException e) { 279 // Should not happen since IP address given 280 return null; 281 } 282 } 283 284 InetAddress[] retVal = new InetAddress[ipAddrs.size()]; 285 return ipAddrs.toArray(retVal); 286 287 } 288 289 /** 290 * Returns all the IP addresses of the local host. 291 */ 292 public static HostAddresses getLocalAddresses() throws IOException 293 { 294 Set<InetAddress> all = new LinkedHashSet<>(); 295 try { 296 if (DEBUG) { 297 System.out.println(">>> KrbKdcReq local addresses are:"); 298 } 299 String extra = Config.getInstance().getAll( 300 "libdefaults", "extra_addresses"); 301 if (extra != null) { 302 for (String s: extra.split("\\s+")) { 303 all.add(InetAddress.getByName(s)); 304 if (DEBUG) { 305 System.out.println(" extra_addresses: " 306 + InetAddress.getByName(s)); 307 } 308 } 309 } 310 for (NetworkInterface ni: 311 Collections.list(NetworkInterface.getNetworkInterfaces())) { 312 if (DEBUG) { 313 System.out.println(" NetworkInterface " + ni + ":"); 314 System.out.println(" " 315 + Collections.list(ni.getInetAddresses())); 316 } 317 all.addAll(Collections.list(ni.getInetAddresses())); 318 } 319 return new HostAddresses(all.toArray(new InetAddress[all.size()])); 320 } catch (Exception exc) { 321 throw new IOException(exc.toString()); 322 } 323 } 324 325 /** 326 * Creates a new HostAddresses instance from the supplied list 327 * of InetAddresses. 328 */ 329 public HostAddresses(InetAddress[] inetAddresses) 330 { 331 if (inetAddresses == null) 332 { 333 addresses = null; 334 return; 335 } 336 337 addresses = new HostAddress[inetAddresses.length]; 338 for (int i = 0; i < inetAddresses.length; i++) 339 addresses[i] = new HostAddress(inetAddresses[i]); 340 } 341 342 @Override 343 public String toString() { 344 return Arrays.toString(addresses); 345 } 346} 347