ACID: Frequently Asked Questions

Last Updated: March 6. 2003

About the ACID project

(A-1) What is ACID?
(A-2) What devices/log types can be read by ACID?
(A-3) Where is the official web site and source code?
(A-4) How can I contribute to the project?


(B-1) What database permissions are necessary on the tables?
(B-2) Why is PHP4 required for ACID?
(B-3) What build options do I need for PHP?
(B-4) Why is ADODB required for ACID?
(B-5) ADODB Troubleshooting
(B-6) Why do all the ACID pages return as raw HTML (or ask me to save them) to the browser?
(B-7) Portscan and Spade alerts are not showing up?
(B-8) Graph Troubleshooting: No chart appears when graphing alert data
(B-9) PostgreSQL optimizations
(B-10) MySQL optimizations
(B-11) Emailing alerts Troubleshooting: Why do emailed alerts never arrive?
(B-12) Why are the sensors names being listed as 'unknown'?


(C-1) ACID appears to be broken in the Lynx and Links browsers
(C-2) Can priorities and classifications be assigned to Alerts?
(C-3) Why do certain alerts have 'unknown' IPs?
(C-4) Why does the 'error deleting alert' message occur when attempting to delete an alert?
(C-5) My connection times-out when performing long operations (e.g. deleting a large number of alerts)
(C-6) Why are searches so slow after moving alerts into Alert Groups?
(C-7) What is an Alert Event cache? $event_cache_auto_update?
(C-8) Improving hostname lookup (DNS) performance
(C-9) Performance Tuning: ACID is running really slow
(C-10) Why does the browser 'back' button not work?
(C-11) The predefined criteria is being ignored after the second page
(C-12) How does one read the archive database?


(D-1) Common ACID Error messages
(D-2) Common PostgreSQL error messages
(D-3) Common MySQL error messages
(D-4) Common Browser error messages
(D-5) Reporting a bug

Database schema

(E-1) How are IP addresses stored?

About the ACID project

(A-1) What is ACID?
ACID is a PHP-based analysis engine to search and process a database of security incidents generated by security-related software such as IDSes and firewalls. It is portable without modification to any operating system that can support PHP (e.g., Linux, *BSD, Windows, Solaris).

ACID was developed by Roman Danyliw at the CERT Coordination Center initially as a part of the AIRCERT project. It is currently maintained in the context of this project and in the author's free time.

ACID is open-source and released under GPL licensing.

(A-2) What devices/log types can be read by ACID?

Only Snort can write to the underlying database in real-time. However, Linux ipchains/ipfw and Cisco firewall reject-packet messages can be post-processed, extracted from syslog and inserted into the database (and read by ACID) with the logsnorter script written by Jason Haar

(A-3) Where is the official web site and source code?

The official web site with the latest information is hosted by Sourceforge under the acidlab project name:

(A-4) How can I contribute to the project?

As an open-source project, ACID should grow with community involvement. Contributions are highly encouraged. Find a needed feature or bug and send the author the patch. If the functionality is a bit more involved, email the author to coordinate so that no effort is duplicated. Modifications to code should be made from the latest source-code base found in CVS.


(B-1) What database permissions are necessary on the tables?

See the Installing and Configuration documentation for a table level list of the required permissions.

Note: If the PostgreSQL users shadow the underlying OS user credentials, the user running the web process will require access to the database.

(B-2) Why is PHP4.0.4pl1+ required for ACID?

PHP4.0.4pl1 is required for full ACID functionality; using PHP3 will cause unexplained behavior in certain code. Specifically, PHP4 is needed to support two-dimensional arrays, session handling, and output buffering.

(B-3) What build options do I need for PHP?

Note: For Windows users it may be undesirable to have to re-compile from source. Download the "full" .zip file which has pre-compiled support for most of the needed functionality. Additions such as GD will most likely need to be added via the PHP extension system (see the php.ini and the PHP documentation for more information).

(B-4) Why is ADODB required for ACID?

