Skip to content

Commit c2fcbc0

Browse files
authored
Merge pull request #84 from nginxinc/NLB-4532-lua
NLB-4532: Add lua module
2 parents a1fb904 + 9475278 commit c2fcbc0

File tree

6 files changed

+452
-0
lines changed

6 files changed

+452
-0
lines changed

analyze.go

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2509,3 +2509,176 @@ func MatchAppProtectWAFv5(directive string) ([]uint, bool) {
25092509
masks, matched := appProtectWAFv5Directives[directive]
25102510
return masks, matched
25112511
}
2512+
2513+
// LuaDirectives is a list of directives that are used in the Lua module
2514+
// https://github.com/openresty/lua-nginx-module/tree/master?tab=readme-ov-file#directives
2515+
//
2516+
//nolint:gochecknoglobals
2517+
var LuaDirectives = map[string][]uint{
2518+
"lua_load_resty_core": {
2519+
ngxHTTPMainConf | ngxConfFlag,
2520+
},
2521+
"lua_capture_error_log": {
2522+
ngxHTTPMainConf | ngxConfTake1,
2523+
},
2524+
"lua_use_default_type": {
2525+
ngxHTTPMainConf | ngxHTTPSrvConf | ngxHTTPLocConf | ngxHTTPLifConf | ngxConfFlag,
2526+
},
2527+
"lua_malloc_trim": {
2528+
ngxHTTPMainConf | ngxConfTake1,
2529+
},
2530+
"lua_code_cache": {
2531+
ngxHTTPMainConf | ngxHTTPSrvConf | ngxHTTPLocConf | ngxHTTPLifConf | ngxConfFlag,
2532+
},
2533+
"lua_thread_cache_max_entries": {
2534+
ngxHTTPMainConf | ngxConfTake1,
2535+
},
2536+
"lua_regex_cache_max_entries": {
2537+
ngxHTTPMainConf | ngxConfTake1,
2538+
},
2539+
"lua_regex_match_limit": {
2540+
ngxHTTPMainConf | ngxConfTake1,
2541+
},
2542+
"lua_package_path": {
2543+
ngxHTTPMainConf | ngxConfTake1,
2544+
},
2545+
"lua_package_cpath": {
2546+
ngxHTTPMainConf | ngxConfTake1,
2547+
},
2548+
"init_by_lua_file": {
2549+
ngxHTTPMainConf | ngxConfTake1,
2550+
},
2551+
"init_worker_by_lua_file": {
2552+
ngxHTTPMainConf | ngxConfTake1,
2553+
},
2554+
"exit_worker_by_lua_file": {
2555+
ngxHTTPMainConf | ngxConfTake1,
2556+
},
2557+
"set_by_lua_file": {
2558+
ngxHTTPSrvConf | ngxHTTPSifConf | ngxHTTPLocConf | ngxHTTPLifConf | ngxConf2More,
2559+
},
2560+
"content_by_lua_file": {
2561+
ngxHTTPLocConf | ngxHTTPLifConf | ngxConfTake1,
2562+
},
2563+
"server_rewrite_by_lua_file": {
2564+
ngxHTTPMainConf | ngxHTTPSrvConf | ngxConfTake1,
2565+
},
2566+
"rewrite_by_lua_file": {
2567+
ngxHTTPMainConf | ngxHTTPSrvConf | ngxHTTPLocConf | ngxHTTPLifConf | ngxConfTake1,
2568+
},
2569+
"access_by_lua_file": {
2570+
ngxHTTPMainConf | ngxHTTPSrvConf | ngxHTTPLocConf | ngxHTTPLifConf | ngxConfTake1,
2571+
},
2572+
"header_filter_by_lua_file": {
2573+
ngxHTTPMainConf | ngxHTTPSrvConf | ngxHTTPLocConf | ngxHTTPLifConf | ngxConfTake1,
2574+
},
2575+
"body_filter_by_lua_file": {
2576+
ngxHTTPMainConf | ngxHTTPSrvConf | ngxHTTPLocConf | ngxHTTPLifConf | ngxConfTake1,
2577+
},
2578+
"log_by_lua_file": {
2579+
ngxHTTPMainConf | ngxHTTPSrvConf | ngxHTTPLocConf | ngxHTTPLifConf | ngxConfTake1,
2580+
},
2581+
"balancer_by_lua_file": {
2582+
ngxHTTPUpsConf | ngxConfTake1,
2583+
},
2584+
"lua_need_request_body": {
2585+
ngxHTTPMainConf | ngxHTTPSrvConf | ngxHTTPLocConf | ngxHTTPLifConf | ngxConfFlag,
2586+
},
2587+
"ssl_client_hello_by_lua_file": {
2588+
ngxHTTPMainConf | ngxHTTPSrvConf | ngxConfTake1,
2589+
},
2590+
"ssl_certificate_by_lua_file": {
2591+
ngxHTTPMainConf | ngxHTTPSrvConf | ngxConfTake1,
2592+
},
2593+
"ssl_session_fetch_by_lua_file": {
2594+
ngxHTTPMainConf | ngxConfTake1,
2595+
},
2596+
"ssl_session_store_by_lua_file": {
2597+
ngxHTTPMainConf | ngxConfTake1,
2598+
},
2599+
"lua_shared_dict": {
2600+
ngxHTTPMainConf | ngxConfTake2,
2601+
},
2602+
"lua_socket_connect_timeout": {
2603+
ngxHTTPMainConf | ngxHTTPSrvConf | ngxHTTPLocConf | ngxHTTPLifConf | ngxConfTake1,
2604+
},
2605+
"lua_socket_send_timeout": {
2606+
ngxHTTPMainConf | ngxHTTPSrvConf | ngxHTTPLocConf | ngxHTTPLifConf | ngxConfTake1,
2607+
},
2608+
"lua_socket_send_lowat": {
2609+
ngxHTTPMainConf | ngxHTTPSrvConf | ngxHTTPLocConf | ngxHTTPLifConf | ngxConfTake1,
2610+
},
2611+
"lua_socket_read_timeout": {
2612+
ngxHTTPMainConf | ngxHTTPSrvConf | ngxHTTPLocConf | ngxHTTPLifConf | ngxConfTake1,
2613+
},
2614+
"lua_socket_buffer_size": {
2615+
ngxHTTPMainConf | ngxHTTPSrvConf | ngxHTTPLocConf | ngxHTTPLifConf | ngxConfTake1,
2616+
},
2617+
"lua_socket_pool_size": {
2618+
ngxHTTPMainConf | ngxHTTPSrvConf | ngxHTTPLocConf | ngxHTTPLifConf | ngxConfTake1,
2619+
},
2620+
"lua_socket_keepalive_timeout": {
2621+
ngxHTTPMainConf | ngxHTTPSrvConf | ngxHTTPLocConf | ngxHTTPLifConf | ngxConfTake1,
2622+
},
2623+
"lua_socket_log_errors": {
2624+
ngxHTTPMainConf | ngxHTTPSrvConf | ngxHTTPLocConf | ngxHTTPLifConf | ngxConfFlag,
2625+
},
2626+
"lua_ssl_ciphers": {
2627+
ngxHTTPMainConf | ngxHTTPSrvConf | ngxHTTPLocConf | ngxConfTake1,
2628+
},
2629+
"lua_ssl_crl": {
2630+
ngxHTTPMainConf | ngxHTTPSrvConf | ngxHTTPLocConf | ngxConfTake1,
2631+
},
2632+
"lua_ssl_protocols": {
2633+
ngxHTTPMainConf | ngxHTTPSrvConf | ngxHTTPLocConf | ngxConf1More,
2634+
},
2635+
"lua_ssl_certificate": {
2636+
ngxHTTPMainConf | ngxHTTPSrvConf | ngxHTTPLocConf | ngxConfTake1,
2637+
},
2638+
"lua_ssl_certificate_key": {
2639+
ngxHTTPMainConf | ngxHTTPSrvConf | ngxHTTPLocConf | ngxConfTake1,
2640+
},
2641+
"lua_ssl_trusted_certificate": {
2642+
ngxHTTPMainConf | ngxHTTPSrvConf | ngxHTTPLocConf | ngxConfTake1,
2643+
},
2644+
"lua_ssl_verify_depth": {
2645+
ngxHTTPMainConf | ngxHTTPSrvConf | ngxHTTPLocConf | ngxConfTake1,
2646+
},
2647+
"lua_ssl_conf_command": {
2648+
ngxHTTPMainConf | ngxHTTPSrvConf | ngxHTTPLocConf | ngxConfTake2,
2649+
},
2650+
"lua_http10_buffering": {
2651+
ngxHTTPMainConf | ngxHTTPSrvConf | ngxHTTPLocConf | ngxHTTPLifConf | ngxConfFlag,
2652+
},
2653+
"rewrite_by_lua_no_postpone": {
2654+
ngxHTTPMainConf | ngxConfFlag,
2655+
},
2656+
"access_by_lua_no_postpone": {
2657+
ngxHTTPMainConf | ngxConfFlag,
2658+
},
2659+
"lua_transform_underscores_in_response_headers": {
2660+
ngxHTTPMainConf | ngxHTTPSrvConf | ngxHTTPLocConf | ngxHTTPLifConf | ngxConfFlag,
2661+
},
2662+
"lua_check_client_abort": {
2663+
ngxHTTPMainConf | ngxHTTPSrvConf | ngxHTTPLocConf | ngxHTTPLifConf | ngxConfFlag,
2664+
},
2665+
"lua_max_pending_timers": {
2666+
ngxHTTPMainConf | ngxConfTake1,
2667+
},
2668+
"lua_max_running_timers": {
2669+
ngxHTTPMainConf | ngxConfTake1,
2670+
},
2671+
"lua_sa_restart": {
2672+
ngxHTTPMainConf | ngxConfFlag,
2673+
},
2674+
"lua_worker_thread_vm_pool_size": {
2675+
ngxHTTPMainConf | ngxConfTake1,
2676+
},
2677+
}
2678+
2679+
// MatchLua is a match function for parsing an NGINX config that contains the
2680+
// Lua module.
2681+
func MatchLua(directive string) ([]uint, bool) {
2682+
masks, matched := LuaDirectives[directive]
2683+
return masks, matched
2684+
}

