IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> jboss一个bogon引发的思考 -> 正文阅读

[系统运维]jboss一个bogon引发的思考

1.背景

??????? 在运行JBoss程序时,出现如下错误。

Caused by: java.net.UnknownHostException: bogon: bogon: 未知的名称或服务

	at java.net.InetAddress.getLocalHost(InetAddress.java:1506)

	at org.jboss.ws.common.management.AbstractServerConfig.setWebServiceHost(AbstractServerConfig.java:133)

	at org.jboss.as.webservices.config.ServerConfigImpl.setWebServiceHost(ServerConfigImpl.java:98)

	at org.jboss.as.webservices.dmr.WSSubsystemAdd.createServerConfig(WSSubsystemAdd.java:103)

	... 12 more

Caused by: java.net.UnknownHostException: bogon: 未知的名称或服务

	at java.net.Inet4AddressImpl.lookupAllHostAddr(Native Method)

	at java.net.InetAddress$2.lookupAllHostAddr(InetAddress.java:929)

	at java.net.InetAddress.getAddressesFromNameService(InetAddress.java:1324)

	at java.net.InetAddress.getLocalHost(InetAddress.java:1501)

	... 15 more

????????最终定位原因是因为无法通过主机名,解析出IP地址所致,将/etc/hosts中增加了主机名与IP地址的映射后问题解决。但是发现解决的太容易,有些问题和原理没有想透彻。

??????? bogon是什么含义?在哪里定义的?

????????java的java.net.InetAddress.getLocalHost为何与bogon扯上关系?

2.分析过程

??????? 在分析之前先了解一下Linux命令 ipcalc。ipcalc是RedHat提供的一个开源软件,其提供了一种计算主机IP信息的简单方法。比如可以通过IP地址与子网掩码计算出网络地址、广播地址等等,也可以通过IP地址反向获取主机名。

[yeqiyu@CentOS7-229 ~]$ ipcalc --help
Usage: ipcalc [OPTION...]
  -c, --check         Validate IP address for specified address family
  -4, --ipv4          IPv4 address family (default)
  -6, --ipv6          IPv6 address family
  -b, --broadcast     Display calculated broadcast address
  -h, --hostname      Show hostname determined via DNS
  -m, --netmask       Display default netmask for IP (class A, B, or C)
  -n, --network       Display network address
  -p, --prefix        Display network prefix
  -s, --silent        Don't ever display error messages

Help options:
  -?, --help          Show this help message
  --usage             Display brief usage message

??????? 在不同状态使用ipcalc命令,查看效果。可以看到,已经出现了HOSTNAME=bogon关键信息。

#hosts中未进行主机名与IP的映射
[yeqiyu@CentOS7-229 ~]$ ipcalc -h 192.168.130.229
HOSTNAME=bogon

#hosts中进行了主机名与IP的映射
[yeqiyu@CentOS7-229 ~]$ ipcalc -h 192.168.130.229
HOSTNAME=vcentos7-229

????????因此,可以推测,当本地DNS未设置时,会使用公共DNS,但公共DNS无法将IP地址反向解析为主机名时,会使用默认值bogon。我们换个方式佐证一下。

??????? 更换同版本的Linux环境

[yeqiyu@s168 ~]$ nslookup 192.168.129.168
168.129.168.192.in-addr.arpa    name = bogon.

Authoritative answers can be found from:

??????? 更换Windows机器查看现象。DNS服务商将IP反向解析为了bogon。

C:\Users\YQY>nslookup 192.168.40.105
服务器:  public1.114dns.com
Address:  114.114.114.114

名称:    bogon
Address:  192.168.40.105


C:\Users\YQY>nslookup 202.106.0.20
服务器:  public1.114dns.com
Address:  114.114.114.114

名称:    gjjline.bta.net.cn
Address:  202.106.0.20

??????? 通过不同操作系统、不同工具、不同IP验证,基本可以得出与IP地址的反向解析有关。当目标IP是私有地址或者无法被DNS反向解析时,都会将IP解析为bogon。

3.Bogon是什么

????????Bogon IP Addresses是一组IP地址,不被互联网地址分配机构(IANA)和RIR(区域互联网注册)分配给任何实体,这个未分配的地址空间称为虚假空间。bogon还包括保留的私有地址和链路本地地址范围(Martian Packets)。

??????? IPv4 Bobon范围

