admin
2022-04-25 bfb5dfa709ec55ab0cc57981b7d1504088d1bfac
应对DDOS攻击IP切换优化
2个文件已修改
345 ■■■■■ 已修改文件
src/main/java/com/yeshi/buwan/job/domain/DDOSJob.java 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/yeshi/buwan/job/domain/TencentCloudCLBUtil.java 274 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/yeshi/buwan/job/domain/DDOSJob.java
@@ -2,6 +2,7 @@
import com.aliyun.alidns20150109.models.DescribeSubDomainRecordsResponseBody;
import com.tencentcloudapi.clb.v20180317.models.LoadBalancer;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import com.yeshi.buwan.domain.live.TVLiveChannel;
@@ -30,6 +31,12 @@
@Component
public class DDOSJob {
    private String getBindIP() throws Exception {
        DescribeSubDomainRecordsResponseBody.DescribeSubDomainRecordsResponseBodyDomainRecordsRecord record = AliyunDomainParseUtil.getIP("api.ysdq.yeshitv.com");
        String ip = record.getValue().trim();
        return ip;
    }
    //切换被腾讯云封堵的IP
    @XxlJob("ddos-buwan-server-change")
    public ReturnT<String> buwanServerChange(String params) throws Exception {
@@ -40,18 +47,30 @@
        List<String> blockIPS = new ArrayList<>();
        List<String> normalIPS = new ArrayList<>();
        List<LoadBalancer> normals = new ArrayList<>();
        for (LoadBalancer b : balances) {
            if (b.getIsBlock()) {
                blockIPS.add(b.getLoadBalancerVips()[0].trim());
            } else {
                normalIPS.add(b.getLoadBalancerVips()[0].trim());
                normals.add(b);
            }
        }
        //无封堵
        if (blockIPS.size() == 0) {
            //在没有封堵的情况下删除多余的负载均衡
            if (normalIPS.size() > 2) {
                deleteMore(normals, getBindIP());
            }
            return ReturnT.SUCCESS;
        }
        //删除多余的负载均衡
        if (normalIPS.size() > 2) {
            deleteMore(normals, getBindIP());
        }
        //获取阿里云解析的域名
        DescribeSubDomainRecordsResponseBody.DescribeSubDomainRecordsResponseBodyDomainRecordsRecord record = AliyunDomainParseUtil.getIP("api.ysdq.yeshitv.com");
@@ -67,16 +86,54 @@
            throw new Exception("腾讯云负载均衡IP已全部被封堵,请增加IP");
        }
        AliyunDomainParseUtil.setIP(record, normalIPS.get(normalIPS.size() - 1));
        //每次切换IP后需要判断是否需要增加IP,用于创建新的负载均衡
        autoAdd(normalIPS.size(), balances.length);
        return ReturnT.SUCCESS;
    }