analyze_test.go

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1920,3 +1920,95 @@ func TestAnalyze_nap_app_protect_waf_v5(t *testing.T) {
19201920
})
19211921
}
19221922
}
1923+
1924+
//nolint:funlen
1925+
func TestAnalyze_lua(t *testing.T) {
1926+
t.Parallel()
1927+
testcases := map[string]struct {
1928+
stmt *Directive
1929+
ctx blockCtx
1930+
wantErr bool
1931+
}{
1932+
"content_by_lua_file ok": {
1933+
&Directive{
1934+
Directive: "content_by_lua_file",
1935+
Args: []string{"/path/to/lua/app/root/$path.lua"},
1936+
Line: 5,
1937+
},
1938+
blockCtx{"http", "location", "location if"},
1939+
false,
1940+
},
1941+
"content_by_lua_file relative path ok": {
1942+
&Directive{
1943+
Directive: "content_by_lua_file",
1944+
Args: []string{"foo/bar.lua"},
1945+
Line: 5,
1946+
},
1947+
blockCtx{"http", "location", "location if"},
1948+
false,
1949+
},
1950+
"content_by_lua_file nor ok": {
1951+
&Directive{
1952+
Directive: "content_by_lua_file",
1953+
Args: []string{"foo/bar.lua"},
1954+
Line: 5,
1955+
},
1956+
blockCtx{"server"},
1957+
false,
1958+
},
1959+
"lua_shared_dict ok": {
1960+
&Directive{
1961+
Directive: "lua_shared_dict",
1962+
Args: []string{"dogs", "10m"},
1963+
Line: 5,
1964+
},
1965+
blockCtx{"http"},
1966+
false,
1967+
},
1968+
"lua_shared_dict not ok": {
1969+
&Directive{
1970+
Directive: "lua_shared_dict",
1971+
Args: []string{"10m"},
1972+
Line: 5,
1973+
},
1974+
blockCtx{"http"},
1975+
true,
1976+
},
1977+
"lua_sa_restart ok": {
1978+
&Directive{
1979+
Directive: "lua_sa_restart",
1980+
Args: []string{"off"},
1981+
Line: 5,
1982+
},
1983+
blockCtx{"http"},
1984+
false,
1985+
},
1986+
"lua_sa_restart not ok": {
1987+
&Directive{
1988+
Directive: "lua_sa_restart",
1989+
Args: []string{"something"},
1990+
Line: 5,
1991+
},
1992+
blockCtx{"http"},
1993+
true,
1994+
},
1995+
}
1996+
1997+
for name, tc := range testcases {
1998+
tc := tc
1999+
t.Run(name, func(t *testing.T) {
2000+
t.Parallel()
2001+
err := analyze("nginx.conf", tc.stmt, ";", tc.ctx, &ParseOptions{
2002+
MatchFuncs: []MatchFunc{MatchLua},
2003+
})
2004+
2005+
if !tc.wantErr && err != nil {
2006+
t.Fatal(err)
2007+
}
2008+
2009+
if tc.wantErr && err == nil {
2010+
t.Fatal("expected error, got nil")
2011+
}
2012+
})
2013+
}
2014+
}

