Hi, wroot.
I found that the smackx only got the IP address in the first Network Interface using method:
java.net.InetAddress.getLocalHost().
The source code is here:
Line 99 in class org.jivesoftware.smackx.bytestreams.socks.Socks5Proxy.
The original source code is:
/**
* Private constructor.
*/
private Socks5Proxy() {
this.serverProcess = new Socks5ServerProcess(); // add default local address
try {
this.localAddresses.add(InetAddress.getLocalHost().getHostAddress());
}
catch (UnknownHostException e) {
// do nothing
} }
I don’t think it’s intelligent to code like this.
If I have multi-network interface in my computer, the method getLocalHost() gets only the first IP for the first network interface.
I think it should be optional for users. If users do not point out which IP to use, we can use getLocalHost() to get the local internet address. But if users want to bind Spark at the specific IP, there should be a way for users to do this.
So, I modified the code as:
/**
* Private constructor.
*/
private Socks5Proxy() {
this.serverProcess = new Socks5ServerProcess(); // add default local address
try {
InetAddress localHost;
try {
localHost = getInetAddress();
if(localHost == null){
localHost = InetAddress.getLocalHost();
}
} catch (IOException e) {
localHost = InetAddress.getLocalHost();
e.printStackTrace();
} this.localAddresses.add(localHost.getHostAddress());
}
catch (UnknownHostException e) {
// do nothing
} }
and the method getInetAddress is just as below:
/**
* Returns the local IP address
* Author Michael Pan
*/
private InetAddress getInetAddress() throws IOException{
File patchFile = new File("patch.dat");
BufferedReader br = new BufferedReader(new FileReader(patchFile));
String str = null;
InetAddress inetAddr = null;
while((str = br.readLine()) != null){
str = str.trim();
if(str.startsWith("#")) continue;
str = str.toUpperCase();
str = str.replaceAll(" ", "");
str = str.replaceAll("\t", "");
if(str.startsWith("IP:")){
inetAddr= InetAddress.getByName(str.substring(3));
if(inetAddr != null) break;
}else if(str.startsWith("IPV6:")){
str = str.replaceAll("-", ":");
inetAddr = InetAddress.getByName(str.substring(5));
if(inetAddr != null) break;
}else if(str.startsWith("MAC:")){
str = str.substring(4);
str = str.replaceAll(":", "");
str = str.replaceAll("-", ""); String hostName;
InetAddress localHost;
InetAddress[] localAddresses; localHost = InetAddress.getLocalHost();
hostName = localHost.getHostName(); localAddresses = InetAddress.getAllByName(hostName);
if (localAddresses == null || localAddresses.length == 0) continue; for (int i = 0; i < localAddresses.length; i++) {
localHost = localAddresses[i];
NetworkInterface nic = NetworkInterface.getByInetAddress(localHost);
byte[]mac = nic.getHardwareAddress();
if(mac == null) continue;
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
for(int j=0; j < mac.length; j++){
pw.printf("%2X", mac[j]);
}
if(sw.toString().equals(str)){
inetAddr = localHost;
break;
}
}
}
}
br.close();
return inetAddr;
}
The format of patch.dat is like this:
# please enter your local IP(both IPv4 and IPv6 are OK) or MAC address.
# comment with '#'
IP: 172.18.8.54
#IPv6: 2001:da8:1002:a537:8c02:c337:8649:2619
#MAC: 84-2B-2B-AB-14-D0
Of cource, I just give a simple method for bind Spark at a specific IP as a temporary solution for my Spark. It will be better to add a choosing panel in Spark Settings. Sorry to say that I have little time to read Spark UI codes now and I don’t know how to add a panel in Spark codes till now. I hope that developers could think about it.
Thanks!
Original_Socks5Proxy_Smackx_3_2_0.zip (4165 Bytes)
Modified_Socks5Proxy_Smackx_3_2_0.zip (4803 Bytes)
patch.dat.zip (282 Bytes)