dubbox icon indicating copy to clipboard operation
dubbox copied to clipboard

dubbo-admin同时对多个ip进行黑名单访问控制无效

Open dimmacro opened this issue 9 years ago • 5 comments

在dubbo-admin中对一个服务可以按ip进行访问控制,测试中发现只禁用一个ip才有效果,但是同时禁用多个ip则会整个禁用控制失效,经跟踪代码发现com.alibaba.dubbo.rpc.cluster.router.condition.ConditionRouter.java里的 private static final class MatchPair { final Set<String> matches = new HashSet<String>(); final Set<String> mismatches = new HashSet<String>(); public boolean isMatch(String value, URL param) { for (String match : matches) { if (! UrlUtils.isMatchGlobPattern(match, value, param)) { return false; } } for (String mismatch : mismatches) { if (UrlUtils.isMatchGlobPattern(mismatch, value, param)) { return false; } } return true; } } ismacth方法,当有多个不同的ip禁用时,如上代码所示,只要有一个match值与value不一致,就会返回false,从而使需要禁用的ip也能匹配失败。

dimmacro avatar Sep 01 '16 07:09 dimmacro

路由的时候遇到相同的问题,后面换用IP段来路由。

phoebechengz avatar Feb 17 '17 05:02 phoebechengz

确实,com.alibaba.dubbo.rpc.cluster.router.condition.ConditionRouter.MatchPair#isMatch 这个方法判断是否匹配有问题

daleyzou avatar May 06 '20 14:05 daleyzou

通过自定RouterFactory拓展点可以解决此问题,如下是本人的解决方案:

  1. 定义如下类MyConditionRouterFactory
public class MyConditionRouterFactory implements RouterFactory {
    public static final String NAME = "myCondition";
    public Router getRouter(URL url) {
        return new MyConditionRouter(url);
    }
}
  1. 增加类MyConditionRouter,基于源码com.alibaba.dubbo.rpc.cluster.router.condition.ConditionRouter,并修改如下关键方法
...
private static final class MatchPair {
        final Set<String> matches = new HashSet<String>();
        final Set<String> mismatches = new HashSet<String>();

        public boolean isMatch(String value, URL param) {

            for (String mismatch : mismatches) {
                if (UrlUtils.isMatchGlobPattern(mismatch, value, param)) {
                    return false;
                }
            }

            if (matches.isEmpty()) return true;
           //这里只要任意个匹配,直接返回,形如 application=myConsumer => host = 127.0.0.1,127.0.0.2
            for (String match : matches) {
                if (UrlUtils.isMatchGlobPattern(match, value, param)) {
                    return true;
                }
            }

            return false;
        }
    }
...
  1. 在 META-INF/dubbo增加拓展点配置文件com.alibaba.dubbo.rpc.cluster.RouterFactory,内容: myCondition=xxx.MyConditionRouterFactory

  2. 使用上述自定义路由规则,举例:

RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();
Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://xxx:2181"));
        
//注意这里改为myCondition(协议?^_^)
final URL url = URL.valueOf("myCondition://0.0.0.0/xxx.DemoService?category=routers&force=true&enabled=true&dynamic=false&rule=" +
                URL.encode("application = myConsumer => host = 127.0.0.1,127.0.0.2"));

registry.register(url);


以上

dynastqin avatar Dec 30 '20 12:12 dynastqin

方案二:基于script的路由,思路与myCondition路由大同小异,这是在不改任何源代码的方式来实现(dubbo的script路由很灵活),定义如下:

RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();
Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://xxx:2181"));

String script = "(function route(invokers,invocation){var routeApp='myConsumer';var routeHosts='127.0.0.1,127.0.0.2'.split(',');var result=new java.util.ArrayList();for(var i=0;i<invokers.size();i++){var url=invokers.get(i).getUrl();if(url.getParameter('application')!==routeApp){result.add(invokers.get(i))}else if(routeHosts.indexOf(url.getHost())>=0){result.add(invokers.get(i))}}return result}(invokers,invocation));";

URL url = URL.valueOf("script://0.0.0.0/xxx.DemoService?category=routers&force=true&enabled=true&dynamic=false&type=javascript&rule=" + URL.encode(script));

registry.register(url);

ps 完整的script如下:

(function route(invokers, invocation) {

    var routeApp = 'myConsumer';
    var routeHosts = '127.0.0.1,127.0.0.2'.split(',');

    var result = new java.util.ArrayList();

    for (var i = 0; i < invokers.size(); i++) {
        var url = invokers.get(i).getUrl();

        if (url.getParameter('application') !== routeApp) {
            result.add(invokers.get(i));
        } else if (routeHosts.indexOf(url.getHost()) >= 0) {
            result.add(invokers.get(i));
        }
    }
    return result;
}(invokers, invocation));

dynastqin avatar Feb 25 '21 12:02 dynastqin

方案二:基于script的路由,思路与myCondition路由大同小异,这是在不改任何源代码的方式来实现(dubbo的script路由很灵活),定义如下:

RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();
Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://xxx:2181"));

String script = "(function route(invokers,invocation){var routeApp='myConsumer';var routeHosts='127.0.0.1,127.0.0.2'.split(',');var result=new java.util.ArrayList();for(var i=0;i<invokers.size();i++){var url=invokers.get(i).getUrl();if(url.getParameter('application')!==routeApp){result.add(invokers.get(i))}else if(routeHosts.indexOf(url.getHost())>=0){result.add(invokers.get(i))}}return result}(invokers,invocation));";

URL url = URL.valueOf("script://0.0.0.0/xxx.DemoService?category=routers&force=true&enabled=true&dynamic=false&type=javascript&rule=" + URL.encode(script));

registry.register(url);

ps 完整的script如下:

(function route(invokers, invocation) {

    var routeApp = 'myConsumer';
    var routeHosts = '127.0.0.1,127.0.0.2'.split(',');

    var result = new java.util.ArrayList();

    for (var i = 0; i < invokers.size(); i++) {
        var url = invokers.get(i).getUrl();

        if (url.getParameter('application') !== routeApp) {
            result.add(invokers.get(i));
        } else if (routeHosts.indexOf(url.getHost()) >= 0) {
            result.add(invokers.get(i));
        }
    }
    return result;
}(invokers, invocation));

相当于是推了个js脚本到zookeeper中下发,从ip规则转为脚本规则。 感觉还是升级大法好,哈哈

daleyzou avatar Mar 02 '21 15:03 daleyzou