001 /* 002 * Sonar, open source software quality management tool. 003 * Copyright (C) 2008-2012 SonarSource 004 * mailto:contact AT sonarsource DOT com 005 * 006 * Sonar is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 3 of the License, or (at your option) any later version. 010 * 011 * Sonar is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public 017 * License along with Sonar; if not, write to the Free Software 018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 019 */ 020 package org.sonar.server.platform; 021 022 import com.google.common.collect.Lists; 023 import org.apache.commons.codec.digest.DigestUtils; 024 import org.apache.commons.lang.StringUtils; 025 import org.slf4j.LoggerFactory; 026 027 import java.io.UnsupportedEncodingException; 028 import java.net.InetAddress; 029 import java.net.NetworkInterface; 030 import java.net.SocketException; 031 import java.net.UnknownHostException; 032 import java.util.Enumeration; 033 import java.util.List; 034 035 /** 036 * @since 2.11 037 */ 038 public class ServerIdGenerator { 039 040 /** 041 * Increment this version each time the algorithm is changed. Do not exceed 9. 042 */ 043 static final String VERSION = "1"; 044 045 static final int CHECKSUM_SIZE = 14; 046 047 private final boolean acceptPrivateAddress; 048 049 public ServerIdGenerator() { 050 this(false); 051 } 052 053 ServerIdGenerator(boolean acceptPrivateAddress) { 054 this.acceptPrivateAddress = acceptPrivateAddress; 055 } 056 057 public String generate(String organisation, String ipAddress) { 058 String id = null; 059 if (StringUtils.isNotBlank(organisation) && StringUtils.isNotBlank(ipAddress)) { 060 InetAddress inetAddress = toValidAddress(ipAddress); 061 if (inetAddress != null) { 062 id = toId(organisation, inetAddress); 063 } 064 } 065 return id; 066 } 067 068 boolean isFixed(InetAddress address) { 069 // Loopback addresses are in the range 127/8. 070 // Link local addresses are in the range 169.254/16 (IPv4) or fe80::/10 (IPv6). They are "autoconfiguration" addresses. 071 // They can assigned pseudorandomly, so they don't guarantee to be the same between two server startups. 072 return acceptPrivateAddress || (!address.isLoopbackAddress() && !address.isLinkLocalAddress()); 073 } 074 075 String toId(String organisation, InetAddress address) { 076 String id = new StringBuilder().append(organisation).append("-").append(address.getHostAddress()).toString(); 077 try { 078 return VERSION + DigestUtils.shaHex(id.getBytes("UTF-8")).substring(0, CHECKSUM_SIZE); 079 080 } catch (UnsupportedEncodingException e) { 081 throw new IllegalArgumentException("Organisation is not UTF-8 encoded: " + organisation, e); 082 } 083 } 084 085 public InetAddress toValidAddress(String ipAddress) { 086 if (StringUtils.isNotBlank(ipAddress)) { 087 List<InetAddress> validAddresses = getAvailableAddresses(); 088 try { 089 InetAddress address = InetAddress.getByName(ipAddress); 090 if (validAddresses.contains(address)) { 091 return address; 092 } 093 } catch (UnknownHostException e) { 094 // ignore, not valid property 095 } 096 } 097 return null; 098 } 099 100 public List<InetAddress> getAvailableAddresses() { 101 List<InetAddress> result = Lists.newArrayList(); 102 try { 103 Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces(); 104 while (networkInterfaces.hasMoreElements()) { 105 NetworkInterface networkInterface = networkInterfaces.nextElement(); 106 Enumeration<InetAddress> addresses = networkInterface.getInetAddresses(); 107 while (addresses.hasMoreElements()) { 108 InetAddress ownedAddress = addresses.nextElement(); 109 if (isFixed(ownedAddress)) { 110 result.add(ownedAddress); 111 } 112 } 113 } 114 } catch (SocketException e) { 115 LoggerFactory.getLogger(ServerIdGenerator.class).error("Fail to browse network interfaces", e); 116 } 117 return result; 118 } 119 }