Как проверить, работает ли максимальное количество подключений (и максимальное количество подключений в секунду)

Я добавил следующие правила в свои правила iptables:

#limit numbeer of connections
iptables -t filter -I INPUT -p tcp --syn --dport 80 -m connlimit  --connlimit-above 15 --connlimit-mask 32 -j DROP
iptables -t filter -I INPUT -p tcp --syn --dport 443 -m connlimit  --connlimit-above 15 --connlimit-mask 32 -j DROP
iptables -t filter -I INPUT -p tcp --syn --dport 8008 -m connlimit  --connlimit-above 15 --connlimit-mask 32 -j DROP

iptables -I INPUT -p tcp --dport 80 -m state --state NEW -m recent
--set iptables -I INPUT -p tcp --dport 80 -m state --state NEW -m recent --update --seconds 2 --hitcount 25 -j DROP iptables -I INPUT -p tcp --dport 443 -m state --state NEW -m recent --set iptables -I INPUT
-p tcp --dport 443 -m state --state NEW -m recent --update --seconds 2 --hitcount 25 -j DROP iptables -I INPUT -p tcp --dport 8008 -m state --state NEW -m recent --set iptables -I INPUT -p tcp --dport 8008 -m state --state NEW -m recent --update --seconds 2 --hitcount 25 -j DROP

Вот так выглядят полные правила iptables:

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
DROP       tcp  --  anywhere             anywhere             tcp dpt:ssh state NEW recent: UPDATE seconds: 60 hit_count: 3 TTL-Match name: sshprobe side: source mask: 255.255.255.255
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:ssh state NEW recent: SET name: sshprobe side: source mask: 255.255.255.255
DROP       tcp  --  anywhere             anywhere             tcp dpt:8008 state NEW recent: UPDATE seconds: 2 hit_count: 25 name: DEFAULT side: source mask: 255.255.255.255
           tcp  --  anywhere             anywhere             tcp dpt:8008 state NEW recent: SET name: DEFAULT side: source mask: 255.255.255.255
DROP       tcp  --  anywhere             anywhere             tcp dpt:https state NEW recent: UPDATE seconds: 2 hit_count: 25 name: DEFAULT side: source mask: 255.255.255.255
           tcp  --  anywhere             anywhere             tcp dpt:https state NEW recent: SET name: DEFAULT side: source mask: 255.255.255.255
DROP       tcp  --  anywhere             anywhere             tcp dpt:http state NEW recent: UPDATE seconds: 2 hit_count: 25 name: DEFAULT side: source mask: 255.255.255.255
           tcp  --  anywhere             anywhere             tcp dpt:http state NEW recent: SET name: DEFAULT side: source mask: 255.255.255.255
DROP       tcp  --  anywhere             anywhere             tcp dpt:8008 flags:FIN,SYN,RST,ACK/SYN #conn src/32 > 15
DROP       tcp  --  anywhere             anywhere             tcp dpt:https flags:FIN,SYN,RST,ACK/SYN #conn src/32 > 15
DROP       tcp  --  anywhere             anywhere             tcp dpt:http flags:FIN,SYN,RST,ACK/SYN #conn src/32 > 15
ACCEPT     all  --  anywhere             anywhere             state RELATED,ESTABLISHED
ACCEPT     all  --  anywhere             anywhere            
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:http
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:ssh
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:http-alt
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:8181
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:https
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:8008
DROP       all  --  anywhere             anywhere            

Chain FORWARD (policy DROP)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination 

Я хотел бы проверить, работает ли эта новая политика.

Как я могу проверить это? Я попытался использовать тест Apache, чтобы проверить, не обрываются ли некоторые соединения с моего локального хоста:

ab -n 10000 -c 9000 http://www.tralev.com/web/main

Но из вывода я не вижу, чтобы какое-либо соединение было прервано:

Failed requests:        82
   (Connect: 0, Receive: 0, Length: 82, Exceptions: 0)

(эта ошибка длины, вероятно, связана с некоторым динамическим содержимым на сервере).

Итак, как я могу исправить свои настройки iptables или настроить тест, который показывает, что текущие настройки фактически ограничивают количество подключений с IP-адреса до 15 (и максимальное количество подключений в секунду до 15)?


person Mladen Adamovic    schedule 04.03.2017    source источник


Ответы (1)


Поскольку никто не ответил на это сообщение более 24 часов, я написал код Java для проверки ответа сервера. Код ниже для справки. Кстати, кажется, что мои правила iptables не работают (из-за выполнения кода).

public class TestConcurrentCalls {

  class Tester implements Runnable {

    String url;
    boolean error;
    TestConcurrentCalls parent;

