Fortinet black logo

TCP commands

TCP commands

TCP commands contains functions to obtain and manipulate information related to the TCP layer, such as sockopt:

TCP:reject() — Allows the user to reject a TCP connection from a client.

TCP:set_snat_ip(str) — Allows the user to set the backend TCP connection’s source address and port.

TCP:clear_snat_ip() — Allows the user to clear any IP that was set using the set_snat_ip() command.

TCP:sockopt() — Can set or get various socket/IP/TCP operations, such as buffer size, timeout, MSS, etc. For client-side events, this command applies to the client-side socket; for server-side events, it applies to server-side socket.

TCP:after_timer_set() — Allows the user to create and schedule a timer with a callback function and timeout value. This allows you to create multiple timers each with a unique callback function name.

TCP:after_timer_cancel() — Allows the user to cancel a scheduled timer. This function can only cancel a timer before it is triggered if it is not periodic.

TCP:after_timer_get() — Allows the user to get the information about the scheduled timers.

TCP:close() — Allows the user to close the TCP connection immediately.

TCP:reject()

Allows the user to reject a TCP connection from a client.

Syntax

TCP:reject();

Arguments

N/A

Example
when TCP_ACCEPTED {
--check if the st is true or false;
If st then
TCP:reject();
end
}

FortiADC version: V5.0

Used in events: TCP_ACCEPTED

TCP:set_snat_ip(str)

Allows the user to set the backend TCP connection’s source address and port.

Syntax

TCP:set_snat_ip(str);

Note: To use the set_snat_ip() command, you must ensure the SOURCE ADDRESS flag is selected in the HTTP or HTTPS profile type.

Arguments
Name Description

str

A string which specifies the ip address.

Example
when TCP_ACCEPTED{
addr_group = “172.24.172.60/24”
client_ip = IP:client_addr()
matched = cmp_addr(client_ip, addr_group)
if matched then
if TCP:set_snat_ip(“10.106.3.124”) then
debug(“set SNAT ip to 10.106.3.124\n”)
end
end
}

Note: The VS must have the client address enabled in the profile, as shown in the example below.

config load-balance profile

edit "http"

set type http

set client-address enable

next

end

FortiADC version: V5.2

Used in events: TCP_ACCEPTED / HTTP_REQUEST / HTTP_DATA_REQUEST / CLIENTSSL_HANDSHAKE

TCP:clear_snat_ip()

Allows the user to clear any IP that was set using the set_snat_ip() command.

Syntax

TCP:clear_snat_ip();

Arguments

N/A

Example
when HTTP_REQUEST {
if TCP:clear_snat_ip() then
debug(“clear SNAT ip!\n”)
}

FortiADC version: V5.0

Used in events: TCP_ACCEPTED / HTTP_REQUEST / HTTP_DATA_REQUEST / CLIENTSSL_HANDSHAKE

TCP:sockopt()

Can set or get various socket/IP/TCP operations, such as buffer size, timeout, MSS, etc. For client-side events, this command applies to the client-side socket; for server-side events, it applies to server-side socket.

Note: In FortiADC version 7.4.3, the TCP:sockopt() functionality has been extended with the added new "type" parameter that allows FortiADC to read the customized TCP option. However, the "type" parameter currently only supports the GET operations.

Syntax

TCP:sockopt(table_parameter);

Arguments
Name Description

table_parameter

A Lua table which specifies the event and operation, variable:

t = {}

t["op"] = "set";

t["message"] = "maxseg";

t["value"] = 1240;

ret = TCP:sockopt(t);

OR

t = {}

t["op"] = "get";

t["type"] = 28;

ret = TCP:sockopt(t);

  • "op" — the action which can be either GET or SET. All options support both GET and SET operations except for "type" that only supports GET.

  • "message" — all options are passed via "message" except for "type".

  • "value" — a value is required for SET operations.

  • "type" — sets the custom TCP option type. This is newly added in FortiADC version 7.4.3.

Option(s) that support GET and SET operations:

  • "snd_buf"

  • "rcv_buf"

  • "so_type"

  • "so_priority"

  • "ip_ttl"

  • "fastopen"

  • "maxseg"

  • "so_mark"

  • "tos"

  • "ip_mtu"

  • "tcp_nodelay"

  • "tcp_cork"

  • "tcp_quickack"

  • "keepalive"

  • "ip_reputation"

  • "ipv6_v6only"

  • "linger"

  • "snd_timeo"

  • "rcv_timeo"

Option(s) that only support GET operations:

  • "type"

Examples

The following examples and notes only apply to the "type" parameter that was introduced in V7.4.3:

