001/**
002 *
003 * Copyright 2019 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 static InternetAddress from(String address) {
069        final InternetAddress internetAddress;
070        if (InetAddressUtil.isIpV4Address(address)) {
071            internetAddress = new InternetAddress.Ipv4(address);
072        } else if (InetAddressUtil.isIpV6Address(address)) {
073            internetAddress = new InternetAddress.Ipv6(address);
074        } else if (address.contains(".")) {
075            InternetAddress domainNameInternetAddress;
076            try {
077                DnsName dnsName = DnsName.from(address);
078                domainNameInternetAddress = new InternetAddress.DomainName(address, dnsName);
079            } catch (InvalidDnsNameException e) {
080                domainNameInternetAddress = new InternetAddress.InvalidDomainName(address, e);
081            }
082            internetAddress = domainNameInternetAddress;
083        } else {
084            DnsLabel dnsLabel = DnsLabel.from(address);
085            internetAddress = new InternetAddress.DomainNameLabel(address, dnsLabel);
086        }
087        return internetAddress;
088    }
089
090    public static InternetAddress from(InetAddress inetAddress) {
091        if (inetAddress instanceof Inet4Address) {
092            return new InternetAddress.Ipv4(inetAddress.getHostAddress(), (Inet4Address) inetAddress);
093        } else if (inetAddress instanceof Inet6Address) {
094            return new InternetAddress.Ipv6(inetAddress.getHostAddress(), (Inet6Address) inetAddress);
095        } else {
096            throw new IllegalArgumentException("Unknown type " + inetAddress.getClass() + " of " + inetAddress);
097        }
098    }
099
100    private static class InetAddressInternetAddress extends InternetAddress {
101        private final InetAddress inetAddress;
102
103        protected InetAddressInternetAddress(String originalString, InetAddress inetAddress) {
104            super(originalString);
105            this.inetAddress = inetAddress;
106        }
107
108        @Override
109        public InetAddress asInetAddress() {
110            return inetAddress;
111        }
112    }
113
114    public static final class Ipv4 extends InetAddressInternetAddress {
115
116        private final Inet4Address inet4Address;
117
118        private Ipv4(String originalString) {
119            this(originalString, InetAddressUtil.ipv4From(originalString));
120        }
121
122        private Ipv4(String originalString, Inet4Address inet4Address) {
123            super(originalString, inet4Address);
124            this.inet4Address = inet4Address;
125        }
126
127        public Inet4Address getInet4Address() {
128            return inet4Address;
129        }
130    }
131
132    public static final class Ipv6 extends InetAddressInternetAddress {
133
134        private Inet6Address inet6Address;
135
136        private Ipv6(String originalString) {
137            this(originalString, InetAddressUtil.ipv6From(originalString));
138        }
139
140        private Ipv6(String originalString, Inet6Address inet6Address) {
141            super(originalString, inet6Address);
142            this.inet6Address = inet6Address;
143        }
144
145        public Inet6Address getInet6Address() {
146            return inet6Address;
147        }
148    }
149
150    private static class NonNumericInternetAddress extends InternetAddress {
151        private boolean attemptedToResolveInetAddress;
152        private InetAddress inetAddress;
153
154        protected NonNumericInternetAddress(String originalString) {
155            super(originalString);
156        }
157
158        @Override
159        public InetAddress asInetAddress() throws UnknownHostException {
160            if (inetAddress != null || attemptedToResolveInetAddress) {
161                return inetAddress;
162            }
163
164            attemptedToResolveInetAddress = true;
165            inetAddress = InetAddress.getByName(originalString);
166
167            return inetAddress;
168        }
169    }
170
171    public static final class DomainName extends NonNumericInternetAddress {
172
173        private final DnsName dnsName;
174
175        private DomainName(String originalString, DnsName dnsName) {
176            super(originalString);
177            this.dnsName = dnsName;
178        }
179
180        public DnsName getDnsName() {
181            return dnsName;
182        }
183
184    }
185
186    public static final class DomainNameLabel extends NonNumericInternetAddress {
187
188        private final DnsLabel dnsLabel;
189
190        private DomainNameLabel(String originalString, DnsLabel dnsLabel) {
191            super(originalString);
192            this.dnsLabel = dnsLabel;
193        }
194
195        public DnsLabel getDnsLabel() {
196            return dnsLabel;
197        }
198    }
199
200    public static final class InvalidDomainName extends NonNumericInternetAddress {
201
202        private final InvalidDnsNameException invalidDnsNameException;
203
204        private InvalidDomainName(String originalString, InvalidDnsNameException invalidDnsNameException) {
205            super(originalString);
206            this.invalidDnsNameException = invalidDnsNameException;
207        }
208
209        public InvalidDnsNameException getInvalidDnsNameException() {
210            return invalidDnsNameException;
211        }
212    }
213}