1. 前言
Windows抓包与网络分析工具总结:https://blog.csdn.net/a82514921/article/details/104609924
Linux抓包与网络分析工具总结:https://blog.csdn.net/a82514921/article/details/104616502
Java程序网络连接分析方法总结:https://blog.csdn.net/a82514921/article/details/104616519
iptables模拟网络连接问题并分析:https://blog.csdn.net/a82514921/article/details/104616548
2. Java
以下在Windows环境进行测试,使用的Java版本为JDK8。
2.1 BTrace
BTrace是Java平台的动态跟踪工具,下载地址为https://github.com/btraceio/btrace,使用说明可查看https://github.com/btraceio/btrace/wiki。
以下使用的BTrace版本为1.3.11.3。
2.1.1 使用说明
https://github.com/btraceio/btrace#installation说明了BTrace的下载地址,当前版本地址为https://github.com/btraceio/btrace/releases/tag/v1.3.11.3,可下载btrace-bin-1.3.11.3.tgz或btrace-bin-1.3.11.3.zip。
将btrace-bin-xxx压缩包解压后即可使用,btrace的bin目录中包含了btrace、btracec、btracer等命令。
在Windows环境时,可将btrace的bin目录添加至环境变量的Path变量中,方便在任意目录执行btrace等命令。
通常情况下,将BTrace动态附加到程序,只需要执行“btrace [pid] [跟踪脚本文件名/路径]”。
可查看https://github.com/btraceio/btrace/wiki#dynamically-attaching-to-application说明。
用于快速连接到已运行的应用程序,获取感兴趣的数据并分离,删除任何跟踪代码。
将BTrace动态附加到程序的命令如下:
btrace [-p <port>] [-cp <classpath>] <pid> <btrace-script> [<args>] |
l port
BTrace agent监听的端口,是可选的参数。
l classpath
设置BTrace编译期间搜索类的目录或jar文件命令,默认为“.”。
l pid
需要被跟踪的Java程序的进程ID。
l btrace-script
跟踪脚本文件名或路径。若为java文件,则会在使用前进行编译;否则会被当作预编译的class文件并使用。
可查看https://github.com/btraceio/btrace/wiki#starting-application-with-btrace说明。
在这种模式下,BTrace会在应用程序启动代码运行之前就启动。可以在应用程序生命周期的早期跟踪执行的代码。
使用BTrace agent启动应用程序的语法如下:
java -javaagent:btrace-agent.jar=[<agent-arg>[,<agent-arg>]*]? <launch-args> |
agent使用逗号分隔的参数列表,如下所示:
noServer - don't start the socket server bootClassPath - boot classpath to be used systemClassPath - system classpath to be used debug - turns on verbose debug messages (true/false) trusted - do not check for btrace restrictions violations (true/false) dumpClasses - dump the transformed bytecode to files (true/false) dumpDir - specifies the folder where the transformed classes will be dumped to stdout - redirect the btrace output to stdout instead of writing it to an arbitrary file (true/false) probeDescPath - the path to search for probe descriptor XMLs startupRetransform - enable retransform of all the loaded classes at attach (true/false) scriptdir - the path to a directory containing scripts to be run at the agent startup scriptOutputFile - the path to a file the btrace agent will store its output script - colon separated list of tracing scripts to be run at the agent startup |
如果不需要自定义代理程序参数,则可以使用btracer应用程序脚本进行替代。
agent使用的参数格式可以参考https://github.com/btraceio/btrace/blob/master/docs/usersguide.html,示例如下:
java -javaagent:btrace-agent.jar=script=<pre-compiled-btrace-script> <MainClass> <AppArguments> |
以下对下文会使用的agent参数进行说明:
l debug
打印详细的调试日志(true开启)。
l dumpClasses
将被修改类的字节码转储至文件(true开启)。
l dumpDir
指定保存被修改类的字节码转储文件的保存目录。
l stdout
将BTrace的输出重定向至标准输出,而不是保存至文件中(true重定向至标准输出)。
当stdout参数不是true时,BTrace的输出会保存至文件中,默认保存在class文件所在目录,文件名格式为“[类名].class-.default.[时间毫秒数].btrace”,如“TestSocketConnect.class-.default.1548128796288.btrace”。
输出文件相关参数配置有误时,可能在当前目录生成文件。
l scriptdir
指定BTrace agent启动时需要执行的跟踪脚本的保存目录。
l scriptOutputFile
指定BTrace agent将输出保存至文件的文件路径(需要指定文件路径,不能指定为目录)。
l script
指定BTrace agent启动时需要执行的跟踪脚本的文件名或完整路径列表,使用冒号分隔。
需要执行的脚本需要提前使用btracec命令编译为字节码,即class文件。
当跟踪脚本文件保存在当前目录时,可通过script指定脚本文件名。
当通过scriptdir参数指定脚本文件目录时,可通过script指定脚本文件名。
其他情况下,可通过script指定脚本文件完整路径。
通常情况下,通过btracec命令将跟踪脚本由java文件编译为class文件,可执行“btracec [java文件名/路径]”,类似javac命令,生成的class文件在当前目录。
btracec命令使用说明见https://github.com/btraceio/btrace/wiki/btracec。
btracec命令使用方法为:
btracec [-cp <classpath>] [-d <directory>] <one-or-more-BTrace-.java-files> |
l classpath
编译BTrace程序时用于编译的类路径,默认为“.”。
l directory
保存编译生成的class文件的目录,默认为“.”。
BTrace脚本注解说明可查看https://github.com/btraceio/btrace/wiki/BTrace-Annotations,BTrace脚本的说明可查看https://github.com/btraceio/btrace/wiki/Trace-Scripts。
以下介绍下文使用的注解。
@OnMethod注解,用于指定目录类,目标方法,及方法的位置。
@OnMethod注解的使用说明如下:
@OnMethod(clazz=<cname_spec>[, method=<mname_spec>]? [, type=<signature>]? [, location=<location_spec>]?)
cname_spec = <class_name> | +<class_name> | /regex/ class_name is a fully qualified class name +class_name is a fully qualified class name prepended with +; means all subclasses and implementors of the prepended class name /regex/ is a standard regular expression used to identify the class names mname_spec = <method_name> | /regex/ method_name is a simple method name (no signature or return type) signature = <return_type> ((arg_type(,arg_type)*)? return_type is the methods return type as written in java (eg. void, java.lang.String) arg_type is the argument type as written in java |
当匹配方法到达指定位置时,将调用由此注解注释的操作方法。在OnMethod注解中,跟踪类名由“clazz”属性指定,跟踪方法由“method”属性指定。“clazz”可以是完全限定的类名(如java.awt.Component或在两个正斜杠中指定的正则表达式。请参考示例NewComponent.java和Classload.java。
正则表达式可以匹配零个或多个类,在这种情况下,所有匹配的类都会被检测。如“/java\.awt\..+/”匹配java.awt包中的所有类。此外,方法名称也可以是正则表达式,可匹配零个或多个方法。请参考示例MultiClass.java。
还有另一种方法可以抽象地指定跟踪类和方法。可以通过注解指定跟踪的类和方法。例如,将“clazz”属性指定为@javax.jws.WebService,则BTrace将检测由@WebService批解注释的所有类。类似地,方法级别注解可用于抽象地指定方法。请参考示例WebServiceTracker.java。
也可以将正则表达式与注解相结合 - 比如“@/com\.acme\..+/”匹配任何由与给定正则表达式匹配的注解注释的类。
可以通过指定超类型来匹配多个类。即匹配作为给定超类型的子类型的所有类。如“+java.lang.Runnable”匹配实现java.lang.Runnable接口的所有类。请参考示例SubtypeTracer.java。
BTrace脚本的限制可查看https://github.com/btraceio/btrace/wiki/Trace-Scripts#restrictions。
经测试发现BTrace脚本中还存在以下限制:
不允许调用类的getClass()方法 |
不允许进行强制类型转换 |
若不满足以上限制,在使用btracec编译时,会出现类似“xxx.java:[行号]:method calls are not allowed - only calls to BTraceUtils are allowed”提示。
当需要调用类的getClass方法时,可以调用BTraceUtils的classOf方法获取Class对象,由于已经导入“import static com.sun.btrace.BTraceUtils.*;”,因此可以直接调用classOf方法。当需要获取Class的字符串类名时,可调用name方法。
由于无法进行强制类型转换,当需要将父类对象强制类型转换为子类对象并获取属性时,可以使用反射的方式。
BTraceUtils中的Reflective.field方法可以获取对象的field对象,可直接调用field方法。
BTraceUtils中的Reflective.get方法可以获取对象的field的值,可直接调用get方法。
BTraceUtils中的Reflective.printFields方法可以打印对象的全部field的值,可直接调用printFields方法。
BTrace提供的反射方法与JDK的反射方法使用类似。
BTrace脚本示例可从https://github.com/btraceio/btrace/tree/master/samples下载,各示例的说明可查看https://github.com/btraceio/btrace/blob/master/docs/usersguide.html。
2.1.2 使用BTrace监控TCP连接
Java程序在进行TCP连接时,通常需要调用java.net.Socket类的connect方法(BIO)。
以下使用btrace,当调用java.net.Socket类的connect方法时,在入口增加信息输出,用于监控TCP连接过程。
以下为btrace执行的TestSocketConnect.java类代码:
|
在跟踪脚本的方法中添加被跟踪方法的调用参数,可以在跟踪脚本中获得被跟踪方法的参数值。
jstack方法可以打印调用堆栈。
以下启动使用httpclient进行HTTP通信的Java程序进行测试,监控TCP连接操作。
在执行前,需要先使用btracec命令将java文件编译为class文件。
l BTrace动态附加到进程
命令略。
由于以下进行测试时,Java程序只在测试时启动,不是长期启动,将BTrace动态附加到进程相对比较麻烦,每次需要修改Java程序的PID,因此通过BTrace启动Java程序测试更方便。
l 通过BTrace启动Java程序
使用IDEA执行Java程序,在“VM Options”中增加BTrace需要的参数,示例如下:
-javaagent:C:/dir/btrace/build/btrace-agent.jar=script=D:/dir/TestSocketConnect.class,stdout=true |
上述参数中,设置为“stdout=true”,使BTrace输出到标准输出,如果需要输出到文件,可以去掉。
当需要查看BTrace详细调试信息时,可以增加“debug=true”参数。
可以将跟踪脚本的目录与文件名分开配置,如下所示:
-javaagent:C:/dir/btrace/build/btrace-agent.jar=scriptdir=D:/dir/,script=TestSocketConnect.class,stdout=true |
添加以上参数后,正常启动,就可以通过BTrace启动被跟踪的Java程序。
以下为BTrace的输出内容,可以看到TCP连接的服务器信息,及调用堆栈等(使用HTTP协议)。
Socket.connect java.net.InetSocketAddress /127.0.0.1:8888 java.net.Socket.connect(Socket.java) org.apache.http.conn.socket.PlainConnectionSocketFactory.connectSocket(PlainConnectionSocketFactory.java:72) org.apache.http.impl.conn.HttpClientConnectionOperator.connect(HttpClientConnectionOperator.java:125) org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:319) org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:363) org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:219) org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:195) org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:86) org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:108) org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184) org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82) org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:106) |
通过BTrace启动Java程序时,可以将被改造的类的字节码转储到文件。
在BTrace启动参数增加dumpClasses与dumpDir,修改为如下:
-javaagent:C:/dir/btrace/build/btrace-agent.jar=script=D:/dir/TestSocketConnect.class,stdout=true,dumpClasses=true,dumpDir=D:/dir1 |
执行后可以看到在dumpDir目录中生成了转存储的class文件,分别为TestSocketConnect_bcp.class与java\net\Socket.class。
TestSocketConnect_bcp.class文件忽略。
Socket.class是对JDK的Socket类进行了改造,反编译后查看内容如下:
|
|
可以看到,跟踪脚本对Socket类的connect方法进行了跟踪,在被改造的Socket类中,在connect方法入口增加了“$btrace$TestSocketConnect$testFun(var1, var2);”调用,在类的最后增加了“$btrace$TestSocketConnect$testFun(var1, var2);”方法的定义。
2.2 Arthas
Arthas是Alibaba开源的Java诊断工具,可参考https://alibaba.github.io/arthas/index.html。
Arthas比BTrace功能更强大,使用更简单,只需要执行命令就可完成所需的操作。
以下使用Arthas 3.1.7版本。
2.2.1 使用Arthas监控TCP连接
java.net.Socket类属于系统级别的类,为了使Arthas对系统级别的类进行增强,需要将unsafe选项设置为true,可参考https://alibaba.github.io/arthas/options.html#options。
在Arthas命令窗口中执行“options unsafe true”,开启对系统级别的类进行增强,输出结果如下所示:
[arthas@10152]$ options unsafe true NAME BEFORE-VALUE AFTER-VALUE ----------------------------------- unsafe false true |
使用stack命令可以输出当前方法被调用的调用路径,可参考https://alibaba.github.io/arthas/stack.html。
可使用stack命令监控TCP连接。
执行“stack java.net.Socket connect”,监控TCP连接时的调用堆栈,输出结果如下所示(使用HTTPS协议):
@java.net.Socket.connect() at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:244) at org.apache.http.impl.conn.HttpClientConnectionOperator.connect(HttpClientConnectionOperator.java:125) at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:319) at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:363) at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:219) at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:195) at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:86) at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:108) at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:106) |
3. 网络分析工具使用场景
以上网络分析相关工具可在以下场景使用。
3.1 网络连接问题分析
当遇到网络连接问题时,可分析端口是否已监听,及监听端口的进程信息、IP地址信息等。(如监听时地址使用127.0.0.1,则只有本机能访问对应端口)。
3.2 分析通信数据
可以分析通信数据。
如在HTTP服务器捕获通信数据包,分析HTTP请求。
或捕获应用访问MySQL时的通信数据,分析是否使用了绑定变量方式,是否存在SQL注入风险。
3.3 分析HTTP keep-alive特性
可通过监控TCP连接操作,分析HTTP的keep-alive特性。
3.4 分析连接池
可通过监控TCP连接操作,分析连接池建立连接的情况。
3.5 监控连接数量
可以使用watch及ss命令,实时监控连接数量及状态。
3.6 监控连接信息
可以使用watch及对应命令(或使用lsof -r模式),实时监控关心的连接信息。