when HTTP_REQUEST {
	debug("============begin scripting.\n")
	
	clientip = nil
	t = {}
	t["op"] = "get"
	-- Set the custom TCP option type
	t["type"] = 28
	ret = TCP:sockopt(t)
	if ret and (string.len(ret)>=4) then
		debug("------> TCP get sockopt(%d): (returned %d bytes) successfully.\n", t["type"], string.len(ret));
		print_byte_array(ret)
		clientip = binStrToIpAddress(ret)
		debug("clientip = %s\n", clientip)
	else
		debug("------> TCP get sockopt(%d) failed.\n", t["type"])
	end

	if clientip then
		res = HTTP:header_insert("X-Forwarded-For", clientip)
		if res then
			debug("------> Header inserted successfully.\n")
		else
			debug("------> Header failed to insert.\n")
		end
	end
	
	debug("============end scripting.\n")
}

function binStrToIpAddress(binStr)
    return  tostring(string.byte(binStr,1)) .. "." .. tostring(string.byte(binStr,2)) ..
        	"." .. tostring(string.byte(binStr,3)) .. "." .. tostring(string.byte(binStr,4))
end

function print_byte_array(s)
  for i=1, string.len(s) do
     debug("0x%x.", string.byte(s,i))
  end
  debug("\n")
end

Notes:

For TCP options including Kind 28 type packet, only the first 4 bytes will be read.

For example:

Sent:

Kind: 28
Length: …
192,168,1,100,192.168,1,200,192,168,1,2

FortiADC reads:

=========begin scripting.        
clientip = 192.168.1.100

When the data sent is "abcd..." instead of regular numbers, decimals (ASCII code) 97,98,99,100 will be displayed.

For example:

Sent:

Kind: 28
Length: …
abcdef…

FortiADC reads:

------> TCP get sockopt(28): (returned 4 bytes) successfully.
0x61.0x62.0x63.0x64.
clientip = 97.98.99.100

If TCP options only contain two packets with Kind 28, only the first one will be read.

For example:

Sent:

Kind: 28
Length: 6
192,168,1,100
Kind: 28
Length: 6
192,168,1,100

FortiADC reads:

=========begin scripting.        
clientip = 192.168.1.100

The following examples apply to the TCP:sockopt() as introduced in V5.0:

when RULE_INIT {
debug(" ======== RULE_INIT ========\n");
-- access to https://notes.shichao.io/unp/ch7/ for more details.
tcp_message = {};
tcp_message[1]="snd_buf"; --int
tcp_message[2]="rcv_buf"; --int
setIntMsg = {};
setIntMsg[1]="snd_buf"; --int
setIntMsg[2]="rcv_buf"; --int
setIntValue = {};
setIntValue[1] = 111222;
setIntValue[2] = 111222;
}
when VS_LISTENER_BIND{
--when a VS tries to bind.
debug(" ======== VS_LISTENER_BIND ========\n");
for k,v in pairs(tcp_message) do
t = {};
t["op"] = "get"
t["message"]=v
if TCP:sockopt(t) then
debug("%s value is %d\n",v, TCP:sockopt(t));
else
debug("get %s status     %s\n",v,TCP:sockopt(t));
end
end
debug("        ==== set ==== \n");
for k,v in pairs(setIntMsg) do
s = {};
s["op"] = "set"; --or "set"
s["message"] = v
s["value"] = setIntValue[k]; -- for integer value
result = TCP:sockopt(s);
debug("setting %s to %s return %s\n",v,setIntValue[k], result);
end
debug("        ==== End set ==== \n");
for k,v in pairs(tcp_message) do
t = {};
t["op"] = "get"
t["message"]=v
if TCP:sockopt(t) then
debug("%s value is %d\n",v, TCP:sockopt(t));
else
debug("get %s status     %s\n",v,TCP:sockopt(t));
end
end
}
when HTTP_RESPONSE {
debug(" ======== HTTP_RESPONSE ========\n");
t={}
t["size"] = 100;
HTTP:collect(t)
debug("        ==== set ==== \n");
for k,v in pairs(setIntMsg) do
s = {};
s["op"] = "set"; --or "set"
s["message"] = v
s["value"] = setIntValue[k]; -- for integer value
result = TCP:sockopt(s);
debug("setting %s to %s return %s\n",v,setIntValue[k], result);
end
debug("        ==== End set ==== \n");
for k,v in pairs(tcp_message) do
t = {};
t["op"] = "get"
t["message"]=v
if TCP:sockopt(t) then
debug("%s value is %d\n",v, TCP:sockopt(t));
else
debug("get %s status     %s\n",v,TCP:sockopt(t));
end
end
}
when HTTP_DATA_RESPONSE {
debug(" ======== HTTP_DATA_RESPONSE ========\n");
debug("        ==== set ==== \n");
for k,v in pairs(setIntMsg) do
s = {};
s["op"] = "set"; --or "set"
s["message"] = v
s["value"] = setIntValue[k]; -- for integer value
result = TCP:sockopt(s);
debug("setting %s to %s return %s\n",v,setIntValue[k], result);
end
debug("        ==== End set ==== \n");
for k,v in pairs(tcp_message) do
t = {};
t["op"] = "get"
t["message"]=v
if TCP:sockopt(t) then
debug("%s value is %d\n",v, TCP:sockopt(t));
else
debug("get %s status     %s\n",v,TCP:sockopt(t));
end
end
}