NetblockDescription
0.0.0.0/8"This" network
10.0.0.0/8Private-use networks
100.64.0.0/10Carrier-grade NAT
127.0.0.0/8Loopback
127.0.53.53Name collision occurrence
169.254.0.0/16Link local
172.16.0.0/12Private-use networks
192.0.0.0/24IETF protocol assignments
192.0.2.0/24TEST-NET-1
192.168.0.0/16Private-use networks
198.18.0.0/15Network interconnect device benchmark testing
198.51.100.0/24TEST-NET-2
203.0.113.0/24TEST-NET-3
224.0.0.0/4Multicast
240.0.0.0/4Reserved for future use
255.255.255.255/32Limited broadcast

4.JAVA解析过程分析

??????? 上述过程分析了在操作系统层面,什么情况会返回bogon,那么,JAVA层面是如何实现解析的呢?

??????? 分析JDK源码,找到类InetAddress,查看方法 getLocalHost(),可以看到其通过impl.getLocalHostName()获取了主机名,然后再通过主机名获取IP地址。根据错误提示,程序已经获得了主机名(bogon),因此关键点要找到getLocalHostName的具体实现。

    /**
     * Returns the address of the local host. This is achieved by retrieving
     * the name of the host from the system, then resolving that name into
     * an {@code InetAddress}.
     *
     * <P>Note: The resolved address may be cached for a short period of time.
     * </P>
     *
     * <p>If there is a security manager, its
     * {@code checkConnect} method is called
     * with the local host name and {@code -1}
     * as its arguments to see if the operation is allowed.
     * If the operation is not allowed, an InetAddress representing
     * the loopback address is returned.
     *
     * @return     the address of the local host.
     *
     * @exception  UnknownHostException  if the local host name could not
     *             be resolved into an address.
     *
     * @see SecurityManager#checkConnect
     * @see java.net.InetAddress#getByName(java.lang.String)
     */
   public static InetAddress getLocalHost() throws UnknownHostException {

        SecurityManager security = System.getSecurityManager();
        try {
            String local = impl.getLocalHostName();

            if (security != null) {
                security.checkConnect(local, -1);
            }

            if (local.equals("localhost")) {
                return impl.loopbackAddress();
            }

            InetAddress ret = null;
            synchronized (cacheLock) {
                long now = System.currentTimeMillis();
                if (cachedLocalHost != null) {
                    if ((now - cacheTime) < maxCacheTime) // Less than 5s old?
                        ret = cachedLocalHost;
                    else
                        cachedLocalHost = null;
                }

                // we are calling getAddressesFromNameService directly
                // to avoid getting localHost from cache
                if (ret == null) {
                    InetAddress[] localAddrs;
                    try {
                        localAddrs =
                            InetAddress.getAddressesFromNameService(local, null);
                    } catch (UnknownHostException uhe) {
                        // Rethrow with a more informative error message.
                        UnknownHostException uhe2 =
                            new UnknownHostException(local + ": " +
                                                     uhe.getMessage());
                        uhe2.initCause(uhe);
                        throw uhe2;
                    }
                    cachedLocalHost = localAddrs[0];
                    cacheTime = now;
                    ret = localAddrs[0];
                }
            }
            return ret;
        } catch (java.lang.SecurityException e) {
            return impl.loopbackAddress();
        }
    }

getLocalHostName实现了接口InetAddressImpl的getLocalHostName方法,而Inet4AddressImpl又是InetAddressImpl的一个实现,可以找到该方法。

public native String getLocalHostName() throws UnknownHostException;

关键native表示该方法由C语言实现,找到源码。

 
JNIEXPORT jstring JNICALL
Java_java_net_Inet4AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
    char hostname[NI_MAXHOST+1];
 
    hostname[0] = '\0';
    if (JVM_GetHostName(hostname, sizeof(hostname))) {//如果获取失败,则设置默认值localhost
        /* Something went wrong, maybe networking is not setup? */
        strcpy(hostname, "localhost");
    } else {
        struct addrinfo hints, *res;
        int error;
 
        hostname[NI_MAXHOST] = '\0'; //设置默认结束符
        memset(&hints, 0, sizeof(hints));
        hints.ai_flags = AI_CANONNAME; //这个参数很重要,要求返回主机规范名称,非别名
        hints.ai_family = AF_INET;
 
        error = getaddrinfo(hostname, NULL, &hints, &res); //这里hostname会重新改写
 
        if (error == 0) {/* host is known to name service */
            getnameinfo(res->ai_addr,
                        res->ai_addrlen,
                        hostname,
                        NI_MAXHOST,
                        NULL,
                        0,
                        NI_NAMEREQD);
 
            /* if getnameinfo fails hostname is still the value
               from gethostname */
 
            freeaddrinfo(res);
        }
    }
    return (*env)->NewStringUTF(env, hostname);
}

