This file describes falco
linter rules and how to fix it.
Syntax error on ACL definition.
Acl syntax is:
acl (?<acl_name>[a-zA-Z0-9_]+) {
(?<inverse>!?)"(?<ip_address>[0-9a-z\.:]+)"(/?)(?<cidr_mask>[0-9]+);
...
}
For example:
acl internal {
"10.0.0.1";
!"10.0.0.2";
"10.0.0.3"/32;
!"10.0.0.4"/32;
...
}
Note: ip_address
variable could specify ipv6 format like "2001:db8:ffff:ffff:ffff:ffff:ffff:ffff".
Fastly Document : https://developer.fastly.com/reference/vcl/declarations/acl/
Duplicate ACL declaration.
Problem:
acl internal {
...
}
acl internal { // Duplicated
...
}
Fix:
acl internal {
...
}
Syntax error on BACKEND definition.
Backend syntax is:
backend (?<backend_name>[a-zA-Z0-9_]+) {
// common property
.(?<property_name>[a-zA-Z0-9_]+) = (?<property_value>.+);
...
// probe object (for healthcheck)
.probe = {
.(?<property_name>[a-zA-Z0-9_]+) = (?<property_value>.+);
...
}
}
For example:
backend example_backend {
.host = "example.com";
.probe = {
.request = "GET / HTTP/1.1" "Host: example.com" "Connection: close";
}
}
Fastly Document: https://developer.fastly.com/reference/vcl/declarations/backend/
Duplicate BACKEND declaration.
Problem:
backend example {
...
}
backend example { // Duplicated
...
}
Fix:
backend example {
...
}
Backend is not found in director or req.backend
.
Problem:
sub vcl_recv {
...
set req.backend = F_example_backend_0; // F_example_backend_0 is not found
}
Fix:
backend F_example_backend_0 {
...
}
...
sub vcl_recv {
...
set req.backend = F_example_backend_0;
}
Misconfiguration for backend probe section.
The .initial
property should be less than .threshold
property.
Problem:
backend F_example_backend_0 {
...
.probe = {
.initial = 5;
.threshold = 2;
}
}
Fix:
backend F_example_backend_0 {
...
.probe = {
.initial = 5;
.threshold = 10;
}
}
Syntax error on DIRECTOR definition.
Director syntax is:
director (?<director_name>[a-zA-Z0-9_]+) (?<directory_type>random|fallback|hash|client|chash) {
// common property
.(?<property_name>[a-zA-Z0-9_]+) = (?<property_value>.+);
...
// backend object
{ .(?<property_name>[a-zA-Z0-9_]+) = (?<property_value>.+); ... }
...
}
For example:
director example_director client {
.quorum = "50%";
{ .backend= F_origin_0; .weight = 1; }
}
Fastly document: https://developer.fastly.com/reference/vcl/declarations/director/
Duplicate DIRECTOR declaration.
Problem:
director example fallback {
...
}
director example fallback { // Duplicated
...
}
Fix:
director example fallback {
...
}
Required property is not declared on random
director.
Fastly document: https://developer.fastly.com/reference/vcl/declarations/director/#random
Required property is not declared on fallback
director.
Fastly document: https://developer.fastly.com/reference/vcl/declarations/director/#fallback
Required property is not declared on hash
director.
Fastly document: https://developer.fastly.com/reference/vcl/declarations/director/#content
Required property is not declared on client
director.
Fastly document: https://developer.fastly.com/reference/vcl/declarations/director/#client
Required property is not declared on chash
director.
Fastly document: https://developer.fastly.com/reference/vcl/declarations/director/#consistent-hashing
Director must have one backend at least.
Problem:
director example client {
.quorum = "50%";
// Nothing to specify backend
}
Fix:
director example client {
.quorum = "50%";
{ .backend = F_origin_0; .weight = 1; }
}
Syntax error on TABLE declaration.
Table syntax is:
table (?<table_name>[a-zA-Z0-9_]+) (?<value_type>(STRING|INTEGER|BOOL|FLOAT|BACKEND|ACL|RTIME)?) {
"(?<property_name>.+)" = (?<property_value>.+),
...
}
For example:
table example_table {
"some_key": "value",
}
Note: value_type
is optional and default is STRING
.
Fastly document: https://developer.fastly.com/reference/vcl/declarations/table/
Invalid value_type
spefication on TABLE. value_type
is allowed to specify with STRING
, INTEGER
, BOOL
, FLOAT
, BACKEND
, ACL
and RTIME
.
Problem:
table example_table FOO { // unexpected value type of FOO
"some_key": "value",
...
}
Fix:
table example_table {
"some_key": "value",
...
}
Note: The COMMA of last table property can omit.
Fastly document: https://developer.fastly.com/reference/vcl/declarations/table/#type-variations
Table properties is limited under 1000 items.
Problem:
table example_table {
"some_key": "value",
...(1000 items) // limited under 1000 items
}
Fix:
table example_table {
"some_key": "value",
...(under 999 items)
}
Note: 1000 items as default, but you may increase this limitation by contacting to Fastly support.
Fastly document: https://developer.fastly.com/reference/vcl/declarations/table/#limitations
Duplicate TABLE declaration.
Problem:
table example {
...
}
table example { // Duplicated
...
}
Fix:
table example {
...
}
Syntax error on Subroutine declaration.
Subroutine syntax is:
sub (?<subroutine_name>[a-zA-Z0-9_]+) {
...statements
}
For example:
sub vcl_recv {
set req.backend = F_origin_0;
}
Fastly document: https://developer.fastly.com/reference/vcl/subroutines/
Fastly wants boilerplate macro on reserved subroutine.
Problem:
sub vcl_recv {
...statements
}
Fix:
sub vcl_recv {
#Fastly recv
set req.backend = F_origin_0;
}
Fastly document: https://developer.fastly.com/learning/vcl/using/#adding-vcl-to-your-service-configuration
Duplicate Subroutine declaration.
Problem:
sub check_password {
...
}
sub check_password { // Duplicated
...
}
Fix:
sub check_password {
...
}
A functional subroutine declaration has an invalid return type, or return type is specified for state-machine subroutine like vcl_recv
.
Problem:
sub functional_subroutine COMPLEX { // COMPLEX type is invalid
....
}
Fix:
sub functional_subroutine STRING {
....
}
Syntax error on penaltybox
declaration.
Declaration syntax is:
penaltybox (?<penaltybox_name>[a-zA-Z0-9_]+) {}
Fastly document: https://developer.fastly.com/reference/vcl/declarations/penaltybox/
The penaltybox
declaration block content must be empty.
Declaration syntax is:
penaltybox (?<penaltybox_name>[a-zA-Z0-9_]+) {
// Must be empty
}
Fastly document: https://developer.fastly.com/reference/vcl/declarations/penaltybox/
The penaltybox
declaration is duplicated.
Problem:
penaltybox foo {}
penaltybox foo {}
Fix:
penaltybox foo {}
Syntax error on ratecounter
declaration.
Declaration syntax is:
ratecounter (?<ratecounter_name>[a-zA-Z0-9_]+) {}
Fastly document: https://developer.fastly.com/reference/vcl/declarations/ratecounter/
The ratecounter
declaration block content must be empty.
Declaration syntax is:
ratecounter (?<ratecounter_name>[a-zA-Z0-9_]+) {
// Must be empty
}
Fastly document: https://developer.fastly.com/reference/vcl/declarations/ratecounter/
The ratecounter
declaration is duplicated.
Problem:
ratecounter foo {}
ratecounter foo {}
Fix:
ratecounter foo {}
Syntax error on declare
statement.
Statement syntax is:
declare local (?<variable_name>var\.[a-zA-Z0-9_]+) (?<variable_type>(STRING|INTEGER|BOOL|FLOAT|BACKEND|ACL|RTIME)>;
For example:
declare local var.exampleString STRING;
Fastly document: https://developer.fastly.com/reference/vcl/variables/#user-defined-variables
declare variable type is invalid.
Problem:
declare local var.Example FOO; // variable type is invalid
Fix:
declare local var.Example STRING;
Fastly document: https://developer.fastly.com/reference/vcl/variables/#user-defined-variables
Duplicate declare variable statement.
Problem:
declare local var.Example STRING;
declare local var.Example INTEGER; // var.Example is already declared.
Fix:
declare local var.Example STRING;
Syntax error on set
statement.
set syntax is:
set (?<identifier>[a-zA-Z0-9\._-:]+) (?<operator>(\+|\*|\/|%|\||&|\^|<<|>>|rol|ror|&&|\|\|)?=) (?<expression>.+);
For example:
set req.http.X-Forwarded-For = client.ip;
set req.http.Cookie:session = "session";
Fastly document: https://developer.fastly.com/reference/vcl/statements/set/
In VCL, bang operator could not use in set/add statement expression, and only string concatenation expression could use.
declare local var.Foo BOOL;
declare local var.Bar STRING;
set var.Bar = "foo" "bar"; // -> valid, string concatenation operator can use
set var.Foo = !false; // -> invalid, could not use in set statement
set var.Foo = req.http.Host == "example.com"; // -> invalid, equal operator could not use in set statement
set var.Foo = (req.http.Host == "example.com"); // -> valid, equal operator cau use inside grouped expression set statement
Fastly document: https://developer.fastly.com/reference/vcl/operators/#assignment-operators
Syntax error on unset
statement.
unset syntax is:
unset (?<identifier>[a-zA-Z0-9\._-:]+);
For example:
unset req.http.X-Forwarded-For;
Fastly document: https://developer.fastly.com/reference/vcl/statements/unset/
Syntax error on remove
statement.
remove syntax is:
remove (?<identifier>[a-zA-Z0-9\._-:]+);
For example:
remove req.http.X-Forwarded-For;
Note: remove
is just alias for unset
.
Faslty document: https://developer.fastly.com/reference/vcl/statements/remove/
Conditional operator is using for unexpected type.
Problem:
if (beresp.status ~ "200") { // beresp.status is INTEGER, regex operator cannot use for INTEGER type.
...
}
Fix:
if (beresp.status == 200) {
...
}
Faslty document: https://developer.fastly.com/reference/vcl/operators/#conditional-operators
Calling restart
on invalid scope, the restart
statement enables in RECV
, HIT
, FETCH
, ERROR
and DELIVER
scope.
Problem:
sub vcl_hash {
#Fastly hash
restart; // restart cannot use in HASH scope.
}
Fastly document: https://developer.fastly.com/reference/vcl/statements/restart
Syntax error on add
statement.
add syntax is:
add (?<identifier>[a-zA-Z0-9\._-:]+) = (?<expression>.+);
For example:
add req.http.Cookie = "additional_cookie;
}
Note: may only =
operator can use in add
statement operator.
Fastly document: https://developer.fastly.com/reference/vcl/statements/add/
Syntax error on call
statement.
call syntax is:
call (?<identifier>[a-zA-Z0-9\._]+);
For example:
call check_password;
Fastly document: https://developer.fastly.com/reference/vcl/statements/call/
Calling subroutine must be defined before this statement.
Problem:
sub vcl_recv {
call auth; // calling "auth" subroutine before it is defined
}
sub auth {
...
}
Fix:
sub auth {
...
}
sub vcl_recv {
call auth;
}
Calling error
on invalid scope, the error
statement could use in RECV
, HIT
, MISS
, PASS
and FETCH
.
Problem:
sub vcl_deliver {
#Fastly deliver
error 699; // error cannot use in DELIVER scope.
}
Fastly document: https://developer.fastly.com/reference/vcl/statements/error/
Faslty recommends error statement code should use in range of 600-699.
Problem:
sub vcl_recv {
#Fastly recv
...
error 799; // custom error code should use in range of 600-699
}
Fix:
sub vcl_recv {
#Fastly recv
...
error 699; // custom error code should use in range of 600-699
}
Fastly document: https://developer.fastly.com/reference/vcl/statements/error/#best-practices-for-using-status-codes-for-errors
Calling synthetic
on invalid scope, the synthetic
statement could use only in ERROR
.
Problem:
sub vcl_deliver {
#Fastly deliver
synthetic {"some of error"} // synthetic cannot use in DELIVER scope.
}
Fastly document: https://developer.fastly.com/reference/vcl/statements/synthetic/
Calling synthetic.base64
on invalid scope, the synthetic.base64
statement could use only in ERROR
.
Problem:
sub vcl_deliver {
#Fastly deliver
synthetic.base64 {"some of error"} // synthetic.base64 cannot use in DELIVER scope.
}
Fastly document: https://developer.fastly.com/reference/vcl/statements/synthetic-base64/
if
condtion expression accepts STRING or BOOL (evaluate as truthy/falsy), but forbid to use literal.
For example:
if (req.http.Host) { ... } // -> valid, req.http.Host is STRING and used as identity
if ("foobar") { ... } // -> invalid, string literal in condition expression could not use
if (req.http.Host == "example.com") { ... } // -> valid, left expression is identity
if ("example.com" == req.http.Host) { ... } // -> invalid(!), left expression is string literal... messy X(
IP string is invalid.
Problem:
declare local var.LocalIP IP;
set var.LocalIP = std.ip("192.168.0.1", "192.168.0.256"); // Invalid IP
Calling function arguments count mismatch.
Problem:
declare local var.LocalIP IP;
set var.LocalIP = std.ip("192.168.0.1"); // std.ip function expects 2 arguemnts but supply 1 argument
Fix:
declare local var.LocalIP IP;
set var.LocalIP = std.ip("192.168.0.1", "192.168.0.2");
Calling function argument type mismatch.
Problem:
declare local var.lat FLOAT;
set var.lat = math.floor("2.2"); // math.floor expects 1st argument as FLOAT but STRING supplied
Fix:
declare local var.lat FLOAT;
set var.lat = math.floor(2.2);
Include target module not found.
Failed to load include target module.
Regex matched operator re.group.N
value will be overriden.
These variables could use if(else) block statement when condition has regex operator like ~
or !~
.
Note that group matched variable has potential of making bugs due to its spec:
- re.group.N variable scope is subroutine-global, does not have block scope
- matched value may override on second regex matching
For example:
declare local var.S STRING;
set var.S = "foo bar baz";
if (req.http.Host) {
if (var.S) {
if (var.S !~ "(foo)\s(bar)\s(baz)") { // make matched values first (1)
set req.http.First = "1";
}
set var.S = "hoge huga";
if (var.S ~ "(hoge)\s(huga)") { // override matched values (2)
set req.http.First = re.group.1;
}
}
set req.http.Third = re.group.2; // difficult to know which (1) or (2) matched result is used
}
if (req.http.Host) {
set req.http.Fourth = re.group.3; // difficult to know which (1) or (2) matched result is used or empty
}
A return
statement in state-machine subroutine like vcl_recv
must have the next state.
Problem:
sub vcl_recv {
...
return; // Must return with next state
}
Fix:
sub vcl_recv {
...
return (lookup);
}
Fastly document: https://developer.fastly.com/reference/vcl/subroutines#returning-a-state