001/*
002 * Copyright 2015-2018 the original author or authors
003 *
004 * This software is licensed under the Apache License, Version 2.0,
005 * the GNU Lesser General Public License version 2 or later ("LGPL")
006 * and the WTFPL.
007 * You may choose either license to govern your use of this software only
008 * upon the condition that you accept all of the terms of either
009 * the Apache License 2.0, the LGPL 2.1+ or the WTFPL.
010 */
011package org.minidns.util;
012
013import java.net.Inet4Address;
014import java.net.Inet6Address;
015import java.net.InetAddress;
016import java.net.UnknownHostException;
017import java.util.regex.Pattern;
018
019import org.minidns.dnsname.DnsName;
020
021public class InetAddressUtil {
022
023    public static Inet4Address ipv4From(CharSequence cs) {
024        InetAddress inetAddress;
025        try {
026            inetAddress = InetAddress.getByName(cs.toString());
027        } catch (UnknownHostException e) {
028            throw new IllegalArgumentException(e);
029        }
030        if (inetAddress instanceof Inet4Address) {
031            return (Inet4Address) inetAddress;
032        }
033        throw new IllegalArgumentException();
034    }
035
036    public static Inet6Address ipv6From(CharSequence cs) {
037        InetAddress inetAddress;
038        try {
039            inetAddress = InetAddress.getByName(cs.toString());
040        } catch (UnknownHostException e) {
041            throw new IllegalArgumentException(e);
042        }
043        if (inetAddress instanceof Inet6Address) {
044            return (Inet6Address) inetAddress;
045        }
046        throw new IllegalArgumentException();
047    }
048
049    // IPV4_REGEX from http://stackoverflow.com/a/46168/194894 by Kevin Wong (http://stackoverflow.com/users/4792/kevin-wong) licensed under
050    // CC BY-SA 3.0.
051    private final static Pattern IPV4_PATTERN = Pattern.compile("\\A(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}\\z");
052
053    public static boolean isIpV4Address(CharSequence address) {
054        if (address == null) {
055            return false;
056        }
057        return IPV4_PATTERN.matcher(address).matches();
058    }
059
060    // IPv6 Regular Expression from http://stackoverflow.com/a/17871737/194894 by David M. Syzdek
061    // (http://stackoverflow.com/users/903194/david-m-syzdek) licensed under CC BY-SA 3.0.
062    private final static Pattern IPV6_PATTERN = Pattern.compile(
063            "(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))");
064
065    public static boolean isIpV6Address(CharSequence address) {
066        if (address == null) {
067            return false;
068        }
069        return IPV6_PATTERN.matcher(address).matches();
070    }
071
072    public static boolean isIpAddress(CharSequence address) {
073        return isIpV6Address(address) || isIpV4Address(address);
074    }
075
076    public static DnsName reverseIpAddressOf(Inet6Address inet6Address) {
077        final String ipAddress = inet6Address.getHostAddress();
078        final String[] ipAddressParts = ipAddress.split(":");
079
080        String[] parts = new String[32];
081        int currentPartNum = 0;
082        for (int i = ipAddressParts.length - 1; i >= 0; i--) {
083            final String currentPart = ipAddressParts[i];
084            final int missingPlaces = 4 - currentPart.length();
085            for (int j = 0; j < missingPlaces; j++) {
086                parts[currentPartNum++] = "0";
087            }
088            for (int j = 0; j < currentPart.length(); j++) {
089                parts[currentPartNum++] = Character.toString(currentPart.charAt(j));
090            }
091        }
092
093        return DnsName.from(parts);
094    }
095
096    public static DnsName reverseIpAddressOf(Inet4Address inet4Address) {
097        final String[] ipAddressParts = inet4Address.getHostAddress().split("\\.");
098        assert(ipAddressParts.length == 4);
099
100        return DnsName.from(ipAddressParts);
101    }
102}