????????可以看到关键函数JVM_GetHostName和getaddrinfo,对变量hostname做了操作。参照JDK的源码,写一个Demo,来看下在哪里发生了变化。

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#define NI_MAXHOST 1025
int main() {
    char hostname[NI_MAXHOST+1] = {0};
    gethostname(hostname, NI_MAXHOST);
    printf("hostname_1=%s\n", hostname);
    struct addrinfo hints, *res;
    int error;
 
    memset(&hints, 0, sizeof(hints));
    hints.ai_flags = AI_CANONNAME;
    hints.ai_family = AF_INET;
 
    error = getaddrinfo(hostname, NULL, &hints, &res);
    printf("hostname_2=%s\n", hostname);
    if (error == 0) {/* host is known to name service */
        getnameinfo(res->ai_addr,
                    res->ai_addrlen,
                    hostname,
                    NI_MAXHOST,
                    NULL,
                    0,
                    NI_NAMEREQD);
 
        /* if getnameinfo fails hostname is still the value
            from gethostname */
 
        freeaddrinfo(res);
    }
    printf("hostname_3=%s\n", hostname);
}

编译

gcc gethostname_demo.c -o gethostname_demo

执行

[root@CentOS7-229 HostnameDemo_lib]# ./gethostname_demo 
hostname_1=CentOS7-229
hostname_2=CentOS7-229
hostname_3=bogon

可以看到,经过getaddrinfo函数之后,hostname变成了bogon

此时,我们修改host文件,补充主机名到IP的解析,然后再用demo查看,可以获取主机名了。

[root@CentOS7-229 HostnameDemo_lib]# cat /etc/hosts
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
192.168.130.229 CentOS7-229
[root@CentOS7-229 HostnameDemo_lib]# ./gethostname_demo 
hostname_1=CentOS7-229
hostname_2=CentOS7-229
hostname_3=CentOS7-229

?????? 关键点在于getnameinfo函数,如果在没有进行主机名和IP映射时,getnameinfo做了哪些事情?

????????

#include <netdb.h>
#include <sys/socket.h>

int getnameinfo(const struct sockaddr* restrict addr, socklen_t addrlen,
                char* restrict host, socklen_t hostlen,
                char* restrict serv, socklen_t servlen, int flags);
???是getaddrinfo的互补函数,以一个套接字地址为参数,返回描述其中的主机的一个字符串和描述其中的服务的另一个字符串。那么问题来了,明明已经通过gethostname和getaddrinfo函数拿到了主机名,又要再通过getnameinfo重新走一遍hosts、reslov.conf,将bogon ip反向解析为bogon名称,这么做的原因是什么呢?

?当前的能力还无法理解,暂且记录下来,后续再补充。

5.jboss与bogon

????????当jboss.bind.address=127.0.0.1或者192.168.130.229时,虽然会出现如下警告,但并不会出现ERROR级别错误。

21:59:44,867 WARN  [com.arjuna.ats.arjuna] (MSC service thread 1-8) ARJUNA012210: Unable to use InetAddress.getLocalHost() to resolve address.

??????? 在JBOSS启动时,jboss.bind.address=0.0.0.0,且不在hosts中映射,两个条件同时都满足,才会出现UnknownHostException: bogon: bogon: 未知的名称或服务。由JAVA实现的JBOSS又是怎么和bogon关联起来的呢? ????

??????? 这需要研究一下jboss.bind.address的实现机制。初步推测是如果设置具体IP地址,则直接监听这个指定的IP即可。如果设置为0.0.0.0,则需要监听本机上的所有IP,所以会调用getlocalhost的方法,来获取本机所有IP,于是便出现了步骤4的现象。

6.总结

??????? 借着这个问题,重新温习了Linux下DNS解析过程,将JAVA DNS内部实现原理进行了基本的学习,在Linux下的C开发与使用有了进一步了解。虽留有遗憾,仍然收获满满。

7.参考

ipcalc命令 – 简单的IP地址计算器 – Linux命令大全(手册)

Bogon IP addresses, ipv4 and ipv6 bogon IP Ranges

networking - Java DNS resolution hangs forever - Stack Overflow

getnameinfo(3) - Linux manual page

getaddrinfo(3) - Linux manual page

https://www.ibm.com/docs/en/zos/2.3.0?topic=functions-getnameinfo-get-name-information

Jdk8 DNS解析 - Loull - 博客园

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-04-23 11:09:45  更:2022-04-23 11:11:45 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 19:32:48-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码