Fortinet white logo
Fortinet white logo

Script Reference Guide

TCP:sockopt()

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"

Events

Applicable in the following 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.

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
}

Supported Version

FortiADC version 5.0.x and later. Updated in version 7.4.3.

TCP:sockopt()

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"

Events

Applicable in the following 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.

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
}

Supported Version

FortiADC version 5.0.x and later. Updated in version 7.4.3.