FortiADC version: introduced in V5.0, updated in V7.4.3

Used in events:

  • In client-side events, including TCP_BIND, TCP_ACCEPTED, HTTP_REQUEST, HTTP_DATA_REQUEST

  • In server-side events, including HTTP_RESPONSE, HTTP_DATA_RESPONSE, BEFORE_CONNECT, SERVER_CONNECTED.

TCP:after_timer_set()

Allows the user to create and schedule a timer with a callback function and timeout value. This allows you to create multiple timers each with a unique callback function name. Periodic timers will be executed periodically until the associated session is closed or the after_timer is closed.

Returns Boolean true if successful, otherwise, returns Boolean false.

Syntax

TCP:after_timer_set (timer_cb_name, timeout, periodic);

Arguments
Name Description

timer_cb_name

A string of the callback function name. This is also the unique identification of a timer. This parameter is required.

timeout

An integer as the timeout value in milliseconds. This parameter is required.

periodic

A Boolean to indicate whether this timer is periodic. This parameter is required.

Example
when TCP_ACCEPTED {
    debug("[%s]------> TCP accepted begin:\n",ctime());
	local_count = 10
	cip = IP:client_addr();
	debug("[%s]------> client IP %s\n", ctime(),cip);
	cport = IP:client_port();
	debug("[%s]------> client Port %s\n", ctime(),cport);
	debug("[%s]------> local_count= %d\n", ctime(),local_count);
	debug("[%s]------> After function called here.\n",ctime());
 
	AFTER_TIMER_NAME = function ()
		debug("[%s]=======> After function call begin:\n",ctime())
		cport = IP:client_port();
		debug("[%s]=======> client Port %s\n",ctime(),cport);
		debug("[%s]=======> After function call end.\n",ctime())
	end
 
	TCP:after_timer_set("AFTER_TIMER_NAME", 5000, true);
}

When the client successfully creates a TCP connection, the script will be executed. The function will be executed every 5 seconds (5000 milliseconds) and print out the text.

FortiADC console debug output:

[Thu Jan 11 16:30:50 2024]------> TCP accepted begin:
[Thu Jan 11 16:30:50 2024]------> client IP 10.1.0.161
[Thu Jan 11 16:30:50 2024]------> client Port 37818
[Thu Jan 11 16:30:50 2024]------> local_count= 10
[Thu Jan 11 16:30:50 2024]------> After function called here.
[Thu Jan 11 16:30:55 2024]=======> After function call begin:
[Thu Jan 11 16:30:55 2024]=======> client Port 37818
[Thu Jan 11 16:30:55 2024]=======> After function call end.
[Thu Jan 11 16:31:00 2024]=======> After function call begin:
[Thu Jan 11 16:31:00 2024]=======> client Port 37818
[Thu Jan 11 16:31:00 2024]=======> After function call end.

FortiADC version: V7.4.1

Used in events:

  • HTTP events: HTTP_REQUEST / HTTP_RESPONSE / HTTP_DATA_REQUEST / HTTP_DATA_RESPONSE

  • TCP events: TCP_ACCEPTED / SERVER_CONNECTED / SERVER_BEFORE_CONNECT

TCP:after_timer_cancel()

Allows the user to cancel a scheduled timer. This function can only cancel a timer before it is triggered if it is not periodic.

Returns Boolean true if successful, otherwise, returns Boolean false.

Syntax

TCP:after_timer_cancel (timer_cb_name);

Arguments
Name Description

timer_cb_name

A string to indicate the name of the timer to be canceled. This parameter is required.

