tomcat access log get my eth0 ip? - linux

<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern="%t %a %A %p %r %q %s %B %D %{User-Agent}i %{Referer}i"
resolveHosts="false" />
This is my server.xml ,then i found the result is like this:
[29/Mar/2017:10:36:16 +0800] 192.168.5.149 127.0.0.1 80 GET /favicon.ico HTTP/1.1 404 0 0 Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:52.0) Gecko/20100101 Firefox/52.0 -
in the server.xml %A just give me the loop ip, but i want eth0 ip ..
So what should i do? Thanks a lot!

Check host name:
$ hostname
yourhost
Edit /etc/hosts and add:
192.168.5.1 yourhost
FYI, Tomcat source code:
/**
* write local IP address - %A
*/
protected static class LocalAddrElement implements AccessLogElement {
private static final String LOCAL_ADDR_VALUE;
static {
String init;
try {
init = InetAddress.getLocalHost().getHostAddress();
} catch (Throwable e) {
ExceptionUtils.handleThrowable(e);
init = "127.0.0.1";
}
LOCAL_ADDR_VALUE = init;
}
#Override
public void addElement(StringBuilder buf, Date date, Request request,
Response response, long time) {
buf.append(LOCAL_ADDR_VALUE);
}
}

Related

Node.JS dns.reverse multiple nameservers

