🙈 By 陈潞波 2024-01-04
range 端口转发模块
1.1 需求
在很多时候,比如流量劫持、ftp被动模式代理等功能需要能够支持流量端口转发。比如需要将10000到11000端口范围的所有流量都统一转到12000端口上,然后在12000端口上接收所有的报文进行后续处理。
1.2 依赖
该功能的实现依赖于iptables,如果通过rpm包安装,则自动为privilege进程为root启动
如果是普通用户启动,需要对opennjet设置setuid权限
setcap cap_setuid=eip /home/njet/sbin/njet
1.3 指令设计
Syntax | range type={tcp|udp} src_ports={port1:port2} dst_port={dst_port};如果默认iptables path为/usr/sbin/iptables, 如果系统iptables路径不是这个,需要指定使用如下指令range iptables_path={iptables_path}; |
---|---|
Default | - |
Context | Core, 支持配置多条 |
参数说明:
参数 | 类型 | 必填 | 默认值 | 说明 |
---|---|---|---|---|
type | string | 否 | tcp | [tcp|udp], 指明是tcp还是udp数据,默认tcp |
src_ports | string | 是 | - | 支持单端口或者端口范围,格式如下:端口范围(冒号分隔): 11000:12000一个端口: 11000 |
dst_port | int | 是 | - | 目标端口 |
iptables_path | string | 否 | /usr/sbin/iptables | 这个根据系统而定,调用system执行的时候可能会出现找不到iptables错误,这个时候需要看看对应系统的iptables path,然后设置一下这个参数如果配置多条range指令,则以最后一个明确指定的iptables_path为准 |
配置示例(tcp为例):
- 将发往本机端口为11000到12000范围的数据,转发到13000端口:
range type=tcp src_ports=11000:12000 dst_port=13000
- 将发往本机端口为11000,转发到13000端口:
range type=tcp src_ports=11000 dst_port=13000
- 设置iptables path为/usr/sbin/iptables
range iptables_path=/usr/sbin/iptables;
1.4 实现方案
本功能的实现借助于iptables规则,通过range指令解析参数,然后生成对应的iptables规则下发。
range指令支持配置多条规则
模块init的时候会根据规则生成iptables规则
模块exit的时候会将规则进行删除
所有的规则都会放到自定义iptables链 OPENNJET上
1.5 测试
1.5.1 配置示例
njet.conf 配置里配置两条range指令
load_module modules/njt_range_module.so; #加载range模块
...
user nobody;
events {
worker_connections 1024;
}
error_log logs/error_privilege.log info;
#配置两条range指令
range type=tcp src_ports=11000:12000 dst_port=13000;
range type=tcp src_ports=10000 dst_port=14000;
#默认路径为/usr/sbin/iptables, 如果系统路径不一致需要调用该指令设置下路径
range iptables_path=/usr/sbin/iptables;
http {
access_log logs/access_privilege.log combined;
include mime.types;
server {
...
}
}
cluster_name helper;
node_name node1;
1.5.2 测试结果
启动OpenNJet前
查询系统iptables 规则:
启动OpenNJet后
重新查询iptables规则,发现两条规则生效
reload重启后
重新查询,发现两条规则还在
停止OpenNJet后
重新查询,两条规则删除
2. 命令式 API 动态配置端口转发规则
2.1 需求:
能够通过api接口查询全量的range 配置规则
能够通过api增加或者删除一条range配置规则
根据type、src_ports、dst_port三个字段来确定一条规则
2.2 配置
ctrl控制面配置:
...
load_module modules/njt_http_range_api_module.so; #load range api module
...
server {
listen 8081;
location /range {
dyn_range_api; #配置range api开关
}
}
...
2.3 动态API
查询:
GET http://192.168.40.136:8081/range
{ "ranges": [
{ "type": "tcp",
"src_ports": "11000:12000",
"dst_port": 10001
},
{
"type": "tcp",
"src_ports": "10000",
"dst_port": 14000
}
]
}
PUT http://192.168.40.136:8081/range #添加一条规则
{
"action": "add",
"type": "tcp",
"src_ports": "11000:13000",
"dst_port": 10001 }
#删除一条规则
{
"action": "del",
"type": "tcp",
"src_ports": "11000:13000",
"dst_port": 10001 }
参数 | 类型 | 必填 | 默认值 | 说明 |
---|---|---|---|---|
action | string | 是 | - | [add|del] |
type | string | 是 | - | [tcp|udp], 指明是tcp还是udp数据 |
src_ports | string | 是 | - | 支持单端口或者端口范围,格式如下:端口范围(冒号分隔): 11000:12000一个端口: 11000 |
dst_port | int | 是 | - | 目标端口 |
return:
{ “code”: 0, #0 表示成功, 非0 表示失败 “msg”: “success” }
错误码
code | msg | 描述 | |
---|---|---|---|
0 | success | 成功 | |
2 | - | 内存分配失败相关的一些错误信息 | |
4 | rule is not found | 删除一个不存在的规则 | |
4 | rule has exist | 添加一个已经存在的规则 | |
4 | 其他错误 |
2.4 swagger访问
可以通过doc模块提供的swagger界面操作
http://192.168.40.136:8081/doc/swagger/
2.5 测试
通过swagger页面进行api测试
初始状态get 查询配置
查询iptables
通过swagger页面添加一个规则
再次 查询配置和iptables
reload后再次查询,动态添加的配置和iptables都存在刚才动态添加的配置
Stop OpenNJet后,iptables规则消失