A script is a compound of instructions. It is executed sequentially and
you can make branches with the 'if' statements. 'if' and 'if/else'
statements are the only supported. No loops are implemented. The syntax is
almost like C code except that you have to put 'if' blocks into graph
parentheses '{' '}', even if they contain only one instruction.
NOTE: you have to put a space between the 'if' and the '('.
You must not put the space between the function name and the '('.
Example:
if (conditions) { }
func(args...);
The conditions for an 'if' statement can be either functions
or comparisons. Two or more conditions can be linked together with
logical operators like OR '||' and AND '&&'.
Example:
if (tcp.src == 21 && search(DATA.data, "ettercap")) {
}
Pay attention to the operator precedence. You cannot use
parentheses to group conditions, so be careful with the order. An AND at
the beginning of a conditions block will exclude all the other tests if
it is evaluated as false. The parsing is left-to-right, when an operator
is found: if it is an AND and the previous condition is false, all the
statement is evaluated as false; if it is an OR the parsing goes on even
if the condition is false.
Example:
if (ip.proto == UDP || ip.proto == TCP && tcp.src == 80) {
}
if (ip.proto == TCP && tcp.src == 80 || ip.proto ==
UDP) {
}
the former condition will match all udp or http traffic. The
latter is wrong, because if the packet is not tcp, the whole condition
block will be evaluated as false. If you want to make complex
conditions, the best way is to split them into nested 'if' blocks.
Since etterfilter support both IP address families, you should
care whether you use 'ip.proto' which is specific for the IPv4 address
family or it's IPv6 couterpart 'ipv6.nh'. Especially for the L4 protocol
matching using 'ip.proto' and/or 'ipv6.nh', you should be careful if
you're really acting on the right protocol. This should be enforced
using the L3 protocol identifier 'eth.proto'.
Example:
if (eth.proto == IP && ip.proto == TCP && tcp.dst == 80 ||
tcp.src == 80) {
}
if (eth.proto == IP6 && ipv6.nh == TCP &&
tcp.dst == 80 || tcp.src == 80) {
}
if (tcp.dst == 80 || tcp.src == 80) {
}
The first example correctly matches http traffic only on IPv4
while the second would match http traffic only on IPv6. The thrid
example matches http regardless it's IP address familiy.
Every instruction in a block must end with a semicolon
';'.
Comparisons are implemented with the '==' operator and can be
used to compare numbers, strings or ip addresses. An ip address MUST be
enclosed within two single quotes (eg. '192.168.0.7' or '2001:db8::2').
You can also use the 'less than' ('<'), 'greater than' ('>'),
'less or equal' ('<=') and 'greater or equal' ('>=') operators.
The lvalue of a comparison must be an offset (see later)
Example:
if (DATA.data + 20 == "ettercap" && ip.ttl > 16) {
}
Assignments are implemented with the '=' operator and the
lvalue can be an offset (see later). The rvalue can be a string, an
integer or a hexadecimal value.
Example:
ip.ttl = 0xff;
DATA.data + 7 = "ettercap NG";
You can also use the 'inc' and 'dec' operations on the packet
fields. The operators used are '+=' and '-='. The rvalue can be an
integer or a hexadecimal value.
Example:
ip.ttl += 5;
More examples can be found in the etter.filter.examples
file.