package er.extensions.net; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.UnknownHostException; import java.text.DecimalFormat; import java.util.Enumeration; import java.util.StringTokenizer; import java.util.regex.Pattern; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.webobjects.foundation.NSArray; import com.webobjects.foundation.NSComparator; import com.webobjects.foundation.NSMutableArray; import er.extensions.foundation.ERXArrayUtilities; import er.extensions.foundation.ERXProperties; import er.extensions.foundation.ERXStringUtilities; import er.extensions.foundation.ERXValueUtilities; /** * <div class="ja"> * ネットワーク関連のツール類 * 特に TCP/IP * </div> */ public class ERXTcpIp { private static final Logger log = LoggerFactory.getLogger(ERXTcpIp.class); //******************************************************************** // プロパティー //******************************************************************** /** * <div class="ja">Internet Protocol バージョン 4 (IPv4) アドレスエラー値 -> -1</div> */ public static final long INET4_IPADDRESS_ERROR_LONG = -1; /** * <div class="ja"> * Internet Protocol バージョン 4 (IPv4) アドレスを数字(long)にしたときの最小値 * 0.0.0.0 = 0*256*256*256 + 0*256*256 + 0*256 + 0 = 0 * </div> */ public static final long INET4_IPADDRESS_MINIMUM_LONG = 0; /** * <div class="ja"> * Internet Protocol バージョン 4 (IPv4) アドレスを数字(long)にしたときの最大値 * 255.255.255.255 = 255*256*256*256 + 255*256*256 + 255*256 + 255 = 4294967295 * </div> */ public static final long INET4_IPADDRESS_MAXIMUM_LONG = 255L*256L*256L*256L + 255L*256L*256L + 255L*256L + 255L; /** * <div class="ja"> * Internet Protocol バージョン 4 (IPv4) アドレス正規表現パターン * 「0.0.0.0」 * "[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}" * </div> */ public static final String INET4_IPADDRESS_PATTERN_STR = "([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})"; public static final Pattern INET4_IPADDRESS_PATTERN = Pattern.compile(INET4_IPADDRESS_PATTERN_STR); /** * <div class="ja">INET : ローカル・アドレス</div> */ public static final String LOCAL_IP_ADDRESS = "127.0.0.1"; /** * <div class="ja">ET定数:. (ドット) </div> */ private static final String _DOT = "."; /** * <div class="ja"> * 特殊記号やコントロールコードなど基本的な定数 * 『 _ 』:_ アンダーバー * </div> */ public static final String UNDER_BAR = "_"; /** * <div class="ja">NET定数:"000" IPアドレス数字フォーマット </div> */ private static final DecimalFormat _3DIGIT_FORMAT = new DecimalFormat("000"); //******************************************************************** // Methods //******************************************************************** /** * <div class="ja"> * Internet Protocol バージョン 4 (IPv4) アドレス(文字列)をフォーマット。 * 入力値の各IP値(0〜255)の桁数を0で埋めた3文字にフォーマットする。 *  入力値: 0.0.0.0 *  出力値: 000.000.000.000 * * @param aIPstr - IPアドレスの文字列形式は「0.0.0.0」〜「255.255.255.255」のみ。 * * @return Stringフォーマット後の文字列。 null:IPアドレスが正しくないとき * </div> */ public static String inet4IpAddressTo3digitFromat(String aIPstr){ if(inet4IpAddressToLong(aIPstr) == INET4_IPADDRESS_ERROR_LONG) return null; String ipStr = null; if(ERXStringUtilities.stringIsNullOrEmpty(aIPstr)) return ipStr; StringTokenizer tempStringTokenizer = new StringTokenizer(aIPstr,_DOT); long countToken = tempStringTokenizer.countTokens(); if( countToken == 4 ){ // 4 digit時処理 try{ long ip1 = Long.parseLong(tempStringTokenizer.nextToken()); long ip2 = Long.parseLong(tempStringTokenizer.nextToken()); long ip3 = Long.parseLong(tempStringTokenizer.nextToken()); long ip4 = Long.parseLong(tempStringTokenizer.nextToken()); ipStr = _3DIGIT_FORMAT.format(ip1) + _DOT + _3DIGIT_FORMAT.format(ip2) + _DOT + _3DIGIT_FORMAT.format(ip3) + _DOT + _3DIGIT_FORMAT.format(ip4); } catch ( Exception e ){ // 「null」値を返す } } return ipStr; } /** * <div class="ja"> * Internet Protocol バージョン 4 (IPv4) アドレス(文字列)を数字(long)に変換。 * 各桁が「0〜255」の範囲外なら-1:IPアドレスの指定ミスを返す。 * * @param aIPstr - IPアドレスの文字列形式は「0.0.0.0」〜「255.255.255.255」のみ。 * * @return long 変換後のIPアドレス数値。-1:IPアドレスの指定ミス。 * </div> */ public static long inet4IpAddressToLong(String aIPstr){ long ip = INET4_IPADDRESS_ERROR_LONG; if(ERXStringUtilities.stringIsNullOrEmpty(aIPstr)) return ip; StringTokenizer tempStringTokenizer = new StringTokenizer(aIPstr,_DOT); long countToken = tempStringTokenizer.countTokens(); if( countToken == 4 ){ // 4 digit時処理 try{ long ip1 = Long.parseLong(tempStringTokenizer.nextToken()); if((ip1 >= 0) && (ip1 <= 255)){ long ip2 = Long.parseLong(tempStringTokenizer.nextToken()); if((ip2 >= 0) && (ip2 <= 255)){ long ip3 = Long.parseLong(tempStringTokenizer.nextToken()); if((ip3 >= 0) && (ip3 <= 255)){ long ip4 = Long.parseLong(tempStringTokenizer.nextToken()); if((ip4 >= 0) && (ip4 <= 255)){ ip = (ip1 * 256 * 256 * 256) + (ip2 * 256 * 256) +(ip3 * 256) +(ip4) ; } } } } } catch ( Exception e ){ // 「INET4_IPADDRESS_ERROR_LONG」値を返す } } return (ip <= INET4_IPADDRESS_MAXIMUM_LONG) ? ip: INET4_IPADDRESS_ERROR_LONG; } /** * <div class="ja"> * 指定したInternet Protocol バージョン 4 (IPv4) アドレス(long)が範囲内かの判断。 * 判断ロジック * ((INET4_IPADDRESS_MINIMUM_LONG <= ipl) && (ipl <= INET4_IPADDRESS_MAXIIMUM_LONG)) * * @param ipl - IPアドレスの数値。 * * @return boolean true:範囲内のIPアドレス * </div> */ public static boolean isInet4IPAddressRange( long ipl ){ return ((INET4_IPADDRESS_MINIMUM_LONG <= ipl) && (ipl <= INET4_IPADDRESS_MAXIMUM_LONG)); } /** * <div class="ja"> * 指定したInternet Protocol バージョン 4 (IPv4) アドレス(文字列)が範囲内かの判断。 * 判断ロジック * ((INET4_IPADDRESS_MINIMUM_LONG <= ipl) && (ipl <= INET4_IPADDRESS_MAXIIMUM_LONG)) * * @param ipStr - IPアドレスの文字列。「0.0.0.0」〜「255.255.255.255」のみ。 * @return boolean true:範囲内のIPアドレス * </div> */ public static boolean isInet4IPAddressRange( String ipStr ){ return isInet4IPAddressRange(inet4IpAddressToLong(ipStr)); } /** * <div class="ja"> * 指定したInternet Protocol バージョン 4 (IPv4) アドレス(long)が指定した範囲内かの判断。 * 判断ロジック * 次の場合には直ぐに範囲外 *   ipStartが範囲外 or ipが範囲外 or ipが範囲外 * 3つの指定IPが範囲内の時に次の判断を実施 * ((ipStart <= ip) && (ip <= ipEnd)) * * @param ipStart - IPアドレス-開始。 * @param ip - IPアドレス-比較。 * @param ipEnd - IPアドレス-終了。 * * @return boolean true:範囲内のIPアドレス * </div> */ public static boolean isInet4IPAddressWithinRange( long ipStart, long ip, long ipEnd ){ if(!isInet4IPAddressRange(ipStart) || !isInet4IPAddressRange(ip) || !isInet4IPAddressRange(ipEnd)) return false; return ((ipStart <= ip) && (ip <= ipEnd)); } /** * <div class="ja"> * 指定したInternet Protocol バージョン 4 (IPv4) アドレス(文字列)が指定した範囲内かの判断。 * 判断ロジック * 次の場合には直ぐに範囲外 *   ipStrStartが範囲外 or ipStrが範囲外 or ipEndが範囲外 * 3つの指定IPが範囲内の時に次の判断を実施 * ((ipStrStart <= ipStr) && (ipStr <= ipStrEnd)) * * @param ipStrStart - IPアドレスの文字列-開始。「0.0.0.0」〜「255.255.255.255」のみ。 * @param ipStr - IPアドレスの文字列-比較。「0.0.0.0」〜「255.255.255.255」のみ。 * @param ipStrEnd - IPアドレスの文字列-終了。「0.0.0.0」〜「255.255.255.255」のみ。 * * @return boolean true:範囲内のIPアドレス * </div> */ public static boolean isInet4IPAddressWithinRange( String ipStrStart, String ipStr, String ipStrEnd ){ long ipStart = inet4IpAddressToLong(ipStrStart); long ip = inet4IpAddressToLong(ipStr); long ipEnd = inet4IpAddressToLong(ipStrEnd); return isInet4IPAddressWithinRange(ipStart, ip, ipEnd); } /** * <div class="ja"> * マシンで設定されているIPリストを取得します。 * 環境設定については: A10Properties. InIpRangeOperatorを参照 * * @return IP 配列が戻ります * </div> */ public static NSArray<String> machineIpList() { // この関数は WOApplication がインスタンス化される前に実行されるので、ログ出力は標準ではない if(ERXArrayUtilities.arrayIsNullOrEmpty(_machineIpList)) { // プロパティー内でどの IP を使用するかどうかを読込みます。 String machineIp = ERXProperties.stringFor2Keys("er.erxtensions.ERXTcpIp.UseThisIp", "wodka.a10.A10TcpIp.UseThisIp"); try { // プロパティーがなければ、自動設定を行う if(ERXStringUtilities.stringIsNullOrEmpty(machineIp)){ log.debug("MachineIp Automatic Mode"); // マシンIPを得る if(ERXArrayUtilities.arrayIsNullOrEmpty(_machineIpList)) _machineIpList = _machineIpList(); // 処理不能 ?? if(ERXArrayUtilities.arrayIsNullOrEmpty(_machineIpList)) { String noIpAndNoNetwork = ERXProperties.stringFor2Keys("er.erxtensions.ERXTcpIp.NoIpAndNoNetwork", "wodka.a10.A10TcpIp.NoIpAndNoNetwork"); // No IP と No ネットワークも設定されていなければ、ローカル IP を使用する if(ERXStringUtilities.stringIsNullOrEmpty(noIpAndNoNetwork)) noIpAndNoNetwork = LOCAL_IP_ADDRESS; // 使用する IP をセットします _machineIpList = new NSArray<>( new String[] {noIpAndNoNetwork}); log.warn("No IpAddress --- no network! use Address : {}", noIpAndNoNetwork); } } else { // 使用する IP をセットします _machineIpList = new NSArray<>( new String[] {machineIp}); } } catch (Exception e) { // ここでの処理失敗は致命的 log.error( "getIpAddress error!!!" ); _machineIpList = new NSArray<>( new String[] {LOCAL_IP_ADDRESS}); } if(log.isInfoEnabled()) log.info( "MachineIp {} is in use.", ERXArrayUtilities.arrayToLogstring(_machineIpList)); } return _machineIpList; } /** * <div class="ja">動作マシンが所有しているIPアドレス保持用変数:キャシュ用</div> */ private static NSArray<String> _machineIpList = NSArray.EmptyArray; /** * <div class="ja"> * ネットワークインアーフェースからIP一覧を得る * * @return 動作マシンのネットワーク設定が所有しているIPアドレス配列 * * @exception Exception * </div> */ private static NSArray<String> _machineIpList() throws Exception { // ワーク用 NSMutableArray<String> workArray = new NSMutableArray<>(); // 全ネットワーク・インタフェース Enumeration<NetworkInterface> enNi = NetworkInterface.getNetworkInterfaces(); while( enNi.hasMoreElements() ){ NetworkInterface ni = enNi.nextElement(); // 全 InetAddress Enumeration<InetAddress> enIp = ni.getInetAddresses(); while( enIp.hasMoreElements() ){ String ip = enIp.nextElement().getHostAddress(); // IP アドレスとプロパティー内に保存されている優先順を合体する if( ( ip.indexOf( ":" ) < 0 )&&( !ip.equals( LOCAL_IP_ADDRESS ) )){ String ipPri = ERXProperties.stringFor2Keys("er.erxtensions.ERXTcpIp.IpPriority" + ip, "wodka.a10.A10TcpIp.IpPriority" + ip); if(ERXStringUtilities.stringIsNullOrEmpty(ipPri)) { ipPri = "9999"; } else { ipPri = ERXStringUtilities.trimZeroInFrontOfNumbers(ipPri); while( ipPri.length() < 4 ){ ipPri = "0" + ipPri; } } workArray.addObject(ipPri + UNDER_BAR + ip); } } } // 優先順位順に並べ、IPのみ抜き出してArrayListにする workArray.sortUsingComparator(NSComparator.AscendingStringComparator); // 戻す配列の準備 NSMutableArray<String> resultArray = new NSMutableArray<>(workArray.count()); for(String obj : workArray) { resultArray.addObject(obj.substring(5)); } return resultArray.immutableClone(); } /** * <div class="ja"> * ドメイン又は ip リストを全件表示するドメイン又は ip リストに変換します * * 例: * www.ksroom.com はそのままで戻る * 1.2.3.4 はそのままで戻る * 1.2.3.4-6 は (1.2.3.4, 1.2.3.5, 1.2.3.6) として戻る * * @param data - NSArray<String> ドメイン又は ip リスト * * @return 全件のドメイン又は ip リスト * </div> */ public static NSArray<String> fullDomainIpList(NSArray<String> data) { NSMutableArray<String> results = new NSMutableArray<>(data.count()); for (String string : data) { if(ERXStringUtilities.stringIsNullOrEmpty(string)) { continue; } // 文字で始まるドメイン char firstLetter = string.charAt(0); if(!StringUtils.isNumeric("" + firstLetter)) { results.addObject(string); // IP を調査し追加すること InetAddress addr; try { addr = InetAddress.getByName(string); if(addr != null) results.addObject(addr.getHostAddress()); } catch (UnknownHostException e) { e.printStackTrace(); } continue; } // 数字で始まる普通のドメイン又は、IPアドレス if(!string.contains("-")) { results.addObject(string); continue; } // 数字で始まる又は - を持つドメイン NSArray<String> bubuns = NSArray.componentsSeparatedByString(string, "-"); if(bubuns.count() != 2) { // 複数の "-" がある results.addObject(string); continue; } String startIP = ERXTcpIp.inet4IpAddressTo3digitFromat(bubuns.objectAtIndex(0)); // 正しい IP ? if(ERXStringUtilities.stringIsNullOrEmpty(startIP)) { results.addObject(string); continue; } // IP 追加処理 long endIp = ERXValueUtilities.longValue(bubuns.objectAtIndex(1)); StringTokenizer tempStringTokenizer = new StringTokenizer(startIP, "."); long countToken = tempStringTokenizer.countTokens(); if(countToken == 4){ // 4 digit時処理 try{ long ip1 = Long.parseLong(tempStringTokenizer.nextToken()); long ip2 = Long.parseLong(tempStringTokenizer.nextToken()); long ip3 = Long.parseLong(tempStringTokenizer.nextToken()); long ip4 = Long.parseLong(tempStringTokenizer.nextToken()); for(long i = ip4; i <= endIp; i++) { String ipStr = "" + ip1 + _DOT + ip2 + _DOT +ip3 + _DOT + i; results.addObject(ipStr); } } catch ( Exception e ){ } } } return results.immutableClone(); } }