    public Tester(String url, TestConcurrentCalls parent) {
      this.url = url;
      this.parent = parent;
    }

    @Override
    public void run() {
      String content = WebOperations.getFromURL(url).toString();
      if (content == null || content.length() < 10) {
        synchronized (parent) {
          parent.errors++;
        }
      } else {
        synchronized (parent) {
          parent.ok++;
        }
      }
    }
  }

  static public int errors = 0;
  static public int ok = 0;

  public void test(String url, int threads) {
    for (int thread = 0; thread < threads; thread++) {
      testOne(url);
    }
    int sleeps = 0;
    try {
      do {
        Thread.sleep(1000L);
        sleeps++;
      } while (threads > errors + ok || sleeps > 1000);
    } catch (InterruptedException ex) {
      Logger.getLogger(TestConcurrentCalls.class.getName()).log(Level.SEVERE, null, ex);
    }
  }

  public void testOne(String url) {
    Tester tester = new Tester(url, this);
    Thread thread = new Thread(tester);
    thread.start();
  }

  public static void main(String[] args) {
    TestConcurrentCalls test = new TestConcurrentCalls();
    test.test("http://www.tralev.com/web/main", 1000);
    System.out.println("Errors: " + errors + "    , ok: " + ok);
  }

}

Этот код использует мой внутренний метод WebOperations.getFromUrl, который написан следующим образом:

  public static StringBuilder getFromURL(String address) {
    return getFromURL(address, null);
  }

  public static StringBuilder getFromURL(String address,String referer) {
    return getFromURL(address, referer, 60, null); // wait one minute at most
  }


  public static StringBuilder getFromURL(String address,String referer, int maxSecondsToWait, String accept) {

    StringBuilder result=new StringBuilder();
    try {
        if(!address.toLowerCase().contains("://"))
            address="http://"+address;
        Logger.getLogger(WebOperations.class.getName()).info("URL for fetching " + address);
        URL url = new URL(address);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
      connection.setConnectTimeout(maxSecondsToWait * 1000); 
      if (accept != null) {
        connection.setRequestProperty("Accept", accept);
      }
      connection.setReadTimeout(maxSecondsToWait * 1000);
      connection.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)");
      //connection.setRequestProperty("Accept","*/*");
      if (referer != null && !referer.equals("")) {
        connection.setRequestProperty("From", referer);
        connection.setRequestProperty("Referer", referer);
      }

      // Get all cookies from the server.
      // Note: The first call to getHeaderFieldKey() will implicit send
      // the HTTP request to the server.
      for (int i = 0;; i++) {
        String headerName = connection.getHeaderFieldKey(i);
        String headerValue = connection.getHeaderField(i);

        if (headerName == null && headerValue == null) {
          // No more headers
          break;
        }
        if ("Set-Cookie".equalsIgnoreCase(headerName)) {
          // Parse cookie
          String[] fields = headerValue.split(";\\s*");

          String cookieValue = fields[0];
          String expires = null;
          String path = null;
          String domain = null;
          boolean secure = false;

          // Parse each field
          for (int j = 1; j < fields.length; j++) {
            if ("secure".equalsIgnoreCase(fields[j])) {
              secure = true;
            } else if (fields[j].indexOf('=') > 0) {
              String[] f = fields[j].split("=");
              if ("expires".equalsIgnoreCase(f[0])) {
                expires = f[1];
              } else if ("domain".equalsIgnoreCase(f[0])) {
                domain = f[1];
              } else if ("path".equalsIgnoreCase(f[0])) {
                path = f[1];
              }
            }
          }

        // Save the cookie...

        }
      }

      int responseCode = 200;
      //try {
      //responseCode = connection.getResponseCode();
      //} catch (SocketException e) {
      //  Logger.getLogger(WebOperations.class.getName()).log(Level.SEVERE, e.getMessage(), e);
      //}
      if (responseCode >= 400 && responseCode < 600) {
        return result;
      }
      String contentType = connection.getContentType();
        if (contentType == null) {
          contentType = "html";
        }
        String nameContentType=contentType.toLowerCase();
        if(nameContentType.contains("html") || nameContentType.contains("text") || nameContentType.contains("txt") || nameContentType.contains("json") || nameContentType.contains("json")) {
            BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            String inputLine;
            while ((inputLine = in.readLine()) != null ) {
                result.append(inputLine).append("\n");
            }
            in.close();
        }
    } catch (Exception e) {
        if(e instanceof MalformedURLException) {
            System.err.println("MalformedURLException for "+address);
        }
        //System.err.println(e.getMessage());
        Logger.getLogger(WebOperations.class.getName()).log(Level.WARNING, "Exception while reading web page", e);
    }
    return result;
}
person Mladen Adamovic    schedule 06.03.2017