DragonFly On-Line Manual Pages
IPA.CONF(5) DragonFly File Formats Manual IPA.CONF(5)
NAME
ipa.conf -- ipa(8) configuration file
DESCRIPTION
The ipa.conf file is a configuration file for ipa(8). This file or any
other one specified in the -f option in the ipa(8) command line is read
when ipa(8) starts working or receives a SIGHUP signal.
FILE FORMAT
The ipa.conf file can be quite simple and can be complex enough. The
main idea is to place as much as possible into configuration file(s)
instead of writing external programs to do accounting related tasks.
This manual page contains the complete file format description and
complete documentation about all features of ipa(8).
There is an example almost after each paragraph. Since IPA
distribution does not have any module, ipa_ipfw, ipa_ip6fw, ipa_atest
and ipa_db_sdb modules are used in examples just because they were the
first modules designed for IPA.
General syntax
Any logical line in the configuration file can be written in several
text lines for indenting purpose. There is not any rule in which line
to place reserved words, arguments and special symbols. If some format
allows one space character, then as much as needed space characters,
tab characters and newline characters can be written there for
indenting. All elements in a configuration file are case sensitive. A
configuration file consists of sections, parameters and comments.
Comments
There are shell-like and C-like comments. If you use a C-like comment
in a shell-like comment, then a C-like comment is ignored.
Example:
# Shell-like comment.
/* C-like comment. */
/*
* Another C-like comment.
*/
Sections and parameters
A section consists of its name, optional arguments and its body. A
section's body should be placed in curly braces:
section [[=] argument] {
/* Parameters and sections. */
}
A parameter consists of its name and optional arguments. Every
parameter should have the `;' character at the end of its arguments
list:
parameter [[=] argument];
The `=' character after the section's or parameter's name is optional.
Some parameters look like variables (it is naturally to use the `='
character for them), another ones look like instructions. In any case
you can choose a syntax you like more.
An argument can contain strings:
"string"
The ``\t'', ``\n'', ``\\'' and ``\"'' sequences should be used for
representing tab, newline, back-slash and double quote characters
inside a string. If it is needed to split a string to several lines,
then use one `\' character at the end of the current line (do not put
extra space characters after the back-slash character). If a string is
written in several lines without `\' characters, then each newline
character is added to a string.
Macro variables
The definition of a macro variable has the following form:
${variable} = "string";
A macro variable name consists of letters, digits, '_' symbols and
dollar signs. What is a letter is checked with isalpha(3) function
which uses current locale.
A value of any macro variable should be a string, when a macro variable
is expanded then first and last double quotes of its value are removed.
Macro variables can be local or global. A macro variable is global if
it is defined outside any section, else a macro variable is local. A
local macro variables are local for all nested sections and for all
external sections. Local macro variables can hide global ones.
There are some predefined macro variables:
${$} - a `$' character;
${rule} - the current rule name;
${limit} - the current limit name;
${sublimit} - the current sublimit name;
${threshold} - the current threshold name;
${autorule} - the current autorule name.
Any macro variable (including predefined ones) except ${$} can be
redefined if needed. It is not recommended to redefine or delete
predefined macro variables in modules.
Macro variable ${$} cannot be used for constructing macro variables
names (see the example).
Macro variable can be used almost anywhere in the configuration file.
When macro variable is expanded, then its value is expanded
recursively. Macro variables are expanded at the moment of their usage
and not at the moment of their definition. Macro variables are
expanded also in strings. Macro variables is a feature of the internal
configuration file parser, so ${rule} macro variable cannot be used in
autorules and in rules patterns (see information about substitutions in
command strings).
Example:
${a} = "${b}"; # Definition of ${a}.
${b} = "1"; # Definition of ${b}.
param = ${a}; # Expands to 1.
${b} = "2"; # Redefine ${b}.
param = ${a}; # Expands to 2.
param = "${$}{b}"; # Expands to "${b}" (sequence of characters).
section {
${a} = "1"; # Definition of local ${a} which hides
# global ${a}.
${c} = "4"; # Definition of local ${c}.
param = ${a}; # Expands to 1.
subsection {
${a} = "2"; # Redefine local ${a}.
${b} = "3"; # Redefine global ${b}.
}
param = ${a}; # Expands to 2.
param = ${b}; # Expands to 3.
}
# param = ${c}; <-- Error: ${c} is not defined as global.
Including files
Configuration information can be kept in several configuration files.
Files are included with the help of the following parameters:
include "/path/file";
include_files "/directory/pattern";
The include parameter includes one file. The include_files parameter
includes files which match the given shell pattern from the specified
directory.
These parameters can be used anywhere in the configuration file except
inside modules' sections, and contents of included files will be
included immediately. Files can be included from included files. Each
included file should have correctly specified parameters with
arguments, comments and sections with arguments, but it can have not
closed sections.
POSIX regular expressions can be used as patterns in include_files
parameters as well, to enable them set the posix_re_pattern parameter
to ``yes'' before parameters which include files with POSIX regular
expression patterns (the default value is ``no''):
posix_re_pattern = <boolean>;
This parameter should not be placed in any section.
Included files must be owned by the user who run ipa(8) and must not be
writable for group and other users. If files are included with the
help of the include_files parameter, then a directory specified in this
parameter also should have the same properties.
Examples:
posix_re_pattern = yes;
include "/usr/local/etc/ipa.local.conf";
include_files "/usr/local/etc/ipa/LAN/.";
First parameter includes one file, second parameter includes each file
in the given directory (the ``.'' POSIX regular expression means ``any
character'').
/* posix_re_pattern = no; */
include_files "/usr/local/etc/ipa/LAN/*";
Here a shell pattern is used. First string should be uncommented if
previously POSIX regular expressions were used.
Using accounting modules
IPA accounting modules are used for gathering statistics. ipa(8) and
accounting modules work together via the ipa_ac_mod API described in
the ipa_mod(3) manual page.
The ac_mod parameter dynamically loads the given accounting module:
ac_mod "file_name";
This parameter should not be placed in any section. Several accounting
modules can be used at one time.
The given file name should be a shared-object (shared library) file
name if ipa(8) uses dlopen(3) interface or it can be a .la file name if
the libtool's ltdl library interface is used.
Example:
ac_mod "ipa_ipfw.so";
ac_mod "ipa_ip6fw.so";
These parameters load two accounting modules.
Using database modules
IPA database modules are used for storing statistics in databases.
ipa(8) and database modules work together via the ipa_db_mod API
described in the ipa_mod(3) manual page.
The db_mod parameter loads the given database module:
db_mod "file_name";
This parameter should not be placed in any section. Several database
modules can be used at one time.
The given file name should be a shared-object (shared library) file
name if ipa(8) uses dlopen(3) interface or it can be a .la file name if
the libtool's ltdl library interface is used.
Example:
db_mod "ipa_db_sdb.so";
This parameter loads one database module.
Configuring modules
Documentation for some IPA module should give all information how to
configure it. Usually configuration of a IPA module is integrated to
the configuration file ipa.conf(5).
Each module has a configuration prefix, which is used for
distinguishing module's sections and parameters. If there is a
parameter like this one:
prefix:parameter [[=] argument];
then ipa(8) will try to find a loaded module with configuration prefix
``prefix'', then ipa(8) will give this parameter for parsing to the
found module.
Sections also can have prefixes:
prefix:section [[=] argument] {
/* Module's parameters and sections. */
}
In this case parameters and sections inside such section should be
written without a prefix and this section and all its internal sections
and parameters will be passed to the appropriate module for parsing.
Documentation for some module should describe a module itself, module's
configuration prefix, database or accounting system name and all
module's parameters and sections.
Example:
sdb: {
allow_symlinks = yes;
}
ipfw:debug = 1;
Given section's name can confuse one, but everything is correct. A
module can have empty section's and parameter's name.
Units of statistics
Arguments of some parameters and sections can be bytes, time and
unsigned 64-bit integer numbers. Such data type is defined as
IPA_CONF_TYPE_VALUE in ipa_mod(3). Sometimes it is desirable to use
only one data type for such values, because ``10'', ``10m'' and ``10M''
are correct values and mean 10, 10 minutes and 10 Mbytes respectively.
The value_units parameter can be used for specifying desired data type
for arguments with IPA_CONF_TYPE_VALUE data type and for controlling
their real values:
value_units = <type>;
This parameter should not be placed in any section and it is better to
place it before other parameters and sections. It accepts the
following values: ``any'' (the default value), ``time'', ``bytes'' and
``number''.
Parameters limit, threshold, threshold_deviation and sublimit section
accept arguments with IPA_CONF_TYPE_VALUE data type.
Accounting rules
ipa(8) performs accounting based on rules. There are static and
dynamic rules. A static rule is described in the rule section. A
dynamic rule does not have description in the configuration file, but
it is generated on-the-fly from some autorule described in the autorule
section.
Several rules (static, dynamic) can share settings. There are several
ways to do this. The first way is using the global section. The
second way is using rulepat (rules patterns) sections. And the third
way is specifying common settings for dynamic rules in autorule
sections.
If some rule (static, dynamic) does not have settings for some section
or parameter, then it inherits settings from matched rulepat section,
then it inherits settings from the global section; if there are still
some unspecified sections or parameters, then default settings are
used. Run ipa(8) with -tt switches to see real values of all
parameters.
Following parameters can be used in global, rulepat, rule and autorule
sections: ac_list, db_list, append_time, update_time, worktime,
ctl_rule_acl, debug_exec, debug_limit, debug_limit_init,
debug_threshold, debug_threshold_init.
Using accounting systems
The ac_list parameter specifies a list of used accounting systems:
ac_list = <list>;
<List> is a set of names separated by a space character. To get names
of accounting systems read documentations for modules you specified in
ac_mod parameters.
If some rule has the ac_list parameter, then accounting systems listed
in its argument will be asked for statistics for this rule. This
parameter allows to create per rule accounting systems list.
There is one built-in accounting system null: this accounting system
always returns 0 as statistics. If the ac_list parameter is not
specified and is not inherited, then the null accounting system is
used.
Example:
ac_mod "ipa_ipfw.so";
ac_mod "ipa_ip6fw.so";
global {
ac_list = ipfw ip6fw;
}
Here two accounting systems are specified.
Using databases
The db_list parameter specifies a list of used databases:
db_list = <list>;
<List> is a set of names separated by a space character. To get names
of databases read documentations for modules you specified in db_mod
parameters.
If some rule has the db_list parameter, then databases listed in its
argument will be used for storing statistics for this rule. This
parameter allows to create per rule databases list. The same
corresponds to limits and thresholds.
There is one built-in database null: data sent to this database is not
kept anywhere. If the db_list parameter is not specified and is not
inherited, then the null database is used.
Example:
db_mod "ipa_db_sdb.so";
global {
db_list = sdb;
}
Here one database is specified.
Accounting per period of a week
By default accounting is performed for all days in a week, but
accounting can be performed only for some time intervals in a week.
The worktime parameter specifies time intervals when accounting should
be performed:
worktime = <X> h1:m1-h2:m2 [h1:m1-h2:m2];
worktime = <X> *;
<X> means a week day. Valid values for <X> are: `S' Sunday, `M'
Monday, `T' Tuesday, `W' Wednesday, `H' Thursday, `F' Friday, `A'
Saturday. There can be only one record for each day. Time intervals
cannot be overlapped or be placed not in the order.
00:00-24:00 interval or the `*' character means whole day.
When worktime allows to perform accounting, then the section where it
is placed is called ``active'', else it is called ``inactive''.
What exactly this parameter defines for autorules, rules, limits and
thresholds read in the appropriate paragraphs.
Note that time intervals given in the worktime parameter do not
guarantee that exactly the same time intervals will appear in the
database, because the running copy of ipa(8) can have low priority or
the system can be to busy.
The end of one time interval can be the start of the next time
interval, this feature is only useful for rules (see below).
Example:
Perform accounting only at Monday, Tuesday and Wednesday:
worktime = M * T * W *;
Perform accounting at Thursday from 8:00 till 14:30 and from 18:20 till
21:00, at Sunday from midnight till 10:35 (the value is written in
several lines just for indenting):
worktime = H 08:00-14:30 18:20-21:00
S 00:00-10:35;
Database time intervals
The update_time parameter determines time interval when statistics for
some rule should be updated:
update_time = <time>;
If this parameter is omitted, then the default value is 1 minute.
The append_time parameter determines time interval when a new
statistics record for some rule should be appended:
append_time = <time>;
This parameter does not have a default value. A new statistics record
for each rule is appended to the database at the end of each day in any
case.
Usually the value of the append_time parameter is greater than the
value of the update_time parameter.
ipa(8) tries to combine several time events into one to reduce resource
usage, this feature has another interesting moment. For example, if
update_time is 5 minutes, then ipa(8) always schedules time events for
this parameter at 00:00, 00:05, 00:10 and so on.
There are programs that can change UTC and local time, also the time
zone can change itself. Such events can cause ``some time related
problems occurred'' non fatal errors in ipa(8). Too small values of
parameters update_time and append_time can cause more such errors. For
example, if you synchronize time very often and the value of the
update_time parameter is nearly equal to the time interval of time
synchronization, then you can receive a lot of such warning messages.
The sensitive_time parameter allows to specify how time events are
sensitive to time changes:
sensitive_time = <time>;
By default the value is 30 seconds. This parameter should not be
placed in any section.
The wakeup_time parameter specifies maximum number of seconds ipa(8)
can sleep. This parameter tells ipa(8) when to wake up and check if
everything is correct with time, time zone, etc.:
wakeup_time = <time>;
The default value is 10 minutes. This parameter should not be placed
in any section.
Example:
global {
update_time = 30s;
append_time = 1h 30m;
}
The `s' character means seconds, `m' minutes, `h' hours (spaces in
<time> are optional). If <time> is specified as a complex value, then
hours should be placed before minutes and seconds, minutes should be
placed before seconds.
Descriptions of rules, limits and thresholds
Sections rule, limit and threshold can have the optional parameter
info, which is passed to the database and is used for describing a
section:
info = "string";
The value of this parameter should not contain `\n' and `\t'
characters. Usually this value should help to recall what this rule,
limit or threshold is used for.
A dynamic rule gets its description from an accounting module that
generates it, so you cannot specify descriptions for dynamic rules in
the configuration file.
Example:
rule 10.1.2.3-in {
info = "My traffic from ISP";
/* ... */
}
Sometimes rule's name is not very informative, so describing a rule is
a good idea.
Names of rules, limits, thresholds and autorules
Any symbol in any name must be letter, digit or punctuation symbol from
the ASCII character set.
Any name cannot contain double quote, '/' and '\' symbols.
You should give such names that are also valid rules names for
databases you use.
These restriction also work for dynamic rules and for names used in
commands in ictl parameters.
Static rules
Static rules are called ``static'' because they exist in the
configuration file and any accounting module cannot delete them.
The rule section describes settings for one static rule:
rule <rule-name> {
/* Rule's parameters and sections. */
}
The rule section does not have any mandatory settings. If some rule
does not have any sections and parameters, then it is called an empty
rule. It is obvious that empty rules are senseless, so any rule
usually has some parameters (own or inherited).
If a rule has the worktime parameter, then a new accounting record is
appended to the database when a new time interval begins. If a rule is
inactive, then all its limits and thresholds are inactive as well.
Example:
ac_mod "ipa_ipfw.so";
ac_mod "ipa_ip6fw.so";
db_mod "ipa_db_sdb.so";
rule local.traf {
ac_list = ipfw ip6fw;
db_list = sdb;
info = "Traffic to my LAN";
sdb:db_group = staff;
ipfw:rules = 100 200 300;
ip6fw:rules = 1.10;
}
Here a rule uses two accounting systems and one database. It also has
a description and several modules' specific parameters.
Running commands
There are several sections which allow to specify a list of commands
which should be run if some event occurred. The exec parameter is used
for running commands:
exec [<user>] "/path/command [arguments]";
The exec parameter without <user> runs a command with privileges of the
user who run ipa(8), that is no actions in changing user or groups are
performed.
The exec parameter with <user> runs a command with privileges of the
given user. A user can be given only by its name. ipa(8) will get UID
and GIDs of the user just before running a command. This parameter can
be used if ipa(8) is run by the super-user only.
If is needed to use name of the rule in some command string in rulepat
or autorule section, then use substitutions. Two substitutions are
defined: %rule% means the name of the rule, %% means the `%' character.
These substitutions do not work in command strings placed in rule
sections, use macro variable ${rule} and single `%' character there
instead.
By default commands should be given with absolute pathname, but it is
possible to specify commands with relative pathnames, just set the
only_abs_paths parameter to ``no'' (the default value is ``yes''):
only_abs_paths = <boolean>;
All commands are run by a command shell, so any shell-specific command
line constructions can be used:
<shell_path> <shell_arg1> /path/command [arguments]
Note that the standard input (stdin), standard output (stdout) and the
standard error (stderr) are handled in the same way as in ipa(8).
<Shell_path> is determined when IPA is built (see output of the
``ipa -v'' command for the real pathname), but it can be redefined in
the shell_path parameter:
shell_path = "/path/shell";
<Shell_arg1> is equal to ``-c'' by default, but it can be redefined in
the shell_arg1 parameter:
shell_arg1 = "<arg1>";
If there are not enough resources and ipa(8) is not able, for example,
to fork(2) a child to run a commands list, then ipa(8) will exit with
an error code. But if any error occurred in a child which runs a
command, then ipa(8) will ignore this error and a child simply will log
a warning message. There is no a portable way to implement a better
handling of such errors.
Parameters only_abs_paths, shell_path and shell_arg1 should not be
placed in any section.
Example:
startup {
exec "/bin/echo \"ipa started\" | mail me";
exec nobody "/usr/local/bin/something";
}
only_abs_path = no;
shutdown {
exec "echo \"ipa stopped\" | mail me";
}
rulepat "^client" {
startup {
exec "command %rule%";
}
}
rule 1 {
shutdown {
exec "echo rule off >> /tmp/${rule}.log";
}
}
In the first section the ``mail'' command is given without an absolute
pathname. This is correct because only the first command is checked
for an absolute pathname, ipa(8) does not interpret shell-specific
command line constructions.
In the rulepat section substitution %rule% is used and in the rule
section macro variable ${rule} is used for inserting the name of the
rule to the command string.
Running commands at startup and shutdown
One can specify which commands should be run when ipa(8) starts
(finishes) its work in startup (shutdown) sections. These sections can
be placed alone (global commands) and in autorule, rulepat, rule,
limit, sublimit and threshold sections.
If these sections are placed alone (see below usage of these sections
inside other sections), then they can contain only sync_exec, ictl
(only inside startup) and exec parameters.
The algorithm of running commands in startup (shutdown) sections is the
following:
1. run global commands;
2. run commands from rule sections;
2a. in each rule section run commands for limits and thresholds;
2b. in each limit section run commands for its sublimits.
When ipa(8) rereads the configuration file (when it receives a SIGHUP
signal), then commands in startup sections are ignored, but new
commands for shutdown sections will be used.
Example:
startup {
exec "command1";
}
rule 1 {
startup {
exec "command2";
}
limit 1 {
/* ... */
startup {
exec "command3";
}
}
}
rule 2 {
startup {
exec "command4";
}
}
Here commands are run in the following order on startup: command1,
command2, command3 and command4.
Running commands synchronously and asynchronously
There are two regimes of running commands: synchronous and
asynchronous. In synchronous regime ipa(8) is waiting for the exit of
running commands. In asynchronous regime ipa(8) having run commands,
is not waiting for the exit of running commands and continues its work.
By default commands in all startup and shutdown sections are run
synchronously, in all other sections commands are run asynchronously.
The sync_exec parameter allows to specify synchronous or asynchronous
regime for any section:
sync_exec = <boolean>;
This parameter can be used in any section which accepts exec
parameters.
Example:
startup {
sync_exec = no;
exec "/path/something";
}
In this example default synchronous regime of the startup section is
changed to asynchronous.
About statistics
In IPA statistics is 64-bit unsigned integer numbers. Statistics can
be whatever (time, bytes or numbers). If some rule uses several
accounting systems, then ipa(8) summarizes statistics got from each
accounting system. Usually an accounting module returns positive
statistics, but it can return negative statistics. Any database gets
statistics as 64-bit unsigned integer numbers together with the current
local time.
Internally each rule has two 64-bit unsigned integer counters: one
counter for positive statistics and another one for negative
statistics. In any time one of these counters is equal to zero. If
the negative statistics counter is overflowed, then ipa(8) reports
about occurred problem and exits since such overflow means wrong
configuration. If the positive statistics counter is overflowed, then
ipa(8) asks the database to append a new statistics record for a rule
to store statistics which does not fit the size of its internal
counter.
Internally any limit or threshold has the same two counters, but if
limit's or threshold's positive or negative counter is overflowed, then
ipa(8) reports about occurred problem and exits since such overflow
means wrong configuration. Also each threshold has several counters
for each time slice (signs of counters are kept in a bitmap).
Usually positive statistics is greater than negative statistics, but
this is not required. Only positive statistics is stored in the
database and while ipa(8) is running negative statistics is kept in its
memory, but when ipa(8) exits and some rule (limit or threshold) has
negative statistics, then this negative statistics is lost (a log
message will be sent). In other words, ipa(8) is able to subtract
statistics from the current value of its positive statistics counter
and there is not any way to subtract statistics from old statistics in
the database.
Limits: introduction
A limit should be considered with the context of some rule. Sometimes
limits in IPA are called triggers. If it is necessary to do some
actions when statistics for some rule reaches some value during some
time period, then the limit section should be used. This section can
have several sections and must have at least one parameter named limit:
limit <limit-name> {
limit = <limit-value>;
/* Limit's parameters and sections. */
}
One rule can have several limits. If a rule has at least one limit,
then it will no inherit any limits from the matched rulepat section.
Any limit has 64-bit unsigned integer counter for positive statistics.
This counter is updated synchronously with a rule's counter. If the
counter becomes equal to or greater than the value of the limit
parameter, then a limit is treated as reached and its counter will not
be updated any more.
<Limit-value> can be: bytes, time or unsigned 64-bit integer number
(see examples below); and it can be equal to zero.
A limit can pass several states: a limit is not reached, a limit is
reached (plus optionally running commands), a reached limit is expired
(plus optionally running commands) and pseudo state when a not reached
limit should be restarted. The limit section can have some parameters
and some sections which determine a limit's states (described below).
If a limit is not reached, then its statistics is checked each time
when its rule is updated (this time interval is not more than the value
of the update_time parameter).
Example:
rule my-account {
/* Rule's parameters and sections. */
limit 1 {
limit = 1M 500K;
info = "Bytes limit";
}
limit 2 {
limit = 2h 30m;
info = "Time limit";
}
limit 3 {
limit = 1234567890;
info = "Numerical limit";
}
}
There are three limits in one rule in this example.
When the value of the limit parameter is given as bytes, then the `T'
character means Tbytes, `G' Gbytes, `M' Mbytes, `K' Kbytes, `B' bytes
(spaces are optional). If a value is specified as a complex value,
then Tbytes should be placed before Gbytes and Mbytes and so on.
1 Kbyte is equal to 1024 bytes.
Restarting a not reached limit
The restart parameter in the restart section allows to specify time
when a not reached limit should be restarted with zeroed (flushed)
positive and negative counters:
limit <limit-name> {
/* Limit's parameters and sections. */
restart {
restart = <restart-time>;
/* Commands. */
}
}
The time when a new limit was created or a reached limit was restarted
again is known as ``start time''. The <restart-time> value is relative
to limit's start time (see example).
The restart section can contain optional commands which will be run at
the moment of limit restart.
Accounting systems used by limit's rule are informed when a not reached
limit is restarted. So if you do not specify commands in the restart
section, then some actions still can be performed by accounting
systems.
If a limit does not have the restart parameter, then this limit (if it
is not reached) cannot be automatically restarted. But it can be
restarted by the ipactl(8) utility or by ictl parameters and all
commands from the restart section will be run.
A not reached limit can restart only when its rule is active.
Example 1:
rule my.traf {
ac_list = ipfw;
ipfw:rules = 100 200;
limit 1 {
limit = 1G;
restart {
restart = 20h 30m;
}
}
}
Here the value of the restart parameter is added to limit's start time
and calculated value is time when a limit should be restarted. Here
restart time is simply a number of seconds from limit's start time.
The `s' character means seconds, `m' minutes, `h' hours, `D' days and
`W' weeks.
Example 2:
rule my.traf {
ac_list = ipfw;
ipfw:rules = 100 200;
limit 1 {
limit = 1G;
restart {
restart = +W;
}
}
}
Here the limit will be restarted at the end of a week after limit's
start time. A character after the `*' sign means: `m' a minute, `h' a
hour, `D' a day, `W' a week, `M' a month.
Example 3:
rule my.traf {
ac_list = ipfw;
ipfw:rules = 100 200;
limit 1 {
limit = 1G;
restart {
restart = +M 2D;
}
}
}
In this example the limit will be restarted on the beginning of the
third day of the next month after limit's start time: the restart time
for ``+M'' (start of the next month) is calculated and then ``2D'' (two
days) are added to the calculated value.
Note that ``2D +M'' is not the same: here ``2D'' is added to limit's
start time and then the restart time for ``+M'' is calculated (and we
always will get first day of some next month here).
Actions when a limit becomes reached
If a limit becomes reached, then commands listed in the reach section
are run:
limit <limit-name> {
/* Limit's parameters and sections. */
reach {
/* Commands. */
}
}
The reach section can be absent or empty and in this case no commands
will be run when a limit becomes reached.
Accounting systems used by limit's rule are informed when a limit
becomes reached. So if you do not specify commands in the reach
section, then some actions still can be performed by accounting
systems.
Example:
rule my.traf {
ac_list = ipfw;
ipfw:rules = 100;
limit 1 {
limit = 1G;
restart {
restart = +W;
}
reach {
exec "/somewhere/stop_traffic";
}
}
}
Here there is 1 Gbyte limit. If this limit is not reached, then it
will be restarted at the end of the week. If this limit is reached,
then the given command will be run.
Restarting a reached limit
The expire parameter in the expire section allows to specify time when
a reached limit should be restarted with zeroed (flushed) positive and
negative counters:
limit <limit-name> {
/* Limit's parameters and sections. */
expire {
expire = <restart-time>;
/* Commands. */
}
}
The <restart-time> value is relative to time when a limit was reached
(see example).
The expire section can contain optional commands, which will be run at
the moment of limit restart.
Accounting systems used by limit's rule are informed when a reached
limit is restarted. So if you do not specify commands in the expire
section, then some actions still can be performed by accounting
systems.
If a limit does not have the expire parameter, then this limit (if it
is reached) cannot be automatically restarted. But it can be restarted
by the ipactl(8) utility and by ictl parameters and all commands from
the expire section will be run.
The value of the expire parameter can be 0s, this means that reached
limit will be restarted immediately.
A reached limit can expire only when its rule is active.
Example:
rule my.traf {
ac_list = ipfw;
ipfw:rules = 100;
limit 1 {
limit = 1G;
restart {
restart = +W;
}
reach {
exec "/somewhere/stop_traffic";
}
expire {
expire = +W;
exec "/somewhere/start_traffic";
}
}
}
Here there is 1 Gbyte per week limit. If the limit is reached, then at
the beginning of the next week it will be restarted. If this limit is
not reached, then it is also restarted at the beginning of the next
week.
Active and inactive limits
If a limit does not have own worktime parameter, then it inherits this
parameter from its rule. Any limit can have own worktime parameter.
If a rule is inactive, then all its limits are inactive as well. If a
limit is inactive, then times defined by the restart and expire
parameters are not checked.
It is possible to have active rule and inactive limit, but it is
impossible to have inactive rule and active limit. All time intervals
in the limit's worktime parameter must be subsets of time intervals in
the rule's worktime parameter. To check time intervals subsets in
static rules and autorules run ipa(8) with -tt switches.
Example:
rule my-account {
/* ... */
worktime = A * S *;
limit 1 {
limit = 10M;
worktime = A 08:00-21:00 S 08:00-21:00;
}
}
Here the rule is active only at Saturday and Sunday and the limit is
active only from 08:00 till 21:00 at the same days. Since 08:00-21:00
time interval is a subset of 00:00-24:00 time interval, then everything
is correct with these two parameters.
Startup and shutdown sections for a rule
A rule can have own startup and shutdown sections with the following
extra subsections:
if_any_reached - if any of rule's limits is reached;
if_any_not_reached - if any of rule's limits is not reached;
if_all_reached - if all rule's limits are reached;
if_all_not_reached - if all of rule's limits are not reached.
These subsections determine commands, which should be run if limits'
states fit a subsection condition.
Any rule can have empty startup or shutdown section, in this case this
section is not inherited from the matched rulepat section.
Example:
rule my.traf {
ac_list = ipfw;
ipfw:rules = 100;
startup {
exec "/somewhere/count_traffic";
if_any_reached {
/* ... */
exec "/bin/echo \"Some limit in \
rule ${rule} was reched\" | mail admin";
}
}
limit 1 {
limit = 1G;
restart {
restart = +M;
}
info = "1G per month";
/* ... */
}
limit 2 {
limit = 500M;
restart {
restart = +W;
}
info = "500M per week";
/* ... */
}
}
Here there are two limits: 1 Gbyte per month and 500 Mbytes per week,
the if_any_reached section will be used if any of these two limits is
reached at the moment of the start of ipa(8). Also rule's startup
section has one command, which is always run at startup. Here we use
one back-slash character for splitting a command string.
Startup and shutdown sections for a limit
A limit can have own startup and shutdown sections with the following
extra subsections:
if_reached - if a limit is reached;
if_not_reached - if a limit is not reached.
These subsections determine commands, which should be run if a limit's
state fits a subsection condition.
Accounting systems used by limit's rule are informed at startup and
shutdown whether a limit is reached or is not reached. So if you do
not specify startup and/or shutdown commands for a limit, then some
actions still can be performed by accounting systems.
Databases and limits (thresholds)
A limit inherits a list of databases from its rule, but a limit can
have own list of database:
rule <rule-name> {
/* Rule's parameters and sections. */
db_list = <list1>;
limit <limit-name> {
/* Limit's parameters and sections. */
db_list = <list2>;
}
}
<List1> and <list2> can contain common elements, <list1> is used only
for a rule and <list2> is used only for a limit in any case.
Why to use separate database lists for a rule and a limit? Not all
databases work with limits and even if some database works with limits,
it can support not all functions (methods) for limits. See
implementation details in the ipa_mod(3) manual page.
Suppose some limit uses several databases. During initialization the
first database, that is able to return a limit's state, will be asked
for the current limit's state. Even if some other database has another
limit's state, it will not be asked for it and its limit's state will
be updated.
Note that the order of databases for a limit is important.
Read in the database module's documentation whether it can work with
limits and what exactly a module supports when it works with limits.
Everything said above corresponds to thresholds as well.
Using the limit (threshold) parameter from the database
The load_limit parameter allows to fetch the value of the limit
parameter from the database:
limit <limit-name> {
/* Limit's parameters and sections. */
load_limit = <boolean>;
}
If it is necessary to load the value of the limit parameter from the
database, then set the value of the load_limit parameter to ``yes''
(the default value is ``no''). If the database does not have the
current state of a limit (if a limit is new), then the value of the
limit parameter from the configuration file will be used, that's why
the limit parameter always must be specified.
One of possible cases why one wants to set this parameter to ``yes'' is
the usage of the ipactl(8) utility for changing the value of the limit
parameter on-the-fly.
This parameter can be specified in the global section. If some limit
does not have this parameter, then its value will be inherited from the
global section.
Everything said above corresponds to thresholds as well, but the
load_threshold parameter should be used for thresholds.
Limits initialization
When ipa(8) starts, rereads the configuration file or does
reinitialization when some time related problems occurred, it performs
the following steps for each limit:
1. The current limit's state is read from the database. If the
database does not have the limit's state, then a new limit's
state is registered with the value of the limit parameter from
the configuration file and with zero counter and initialization
of the limit is complete, else ipa(8) does second step (2a or
2b).
2a. If the limit is not reached with the current state from the
database, then if the value of the load_limit parameter is
``no'', then ipa(8) updates the value of the limit parameter
from the configuration file; if the value of the load_limit
parameter is ``yes'', then ipa(8) ignores the value of the limit
parameter from the configuration file and gets this value from
the database. In any case the limit is marked as not reached,
even if with new settings it becomes reached. Then ipa(8)
updates date when the limit should be restarted accordingly to
the value of the restart parameter from the configuration file,
ignoring this date from the database.
If start time of a not reached limit is greater than current
time, then ipa(8) changes its start time to current time. The
limit's counter is not changed.
2b. If the limit is reached, then ipa(8) marks this limit as reached
and does not update the value of the limit parameter in the
database (that is, it does not honor the value of the load_limit
parameter at this moment). Then ipa(8) updates date when the
limit will expire accordingly to the value of the expire
parameter from the configuration file, ignoring this date from
the database.
A reached or not reached limit can be restarted during initialization
only if used database returned incorrect data about its state.
To verify the current limit's state use ipactl(8) with command status.
Limits: state diagram
To help to understand how exactly an arbitrary limit works, let's draw
the state diagram:
+--------------+--> Restart (Tstart)
| |
Trestart_exec Treach_exec Texpire_exec
--|------>------||------>------||------>------||------------->
Tstart Trestart Treach Texpire time
Sublimits
A sublimit is a part of some limit. The main purpose of a sublimit is
to register an event when some part of the limit parameter's value is
reached. Since a sublimit is a part of some limit section, then the
value of a sublimit must be given in the same units as the value of the
limit parameter or in per cent:
limit <limit-name> {
limit = <limit-value>;
/* Limit's parameters and sections. */
sublimit <sublimit-value> {
/* Sublimit's sections. */
}
}
Sublimits can contain only reach, startup and shutdown sections. All
these sections has the same format and mean the same as for limits. A
limit can have several sublimits.
Accounting systems are not informed about sublimits' events, because
sublimits are invisible for modules. Since sublimits states are not
kept in the database, it is always better to use sublimits than adding
extra limits to some rule if possible.
Example:
rule my.traf {
/* ... */
limit l1 {
limit = 1G;
load_limit = yes;
restart {
restart = +M;
}
info = "${rule}, ${limit} per month";
/* ... */
sublimit 50% {
reach {
exec "/bin/echo \"half of ${rule}'s \
limit ${limit} reached\" | mail me";
}
}
}
}
Here there is the sublimit, which will send an email when half of the
l1 limit is reached. Even if the value of the limit parameter will be
changed by the ipactl(8) utility, sublimit's value will be adjusted,
because it is given in per cent.
Thresholds: introduction
A threshold allows to monitor rule's statistics for some time period
before current time and do some actions when statistics for this time
period is less than, equal to or greater than the given value. This
time period also can be called ``sliding time window''. A threshold is
described in the threshold section with the following format:
threshold <threshold-name> {
threshold = <threshold-value>;
threshold_time_width = <time>;
threshold_time_slice = <time>;
/* Other threshold's parameters and sections. */
}
One rule can have several thresholds. If a rule has at least one
threshold, then it will no inherit any thresholds from the matched
rulepat section.
Any threshold has 64-bit unsigned integer counter, which is updated and
which is compared with the value of the threshold parameter. If the
counter becomes less than, equal to or greater than the value of the
threshold parameter, then commands from the optional below_threshold,
equal_threshold or above_threshold section are run. This counter is
updated synchronously with a rule's counter each threshold_time_slice
time interval.
<Threshold-value> can be: bytes, time or unsigned 64-bit integer
number; and it can be equal to zero.
It is possible to specify a deviation of <threshold-value> in the
threshold_deviation parameter. The value of the threshold_deviation
parameter must be given in the same units as the value of the threshold
parameter or in per cent.
The value of the threshold_time_width parameter determines the width of
sliding time window. The value of the threshold_time_slice parameter
determines time intervals of sliding time window movement. The
threshold_time_width parameter's value must be greater than the
threshold_time_slice parameter's value and must be divisible on this
value.
A threshold's counter represents a snapshot of rule's statistics for
the last threshold_time_width seconds. Unlike limits thresholds do not
have ``start time'', because their statistics is sliding in time in
discrete time intervals equal to threshold_time_slice seconds. These
two parameters can be specified in the global section and they will be
inherited if some threshold does not have them.
Accounting systems used by a threshold's rule are informed about
threshold's events. So accounting systems can do some actions when the
value of a threshold's counter is less, equal or greater than the
threshold parameter's value.
To limit number of times commands are run and accounting systems are
informed from below_threshold (X), equal_threshold (Y) and
above_threshold (Z) sections use the threshold_balance parameter:
threshold_balance = X:Y:Z;
This parameter can be specified in the global section and if some
threshold does not have it, then its value will be inherited from the
global section.
There are three internal counters x, y and z which count how many times
commands were run and accounting systems were informed from
below_threshold, equal_threshold and above_threshold sections
consecutively. These counters initially are equal to X, Y and Z
respectively. When threshold's counter is below than the value of the
threshold parameter and x is not equal to zero, then it is decreased, y
is set to Y and z is set to Z, then commands from the below_threshold
section are run and accounting systems are informed about threshold's
event. The same happens for y and z counters.
To unlimit value of X, Y or Z set it to `-'. In implementation
infinitive value really is equal to maximum value of 'unsigned int'
data type. The default value of this parameter is -:-:-.
Example:
rule lan {
ac_list = ipfw;
ipfw:rules = 100 200 -300;
update_time = 1m;
limit l1 {
limit = 1G;
info = "Control each 1G of bandwidth usage";
reach {
exec "/bin/echo \"1G of ${rule} reached\" | mail me";
}
expire {
expire = 0s;
}
}
threshold t1 {
threshold = 500M;
threshold_balance = 1:-:1;
threshold_deviation = 50M;
threshold_time_width = 24h;
threshold_time_slice = 15m;
info = "500M plus-minus 50M threshold per 24h";
below_threshold {
exec "/somewhere/increase_bandwidth ${rule}";
}
above_threshold {
exec "/somewhere/decrease_bandwidth ${rule}";
}
}
}
Here the rule has one threshold and one limit.
The threshold allows to dynamically control bandwidth in 500 Mbytes
plus-minus 50 Mbytes (we increase speed by some increase_bandwidth
program and decrease speed by some decrease_bandwidth program) per 24
hours (this is one day, but not a week day, here 24 hours mean time
interval). Time slice is 15 minutes, note that the threshold will not
be checked every minute here (the value of the update_time parameter
for this rule).
Statistics for the rule and the limit will be updated every minute.
The limit allows to send an email when next 1 Gbyte of bandwidth has
been used.
Active and inactive thresholds
Like a limit any threshold can be active and inactive and can have own
worktime parameter. Read appropriate paragraph for limits for more
information.
What is the value of the threshold's counter when a threshold was
inactive and becomes active due to the worktime parameter's value? One
solution is to allow a threshold's time window to slide during time
interval of inactivity, another solution is to ``move'' a threshold's
time window over time interval of inactivity. In the first solution
statistics for the threshold's counter during time interval of
inactivity is 0 and the value of the threshold's counter is decreased.
In the second solution statistics during time interval of inactivity is
ignored (it is skipped) and the value of the threshold's counter is not
changed.
What is the value of the threshold's counter when ipa(8) starts working
and there is a state of a threshold in the database? There are also
two solutions for this situation as for previous question.
To select solutions for above described situations use the
threshold_type parameter, its value is equal to ORed bits (given as
hexadecimal values):
0x1 jump over time interval when ipa(8) did not run (was stopped),
this bit is checked when a threshold is initialized;
0x2 jump over time interval when a threshold was inactive, this bit
is checked when a threshold became active again due to settings
of its worktime parameter.
The default value of this parameter is zero. Possible values of this
parameter are: 0, 1, 2 and 3 (0x1|0x2). Normal values for this
parameter are 0 or 3. Values with only one bit set should be used with
care, since when a threshold is initialized, it is treated as active
(read the paragraph about thresholds initialization).
This parameter can be specified in the global section and if some
threshold does not have it, then its value will be inherited from the
global section.
Example:
rule client {
ac_list = ipfw;
ipfw:rules = 100 200 300;
update_time = 1m;
threshold t {
threshold = 100M;
threshold_deviation = 10%;
threshold_time_width = 5h;
threshold_time_slice = 15m;
threshold_type = 3;
worktime = M 08:00-21:00 T 08:00-21:00 W 08:00-21:00
H 08:00-21:00 F 08:00-21:00;
info = "100M plus-minus 10% threshold per 5h (type 3)";
below_threshold {
exec "/somewhere/increase_bandwidth ${rule}";
}
above_threshold {
exec "/somewhere/decrease_bandwidth ${rule}";
}
}
}
Suppose that the given rule is for one client which has access to
Internet each work day from 08:00 to 21:00. We allow him 100 Mbytes
plus-minus 10% per 5 hours speed (we increase speed by some
increase_bandwidth program and decrease speed by some
decrease_bandwidth program).
Suppose that the threshold's current counter's value is 90 Mbytes at
21:00. When 08:00 of the next day comes, by default the threshold's
current counter's value becomes 0 Mbyte, because there is at least one
time interval in 5 hours between 21:00 and 08:00 of the next day. Here
we use threshold type 3 and time window will ``jump'' from 21:00 to
08:00 and the threshold's current counter's value will not be changed,
it will be 90 Mbytes at 08:00 of the next day. We also can stop ipa(8)
at 21:00 and run it again at 08:00 and a threshold's time window will
also ``jump'' from 21:00 to 08:00.
If there are several clients with the same settings, then at 08:00 non
of them will be able to intensively start to use own part of common
bandwidth.
Startup and shutdown sections for a threshold
A threshold can have own startup and shutdown sections, which can
contain only lists of commands.
Thresholds initialization
When ipa(8) starts, rereads the configuration file or does
reinitialization when some time related problems occurred, it performs
the following steps for each threshold:
1. The current threshold's state is read from the database. If the
database does not have the threshold's state, then a new
threshold's state is registered with the value of the threshold
parameter from the configuration file and with zero counter and
initialization of the threshold is complete, else ipa(8) does
second step.
2. Using values of load_threshold and threshold_type parameters and
the threshold's state is updated. Since threshold's statistics
slices are not saved in the database, valid statistics slices
are initialized approximately accordingly to the current local
time, threshold's timestamps and counter value.
When a threshold is initialized it is assumed as active even if its
worktime parameter marks this threshold as inactive.
Thresholds: time diagram
To help to understand how exactly an arbitrary threshold works, let's
draw the time diagram:
<-------------- time_width ------------->
(t1) |---c1--|---c2--|---c3--|---c4--|---c5--| --> sliding
(t2) |---c2--|---c3--|---c4--|---c5--|---c6--| --> sliding
<-slice->
-----|-------|-------|-------|-------|-------|-------|-------|-->
t1 t2 time
On this diagram there is threshold's statistics at time t1 and at time
t2. All statistics is represented as a sum of ci, each ci is equal to
statistics of a rule for one time slice t2 - t1. A threshold slides in
time discretely and its statistics is a snapshot of rule's statistics
for last time_width seconds.
Dynamic rules
Dynamic rules are generated from autorules by specially designed
accounting modules on-the-fly. Internally static and dynamic rules are
almost indistinguishable in ipa(8) and any parameter (except only three
parameters) and section from static rules can be used in dynamic rules.
The autorule section describes settings for one autorule:
autorule <autorule-name> {
/* Parameters and sections. */
}
A dynamic rule is looks like a static rule. There are only two
restrictions for autorules (hence for dynamic rules): an autorule can
have only one accounting system in the ac_list parameter's value and an
autorule cannot have ac_gather_* and ictl parameters.
The configuration file can have several autorules at once. Any
autorule usually have at least the ac_list parameter with one element
in its value. (It is possible to implement support for several
accounting systems for one autorule, but it is senseless.) This one
element determines accounting system that can create and delete dynamic
rules. Every time when this accounting system is asked for new
statistics, it can create and/or delete (previously created) dynamic
rules.
If you want to use some database for dynamic rules, then this database
should support dynamic rules.
If an autorule has the worktime parameter, then this parameter is for
this autorule. A dynamic rule generated from this autorule inherits
autorule's worktime_rule parameter as its worktime parameter. If an
autorule does not have the worktime parameter, then it inherits this
parameter from the global section.
Since an autorule and its dynamic rules can use different worktime
parameters it is possible to have inactive autorule and active dynamic
rules and vice versa.
A dynamic rule inherits parameters and sections from its autorule, if
some parameters and sections are still undefined, then they are
inherited from the matched rulepat section, then from the global
section and then default settings are used.
If an autorule has startup and shutdown sections, then these sections
are for dynamic rules, not for an autorule itself. If it is necessary
to use the name of some dynamic rule in some command line, then do not
use the ${rule} macro variable, because it is expanded by the internal
configuration file parser, use command line substitutions instead.
Any autorule can have empty startup or shutdown section, in this case
this section is not inherited from the matched rulepat section for its
dynamic rules.
If it is necessary to use different limits (thresholds) for dynamic
rules created from the same autorule, then specify these limits
(thresholds) in different rulepat sections.
Example:
ac_mod "ipa_atest.so";
db_mod "ipa_db_sdb.so";
global {
db_list = sdb;
append_time = 1h;
}
autorule a {
ac_list = atest;
update_time = 1m;
limit 1 {
limit = 100M;
restart {
restart = +W;
}
reach {
exec "/somewhere/stop_traffic.sh %rule%";
exec "/bin/echo \"%rule%'s limit ${limit} reached\" |
mail admin";
}
expire {
expire = +M;
exec "/somewhere/start_traffic.sh %rule%";
}
}
}
Here each dynamic rule generated from the autorule will inherit
autorule's update_time parameter and db_list and append_time parameters
from the global section. Each dynamic rule will have one limit, since
the ${rule} macro variable cannot be used in dynamic rules (actually in
autorules), then %rule% substitution is used. Using the ${limit} macro
variable in a limit in an autorule is correct, since limit's name is
know for the configuration file parser.
Rules patterns
Using rules patterns is an effective method for sharing common settings
for rules. The global section allows to specify some common settings
for any rules, dynamic rules can inherit common settings from their
autorules. Rules patterns allow to specify common settings for classes
of static and dynamic rules.
If some static or dynamic rule does not have some parameter or section,
then it inherits this parameter or section from the matched rule
pattern. A rule pattern is defined in the rulepat section:
rulepat "<regexp>" {
/* Parameters and sections. */
}
Each rule pattern is named by POSIX regular expression. Having parsed
the configuration file, ipa(8) finds a matched rule pattern for each
static rule and applies unspecified settings from a rule pattern to a
static rule. Similarly, having created a dynamic rule, ipa(8) finds a
matched rule pattern and applies unspecified settings from a rule
pattern to a dynamic rule.
By default when a matched rule pattern is found the search terminates.
To continue search for other rule patters set the check_next_rulepat
parameter to ``yes'' (the default value is ``no''):
check_next_rulepat = <boolean>;
This parameter can be used only in the rulepat section.
Any parameter (except ac_gather_* and ictl parameters) and any section,
which is allowed to use in the rule section, can be used in the rulepat
section.
Rules patterns can be placed anywhere in the configuration file, but
their order is important, because theirs regular expressions are
checked in the same order as they appear in the configuration file.
Modules also can expect their parameters and sections in rulepat
sections.
Example:
ac_mod "ipa_ipfw.so";
db_mod "ipa_db_sdb.so";
global {
ac_list = ipfw;
db_list = sdb;
update_time = 1m;
load_limit = yes;
sdb:db_group = staff;
}
rulepat "0${$}" {
check_next_rulepat = yes;
update_time = 30s;
threshold 1 {
threshold = 1G;
threshold_deviation = 10%;
threshold_time_width = 10h;
threshold_time_slice = 5m;
below_threshold {
exec "/somewhere/increase-bandwidth.sh %rule%";
}
above_threshold {
exec "/somewhere/decrease-bandwidth.sh %rule%";
}
}
}
rulepat "^client" {
worktime = M 08:00-20:00 T 08:00-20:00 W 08:00-20:00
H 08:00-20:00 F 08:00-20:00 A 08:00-17:00;
}
Here first rulepat section ``catches'' all rules with zero at the end
of their names (macro variable ${$} is expanded to single character
`$'). Since the value of its check_next_rulepat is ``yes'', then next
rule pattern is checked. Second rulepat section ``catches'' all rules
with ``client'' substring at the beginning of their names.
Gathering statistics from rules
Usually each rule gets statistics from accounting systems, but
sometimes it is necessary to summarize statistics from several rules
and it is impossible or too expensive give this task to accounting
modules.
The ac_gather_add and ac_gather_sub parameter allow to get statistics
for one rule from several rules:
rule <rule-name> {
/* Rule's parameters and sections. */
ac_gather_add = "<regexp>";
ac_gather_sub = "<regexp>";
}
Here <regexp> is a POSIX regular expression. If some rule's name
matches this regular expression, then its statistics is gathered by a
rule in which the ac_gather_* parameters are specified and is added to
(ac_gather_add) or subtracted from (ac_gather_sub) rule's statistics.
It is also possible to make complex dependencies with these parameters
(see the example).
These parameters can be used with static rules only, but can gather
statistics from static and dynamic rules.
The ac_list is a synchronous parameter in respect to the rule section:
when some rule is updated statistics is fetched from each accounting
system specified in a rule. Parameters ac_gather_* are asynchronous
parameters in respect to the rule section: current rule gets statistics
from a rule matched ac_gather_* parameters' regular expressions when
this matched rule is updated.
A rule can have ac_gather_* parameters and the ac_list parameter.
Example:
ac_mod "ipa_ipfw.so";
global {
ac_list = ipfw;
}
rule client1 {
ipfw:rules = 100 102 104;
info = "Statistics for first client";
}
rule client2 {
ipfw:rules = 200 202 204;
info = "Statistics for second client";
/* ac_gather_add = "^clients${$}"; <-- WRONG! */
}
rule clients {
ac_gather_add = "^client[[:digit:]]+${$}";
info = "Statistics for all clients";
}
rule server {
ipfw:rules = 1000 1002;
info = "Statistics for server";
}
rule all_stat {
ac_gather_add = "^(server|clients)${$}";
info = "Statistics for all in my LAN";
}
rule all_except_client2_stat {
ac_gather_add = "^all_stat${$}";
ac_gather_sub = "^client2${$}";
info = "Statistics for all in my LAN except client2";
}
Here there are six static rules: client1, client2, clients, server,
all_stat and all_except_client2_stat. The rule clients gets statistics
from rules client1 and client2. The rule all_stat gets statistics from
rules clients and server. And the rule all_except_client2_stat gets
statistics from rules clients and server not including statistics from
rule client2.
The rule client2 has incorrectly used the ac_gather_add parameter in a
comment. If this parameter exists in this rule, then we will get cycle
in rules dependencies: client2->clients->client2... ipa(8) does not
check cycles in rules dependencies.
Using ipactl(8) program
The ipactl(8) program allows to send control commands to ipa(8) via an
Unix domain socket. Before using this program it is necessary to allow
to use it by setting the ctl_enable parameter to ``yes'' (the default
value is ``no''):
ctl_enable = <boolean>;
If the value of this parameter is ``yes'', then ipa(8) creates a local
socket and listens for commands on it. The created socket is owned by
the user who run ipa(8).
Access permissions for the socket are defined by the value of the
ctl_socket_perm parameter (the default value is ``u''):
ctl_socket_perm = <permission>;
<Permissions> is a sequence of characters `u' (user), `g' (group) and
`o' (others). These characters determine who is allowed to write to
the socket. Other users can be allowed to write to the socket only if
ipa(8) uses ACL (access control list).
There is the default path to this socket (see the output of the
``ipactl -h'' command), but you it can be redefined in the
ctl_socket_path parameter:
ctl_socket_path = "/path/to/socket";
The socket has timeout equal to 10 seconds by default, but this value
can be changed in the ctl_timeout parameter:
ctl_timeout = <time>;
There is a limit on maximum size of a control query recevied by ipa(8).
Its default is 1 Kbyte. This value can be changed in the
ctl_query_max_size parameter:
ctl_query_max_size = <bytes>;
ipa(8) run under FreeBSD and NetBSD is able to check ipactl(8)'s
messages credentials (check this in the output of the ``ipa -v''
command), so on these systems one has to define ctl_acl_class and
ctl_*_acl parameters.
The ctl_acl_class parameter defines ACL class: the name of ACL followed
by ACL definition:
ctl_acl_class <class> [<ACL>];
This parameter should not be placed in any section.
ACL consists of elements separated by space character, each its element
has the following format:
[!]<user>|%<group>
The `!' character means that access is denied. The `%' character means
that the following name is a group name. <User> and <group> must be
given as symbolic names (UID and GID do not work here). Elements in
ACL are checked from the left to the right. Here ``access denied''
means that the user is not allowed to use some control command. When a
control message arrives, ipa(8) translates user name or groups name of
each ACL to UID or GID and compares it with a message's sender
credentials.
The ctl_dump_acl parameter applies ACL for the command dump:
ctl_dump_acl = <class>;
The ctl_freeze_acl parameter applies ACL for the command freeze:
ctl_freeze_acl = <class>;
The ctl_stat_acl parameter applies ACL for status and memory commands:
ctl_stat_acl = <class>;
The ctl_rule_acl parameter applies ACL to a rule for delete, expire,
restart, set and status commands and it applies ACL to an autorule for
create and status commands:
ctl_rule_acl = <class>;
If ACL is not defined and is not inherited, then it is considered as
empty ACL and means that access is denied for anybody.
Let's show how to use all these parameters in examples.
Example 1:
ctl_enable = yes;
ctl_socket_perm = ug;
In this example ipa(8) does not know how to get ipactl(8)'s control
messages credentials. User and group are allowed to send commands to
the socket (this is controlled by access permissions of the socket).
It is impossible to allow other users to write to the socket for
security reasons.
Example 2:
ctl_enable = yes;
ctl_socket_path = "/var/tmp/ipactl.sock";
ctl_timeout = 10s;
Here the socket path and timeout are redefined.
Example 3:
ctl_enable = yes;
ctl_socket_perm = ugo;
ctl_acl_class = empty;
ctl_acl_class = root root;
ctl_acl_class = admins root !john %wheel;
ctl_dump_acl = root;
global {
ctl_rule_acl = admins;
/* ... */
}
rulepat "^vip" {
ctl_rule_acl = root;
/* ... */
}
rulepat "^staff" {
ctl_rule_acl = admins;
/* ... */
}
rule lan-all {
ctl_rule_acl = empty;
/* ... */
}
In this example ipa(8) knows how to get ipactl(8)'s control messages
credentials. Three ACL classes are defined: empty, root and admins.
Others users are allowed to send commands to the socket.
Built-in ipactl
Any program can be run in any section which accepts exec parameters.
In such sections the ipactl(8) utility also can be run in an
asynchronous regime. If ipactl(8) is called in a synchronous regime
and if it connects to ipa(8) process which run it and if it has
infinitive timeout for connection, then it will run forever.
But calling ipactl(8) asynchronously from the exec parameter has one
disadvantage: such call is not atomic and it requires some time. The
problem is even worst if it is necessary to call ipactl(8) several
times from the same section.
The ictl parameter is a built-in version of ipactl(8) and supports the
following commands:
ictl "-r <rule> set ...";
ictl "-r <rule> -l <limit> expire|restart|set ...";
ictl "-r <rule> -t <threshold> set ...";
Formats of these parameter's values are similar to formats of
corresponding commands in ipactl(8). This parameter can be used in any
section which accepts exec parameters and it should be specified before
exec parameters. It is possible to use several ictl parameters. The
given control command in this parameter always is called synchronously,
ignoring the value of the sync_exec parameter. Actually ipactl(8) even
is not called, because corresponding functions are called directly.
The ictl parameter can be used inside static rules and inside global
startup section only. This parameter cannot be used inside any
shutdown section. It is possible to implement support for this
parameter for dynamic rules, but it is unclear if this is necessary.
There is one restriction for control commands. A control command
cannot be called for the rule (limit or threshold) from which it is
called. It is possible to create loops of control commands invocations
(e.g. a control command is called from one limit and modifies state of
another limit, that another limit calls a control command that changes
state of the original limit). Such loops are checked by ipa(8) and are
considered as wrong configuration.
As it was said above the ictl parameter can be used in startup
sections, but you should use it there only if you completely understand
what you are doing.
Any command given in the ictl parameter: 1) for a limit is synchronous
in respect to this limit's events; 2) for a threshold is asynchronous
in respect to this threshold's events; 3) for a rule is asynchronous in
respect to limits' and thresholds' events of this rule.
If you want to check correctness of specified names of rules, limits
and thresholds in control commands, then run ipa(8) with -tt switches,
because single -t switch does not check existence of names.
Example:
rule 1 {
/* ... */
limit 1 {
/* ... */
expire {
expire = +W;
ictl "-r 1 -l 2 expire";
ictl "-r 2 -l 1 restart";
ictl "-r 2 set counter +1000";
/* ... */
}
}
limit 2 {
/* ... */
}
}
rule 2 {
/* ... */
limit 1 {
/* ... */
}
}
When the first limit from the first rule expires, it will also
``expire'' (possibly reached) second limit from the first rule, restart
(possibly not reached) first limit from the second rule and it will add
1000 units of statistics to the second rule.
Freezing work of ipa(8)
It is sometime necessary to be sure that ipa(8) does nothing during
some period of time. There are two parameters which allow to freeze
work of ipa(8).
First parameter sleep_after_dump allows to specify period of time
during which ipa(8) should sleep and ignore any signals after execution
of the dump command from ipactl(8).
Second parameter freeze_time allows to specify period of time during
which ipa(8) should sleep and ignore any signals after receiving the
freeze command from ipactl(8).
These parameters have the following arguments:
freeze_time = <time>;
sleep_after_dump = <time>;
Values of these parameter should not be relatively big, because there
is a chance that some time event can be checked too late. The default
value of each parameter is equal to zero.
These parameters should not be placed in any section.
Example:
freeze_time = 30s;
sleep_after_dump = 5s;
Here we say ipa(8) to sleep 5 seconds after the dump command, and sleep
30 seconds after the freeze command. The scenario is the following: we
send the dump command (for example, if we want to fetch current
statistics later), and we send the freeze command to freeze work of
ipa(8) and change something in the system. Here we assume that 30
seconds will be enough to make all necessary changes in the system.
Order of active rules
ipa(8) checks rules starting from the head of the active rules queue.
If all rules are independent, then one should not worry about their
order; but if, for example, rule r1 should be checked before rule r2,
then read following several paragraphs.
If there is not any ac_gather_* parameters and there is not any
worktime parameters, then the order of active rules is the same as the
order of rules in the configuration file.
If there is at least one ac_gather_* parameter, then the order of rules
is changed to follow dependencies specified in ac_gather_* parameters,
but if some rules do not match regular expressions given in ac_gather_*
parameters, then their relative order is the same as their relative
order in the configuration file.
If there is not any ac_gather_* parameters and there are rules with
worktime parameters, then the order of these rules can be changed.
Dynamic rules always are added to the head of the active rules queue,
because dynamic rules cannot have ac_gather_* parameters, but some
static rule can get statistics from dynamic rules and dynamic rules can
have worktime parameters.
To keep the order of active rules the same as the order of rules in the
configuration file set the keep_rules_order parameter to ``yes' (the
default value is ``no''):
keep_rules_order = <boolean>;
Be careful with the order of rules in the configuration file if you
have at least one ac_gather_* parameter and the keep_rules_order
parameter is set to ``yes'': place rules which give statistics below
rules which get statistics.
Limits and thresholds in one rule are checked in the same order, as
they are written in the configuration and this order is not changed.
All limits are checked before thresholds in one rule.
Note that some modules are sensitive to the order of active rules.
This parameter should not be placed in any section.
Example:
keep_rules_order = yes;
Now ipa(8) will not change the order of active rules.
Debugging
Sometime it is necessary to find out why something goes wrong. There
are some parameters which can be used for debugging:
debug_ac_null - report when null accounting system is used (alone, 1);
debug_db_null - report when null database is used (alone, 1);
debug_time - debug various time related events (alone, 2);
debug_worktime - debug worktime parameters (alone, 1);
debug_exec - debug exec parameters (rule, 1);
debug_autorule - debug autorules (alone, 1);
debug_limit - debug limit related events (rule, 1);
debug_limit_init - report about limit initialization (rule, 1);
debug_threshold - debug threshold related events (rule, 1);
debug_threshold_init - report about threshold initialization (rule, 1).
Each debugging parameter accepts a debug level as an argument, maximum
debug level for each debug parameter is specified as a number in
parenthesis. If there is a word ``alone'' in parenthesis, then a
parameter should not be placed in any section. If there is a word
``rule'' in parenthesis, then a parameter can be placed in global,
rule, rulepat and autorule sections.
By default debugging is off for everything.
Example:
debug_worktime = 1;
global {
debug_limit_init = 1;
}
In this example detail information will be sent to the log file about
worktime's time intervals and about limits initialization for all
rules.
FILES
ipa.conf
(run ipa(8) with the -h switch and check default configuration file
pathname)
SEE ALSO
ipa(8), ipactl(8), ipastat(8), ipastat.conf(5), ipa_mod(3)
AUTHOR
Andrey Simonenko <simon@comsys.ntu-kpi.kiev.ua>
BUGS
If you find any, please send email me.
March 3, 2010 IPA.CONF(5)