I have an issue with my Node.JS application.
For some reason, dns.reverse is only working with the first nameserver specified and ignoring the second one.
I have the following piece of code:
import Resolver from '~/classes/resolver';
Resolver.addNameServer('192.168.2.1', '192.168.1.254').boot();
Resolver.hostnameFromIP('192.168.1.30').then((hostname: string) => {
console.log(hostname);
}).catch((error) => {
console.log(error); // We are going to end up here as the 192.168.2.1 is the first and only nameserver which will be queried
});
And here is Resolver class:
import q, { Deferred } from 'q';
import dns from 'dns';
import { ResolverInterface } from '~/classes/resolver/interfaces';
/**
* Resolver class
*/
class Resolver implements ResolverInterface {
/**
* List of nameservers used for hostname resolution
* #type { string[] }
*/
public nameservers: string[] = [];
/**
* Add nameserver for resolver to use
* #param { string } nameserver
* #return { Resolver }
*/
public addNameServer(...nameserver: string[]) : Resolver {
this.nameservers.push(...nameserver);
return this;
}
/**
* Initialize resolver
* #return { void }
*/
public boot() : void {
if (this.nameservers.length === 0) {
this.initializeWithDefaultNameServers();
}
dns.setServers(this.nameservers);
}
/**
* Resolve hostname from the IP address
* #param { string } ip
* #return { q.Promise<string> }
*/
public hostnameFromIP(ip: string) : q.Promise<string> {
const deferred: Deferred<any> = q.defer();
dns.reverse(ip, (error: NodeJS.ErrnoException | null, hostnames: string[]) => {
const defaultErrorMessage: string = 'Unable to resolve hostname';
if (error) {
return deferred.reject(defaultErrorMessage);
}
let hostname: string = hostnames.length === 0 ? defaultErrorMessage : hostnames[0];
hostname = hostname.replace('.localdomain', '').trim();
deferred.resolve(hostname);
});
return deferred.promise as q.Promise<string>;
}
/**
* Initialize resolver with default nameservers
* #return { void }
* #private
*/
private initializeWithDefaultNameServers() : void {
const nameservers: string[] = [
'192.168.0.1',
'192.168.1.1',
'192.168.2.1',
];
nameservers.forEach((nameserver: string) : void => {
this.nameservers.push(nameserver);
});
}
}
export default new Resolver;
Expected behavior:
Application should go through all specified nameservers to resolve the hostname for specified IP address
Actual behavior:
Depending on which nameserver is first, only that nameserver will be queried for the hostname.
If 192.168.2.1 is first, i can query data for 192.168.2.10, but i cannot do that for 192.168.1.30.
If 192.168.1.254 is first, i can query data for 192.168.1.30, but i cannot do that for 192.168.2.10.
Is there a way to use all specified nameservers while doing reverse hostname lookup using dns.reverse in Node.JS?
Thanks for help to Jorge Fuentes González, here is the version i've ended up using, at least it works for 2 nameservers.
/**
* Resolve hostname from IP address
* #param { string } ip
* #return { Promise<string> }
*/
public async hostnameFromIP(ip: string) : Promise<string> {
return await this.resolveForHostnameFromIP(ip)
.then((hostname: string): string => hostname)
.catch(async (error: string): Promise<string> => {
const indexOf: number = this.nameservers.indexOf(this.currentNameServer);
const newNameserverIndex: number = indexOf + 1;
if (newNameserverIndex <= this.nameservers.length - 1) {
this.currentNameServer = this.nameservers[indexOf + 1];
this.setCurrentNameServerValue();
return await this.hostnameFromIP(ip).then((hostname: string): string => hostname);
}
return error;
});
}
/**
* Helper method to resolve hostname from the IP address
* #param { string } ip
* #return { q.Promise<string> }
*/
private resolveForHostnameFromIP(ip: string) : q.Promise<string> {
const deferred: Deferred<any> = q.defer();
this.resolver.reverse(ip, (error: NodeJS.ErrnoException | null, hostnames: string[]) => {
const defaultErrorMessage: string = 'Unable to resolve hostname';
if (error) {
return deferred.reject(defaultErrorMessage);
} else {
let hostname: string = hostnames.length === 0 ? defaultErrorMessage : hostnames[0];
hostname = hostname.replace('.localdomain', '').trim();
deferred.resolve(hostname);
}
});
return deferred.promise as q.Promise<string>;
}
/**
* Update resolver configuration with current name server
* #return { void }
* #private
*/
private setCurrentNameServerValue() : void {
this.resolver.setServers([this.currentNameServer]);
};
Sorry, got the question wrong so this part is not important. Proper answer below. Btw keeping it here just in case someone has a problem like this:
That's not how DNS server lists work in almost any platform. If you look in your system network settings (Windows, Mac or Linux), surely you will see 2 nameservers (as is the default amount all ISPs provide). That's because there is a main server and a fallback server if the main one fails. You system won't return 2 different IPs when you are browsing Internet. That's weird. What your browser want is just an IP to connect to, not a list of IPs. NodeJS works the same. The rest of nameservers are just fallback ones just in case the main one fails.
Now the proper part:
When a nameserver replies with NOTFOUND, nodejs will not continue to the next nameserver, as is actually a working nameserver. Fallback nameservers are only used when the nameserver fails (with a weird error/response or a timeout. Documentation link below with this info).
To achieve what you want you need to set your nameserver, make your query, wait for the response, set the next nameserver, make your query, etc... with your current code must be an easy task. Looks pretty.
Be careful as you must not change the nameservers when a DNS query is in progress as you can read in the documentation.

RestSharp - Request to Spotify API