Unfortunately, PHP does not have a common database API for accessing different databases. Thus, in order for ACID to support multiple database types, some level of database abstraction was required. From examining the various candidates, ADODB seemed the most mature. Regardless, another level of abstraction was created around ADODB to create an ACID specific DB library. Such a construct will allow the underlying DB abstraction library to change without any code modifications.

(B-5) ADODB Troubleshooting

Confirm the following installation and configuration:

(B-6) Why do all the ACID pages return as raw HTML (or ask me to save them) to the browser?

If all ACID pages seem to come up as raw HTML in the browser, perhaps always starting with the line "<?php", then mostly likely the web server has not been properly configured to use PHP. The MIME types are not set correctly; the web server is treating files with the ".php" extension as normal text instead of parsing then with PHP.

It is also possible that a mis-configured web server will cause the browser to prompt you to save the ACID file, instead of rendering the results.

In Apache the following lines need to included in the httpd.conf configuration file.

    AddType application/x-httpd-php .php
    AddType application/x-httpd-php-source .phps

(B-7) Portscan and Spade alerts are not showing up?

Most likely this is due to the Snort database plug-in being configured improperly. The portscan pre-processor is hard coded to output to the "alert" logging facility; it will only write to those output plug-ins registered to "alert" logging. However, the default configuration for the database plug-in is to register itself as a "log" output facility.

Sample DB plug-in configuration for logging portscans (Note the "alert")

output database: alert, mysql, user=snort, dbname=snort_log host=localhost password=foo

Even with this configuration, only the occurrence of portscan (or spade) event will be logged to the database. The specific ports involved will not be stored. This port information is only available in the portscan log file. Logging the individual ports is currently not possible in snort due to an architectural limitation: pre-processors cannot pass data to the output plug-in.

ACID provides a limited solution to this issue by providing the capability to browse a single portscan.log log file from the IP statistics page (acid_stat_ipaddr.php). The portscan log file read by ACID is set with the $portscan_file configuration variable. Note that this port information extracted from the log file is never imported into the database. Rather, file parsing is done on demand to extract and present the relevant information. Thus, it is not possible to search on IP addresses or ports found in this file.

Multiple portscan.log files cannot be read directly, but this can be crudely circumvented by simply combining all the log files into a single file and using this with ACID.

