Fortinet white logo
Fortinet white logo

Key concepts and features

Key concepts and features

This section covers key concepts and features you can reference when implementing Lua scripting in FortiWeb:

Lua package compatibility

FortiWeb uses Lua version 5.4.

Package name

Compatible details

global

Supported, but:

• Disable dofile()

• Disable loadfile()

• Modify print() to FortiWeb version, printing to debug log with level 1. (diag debug proxyd scripting-user <1-7>)

package

Disabled

coroutine Disabled
table Supported
io Disabled
os Disabled
string Supported
math Supported

utf8

Supported

Definition of terms

Frontend

The connection established between the client and FortiWeb when accessing a virtual server service.

Backend

The connection between FortiWeb and the real server after FortiWeb receives and load-balances the client request.

Source IP address (frontend)

The client IP address on the frontend connection.

Destination address (frontend)

The virtual server IP address on the frontend connection.

Source IP address (backend)

The IP address of FortiWeb’s outgoing interface on the backend connection.

Destination address (backend)

The real server IP address on the backend connection.

Control structures

The following table lists the Lua control structures.

Type

Structure

if then else

if condition1 then
    ...
elseif condition2 then
    ...
    break
else
    ... 
    goto location1 
end
 
::location1::

for

The following iterates through all key-value pairs in table 't':

for k, v in pairs(t) do
...
end

Operators

Operators are symbols used to perform specific mathematical or logical manipulations.

The Lua language includes the following categories of built-in operators:

For more details, see the Lua Reference Manual.

Arithmetic operators

The arithmetic operators listed below operate on real numbers. In the Example column, assume that variable A is 10 and variable B is 20.

Operator

Description

Example

+

Adds two operands.

A + B results in 30.

-

Subtracts the second operand from the first.

A - B results in -10.

*

Multiplies both operands.

A * B results in 200.

/

Divides the first operand by the second operand

B / A results in 2.

//

Floor division divides two operands and rounds the result down toward negative infinity, returning the largest integer less than or equal to the exact division result.

B // A results in 2.

%

Modulo returns the remainder of an integer division where the quotient is rounded toward negative infinity (floor division).

B % A results in 0.

^

Raises the first operand to the power of the second.

A^2 results in 100

-

Unary minus acts as negation.

-A results in -10

Bitwise operators

Bitwise operators convert its operands to integers, operate on all bits of those integers, and result in an integer.

In the Example column, assume we have two integer variables with binary representations:

a = 1100; // (12 in decimal)

b = 1010; // (10 in decimal)

Operator

Description

Example

&

Bitwise AND: compares each bit of the first operand with the corresponding bit of the second operand.

If both bits are 1, the corresponding result bit is set to 1. Otherwise, the result bit is set to 0.

c = a & b; // (8 in decimal)

c = 1000;

|

Bitwise OR: compares each bit of the first operand to the corresponding bit of the second operand.

If either of the bits is 1, the corresponding result bit is set to 1. Otherwise, the result bit is set to 0.

c = a | b; // (14 in decimal)

c = 1110;

^

Bitwise exclusive OR (XOR): compares each bit of the first operand to the corresponding bit of the second operand.

If the bits are different, the corresponding result bit is set to 1. Otherwise, the result bit is set to 0.

c = a ^ b; // (6 in decimal)

c = 0110;

>>

Bitwise Right Shift: shifts the bits of the given number to the right by the specified positions.

When a number is right shifted, 0s are added to the left side of the number, and the rightmost bits are discarded.

Using a variable "n" and a shift count "s", the left shift operation can be represented as:

c = n >> s;

a = 1100; (12 in decimal)

If we right shift "a" by 2 positions, the resulting value is:

c = a >> 2; // (3 in decimal)

c = 11;

<<

Bitwise Left Shift: shifts the bits of the given number to the left by the specified positions. When a number is left shifted, 0s are added to the right side of the number. The leftmost bits are discarded.

Using a variable "n" and a shift count "s", the left shift operation can be represented as:

