Skip to content

Commit 2b04d54

Browse files
authored
feat: allow privileged agent to listen port (#71)
1 parent bdfa2f3 commit 2b04d54

File tree

3 files changed

+271
-2
lines changed

3 files changed

+271
-2
lines changed

.github/workflows/ci.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ on:
88

99
jobs:
1010
build:
11-
runs-on: "ubuntu-18.04"
11+
runs-on: "ubuntu-20.04"
1212
env:
1313
OPENRESTY_PREFIX: "/usr/local/openresty"
1414

@@ -20,7 +20,9 @@ jobs:
2020
uses: egor-tensin/setup-clang@v1
2121

2222
- name: Get dependencies
23-
run: sudo apt install -y cpanminus build-essential libncurses5-dev libreadline-dev libssl-dev perl
23+
run: |
24+
sudo apt install -y cpanminus build-essential libncurses5-dev libreadline-dev libssl-dev perl luarocks
25+
sudo luarocks install lua-resty-http > build.log 2>&1 || (cat build.log && exit 1)
2426
2527
- name: Before install
2628
run: |
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
diff --git src/core/ngx_connection.c src/core/ngx_connection.c
2+
index 568ae3d..e22c990 100644
3+
--- src/core/ngx_connection.c
4+
+++ src/core/ngx_connection.c
5+
@@ -434,6 +434,10 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle)
6+
continue;
7+
}
8+
9+
+ if (ngx_is_privileged_agent != ls[i].privileged_agent) {
10+
+ continue;
11+
+ }
12+
+
13+
#if (NGX_HAVE_REUSEPORT)
14+
15+
if (ls[i].add_reuseport) {
16+
diff --git src/core/ngx_connection.h src/core/ngx_connection.h
17+
index be75d82..12c8694 100644
18+
--- src/core/ngx_connection.h
19+
+++ src/core/ngx_connection.h
20+
@@ -66,6 +66,7 @@ struct ngx_listening_s {
21+
unsigned shared:1; /* shared between threads or processes */
22+
unsigned addr_ntop:1;
23+
unsigned wildcard:1;
24+
+ unsigned privileged_agent:1;
25+
26+
#if (NGX_HAVE_INET6)
27+
unsigned ipv6only:1;
28+
diff --git src/event/ngx_event.c src/event/ngx_event.c
29+
index d800af0..f73e57c 100644
30+
--- src/event/ngx_event.c
31+
+++ src/event/ngx_event.c
32+
@@ -818,7 +818,9 @@ ngx_event_process_init(ngx_cycle_t *cycle)
33+
for (i = 0; i < cycle->listening.nelts; i++) {
34+
35+
#if (NGX_HAVE_REUSEPORT)
36+
- if (ls[i].reuseport && ls[i].worker != ngx_worker) {
37+
+ if ((ngx_is_privileged_agent && !ls[i].privileged_agent)
38+
+ || (ls[i].reuseport && ls[i].worker != ngx_worker))
39+
+ {
40+
ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
41+
"closing unused fd:%d listening on %V",
42+
ls[i].fd, &ls[i].addr_text);
43+
@@ -833,6 +835,10 @@ ngx_event_process_init(ngx_cycle_t *cycle)
44+
45+
continue;
46+
}
47+
+
48+
+ if (!ngx_is_privileged_agent && ls[i].privileged_agent) {
49+
+ continue;
50+
+ }
51+
#endif
52+
53+
c = ngx_get_connection(ls[i].fd, cycle->log);
54+
diff --git src/http/ngx_http.c src/http/ngx_http.c
55+
index e1d3d00..7ad72e3 100644
56+
--- src/http/ngx_http.c
57+
+++ src/http/ngx_http.c
58+
@@ -1217,6 +1217,13 @@ ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
59+
continue;
60+
}
61+
62+
+ if (lsopt->privileged_agent != addr[i].opt.privileged_agent) {
63+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
64+
+ "%V is already occupied by privileged agent",
65+
+ &addr[i].opt.addr_text);
66+
+ return NGX_ERROR;
67+
+ }
68+
+
69+
/* the address is already in the address list */
70+
71+
if (ngx_http_add_server(cf, cscf, &addr[i]) != NGX_OK) {
72+
@@ -1769,6 +1776,8 @@ ngx_http_add_listening(ngx_conf_t *cf, ngx_http_conf_addr_t *addr)
73+
ls->reuseport = addr->opt.reuseport;
74+
#endif
75+
76+
+ ls->privileged_agent = addr->opt.privileged_agent;
77+
+
78+
return ls;
79+
}
80+
81+
diff --git src/http/ngx_http_core_module.c src/http/ngx_http_core_module.c
82+
index 6287d6e..a84dd80 100644
83+
--- src/http/ngx_http_core_module.c
84+
+++ src/http/ngx_http_core_module.c
85+
@@ -4202,6 +4202,20 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
86+
continue;
87+
}
88+
89+
+ if (ngx_strncmp(value[n].data, "enable_process=", 15) == 0) {
90+
+ if (ngx_strcmp(&value[n].data[15], "privileged_agent") == 0) {
91+
+ lsopt.privileged_agent = 1;
92+
+
93+
+ } else {
94+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
95+
+ "invalid enable_process value: \"%s\"",
96+
+ &value[n].data[15]);
97+
+ return NGX_CONF_ERROR;
98+
+ }
99+
+
100+
+ continue;
101+
+ }
102+
+
103+
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
104+
"invalid parameter \"%V\"", &value[n]);
105+
return NGX_CONF_ERROR;
106+
diff --git src/http/ngx_http_core_module.h src/http/ngx_http_core_module.h
107+
index 2aadae7..6ba3a90 100644
108+
--- src/http/ngx_http_core_module.h
109+
+++ src/http/ngx_http_core_module.h
110+
@@ -82,6 +82,7 @@ typedef struct {
111+
unsigned reuseport:1;
112+
unsigned so_keepalive:2;
113+
unsigned proxy_protocol:1;
114+
+ unsigned privileged_agent:1;
115+
116+
int backlog;
117+
int rcvbuf;
118+
diff --git src/os/unix/ngx_process_cycle.c src/os/unix/ngx_process_cycle.c
119+
index e8ebf3d..8227ecf 100644
120+
--- src/os/unix/ngx_process_cycle.c
121+
+++ src/os/unix/ngx_process_cycle.c
122+
@@ -1250,7 +1250,11 @@ ngx_privileged_agent_process_cycle(ngx_cycle_t *cycle, void *data)
123+
ngx_process = NGX_PROCESS_HELPER;
124+
ngx_is_privileged_agent = 1;
125+
126+
- ngx_close_listening_sockets(cycle);
127+
+ if (ngx_open_listening_sockets(cycle) != NGX_OK) {
128+
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
129+
+ "failed to init privileged agent listeners");
130+
+ exit(2);
131+
+ }
132+
133+
/* Set a moderate number of connections for a helper process. */
134+
cycle->connection_n = 512;
135+
@@ -1265,6 +1269,7 @@ ngx_privileged_agent_process_cycle(ngx_cycle_t *cycle, void *data)
136+
137+
if (ngx_terminate || ngx_quit) {
138+
ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting");
139+
+ ngx_close_listening_sockets(cycle);
140+
ngx_worker_process_exit(cycle);
141+
}

