wtorek, 15 stycznia 2013

Linux: UDP buffer monitoring utility (udpstat)

Udp statistics tool

The goals

The goal for this utility was to:

1. Present /proc/net/udp in human readable form:
- timestamp
- local address - from hex to dot notated (in case of IPv6 in hex) + port
- remote address - from hex to dot notated (in case of IPv6 in hex) + port
- rx, tx queue - in bytes, kbytes, mbytes (constrolled by parameter)
- drops

2. Constant monitoring with configurable interval polling:
- statistics presented every n seconds
- monitor interval controlled by command line parameter
- number of polls controlled by command line interface

3. Print Per pid statistics - present udp statistics per pid (/proc//net/udp)

4. Print kernel configuration parameters: max size + utilization of the buffer (rx queue / rx max size & tx queue / tx max size)

Where it can be downloaded from?

It has become a part of the yapcg project. The latest version available here: http://code.google.com/p/yapcg/source/browse/measurements/perftools/udpstat should meet all the goals . You can give it a try - what you will need is ruby 1.9.3 with optparse, ostruct gems (should be available in standard installation, at least these was the case on my Ubuntu 12.10 box)

The syntax of the utility is:


$ udpstat
Usage: udpstat [options]

Specific options:
    -6, --ipv6                       Enable IPv6 stat parsing
    -K, --kilobytes                  Present values in kilobytes
    -M, --megabytes                  Present values in megabytes
    -p, --ppid pid                   PID of the process to be monitored

Common options:
    -h, --help                       Show this message
    -v, --version                    Show version

    - interval in which statistics are to be reported
       - the number of statistics to be shown

@2013 Krystian Brachmanski, Wroclaw


As previously mentioned it has been verified on Ubuntu 12.10 64-bit OS, running 3.5.0-21-generic kernel and ruby 1.9.3p194 (2012-04-20 revision 35410) [x86_64-linux].

How to use it?

I always say that I learn the most on examples therefore I recommend to check another article on my blog to see how you can truoubleshoot a simulated udp buffer problem in the application.

poniedziałek, 14 stycznia 2013

Ubuntu 12.10: UDP buffer monitoring (kernel 3.5.0-21)

Some time ago I was involved in analysis of a networking problem, the symptom of which were client-side timeouts (no answer received). The protocol was standardized, based on UDP.

Let's first analyze the flow of information from network adapter towards the application. There is an excellent document provided by RedHat as part of their OS documentation - it can be found here. I recommend reading chapter 8 about networking. In general the flow looks as presented on the pic below:

Figure 1 Packet reception diagram (from RedHat Performance Tuning Guide)


Hardware/interrupt buffers

These are internal HW buffers inside the network interface card (NIC). If you see hw buffer overruns on your system the only thing that you will know is that the transfer rate is too high for this interface. The document previously mentioned gives indication how to monitor it using ethtool and what you could do to minimize the impact.

You can monitor this using tools getting stats from the NIC like ifconfig. Below you can find an example from my Ubuntu box (overruns indicate the number of times the HW buffer overrun happened):

$ ifconfig eth0
eth0      Link encap:Ethernet  HWaddr b4:99:ba:e8:d3:6c 
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0
overruns:0 frame:0
          TX packets:0 errors:0 dropped:0
overruns:0 carrier:0          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
          Interrupt:20 Memory:d7500000-d7520000





UDP socket buffers

There is a lot explained what can be tuned in the document mentioned above. I will only try to explain how it can happen that the buffer queue will grow. In order to do that I will prepare a sample Java application (a modification of UDP echo client/server app). It consists of the server application and client one.

Test application

The client will be sending every 10 milliseconds an UDP datagram containing 64 bytes long string (16 times the word "test").

The server on the other hand will be one-thread application reading from socket. The reading thread after retrieving information from the socket will be sleeping for 1 second - 1s is set to show the effect in shorter timeframe but please notice any value above 10 ms (sleep on the client side) will cause this behaviour. In general such problem might happen in real life scenario if the same thread that is reading from socket is doing some processing.

Code for udp echo client:
package org.krystianek.udp.test.echo;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.logging.Logger;
 

public class EchoClient {

          public static void main(String[] args) throws Exception {
                    String hostname = "localhost";
                    InetAddress ia = InetAddress.getByName(hostname);
                    SenderThread sender = new SenderThread(ia, 9999);
                    sender.start();
                  }

}

class SenderThread extends Thread {

          private InetAddress server;
          private DatagramSocket socket;
          private boolean stopped = false;
          private int port;

          public SenderThread(InetAddress address, int port) throws SocketException {
            this.server = address;
            this.port = port;
            this.socket = new DatagramSocket();
            this.socket.connect(server, port);
          }

          public void halt() {
            this.stopped = true;
          }

          public DatagramSocket getSocket() {
            return this.socket;
          }

          public void run() {

            try {
              String theLine ="test
testtesttesttesttesttesttesttesttesttesttesttesttesttesttest";
              while (true) {
                byte[] data = theLine.getBytes();
                DatagramPacket output = new DatagramPacket(data, data.length, server, port);

                System.out.println("Sending : " + output.getData().length + " bytes ");
                socket.send(output);
                Thread.yield();
                Thread.sleep(100);
              }

            }
            catch (Exception ex) {
              System.err.println(ex);
            }
          }
        }


Code for udp echo server:

package org.krystianek.udp.test.echo;

import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;

/**
 * @author krychu
 *
 */
public class EchoServer {

        public static void main(String[] args) throws Exception {
                DatagramChannel channel = DatagramChannel.open();
                DatagramSocket socket = channel.socket();
                SocketAddress address = new InetSocketAddress(9999);
                socket.bind(address);
                ByteBuffer buffer = ByteBuffer.allocateDirect(65507);
                while (true) {
                        SocketAddress client = channel.receive(buffer);
                        try {
                           Thread.sleep(1000);
                        } catch (Exception ex) {
                           ex.printStackTrace();
                        }

                        buffer.flip();
//                      System.out.println("Server received : " + buffer);
//                      channel.send(buffer, client);
//                      buffer.clear();

                }
        }

}


For the test the classes have been packaged into echo-0.0.1-SNAPSHOT.jar using maven build system.

Monitoring the system

The next step was to identify how to monitor the buffer utilization. There are different ways - in my article I will use the statistics available in the proc filesystem - quite good description can be found in the man page:


$ man proc
...




/proc/net/udp
Holds a dump of the UDP socket table. Much of the information is not of use apart from debugging. The "sl" value is the kernel hash slot for the socket, the "local_address" is the local address and port number pair. The "rem_address" is the remote address and port number pair (if connected). "St" is the internal status of the socket. The "tx_queue" and "rx_queue" are the outgoing and incoming data queue in terms of kernel memory usage. The "tr", "tm->when", and "rexmits" fields are not used by UDP. The "uid" field holds the effective UID of the creator of the socket. The format is:
sl  local_address rem_address   st tx_queue rx_queue tr rexmits  tm->when uid
1: 01642C89:0201 0C642C89:03FF 01 00000000:00000001 01:000071BA 00000000 0
1: 00000000:0801 00000000:0000 0A 00000000:00000000 00:00000000 6F000100 0
1: 00000000:0201 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0
...

There are two files available one for IPv4 (/proc/net/udp) and IPv6 (/proc/net/udp6) - the example output can be found below

$ cat /proc/net/udp
  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode ref pointer drops            
  564: 00000000:0801 00000000:0000 07 00000000:00000000 00:00000000 00000000     0        0 13276 2 0000000000000000 0        
  601: 00000000:E026 00000000:0000 07 00000000:00000000 00:00000000 00000000   118        0 12564 2 0000000000000000 0        
...
 1833: 00000000:9CF6 00000000:0000 07 00000000:00000000 00:00000000 00000000     0        0 13808 2 0000000000000000 0        
 1884: 00000000:ED29 00000000:0000 07 00000000:00000000 00:00000000 00000000     0        0 1145241 2 0000000000000000 0      
$

$ cat /proc/net/udp6
  sl  local_address                         remote_address                        st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode ref pointer drops
    2: 00000000000000000000000000000000:ADCF 00000000000000000000000000000000:0000 07 00000000:00000000 00:00000000 00000000     0        0 13287 2 0000000000000000 0
   37: 00000000000000000000000000000000:9DF2 00000000000000000000000000000000:0000 07 00000000:00000000 00:00000000 00000000   104        0 10786 2 0000000000000000 0
...
 1820: 00000000000000000000000000000000:14E9 00000000000000000000000000000000:0000 07 00000000:00000000 00:00000000 00000000   104        0 10784 2 0000000000000000 0 2024: 00000000000000000000000000000000:B5B5 00000000000000000000000000000000:0000 07 00000000:00000000 00:00000000 00000000     0        0 13796 2 0000000000000000 0


In addition I developed a simple ruby script for parsing the udp stats.
The full parameter set for the utility:

$ udpstat
Usage: udpstat [options]

Specific options:
    -6, --ipv6                       Enable IPv6 stat parsing
    -K, --kilobytes                  Present values in kilobytes
    -M, --megabytes                  Present values in megabytes
    -p, --ppid pid                   PID of the process to be monitored

Common options:
    -h, --help                       Show this message
    -v, --version                    Show version

    - interval in which statistics are to be reported
       - the number of statistics to be shown

@2013 Krystian Brachmanski, Wroclaw


The example dump can be found below:

$ ./measurements/perftools/udpstat -6 1 2
   Timestamp       Local IP:port        Remote IP:port    rx[B]   rbuf[B]     tx[B]   tbuf[B]   drops
  1353956875 00000000000000000000000000000000:44495 00000000000000000000000000000000:0            0  1048576        0  1048576       0
  1353956875 00000000000000000000000000000000:40434 00000000000000000000000000000000:0            0  1048576        0  1048576       0
  1353956875 00000000000000000000000000000000:24105 00000000000000000000000000000000:0            0  1048576        0  1048576       0
  1353956875 00000000000000000000000000000000:36499 00000000000000000000000000000000:0            0  1048576        0  1048576       0
  1353956875 00000000000000000000000000000000:51186 00000000000000000000000000000000:0            0  1048576        0  1048576       0
  1353956875 00000000000000000000000000000000:2049  00000000000000000000000000000000:0            0  1048576        0  1048576       0
  1353956875 00000000000000000000000000000000:111   00000000000000000000000000000000:0            0  1048576        0  1048576       0
  1353956875 00000000000000000000000001000000:123   00000000000000000000000000000000:0            0  1048576        0  1048576       0
  1353956875 000080FE00000000FFD724029C55BDFE:123   00000000000000000000000000000000:0            0  1048576        0  1048576       0
  1353956875 00000000000000000000000000000000:123   00000000000000000000000000000000:0            0  1048576        0  1048576       0
  1353956875 00000000000000000000000000000000:45593 00000000000000000000000000000000:0            0  1048576        0  1048576       0
  1353956875 00000000000000000000000000000000:612   00000000000000000000000000000000:0            0  1048576        0  1048576       0
  1353956875 00000000000000000000000000000000:5353  00000000000000000000000000000000:0            0  1048576        0  1048576       0
  1353956875 00000000000000000000000000000000:46517 00000000000000000000000000000000:0            0  1048576        0  1048576       0
  1353956876 00000000000000000000000000000000:44495 00000000000000000000000000000000:0            0  1048576        0  1048576       0
  1353956876 00000000000000000000000000000000:40434 00000000000000000000000000000000:0            0  1048576        0  1048576       0
  1353956876 00000000000000000000000000000000:24105 00000000000000000000000000000000:0            0  1048576        0  1048576       0
  1353956876 00000000000000000000000000000000:36499 00000000000000000000000000000000:0            0  1048576        0  1048576       0
  1353956876 00000000000000000000000000000000:51186 00000000000000000000000000000000:0            0  1048576        0  1048576       0
  1353956876 00000000000000000000000000000000:2049  00000000000000000000000000000000:0            0  1048576        0  1048576       0
  1353956876 00000000000000000000000000000000:111   00000000000000000000000000000000:0            0  1048576        0  1048576       0
  1353956876 00000000000000000000000001000000:123   00000000000000000000000000000000:0            0  1048576        0  1048576       0
  1353956876 000080FE00000000FFD724029C55BDFE:123   00000000000000000000000000000000:0            0  1048576        0  1048576       0
  1353956876 00000000000000000000000000000000:123   00000000000000000000000000000000:0            0  1048576        0  1048576       0
  1353956876 00000000000000000000000000000000:45593 00000000000000000000000000000000:0            0  1048576        0  1048576       0
  1353956876 00000000000000000000000000000000:612   00000000000000000000000000000000:0            0  1048576        0  1048576       0
  1353956876 00000000000000000000000000000000:5353  00000000000000000000000000000000:0            0  1048576        0  1048576       0
  1353956876 00000000000000000000000000000000:46517 00000000000000000000000000000000:0            0  1048576        0  1048576       0


You can find the utility in google code as part of the yapcg tool: http://code.google.com/p/yapcg/source/browse/measurements/perftools/udpstat

Testing the UDP buffers

Configuration of the test application (actually it is in the code):
- udp port: 9999
- IPv6 socket listening
- system settings:
     net.core.rmem_default = 1048576
     net.core.rmem_max = 1048576

1. Starting the Echo UDP server in the background:
$ java -cp ./target/echo-0.0.1-SNAPSHOT.jar org.krystianek.udp.test.echo.EchoServer &

2. Start the udp6 monitor the ipv6 udp sockets in the background and present the statistics in kilobytes:
$ ./udpstat -6 -KB 1 100000 > udpstat.out 2>&1 &
...

3. Starting the client:
$ java -cp ./target/echo-0.0.1-SNAPSHOT.jar org.krystianek.udp.test.echo.EchoClient

4. Analysis of the results:

- if we take a look at the generated output:
$ cat udpstat.out
   Timestamp       Local IP:port        Remote IP:port     rx[KB]  rbuf[KB]    tx[KB]  tbuf[KB]   drops
...
  1358196897 00000000000000000000000000000000:9999  00000000000000000000000000000000:0            0     1024        0     1024       0
...
  1358196898 00000000000000000000000000000000:9999  00000000000000000000000000000000:0            8     1024        0     1024       0

...
  1358196902 00000000000000000000000000000000:9999  00000000000000000000000000000000:0           38     1024        0     1024       0

...
  1358196906 00000000000000000000000000000000:9999  00000000000000000000000000000000:0           68     1024        0     1024       0

...
  1358196909 00000000000000000000000000000000:9999  00000000000000000000000000000000:0           90     1024        0     1024       0

...
  1358196910 00000000000000000000000000000000:9999  00000000000000000000000000000000:0           97     1024        0     1024       0

...
  1358196917 00000000000000000000000000000000:9999  00000000000000000000000000000000:0          149     1024        0     1024       0

...
  1358196928 00000000000000000000000000000000:9999  00000000000000000000000000000000:0          230     1024        0     1024       0
...

  1358197036 00000000000000000000000000000000:9999  00000000000000000000000000000000:0         1024     1024        0     1024       9  1358197037 00000000000000000000000000000000:9999  00000000000000000000000000000000:0         1024     1024        0     1024       8  1358197038 00000000000000000000000000000000:9999  00000000000000000000000000000000:0         1024     1024        0     1024       7  1358197039 00000000000000000000000000000000:9999  00000000000000000000000000000000:0         1024     1024        0     1024       7
...

As expected the receive socket buffer starts to increase as soon as the UDP echo client starts since the transmission rate of the client is much higher than the reception rate of the server (Server receiver once per second, while client transmitting 100 times 64 bytes per second). As soon as the receive socket buffer utilization level reaches the maximum defined in system kernel parameters one can see packets drops happening (marked with red colour).

Everything seems to be working as expected...

Conclusions

When designing an application that is processing high volumes of data always ensure that the thread reading from the socket is not doing any additional, unnecessary processing since it may cause your socket buffers utilization go high and eventually would cause packet drop. If the additional processing/decoding is necessary then still an option with a thread pool might solve the buffer issue.

Anyway in my opinion the general rule of thumb should be that it is always beneficial to make the socket reading layer as lightweight as possible. With a single threaded approach one could think of creating a queue to which the reader thread would put the payload and a pool of worker threads would read from the queue and continue with the processing.



sobota, 12 stycznia 2013

Ubuntu: port-scan detection tools (psad, snort)

Do you know any port scan detection tools under Linux?

Today I needed one but did not have much experience or should I rather say overview on what is available. After some googling I found some tools and have chosen two of them to verify more in depth: psad and snort.

Psad


1. Installation

The psad utility is present in standard ubuntu repository and can be installed via apt-get utility:

#apt-get install psad
...

2. Configuration

2.1 Psad configuration

The details about parameters can be found here: http://cipherdyne.org/psad/docs/config.html
Generally in my case the email was pointing to root@localhost; HOME_NET and EXTERNAL_NET were pointing to any.

Iptables log file location:
IPT_SYSLOG_FILE             /var/log/kern.log;

2.2 Iptables configuration

Turn on iptables logging:

# iptables -A INPUT -j LOG
# iptables -A FORWARD -j LOG

3. Startup

Ensure that the service is restarted after changing the configuration (of course from root account):

# service psad restart

 * Stopping the psadwatchd process
 * Stopping the kmsgsd process
 * Stopping the psad process
 * Stopping Port Scan Attack Detector psad                               [ OK ] 
 * Starting Port Scan Attack Detector psad                               [ OK ] 


4. Test

For doing the test the nmap utility has been used by me (from localhost - my local IP address is 192.168.1.106).

NMap scan:

# nmap -v -p1-65535 192.168.1.106

Starting Nmap 6.00 ( http://nmap.org ) at 2013-01-11 07:52 CET
Initiating Parallel DNS resolution of 1 host. at 07:52
Completed Parallel DNS resolution of 1 host. at 07:52, 0.33s elapsed
Initiating SYN Stealth Scan at 07:52
Scanning 192.168.1.106 [65535 ports]
...

After few minutes the information about the scan appeared in the psad statistics (before that nothing was shown):

# psad -S

[+] psadwatchd (pid: 12733)  %CPU: 0.0  %MEM: 0.0
    Running since: Fri Jan 11 07:29:55 2013

[+] psad (pid: 12731)  %CPU: 3.0  %MEM: 1.2
    Running since: Fri Jan 11 07:29:55 2013
    Command line arguments: [none specified]
    Alert email address(es): root@localhost

[+] Version: psad v2.2

[+] Top 50 signature matches:
      "BACKDOOR DoomJuice file upload attempt" (tcp),  Count: 60,  Unique sources: 1,  Sid: 2375
      "P2P BitTorrent communication attempt" (tcp),  Count: 9,  Unique sources: 1,  Sid: 2181
      "BACKDOOR NetSphere Connection attempt" (tcp),  Count: 3,  Unique sources: 1,  Sid: 100044
      "POLICY HP JetDirect LCD communication attempt" (tcp),  Count: 3,  Unique sources: 1,  Sid: 510
      "DOS DB2 dos communication attempt" (tcp),  Count: 2,  Unique sources: 1,  Sid: 1641
      "POLICY vncviewer Java applet communication attempt" (tcp),  Count: 2,  Unique sources: 1,  Sid: 1846
      "MISC Ghostsurf communication attempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 100203
      "MISC HP Web JetAdmin communication attempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 100084
      "MISC Microsoft PPTP communication attempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 100082
      "P2P Napster Server Login communication attempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 565
      "MISC Xtramail communication attempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 1636
      "BACKDOOR Subseven connection attempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 100207
      "BACKDOOR Doly 2.0 Connection attempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 119
      "MISC VNC communication attempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 100202
      "MISC MS Terminal Server communication attempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 100077
      "BACKDOOR RUX the Tick connection attempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 100063
      "BACKDOOR HackAttack 1.20 Connection attempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 141
      "RPC portmap listing TCP 32771" (tcp),  Count: 1,  Unique sources: 1,  Sid: 599
      "MISC Microsoft SQL Server communication attempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 100205
      "BACKDOOR NetBus Pro 2.0 Connection Cttempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 100029
      "MISC Radmin Default install options attempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 100204
      "DDOS Trin00 Attacker to Master connection attempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 100007
      "BACKDOOR QAZ Worm Client Login access" (tcp),  Count: 1,  Unique sources: 1,  Sid: 108
      "DDOS mstream client to handler" (tcp),  Count: 1,  Unique sources: 1,  Sid: 249
      "BACKDOOR WinCrash 1.0 communication attempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 163
      "BACKDOOR GirlFriend Connection attempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 145
      "PSAD-CUSTOM Kuang2 virus communication attempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 100206
      "BACKDOOR netbus Connection Cttempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 100028
      "MISC PCAnywhere communication attempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 100073
      "MISC Alcatel PABX 4400 connection attempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 1819
      "BACKDOOR Remote PC Access connection attempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 2124
      "BACKDOOR BackConstruction 2.1 connection attempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 152
      "MISC xfs communication attempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 1987
      "DOS arkiea backup communication attempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 282
      "BACKDOOR PhaseZero Server Active on Network" (tcp),  Count: 1,  Unique sources: 1,  Sid: 208
      "SNMP AgentX/tcp request" (tcp),  Count: 1,  Unique sources: 1,  Sid: 1421
      "MISC Insecure TIMBUKTU communication attempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 505
      "FTP Yak! FTP server communication attempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 100100
      "P2P eDonkey transfer attempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 2586
      "BACKDOOR Infector.1.x Connection attempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 100040
      "BACKDOOR Asylum 0.1 connection request" (tcp),  Count: 1,  Unique sources: 1,  Sid: 100064
      "P2P napster communication attempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 100090
      "BACKDOOR NetMetro File List connection attempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 159
      "P2P Napster Client Data communication attempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 564
      "P2P Napster Client Data communication attempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 562
      "P2P Napster Client Data communication attempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 563
      "DOS Real Audio Server communication attempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 100112
      "P2P Fastrack kazaa/morpheus communication attempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 1383
      "BACKDOOR DonaldDick 1.53 connection attempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 153
      "POLICY HP JetDirect LCD commnication attempt" (tcp),  Count: 1,  Unique sources: 1,  Sid: 568

[+] Top 25 attackers:
      192.168.1.106   DL: 5, Packets: 56653, Sig count: 126, (local IP)
      127.0.0.1       DL: 1, Packets: 13, Sig count: 0, (local IP)
      193.41.112.18   DL: 1, Packets: 6, Sig count: 0

[+] Top 20 scanned ports:
      tcp 51708 1 packets
      tcp 58684 1 packets
      tcp 57573 1 packets
      tcp 19544 1 packets
      tcp 44919 1 packets
      tcp 8563  1 packets
      tcp 58017 1 packets
      tcp 9323  1 packets
      tcp 28336 1 packets
      tcp 5006  1 packets
      tcp 28801 1 packets
      tcp 63406 1 packets
      tcp 55548 1 packets
      tcp 38756 1 packets
      tcp 31922 1 packets
      tcp 62374 1 packets
      tcp 55430 1 packets
      tcp 3509  1 packets
      tcp 10713 1 packets
      tcp 36235 1 packets

      udp 111   12 packets
      udp 53    7 packets
      udp 17500 5 packets
      udp 5353  5 packets
      udp 50685 1 packets
      udp 30969 1 packets
      udp 22220 1 packets
      udp 63507 1 packets
      udp 44743 1 packets
      udp 50374 1 packets
      udp 41192 1 packets
      udp 22675 1 packets
      udp 123   1 packets
      udp 60162 1 packets
      udp 26877 1 packets
      udp 33571 1 packets
      udp 52566 1 packets
      udp 60029 1 packets
      udp 37490 1 packets

[+] iptables log prefix counters:
      "[UFW BLOCK]": 11

    Total packet counters: tcp: 56646 udp: 44

[+] IP Status Detail:

SRC:  192.168.1.106, DL: 5, Dsts: 4, Pkts: 56653, Unique sigs: 26, Email alerts: 2, Local IP

    DST: 255.255.255.255
        Scanned ports: UDP 17500, Pkts: 1, Chain: INPUT, Intf: wlan0
    DST: 192.168.1.106, Local IP
        Scanned ports: TCP 1-65535, Pkts: 56646, Chain: INPUT, Intf: lo
        Signature match: "BACKDOOR Remote PC Access connection attempt"
            TCP, Chain: INPUT, Count: 1, DP: 34012, SYN, Sid: 2124
        Signature match: "MISC Ghostsurf communication attempt"
            TCP, Chain: INPUT, Count: 1, DP: 7212, SYN, Sid: 100203
        Signature match: "MISC xfs communication attempt"
            TCP, Chain: INPUT, Count: 1, DP: 7100, SYN, Sid: 1987
        Signature match: "BACKDOOR NetSphere Connection attempt"
            TCP, Chain: INPUT, Count: 2, DP: 30101, SYN, Sid: 100044
        Signature match: "DOS arkiea backup communication attempt"
            TCP, Chain: INPUT, Count: 1, DP: 617, SYN, Sid: 282
        Signature match: "SNMP AgentX/tcp request"
            TCP, Chain: INPUT, Count: 1, DP: 705, SYN, Sid: 1421
        Signature match: "P2P BitTorrent communication attempt"
            TCP, Chain: INPUT, Count: 1, DP: 6889, SYN, Sid: 2181
        Signature match: "BACKDOOR Subseven connection attempt"
            TCP, Chain: INPUT, Count: 1, DP: 27374, SYN, Sid: 100207
        Signature match: "P2P eDonkey transfer attempt"
            TCP, Chain: INPUT, Count: 1, DP: 4242, SYN, Sid: 2586
        Signature match: "BACKDOOR Infector.1.x Connection attempt"
            TCP, Chain: INPUT, Count: 1, DP: 146, SYN, Sid: 100040
        Signature match: "POLICY vncviewer Java applet communication attempt"
            TCP, Chain: INPUT, Count: 2, DP: 5801, SYN, Sid: 1846
        Signature match: "BACKDOOR HackAttack 1.20 Connection attempt"
            TCP, Chain: INPUT, Count: 1, DP: 31785, SYN, Sid: 141
        Signature match: "DOS DB2 dos communication attempt"
            TCP, Chain: INPUT, Count: 1, DP: 6790, SYN, Sid: 1641
        Signature match: "MISC Microsoft SQL Server communication attempt"
            TCP, Chain: INPUT, Count: 1, DP: 1433, SYN, Sid: 100205
        Signature match: "P2P Napster Client Data communication attempt"
            TCP, Chain: INPUT, Count: 1, DP: 7777, SYN, Sid: 562
        Signature match: "P2P Napster Client Data communication attempt"
            TCP, Chain: INPUT, Count: 1, DP: 6666, SYN, Sid: 563
        Signature match: "DDOS Trin00 Attacker to Master connection attempt"
            TCP, Chain: INPUT, Count: 1, DP: 27665, SYN, Sid: 100007
        Signature match: "DDOS mstream client to handler"
            TCP, Chain: INPUT, Count: 1, DP: 15104, SYN, Sid: 249
        Signature match: "BACKDOOR DonaldDick 1.53 connection attempt"
            TCP, Chain: INPUT, Count: 1, DP: 23476, SYN, Sid: 153
        Signature match: "BACKDOOR WinCrash 1.0 communication attempt"
            TCP, Chain: INPUT, Count: 1, DP: 5714, SYN, Sid: 163
        Signature match: "POLICY HP JetDirect LCD communication attempt"
            TCP, Chain: INPUT, Count: 1, DP: 9001, SYN, Sid: 510
        Signature match: "BACKDOOR Doly 1.5 Connection attempt"
            TCP, Chain: INPUT, Count: 1, DP: 1015, SYN, Sid: 1985
        Signature match: "BACKDOOR DoomJuice file upload attempt"
            TCP, Chain: INPUT, Count: 25, DP: 3198, SYN, Sid: 2375
        Signature match: "MISC Alcatel PABX 4400 connection attempt"
            TCP, Chain: INPUT, Count: 1, DP: 2533, SYN, Sid: 1819
        Signature match: "BACKDOOR - Dagger_1.4.0 Connection attempt"
            TCP, Chain: INPUT, Count: 1, DP: 2589, SYN, Sid: 100038
        Signature match: "DDOS mstream client to handler"
            TCP, Chain: INPUT, Count: 1, DP: 12754, SYN, Sid: 247
    DST: 192.168.1.255, Local IP
        Scanned ports: UDP 111-17500, Pkts: 4, Chain: INPUT, Intf: wlan0
    DST: 224.0.0.251
        Scanned ports: UDP 5353, Pkts: 2, Chain: INPUT, Intf: wlan0

    ...

    Total scan sources: 4
    Total scan destinations: 6

[+] These results are available in: /var/log/psad/status.out

And in the syslog you should have the following lines (rsyslog in backward compatibility mode):

Jan 11 07:53:54 krystianek psad: scan detected: 192.168.1.106 -> 192.168.1.255 udp: [111-17500] udp pkts: 3 DL: 5
Jan 11 07:53:54 krystianek psad: src: 192.168.1.106 signature match: "BACKDOOR Remote PC Access connection attempt" (sid: 2124) tcp port: 34012
Jan 11 07:53:54 krystianek psad: src: 192.168.1.106 signature match: "MISC xfs communication attempt" (sid: 1987) tcp port: 7100
Jan 11 07:53:54 krystianek psad: src: 192.168.1.106 signature match: "MISC Ghostsurf communication attempt" (sid: 100203) tcp port: 7212
Jan 11 07:53:54 krystianek psad: src: 192.168.1.106 signature match: "BACKDOOR NetSphere Connection attempt" (sid: 100044) tcp port: 30101
Jan 11 07:53:54 krystianek psad: src: 192.168.1.106 signature match: "DOS arkiea backup communication attempt" (sid: 282) tcp port: 617
Jan 11 07:53:54 krystianek psad: src: 192.168.1.106 signature match: "SNMP AgentX/tcp request" (sid: 1421) tcp port: 705
Jan 11 07:53:54 krystianek psad: src: 192.168.1.106 signature match: "P2P BitTorrent communication attempt" (sid: 2181) tcp port: 6889
Jan 11 07:53:54 krystianek psad: src: 192.168.1.106 signature match: "BACKDOOR Subseven connection attempt" (sid: 100207) tcp port: 27374
Jan 11 07:53:54 krystianek psad: src: 192.168.1.106 signature match: "P2P eDonkey transfer attempt" (sid: 2586) tcp port: 4242
Jan 11 07:53:54 krystianek psad: src: 192.168.1.106 signature match: "POLICY vncviewer Java applet communication attempt" (sid: 1846) tcp port: 5801
Jan 11 07:53:54 krystianek psad: scan detected: 192.168.1.106 -> 192.168.1.106 tcp: [6-65532] flags: SYN tcp pkts: 16889 DL: 5


Snort

Snort is much more than port scanner detection tool. It is an Network Intrusion Detection System (NIDS) allowing to . Actually the port scan detector (sfportscan)  is only a module in it

1. Installation

The package is available in the standard repo (installation can be done via apt-get as below):

# apt-get install snort
...

2. Configuration

2.1 Main configuration file: snort.conf

What you need to do is to uncomment the sfportscan preprocessor in the main configuration file (snort.conf) as below:

# cat /etc/snort/snort.conf
...

# Portscan detection.  For more information, see README.sfportscan
preprocessor sfportscan: proto  { all } memcap { 10000000 } sense_level { low } logfile { /var/log/snort/portscan.log }

...

In my case I added the location of the log file (marked with red) to /var/log/snort/portscan.log. The sense_level is set to low, it is possible to set higher level. However you can expect plenty of messages concerning for example access to your samba shares (this happened in my case).

2.2 Additional configurations: snort.debian.conf

You can configure it after installation of the snort package or also afterwards:
# dpkg-reconfigure snort

In my case I wanted snort to monitor two interfaces, send stats via email once per day - the content of the configuration file can be found below:

# cat /etc/snort/snort.debian.conf
...

DEBIAN_SNORT_STARTUP="boot"
DEBIAN_SNORT_HOME_NET="192.168.0.0/16 10.0.0.0/8"
DEBIAN_SNORT_OPTIONS=""
DEBIAN_SNORT_INTERFACE="eth0 wlan0"
DEBIAN_SNORT_SEND_STATS="true"
DEBIAN_SNORT_STATS_RCPT="root@localhost"
DEBIAN_SNORT_STATS_THRESHOLD="1"



3. Startup

The startup of snort is controlled via init start scripts - ensure that after changing the configuration the service is restarted:


# service snort restart
 * Stopping Network Intrusion Detection System  snort                    [ OK ] 
 * Starting Network Intrusion Detection System  snort                    [ OK ] 
#


Now the snort daemon should be up and running with the new configuration.

4. Test

In this case I executed the scanning from a remote host (WinXP) using nmap. The IP address of the remote host was 192.168.1.103 and the local one being scanned 192.168.1.106 (as in previous test run). The nmap parameters were the same as in case of psad, scanning was initiated from GUI.

snort portscan log file (lines appeared almost real-time):

...
Time: 01/12-12:26:15.168523 
event_ref: 0
192.168.1.103 -> 192.168.1.106 (portscan) TCP Portscan
Priority Count: 8
Connection Count: 10
IP Count: 1
Scanner IP Range: 192.168.1.103:192.168.1.103
Port/Proto Count: 10
Port/Proto Range: 21:5900
...

syslog (auth.log):
...
Jan 12 12:26:16 krystianek snort[1225]: [1:1421:11] SNMP AgentX/tcp request [Classification: Attempted Information Leak] [Priority: 2] {TCP} 192.168.1.103:49221 -> 192.168.1.106:705
...
Jan 12 12:26:29 krystianek snort[1225]: [1:1420:11] SNMP trap tcp [Classification: Attempted Information Leak] [Priority: 2] {TCP} 192.168.1.103:49221 -> 192.168.1.106:162
...
Jan 12 12:26:51 krystianek snort[1225]: [1:249:8] DDOS mstream client to handler [Classification: Attempted Denial of Service] [Priority: 2] {TCP} 192.168.1.103:49221 -> 192.168.1.106:15104
...


The scan has been detected really fast.


Summary

Both utilities (psad and snort) can be used to detect a port scanning activity. However they use different methods for achieving this goal. It seems that psad relies mostly on parsing iptables logs in a text format, while snort does that in binary form.

In my opinion the biggest disadvantage of psad utility is that it requires iptables logging enabled, which might cause flood of messages going into the logs (if misconfigured or due to excessive ammount of traffic to be logged). In case of snort there is no need to enable any logging it does the monitoring of the packtes by itself (in binary form). The danger of flooding the logs, leading to any service impact, is minimal.

As far as automatic actions after discovering a scan are concerned psad can be configured to automatically block the IP address (from which the scan has been detected) using iptables and tcpwrapper. For details please refer the documentation I have not used this option. For snort I could not easily find anything, for sure there are additional utilities that could help to do this like snortsam: http://www.snortsam.net/ or sagan log (auth.log) parser: http://sagan.quadrantsec.com/.