(B-8) Chart Troubleshooting: No chart appears when graphing alert data

  • Verify that GD was compiled into PHP (--with-gd).

  • Run the PHPlot diagnostic page found at examples/test_setup.php in the PHPlot distribution to test correct installation. Verify that at least one chart appears (See the Figure 1 of the installation instructions).

    If the following error message appears, then the underlying graphing libraries that GD uses have not been compiled into PHP correctly.

         Test to see if GIF graphs work
         Test to see if PNG graphs work
         Test to see if JPEG graphs work
    Explicitly build in JPEG (via libjpeg) or PNG (via libpng) support by using the following parameters to the PHP ./configure script:
         --with-jpeg-dir=DIR       GD: Set the path to libjpeg install prefix.
         --with-png-dir=DIR        GD: Set the path to libpng install prefix.

  • Verify that the valid chart file format (jpeg, gif, png) which displayed in the diagnostic page conforms to the file format set in the $chart_file_format variable.

  • Confirm that '~E_NOTICE' is not set in the "error_reporting" variable in your php.ini config file. Likewise, verify that "display_errors" is not enabled. Inline debugging information will disrupt the HTTP headers of the image.
  • (B-9) PostgreSQL optimizations

    Database configuration
    An "out-of-the-box" PostgreSQL 7+ install needs to be tweaked to gain optimal Snort logging performance. It is highly recommended to enable the the nofsync in the postgresql.conf configuration file (its default location is /var/lib/pgsql/data/). This option will disable the synchronization of the tables to disk on every read and write operations yielding increased write performance. Likewise, check that the the maximum amount of shared memory allowed by the operating system is sufficient large, and check that the shared_buffers and sort_buffers settings are optimal for your available memory.

    Creating indexes
    Many of the required indexes are not created in initial PostgreSQL creation script. At a minimum the following fields should have indexes created on them:

    (B-10) MySQL optimizations

    Compact the tables
    After numerous delete operations, "holes" will occur in the native files used to store the tables decreasing the speed of the all queries. The following shell script will examine all the MySQL tables and compact them.
    for table in `echo show tables|mysql snort|tail +2` 
       echo optimize  table $table|mysql snort 
    Creating indexes
    Some of the required indexes are not created in initial MySQL creation script. The following indexes can be added to significantly improve performance:
    (B-11) Emailing alerts Troubleshooting: Why do emailed alerts never arrive?
    If the alert action "Email alerts" returns successful completion status, but no email ever arrives the mail server may not be properly configured.
    1. Open the php.ini configuration file and scroll down to the section labeled "[mail function]"
         [mail function]
         SMTP = localhost                   ;for win32 only
         sendmail_from =   ;for win32 only
         ;sendmail_path  =                  ;for unix only 
    2. For Windows machines the incorrect mail server was probably specified. Set the "SMTP" variable to a valid STMP server.

      For UNIX machines an MTA probably could not be found. Set the variable "sendmail_path" to the MTA binary (include a full path).

    3. Restart the Web server
    (B-12) Why are the sensors names being listed as 'unknown'?
    Snort sets this sensor name the first time it is started based in the IP address of the host. If the IP address cannot be resolved, the sensor name might be logged as 'unknown'. Use the 'sensor_name' configuration option of the database output plugin to explicitly set the name of the sensor. For example, output database: log, mysql, sensor_name=foobar database=snort ....


    (C-1) ACID appears to be broken in the Lynx and Links browsers

    This is a known issue. Lynx and Links both mangle some of the GET arguments appended to the URL. It's resolution is being investigated, but use Netscape, Opera, or IE in the mean time.

    (C-2) Can priorities and classifications be assigned to Alerts?

    The quick answer to this question is that it depends. ACID is at the mercy of the underlying database. Snort versions prior to 1.7 did not support priorities, hence ACID did not have priorities. In version 1.8, rudimentary support for classification and priorities was added into Snort (DB schema v103). At this time ACID only support classifications, but will also support priorities in the near future. In the mean time, there are several work-arounds:

    (C-3) Why do certain alerts have 'unknown' IPs?

    The Snort database plug-in only logs packet information into the database when an alert is triggered by a rule (signature). Therefore, since alerts generated by pre-processors such as portscan and mini-fragment have no corresponding rules, no packet information is logged beyond an entry indicating their occurrence. As a consequence, ACID cannot display any packet-level (e.g. IP address) information for these alerts.

    For these particular alerts, certain statistics may show zero unique IP addresses, list the IP address as 'unknown', and will not list any packet information when decoding the alert.

    (C-4) Why does the 'error deleting alert' message occur when attempting to delete an alert?

    Most likely the DB user configure in ACID does not have sufficient privileges. In addition to those privileges granted to log the alerts into the database (INSERT, SELECT), DELETE is also required.

    This permission related issue can be confirmed by manually inserting a row into the database, then trying to delete it.

    1. login to MySQL with the same credentials (i.e. username, password) as you use in ACID.
      e.g. % mysql  -u  -p
    2. insert a test row into the event table
    mysql> INSERT INTO event (sid, cid, signature, timestamp) VALUES (1, 1000000, "test", "0");
    (this assumes that you don't already have a row with an event ID=1000000. If you do just choose another event id #)

    3. now delete this newly inserted row

    mysql> DELETE FROM event WHERE sid=1 AND cid=10000000; 
    If you where not able to delete, this confirms that this is a permission problem. Re-login to mysql as root, and issue a GRANT command (giving the DELETE permission) to the ACID DB user.
      e.g. GRANT DELETE on snort.* to acid@localhost
    (this assumes that my alert database is 'snort', username is 'acid', and logging from the 'localhost')

    (C-5) My connection times-out when performing long operations (e.g. deleting a large number of alerts)

    Fatal error: Maximum execution time of 30 seconds exceeded

    PHP has an internal variable set to limit the length an script can execute. It is used to prevent poorly written code from executing indefinitely. In order to modify the time-out value, examine the 'max_execution_time' variable found in the 'php.ini' configuration file.

    Alternatively, modify the '$max_script_runtime' variable in acid_conf.php to tweak only the ACID script max_execution_time.

    (C-6) Why are searches so slow after moving alerts into Alert Groups

    You might need to run "myisamchk --analyze", "myisamchk -r", and then do a "mysqladmin refresh" on all the tables in order to refresh the indexes.
    (C-7) What is an Alert Event cache? $event_cache_auto_update?
    The alert event cache is an optimization introduced to decrease the processing time of various analysis operations. With the growing functionality of ACID, the SQL queries to the database are becoming increasing complicated requiring at a minimum the JOINing of several tables. The JOIN of tables can become extremely memory intensive as the size of the tables (i.e. the number of alerts grows). In an effort to minimize these table JOINS, an alert event cache tables was created (table: acid_event).

    The newly introduced acid_event table combines the most commonly used information about an alert into a single table: IP address, ports, signature name, classification, and priorities. Two observations can be made about this new table: it redundantly stores information, and is not normalized. While these are usually undesirable features, it was felt that with the declining price of storage this was a reasonable trade-off to yield much better performance.

    All analysis operations now are performed from this event cache. This reality introduces a new paradigm shift for ACID: alerts are no longer processed in real-time from the same tables as they were logged by Snort or other security devices. Hence, the event cache must now be maintained; that is, newly logged alerts must be moved into a new table structure in order to be "seen" and analyzed by ACID. It must be stressed that this "caching" operation is a one time cost and must be done only once per alert.

    There are two possible strategies by which to manage the alert event cache:

    (C-8) Improving hostname lookup (DNS) performance

    Under many circumstances DNS lookups may take a very long if an IP address does not resolve. Thus, modify the $resolve_IP variable in the acid_conf.php configuration file to $resolve_IP=0.

    While DNS lookups can be turned off, having hostnames can be quite useful. Therefore, ACID implements several constructs to facilitate these lookups.

    (C-9) Performance Tuning: ACID is running really slow

    If ACID is running "slow", here are several things to try to increase performance.




    (C-10) Why does the browser 'back' button not work?

    Use the ACID 'back' button in the upper-right hand corner of each page, instead of the the browser 'back' button.

    Using the browser 'back' button works on most web sites. However, in ACID, it will not produce the desired results: displaying the previous page. ACID dynamically generates all pages based on shared state (e.g. search criteria to pass among the page) in a PHP session. When, the browser 'back' button is clicked, the correct file will be loaded, however, the context used to generate this page will not be correct. Hence, the wrong information will be rendered. Specifically, the criteria from the last correctly generated page will be used. Always use the ACID 'back' button.

    (C-11) The predefined criteria is being ignored after the second page

    If some predefined criteria list is applied against results (successfully), but this criteria is subsequently ignored when scrolling through the other pages of results, some configuration tweaking might be necessary. This condition is being caused when session information is not propagated correctly.

    (C-12) How does one read the archive database?

    A single instance of ACID cannot currently browse the active alert and archive database simultaneously. However, since the archive database structure is identical to the the alert database, merely using another instance of ACID while provide identical functionality on the archive database as in the original alert database.

    Copy the ACID files into another directory and configure the alert_dbname variable (and associated database connection parameters) of acid_conf.php to read the archive database.


    (D-1) Common ACID Error messages

    From any ACID page:
    Fatal error: Call to undefined function: adoloadcode() in
        Warning: Failed opening 'd:/inetpub/wwwroot/php/adodb/'
        for inclusion (include_path='.:/usr/local/lib/php') in
        /usr/local/adodb/ on line 1087
    ADODB has not been configured correctly. Edit the $ADODB_DIR variable in adodb-inc.php to reflect the directory in which ADODB is installed.

     Fatal error: Call to undefined function: mysql_pconnect() in 
     /var/www/html/adodb/ on line 81
     Fatal error: Call to undefined function: postgres_pconnect() in  
     /var/www/html/adodb/ on line 81
    PHP has not been compiled correctly with the required database support. Re-build PHP with the necessary library by specifying either --enable-mysql or --enable-pgsql from the configure script.

    Warning: Cannot send session cookie - headers already sent by 
    (output started at acid_conf.php:line number)
    This PHP warning message is generated due to extraneous carriage returns (blank lines) in the acid_conf.php file. No extra line can exist before the "acid_conf.php and remove this line.

    Warning: Undefined variable: some name in  ...
    Warning: Undefined offset: some number in ...
    These are "warning" messages generated by the PHP engine. Mostly likely you have the sensitivity of debugging (in PHP) turned on to the maximum. Examine the setting of the variable "error_reporting" in your php.ini config file. Verify that E_NOTICE is not set (you probably want to have ~E_NOTICE). In order to remove all inline error messages (i.e. errors printed in the returned HTML) set error_reporting = Off

    These messages won't affect functionality, but are visually annoying. They are the artifact of "unclean" code practices and with the next code clean-up most of these will be eliminated.

    Warning: open(/tmp\sess_ ... , O_RDWR) failed: ...
    The directory in which PHP is storing session information is not correct. This problem often occurs on Windows machines since the default directory is typically /tmp.
    1. Open the php.ini configuration file and scroll down to the section labeled "[Session]"

    2. Find the variable variable named "session.saved_path".
           session.save_path         = /tmp    ; argument passed to save_handler
                                               ; in the case of files,
                                               ; path where data files
    3. Change "session.saved_path to be a valid directory: \temp, \\temp, c:\temp, c:/temp

    4. Restart the Web server

    Parse error in acid_conf.php on line ...
    There is an error in the ACID configuration file acid_conf.php. Remember that this file is really source code an conforms to the PHP language syntax.

    Fatal error: Allowed memory size of XXX bytes exhausted (tried to allocate XXX bytes)
    PHP can be configured with a memory limit on each instance of a script. This functionality is controlled by the memory_limit variable in the php.ini. If this memory cap is exhausted, execution of the current script terminates. Increase memory_limit to prevent this error.

    PHP ERROR: Incompatible version: Version X.X.X of PHP is too old.  Please upgrade to version
    4.0.4 or later.
    ACID has a prerequisite of at least PHP v4.0.4 or later.

    In older versions of ACID, there exists a bug in the routine that checks the the age of the current version of PHP. This bug causes all version later than 4.2.0 to be detected as too old. Upgrade to a newer version of ACID to fix this issue. (D-2) Common PostgreSQL error messages

    With any errors in PostgreSQL, first confirm that you are running version 7.1+.

    From any ACID page:

    Warning: Unable to connect to PostgreSQL server: FATAL 1: SetUserId: user 'nobody' is not in 'pg_shadow' in
    /adodb/ on line 127
    ACID cannot properly authenticate to the database. Since user shadowing is implemented, the owner of the httpd (web process) does not have rights on the database.

    Warning: Unable to connect to PostgreSQL server: PQconnectPoll() -- connect() failed: Connection refused Is the postmaster running (with -i) at
    'localhost' and accepting connections on TCP/IP port '5432'? in ...
    ACID cannot connect to the database server. Is it possible that PostgreSQL is only accepting connections through a local socket?

    Database ERROR:ERROR: <some table name>: Permission denied. 
    The current database user has insufficient privileges to access the table. Use the GRANT command to assign the appropriate rights.

    OUTER JOIN is not supported
    This error is an artifact of using an older version of PostgreSQL. Prior to version 7.1, PostgreSQL only supported INNER JOINs of tables. Upgrade to PostgreSQL 7.1+ to fix the error.

    (D-3) Common MySQL error messages

    Warning: Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (111) 
    Warning: Can't connect to local MySQL server through socket '/tmp/mysql.sock' (111) 
    MySQL has been configured to communicate over a UNIX domain socket, but this socket file could not be found in the default directory.

    Database Error: Access denied for user: 'snort@localhost' (Using password:YES)
    Access denied for user in /apache_1.3.22/adodb/ on line ...
    The database user specified in the $alert_user variable of acid_conf.php cannot authenticate to the MySQL alert database. For additional information on "Accessed denied" error messages consult the MySQL documentation:

    (D-4) Common Browser error messages

    Browser returns a Document contains no data error message when browsing an ACID page.

    When this error occurs, PHP and ACID debugging needs to be enabled to the highest sensitivity to enable troubleshooting.

    (D-5) Reporting a bug
    Bug reports should be sent to, and CC-ed to the (Snort-users mailing list).

    The following information should be included in the report:

    If the bug is reproducible, please turn on "debug mode" to increase the verbosity of any error messages and repeat the steps which produced the error. Include the page on which the error occurred in your report. "Debug mode" is enabled by editing the acid_conf.php file, and setting the variable $debug_mode = 1.

    If the error appears to be database related (the error message produces SQL), also enable "SQL tracing" when reproducing the error. "SQL tracing" is enabled by editing the acid_conf.php file, and setting the variable $sql_trace_mode = 1 and specifying a target file with the $sql_trace_file variable. Send the output found in the SQL trace file related to the page on which the error occurred.

    Database schema

    (E-1) How are IP addresses stored?

    IP addresses are stored in the database as unsigned 32-bit integers. This format allows for more efficient storage as well as complex queries involving network masks. The database schema stores IP addresses in four fields: iphdr.ip_src, iphdr.ip_dst, acid_event.ip_src, acid_event.ip_dst . The following is a description of how to convert a 32-bit unsigned integer representation of an IP address into a human readable 4-byte format.


    Let IP  = the 32-bit unsigned integer representation of the IP address
        ip1 = octet 1 of 4 (high-order)
        ip2 = octet 2 of 4
        ip3 = octet 3 of 4
        ip4 = octet 4 of 4 (low-order)
        >>  = bitwise shift right operator; takes an operand of the number bits to shift
        AND = bitwise AND operator
       ip1 = IP >> 24
       ip2 = (IP AND 00000000 11111111 00000000 00000000) >> 16
       ip3 = (IP AND 00000000 00000000 11111111 00000000) >> 8
       ip4 = (IP AND 00000000 00000000 00000000 11111111)
       IP = ip1 . ip2 . ip3 . ip4


    MySQL provides a native function, inet_ntoa(), which will convert an unsigned 32-bit integer into a 4-octet IP address.

    mysql> SELECT ip_src, inet_ntoa(ip_src) FROM iphdr;
    | ip_src     | inet_ntoa(ip_src) |
    | 2130706433 |         |


    PostgreSQL does not provide a native function to convert the unsigned 32-bit representation into a 4-octet IP address. However, the following custom function provides the same functionality.

    CREATE FUNCTION plpgsql_call_handler () RETURNS OPAQUE AS
    '/usr/lib/pgsql/' LANGUAGE 'C';
    -- Note: remember to change the above path to '' 
    CREATE TRUSTED PROCEDURAL LANGUAGE 'plpgsql' HANDLER plpgsql_call_handler
    CREATE FUNCTION int8ip_to_str(int8) RETURNS inet AS '
        t inet;
        t = (($1>>24) & 255::int8) || ''.'' ||
            (($1>>16) & 255::int8) || ''.'' ||
            (($1>>8)  & 255::int8) || ''.'' ||
            ($1     & 255::int8);
        RETURN t;
    ' LANGUAGE 'plpgsql';
    The following is an example of the custom function int8ip_to_str():
    snort_db=# SELECT ip_src, int8ip_to_str(ip_src) FROM iphdr;
       ip_src   | int8ip_to_str 
     2130706433 |

    Author: Roman Danyliw
        - Bill Marquette
        - Jason Haar
        - Steve Halligan
        - Philip Mayers