//    public static void main(String[] args){
//        try {
//            new DDOSJob().buwanServerChange("");
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//    }
    private void autoAdd(int normalIPCount, int totalCount) throws TencentCloudSDKException {
        if (normalIPCount < 2) {
            //始终保持2个正常IP
            TencentCloudCLBUtil.createBuWanCLB(totalCount);
        }
    }
    //删除多余的
    private void deleteMore(List<LoadBalancer> normals, String bindIP) throws TencentCloudSDKException {
        if (StringUtil.isNullOrEmpty(bindIP)) {
            return;
        }
        if (normals.size() > 2) {
            //始终保持2个正常IP
            int deleteCount = normals.size() - 2;
            List<String> bids = new ArrayList<>();
            for (LoadBalancer balancer : normals) {
                //没有绑定,并且还能删除
                if (!balancer.getLoadBalancerVips()[0].trim().equalsIgnoreCase(bindIP)) {
                    if (bids.size() < deleteCount) {
                        bids.add(balancer.getLoadBalancerId());
                    }
                }
            }
            if (bids.size() > 0) {
                for (String bid : bids) {
                    TencentCloudCLBUtil.deleteCLB(bid);
                }
            }
        }
    }
    public static void main(String[] args){
        try {
            new DDOSJob().buwanServerChange("");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
src/main/java/com/yeshi/buwan/job/domain/TencentCloudCLBUtil.java
@@ -1,13 +1,15 @@
package com.yeshi.buwan.job.domain;
import com.tencentcloudapi.clb.v20180317.ClbClient;
import com.tencentcloudapi.clb.v20180317.models.DescribeLoadBalancersRequest;
import com.tencentcloudapi.clb.v20180317.models.DescribeLoadBalancersResponse;
import com.tencentcloudapi.clb.v20180317.models.LoadBalancer;
import com.tencentcloudapi.clb.v20180317.models.*;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.yeshi.buwan.util.TimeUtil;
import java.util.Arrays;
import java.util.List;
/**
 * @author hxh
@@ -51,9 +53,271 @@
    }
    /**
     * @return java.lang.String[]
     * @author hxh
     * @description 添加负载均衡
     * @date 17:24 2022/4/25
     * @param: name CLB名称
     **/
    public static String[] addCLB(String name) throws TencentCloudSDKException {
        Credential cred = new Credential(SECRET_ID, SECRET_KEY);
        // 实例化一个http选项,可选的,没有特殊需求可以跳过
        HttpProfile httpProfile = new HttpProfile();
        httpProfile.setEndpoint("clb.tencentcloudapi.com");
        // 实例化一个client选项,可选的,没有特殊需求可以跳过
        ClientProfile clientProfile = new ClientProfile();
        clientProfile.setHttpProfile(httpProfile);
        // 实例化要请求产品的client对象,clientProfile是可选的
        ClbClient client = new ClbClient(cred, "ap-guangzhou", clientProfile);
        // 实例化一个请求对象,每个接口都会对应一个request对象
        CreateLoadBalancerRequest req = new CreateLoadBalancerRequest();
        req.setLoadBalancerType("OPEN");
        req.setLoadBalancerName(name);
        // 返回的resp是一个CreateLoadBalancerResponse的实例,与请求对象对应
        CreateLoadBalancerResponse resp = client.CreateLoadBalancer(req);
        return resp.getLoadBalancerIds();
        // 输出json格式的字符串回包
    }
    public static LoadBalancer getCLB(String balanceId) throws TencentCloudSDKException {
        Credential cred = new Credential(SECRET_ID, SECRET_KEY);
        // 实例化一个http选项,可选的,没有特殊需求可以跳过
        HttpProfile httpProfile = new HttpProfile();
        httpProfile.setEndpoint("clb.tencentcloudapi.com");
        // 实例化一个client选项,可选的,没有特殊需求可以跳过
        ClientProfile clientProfile = new ClientProfile();
        clientProfile.setHttpProfile(httpProfile);
        // 实例化要请求产品的client对象,clientProfile是可选的
        ClbClient client = new ClbClient(cred, "ap-guangzhou", clientProfile);
        // 实例化一个请求对象,每个接口都会对应一个request对象
        DescribeLoadBalancersRequest req = new DescribeLoadBalancersRequest();
        String[] loadBalancerIds1 = {balanceId};
        req.setLoadBalancerIds(loadBalancerIds1);
        // 返回的resp是一个DescribeLoadBalancersResponse的实例,与请求对象对应
        DescribeLoadBalancersResponse resp = client.DescribeLoadBalancers(req);
        return resp.getLoadBalancerSet()[0];
    }
    public static void deleteCLB(String balanceId) throws TencentCloudSDKException {
        Credential cred = new Credential(SECRET_ID, SECRET_KEY);
        // 实例化一个http选项,可选的,没有特殊需求可以跳过
        HttpProfile httpProfile = new HttpProfile();
        httpProfile.setEndpoint("clb.tencentcloudapi.com");
        // 实例化一个client选项,可选的,没有特殊需求可以跳过
        ClientProfile clientProfile = new ClientProfile();
        clientProfile.setHttpProfile(httpProfile);
        // 实例化要请求产品的client对象,clientProfile是可选的
        ClbClient client = new ClbClient(cred, "ap-guangzhou", clientProfile);
        // 实例化一个请求对象,每个接口都会对应一个request对象
        DeleteLoadBalancerRequest req = new DeleteLoadBalancerRequest();
        String[] loadBalancerIds1 = {balanceId};
        req.setLoadBalancerIds(loadBalancerIds1);
        // 返回的resp是一个DeleteLoadBalancerResponse的实例,与请求对象对应
        DeleteLoadBalancerResponse resp = client.DeleteLoadBalancer(req);
        // 输出json格式的字符串回包
    }
    /**
     * @return java.lang.String[]
     * @author hxh
     * @description 添加监听器
     * @date 17:26 2022/4/25
     * @param: balanceId
     * @param: port
     **/
    public static String[] addListener(String balanceId, Long port) throws TencentCloudSDKException {
        // 实例化一个认证对象,入参需要传入腾讯云账户secretId,secretKey,此处还需注意密钥对的保密
        // 密钥可前往https://console.cloud.tencent.com/cam/capi网站进行获取
        Credential cred = new Credential(SECRET_ID, SECRET_KEY);
        // 实例化一个http选项,可选的,没有特殊需求可以跳过
        HttpProfile httpProfile = new HttpProfile();
        httpProfile.setEndpoint("clb.tencentcloudapi.com");
        // 实例化一个client选项,可选的,没有特殊需求可以跳过
        ClientProfile clientProfile = new ClientProfile();
        clientProfile.setHttpProfile(httpProfile);
        // 实例化要请求产品的client对象,clientProfile是可选的
        ClbClient client = new ClbClient(cred, "ap-guangzhou", clientProfile);
        // 实例化一个请求对象,每个接口都会对应一个request对象
        CreateListenerRequest req = new CreateListenerRequest();
        req.setLoadBalancerId(balanceId);
        Long[] ports1 = {port};
        req.setPorts(ports1);
        req.setProtocol("TCP");
        // 返回的resp是一个CreateListenerResponse的实例,与请求对象对应
        CreateListenerResponse resp = client.CreateListener(req);
        return resp.getListenerIds();
    }
    /**
     * @return com.tencentcloudapi.clb.v20180317.models.Listener[]
     * @author hxh
     * @description 获取负载均衡的监听器接口
     * @date 17:10 2022/4/25
     * @param: balanceId
     **/
    public static Listener[] listListner(String balanceId) throws TencentCloudSDKException {
        // 实例化一个认证对象,入参需要传入腾讯云账户secretId,secretKey,此处还需注意密钥对的保密
        // 密钥可前往https://console.cloud.tencent.com/cam/capi网站进行获取
        Credential cred = new Credential(SECRET_ID, SECRET_KEY);
        // 实例化一个http选项,可选的,没有特殊需求可以跳过
        HttpProfile httpProfile = new HttpProfile();
        httpProfile.setEndpoint("clb.tencentcloudapi.com");
        // 实例化一个client选项,可选的,没有特殊需求可以跳过
        ClientProfile clientProfile = new ClientProfile();
        clientProfile.setHttpProfile(httpProfile);
        // 实例化要请求产品的client对象,clientProfile是可选的
        ClbClient client = new ClbClient(cred, "ap-guangzhou", clientProfile);
        // 实例化一个请求对象,每个接口都会对应一个request对象
        DescribeListenersRequest req = new DescribeListenersRequest();
        req.setLoadBalancerId(balanceId);
        // 返回的resp是一个DescribeListenersResponse的实例,与请求对象对应
        DescribeListenersResponse resp = client.DescribeListeners(req);
        return resp.getListeners();
    }
    /**
     * @return void
     * @author hxh
     * @description 绑定负载均衡
     * @date 17:11 2022/4/25
     * @param: balancerId
     * @param: listenerId
     * @param: servers
     **/
    public static void bindServer(String balancerId, String listenerId, List<BindServerInfo> servers) throws TencentCloudSDKException {
        Credential cred = new Credential(SECRET_ID, SECRET_KEY);
        // 实例化一个http选项,可选的,没有特殊需求可以跳过
        HttpProfile httpProfile = new HttpProfile();
        httpProfile.setEndpoint("clb.tencentcloudapi.com");
        // 实例化一个client选项,可选的,没有特殊需求可以跳过
        ClientProfile clientProfile = new ClientProfile();
        clientProfile.setHttpProfile(httpProfile);
        // 实例化要请求产品的client对象,clientProfile是可选的
        ClbClient client = new ClbClient(cred, "ap-guangzhou", clientProfile);
        // 实例化一个请求对象,每个接口都会对应一个request对象
        RegisterTargetsRequest req = new RegisterTargetsRequest();
        req.setLoadBalancerId(balancerId);
        req.setListenerId(listenerId);
        Target[] targets1 = new Target[servers.size()];
        for (int i = 0; i < servers.size(); i++) {
            Target target = new Target();
            target.setType("CVM");
            target.setInstanceId(servers.get(i).getCvmInstanceId());
            target.setPort(servers.get(i).getPort());
            target.setWeight(servers.get(i).getWeight());
            targets1[i] = target;
        }
        req.setTargets(targets1);
        // 返回的resp是一个RegisterTargetsResponse的实例,与请求对象对应
        RegisterTargetsResponse resp = client.RegisterTargets(req);
        // 输出json格式的字符串回包
        System.out.println(RegisterTargetsResponse.toJsonString(resp));
    }
    public static void createBuWanCLB(int count) throws TencentCloudSDKException {
        String[] clbs = addCLB("布丸-备用" + count + "-" + TimeUtil.getGernalTime(System.currentTimeMillis(), "yyyyMMddHHmmss"));
        if (clbs.length > 0) {
            String balancerId = clbs[0];
            //查询是否正常
            for (int i = 0; i < 5; i++) {
                LoadBalancer balancer = getCLB(balancerId);
                if (balancer.getStatus() == 1) {
                    break;
                }
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            try {
                String[] listeners = addListener(balancerId, 8089L);
                if (listeners.length > 0) {
                    for (int j = 0; j < 5; j++) {
                        try {
                            bindServer(balancerId, listeners[0], Arrays.asList(new BindServerInfo[]{
                                    new BindServerInfo("ins-j7d29j8o", 8089L, 10L),
                                    new BindServerInfo("ins-j7d29j8o", 8086L, 1L),
                            }));
                            break;
                        } catch (Exception e) {
                            Thread.sleep(1000);
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
                for (int i = 0; i < 5; i++) {
                    try {
                        deleteCLB(balancerId);
                        break;
                    } catch (Exception e1) {
                        e1.printStackTrace();
                        try {
                            Thread.sleep(2000);
                        } catch (InterruptedException e2) {
                            e2.printStackTrace();
                        }
                    }
                }
            }
        }
    }
    public static void main(String[] args) throws TencentCloudSDKException {
        LoadBalancer[] bs = TencentCloudCLBUtil.getCLBList("布丸-备用");
        System.out.println(bs);
        deleteCLB("lb-rmp1hyzm");
    }
    static class BindServerInfo {
        //ins-j7d29j8o
        private String cvmInstanceId;
        private long port;
        private long weight;
        public BindServerInfo(String cvmInstanceId, long port, long weight) {
            this.cvmInstanceId = cvmInstanceId;
            this.port = port;
            this.weight = weight;
        }
        public String getCvmInstanceId() {
            return cvmInstanceId;
        }
        public void setCvmInstanceId(String cvmInstanceId) {
            this.cvmInstanceId = cvmInstanceId;
        }
        public long getPort() {
            return port;
        }
        public void setPort(long port) {
            this.port = port;
        }
        public long getWeight() {
            return weight;
        }
        public void setWeight(long weight) {
            this.weight = weight;
        }
    }