RestClient Client = new RestClient(Settings.Url)
{
UserAgent = Settings.UserAgent,
FollowRedirects = false
};
RestRequest Req = new RestRequest(Method.POST);
Req.AddHeader("Content-Type", Settings.ContentType);
Req.AddHeader("Accept", "application/json, text/plain, */*");
Req.AddHeader("Accept-Encoding", "gzip, deflate, br");
Req.AddHeader("Accept-Language", "en-US,en;q=0.9");
Req.AddHeader("Referer", Settings.Referer);
Req.AddParameter("remember=false&username=xxx&password=xxx&captcha_token=&csrf_token=", ParameterType.RequestBody);
Client.ExecuteAsync(Req, response =>
{
if (response.StatusCode == HttpStatusCode.BadRequest)
{
Console.WriteLine("Access DENIED!", Color.DarkRed);
}
else
{
Console.WriteLine("Accessed.", Color.Green);
}
});
This is my basic Request.
here is my Class Settings:
public class Settings
{
public static string Url = "https://accounts.spotify.com/api/login";
public static string Referer = "https://accounts.spotify.com/en/login/";
public static string UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36";
public static string ContentType = "application/x-www-form-urlencoded";
}
So my problem is that I always get the Access Denied even if I put in correct details.
This is how the Form Data looks like:
remember: true
username: fsdfsdfds
password: sfdfdsfsd
captcha_token:
csrf_token: AQC-Y5OnqJvcV1PLrsvXFU-FdVNANBKZOpB5S3vDxCKH0VpPE3flpkMNJKheqQGzut066RziyASQSDeB-Tj7I0TSKtmtZ3FKs6tLMnCUkES4Lr2aKwIy8mh80NWtX70uU-i6
Do I need to bypass the CSRF_Token somehow?
Or can you find another Error?

How to make SSL peer_verify work on Android?