c = n << s;

a = 1010; (10 in decimal)

If we left shift "a" by 2 positions, the resulting value is:

c = a << 2; // (40 in decimal)

c = 101000;

~

Unary bitwise NOT: used to perform bitwise negation on a single operand. It flips all the bits of the operand, changing each - bit to 1 and each 1 bit to 0.

Using the variable "a":

a = 1010; (10 in decimal)

c = ~a

c = 11111111111111111111111111110101; (-11 in decimal)

Applying the unary bitwise NOT operator to "10" flips all the bits, resulting in the Lua integer "-11".

Relational operators

Lua provides the Relational operators listed below. This type of operator always results in true or false.

In the Example column, assume variable A is 10 and variable B is 20.

Operator

Description

Example

==

Checks if the value of two operands are equal or not. If yes, then the condition is true.

(A == B) is false.

~=

Checks if the value of two operands are equal or not. If the values are not equal, then the condition is true.

(A ~= B) is true.

>

Checks if the value of the left operand is greater than the value of the right operand. If yes, then the condition is true.

(A > B) is not false.

<

Checks if the value of the left operand is less than the value of the right operand. If yes, then the condition is true.

(A < B) is true.

>=

Checks if the value of the left operand is greater than or equal to the value of the right operand. If yes, then the condition is true.

(A >= B) is false.

<=

Checks if the value of the left operand is less than or equal to the value of the right operand. If yes, then the condition is true.

(A <= B) is true.

Logical operators

Lua provides the Logical operators listed below. This type of operator considers false and nil both as false, and anything else as true.

In the Example column, assume variable A is 0 and variable B is 10.

Operator

Description

Example

and

Performs a logical "and" comparison between two values. If both the operands are non-zero then the condition is true. The operator and returns its first argument if it is false; otherwise, it returns its second argument.

(A and B) is false.

or

Performs a logical "or" comparison between two values. If any of the two operands is non-zero, then the condition is true. The operator or returns its first argument if it is not false; otherwise, it returns its second argument

(A or B) is true.

!

Performs a logical "not" on a value. Used to reverse the logical state of its operand. If a condition is true, then the logical not operator will make it false.

!(A and B) is true.

Miscellaneous operators

Miscellaneous operators supported by Lua include concatenation and length.

Operator Description Example
..

The string concatenation operator in Lua is denoted by two dots ('..').

If both operands are strings or numbers, then they are converted to a string, similarly to __concat.

a = "Hello "

b = "World"

a..b returns "Hello World".

#

The length operator returns the length of a string or an array-like table.

The length of a string is its number of bytes (that is, the usual meaning of string length when each character is one byte).

The length of a table t is defined to be any integer index n such that t[n] is not nil and t[n+1] is nil; moreover, if t[1] is nil, n can be zero.

a = "FortiWeb"

t = {1, 2, 3, 4}

#a returns 8

#t returns 4

Functions

FortiWeb supports basic lua commands. Additional capabilities can be implemented by creating custom functions using these commands.

Syntax

function function_name(parameter)
…
End

For example, this function extracts all IPs from XFF headers and returns IP array:

