diff --git a/assets/run-example/client-connect-log1.png b/assets/run-example/client-connect-log1.png new file mode 100644 index 00000000..361956e5 Binary files /dev/null and b/assets/run-example/client-connect-log1.png differ diff --git a/assets/run-example/home.png b/assets/run-example/home.png new file mode 100644 index 00000000..524e0a3a Binary files /dev/null and b/assets/run-example/home.png differ diff --git a/assets/run-example/job-log1.png b/assets/run-example/job-log1.png new file mode 100644 index 00000000..4e87eedb Binary files /dev/null and b/assets/run-example/job-log1.png differ diff --git a/assets/run-example/job-manager1.png b/assets/run-example/job-manager1.png new file mode 100644 index 00000000..3e174bf1 Binary files /dev/null and b/assets/run-example/job-manager1.png differ diff --git a/assets/run-example/license-flow-month1.png b/assets/run-example/license-flow-month1.png new file mode 100644 index 00000000..76f39b99 Binary files /dev/null and b/assets/run-example/license-flow-month1.png differ diff --git a/assets/run-example/license-flow1.png b/assets/run-example/license-flow1.png new file mode 100644 index 00000000..7caedbc4 Binary files /dev/null and b/assets/run-example/license-flow1.png differ diff --git a/assets/run-example/license1.png b/assets/run-example/license1.png index 1ce7e56a..07d00748 100644 Binary files a/assets/run-example/license1.png and b/assets/run-example/license1.png differ diff --git a/assets/run-example/login-log1.png b/assets/run-example/login-log1.png new file mode 100644 index 00000000..73d97036 Binary files /dev/null and b/assets/run-example/login-log1.png differ diff --git a/assets/run-example/port-group1.png b/assets/run-example/port-group1.png new file mode 100644 index 00000000..3c2acaaa Binary files /dev/null and b/assets/run-example/port-group1.png differ diff --git a/assets/run-example/port-mapping1.png b/assets/run-example/port-mapping1.png index 99a86b96..9e44009d 100644 Binary files a/assets/run-example/port-mapping1.png and b/assets/run-example/port-mapping1.png differ diff --git a/assets/run-example/port-pool1.png b/assets/run-example/port-pool1.png index 26a6322b..0400e2e9 100644 Binary files a/assets/run-example/port-pool1.png and b/assets/run-example/port-pool1.png differ diff --git a/assets/run-example/user-flow-month1.png b/assets/run-example/user-flow-month1.png new file mode 100644 index 00000000..0b6254e3 Binary files /dev/null and b/assets/run-example/user-flow-month1.png differ diff --git a/assets/run-example/user-flow1.png b/assets/run-example/user-flow1.png new file mode 100644 index 00000000..daa0eaa2 Binary files /dev/null and b/assets/run-example/user-flow1.png differ diff --git a/assets/run-example/user-manager1.png b/assets/run-example/user-manager1.png index 92818d83..7afd7dae 100644 Binary files a/assets/run-example/user-manager1.png and b/assets/run-example/user-manager1.png differ diff --git a/docs/article/2023/01/01.MD b/docs/article/2023/01/01.MD new file mode 100644 index 00000000..574e2626 --- /dev/null +++ b/docs/article/2023/01/01.MD @@ -0,0 +1,200 @@ +## 1、关于作者 +- dromara开源组织成员,[dromara/neutrino-proxy](https://gitee.com/asgc/neutrino-proxy)项目作者 +- 名称:傲世孤尘、雨韵诗泽 +- 名言: + - 扎根土壤,心向太阳。积蓄能量,绽放微光。 + - 拘浊酒邀明月,借赤日暖苍穹。喻万物为星斗,化沧海成诗篇。 + - 还生命以坦然,遗沧海以一笑。 +- 微信号:yuyunshize +- Gitee: https://gitee.com/asgc + +## 2、项目简介 +- [中微子代理(neutrino-proxy)](https://gitee.com/asgc/neutrino-proxy) 是一款基于netty的内网穿透神器。该项目采用最为宽松的MIT协议,因此您可以对它进行复制、修改、传播并用于任何个人或商业行为。 +- 演示环境: + - 地址:http://103.163.47.16:9527 + - 账号:visitor/123456 +- 该开源版本针对开发者个人,不提供任何付费服务。上面提供的地址、账号仅用于演示,已提供现成的license供大家测试。 +- 市面上基于内网穿透的常见产品有:花生壳、TeamView、cpolar等。 +- 该项目的目标是打开内网穿透功能黑盒,让更多感兴趣的朋友能更简单、低成本的掌握内网穿透技术。 +- 学习、使用过程中,有任何问题都可以通过微信(通过上面的微信号,或扫描结尾的二维码)与笔者联系。同时,若该项目对您有所帮助,也请大家不吝转发推荐。 + +## 3、目录&文件说明 +``` +├── data.db 'sqlite数据库文件。若未配置mysql,默认使用sqlite,项目首次启动会自动初始化sqlite数据库。 +├── docs '项目相关的一些文档 +├── ├── Aop.MD '框架层Aop机制、使用说明 +├── └── Channel.MD '内网穿透实现原理、代理实现流程说明 +├── lib '项目开启了将自动生成的类保存到本地后,运行过程中动态生成的类自动保存到此处,方便学习、调试 +├── neutrino-core '一套手写的基于netty的框架,相当于简易版的SpringBoot + Mybatis + xxljob,计划后期分离为单独开源项目维护 +├── neutrino-proxy-admin '基于vue-element-admin开发的一个管理系统,用于可视化操作端口映射、代理数据实时监控 +├── neutrino-proxy-client '基于netty的代理客户端,用于和服务端交互、转发内网数据 +├── neutrino-proxy-core '代理相关的公共代码(协议、常量) +├── neutrino-proxy-server '基于netty的代理服务端,用于和客户段交互,将客户端转发的内网数据转发至外网端口 +└── todolist.MD '近期的开发计划 +``` + +## 4、项目亮点 +- 性能:基于netty,天然拥有netty的高性能优势 +- 学习:除netty之外,只依赖了最基本的日志、数据库驱动/连接池、json等jar包,代理层代码量非常精简。极其适合java初学者用来学习和掌握Web框架底层原理、内网穿透实现机制。 +- 调试:只需要安装jdk8,甚至连数据库都无需考虑,即可直接在本地运行服务端+客户端,调试代理流程。尽可能减少前期步骤,确保大家能更快上手。 +- 测试:针对框架层封装(如:AOP、Web容器、ORM、调度管理等),提供了丰富的测试代码。 + +## 5、运行环境 +以下版本均为笔者开发时实际的使用版本 + +- `Node`:v13.12.0 +- `Java`:1.8.0_351 +- `Mysql`:8.0.31 (非必需,使用sqlite则无需考虑数据库) +- `Nginx`:1.21.4 (非必需,可直接使用服务端项目提供的静态资源服务) + +## 6、使用方法 +### 6.1、打包 +可直接前往[Gitee仓库发行版页面](https://gitee.com/dromara/neutrino-proxy/releases)下载所需版本已打好的包。 +若需手动打包,则可参照下面的执行命令: +```sh +# 服务端打包 +mvn clean install -U -pl neutrino-proxy-server -am -Dmaven.test.skip=true + +# 客户端打包 +clean install -U -pl neutrino-proxy-client -am -Dmaven.test.skip=true + +# 管理后台前端项目打包(本地环境,local改为dev则为dev环境,同时需要修改config目录下面的环境配置) +npm run build:local +``` + +### 6.2、部署 +#### 6.2.1、服务端部署 +使用常规的jar包部署方式即可,如:java -jar xxxx + +#### 6.2.2、管理后台部署 +Nginx方式部署(推荐): + +``` +server { + listen 9527; + server_name localhost; + + #开启gzip + gzip on; + #低于1kb的资源不压缩 + gzip_min_length 1k; + #压缩级别1-9,越大压缩率越高,同时消耗cpu资源也越多,建议设置在5左右。 + gzip_comp_level 5; + #需要压缩哪些响应类型的资源,多个空格隔开。不建议压缩图片. + gzip_types text/plain application/javascript application/x-javascript text/javascript text/xml text/css; + #配置禁用gzip条件,支持正则。此处表示ie6及以下不启用gzip(因为ie低版本不支持) + gzip_disable "MSIE [1-6]\."; + #是否添加“Vary: Accept-Encoding”响应头 + gzip_vary on; + + location / { + root /work/projects/neutrino-proxy-server/neutrino-proxy-admin/dist; + try_files $uri $uri/ /index.html; + add_header Last-Modified $date_gmt; + } +} +``` + +在没有Nginx时,为了快速体验代理效果,可直接使用服务端项目提供的静态资源服务。 +直接将`neutrino-proxy-admin`打包后的文件解压放在`neutrino-proxy-server.jar`同级别目录下即可。 +例如:服务端配置的web端口为8080,则访问http://服务端IP:8080, 则会直接解析渲染`neutrino-proxy-server.jar`同级别目录下`neutrino-proxy-admin/dist/index.html`。 + +需要注意的是,使用服务端自带的静态资源服务时,由于框架目前未支持缓存、gzip压缩,所以访问速度没有使用nginx快,正式使用推荐用nginx。 + +### 6.3、配置 +#### 6.3.1、配置端口池 +端口池的作用是将代理服务需要对外暴露的端口进行集中管理,方便安全组设置时统一操作。 + +本项目为了简化首次配置,默认初始化数据会将9101~9120的所有端口加入端口池。 +可以在服务端项目sql配置(port_pool.data.sql文件)中自行修改初始化数据,也可以运行后在端口池管理页面手动维护。 + +首次使用如果为了快速体验,建议直接使用默认端口池,则无需任何配置。 + +#### 6.3.2、配置用户 +用户是登录管理后台的身份主体,同时也是持有license的身份主体,用于支持代理连接的合法性认证。 + +本项目为了简化首次配置,默认初始化admin、visitor两个用户,默认密码为123456。 +可以在服务端项目sql配置(user.data.sql文件)中自行修改初始化数据,也可以运行后在用户管理页面手动维护。 + +首次使用如果为了快速体验,建议直接使用默认用户,则无需任何配置。 + +#### 6.3.3、配置License +License是客户端连接代理服务端时所需要的唯一合法凭证,一个License同时只能被一个客户端使用。 + +本项目为了简化首次配置,默认为每个用户初始化了一些license。 +可以在服务端项目sql配置(license.data.sql文件)中自行修改初始化数据,也可以运行后在License管理页面手动维护。 + +首次使用如果为了快速体验,建议直接使用默认License,则无需任何配置。 + +#### 6.3.4、配置端口映射 +端口映射是代理的基本单元,一个外网端口在同一时刻被唯一的映射到一个内网IP+端口。所有流出该外网端口的流量都转发自对应的内网端口,同理所有流入该外网端口的流量都会转发到对应的内网端口。 + +本项目为了简化首次配置,默认为每个用户初始化了一些端口映射。可以在服务端项目sql配置(port_mapping.data.sql文件)中自行修改初始化数据,也可以运行后在端口映射管理页面手动维护。 + +首次使用如果为了快速体验,建议直接使用默认端口映射,则无需任何配置。 + + +### 6.4、开启代理 +上述步骤完成后,就可以开始代理自己的局域网设备了。 + +比如现在有一个license:a123456,该license配置了一个或多个端口映射,其中包含9010到localhost:8080的映射(localhost表示代理客户端所在主机的端口,可以换成客户端所在局域网的任何IP)。此时修改客户端配置的服务端ip、license等启动客户端,就可以开启代理了,端口映射管理对应的记录在线状态为"在线"则证明代理成功建立。 + +该license配置也可以通过客户端启动参数、启动后引导式输入、外置配置提供,为了简化首次体验门槛,这里直接提供一个外置配置模版: +```json +{ + "jksPath":"classpath:/test.jks", + "licenseKey":"b0a907332b474b25897c4dcb31fc7eb6", + "serverIp":"localhost", + "serverPort":9002, + "sslEnable":true +} +``` + +修改上述json中的licenseKey,serverIp、serverPort、sslEnabled后,保存文件命名为`.neutrino-proxy-client.json`,放在客户端当前目录下(jar包启动时,放在jar包同级别目录下。idea启动时,放在项目根目录下),然后直接启动客户端。 + +此时通过访问外网ip+端口,可以成功访问内网服务。通过此方式,可以代理任何基于TCP之上的协议,如:socket、websocket、http、ftp、ssh等。 + +## 7、开发&调试 +篇幅所限,此处不便赘述管理后台相关的开发,有vue基础的童鞋基本都可以自行开发。服务端的初始化数据足够调试工作,开发过程无需单独在管理页面操作。 + +与SpringBoot项目类似,客户端、服务端项目均由一个入口类完成整个项目的启动,分别为`ProxyClient`、`ProxyServer`。 + +内置配置采用yml风格,主要涉及Http端口、静态资源路径、协议参数、代理服务端端口、jks证书、数据源、license等。 +整个项目基于`neutrino-core`,风格类似于SpringBoot。笔者不喜欢因过分炫技而引入过多花式操作,因为项目的定位是个人开发者,且满足使用的同时兼顾学习其原理的需求。基本使用方式与SpringBoot类似,尽可能降低首次学习成本。 + +`neutrino-core`项目test目录下包含众多核心封装的测试代码,通过调试这些代码,能尽可能减少大家学习的障碍。 + +## 8、运行截图 +License管理: + + +端口映射管理: + + +端口池管理: + + +用户管理: + + +## 9、迭代进度&未来计划 +从`2022-06-16` 第一个完整可用版本发布(无管理后台、无DB,纯配置实现)起,该项目已具备完整的内网穿透功能。经过后续的不断重构,初步完成了以下迭代: +- 使用sqlite取代纯配置,增加管理后台界面。解决修改端口映射需要重新打包的问题。 +- 增加mysql支持。初学时,直接默认使用sqlite,可以专注于学习代理相关细节而不必额外安装、配置数据库。有了自己的服务器后,可配置使用mysql,完全兼容。 +- 增加端口池管理。方便服务器统一设置安全组,避免暴露的外网端口杂乱无章。 +- 集成调度管理。个人版项目自带调度管理,降低学习、使用成本。无需部署、接入其他调度服务。 +- 增加简单的游客权限限制。个人版项目无需权限管理,但是为了演示需要,同时避免游客篡改管理员数据。 +- 封装一套类似于SpringBoot + Mybatis的简化框架,用于支撑上层代理项目,减少外部依赖,为后期孵化一个开源框架做准备。 + +由于笔者工作之余才能进行开发,可投入时间不固定。截至目前(2023-02),该项目2.0版本仍未发布,基于此未来的计划如下: +- 完成2.0版本发布(还剩下报表管理、首页图表功能)。 +- 底层框架全部重构。 +- 分离出一个开源框架项目,并持续维护。 +- 思考或着手基于内网穿透的产品开发,包括但不限于内网穿透SaaS服务、堡垒机。 + +## 10、联系我们 +笔者时间、能力有限,且开源项目非一朝一夕之事,存在众多问题亦在所难免。使用、学习过程中有任何问题欢迎大家与我联系。 + +对项目有什么想法或者建议,可以加我微信拉交流群,或者创建[issues](https://gitee.com/dromara/neutrino-proxy/issues),一起完善项目 + + diff --git a/docs/article/2023/01/MyWeChatQRCode.jpeg b/docs/article/2023/01/MyWeChatQRCode.jpeg new file mode 100644 index 00000000..3020c161 Binary files /dev/null and b/docs/article/2023/01/MyWeChatQRCode.jpeg differ diff --git a/docs/article/2023/01/license1.png b/docs/article/2023/01/license1.png new file mode 100644 index 00000000..1ce7e56a Binary files /dev/null and b/docs/article/2023/01/license1.png differ diff --git a/docs/article/2023/01/port-mapping1.png b/docs/article/2023/01/port-mapping1.png new file mode 100644 index 00000000..99a86b96 Binary files /dev/null and b/docs/article/2023/01/port-mapping1.png differ diff --git a/docs/article/2023/01/port-pool1.png b/docs/article/2023/01/port-pool1.png new file mode 100644 index 00000000..26a6322b Binary files /dev/null and b/docs/article/2023/01/port-pool1.png differ diff --git a/docs/article/2023/01/user-manager1.png b/docs/article/2023/01/user-manager1.png new file mode 100644 index 00000000..92818d83 Binary files /dev/null and b/docs/article/2023/01/user-manager1.png differ diff --git a/neutrino-proxy-admin/src/api/portPool.js b/neutrino-proxy-admin/src/api/portPool.js index 7dc48ba3..fb5a60b4 100644 --- a/neutrino-proxy-admin/src/api/portPool.js +++ b/neutrino-proxy-admin/src/api/portPool.js @@ -43,6 +43,14 @@ export function createPortPool(data) { }) } +export function updatePortPool(data) { + return request({ + url: '/port-pool/update', + method: 'post', + data + }) +} + export function deletePortPool(id) { return request({ url: '/port-pool/delete', diff --git a/neutrino-proxy-admin/src/api/report.js b/neutrino-proxy-admin/src/api/report.js index f4632503..44496df3 100644 --- a/neutrino-proxy-admin/src/api/report.js +++ b/neutrino-proxy-admin/src/api/report.js @@ -14,3 +14,27 @@ export function fetchLicenseFlowReportList(query) { params: query }) } + +export function fetchUserFlowMonthReportList(query) { + return request({ + url: '/report/user/flow-month-report/page', + method: 'get', + params: query + }) +} + +export function fetchLicenseFlowMonthReportList(query) { + return request({ + url: '/report/license/flow-month-report/page', + method: 'get', + params: query + }) +} + +export function homeData(query) { + return request({ + url: '/report/home/data-view', + method: 'get', + params: query + }) +} diff --git a/neutrino-proxy-admin/src/lang/zh.js b/neutrino-proxy-admin/src/lang/zh.js index 7fc4f215..b342fe7e 100644 --- a/neutrino-proxy-admin/src/lang/zh.js +++ b/neutrino-proxy-admin/src/lang/zh.js @@ -59,7 +59,9 @@ export default { clientConnectLog: '客户端连接日志', report: '报表管理', userFlowReport: '用户流量报表', - licenseFlowReport: 'License流量报表' + licenseFlowReport: 'License流量报表', + userFlowMonthReport: '用户流量月度明细', + licenseFlowMonthReport: 'License流量月度明细' }, navbar: { logOut: '退出登录', diff --git a/neutrino-proxy-admin/src/router/index.js b/neutrino-proxy-admin/src/router/index.js index 1dd444cf..8fc01e28 100644 --- a/neutrino-proxy-admin/src/router/index.js +++ b/neutrino-proxy-admin/src/router/index.js @@ -91,7 +91,9 @@ export const asyncRouterMap = [ }, children: [ { path: 'userFlowReport', component: _import('report/userFlowReport'), name: 'userFlowReport', meta: { title: 'userFlowReport' }}, - { path: 'licenseFlowReport', component: _import('report/licenseFlowReport'), name: 'licenseFlowReport', meta: { title: 'licenseFlowReport' }} + { path: 'licenseFlowReport', component: _import('report/licenseFlowReport'), name: 'licenseFlowReport', meta: { title: 'licenseFlowReport' }}, + { path: 'userFlowMonthReport', component: _import('report/userFlowMonthReport'), name: 'userFlowMonthReport', meta: { title: 'userFlowMonthReport' }}, + { path: 'licenseFlowMonthReport', component: _import('report/licenseFlowMonthReport'), name: 'licenseFlowMonthReport', meta: { title: 'licenseFlowMonthReport' }} ] }, { diff --git a/neutrino-proxy-admin/src/utils/utils.js b/neutrino-proxy-admin/src/utils/utils.js new file mode 100644 index 00000000..4a1bfb0f --- /dev/null +++ b/neutrino-proxy-admin/src/utils/utils.js @@ -0,0 +1,29 @@ +const SIZE_UNINTS = ['B', 'KB', 'MB', 'GB', 'TB'] +const SIZE_SYSTEM = 1024 +/** + * 根据字节数获取大小描述 + * 1、小于1024字节的以B为单位 + * 2、小于1024KB的以KB为单位 + * 3、小于1024M的以MB为单位 + * 4、小于1024G的以GB为单位 + * 5、其他以TB为单位 + */ +export function getSizeDescByByteCount(byteCount) { + if (byteCount <= 0) { + return '0B' + } + + let res = byteCount + let index = 0 + while (index < SIZE_UNINTS.length && res >= SIZE_SYSTEM) { + res /= SIZE_SYSTEM + index++ + } + + if (index >= SIZE_UNINTS.length) { + index = SIZE_UNINTS.length - 1 + res *= 1024 + } + + return parseFloat(res.toFixed(2)) + SIZE_UNINTS[index] +} diff --git a/neutrino-proxy-admin/src/views/home/admin/components/DailyTrafficChart.vue b/neutrino-proxy-admin/src/views/home/admin/components/DailyTrafficChart.vue index 74c7e7fc..37686327 100644 --- a/neutrino-proxy-admin/src/views/home/admin/components/DailyTrafficChart.vue +++ b/neutrino-proxy-admin/src/views/home/admin/components/DailyTrafficChart.vue @@ -5,6 +5,7 @@ @@ -127,9 +119,9 @@ export default { flex: 0 0 auto; } .pie-chart{ - padding-top: 16px; + padding-bottom: 16px; .el-card{ - min-height: 300px; + min-height: 250px; } } } diff --git a/neutrino-proxy-admin/src/views/log/clientConnectLog.vue b/neutrino-proxy-admin/src/views/log/clientConnectLog.vue index 45d3731f..0a607eab 100644 --- a/neutrino-proxy-admin/src/views/log/clientConnectLog.vue +++ b/neutrino-proxy-admin/src/views/log/clientConnectLog.vue @@ -1,6 +1,9 @@ + + +
+
+
+ + + + {{$t('table.search')}} +
+ + + + + + + + + + + + + + + + + + + +
+ + +
+
+ + + + + diff --git a/neutrino-proxy-admin/src/views/report/userFlowReport.vue b/neutrino-proxy-admin/src/views/report/userFlowReport.vue index 3447a6b6..06d4613f 100644 --- a/neutrino-proxy-admin/src/views/report/userFlowReport.vue +++ b/neutrino-proxy-admin/src/views/report/userFlowReport.vue @@ -29,6 +29,12 @@ {{scope.row.totalFlowDesc}} + + +
+ + + {{$t('table.search')}} {{$t('table.add')}}
@@ -39,6 +42,7 @@