t/privileged_agent.t

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
use t::APISIX_NGINX 'no_plan';
2+
3+
master_on();
4+
run_tests();
5+
6+
__DATA__
7+
8+
=== TEST 1: sanity
9+
--- http_config
10+
init_by_lua_block {
11+
local process = require("ngx.process")
12+
assert(process.enable_privileged_agent())
13+
}
14+
server {
15+
listen 9090;
16+
location / {
17+
content_by_lua_block {
18+
local process = require("ngx.process")
19+
ngx.say(process.type())
20+
}
21+
}
22+
}
23+
server {
24+
listen 127.0.0.1:9091 enable_process=privileged_agent;
25+
location / {
26+
content_by_lua_block {
27+
local process = require("ngx.process")
28+
ngx.say(process.type())
29+
}
30+
}
31+
}
32+
--- config
33+
location /t {
34+
content_by_lua_block {
35+
local http = require "resty.http"
36+
37+
for i = 1, 12 do
38+
local httpc = http.new()
39+
local uri
40+
if i % 2 == 1 then
41+
uri = "http://127.0.0.1:9090"
42+
else
43+
uri = "http://127.0.0.1:9091"
44+
end
45+
local res, err = httpc:request_uri(uri, {method = "GET"})
46+
if not res then
47+
ngx.say(err)
48+
return
49+
end
50+
51+
local exp
52+
if i % 2 == 1 then
53+
exp = "worker\n"
54+
else
55+
exp = "privileged agent\n"
56+
end
57+
58+
assert(exp == res.body)
59+
end
60+
}
61+
}
62+
63+
64+
65+
=== TEST 2: address conflict detection
66+
--- http_config
67+
init_by_lua_block {
68+
local process = require("ngx.process")
69+
assert(process.enable_privileged_agent())
70+
}
71+
server {
72+
listen 127.0.0.1:9091;
73+
location / {
74+
content_by_lua_block {
75+
local process = require("ngx.process")
76+
ngx.say(process.type())
77+
}
78+
}
79+
}
80+
server {
81+
listen 127.0.0.1:9091 enable_process=privileged_agent;
82+
location / {
83+
content_by_lua_block {
84+
local process = require("ngx.process")
85+
ngx.say(process.type())
86+
}
87+
}
88+
}
89+
--- config
90+
location /t {
91+
return 200;
92+
}
93+
--- must_die
94+
--- error_log
95+
127.0.0.1:9091 is already occupied by privileged agent
96+
97+
98+
99+
=== TEST 3: same port, different IP
100+
--- http_config
101+
init_by_lua_block {
102+
local process = require("ngx.process")
103+
assert(process.enable_privileged_agent())
104+
}
105+
server {
106+
listen 9091;
107+
location / {
108+
content_by_lua_block {
109+
local process = require("ngx.process")
110+
ngx.say(process.type())
111+
}
112+
}
113+
}
114+
server {
115+
listen 127.0.0.1:9091 enable_process=privileged_agent;
116+
location / {
117+
content_by_lua_block {
118+
local process = require("ngx.process")
119+
ngx.say(process.type())
120+
}
121+
}
122+
}
123+
--- config
124+
location /t {
125+
return 200;
126+
}

0 commit comments

Comments
 (0)