function extract_xff(xff)
    local t = {}
    local k, v, s
    for k, v in ipairs(xff) do
        for s in v:gmatch("([^,]+)") do
            t[#t + 1] = s:gsub("%s+", "")
        end
    end
    return t
end
when HTTP_REQUEST {
    local ips = extract_xff(HTTP:header("X-Forwarded-For"))
    local r, i, v
    for i, v in ipairs(ips) do
        r = ip.reputation(v) -- check ip, will return an array
        if #r > 0 then -- Found IP in reputation database
            debug("Found bad IP %s in XFF headers, reputation: <%s>, GEO country: <%s>, GEO country code: %s\n",
                v, table.concat(r, ', '),
                ip.geo(v) or "unknown", ip.geo_code(v) or "unknown")
            HTTP:close() -- force close this HTTP connection
            return -- Stop script and return
        end
    end
}

String library

The FortiWeb OS supports only the Lua string library. All other libraries are disabled. The string library includes the following string-manipulation functions:

  • string.byte(s, i)

  • string.char(i1,i2…)

  • string.dump(function)

  • string.find(s, pattern)

  • string.format

  • string.gmatch

  • string.gsub

  • string.len

  • string.lower

  • string.match

  • string.rep

  • string.reverse

  • string.sub

  • string.upper

  • string.starts_with

  • string.ends_with

  • If you want to use regular expression match, you can use string.match with Lua patterns.

  • All relational operators >, <, >=, <=, ~=, == can be applied to strings. In particular, == can be used to test if one string equals to another string.

  • string.find can be used to test whether one string contains another string.

For a tutorial on scripting with the Lua string library, see http://lua-users.org/wiki/StringLibraryTutorial.

Special characters

When written in a string, these characters look like this (between double quotes): "~!@#$^&*()_+{}[].?"

Note: The back slash (\) and the percent (%) signs are handled in a unique way in log and debug scripts. To print out %, you must use %%; to print out \, you must use \\.

Character

Name

~

Tilde

!

Exclamation

@

At sign

#

Number sign (hash)

$

Dollar sign

^

Caret

&

Ampersand

*

Asterisk

(

Left parenthesis

)

Right parenthesis

_

Underscore

+

Plus

{

Left brace

}

Right brace

[

Left bracket

]

Right bracket

.

Full stop

?

Question mark

\

Backslash

HTTP data body commands

HTTP data body commands support regular expressions, where special characters such as $ ^ ? * + . | ( ) [ ] { } \ " have special meanings. You must escape these characters to treat them as literal values.

To escape a special character, prefix it with two backslashes (\\).

For example, to use the literal caret (^) in an HTTP data body command, enter \^.

For grouping characters such as parentheses (), square brackets [], or braces {}, prefix each character with two backslashes.

For example, to use the {and}, enter \\{and\\}.

Key concepts and features

Key concepts and features

This section covers key concepts and features you can reference when implementing Lua scripting in FortiWeb:

Lua package compatibility

FortiWeb uses Lua version 5.4.

Package name

Compatible details

global

Supported, but:

• Disable dofile()

• Disable loadfile()

• Modify print() to FortiWeb version, printing to debug log with level 1. (diag debug proxyd scripting-user <1-7>)

package

Disabled

coroutine Disabled
table Supported
io Disabled
os Disabled
string Supported
math Supported

utf8

Supported

Definition of terms

Frontend

The connection established between the client and FortiWeb when accessing a virtual server service.

Backend

The connection between FortiWeb and the real server after FortiWeb receives and load-balances the client request.

Source IP address (frontend)

The client IP address on the frontend connection.

Destination address (frontend)

The virtual server IP address on the frontend connection.

Source IP address (backend)

The IP address of FortiWeb’s outgoing interface on the backend connection.

Destination address (backend)

The real server IP address on the backend connection.

Control structures

The following table lists the Lua control structures.

Type

Structure

if then else

if condition1 then
    ...
elseif condition2 then
    ...
    break
else
    ... 
    goto location1 
end
 
::location1::

for

The following iterates through all key-value pairs in table 't':

for k, v in pairs(t) do
...
end

Operators

Operators are symbols used to perform specific mathematical or logical manipulations.

The Lua language includes the following categories of built-in operators:

For more details, see the Lua Reference Manual.

Arithmetic operators

The arithmetic operators listed below operate on real numbers. In the Example column, assume that variable A is 10 and variable B is 20.

Operator

Description

Example

+

Adds two operands.

A + B results in 30.

-

Subtracts the second operand from the first.

A - B results in -10.

*

Multiplies both operands.

A * B results in 200.

/

Divides the first operand by the second operand

B / A results in 2.

//

Floor division divides two operands and rounds the result down toward negative infinity, returning the largest integer less than or equal to the exact division result.

B // A results in 2.

%

Modulo returns the remainder of an integer division where the quotient is rounded toward negative infinity (floor division).

B % A results in 0.

^

Raises the first operand to the power of the second.

A^2 results in 100

-

Unary minus acts as negation.

-A results in -10

Bitwise operators

Bitwise operators convert its operands to integers, operate on all bits of those integers, and result in an integer.

In the Example column, assume we have two integer variables with binary representations:

a = 1100; // (12 in decimal)

b = 1010; // (10 in decimal)

Operator

Description

Example

&

Bitwise AND: compares each bit of the first operand with the corresponding bit of the second operand.

If both bits are 1, the corresponding result bit is set to 1. Otherwise, the result bit is set to 0.

c = a & b; // (8 in decimal)

c = 1000;

|

Bitwise OR: compares each bit of the first operand to the corresponding bit of the second operand.

If either of the bits is 1, the corresponding result bit is set to 1. Otherwise, the result bit is set to 0.

c = a | b; // (14 in decimal)

c = 1110;

^

Bitwise exclusive OR (XOR): compares each bit of the first operand to the corresponding bit of the second operand.

If the bits are different, the corresponding result bit is set to 1. Otherwise, the result bit is set to 0.

c = a ^ b; // (6 in decimal)

c = 0110;

>>

Bitwise Right Shift: shifts the bits of the given number to the right by the specified positions.

When a number is right shifted, 0s are added to the left side of the number, and the rightmost bits are discarded.

Using a variable "n" and a shift count "s", the left shift operation can be represented as:

c = n >> s;

a = 1100; (12 in decimal)

If we right shift "a" by 2 positions, the resulting value is:

c = a >> 2; // (3 in decimal)

c = 11;

<<

Bitwise Left Shift: shifts the bits of the given number to the left by the specified positions. When a number is left shifted, 0s are added to the right side of the number. The leftmost bits are discarded.

Using a variable "n" and a shift count "s", the left shift operation can be represented as:

c = n << s;

a = 1010; (10 in decimal)

If we left shift "a" by 2 positions, the resulting value is:

c = a << 2; // (40 in decimal)

c = 101000;

~

Unary bitwise NOT: used to perform bitwise negation on a single operand. It flips all the bits of the operand, changing each - bit to 1 and each 1 bit to 0.

Using the variable "a":

a = 1010; (10 in decimal)

c = ~a

c = 11111111111111111111111111110101; (-11 in decimal)

Applying the unary bitwise NOT operator to "10" flips all the bits, resulting in the Lua integer "-11".

Relational operators

Lua provides the Relational operators listed below. This type of operator always results in true or false.

In the Example column, assume variable A is 10 and variable B is 20.

Operator

Description

Example

==

Checks if the value of two operands are equal or not. If yes, then the condition is true.

(A == B) is false.

~=

Checks if the value of two operands are equal or not. If the values are not equal, then the condition is true.

(A ~= B) is true.

>

Checks if the value of the left operand is greater than the value of the right operand. If yes, then the condition is true.

(A > B) is not false.

<

Checks if the value of the left operand is less than the value of the right operand. If yes, then the condition is true.

(A < B) is true.

>=

Checks if the value of the left operand is greater than or equal to the value of the right operand. If yes, then the condition is true.

(A >= B) is false.

<=

Checks if the value of the left operand is less than or equal to the value of the right operand. If yes, then the condition is true.

(A <= B) is true.

Logical operators

Lua provides the Logical operators listed below. This type of operator considers false and nil both as false, and anything else as true.

In the Example column, assume variable A is 0 and variable B is 10.

Operator

Description

Example

and

Performs a logical "and" comparison between two values. If both the operands are non-zero then the condition is true. The operator and returns its first argument if it is false; otherwise, it returns its second argument.

(A and B) is false.

or

Performs a logical "or" comparison between two values. If any of the two operands is non-zero, then the condition is true. The operator or returns its first argument if it is not false; otherwise, it returns its second argument

(A or B) is true.

!

Performs a logical "not" on a value. Used to reverse the logical state of its operand. If a condition is true, then the logical not operator will make it false.

!(A and B) is true.

Miscellaneous operators

Miscellaneous operators supported by Lua include concatenation and length.

Operator Description Example
..

The string concatenation operator in Lua is denoted by two dots ('..').

If both operands are strings or numbers, then they are converted to a string, similarly to __concat.

a = "Hello "

b = "World"

a..b returns "Hello World".

#

The length operator returns the length of a string or an array-like table.

The length of a string is its number of bytes (that is, the usual meaning of string length when each character is one byte).

The length of a table t is defined to be any integer index n such that t[n] is not nil and t[n+1] is nil; moreover, if t[1] is nil, n can be zero.

a = "FortiWeb"

t = {1, 2, 3, 4}

#a returns 8

#t returns 4

Functions

FortiWeb supports basic lua commands. Additional capabilities can be implemented by creating custom functions using these commands.

Syntax

function function_name(parameter)
…
End

For example, this function extracts all IPs from XFF headers and returns IP array:

function extract_xff(xff)
    local t = {}
    local k, v, s
    for k, v in ipairs(xff) do
        for s in v:gmatch("([^,]+)") do
            t[#t + 1] = s:gsub("%s+", "")
        end
    end
    return t
end
when HTTP_REQUEST {
    local ips = extract_xff(HTTP:header("X-Forwarded-For"))
    local r, i, v
    for i, v in ipairs(ips) do
        r = ip.reputation(v) -- check ip, will return an array
        if #r > 0 then -- Found IP in reputation database
            debug("Found bad IP %s in XFF headers, reputation: <%s>, GEO country: <%s>, GEO country code: %s\n",
                v, table.concat(r, ', '),
                ip.geo(v) or "unknown", ip.geo_code(v) or "unknown")
            HTTP:close() -- force close this HTTP connection
            return -- Stop script and return
        end
    end
}

String library

The FortiWeb OS supports only the Lua string library. All other libraries are disabled. The string library includes the following string-manipulation functions:

  • string.byte(s, i)

  • string.char(i1,i2…)

  • string.dump(function)

  • string.find(s, pattern)

  • string.format

  • string.gmatch

  • string.gsub

  • string.len

  • string.lower

  • string.match

  • string.rep

  • string.reverse

  • string.sub

  • string.upper

  • string.starts_with

  • string.ends_with

  • If you want to use regular expression match, you can use string.match with Lua patterns.

  • All relational operators >, <, >=, <=, ~=, == can be applied to strings. In particular, == can be used to test if one string equals to another string.

  • string.find can be used to test whether one string contains another string.

For a tutorial on scripting with the Lua string library, see http://lua-users.org/wiki/StringLibraryTutorial.

Special characters

When written in a string, these characters look like this (between double quotes): "~!@#$^&*()_+{}[].?"

Note: The back slash (\) and the percent (%) signs are handled in a unique way in log and debug scripts. To print out %, you must use %%; to print out \, you must use \\.

Character

Name

~

Tilde

!

Exclamation

@

At sign

#

Number sign (hash)

$

Dollar sign

^

Caret

&

Ampersand

*

Asterisk

(

Left parenthesis

)

Right parenthesis

_

Underscore

+

Plus

{

Left brace

}

Right brace

[

Left bracket

]

Right bracket

.

Full stop

?

Question mark

\

Backslash

HTTP data body commands

HTTP data body commands support regular expressions, where special characters such as $ ^ ? * + . | ( ) [ ] { } \ " have special meanings. You must escape these characters to treat them as literal values.

To escape a special character, prefix it with two backslashes (\\).

For example, to use the literal caret (^) in an HTTP data body command, enter \^.

For grouping characters such as parentheses (), square brackets [], or braces {}, prefix each character with two backslashes.

For example, to use the {and}, enter \\{and\\}.