Fortinet white logo
Fortinet white logo

Script Reference Guide

TCP:sockopt(t)

TCP:sockopt(t)

The TCP:sockopt() function allows you to set or retrieve various socket, IP, and TCP options, such as buffer size, timeout, and Maximum Segment Size (MSS).

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(t)

Arguments

Name Description

t

A Lua table specifying the operation and option.

The options and required parameters for the Lua table (t) depend on whether you are accessing Standard Options (using "message") or the Custom TCP Option (using "type").

1: Standard Options (Using "message")

Parameter Key

Operation

Required Value

Example Notes

op

"get" or "set"

"get" or "set"

"set"

Specifies the action.

message

Both GET/SET

Option Name

"maxseg"

"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"

value

Only SET

New Option Value

1240

Required only for the "set" operation.

2: Custom TCP Option (Using "type")

Parameter Key

Operation

Required Value

Example Notes

op

Only GET

"get"

"get"

Only the GET operation is supported.

type

Only GET

Option Number

28

Specifies the custom TCP option Type. Do not use "message".

Events

Applicable in the following events:

  • HTTP_DATA_REQUEST
  • HTTP_DATA_RESPONSE
  • HTTP_REQUEST
  • HTTP_RESPONSE
  • SERVER_BEFORE_CONNECT
  • SERVER_CONNECTED
  • TCP_ACCEPTED
  • VS_LISTENER_BIND

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(t)

TCP:sockopt(t)

The TCP:sockopt() function allows you to set or retrieve various socket, IP, and TCP options, such as buffer size, timeout, and Maximum Segment Size (MSS).

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(t)

Arguments

Name Description

t

A Lua table specifying the operation and option.

The options and required parameters for the Lua table (t) depend on whether you are accessing Standard Options (using "message") or the Custom TCP Option (using "type").

1: Standard Options (Using "message")

Parameter Key

Operation

Required Value

Example Notes

op

"get" or "set"

"get" or "set"

"set"

Specifies the action.

message

Both GET/SET

Option Name

"maxseg"

"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"

value

Only SET

New Option Value

1240

Required only for the "set" operation.

2: Custom TCP Option (Using "type")

Parameter Key

Operation

Required Value

Example Notes

op

Only GET

"get"

"get"

Only the GET operation is supported.

type

Only GET

Option Number

28

Specifies the custom TCP option Type. Do not use "message".

Events

Applicable in the following events:

  • HTTP_DATA_REQUEST
  • HTTP_DATA_RESPONSE
  • HTTP_REQUEST
  • HTTP_RESPONSE
  • SERVER_BEFORE_CONNECT
  • SERVER_CONNECTED
  • TCP_ACCEPTED
  • VS_LISTENER_BIND

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.