lex_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,34 @@ var lexFixtures = []lexFixture{
226226
{";", 15},
227227
{"}", 16},
228228
}},
229+
{"lua-basic", []tokenLine{
230+
{"http", 1},
231+
{"{", 1},
232+
{"init_by_lua", 2},
233+
{"\n print(\"I need no extra escaping here, for example: \\r\\nblah\")\n ", 2},
234+
{"lua_shared_dict", 5},
235+
{"dogs", 5},
236+
{"1m", 5},
237+
{";", 5},
238+
{"server", 6},
239+
{"{", 6},
240+
{"listen", 7},
241+
{"8080", 7},
242+
{";", 7},
243+
{"location", 8},
244+
{"/", 8},
245+
{"{", 8},
246+
{"set_by_lua", 9},
247+
{"$res", 9},
248+
{" return 32 + math.cos(32) ", 9},
249+
{";", 9},
250+
{"access_by_lua_file", 10},
251+
{"/path/to/lua/access.lua", 10},
252+
{";", 10},
253+
{"}", 11},
254+
{"}", 12},
255+
{"}", 13},
256+
}},
229257
}
230258

231259
func TestLex(t *testing.T) {

testdata/configs/lua-basic/nginx.conf

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
http {
2+
init_by_lua '
3+
print("I need no extra escaping here, for example: \r\nblah")
4+
'
5+
lua_shared_dict dogs 1m;
6+
server {
7+
listen 8080;
8+
location / {
9+
set_by_lua $res ' return 32 + math.cos(32) ';
10+
access_by_lua_file /path/to/lua/access.lua;
11+
}
12+
}
13+
}

testdata/configs/lua-basic/nginx.json

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
{
2+
"status": "ok",
3+
"errors": [],
4+
"config": [
5+
{
6+
"file": "testdata/configs/lua-block-larger/nginx.conf",
7+
"status": "ok",
8+
"errors": [],
9+
"parsed": [
10+
{
11+
"directive": "http",
12+
"line": 1,
13+
"args": [],
14+
"block": [
15+
{
16+
"directive": "init_by_lua",
17+
"line": 2,
18+
"args": [
19+
"\n print(\"I need no extra escaping here, for example: \\r\\nblah\")\n "
20+
]
21+
},
22+
{
23+
"directive": "lua_shared_dict",
24+
"line": 5,
25+
"args": [
26+
"dogs",
27+
"1m"
28+
]
29+
},
30+
{
31+
"directive": "server",
32+
"line": 7,
33+
"args": [],
34+
"block": [
35+
{
36+
"directive": "listen",
37+
"line": 7,
38+
"args": [
39+
"8080"
40+
]
41+
},
42+
{
43+
"directive": "location",
44+
"line": 8,
45+
"args": [
46+
"/"
47+
],
48+
"block": [
49+
{
50+
"directive": "set_by_lua",
51+
"line": 9,
52+
"args": [
53+
"$res",
54+
" return 32 + math.cos(32) "
55+
]
56+
},
57+
{
58+
"directive": "access_by_lua_file",
59+
"line": 10,
60+
"args": [
61+
"/path/to/lua/access.lua"
62+
]
63+
}
64+
]
65+
}
66+
]
67+
}
68+
]
69+
}
70+
]
71+
}
72+
]
73+
}

0 commit comments

Comments
 (0)