mirror of
https://gitee.com/ja-netfilter/ja-netfilter.git
synced 2024-11-16 23:49:38 +08:00
reorganize builtin plugins
Signed-off-by: pengzhile <pengzhile@gmail.com>
This commit is contained in:
parent
cf57cd2015
commit
a380bf126f
@ -1,4 +1,4 @@
|
||||
# ja-netfilter v1.1.0
|
||||
# ja-netfilter v1.1.1
|
||||
|
||||
### A javaagent lib for network filter
|
||||
|
||||
|
2
pom.xml
2
pom.xml
@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>io.zhile.research</groupId>
|
||||
<artifactId>ja-netfilter</artifactId>
|
||||
<version>1.1.0</version>
|
||||
<version>1.1.1</version>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
|
@ -1,7 +1,7 @@
|
||||
package io.zhile.research.ja.netfilter;
|
||||
|
||||
import io.zhile.research.ja.netfilter.commons.DebugInfo;
|
||||
import io.zhile.research.ja.netfilter.transformers.MyTransformer;
|
||||
import io.zhile.research.ja.netfilter.plugin.MyTransformer;
|
||||
|
||||
import java.lang.instrument.ClassFileTransformer;
|
||||
import java.lang.instrument.IllegalClassFormatException;
|
||||
@ -28,12 +28,20 @@ public class Dispatcher implements ClassFileTransformer {
|
||||
}
|
||||
|
||||
public void addTransformers(List<MyTransformer> transformers) {
|
||||
if (null == transformers) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (MyTransformer transformer : transformers) {
|
||||
addTransformer(transformer);
|
||||
}
|
||||
}
|
||||
|
||||
public void addTransformers(MyTransformer[] transformers) {
|
||||
if (null == transformers) {
|
||||
return;
|
||||
}
|
||||
|
||||
addTransformers(Arrays.asList(transformers));
|
||||
}
|
||||
|
||||
@ -54,7 +62,7 @@ public class Dispatcher implements ClassFileTransformer {
|
||||
for (MyTransformer transformer : transformers) {
|
||||
classFileBuffer = transformer.transform(className, classFileBuffer, order++);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
DebugInfo.output("Transform class failed: " + e.getMessage());
|
||||
}
|
||||
} while (false);
|
||||
|
@ -21,7 +21,7 @@ public class Initializer {
|
||||
|
||||
try {
|
||||
FilterConfig.setCurrent(new FilterConfig(ConfigParser.parse(configFile)));
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
DebugInfo.output(e.getMessage());
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ public class Launcher {
|
||||
URI jarURI;
|
||||
try {
|
||||
jarURI = getJarURI();
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
DebugInfo.output("ERROR: Can not locate ja-netfilter jar file.");
|
||||
return;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package io.zhile.research.ja.netfilter.transformers;
|
||||
package io.zhile.research.ja.netfilter.plugin;
|
||||
|
||||
public interface MyTransformer {
|
||||
String getHookClassName();
|
@ -1,7 +1,6 @@
|
||||
package io.zhile.research.ja.netfilter.plugin;
|
||||
|
||||
import io.zhile.research.ja.netfilter.models.FilterRule;
|
||||
import io.zhile.research.ja.netfilter.transformers.MyTransformer;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -12,6 +11,8 @@ public interface PluginEntry {
|
||||
|
||||
String getName();
|
||||
|
||||
String getAuthor();
|
||||
|
||||
default String getVersion() {
|
||||
return "v1.0.0";
|
||||
}
|
||||
|
@ -3,14 +3,15 @@ package io.zhile.research.ja.netfilter.plugin;
|
||||
import io.zhile.research.ja.netfilter.Dispatcher;
|
||||
import io.zhile.research.ja.netfilter.commons.DebugInfo;
|
||||
import io.zhile.research.ja.netfilter.models.FilterConfig;
|
||||
import io.zhile.research.ja.netfilter.transformers.HttpClientTransformer;
|
||||
import io.zhile.research.ja.netfilter.transformers.InetAddressTransformer;
|
||||
import io.zhile.research.ja.netfilter.transformers.MyTransformer;
|
||||
import io.zhile.research.ja.netfilter.plugins.dns.DNSFilterPlugin;
|
||||
import io.zhile.research.ja.netfilter.plugins.url.URLFilterPlugin;
|
||||
import io.zhile.research.ja.netfilter.utils.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.instrument.Instrumentation;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
@ -29,46 +30,63 @@ public class PluginManager {
|
||||
}
|
||||
|
||||
public void loadPlugins(Instrumentation inst, File currentDirectory) {
|
||||
File pluginsDirectory = new File(currentDirectory, PLUGINS_DIR);
|
||||
if (!pluginsDirectory.exists() || !pluginsDirectory.isDirectory()) {
|
||||
return;
|
||||
}
|
||||
|
||||
File[] pluginFiles = pluginsDirectory.listFiles((d, n) -> n.endsWith(".jar"));
|
||||
if (null == pluginFiles) {
|
||||
return;
|
||||
}
|
||||
|
||||
Dispatcher.getInstance().addTransformers(new MyTransformer[]{ // built-in transformers
|
||||
new HttpClientTransformer(),
|
||||
new InetAddressTransformer()
|
||||
});
|
||||
|
||||
for (File pluginFile : pluginFiles) {
|
||||
for (Class<? extends PluginEntry> klass : getAllPluginClasses(inst, currentDirectory)) {
|
||||
try {
|
||||
JarFile jarFile = new JarFile(pluginFile);
|
||||
Manifest manifest = jarFile.getManifest();
|
||||
String entryClass = manifest.getMainAttributes().getValue(ENTRY_NAME);
|
||||
if (StringUtils.isEmpty(entryClass)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PluginClassLoader classLoader = new PluginClassLoader(jarFile);
|
||||
Class<?> klass = Class.forName(entryClass, false, classLoader);
|
||||
if (!Arrays.asList(klass.getInterfaces()).contains(PluginEntry.class)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
inst.appendToBootstrapClassLoaderSearch(jarFile);
|
||||
|
||||
PluginEntry pluginEntry = (PluginEntry) Class.forName(entryClass).newInstance();
|
||||
pluginEntry.init(FilterConfig.getBySection(pluginEntry.getName()));
|
||||
Dispatcher.getInstance().addTransformers(pluginEntry.getTransformers());
|
||||
|
||||
DebugInfo.output("Plugin loaded: {name=" + pluginEntry.getName() + ", version=" + pluginEntry.getVersion() + "}");
|
||||
} catch (Exception e) {
|
||||
DebugInfo.output("Load plugin failed: " + e.getMessage());
|
||||
addPluginEntry(klass);
|
||||
} catch (Throwable e) {
|
||||
DebugInfo.output("Init plugin failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<Class<? extends PluginEntry>> getAllPluginClasses(Instrumentation inst, File currentDirectory) {
|
||||
List<Class<? extends PluginEntry>> classes = new ArrayList<>();
|
||||
classes.add(DNSFilterPlugin.class);
|
||||
classes.add(URLFilterPlugin.class);
|
||||
|
||||
do {
|
||||
File pluginsDirectory = new File(currentDirectory, PLUGINS_DIR);
|
||||
if (!pluginsDirectory.exists() || !pluginsDirectory.isDirectory()) {
|
||||
break;
|
||||
}
|
||||
|
||||
File[] pluginFiles = pluginsDirectory.listFiles((d, n) -> n.endsWith(".jar"));
|
||||
if (null == pluginFiles) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (File pluginFile : pluginFiles) {
|
||||
try {
|
||||
JarFile jarFile = new JarFile(pluginFile);
|
||||
Manifest manifest = jarFile.getManifest();
|
||||
String entryClass = manifest.getMainAttributes().getValue(ENTRY_NAME);
|
||||
if (StringUtils.isEmpty(entryClass)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PluginClassLoader classLoader = new PluginClassLoader(jarFile);
|
||||
Class<?> klass = Class.forName(entryClass, false, classLoader);
|
||||
if (!Arrays.asList(klass.getInterfaces()).contains(PluginEntry.class)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
inst.appendToBootstrapClassLoaderSearch(jarFile);
|
||||
classes.add((Class<? extends PluginEntry>) Class.forName(entryClass));
|
||||
} catch (Throwable e) {
|
||||
DebugInfo.output("Load plugin failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
} while (false);
|
||||
|
||||
return classes;
|
||||
}
|
||||
|
||||
private void addPluginEntry(Class<? extends PluginEntry> entryClass) throws Exception {
|
||||
PluginEntry pluginEntry = entryClass.newInstance();
|
||||
|
||||
pluginEntry.init(FilterConfig.getBySection(pluginEntry.getName()));
|
||||
Dispatcher.getInstance().addTransformers(pluginEntry.getTransformers());
|
||||
|
||||
DebugInfo.output("Plugin loaded: {name=" + pluginEntry.getName() + ", version=" + pluginEntry.getVersion() + ", author=" + pluginEntry.getAuthor() + "}");
|
||||
}
|
||||
}
|
||||
|
@ -1,21 +1,25 @@
|
||||
package io.zhile.research.ja.netfilter.filters;
|
||||
package io.zhile.research.ja.netfilter.plugins.dns;
|
||||
|
||||
import io.zhile.research.ja.netfilter.commons.DebugInfo;
|
||||
import io.zhile.research.ja.netfilter.models.FilterConfig;
|
||||
import io.zhile.research.ja.netfilter.models.FilterRule;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.util.List;
|
||||
|
||||
public class DNSFilter {
|
||||
private static final String SECTION_NAME = "DNS";
|
||||
private static List<FilterRule> ruleList;
|
||||
|
||||
public static void setRules(List<FilterRule> rules) {
|
||||
ruleList = rules;
|
||||
}
|
||||
|
||||
public static String testQuery(String host) throws IOException {
|
||||
if (null == host) {
|
||||
if (null == host || null == ruleList) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (FilterRule rule : FilterConfig.getBySection(SECTION_NAME)) {
|
||||
for (FilterRule rule : ruleList) {
|
||||
if (!rule.test(host)) {
|
||||
continue;
|
||||
}
|
||||
@ -28,11 +32,11 @@ public class DNSFilter {
|
||||
}
|
||||
|
||||
public static Object testReachable(InetAddress n) throws IOException {
|
||||
if (null == n) {
|
||||
if (null == n || null == ruleList) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (FilterRule rule : FilterConfig.getBySection(SECTION_NAME)) {
|
||||
for (FilterRule rule : ruleList) {
|
||||
if (!rule.test(n.getHostName())) {
|
||||
continue;
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package io.zhile.research.ja.netfilter.plugins.dns;
|
||||
|
||||
import io.zhile.research.ja.netfilter.models.FilterRule;
|
||||
import io.zhile.research.ja.netfilter.plugin.MyTransformer;
|
||||
import io.zhile.research.ja.netfilter.plugin.PluginEntry;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class DNSFilterPlugin implements PluginEntry {
|
||||
private final List<MyTransformer> transformers = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void init(List<FilterRule> filterRules) {
|
||||
transformers.add(new InetAddressTransformer(filterRules));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "DNS";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAuthor() {
|
||||
return "neo";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return "v1.0.0";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "ja-netfilter core: dns plugin";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MyTransformer> getTransformers() {
|
||||
return transformers;
|
||||
}
|
||||
}
|
@ -1,12 +1,22 @@
|
||||
package io.zhile.research.ja.netfilter.transformers;
|
||||
package io.zhile.research.ja.netfilter.plugins.dns;
|
||||
|
||||
import io.zhile.research.ja.netfilter.models.FilterRule;
|
||||
import io.zhile.research.ja.netfilter.plugin.MyTransformer;
|
||||
import jdk.internal.org.objectweb.asm.ClassReader;
|
||||
import jdk.internal.org.objectweb.asm.ClassWriter;
|
||||
import jdk.internal.org.objectweb.asm.tree.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
||||
|
||||
public class InetAddressTransformer implements MyTransformer {
|
||||
private final List<FilterRule> rules;
|
||||
|
||||
public InetAddressTransformer(List<FilterRule> rules) {
|
||||
this.rules = rules;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHookClassName() {
|
||||
return "java/net/InetAddress";
|
||||
@ -14,6 +24,8 @@ public class InetAddressTransformer implements MyTransformer {
|
||||
|
||||
@Override
|
||||
public byte[] transform(String className, byte[] classBytes, int order) throws Exception {
|
||||
DNSFilter.setRules(rules);
|
||||
|
||||
ClassReader reader = new ClassReader(classBytes);
|
||||
ClassNode node = new ClassNode(ASM5);
|
||||
reader.accept(node, 0);
|
||||
@ -22,7 +34,7 @@ public class InetAddressTransformer implements MyTransformer {
|
||||
if ("getAllByName".equals(m.name) && "(Ljava/lang/String;Ljava/net/InetAddress;)[Ljava/net/InetAddress;".equals(m.desc)) {
|
||||
InsnList list = new InsnList();
|
||||
list.add(new VarInsnNode(ALOAD, 0));
|
||||
list.add(new MethodInsnNode(INVOKESTATIC, "io/zhile/research/ja/netfilter/filters/DNSFilter", "testQuery", "(Ljava/lang/String;)Ljava/lang/String;", false));
|
||||
list.add(new MethodInsnNode(INVOKESTATIC, "io/zhile/research/ja/netfilter/plugins/dns/DNSFilter", "testQuery", "(Ljava/lang/String;)Ljava/lang/String;", false));
|
||||
list.add(new InsnNode(POP));
|
||||
|
||||
m.instructions.insert(list);
|
||||
@ -32,7 +44,7 @@ public class InetAddressTransformer implements MyTransformer {
|
||||
if ("isReachable".equals(m.name) && "(Ljava/net/NetworkInterface;II)Z".equals(m.desc)) {
|
||||
InsnList list = new InsnList();
|
||||
list.add(new VarInsnNode(ALOAD, 0));
|
||||
list.add(new MethodInsnNode(INVOKESTATIC, "io/zhile/research/ja/netfilter/filters/DNSFilter", "testReachable", "(Ljava/net/InetAddress;)Ljava/lang/Object;", false));
|
||||
list.add(new MethodInsnNode(INVOKESTATIC, "io/zhile/research/ja/netfilter/plugins/dns/DNSFilter", "testReachable", "(Ljava/net/InetAddress;)Ljava/lang/Object;", false));
|
||||
list.add(new VarInsnNode(ASTORE, 4));
|
||||
list.add(new InsnNode(ACONST_NULL));
|
||||
list.add(new VarInsnNode(ALOAD, 4));
|
@ -1,12 +1,22 @@
|
||||
package io.zhile.research.ja.netfilter.transformers;
|
||||
package io.zhile.research.ja.netfilter.plugins.url;
|
||||
|
||||
import io.zhile.research.ja.netfilter.models.FilterRule;
|
||||
import io.zhile.research.ja.netfilter.plugin.MyTransformer;
|
||||
import jdk.internal.org.objectweb.asm.ClassReader;
|
||||
import jdk.internal.org.objectweb.asm.ClassWriter;
|
||||
import jdk.internal.org.objectweb.asm.tree.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
||||
|
||||
public class HttpClientTransformer implements MyTransformer {
|
||||
private final List<FilterRule> rules;
|
||||
|
||||
public HttpClientTransformer(List<FilterRule> rules) {
|
||||
this.rules = rules;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHookClassName() {
|
||||
return "sun/net/www/http/HttpClient";
|
||||
@ -14,6 +24,8 @@ public class HttpClientTransformer implements MyTransformer {
|
||||
|
||||
@Override
|
||||
public byte[] transform(String className, byte[] classBytes, int order) throws Exception {
|
||||
URLFilter.setRules(rules);
|
||||
|
||||
ClassReader reader = new ClassReader(classBytes);
|
||||
ClassNode node = new ClassNode(ASM5);
|
||||
reader.accept(node, 0);
|
||||
@ -23,7 +35,7 @@ public class HttpClientTransformer implements MyTransformer {
|
||||
InsnList list = new InsnList();
|
||||
list.add(new VarInsnNode(ALOAD, 0));
|
||||
list.add(new FieldInsnNode(GETFIELD, "sun/net/www/http/HttpClient", "url", "Ljava/net/URL;"));
|
||||
list.add(new MethodInsnNode(INVOKESTATIC, "io/zhile/research/ja/netfilter/filters/URLFilter", "testURL", "(Ljava/net/URL;)Ljava/net/URL;", false));
|
||||
list.add(new MethodInsnNode(INVOKESTATIC, "io/zhile/research/ja/netfilter/plugins/url/URLFilter", "testURL", "(Ljava/net/URL;)Ljava/net/URL;", false));
|
||||
list.add(new InsnNode(POP));
|
||||
|
||||
mn.instructions.insert(list);
|
@ -1,22 +1,26 @@
|
||||
package io.zhile.research.ja.netfilter.filters;
|
||||
package io.zhile.research.ja.netfilter.plugins.url;
|
||||
|
||||
import io.zhile.research.ja.netfilter.commons.DebugInfo;
|
||||
import io.zhile.research.ja.netfilter.models.FilterConfig;
|
||||
import io.zhile.research.ja.netfilter.models.FilterRule;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
|
||||
public class URLFilter {
|
||||
private static final String SECTION_NAME = "URL";
|
||||
private static List<FilterRule> ruleList;
|
||||
|
||||
public static void setRules(List<FilterRule> rules) {
|
||||
ruleList = rules;
|
||||
}
|
||||
|
||||
public static URL testURL(URL url) throws IOException {
|
||||
if (null == url) {
|
||||
if (null == url || null == ruleList) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (FilterRule rule : FilterConfig.getBySection(SECTION_NAME)) {
|
||||
for (FilterRule rule : ruleList) {
|
||||
if (!rule.test(url.toString())) {
|
||||
continue;
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package io.zhile.research.ja.netfilter.plugins.url;
|
||||
|
||||
import io.zhile.research.ja.netfilter.models.FilterRule;
|
||||
import io.zhile.research.ja.netfilter.plugin.MyTransformer;
|
||||
import io.zhile.research.ja.netfilter.plugin.PluginEntry;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class URLFilterPlugin implements PluginEntry {
|
||||
private final List<MyTransformer> transformers = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void init(List<FilterRule> filterRules) {
|
||||
transformers.add(new HttpClientTransformer(filterRules));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "URL";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAuthor() {
|
||||
return "neo";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return "v1.0.0";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "ja-netfilter core: url plugin";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MyTransformer> getTransformers() {
|
||||
return transformers;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user