001/** 002 * 003 * Copyright 2019-2023 Florian Schmaus 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.jivesoftware.smack.util; 018 019import java.net.Inet4Address; 020import java.net.Inet6Address; 021import java.net.InetAddress; 022import java.net.UnknownHostException; 023 024import org.minidns.dnslabel.DnsLabel; 025import org.minidns.dnsname.DnsName; 026import org.minidns.dnsname.InvalidDnsNameException; 027import org.minidns.util.InetAddressUtil; 028 029/** 030 * An internet address, can be given as IP or as DNS name. 031 * <p> 032 * This type is meant for strings that hold an internet address. The original string used to construct this type is 033 * stored and returning in the {@link #toString()} method. 034 * </p> 035 * 036 * @since 4.4.0 037 */ 038public abstract class InternetAddress implements CharSequence { 039 040 protected final String originalString; 041 042 protected InternetAddress(String originalString) { 043 this.originalString = Objects.requireNonNull(originalString, "The 'originalString' argument must not be null"); 044 } 045 046 public abstract InetAddress asInetAddress() throws UnknownHostException; 047 048 @Override 049 public String toString() { 050 return originalString; 051 } 052 053 @Override 054 public int length() { 055 return originalString.length(); 056 } 057 058 @Override 059 public char charAt(int index) { 060 return originalString.charAt(index); 061 } 062 063 @Override 064 public CharSequence subSequence(int start, int end) { 065 return originalString.subSequence(start, end); 066 } 067 068 public String getRaw() { 069 return originalString; 070 } 071 072 public static InternetAddress fromIgnoringZoneId(String address) { 073 return from(address, true); 074 } 075 076 public static InternetAddress from(String address) { 077 return from(address, false); 078 } 079 080 private static InternetAddress from(String address, boolean ignoreZoneId) { 081 String raw = address; 082 if (ignoreZoneId) { 083 int percentPosition = address.indexOf('%'); 084 if (percentPosition > 1) { 085 address = address.substring(0, percentPosition); 086 } 087 } 088 089 final InternetAddress internetAddress; 090 if (InetAddressUtil.isIpV4Address(address)) { 091 internetAddress = new InternetAddress.Ipv4(address, raw); 092 } else if (InetAddressUtil.isIpV6Address(address)) { 093 internetAddress = new InternetAddress.Ipv6(address, raw); 094 } else if (address.contains(".")) { 095 InternetAddress domainNameInternetAddress; 096 try { 097 DnsName dnsName = DnsName.from(address); 098 domainNameInternetAddress = new InternetAddress.DomainName(address, dnsName); 099 } catch (InvalidDnsNameException e) { 100 domainNameInternetAddress = new InternetAddress.InvalidDomainName(address, e); 101 } 102 internetAddress = domainNameInternetAddress; 103 } else { 104 DnsLabel dnsLabel = DnsLabel.from(address); 105 internetAddress = new InternetAddress.DomainNameLabel(address, dnsLabel); 106 } 107 return internetAddress; 108 } 109 110 public static InternetAddress from(InetAddress inetAddress) { 111 if (inetAddress instanceof Inet4Address) { 112 return new InternetAddress.Ipv4(inetAddress.getHostAddress(), (Inet4Address) inetAddress); 113 } else if (inetAddress instanceof Inet6Address) { 114 return new InternetAddress.Ipv6(inetAddress.getHostAddress(), (Inet6Address) inetAddress); 115 } else { 116 throw new IllegalArgumentException("Unknown type " + inetAddress.getClass() + " of " + inetAddress); 117 } 118 } 119 120 private static class InetAddressInternetAddress extends InternetAddress { 121 private final InetAddress inetAddress; 122 private final String raw; 123 124 protected InetAddressInternetAddress(String originalString, String raw, InetAddress inetAddress) { 125 super(originalString); 126 this.raw = raw; 127 this.inetAddress = inetAddress; 128 } 129 130 @Override 131 public InetAddress asInetAddress() { 132 return inetAddress; 133 } 134 135 @Override 136 public final String getRaw() { 137 return raw; 138 } 139 } 140 141 public static final class Ipv4 extends InetAddressInternetAddress { 142 143 private final Inet4Address inet4Address; 144 145 private Ipv4(String originalString, String raw) { 146 this(originalString, raw, InetAddressUtil.ipv4From(originalString)); 147 } 148 149 private Ipv4(String originalString, Inet4Address inet4Address) { 150 this(originalString, originalString, inet4Address); 151 } 152 153 private Ipv4(String originalString, String raw, Inet4Address inet4Address) { 154 super(originalString, raw, inet4Address); 155 this.inet4Address = inet4Address; 156 } 157 158 public Inet4Address getInet4Address() { 159 return inet4Address; 160 } 161 } 162 163 public static final class Ipv6 extends InetAddressInternetAddress { 164 165 private Inet6Address inet6Address; 166 167 private Ipv6(String originalString, String raw) { 168 this(originalString, raw, InetAddressUtil.ipv6From(originalString)); 169 } 170 171 private Ipv6(String originalString, Inet6Address inet6Address) { 172 this(originalString, originalString, inet6Address); 173 } 174 175 private Ipv6(String originalString, String raw, Inet6Address inet6Address) { 176 super(originalString, raw, inet6Address); 177 this.inet6Address = inet6Address; 178 } 179 180 public Inet6Address getInet6Address() { 181 return inet6Address; 182 } 183 } 184 185 private static class NonNumericInternetAddress extends InternetAddress { 186 private boolean attemptedToResolveInetAddress; 187 private InetAddress inetAddress; 188 189 protected NonNumericInternetAddress(String originalString) { 190 super(originalString); 191 } 192 193 @Override 194 public InetAddress asInetAddress() throws UnknownHostException { 195 if (inetAddress != null || attemptedToResolveInetAddress) { 196 return inetAddress; 197 } 198 199 attemptedToResolveInetAddress = true; 200 inetAddress = InetAddress.getByName(originalString); 201 202 return inetAddress; 203 } 204 } 205 206 public static final class DomainName extends NonNumericInternetAddress { 207 208 private final DnsName dnsName; 209 210 private DomainName(String originalString, DnsName dnsName) { 211 super(originalString); 212 this.dnsName = dnsName; 213 } 214 215 public DnsName getDnsName() { 216 return dnsName; 217 } 218 219 } 220 221 public static final class DomainNameLabel extends NonNumericInternetAddress { 222 223 private final DnsLabel dnsLabel; 224 225 private DomainNameLabel(String originalString, DnsLabel dnsLabel) { 226 super(originalString); 227 this.dnsLabel = dnsLabel; 228 } 229 230 public DnsLabel getDnsLabel() { 231 return dnsLabel; 232 } 233 } 234 235 public static final class InvalidDomainName extends NonNumericInternetAddress { 236 237 private final InvalidDnsNameException invalidDnsNameException; 238 239 private InvalidDomainName(String originalString, InvalidDnsNameException invalidDnsNameException) { 240 super(originalString); 241 this.invalidDnsNameException = invalidDnsNameException; 242 } 243 244 public InvalidDnsNameException getInvalidDnsNameException() { 245 return invalidDnsNameException; 246 } 247 } 248}