I've successfully built libcurl-7.36.0 with openssl-1.0.1h on Android. I ran a sample code to test HTTPS connection. The SSL_VERIFYPEER is enabled by default. The certificates path on Android is /system/etc/security/cacerts, so I set CURLOPT_CAPATH to /system/etc/security/cacerts.
ls -l /system/etc/security/cacerts
-rw-r--r-- root root 4767 2012-09-22 11:57 00673b5b.0
-rw-r--r-- root root 4573 2012-09-22 11:57 03e16f6c.0
-rw-r--r-- root root 5292 2012-09-22 11:57 08aef7bb.0
......
Here is a snippet of my codes..
curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, "https://www.google.com:443");
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); // default
curl_easy_setopt(curl, CURLOPT_CAPATH, "/system/etc/security/cacerts");
curl_easy_perform(curl);
Curl always returns an error:
== Info: SSL certificate problem: unable to get local issuer certificate
== Info: Closing connection 0
curl_easy_perform() failed: Peer certificate cannot be authenticated with given CA certificates
It's working if I download the CA bundle file ca-bundle.crt from http://curl.haxx.se/docs/caextract.html and curl_easy_setopt(curl, CURLOPT_CAINFO, "path:/ca-bundle.crt").
Here is my question: Is there any way to make SSL peer verification work by reading the certificate from /system/etc/security/cacerts without manually downloading the CA bundle file and specifying CURLOPT_CAINFO?
If using libcurl in an android app, CURLOPT_SSL_VERIFYPEER will fail and hence prevent CURL from sending data if if there is no CA bundle . One way to overcome this is to turn off this option which is very very very bad.
We must provide our own CA bundle and provide the absolute path of the CA bundle file using CURLOPT_CAINFO option.
The "cacert.pem" file from ​http://curl.haxx.se/docs/caextract.html can be placed in resources or assets but I prefer assets directory.
CURL expects absolute path and we cant give absolute path of assets folder because a packaged android APK file is like a zipped folder hence we need to copy the PEM file from assets to internal storage or external storage but I prefer internal storage since it private to the app and provide the absolute path of the internal storage directory in CAINFO. For example if app name is com.example.androidtest then CAINFO path will be "/data/data/com.example.androidtest/cacert.pem" .
Sample implementation of CURL using TLS1.2 ,openSSL 1.01p,curl version 7.40.0 ,cacert.pem bundle with verify peer ,verify hostname option is shown in https://github.com/vyshas/CURL-Android-with-verify-peer-
Important parts from the above link is shown below:
JAVA Side
public native void setDir(String caCertDir);
setDir(saveCertPemFile());
private String saveCertPemFile()
{
Context context=getApplicationContext();
String assetFileName="cacert.pem";
if(context==null || !FileExistInAssets(assetFileName,context))
{
Log.i("TestActivity", "Context is null or asset file doesnt exist");
return null;
}
//destination path is data/data/packagename
String destPath=getApplicationContext().getApplicationInfo().dataDir;
String CertFilePath =destPath + "/" +assetFileName;
File file = new File(CertFilePath);
if(file.exists())
{
//delete file
file.delete();
}
//copy to internal storage
if(CopyAssets(context,assetFileName,CertFilePath)==1) return CertFilePath;
return CertFilePath=null;
}
private int CopyAssets(Context context,String assetFileName, String toPath)
{
AssetManager assetManager = context.getAssets();
InputStream in = null;
OutputStream out = null;
try {
in = assetManager.open(assetFileName);
new File(toPath).createNewFile();
out = new FileOutputStream(toPath);
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1)
{
out.write(buffer, 0, read);
}
in.close();
in = null;
out.flush();
out.close();
out = null;
return 1;
} catch(Exception e) {
Log.e("tag", "CopyAssets"+e.getMessage());
}
return 0;
}
private boolean FileExistInAssets(String fileName,Context context)
{
try {
return Arrays.asList(context.getResources().getAssets().list("")).contains(fileName);
} catch (IOException e) {
// TODO Auto-generated catch block
Log.e("tag", "FileExistInAssets"+e.getMessage());
}
return false;
}
JNI SIDE
JNIEXPORT void JNICALL Java_com_example_androidtest_TestActivity_setDir(JNIEnv* env, jobject obj, jstring caCertDir)
{
if(!caCertDir) return;
const char* caCertDir_c = env->GetStringUTFChars(caCertDir, NULL);
if (!caCertDir_c) return ;
const jsize len = env->GetStringUTFLength(caCertDir);
LOGI( "CaCertDir: %s", caCertDir_c );
std::string caCert(caCertDir_c,len);
caCertPtr=caCert;
LOGI( "CaCertDirptr in std string: %s", caCertPtr.c_str());
env->ReleaseStringUTFChars(caCertDir, caCertDir_c);
}
CURL code
CURL* curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);
/* curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, TRUE);
curl_easy_setopt(curl, CURLOPT_FAILONERROR, TRUE);*/
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &curlCallback);
curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, downloadObject);
curl_easy_setopt(curl,CURLOPT_CAINFO,caCertPtr.c_str());
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L);
curl_version_info_data * vinfo = curl_version_info( CURLVERSION_NOW );
if( vinfo->features & CURL_VERSION_SSL )
// SSL support enabled
LOGI("SSL support enabled");
else
{// No SSL
LOGI("NO SSL");
}
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK){
LOGI("CURL failed with error code %d", res);
}
LOGI("CURL download is OK, result:%d", res);
curl_easy_cleanup(curl);
return res == CURLE_OK;
OpenSSL 0.9.x used MD5 filename hash. OpenSSL 1.0.x used SHA-1 for the filename hash. Android is using MD5 hash. Why old hash?
I tried libcurl-7.36.0 with openssl-0.9.8zb. It's working on Android with CURLOPT_SSL_VERIFYPEER enabled.
The problem is not on Curl, but on openSSL.
openssl 1.1.1x at openssl-1.1.1x/crypto/x509/by_dir.c:
function get_cert_by_subject(), it using X509_NAME_hash() that not compatible with android.
try to modify the by_dir.c at openssl source:
#if defined(__ANDROID__)
h = X509_NAME_hash_old(name);
#else
h = X509_NAME_hash(name);
#endif
it's should be solve the problem.
patch:
--- a/openssl-1.1.1k/crypto/x509/by_dir.c
+++ b/openssl-1.1.1k/crypto/x509/by_dir.c
## -247,7 +247,11 ## static int get_cert_by_subject(X509_LOOKUP *xl,
ctx = (BY_DIR *)xl->method_data;
+#if defined(__ANDROID__)
+ h = X509_NAME_hash_old(name);
+#else
h = X509_NAME_hash(name);
+#endif
for (i = 0; i < sk_BY_DIR_ENTRY_num(ctx->dirs); i++) {
BY_DIR_ENTRY *ent;
int idx;
EDIT: my previous answer was wrong.
CURLOPT_CAPATH should point to a directory prepared for OpenSSL with the c_hash tool. I don't know if that's the same format that Android provides.
I found this description on how to import new certs to a recent Android, and it seems to indicate a slightly different format of the files in that directory than what c_hash makes...
I got this to work on Android by recompiling libcurl and configuring the default search path for certificates. This can be done by passing the option:
--with-ca-path=/system/etc/security/cacerts to ./configure
or
-DCURL_CA_PATH=/system/etc/security/cacerts to cmake

WCat throwing error from ubr file generated from WCat Scenario Creator

I used the WCat Scenario Creator (http://fiddler2wcat.codeplex.com/) to generate the scripts of many requests through a website.
I had to add the "port:8888;" to every request. Then, after the "All clients connected, Test beginning." response, the test produced this error:
Invalid code received.
Error accepting remote connection.
I knew the first two requests worked so it was an issue with what was wrong with the next, 3rd, request.
The request looked like
request {
id = "3";
url = "/Content/Telerik-Kendo/textures/highlight.png";
verb = GET;
cookies = True;
secure = False;
statuscode = 304;
setheader {
name = "Accept";
value = "image/png, image/svg+xml, image/*;q=0.8, */*;q=0.5";
}
setheader {
name = "Referer";
value = "http://server.compute-1.amazonaws.com:8888/Home/Winpoints/?sessionid=502hhfoij5ef4jedzouxz02z&low=0&high=150&companyid=3&verticalmarketid=8";
}
setheader {
name = "Accept-Language";
value = "en-US";
}
setheader {
name = "User-Agent";
value = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)";
}
setheader {
name = "Accept-Encoding";
value = "gzip, deflate";
}
setheader {
name = "Host";
value = "server.compute-1.amazonaws.com:8888";
}
setheader {
name = "If-Modified-Since";
value = "Thu, 27 Sep 2012 05:47:46 GMT";
}
setheader {
name = "If-None-Match";
value = ""0ed9e9e739ccd1:0"";
}
setheader {
name = "Connection";
value = "Keep-Alive";
}
setheader {
name = "Cookie";
value = "ASP.NET_SessionId=502hhfoij5ef4jedzouxz02z";
}
}
The answer, at least for this problem was the double quotes around the value of the "If-None-Match" header.
setheader {
name = "If-None-Match";
value = ""0ed9e9e739ccd1:0"";
}
Changing this to have 1 opening and closing double quote fixed it.
setheader {
name = "If-None-Match";
value = "0ed9e9e739ccd1:0";
}

Understanding JDK 1.6 on Ubuntu Linux IPv6 output handling

I'm running Ubuntu 10.10 and my hosts configuration are as following:
root#maxim-desktop:~# cat /etc/hosts
192.168.20.20 maxim-desktop # Added by NetworkManager
192.168.10.20 maxim-lp
127.0.0.1 localhost.localdomain localhost
::1 maxim-desktop localhost6.localdomain6 localhost6
# The following lines are desirable for IPv6 capable hosts
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
ff02::3 ip6-allhosts
root#maxim-desktop:~# cat /etc/resolv.conf
# Generated by NetworkManager
nameserver 192.168.20.1
root#maxim-desktop:~# cat /etc/hostname
maxim-desktop
root#maxim-desktop:~# hostname
maxim-desktop
root#maxim-desktop:~# hostname --fqdn
root#maxim-desktop:~# ifconfig
eth0 Link encap:Ethernet HWaddr 00:1c:c0:f2:ba:89
inet addr:192.168.20.20 Bcast:192.168.0.255 Mask:255.255.255.0
inet6 addr: fe80::21c:c0ff:fef2:ba89/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:9023854 errors:0 dropped:0 overruns:0 frame:0
TX packets:8532803 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:4839992361 (4.8 GB) TX bytes:1067998152 (1.0 GB)
Interrupt:20 Memory:d3300000-d3320000
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:12333251 errors:0 dropped:0 overruns:0 frame:0
TX packets:12333251 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:3216352432 (3.2 GB) TX bytes:3216352432 (3.2 GB)
I'm trying to reach the same result from within java code.
Sadly, the following code just doesn't seem to cut it through.
//Copyright (c) 2011, Maxim Veksler
//All rights reserved.
//
//Redistribution and use in source and binary forms, with or without
//modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the <organization> nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
//DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
//DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Hostname and IP address info, based on JDK6 NetworkInterface
*
* #author Maxim Veksler <maxim#vekslers.org>
*/
public class NetworkUtil {
private static Logger log = LoggerFactory.getLogger(NetworkUtil.class);
public static void main(String[] args) {
System.out.println("MAC: " + NetworkUtil.getMachineMac());
System.out.println("HOSTNAME: " + NetworkUtil.getMachineHostname());
System.out.println("IP: " + NetworkUtil.getMachineIPAddress());
System.out.println("HOSTNAME ipv6: " + NetworkUtil.getMachineIPv6Hostname());
System.out.println("IP ipv6: " + NetworkUtil.getMachineIPv6Address());
}
/**
* Get the MAC address of the remote IP (if on local LAN).
* #param hostnameOrIP The target IP or Hostname (if you have DNS configured).
*
* #return MAC address if IP in local LAN, null if not.
*/
public static String getRemoteHostMac(String hostnameOrIP) {
try {
InetAddress address = InetAddress.getByName(hostnameOrIP);
NetworkInterface networkInterface = NetworkInterface.getByInetAddress(address);
return obtainMACFromAddress(networkInterface);
} catch (Exception e) {
if(log.isDebugEnabled()) {
log.debug("Failed to obtain MAC address for address " + hostnameOrIP, e);
}
}
// Means we had a failure.
return null;
}
/**
* Get the machine address of the machine we are currently running on.
* #return something like 08-00-27-DC-4A-9E or null if can't obtain mac
*/
public static String getMachineMac() {
try {
return obtainMACFromAddress(getNonLoopbackNetworkInterface());
} catch (Exception e) {
if(log.isDebugEnabled()) {
log.debug("Failed to obtain MAC address for localhost", e);
}
}
return null;
}
/**
* Get machine hostname, based on IPv4 configurations.
*
* #return String representing FQDN or null if can't find hostname
*/
public static String getMachineHostname() {
try {
NetworkInterface networkInterface = getNonLoopbackNetworkInterface();
Inet4Address address = getInet4Address(networkInterface);
if(address != null)
return address.getCanonicalHostName();
} catch (Exception e) {
if(log.isDebugEnabled()) {
log.debug("Failed to obtain MachineHostname", e);
}
}
return null;
}
/**
* Get machine hostname, based on IPv6 configurations.
* #return String representing FQDN or null if can't find hostname
*/
public static String getMachineIPv6Hostname() {
try {
NetworkInterface networkInterface = getNonLoopbackNetworkInterface();
Inet6Address address = getInet6Address(networkInterface);
if(address != null)
return address.getCanonicalHostName();
} catch (Exception e) {
if(log.isDebugEnabled()) {
log.debug("Failed to obtain IPv6Hostname", e);
}
}
return null;
}
/**
* Get machine IP, based on IPv4 configurations.
*
* #return String representing IP or null if can't find properly configured interface
*/
public static String getMachineIPAddress() {
try {
NetworkInterface networkInterface = getNonLoopbackNetworkInterface();
Inet4Address address = getInet4Address(networkInterface);
if(address != null)
return address.getHostAddress();
} catch (Exception e) {
if(log.isDebugEnabled()) {
log.debug("Failed to obtain MachineIPAddress", e);
}
}
return null;
}
/**
* Get machine IP, based on IPv6 configurations.
*
* #return String representing IP or null if can't find properly configured interface
*/
public static String getMachineIPv6Address() {
try {
NetworkInterface networkInterface = getNonLoopbackNetworkInterface();
Inet6Address address = getInet6Address(networkInterface);
if(address != null)
return address.getHostAddress();
} catch (Exception e) {
if(log.isDebugEnabled()) {
log.debug("Failed to obtain MachineIPv6Address", e);
}
}
return null;
}
/*
* ########################
* Helper private functions
*/
private static String obtainMACFromAddress(NetworkInterface networkInterface) throws SocketException {
if(networkInterface != null) {
byte[] mac = networkInterface.getHardwareAddress();
if(mac == null)
throw new Error("Failed to obtain mac address from interface: " + networkInterface.getDisplayName());
StringBuilder stringBuilder = new StringBuilder(17);
/*
* Extract each array of mac address and convert it to hexa with the
* following format 08-00-27-DC-4A-9E.
*/
for (int i = 0; i < mac.length; i++) {
stringBuilder.append(String.format("%02X%s", mac[i], (i < mac.length - 1) ? "-" : ""));
}
return stringBuilder.toString();
}
return null;
}
private static Inet4Address getInet4Address(NetworkInterface networkInterface) {
if(networkInterface != null) {
Enumeration<InetAddress> NICAddresses = networkInterface.getInetAddresses();
while(NICAddresses.hasMoreElements()) {
InetAddress address = NICAddresses.nextElement();
if(address instanceof Inet4Address)
return (Inet4Address)address;
}
}
return null;
}
private static Inet6Address getInet6Address(NetworkInterface networkInterface) {
if(networkInterface != null) {
Enumeration<InetAddress> NICAddresses = networkInterface.getInetAddresses();
while(NICAddresses.hasMoreElements()) {
InetAddress address = NICAddresses.nextElement();
if(address instanceof Inet6Address)
return (Inet6Address)address;
}
}
return null;
}
private static NetworkInterface getNonLoopbackNetworkInterface() throws SocketException {
// We need to iterate over all NIC's machine has because stupid ubuntu does not assign
// MAC address to default loopback interface...
Enumeration<NetworkInterface> b = NetworkInterface.getNetworkInterfaces();
while(b.hasMoreElements()) {
NetworkInterface networkInterface = b.nextElement();
Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();
while(inetAddresses.hasMoreElements()) {
InetAddress address = inetAddresses.nextElement();
if(!address.isLoopbackAddress())
return networkInterface;
}
}
// Means we haven't found any non loopback interfaces. Bummer, return empty handed.
return null;
}
}
The following is printed on my machine:
MAC: 00-1C-C0-F2-BA-89
HOSTNAME: maxim-desktop
IP: 192.168.20.20
HOSTNAME ipv6: fe80:0:0:0:21c:c0ff:fef2:ba89%2
IP ipv6: fe80:0:0:0:21c:c0ff:fef2:ba89%2
As you can see the hostname output for IPv4 & IPv6 are not the same, I wonder why should it be like this?
Also, what is the meaning of the %2 that get's attached to ipv6 related queries - Is it a bug in my code or a JVM / Linux kernel issue?
Thank you,
Maxim.
If you look at the code, here's what it does:
find a non-loopback network interface (ie. in your case, eth0)
query for the IP address of that interface (in your case, 192.168.20.20 or fe80:0:0:0:21c:c0ff:fef2:ba89%2)
resolve the IP address. As you can see from your hosts file, 192.168.20.20 correctly resolves to maxim-desktop, but there is no hostname corresponding to your IPv6 address.
IPv6 addresses beginning with fe80 (or, to be precise, addresses in the fe80::/10 network) are link-local addresses, and that %2 denotes which network interface the system should use.

Resources