Example
when TCP_ACCEPTED {	
	AFTER_TIMER_NAME = function ()		
	debug("[%s]====>After function call begin:\n",ctime());
	debug("[%s]====>After function call end.\n",ctime());
end
TCP:after_timer_set("AFTER_TIMER_NAME", 1000, true);
}
when HTTP_REQUEST{
    debug("[%s]------> Events: HTTP_REQUEST begin:\n", ctime());
    TCP:after_timer_cancel("AFTER_TIMER_NAME");
}

When the client successfully creates a TCP connection, the script will be executed. When the HTTP is requested, the AFTER_TIMER_NAME will be stopped.

FortiADC console debug output:

[Thu Oct  5 13:37:51 2023]====>After function call begin:
[Thu Oct  5 13:37:51 2023]====>After function call end.
[Thu Oct  5 13:37:52 2023]====>After function call begin:
[Thu Oct  5 13:37:52 2023]====>After function call end.
[Thu Oct  5 13:37:53 2023]------> Events: HTTP_REQUEST begin:

FortiADC version: V7.4.1

Used in events:

  • HTTP events: HTTP_REQUEST / HTTP_RESPONSE / HTTP_DATA_REQUEST / HTTP_DATA_RESPONSE

  • TCP events: TCP_ACCEPTED / SERVER_CONNECTED / SERVER_BEFORE_CONNECT

TCP:after_timer_get()

Allows the user to get the information about the scheduled timers.

When successful, returns a string for one timer, a table of strings for multiple timers. For example, the returned string “'AFTER_TIMER_NAME':5000:periodic” shows the timer name, expiration in milliseconds and if it is periodic.

Returns nil for all failures.

Syntax

TCP:after_timer_get ([timer_cb_name]);

Arguments
Name Description

timer_cb_name

A string to indicate the name of the timer.

This parameter is optional. If this parameter is empty, then the function will get the information for all existing timers.

Example
when TCP_ACCEPTED {	
	AFTER_TIMER_NAME = function ()		
	debug("[%s]====>After function call begin:\n",ctime());
	debug("[%s]====>After function call end.\n",ctime());
end

TCP:after_timer_set("AFTER_TIMER_NAME", 1000, true);
ret = TCP:after_timer_get("AFTER_TIMER_NAME");	   
debug("after_timer_get success: %s\n", ret);
}

When the client successfully creates a TCP connection, the script will be executed. This function gets the after_timer information and prints it out on the first line.

FortiADC console debug output:

after_timer_get success: 'AFTER_TIMER_NAME':1000:periodic
[Thu Oct  5 12:36:34 2023]====>After function call begin:
[Thu Oct  5 12:36:34 2023]====>After function call end.
[Thu Oct  5 12:36:35 2023]====>After function call begin:
[Thu Oct  5 12:36:35 2023]====>After function call end.

FortiADC version: V7.4.1

Used in events:

  • HTTP events: HTTP_REQUEST / HTTP_RESPONSE / HTTP_DATA_REQUEST / HTTP_DATA_RESPONSE

  • TCP events: TCP_ACCEPTED / SERVER_CONNECTED / SERVER_BEFORE_CONNECT

TCP:close()

Allows the user to close the TCP connection immediately. Once an associated session is closed, all the after_timers will be deleted.

Returns Boolean true if successful, otherwise, returns Boolean false.

Syntax

TCP:close();

Arguments

N/A

Example
when TCP_ACCEPTED {	
	AFTER_TIMER_NAME = function ()		
	debug("[%s]====>After function call begin:\n",ctime());
	debug("[%s]====>After function call end.\n",ctime());
end

TCP:after_timer_set("AFTER_TIMER_NAME", 1000, true);
}
when HTTP_REQUEST{
    debug("[%s]------> Events: HTTP_REQUEST begin:\n", ctime());
    TCP:close();
}

When the client successfully creates a TCP connection, the script will be executed. When the HTTP is requested, the TCP connection will be closed.

Client side:

