海运的博客

openresty/nginx lua动态更新stream upstream/tcp udp端口转发服务器

发布时间:February 7, 2022 // 分类: // No Comments

有一应用需动态更新目标的ip和端口,使用nginx/openresty tcp/udp端口转发配合lua扩展很方便实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
stream {
    lua_shared_dict ups_dict 1m;
    lua_shared_dict ups_list 1m;
    lua_add_variable $ups_name;
    #当nginx启动或reload时读取配置文件内upstream列表到lua_shared_dict,更新后端的时候判断是否有效
    init_by_lua_block {
       ngx.shared.ups_list:flush_all()
       local file = "/etc/nginx/stream.conf"
       local f = io.open(file, "r")
       local content = f:read("*a")
       f:close()
       for substr in string.gmatch(content, "upstream%s+([%w-_]+)%s+%{") do
           ngx.log(ngx.WARN, substr)
           ngx.shared.ups_list:set(substr, 1)
       end
    }
   
    log_format main '$remote_addr [$time_local] '
                    '$protocol $status $bytes_sent $bytes_received '
                    '$session_time "$upstream_addr" '
                    '"$upstream_bytes_sent" "$upstream_bytes_received" "$upstream_connect_time"';
    access_log /run/log/nginx/dns_access.log main;
    error_log  /run/log/nginx/dns_error.log error;
    #log level: debug, info, notice, warn, error (default), crit, alert, and emerg.
 
    upstream default_tcp {
        server 127.0.0.1:53;
        server 127.0.0.1:55;
    }
    upstream default_udp {
        server 10.0.1.1:53;
        server 10.0.2.1:53;
    }
    upstream default_udp2 {
        server 10.0.3.1:53;
        server 10.0.3.2:53;
    }
    upstream test1_tcp {
        server 127.0.0.1:53;
    }
    upstream test1_udp {
        server 10.0.1.1:53;
    }
    upstream test1_udp2 {
        server 10.0.3.2:53;
    }
    upstream test2_tcp {
        server 127.0.0.1:55;
    }
    upstream test2_udp {
        server 10.0.2.1:53;
    }
    upstream test2_udp2 {
        server 10.0.3.1:53;
    }
 
    server {
        listen     53000 udp;
        preread_by_lua_block {
            assert(not ngx.var.ups_name)
            local ups = ngx.shared.ups_dict:get("ups_name")
            if ups ~= nil then
                ngx.log(ngx.WARN, "udp 53000 use " .. ups .. " upstream")
                ngx.var.ups_name = ups .. "_udp"
            else
                ngx.log(ngx.WARN, "udp 53000 use default upstream")
                ngx.var.ups_name = "default_udp"
            end
        }
        proxy_pass $ups_name;
        proxy_responses 1; #当返回一个udp数据包时就关闭连接,或proxy_timeout时间内无数据关闭连接
        proxy_connect_timeout 1s;
        proxy_timeout 5s;
    }
    server {
        listen     53000;
        preread_by_lua_block {
            assert(not ngx.var.ups_name)
            local ups = ngx.shared.ups_dict:get("ups_name")
            if ups ~= nil then
                ngx.log(ngx.WARN, "tcp 53000 use " .. ups .. " upstream")
                ngx.var.ups_name = ups .. "_tcp"
            else
                ngx.log(ngx.WARN, "tcp 53000 use default upstream")
                ngx.var.ups_name = "default_tcp"
            end
        }
        proxy_pass $ups_name;
        #proxy_responses 1; #当返回一个udp数据包时就关闭连接,或proxy_timeout时间内无数据关闭连接
        proxy_connect_timeout 1s;
        proxy_timeout 5s;
    }
    server {
        listen     53001 udp;
        preread_by_lua_block {
            assert(not ngx.var.ups_name)
            local ups = ngx.shared.ups_dict:get("ups_name")
            if ups ~= nil then
                ngx.log(ngx.WARN, "udp 53001 use " .. ups .. " upstream")
                ngx.var.ups_name = ups .. "_udp2"
            else
                ngx.log(ngx.WARN, "udp 53001 use default upstream")
                ngx.var.ups_name = "default_udp2"
            end
        }
        proxy_pass $ups_name;
        proxy_responses 1; #当返回一个udp数据包时就关闭连接,或proxy_timeout时间内无数据关闭连接
        proxy_connect_timeout 1s;
        proxy_timeout 5s;
    }
 
 
    server {
        listen 53001;
 
        content_by_lua_block {
            local sock = assert(ngx.req.socket(true))
            local data = sock:receive()
            local args, err = ngx.decode_args(data, 0)
            if err == nil then
                for k,v in pairs(args) do
                    --ngx.say(v)
                    ip = v:match("(%d+%.%d+%.%d+%.%d+%:%d+)")
                    if ip ~= nil then
                        local sus, err = ngx.shared.ups_dict:set(k, ip)
                        if sus then
                            ngx.say("set upstream sus: " .. k .. "=" .. ip)
                        else
                            ngx.say(err)
                        end
                    end
                end
            end
        }
        access_log off;
    }
    server {
        listen 53002;
 
        content_by_lua_block {
            local sock = assert(ngx.req.socket(true))
            local data = sock:receive()
            if data then
                local args, err = ngx.decode_args(data, 0)
                if err == nil then
                    for k,v in pairs(args) do
                        --ngx.say(v)
                        --if k == "name" and type(v) == "string" and v:find("dns") then
                        if k == "name" and type(v) == "string" and ngx.shared.ups_list:get(v .. "_udp")  then
                            local sus, err = ngx.shared.ups_dict:set("ups_name", v)
                            if sus then
                                ngx.say("set upstream sus: " .. k .. "=" .. v)
                                ngx.log(ngx.WARN, "set upstream sus: " .. k .. "=" .. v)
                            else
                                ngx.say(err)
                            end
                        end
                    end
                end
            end
        }
        access_log off;
    }
}

使用nc测试设置nginx转发使用的后端upstream名称:

1
2
3
nc 127.0.0.1 53002
name=test1
set upstream sus: name=test1

也可通过53001端口设置目标ip:port,然后proxy_pass即可。
参考:
https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/balancer.md
https://xiangxianzui.github.io/2017/11/nginx-lua%E5%8A%A8%E6%80%81%E6%94%B9%E5%8F%98upstream/

标签:nginx, openresty, lua, 端口转发, nginx动态更新upstream

评论已关闭

分类
最新文章
最近回复
  • opnfense: 谢谢博主!!!解决问题了!!!我之前一直以为内置的odhcp6就是唯一管理ipv6的方式
  • liyk: 这个方法获取的IPv6大概20分钟之后就会失效,默认路由先消失,然后Global IPV6再消失
  • 海运: 不好意思,没有。
  • zongboa: 您好,請問一下有immortalwrt設定guest Wi-Fi的GUI教學嗎?感謝您。
  • 海运: 恩山有很多。
  • swsend: 大佬可以分享一下固件吗,谢谢。
  • Jimmy: 方法一 nghtp3步骤需要改成如下才能编译成功: git clone https://git...
  • 海运: 地址格式和udpxy一样,udpxy和msd_lite能用这个就能用。
  • 1: 怎么用 编译后的程序在家里路由器内任意一台设备上运行就可以吗?比如笔记本电脑 m参数是笔记本的...
  • 孤狼: ups_status_set: seems that UPS [BK650M2-CH] is ...
StatCounter - Free Web Tracker and Counter