[root@Client1 ~]# curl http://10.1.0.15 -v
*   Trying 10.1.0.15:80...
* Connected to 10.1.0.15 (10.1.0.15) port 80 (#0)
> GET / HTTP/1.1
> Host: 10.1.0.15
> User-Agent: curl/8.0.1
> Accept: */*
> 
* Empty reply from server
* Closing connection 0
curl: (52) Empty reply from server

FortiADC version: V7.4.1

Used in events:

  • HTTP events: HTTP_REQUEST / HTTP_RESPONSE / HTTP_DATA_REQUEST / HTTP_DATA_RESPONSE

  • TCP events: TCP_ACCEPTED / SERVER_CONNECTED / SERVER_BEFORE_CONNECT

  • CLIENTSSL_HANDSHAKE

TCP commands

TCP commands contains functions to obtain and manipulate information related to the TCP layer, such as sockopt:

TCP:reject() — Allows the user to reject a TCP connection from a client.

TCP:set_snat_ip(str) — Allows the user to set the backend TCP connection’s source address and port.

TCP:clear_snat_ip() — Allows the user to clear any IP that was set using the set_snat_ip() command.

TCP:sockopt() — Can set or get various socket/IP/TCP operations, such as buffer size, timeout, MSS, etc. For client-side events, this command applies to the client-side socket; for server-side events, it applies to server-side socket.

TCP:after_timer_set() — Allows the user to create and schedule a timer with a callback function and timeout value. This allows you to create multiple timers each with a unique callback function name.

TCP:after_timer_cancel() — Allows the user to cancel a scheduled timer. This function can only cancel a timer before it is triggered if it is not periodic.

TCP:after_timer_get() — Allows the user to get the information about the scheduled timers.

TCP:close() — Allows the user to close the TCP connection immediately.

TCP:reject()

Allows the user to reject a TCP connection from a client.

Syntax

TCP:reject();

Arguments

N/A

Example
when TCP_ACCEPTED {
--check if the st is true or false;
If st then
TCP:reject();
end
}

FortiADC version: V5.0

Used in events: TCP_ACCEPTED

TCP:set_snat_ip(str)

Allows the user to set the backend TCP connection’s source address and port.

Syntax

TCP:set_snat_ip(str);

Note: To use the set_snat_ip() command, you must ensure the SOURCE ADDRESS flag is selected in the HTTP or HTTPS profile type.

Arguments
Name Description

str

A string which specifies the ip address.

Example
when TCP_ACCEPTED{
addr_group = “172.24.172.60/24”
client_ip = IP:client_addr()
matched = cmp_addr(client_ip, addr_group)
if matched then
if TCP:set_snat_ip(“10.106.3.124”) then
debug(“set SNAT ip to 10.106.3.124\n”)
end
end
}

Note: The VS must have the client address enabled in the profile, as shown in the example below.

config load-balance profile

edit "http"

set type http

set client-address enable

next

end

FortiADC version: V5.2

Used in events: TCP_ACCEPTED / HTTP_REQUEST / HTTP_DATA_REQUEST / CLIENTSSL_HANDSHAKE

TCP:clear_snat_ip()

Allows the user to clear any IP that was set using the set_snat_ip() command.

Syntax

TCP:clear_snat_ip();

Arguments

N/A

Example
when HTTP_REQUEST {
if TCP:clear_snat_ip() then
debug(“clear SNAT ip!\n”)
}

FortiADC version: V5.0

Used in events: TCP_ACCEPTED / HTTP_REQUEST / HTTP_DATA_REQUEST / CLIENTSSL_HANDSHAKE

TCP:sockopt()

Can set or get various socket/IP/TCP operations, such as buffer size, timeout, MSS, etc. For client-side events, this command applies to the client-side socket; for server-side events, it applies to server-side socket.

Note: In FortiADC version 7.4.3, the TCP:sockopt() functionality has been extended with the added new "type" parameter that allows FortiADC to read the customized TCP option. However, the "type" parameter currently only supports the GET operations.

Syntax

TCP:sockopt(table_parameter);

Arguments
Name Description

table_parameter

A Lua table which specifies the event and operation, variable:

t = {}

t["op"] = "set";

t["message"] = "maxseg";

t["value"] = 1240;

ret = TCP:sockopt(t);

OR

t = {}

t["op"] = "get";

t["type"] = 28;

ret = TCP:sockopt(t);

  • "op" — the action which can be either GET or SET. All options support both GET and SET operations except for "type" that only supports GET.

  • "message" — all options are passed via "message" except for "type".

  • "value" — a value is required for SET operations.

  • "type" — sets the custom TCP option type. This is newly added in FortiADC version 7.4.3.

Option(s) that support GET and SET operations:

  • "snd_buf"

  • "rcv_buf"

  • "so_type"

  • "so_priority"

  • "ip_ttl"

  • "fastopen"

  • "maxseg"

  • "so_mark"

  • "tos"

  • "ip_mtu"

  • "tcp_nodelay"

  • "tcp_cork"

  • "tcp_quickack"

  • "keepalive"

  • "ip_reputation"

  • "ipv6_v6only"

  • "linger"

  • "snd_timeo"

  • "rcv_timeo"

Option(s) that only support GET operations:

  • "type"

Examples

The following examples and notes only apply to the "type" parameter that was introduced in V7.4.3:

when HTTP_REQUEST {
	debug("============begin scripting.\n")
	
	clientip = nil
	t = {}
	t["op"] = "get"
	-- Set the custom TCP option type
	t["type"] = 28
	ret = TCP:sockopt(t)
	if ret and (string.len(ret)>=4) then
		debug("------> TCP get sockopt(%d): (returned %d bytes) successfully.\n", t["type"], string.len(ret));
		print_byte_array(ret)
		clientip = binStrToIpAddress(ret)
		debug("clientip = %s\n", clientip)
	else
		debug("------> TCP get sockopt(%d) failed.\n", t["type"])
	end

	if clientip then
		res = HTTP:header_insert("X-Forwarded-For", clientip)
		if res then
			debug("------> Header inserted successfully.\n")
		else
			debug("------> Header failed to insert.\n")
		end
	end
	
	debug("============end scripting.\n")
}

function binStrToIpAddress(binStr)
    return  tostring(string.byte(binStr,1)) .. "." .. tostring(string.byte(binStr,2)) ..
        	"." .. tostring(string.byte(binStr,3)) .. "." .. tostring(string.byte(binStr,4))
end

function print_byte_array(s)
  for i=1, string.len(s) do
     debug("0x%x.", string.byte(s,i))
  end
  debug("\n")
end

Notes:

For TCP options including Kind 28 type packet, only the first 4 bytes will be read.

For example:

Sent:

Kind: 28
Length: …
192,168,1,100,192.168,1,200,192,168,1,2

FortiADC reads:

=========begin scripting.        
clientip = 192.168.1.100

When the data sent is "abcd..." instead of regular numbers, decimals (ASCII code) 97,98,99,100 will be displayed.

For example:

Sent:

Kind: 28
Length: …
abcdef…

FortiADC reads:

------> TCP get sockopt(28): (returned 4 bytes) successfully.
0x61.0x62.0x63.0x64.
clientip = 97.98.99.100

If TCP options only contain two packets with Kind 28, only the first one will be read.

For example:

Sent:

Kind: 28
Length: 6
192,168,1,100
Kind: 28
Length: 6
192,168,1,100

FortiADC reads:

=========begin scripting.        
clientip = 192.168.1.100

The following examples apply to the TCP:sockopt() as introduced in V5.0:

when RULE_INIT {
debug(" ======== RULE_INIT ========\n");
-- access to https://notes.shichao.io/unp/ch7/ for more details.
tcp_message = {};
tcp_message[1]="snd_buf"; --int
tcp_message[2]="rcv_buf"; --int
setIntMsg = {};
setIntMsg[1]="snd_buf"; --int
setIntMsg[2]="rcv_buf"; --int
setIntValue = {};
setIntValue[1] = 111222;
setIntValue[2] = 111222;
}
when VS_LISTENER_BIND{
--when a VS tries to bind.
debug(" ======== VS_LISTENER_BIND ========\n");
for k,v in pairs(tcp_message) do
t = {};
t["op"] = "get"
t["message"]=v
if TCP:sockopt(t) then
debug("%s value is %d\n",v, TCP:sockopt(t));
else
debug("get %s status     %s\n",v,TCP:sockopt(t));
end
end
debug("        ==== set ==== \n");
for k,v in pairs(setIntMsg) do
s = {};
s["op"] = "set"; --or "set"
s["message"] = v
s["value"] = setIntValue[k]; -- for integer value
result = TCP:sockopt(s);
debug("setting %s to %s return %s\n",v,setIntValue[k], result);
end
debug("        ==== End set ==== \n");
for k,v in pairs(tcp_message) do
t = {};
t["op"] = "get"
t["message"]=v
if TCP:sockopt(t) then
debug("%s value is %d\n",v, TCP:sockopt(t));
else
debug("get %s status     %s\n",v,TCP:sockopt(t));
end
end
}
when HTTP_RESPONSE {
debug(" ======== HTTP_RESPONSE ========\n");
t={}
t["size"] = 100;
HTTP:collect(t)
debug("        ==== set ==== \n");
for k,v in pairs(setIntMsg) do
s = {};
s["op"] = "set"; --or "set"
s["message"] = v
s["value"] = setIntValue[k]; -- for integer value
result = TCP:sockopt(s);
debug("setting %s to %s return %s\n",v,setIntValue[k], result);
end
debug("        ==== End set ==== \n");
for k,v in pairs(tcp_message) do
t = {};
t["op"] = "get"
t["message"]=v
if TCP:sockopt(t) then
debug("%s value is %d\n",v, TCP:sockopt(t));
else
debug("get %s status     %s\n",v,TCP:sockopt(t));
end
end
}
when HTTP_DATA_RESPONSE {
debug(" ======== HTTP_DATA_RESPONSE ========\n");
debug("        ==== set ==== \n");
for k,v in pairs(setIntMsg) do
s = {};
s["op"] = "set"; --or "set"
s["message"] = v
s["value"] = setIntValue[k]; -- for integer value
result = TCP:sockopt(s);
debug("setting %s to %s return %s\n",v,setIntValue[k], result);
end
debug("        ==== End set ==== \n");
for k,v in pairs(tcp_message) do
t = {};
t["op"] = "get"
t["message"]=v
if TCP:sockopt(t) then
debug("%s value is %d\n",v, TCP:sockopt(t));
else
debug("get %s status     %s\n",v,TCP:sockopt(t));
end
end
}

FortiADC version: introduced in V5.0, updated in V7.4.3

Used in events:

  • In client-side events, including TCP_BIND, TCP_ACCEPTED, HTTP_REQUEST, HTTP_DATA_REQUEST

  • In server-side events, including HTTP_RESPONSE, HTTP_DATA_RESPONSE, BEFORE_CONNECT, SERVER_CONNECTED.

TCP:after_timer_set()

Allows the user to create and schedule a timer with a callback function and timeout value. This allows you to create multiple timers each with a unique callback function name. Periodic timers will be executed periodically until the associated session is closed or the after_timer is closed.

Returns Boolean true if successful, otherwise, returns Boolean false.

Syntax

TCP:after_timer_set (timer_cb_name, timeout, periodic);

Arguments
Name Description

timer_cb_name

A string of the callback function name. This is also the unique identification of a timer. This parameter is required.

timeout

An integer as the timeout value in milliseconds. This parameter is required.

periodic

A Boolean to indicate whether this timer is periodic. This parameter is required.

Example
when TCP_ACCEPTED {
    debug("[%s]------> TCP accepted begin:\n",ctime());
	local_count = 10
	cip = IP:client_addr();
	debug("[%s]------> client IP %s\n", ctime(),cip);
	cport = IP:client_port();
	debug("[%s]------> client Port %s\n", ctime(),cport);
	debug("[%s]------> local_count= %d\n", ctime(),local_count);
	debug("[%s]------> After function called here.\n",ctime());
 
	AFTER_TIMER_NAME = function ()
		debug("[%s]=======> After function call begin:\n",ctime())
		cport = IP:client_port();
		debug("[%s]=======> client Port %s\n",ctime(),cport);
		debug("[%s]=======> After function call end.\n",ctime())
	end
 
	TCP:after_timer_set("AFTER_TIMER_NAME", 5000, true);
}

When the client successfully creates a TCP connection, the script will be executed. The function will be executed every 5 seconds (5000 milliseconds) and print out the text.

FortiADC console debug output:

[Thu Jan 11 16:30:50 2024]------> TCP accepted begin:
[Thu Jan 11 16:30:50 2024]------> client IP 10.1.0.161
[Thu Jan 11 16:30:50 2024]------> client Port 37818
[Thu Jan 11 16:30:50 2024]------> local_count= 10
[Thu Jan 11 16:30:50 2024]------> After function called here.
[Thu Jan 11 16:30:55 2024]=======> After function call begin:
[Thu Jan 11 16:30:55 2024]=======> client Port 37818
[Thu Jan 11 16:30:55 2024]=======> After function call end.
[Thu Jan 11 16:31:00 2024]=======> After function call begin:
[Thu Jan 11 16:31:00 2024]=======> client Port 37818
[Thu Jan 11 16:31:00 2024]=======> After function call end.

FortiADC version: V7.4.1

Used in events:

  • HTTP events: HTTP_REQUEST / HTTP_RESPONSE / HTTP_DATA_REQUEST / HTTP_DATA_RESPONSE

  • TCP events: TCP_ACCEPTED / SERVER_CONNECTED / SERVER_BEFORE_CONNECT

TCP:after_timer_cancel()

Allows the user to cancel a scheduled timer. This function can only cancel a timer before it is triggered if it is not periodic.

Returns Boolean true if successful, otherwise, returns Boolean false.

Syntax

TCP:after_timer_cancel (timer_cb_name);

Arguments
Name Description

timer_cb_name

A string to indicate the name of the timer to be canceled. This parameter is required.

Example
when TCP_ACCEPTED {	
	AFTER_TIMER_NAME = function ()		
	debug("[%s]====>After function call begin:\n",ctime());
	debug("[%s]====>After function call end.\n",ctime());
end
TCP:after_timer_set("AFTER_TIMER_NAME", 1000, true);
}
when HTTP_REQUEST{
    debug("[%s]------> Events: HTTP_REQUEST begin:\n", ctime());
    TCP:after_timer_cancel("AFTER_TIMER_NAME");
}

When the client successfully creates a TCP connection, the script will be executed. When the HTTP is requested, the AFTER_TIMER_NAME will be stopped.

FortiADC console debug output:

[Thu Oct  5 13:37:51 2023]====>After function call begin:
[Thu Oct  5 13:37:51 2023]====>After function call end.
[Thu Oct  5 13:37:52 2023]====>After function call begin:
[Thu Oct  5 13:37:52 2023]====>After function call end.
[Thu Oct  5 13:37:53 2023]------> Events: HTTP_REQUEST begin:

FortiADC version: V7.4.1

Used in events:

  • HTTP events: HTTP_REQUEST / HTTP_RESPONSE / HTTP_DATA_REQUEST / HTTP_DATA_RESPONSE

  • TCP events: TCP_ACCEPTED / SERVER_CONNECTED / SERVER_BEFORE_CONNECT

TCP:after_timer_get()

Allows the user to get the information about the scheduled timers.

When successful, returns a string for one timer, a table of strings for multiple timers. For example, the returned string “'AFTER_TIMER_NAME':5000:periodic” shows the timer name, expiration in milliseconds and if it is periodic.

Returns nil for all failures.

Syntax

TCP:after_timer_get ([timer_cb_name]);

Arguments
Name Description

timer_cb_name

A string to indicate the name of the timer.

This parameter is optional. If this parameter is empty, then the function will get the information for all existing timers.

Example
when TCP_ACCEPTED {	
	AFTER_TIMER_NAME = function ()		
	debug("[%s]====>After function call begin:\n",ctime());
	debug("[%s]====>After function call end.\n",ctime());
end

TCP:after_timer_set("AFTER_TIMER_NAME", 1000, true);
ret = TCP:after_timer_get("AFTER_TIMER_NAME");	   
debug("after_timer_get success: %s\n", ret);
}

When the client successfully creates a TCP connection, the script will be executed. This function gets the after_timer information and prints it out on the first line.

FortiADC console debug output:

after_timer_get success: 'AFTER_TIMER_NAME':1000:periodic
[Thu Oct  5 12:36:34 2023]====>After function call begin:
[Thu Oct  5 12:36:34 2023]====>After function call end.
[Thu Oct  5 12:36:35 2023]====>After function call begin:
[Thu Oct  5 12:36:35 2023]====>After function call end.

FortiADC version: V7.4.1

Used in events:

  • HTTP events: HTTP_REQUEST / HTTP_RESPONSE / HTTP_DATA_REQUEST / HTTP_DATA_RESPONSE

  • TCP events: TCP_ACCEPTED / SERVER_CONNECTED / SERVER_BEFORE_CONNECT

TCP:close()

Allows the user to close the TCP connection immediately. Once an associated session is closed, all the after_timers will be deleted.

Returns Boolean true if successful, otherwise, returns Boolean false.

Syntax

TCP:close();

Arguments

N/A

Example
when TCP_ACCEPTED {	
	AFTER_TIMER_NAME = function ()		
	debug("[%s]====>After function call begin:\n",ctime());
	debug("[%s]====>After function call end.\n",ctime());
end

TCP:after_timer_set("AFTER_TIMER_NAME", 1000, true);
}
when HTTP_REQUEST{
    debug("[%s]------> Events: HTTP_REQUEST begin:\n", ctime());
    TCP:close();
}

When the client successfully creates a TCP connection, the script will be executed. When the HTTP is requested, the TCP connection will be closed.

Client side:

[root@Client1 ~]# curl http://10.1.0.15 -v
*   Trying 10.1.0.15:80...
* Connected to 10.1.0.15 (10.1.0.15) port 80 (#0)
> GET / HTTP/1.1
> Host: 10.1.0.15
> User-Agent: curl/8.0.1
> Accept: */*
> 
* Empty reply from server
* Closing connection 0
curl: (52) Empty reply from server

FortiADC version: V7.4.1

Used in events:

  • HTTP events: HTTP_REQUEST / HTTP_RESPONSE / HTTP_DATA_REQUEST / HTTP_DATA_RESPONSE

  • TCP events: TCP_ACCEPTED / SERVER_CONNECTED / SERVER_BEFORE_CONNECT

  • CLIENTSSL_HANDSHAKE