├── jndc_client ├── jndc-client-backend │ └── src │ │ ├── main │ │ ├── resources │ │ │ ├── bin │ │ │ │ ├── start_jndc_client.cmd │ │ │ │ └── start_jndc_client.sh │ │ │ └── conf │ │ │ │ ├── config.template.yml │ │ │ │ └── logback.xml │ │ └── java │ │ │ └── jndc_client │ │ │ ├── web_support │ │ │ ├── utils │ │ │ │ └── ClientUrlConstant.java │ │ │ └── mapping │ │ │ │ └── ManageMapping.java │ │ │ ├── core │ │ │ ├── ClientDirectManager.java │ │ │ ├── JNDClientApp.java │ │ │ ├── ClientServiceDescription.java │ │ │ └── ClientScheduledTaskCenter.java │ │ │ └── start │ │ │ └── ClientStart.java │ │ └── test │ │ └── java │ │ └── jndc_client │ │ └── ClientTest.java └── pom.xml ├── jndc_server ├── jndc-server-frontend │ ├── public │ │ ├── grid.gif │ │ ├── favicon.ico │ │ ├── static │ │ │ └── runtimeConfig.js │ │ ├── tool_bar_icon │ │ │ ├── agg.png │ │ │ ├── max.png │ │ │ ├── min.png │ │ │ ├── sum.png │ │ │ ├── merge.png │ │ │ ├── average.png │ │ │ └── database.png │ │ └── index.html │ ├── src │ │ ├── assets │ │ │ └── logo.png │ │ ├── views │ │ │ ├── resourceNotFound.vue │ │ │ ├── item_detail │ │ │ │ ├── edg_operation │ │ │ │ │ └── action_edg.vue │ │ │ │ ├── data_source │ │ │ │ │ └── db_vertex.vue │ │ │ │ └── agg │ │ │ │ │ ├── max_vertex.vue │ │ │ │ │ ├── min_vertex.vue │ │ │ │ │ ├── sum_vertex.vue │ │ │ │ │ └── average_vertex.vue │ │ │ ├── rtc.vue │ │ │ └── management.vue │ │ ├── config │ │ │ ├── uiConfig.js │ │ │ ├── mxgraph.js │ │ │ ├── requestConfig.js │ │ │ ├── routeConfig.js │ │ │ ├── webSocketTool.js │ │ │ └── toolbar.js │ │ ├── main.js │ │ └── App.vue │ ├── README.md │ ├── vue.config.js │ └── package.json ├── jndc-server-backend │ └── src │ │ ├── main │ │ ├── resources │ │ │ ├── bin │ │ │ │ ├── shutdown.sh │ │ │ │ ├── startup.sh │ │ │ │ └── jndc-server.service │ │ │ └── conf │ │ │ │ ├── config.template.yml │ │ │ │ ├── db │ │ │ │ ├── migration_sqlite │ │ │ │ │ └── V1__init_tables.sql │ │ │ │ └── migration_mysql │ │ │ │ │ └── V1__init_tables.sql │ │ │ │ └── logback.xml │ │ └── java │ │ │ └── jndc_server │ │ │ ├── core │ │ │ ├── app │ │ │ │ ├── ServerApp.java │ │ │ │ └── JndcCoreServer.java │ │ │ ├── filter │ │ │ │ ├── CustomRule.java │ │ │ │ ├── IpAddressRule.java │ │ │ │ ├── AllowTimeRule.java │ │ │ │ └── CustomRulesFilter.java │ │ │ ├── ScheduledTaskCenter.java │ │ │ ├── TCPDataFlowAnalysisCenter.java │ │ │ ├── AsynchronousEventCenter.java │ │ │ └── JNDCServerApp.java │ │ │ ├── web_support │ │ │ ├── model │ │ │ │ ├── vo │ │ │ │ │ ├── IdVO.java │ │ │ │ │ ├── DeviceInfo.java │ │ │ │ │ ├── ChannelContextVO.java │ │ │ │ │ ├── HttpHostRouteVO.java │ │ │ │ │ ├── IpRecordVO.java │ │ │ │ │ └── PageListVO.java │ │ │ │ ├── dto │ │ │ │ │ ├── IpDTO.java │ │ │ │ │ ├── PageDTO.java │ │ │ │ │ ├── ClearRecordOptionDTO.java │ │ │ │ │ ├── ServiceBindDTO.java │ │ │ │ │ └── HostRouteDTO.java │ │ │ │ └── d_o │ │ │ │ │ └── HttpHostRoute.java │ │ │ ├── http_module │ │ │ │ ├── ServerRuntimeConfig.java │ │ │ │ ├── LiteProxyHandle.java │ │ │ │ ├── HostRouterComponent.java │ │ │ │ ├── HostRouteHandle.java │ │ │ │ ├── LiteHttpProxyPool.java │ │ │ │ ├── LiteHttpProxy.java │ │ │ │ └── JNDCHttpServer.java │ │ │ ├── utils │ │ │ │ ├── BlockValueFeature.java │ │ │ │ ├── AuthUtils.java │ │ │ │ └── ServerUrlConstant.java │ │ │ └── mapping │ │ │ │ └── DevelopDebugMapping.java │ │ │ ├── databases_object │ │ │ ├── IpFilterRule4V.java │ │ │ ├── IpFilterRecord.java │ │ │ ├── ChannelContextCloseRecord.java │ │ │ └── ServerPortBind.java │ │ │ ├── config │ │ │ └── DBConfig.java │ │ │ └── start │ │ │ └── ServerStart.java │ │ └── test │ │ └── java │ │ └── jndc_server │ │ └── exmaple │ │ ├── JacksonTest.java │ │ └── ServerTest.java └── pom.xml ├── jndc_core ├── src │ └── main │ │ └── java │ │ └── jndc │ │ ├── core │ │ ├── NDCApp.java │ │ ├── data_store_support │ │ │ ├── PageResult.java │ │ │ ├── DSKey.java │ │ │ ├── DSTable.java │ │ │ ├── DSFiled.java │ │ │ ├── MysqlDataStore.java │ │ │ ├── DBOperationI.java │ │ │ └── SQLiteDataStore.java │ │ ├── NDCConfigCenter.java │ │ ├── NettyComponentConfig.java │ │ ├── message │ │ │ ├── OpenChannelMessage.java │ │ │ ├── UserError.java │ │ │ ├── TcpServiceDescription.java │ │ │ └── RegistrationMessage.java │ │ ├── UniqueBeanManage.java │ │ ├── SecreteCodec.java │ │ └── NDCPCodec.java │ │ ├── exception │ │ └── SecreteDecodeFailException.java │ │ ├── utils │ │ ├── DataEncryption.java │ │ ├── StringUtils4V.java │ │ ├── UUIDSimple.java │ │ ├── ApplicationExit.java │ │ ├── BeanUtils.java │ │ ├── AESDataEncryption.java │ │ ├── OSUtils.java │ │ ├── ByteBufUtil4V.java │ │ ├── NettyContextUtils.java │ │ ├── RemoteLogAppender.java │ │ ├── HexUtils.java │ │ ├── ObjectSerializableUtils.java │ │ ├── ByteArrayUtils.java │ │ ├── LogPrint.java │ │ ├── YmlParser.java │ │ ├── UniqueInetTagProducer.java │ │ ├── AESUtils.java │ │ ├── JSONUtils.java │ │ ├── PathUtils.java │ │ ├── InetUtils.java │ │ ├── GetNetworkAddress.java │ │ └── ReflectionCache.java │ │ └── web_support │ │ ├── core │ │ ├── QueryKV.java │ │ ├── WebMapping.java │ │ ├── CustomSslHandler.java │ │ ├── JNDCRequestDecoder.java │ │ ├── WebSocketHandle.java │ │ ├── MessageNotificationCenter.java │ │ └── MappingRegisterCenter.java │ │ ├── model │ │ └── dto │ │ │ ├── LoginUser.java │ │ │ └── ResponseMessage.java │ │ ├── utils │ │ ├── SslOneWayContextFactory.java │ │ ├── AuthUtils.java │ │ └── UriUtils.java │ │ └── config │ │ ├── ServeHTTPConfig.java │ │ └── ServeManageConfig.java └── pom.xml ├── .gitignore ├── QA.md └── README_zh_cn.md /jndc_client/jndc-client-backend/src/main/resources/bin/start_jndc_client.cmd: -------------------------------------------------------------------------------- 1 | java -classpath "../lib/*" jndc_client.start.ClientStart -------------------------------------------------------------------------------- /jndc_client/jndc-client-backend/src/main/resources/bin/start_jndc_client.sh: -------------------------------------------------------------------------------- 1 | java -classpath "../lib/*" jndc_client.start.ClientStart -------------------------------------------------------------------------------- /jndc_server/jndc-server-frontend/public/grid.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiweiview/jndc/HEAD/jndc_server/jndc-server-frontend/public/grid.gif -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/core/NDCApp.java: -------------------------------------------------------------------------------- 1 | package jndc.core; 2 | 3 | public interface NDCApp { 4 | public void start(T config); 5 | } 6 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiweiview/jndc/HEAD/jndc_server/jndc-server-frontend/public/favicon.ico -------------------------------------------------------------------------------- /jndc_server/jndc-server-frontend/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiweiview/jndc/HEAD/jndc_server/jndc-server-frontend/src/assets/logo.png -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/resources/bin/shutdown.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ps -ef | grep jndc | grep -v grep | awk '{print $2}' | xargs kill -9 4 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-frontend/public/static/runtimeConfig.js: -------------------------------------------------------------------------------- 1 | window.runtimeConfig = { 2 | BASE_REQUEST_PATH: '', 3 | BASE_WEBSOCKET_PATH: '' 4 | } 5 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-frontend/public/tool_bar_icon/agg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiweiview/jndc/HEAD/jndc_server/jndc-server-frontend/public/tool_bar_icon/agg.png -------------------------------------------------------------------------------- /jndc_server/jndc-server-frontend/public/tool_bar_icon/max.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiweiview/jndc/HEAD/jndc_server/jndc-server-frontend/public/tool_bar_icon/max.png -------------------------------------------------------------------------------- /jndc_server/jndc-server-frontend/public/tool_bar_icon/min.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiweiview/jndc/HEAD/jndc_server/jndc-server-frontend/public/tool_bar_icon/min.png -------------------------------------------------------------------------------- /jndc_server/jndc-server-frontend/public/tool_bar_icon/sum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiweiview/jndc/HEAD/jndc_server/jndc-server-frontend/public/tool_bar_icon/sum.png -------------------------------------------------------------------------------- /jndc_server/jndc-server-frontend/public/tool_bar_icon/merge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiweiview/jndc/HEAD/jndc_server/jndc-server-frontend/public/tool_bar_icon/merge.png -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/exception/SecreteDecodeFailException.java: -------------------------------------------------------------------------------- 1 | package jndc.exception; 2 | 3 | public class SecreteDecodeFailException extends RuntimeException{ 4 | } 5 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-frontend/public/tool_bar_icon/average.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiweiview/jndc/HEAD/jndc_server/jndc-server-frontend/public/tool_bar_icon/average.png -------------------------------------------------------------------------------- /jndc_server/jndc-server-frontend/public/tool_bar_icon/database.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiweiview/jndc/HEAD/jndc_server/jndc-server-frontend/public/tool_bar_icon/database.png -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/core/app/ServerApp.java: -------------------------------------------------------------------------------- 1 | package jndc_server.core.app; 2 | 3 | public interface ServerApp { 4 | public void start(); 5 | } 6 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/utils/DataEncryption.java: -------------------------------------------------------------------------------- 1 | package jndc.utils; 2 | 3 | public interface DataEncryption { 4 | public byte[] encode(byte[] bytes); 5 | 6 | public byte[] decode(byte[] bytes); 7 | } 8 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/utils/StringUtils4V.java: -------------------------------------------------------------------------------- 1 | package jndc.utils; 2 | 3 | public class StringUtils4V { 4 | 5 | public static boolean isBlank(String s){ 6 | return s==null||"".equals(s); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/resources/bin/startup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source /etc/profile 4 | 5 | nohup /data/jdk8/bin/java -classpath "../lib/*" jndc_server.start.ServerStart >>/data/app/jndc-server/bin/nohup.out 2>&1 & 6 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/web_support/core/QueryKV.java: -------------------------------------------------------------------------------- 1 | package jndc.web_support.core; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class QueryKV { 7 | private String key; 8 | 9 | private String value; 10 | } 11 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/utils/UUIDSimple.java: -------------------------------------------------------------------------------- 1 | package jndc.utils; 2 | 3 | import java.util.UUID; 4 | 5 | public class UUIDSimple { 6 | public static String id(){ 7 | return UUID.randomUUID().toString().replaceAll("-",""); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-frontend/src/views/resourceNotFound.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | 11 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/web_support/model/dto/LoginUser.java: -------------------------------------------------------------------------------- 1 | package jndc.web_support.model.dto; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class LoginUser { 7 | private String name; 8 | 9 | private String passWord; 10 | 11 | 12 | } 13 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-frontend/README.md: -------------------------------------------------------------------------------- 1 | ![J NDC](https://s1.ax1x.com/2020/11/04/B6HETJ.png) 2 | 3 | ## 介绍 4 | * [JNDC](https://github.com/qiweiview/jndc) 的项目的默认的前端实现 5 | * 基于[vue](https://cn.vuejs.org/index.html) 编写 6 | * UI框架使用[element ui](https://element.eleme.io/) 7 | 8 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-frontend/src/config/uiConfig.js: -------------------------------------------------------------------------------- 1 | import ElementUI from 'element-ui' 2 | import 'element-ui/lib/theme-chalk/index.css' 3 | import cn from 'element-ui/lib/locale/lang/zh-CN' // lang i18n 4 | import Vue from 'vue' 5 | 6 | 7 | Vue.use(ElementUI, {cn}) 8 | 9 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/core/data_store_support/PageResult.java: -------------------------------------------------------------------------------- 1 | package jndc.core.data_store_support; 2 | 3 | import lombok.Data; 4 | 5 | import java.util.List; 6 | 7 | @Data 8 | public class PageResult { 9 | private List data; 10 | 11 | private int total; 12 | 13 | 14 | } 15 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/utils/ApplicationExit.java: -------------------------------------------------------------------------------- 1 | package jndc.utils; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | @Slf4j 6 | public class ApplicationExit { 7 | 8 | 9 | public static void exit() { 10 | log.error("应用即将退出..."); 11 | System.exit(1); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-frontend/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import router from "@/config/routeConfig"; 4 | import '@/config/uiConfig' 5 | 6 | Vue.config.productionTip = false 7 | 8 | 9 | new Vue({ 10 | render: h => h(App), 11 | router 12 | }).$mount('#app') 13 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/core/NDCConfigCenter.java: -------------------------------------------------------------------------------- 1 | package jndc.core; 2 | 3 | 4 | public interface NDCConfigCenter { 5 | 6 | public void addMessageToSendQueue(NDCMessageProtocol ndcMessageProtocol); 7 | 8 | public void addMessageToReceiveQueue(NDCMessageProtocol ndcMessageProtocol); 9 | 10 | 11 | } 12 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/utils/BeanUtils.java: -------------------------------------------------------------------------------- 1 | package jndc.utils; 2 | 3 | public class BeanUtils { 4 | 5 | 6 | public static T copyValue(Object from,Class tClass){ 7 | String s = JSONUtils.object2JSONString(from); 8 | T t = JSONUtils.str2Object(s, tClass); 9 | return t; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/core/NettyComponentConfig.java: -------------------------------------------------------------------------------- 1 | package jndc.core; 2 | 3 | import io.netty.channel.nio.NioEventLoopGroup; 4 | 5 | /** 6 | * 组件统一替换 7 | */ 8 | public class NettyComponentConfig { 9 | 10 | public static NioEventLoopGroup getNioEventLoopGroup(){ 11 | return new NioEventLoopGroup(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/web_support/model/vo/IdVO.java: -------------------------------------------------------------------------------- 1 | package jndc_server.web_support.model.vo; 2 | 3 | public class IdVO { 4 | private String id; 5 | 6 | public String getId() { 7 | return id; 8 | } 9 | 10 | public void setId(String id) { 11 | this.id = id; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/web_support/model/vo/DeviceInfo.java: -------------------------------------------------------------------------------- 1 | package jndc_server.web_support.model.vo; 2 | 3 | public class DeviceInfo { 4 | private String ip; 5 | 6 | public String getIp() { 7 | return ip; 8 | } 9 | 10 | public void setIp(String ip) { 11 | this.ip = ip; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /jndc_client/jndc-client-backend/src/main/java/jndc_client/web_support/utils/ClientUrlConstant.java: -------------------------------------------------------------------------------- 1 | package jndc_client.web_support.utils; 2 | 3 | public class ClientUrlConstant { 4 | public interface Management { 5 | public static final String login = "/login";//登录 6 | 7 | public static final String userInfo = "/userInfo";//用户信息 8 | 9 | 10 | } 11 | 12 | 13 | } 14 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/utils/AESDataEncryption.java: -------------------------------------------------------------------------------- 1 | package jndc.utils; 2 | 3 | 4 | public class AESDataEncryption implements DataEncryption{ 5 | 6 | 7 | @Override 8 | public byte[] encode(byte[] bytes) { 9 | return AESUtils.encode(bytes); 10 | } 11 | 12 | @Override 13 | public byte[] decode(byte[] bytes) { 14 | return AESUtils.decode(bytes); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/web_support/http_module/ServerRuntimeConfig.java: -------------------------------------------------------------------------------- 1 | package jndc_server.web_support.http_module; 2 | 3 | public class ServerRuntimeConfig { 4 | public static boolean DEBUG_MODEL=false;//only be changed on runtime,init value must be false 5 | 6 | public static String ROUTE_NOT_FOUND_CONTENT="\uD83D\uDEEB\uD83D\uDEEB\uD83D\uDEEBNot Found"; 7 | 8 | 9 | } 10 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/core/data_store_support/DSKey.java: -------------------------------------------------------------------------------- 1 | package jndc.core.data_store_support; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target({ElementType.FIELD}) 10 | public @interface DSKey { 11 | String name() default ""; 12 | } 13 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/core/filter/CustomRule.java: -------------------------------------------------------------------------------- 1 | package jndc_server.core.filter; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | 5 | public interface CustomRule { 6 | 7 | /** 8 | * 规则确认 9 | * 10 | * @param context 11 | * @return 12 | */ 13 | public String ruleCheck(ChannelHandlerContext context); 14 | 15 | 16 | public String getRuleName(); 17 | } 18 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/core/data_store_support/DSTable.java: -------------------------------------------------------------------------------- 1 | package jndc.core.data_store_support; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target({ElementType.TYPE}) 10 | public @interface DSTable { 11 | String name() default ""; 12 | 13 | } 14 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/core/message/OpenChannelMessage.java: -------------------------------------------------------------------------------- 1 | package jndc.core.message; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * 隧道开通消息 9 | */ 10 | @Data 11 | public class OpenChannelMessage implements Serializable { 12 | private static final long serialVersionUID = 7315766480559203141L; 13 | 14 | private String auth; 15 | 16 | private String channelId; 17 | 18 | 19 | } 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build outputs 2 | /target/ 3 | **/target/ 4 | 5 | # IDE files 6 | /.idea/ 7 | **/*.iml 8 | 9 | # Node.js 10 | **/node_modules/ 11 | **/package-lock.json 12 | **/node/ 13 | 14 | # Database files 15 | **/*.db 16 | 17 | # Logs 18 | /log/ 19 | *.log 20 | 21 | # Client specific 22 | /CLIENT_ID 23 | **/client_id 24 | **/config_file/ 25 | 26 | # Frontend build 27 | **/compare_dist/ 28 | 29 | # Configuration files 30 | **/config.yml 31 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/utils/OSUtils.java: -------------------------------------------------------------------------------- 1 | package jndc.utils; 2 | 3 | public class OSUtils { 4 | private static volatile String os; 5 | 6 | 7 | public static boolean isLinux() { 8 | if (os == null) { 9 | os = System.getProperty("os.name"); 10 | } 11 | 12 | if (os.toLowerCase().indexOf("win") != -1) { 13 | return false; 14 | } 15 | return true; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/core/message/UserError.java: -------------------------------------------------------------------------------- 1 | package jndc.core.message; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | 7 | 8 | @Data 9 | public class UserError implements Serializable { 10 | public static final int SERVER_ERROR = 500; 11 | 12 | private static final long serialVersionUID = 2996922883540744896L; 13 | 14 | private int code; 15 | 16 | private String description; 17 | 18 | 19 | } 20 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/web_support/core/WebMapping.java: -------------------------------------------------------------------------------- 1 | package jndc.web_support.core; 2 | 3 | 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | @Target({ElementType.METHOD, ElementType.TYPE}) 10 | @Retention(RetentionPolicy.RUNTIME) 11 | public @interface WebMapping { 12 | String path() default ""; 13 | } 14 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-frontend/vue.config.js: -------------------------------------------------------------------------------- 1 | // vue.config.js 2 | module.exports = { 3 | //assetsDir: 'static', 4 | outputDir: 'compare_dist', 5 | devServer: { 6 | port: 778, 7 | proxy: { 8 | '/': { 9 | target: 'https://qw607.com:4477', // 接口域名 10 | secure: false, // 如果是https接口,需要配置这个参数 11 | changeOrigin: true, //是否跨域 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/web_support/model/vo/ChannelContextVO.java: -------------------------------------------------------------------------------- 1 | package jndc_server.web_support.model.vo; 2 | 3 | 4 | import lombok.Data; 5 | 6 | @Data 7 | public class ChannelContextVO { 8 | 9 | private String id; 10 | 11 | private int supportServiceNum; 12 | 13 | private int channelClientPort; 14 | 15 | private String channelClientIp; 16 | 17 | private long lastHearBeatTimeStamp; 18 | 19 | 20 | } 21 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/core/data_store_support/DSFiled.java: -------------------------------------------------------------------------------- 1 | package jndc.core.data_store_support; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target({ElementType.FIELD}) 10 | public @interface DSFiled { 11 | String name() default ""; 12 | 13 | boolean useFiled() default true; 14 | } 15 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/utils/ByteBufUtil4V.java: -------------------------------------------------------------------------------- 1 | package jndc.utils; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.buffer.ByteBufUtil; 5 | import io.netty.buffer.Unpooled; 6 | import io.netty.buffer.UnpooledByteBufAllocator; 7 | 8 | public class ByteBufUtil4V { 9 | public static byte[] readWithRelease( ByteBuf byteBuf){ 10 | byte[] bytes = ByteBufUtil.getBytes(byteBuf); 11 | byteBuf.discardReadBytes(); 12 | byteBuf.release(); 13 | return bytes; 14 | } 15 | 16 | 17 | } 18 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/web_support/model/dto/IpDTO.java: -------------------------------------------------------------------------------- 1 | package jndc_server.web_support.model.dto; 2 | 3 | public class IpDTO { 4 | private String id; 5 | private String ip; 6 | 7 | 8 | public String getId() { 9 | return id; 10 | } 11 | 12 | public void setId(String id) { 13 | this.id = id; 14 | } 15 | 16 | public String getIp() { 17 | return ip; 18 | } 19 | 20 | public void setIp(String ip) { 21 | this.ip = ip; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /QA.md: -------------------------------------------------------------------------------- 1 | # 常见问题 2 | 3 | ## Q:java.lang.NoClassDefFoundError: javafx/application/Application 无法加载类 4 | * jdk11 后将javafx独立成一个模块 5 | * 解决方法一:单独引入javafx 6 | ``` 7 | 8 | 9 | org.openjfx 10 | javafx 11 | 11 12 | pom 13 | 14 | 15 | ``` 16 | * 解决方法二:降低运行环境jre版本至8-10(本项目使用jdk8执行构建编译) 17 | 18 | ## Q:为什么协议直接定死了IPV4,不能兼容IPV6吗 19 | * 作者认为穿透根本是解决IPV4地址不足造成的访问不可到达问题,若使用IPV6则不存在以上问题。 -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/web_support/model/dto/PageDTO.java: -------------------------------------------------------------------------------- 1 | package jndc_server.web_support.model.dto; 2 | 3 | public class PageDTO { 4 | private int page; 5 | private int rows; 6 | 7 | public int getPage() { 8 | return page; 9 | } 10 | 11 | public void setPage(int page) { 12 | this.page = page; 13 | } 14 | 15 | public int getRows() { 16 | return rows; 17 | } 18 | 19 | public void setRows(int rows) { 20 | this.rows = rows; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/resources/bin/jndc-server.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=jndc-server 3 | After=network.target 4 | StartLimitIntervalSec=0 5 | 6 | [Service] 7 | User=app 8 | Group=app 9 | Type=forking 10 | Restart=always 11 | RestartSec=1 12 | Environment=JAVA_HOME=/data/jdk8 13 | WorkingDirectory=/data/app/jndc-server/bin 14 | ExecStart=/data/app/jndc-server/bin/startup.sh 15 | ExecReload=/data/app/jndc-server/bin/shutdown.sh 16 | ExecStop=/data/app/jndc-server/bin/shutdown.sh 17 | PrivateTmp=true 18 | SuccessExitStatus=143 19 | 20 | [Install] 21 | 22 | WantedBy=multi-user.target -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/web_support/model/vo/HttpHostRouteVO.java: -------------------------------------------------------------------------------- 1 | package jndc_server.web_support.model.vo; 2 | 3 | 4 | import lombok.Data; 5 | 6 | @Data 7 | public class HttpHostRouteVO { 8 | 9 | private String id; 10 | 11 | private String hostKeyWord; 12 | 13 | private int routeType;//0 do redirect 1 return fixed value 14 | 15 | private String fixedResponse; 16 | 17 | private String redirectAddress; 18 | 19 | private String fixedContentType; 20 | 21 | private String forwardHost; 22 | 23 | private int forwardPort; 24 | 25 | private String forwardProtocol; 26 | 27 | 28 | } 29 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/core/message/TcpServiceDescription.java: -------------------------------------------------------------------------------- 1 | package jndc.core.message; 2 | 3 | 4 | 5 | import lombok.Data; 6 | 7 | import java.io.Serializable; 8 | 9 | 10 | /** 11 | * 服务描述 12 | */ 13 | @Data 14 | public class TcpServiceDescription implements Serializable { 15 | 16 | 17 | private static final long serialVersionUID = -6570101717300836163L; 18 | 19 | //服务编号 20 | private String id; 21 | 22 | //本地客户端服务端口 23 | private int servicePort; 24 | 25 | //本地客户端服务ip 26 | private String serviceIp; 27 | 28 | //服务名称 29 | private String serviceName; 30 | 31 | //服务描述 32 | private String description; 33 | 34 | 35 | } 36 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/utils/NettyContextUtils.java: -------------------------------------------------------------------------------- 1 | package jndc.utils; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | 5 | import java.net.InetSocketAddress; 6 | 7 | 8 | public class NettyContextUtils { 9 | 10 | /** 11 | * 获取隧道指纹 12 | * 13 | * @param channelHandlerContext 14 | * @return 15 | */ 16 | public static String getFingerprintFromContext(ChannelHandlerContext channelHandlerContext) { 17 | InetSocketAddress socketAddress = (InetSocketAddress) channelHandlerContext.channel().remoteAddress(); 18 | //todo ip+端口 19 | return socketAddress.getHostString() + socketAddress.getPort(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-frontend/src/config/mxgraph.js: -------------------------------------------------------------------------------- 1 | import mx from 'mxgraph'; 2 | 3 | const mxgraph = mx({ 4 | mxImageBasePath: './src/images', 5 | mxBasePath: './src' 6 | }); 7 | // decode bug https://github.com/jgraph/mxgraph/issues/49 8 | window.mxGraph = mxgraph.mxGraph; 9 | window.mxGraphModel = mxgraph.mxGraphModel; 10 | window.mxEditor = mxgraph.mxEditor; 11 | window.mxGeometry = mxgraph.mxGeometry; 12 | window.mxDefaultKeyHandler = mxgraph.mxDefaultKeyHandler; 13 | window.mxDefaultPopupMenu = mxgraph.mxDefaultPopupMenu; 14 | window.mxStylesheet = mxgraph.mxStylesheet; 15 | window.mxDefaultToolbar = mxgraph.mxDefaultToolbar; 16 | 17 | export default mxgraph; 18 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/utils/RemoteLogAppender.java: -------------------------------------------------------------------------------- 1 | package jndc.utils; 2 | 3 | import ch.qos.logback.classic.spi.ILoggingEvent; 4 | import ch.qos.logback.core.AppenderBase; 5 | 6 | 7 | /** 8 | * 远程日志记录 9 | */ 10 | public class RemoteLogAppender extends AppenderBase { 11 | public static final String NAME = "RemoteLogAppender"; 12 | 13 | 14 | @Override 15 | public String getName() { 16 | return NAME; 17 | } 18 | 19 | 20 | @Override 21 | protected void append(ILoggingEvent iLoggingEvent) { 22 | //todo 日志发送至远程 23 | // System.out.println("RemoteLogAppender:" + iLoggingEvent); 24 | 25 | } 26 | 27 | 28 | } 29 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/databases_object/IpFilterRule4V.java: -------------------------------------------------------------------------------- 1 | package jndc_server.databases_object; 2 | 3 | import jndc.core.data_store_support.DSKey; 4 | import jndc.core.data_store_support.DSTable; 5 | import lombok.Data; 6 | 7 | @Data 8 | @DSTable(name = "server_ip_filter_rule") 9 | public class IpFilterRule4V { 10 | @DSKey 11 | private String id; 12 | 13 | private String ip; 14 | 15 | private int type; //0 white 1 black 16 | 17 | public void black(){ 18 | this.type=1; 19 | } 20 | 21 | public void white(){ 22 | this.type=0; 23 | } 24 | 25 | public boolean isBlack(){ 26 | return type==1; 27 | } 28 | 29 | 30 | } 31 | -------------------------------------------------------------------------------- /jndc_server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | jndc 7 | org.view 8 | 1.0 9 | 10 | 4.0.0 11 | 12 | jndc_server 13 | pom 14 | 15 | jndc-server-backend 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /jndc_client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | jndc 7 | org.view 8 | 1.0 9 | 10 | 11 | 12 | 4.0.0 13 | 14 | jndc_client 15 | pom 16 | 17 | jndc-client-backend 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/web_support/core/CustomSslHandler.java: -------------------------------------------------------------------------------- 1 | package jndc.web_support.core; 2 | 3 | 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.handler.ssl.SslHandler; 6 | import lombok.extern.slf4j.Slf4j; 7 | 8 | import javax.net.ssl.SSLEngine; 9 | 10 | @Slf4j 11 | public class CustomSslHandler extends SslHandler { 12 | 13 | 14 | public static String NAME = "CUSTOM_SSL_HANDLER"; 15 | 16 | 17 | public CustomSslHandler(SSLEngine engine) { 18 | super(engine); 19 | } 20 | 21 | 22 | @Override 23 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 24 | log.error("ssl error" + cause); 25 | ctx.close(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-frontend/src/App.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 20 | 21 | 34 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-frontend/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= htmlWebpackPlugin.options.title %> 9 | 10 | 11 | 12 | 16 |
17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/web_support/model/vo/IpRecordVO.java: -------------------------------------------------------------------------------- 1 | package jndc_server.web_support.model.vo; 2 | 3 | public class IpRecordVO { 4 | private String ip; 5 | private int count; 6 | private long lastTimeStamp; 7 | 8 | public String getIp() { 9 | return ip; 10 | } 11 | 12 | public void setIp(String ip) { 13 | this.ip = ip; 14 | } 15 | 16 | public int getCount() { 17 | return count; 18 | } 19 | 20 | public void setCount(int count) { 21 | this.count = count; 22 | } 23 | 24 | public long getLastTimeStamp() { 25 | return lastTimeStamp; 26 | } 27 | 28 | public void setLastTimeStamp(long lastTimeStamp) { 29 | this.lastTimeStamp = lastTimeStamp; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /jndc_client/jndc-client-backend/src/main/resources/conf/config.template.yml: -------------------------------------------------------------------------------- 1 | secrete: "your-secret-key-here" # 服务端密钥,用于客户端认证,请务必修改为安全的密钥 2 | loglevel: "info" # 日志级别,可选值:debug, info, warn, error 3 | serverIp: "your-server-ip" # 服务端监听IP地址 4 | serverPort: "81" # 服务端监听端口 5 | autoReleaseTimeOut: 600000 # 客户端空闲超时自动断开时间(毫秒) 6 | 7 | clientServiceDescriptions: # 客户端服务配置列表 8 | - serviceName: "example-service" # 服务名称 9 | serviceIp: "example.com" # 服务域名或IP 10 | servicePort: "80" # 服务端口 11 | serviceEnable: false # 是否启用该服务 12 | 13 | manageConfig: # 管理控制台配置 14 | managementApiPort: 777 # 管理API端口 15 | useSsl: false # 是否启用SSL加密 16 | jksPath: "path/to/your/certificate.jks" # SSL证书路径 17 | jksPass: "your-jks-password" # SSL证书密码 18 | loginName: "admin" # 管理控制台登录用户名 19 | loginPassWord: "your-password" # 管理控制台登录密码 20 | adminEnable: false # 是否启用管理控制台 -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/core/message/RegistrationMessage.java: -------------------------------------------------------------------------------- 1 | package jndc.core.message; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.util.List; 7 | 8 | /** 9 | * 服务注册消息 10 | */ 11 | @Data 12 | public class RegistrationMessage implements Serializable { 13 | 14 | private static final long serialVersionUID = 2323315614144754699L; 15 | 16 | public transient static final byte TYPE_REGISTER = 0x00; 17 | 18 | public transient static final byte TYPE_UNREGISTER = 0x01; 19 | 20 | 21 | private byte type; 22 | 23 | private String auth; 24 | 25 | private List tcpServiceDescriptions; 26 | 27 | private String message; 28 | 29 | //客户端唯一编号 30 | private String channelId; 31 | 32 | public RegistrationMessage(byte type) { 33 | this.type = type; 34 | } 35 | 36 | 37 | 38 | } 39 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/utils/HexUtils.java: -------------------------------------------------------------------------------- 1 | package jndc.utils; 2 | 3 | 4 | import java.nio.ByteBuffer; 5 | 6 | public class HexUtils { 7 | 8 | 9 | /** 10 | * return byte array with fix size 4 11 | * @param i 12 | * @return 13 | */ 14 | public static byte[] int2ByteArray(int i){ 15 | ByteBuffer allocate = ByteBuffer.allocate(4); 16 | byte[] array =allocate.putInt(i).array(); 17 | return array; 18 | } 19 | 20 | /** 21 | * accept a fix length byte array 22 | * @param bytes 23 | * @return 24 | */ 25 | public static int byteArray2Int(byte[] bytes){ 26 | if (bytes.length!=4){ 27 | throw new RuntimeException("not a int value"); 28 | } 29 | ByteBuffer wrap = ByteBuffer.wrap(bytes); 30 | int anInt = wrap.getInt(); 31 | return anInt; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/config/DBConfig.java: -------------------------------------------------------------------------------- 1 | package jndc_server.config; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class DBConfig { 7 | 8 | private static final String TYPE_MYSQL = "mysql"; 9 | 10 | private static final String TYPE_SQLITE = "sqlite"; 11 | 12 | /** 13 | * 类型 14 | * mysql 15 | * sqlite 16 | */ 17 | private String type; 18 | 19 | /** 20 | * 21 | */ 22 | private String url; 23 | 24 | /** 25 | * 26 | */ 27 | private String name; 28 | 29 | /** 30 | * 31 | */ 32 | private String password; 33 | 34 | private boolean flywayEnable; 35 | 36 | public boolean useMysql() { 37 | String type = getType(); 38 | if (type == null) { 39 | return false; 40 | } 41 | 42 | return TYPE_MYSQL.equals(type.toLowerCase()); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /jndc_client/jndc-client-backend/src/main/java/jndc_client/core/ClientDirectManager.java: -------------------------------------------------------------------------------- 1 | package jndc_client.core; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | import java.io.File; 6 | 7 | @Slf4j 8 | public class ClientDirectManager { 9 | public static String basePath; 10 | 11 | public static String ymlConfig; 12 | 13 | public static String idPath; 14 | 15 | 16 | static { 17 | basePath = System.getProperty("user.dir"); 18 | 19 | ymlConfig = basePath + File.separator + ".." + File.separator + "conf" + File.separator + "config.yml"; 20 | 21 | idPath = basePath + File.separator + ".." + File.separator + "conf" + File.separator + "client_id"; 22 | 23 | 24 | log.info("=======================使用以下路径启动======================="); 25 | log.info("basePath: " + basePath); 26 | log.info("ymlConfig: " + ymlConfig); 27 | log.info("idPath: " + idPath); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/databases_object/IpFilterRecord.java: -------------------------------------------------------------------------------- 1 | package jndc_server.databases_object; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import jndc.core.data_store_support.DSFiled; 6 | import jndc.core.data_store_support.DSKey; 7 | import jndc.core.data_store_support.DSTable; 8 | import lombok.Data; 9 | 10 | @Data 11 | @JsonIgnoreProperties(ignoreUnknown = true) 12 | @DSTable(name = "ip_filter_record") 13 | public class IpFilterRecord { 14 | 15 | @DSKey 16 | private String id; 17 | 18 | private String ip; 19 | 20 | @DSFiled(name = "v_count") 21 | @JsonProperty("vCount") 22 | private int vCount; 23 | 24 | @DSFiled(name = "time_stamp") 25 | private long timeStamp; 26 | 27 | @DSFiled(name = "record_type") 28 | @JsonProperty("recordType") 29 | private int recordType; 30 | 31 | 32 | } 33 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/web_support/model/vo/PageListVO.java: -------------------------------------------------------------------------------- 1 | package jndc_server.web_support.model.vo; 2 | 3 | import java.util.List; 4 | 5 | public class PageListVO { 6 | private int page; 7 | private int rows; 8 | private int total; 9 | private List data; 10 | 11 | public int getPage() { 12 | return page; 13 | } 14 | 15 | public void setPage(int page) { 16 | this.page = page; 17 | } 18 | 19 | public int getRows() { 20 | return rows; 21 | } 22 | 23 | public void setRows(int rows) { 24 | this.rows = rows; 25 | } 26 | 27 | public int getTotal() { 28 | return total; 29 | } 30 | 31 | public void setTotal(int total) { 32 | this.total = total; 33 | } 34 | 35 | public List getData() { 36 | return data; 37 | } 38 | 39 | public void setData(List data) { 40 | this.data = data; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/web_support/model/dto/ResponseMessage.java: -------------------------------------------------------------------------------- 1 | package jndc.web_support.model.dto; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class ResponseMessage { 7 | private int code = 0; 8 | 9 | private String message = "操作成功"; 10 | 11 | private Object data; 12 | 13 | public static ResponseMessage success(Object data) { 14 | ResponseMessage responseMessage = new ResponseMessage(); 15 | responseMessage.setData(data); 16 | return responseMessage; 17 | 18 | } 19 | 20 | public static ResponseMessage fail(String message) { 21 | ResponseMessage responseMessage = new ResponseMessage(); 22 | responseMessage.setCode(-1); 23 | responseMessage.setMessage(message); 24 | return responseMessage; 25 | 26 | } 27 | 28 | public void error() { 29 | code = 500; 30 | } 31 | 32 | public void error(String message) { 33 | error(); 34 | setMessage(message); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /jndc_client/jndc-client-backend/src/main/resources/conf/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n 8 | utf-8 9 | 10 | output.log 11 | 12 | jndc_output.log.%i 13 | 14 | 15 | 5MB 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/utils/ObjectSerializableUtils.java: -------------------------------------------------------------------------------- 1 | package jndc.utils; 2 | 3 | 4 | import java.io.*; 5 | 6 | public class ObjectSerializableUtils implements Serializable { 7 | 8 | 9 | public static byte[] object2bytes(Object obj) { 10 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 11 | try { 12 | ObjectOutputStream os = new ObjectOutputStream(out); 13 | os.writeObject(obj); 14 | return out.toByteArray(); 15 | } catch (IOException e) { 16 | throw new RuntimeException(e); 17 | } 18 | } 19 | 20 | 21 | public static T bytes2object(byte[] data, Class tClass) { 22 | ByteArrayInputStream in = new ByteArrayInputStream(data); 23 | ObjectInputStream is = null; 24 | try { 25 | is = new ObjectInputStream(in); 26 | Object o = is.readObject(); 27 | return (T) o; 28 | } catch (Exception e) { 29 | throw new RuntimeException(e); 30 | } 31 | 32 | } 33 | 34 | 35 | 36 | 37 | 38 | 39 | } -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/utils/ByteArrayUtils.java: -------------------------------------------------------------------------------- 1 | package jndc.utils; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | 7 | public class ByteArrayUtils { 8 | 9 | /** 10 | * covert a large package to much little package 11 | * @param bytes 12 | * @param length 13 | * @return 14 | */ 15 | public static List bytesUnpack(byte[] bytes, int length) { 16 | List list = new ArrayList<>(); 17 | int maxLength = bytes.length; 18 | 19 | if (maxLength <= length) { 20 | list.add(bytes); 21 | } else { 22 | int s = 0; 23 | int e = 0; 24 | while (true) { 25 | e = e + length; 26 | if (e > maxLength) { 27 | e = maxLength; 28 | } 29 | if (s == e) { 30 | break; 31 | } 32 | list.add(Arrays.copyOfRange(bytes, s, e)); 33 | s = e; 34 | } 35 | } 36 | return list; 37 | 38 | } 39 | 40 | 41 | } 42 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/core/ScheduledTaskCenter.java: -------------------------------------------------------------------------------- 1 | package jndc_server.core; 2 | 3 | import io.netty.channel.EventLoopGroup; 4 | import jndc.core.NettyComponentConfig; 5 | import jndc.core.UniqueBeanManage; 6 | import jndc_server.core.filter.IpChecker; 7 | 8 | import java.util.concurrent.TimeUnit; 9 | 10 | /** 11 | * 定时任务中心 12 | */ 13 | public class ScheduledTaskCenter { 14 | private EventLoopGroup eventLoopGroup = NettyComponentConfig.getNioEventLoopGroup(); 15 | 16 | 17 | public void start() { 18 | 19 | //记录ip访问日志 20 | IpChecker ipChecker = UniqueBeanManage.getBean(IpChecker.class); 21 | eventLoopGroup.scheduleWithFixedDelay(() -> { 22 | ipChecker.storeRecordData(); 23 | }, 0, 1, TimeUnit.HOURS); 24 | 25 | 26 | //检查通道心跳 27 | NDCServerConfigCenter ndcServerConfigCenter = UniqueBeanManage.getBean(NDCServerConfigCenter.class); 28 | eventLoopGroup.scheduleWithFixedDelay(() -> { 29 | ndcServerConfigCenter.checkChannelHealthy(); 30 | }, 0, 5, TimeUnit.MINUTES); 31 | 32 | 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/core/UniqueBeanManage.java: -------------------------------------------------------------------------------- 1 | package jndc.core; 2 | 3 | 4 | import lombok.extern.slf4j.Slf4j; 5 | 6 | import java.util.Map; 7 | import java.util.concurrent.ConcurrentHashMap; 8 | 9 | /** 10 | * simple object management,can use spring or other tools replace 11 | */ 12 | @Slf4j 13 | public class UniqueBeanManage { 14 | 15 | private static Map map = new ConcurrentHashMap<>(); 16 | 17 | public static T getBean(Class tClass) { 18 | Object o = map.get(tClass); 19 | if (o == null) { 20 | log.error("can not find the bean " + tClass); 21 | throw new RuntimeException("no matching bean "+tClass); 22 | } 23 | return (T) o; 24 | } 25 | 26 | 27 | 28 | 29 | 30 | public static void registerBean(Object o) { 31 | registerBean(o.getClass(), o); 32 | } 33 | 34 | public static void registerBean(Class tClass, Object o) { 35 | 36 | Object o1 = map.get(tClass); 37 | if (o1 != null) { 38 | throw new RuntimeException("exist a bean " + o1); 39 | } 40 | 41 | map.put(tClass, o); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/utils/LogPrint.java: -------------------------------------------------------------------------------- 1 | package jndc.utils; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | 6 | @Slf4j 7 | public class LogPrint { 8 | 9 | public static void info(Object msg, Object source){ 10 | if (source!=null){ 11 | 12 | } 13 | if (msg==null){ 14 | msg=""; 15 | } 16 | log.info(msg.toString()); 17 | } 18 | 19 | public static void info(Object msg){ 20 | info(msg,null); 21 | } 22 | 23 | public static void err(Object msg, Object source){ 24 | if (source!=null){ 25 | 26 | } 27 | if (msg==null){ 28 | msg=""; 29 | } 30 | log.error(msg.toString()); 31 | } 32 | 33 | public static void err(Object msg){ 34 | err(msg,null); 35 | } 36 | 37 | public static void debug(Object msg) { 38 | log.debug(msg.toString()); 39 | } 40 | 41 | public static void debug(Object msg, Object source){ 42 | if (source!=null){ 43 | 44 | } 45 | if (msg==null){ 46 | msg=""; 47 | } 48 | log.debug(msg.toString()); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/utils/YmlParser.java: -------------------------------------------------------------------------------- 1 | package jndc.utils; 2 | 3 | 4 | 5 | import org.yaml.snakeyaml.Yaml; 6 | 7 | import java.io.File; 8 | import java.io.FileInputStream; 9 | import java.io.FileNotFoundException; 10 | import java.io.InputStream; 11 | 12 | /** 13 | * 14 | * org.yaml 15 | * snakeyaml 16 | * 1.26 17 | * 18 | */ 19 | public class YmlParser { 20 | private static final Yaml yaml = new Yaml(); 21 | 22 | 23 | public T parseFile(String path, Class type) throws FileNotFoundException { 24 | return parseFile(new FileInputStream(new File(path)), type); 25 | } 26 | 27 | public T parseFile(File file, Class type) throws FileNotFoundException { 28 | return parseFile(new FileInputStream(file), type); 29 | } 30 | 31 | public T parseFile(InputStream input, Class type) { 32 | T t = yaml.loadAs(input, type); 33 | return t; 34 | } 35 | 36 | 37 | public String toYmlString(T t) { 38 | String s = yaml.dumpAsMap(t); 39 | return s; 40 | } 41 | 42 | 43 | } 44 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/core/TCPDataFlowAnalysisCenter.java: -------------------------------------------------------------------------------- 1 | package jndc_server.core; 2 | 3 | import jndc.core.NDCMessageProtocol; 4 | import lombok.Data; 5 | import lombok.extern.slf4j.Slf4j; 6 | 7 | /** 8 | * 流量分析中心 9 | */ 10 | @Data 11 | @Slf4j 12 | public class TCPDataFlowAnalysisCenter { 13 | 14 | public static final String METHOD_REQUEST = "METHOD_REQUEST"; 15 | 16 | public static final String METHOD_RESPONSE = "METHOD_RESPONSE"; 17 | 18 | private AsynchronousEventCenter asynchronousEventCenter; 19 | 20 | public TCPDataFlowAnalysisCenter(AsynchronousEventCenter asynchronousEventCenter) { 21 | this.asynchronousEventCenter = asynchronousEventCenter; 22 | } 23 | 24 | /** 25 | * 数据分析 26 | * 27 | * @param data 28 | */ 29 | public void analyse(NDCMessageProtocol data, String method) { 30 | asynchronousEventCenter.dataAnalyseJob(() -> { 31 | // log.info(method+" ---> "+data.getLocalInetAddress() + ":" + data.getRemotePort() + " to " + data.getRemoteInetAddress() + ":" + data.getLocalPort() + "\n" + new String(data.getData())); 32 | }); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/web_support/utils/BlockValueFeature.java: -------------------------------------------------------------------------------- 1 | package jndc_server.web_support.utils; 2 | 3 | 4 | import jndc.utils.LogPrint; 5 | 6 | public class BlockValueFeature { 7 | private T data; 8 | 9 | public BlockValueFeature() { 10 | } 11 | 12 | public void complete(T t) { 13 | LogPrint.debug("complete by value: "+t); 14 | data = t; 15 | synchronized (this) { 16 | this.notify(); 17 | } 18 | } 19 | 20 | public T get(Integer second) { 21 | synchronized (this) { 22 | try { 23 | if (second>0){ 24 | this.wait(second * 1000); 25 | }else { 26 | this.wait(); 27 | } 28 | LogPrint.debug("return value: "+data); 29 | T t2=data; 30 | data=null; 31 | return t2; 32 | } catch (InterruptedException e) { 33 | throw new RuntimeException("get value fail cause " + e); 34 | } 35 | } 36 | } 37 | 38 | public T get() { 39 | return get(-1); 40 | } 41 | 42 | 43 | } 44 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/databases_object/ChannelContextCloseRecord.java: -------------------------------------------------------------------------------- 1 | package jndc_server.databases_object; 2 | 3 | import jndc.core.data_store_support.DSFiled; 4 | import jndc.core.data_store_support.DSKey; 5 | import jndc.core.data_store_support.DSTable; 6 | import jndc_server.core.ChannelHandlerContextHolder; 7 | import lombok.Data; 8 | 9 | @Data 10 | @DSTable(name = "channel_context_record") 11 | public class ChannelContextCloseRecord { 12 | 13 | @DSKey 14 | private String id; 15 | 16 | 17 | @DSFiled(name = "channel_id") 18 | private String channelId; 19 | 20 | private String ip; 21 | 22 | private int port; 23 | 24 | @DSFiled(name = "time_stamp") 25 | private long timeStamp; 26 | 27 | public static ChannelContextCloseRecord of(ChannelHandlerContextHolder value) { 28 | ChannelContextCloseRecord channelContextCloseRecord = new ChannelContextCloseRecord(); 29 | channelContextCloseRecord.setChannelId(value.getClientId()); 30 | channelContextCloseRecord.setIp(value.getContextIp()); 31 | channelContextCloseRecord.setPort(value.getContextPort()); 32 | return channelContextCloseRecord; 33 | } 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/web_support/utils/SslOneWayContextFactory.java: -------------------------------------------------------------------------------- 1 | package jndc.web_support.utils; 2 | 3 | 4 | import javax.net.ssl.KeyManagerFactory; 5 | import javax.net.ssl.SSLContext; 6 | import java.io.InputStream; 7 | import java.security.KeyStore; 8 | 9 | public final class SslOneWayContextFactory { 10 | 11 | private static final String PROTOCOL = "TLS"; 12 | 13 | 14 | public static SSLContext getServerContext(InputStream stream, char[] keyStore) throws Exception { 15 | 16 | 17 | //密钥管理器 18 | KeyStore ks = KeyStore.getInstance("JKS"); 19 | 20 | //加载服务端的KeyStore ;sNetty是生成仓库时设置的密码,用于检查密钥库完整性的密码 21 | ks.load(stream, keyStore); 22 | 23 | KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); 24 | //初始化密钥管理器 25 | kmf.init(ks, keyStore); 26 | 27 | //获取安全套接字协议(TLS协议)的对象 28 | SSLContext instance = SSLContext.getInstance(PROTOCOL); 29 | 30 | //初始化此上下文 31 | //参数一:认证的密钥 参数二:对等信任认证 参数三:伪随机数生成器 。 由于单向认证,服务端不用验证客户端,所以第二个参数为null 32 | instance.init(kmf.getKeyManagers(), null, null); 33 | 34 | if (stream != null) { 35 | stream.close(); 36 | } 37 | return instance; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jndc_management", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "axios": "^0.21.0", 12 | "core-js": "^3.6.5", 13 | "element-ui": "^2.14.1", 14 | "mxgraph": "^4.2.2", 15 | "vue": "^2.6.11", 16 | "vue-router": "^3.4.9" 17 | }, 18 | "devDependencies": { 19 | "@vue/cli-plugin-babel": "~4.5.0", 20 | "@vue/cli-plugin-eslint": "~4.5.0", 21 | "@vue/cli-service": "~4.5.0", 22 | "babel-eslint": "^10.1.0", 23 | "eslint": "^6.7.2", 24 | "eslint-plugin-vue": "^6.2.2", 25 | "node-sass": "^5.0.0", 26 | "sass-loader": "^10.1.0", 27 | "vue-template-compiler": "^2.6.11", 28 | "vue2-ace-editor": "0.0.15" 29 | }, 30 | "eslintConfig": { 31 | "root": true, 32 | "env": { 33 | "node": true 34 | }, 35 | "extends": [ 36 | "plugin:vue/essential", 37 | "eslint:recommended" 38 | ], 39 | "parserOptions": { 40 | "parser": "babel-eslint" 41 | }, 42 | "rules": {} 43 | }, 44 | "browserslist": [ 45 | "> 1%", 46 | "last 2 versions", 47 | "not dead" 48 | ] 49 | } 50 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/web_support/model/dto/ClearRecordOptionDTO.java: -------------------------------------------------------------------------------- 1 | package jndc_server.web_support.model.dto; 2 | 3 | public class ClearRecordOptionDTO { 4 | 5 | private Integer recordType;//0 release 1 block 6 | 7 | private Integer clearType;//1 save top 10 / 2 clear by date limit 8 | 9 | private Long clearDateLimit; 10 | 11 | 12 | public boolean clearByDateLimit(){ 13 | return clearType==2; 14 | } 15 | 16 | @Override 17 | public String toString() { 18 | return "ClearRecordOptionDTO{" + 19 | "clearType=" + clearType + 20 | ", clearDateLimit='" + clearDateLimit + '\'' + 21 | '}'; 22 | } 23 | 24 | public Integer getRecordType() { 25 | return recordType; 26 | } 27 | 28 | public void setRecordType(Integer recordType) { 29 | this.recordType = recordType; 30 | } 31 | 32 | public Integer getClearType() { 33 | return clearType; 34 | } 35 | 36 | public void setClearType(Integer clearType) { 37 | this.clearType = clearType; 38 | } 39 | 40 | public Long getClearDateLimit() { 41 | return clearDateLimit; 42 | } 43 | 44 | public void setClearDateLimit(Long clearDateLimit) { 45 | this.clearDateLimit = clearDateLimit; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/test/java/jndc_server/exmaple/JacksonTest.java: -------------------------------------------------------------------------------- 1 | package jndc_server.exmaple; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import jndc_server.databases_object.IpFilterRecord; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.junit.Test; 8 | 9 | @Slf4j 10 | public class JacksonTest { 11 | 12 | 13 | @Test 14 | public void test() throws JsonProcessingException { 15 | String json = "[{\"timeStamp\":1663893659336,\"ip\":\"59.1.115.162\",\"vCount\":1},{\"timeStamp\":1663889313973,\"ip\":\"42.157.194.16\",\"vCount\":242},{\"timeStamp\":1663888541502,\"ip\":\"117.25.149.164\",\"vCount\":394},{\"timeStamp\":1663888186590,\"ip\":\"89.248.165.82\",\"vCount\":15},{\"timeStamp\":1663887301296,\"ip\":\"45.61.186.4\",\"vCount\":53},{\"timeStamp\":1663886551099,\"ip\":\"60.217.75.70\",\"vCount\":15},{\"timeStamp\":1663884702840,\"ip\":\"45.61.185.149\",\"vCount\":324},{\"timeStamp\":1663880921666,\"ip\":\"8.219.71.118\",\"vCount\":588},{\"timeStamp\":1663880666460,\"ip\":\"87.236.176.30\",\"vCount\":1},{\"timeStamp\":1663880498397,\"ip\":\"213.226.123.219\",\"vCount\":12}]"; 16 | 17 | ObjectMapper objectMapper = new ObjectMapper(); 18 | IpFilterRecord[] ipFilterRecords1 = objectMapper.readValue(json, IpFilterRecord[].class); 19 | 20 | 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/databases_object/ServerPortBind.java: -------------------------------------------------------------------------------- 1 | package jndc_server.databases_object; 2 | 3 | import jndc.core.data_store_support.DSFiled; 4 | import jndc.core.data_store_support.DSKey; 5 | import jndc.core.data_store_support.DSTable; 6 | import lombok.Data; 7 | 8 | 9 | /** 10 | * 服务端端口监听描述信息表 11 | */ 12 | @Data 13 | @DSTable(name = "server_port_bind") 14 | public class ServerPortBind { 15 | 16 | @DSKey 17 | private String id; 18 | 19 | private String name; 20 | 21 | private int port; 22 | 23 | @DSFiled(name = "enable_date_range") 24 | private String enableDateRange; 25 | 26 | //客户端唯一编号 27 | @DSFiled(name = "bind_client_id") 28 | private String bindClientId; 29 | 30 | @DSFiled(name = "port_enable") 31 | private int portEnable;//1 enable 0 disable 2 preparing 32 | 33 | //服务路由路径 34 | @DSFiled(name = "route_to") 35 | private String routeTo; 36 | 37 | /** 38 | * change state to enable 39 | */ 40 | public void bindEnable(){ 41 | setPortEnable(1); 42 | } 43 | 44 | /** 45 | * change state to disable 46 | */ 47 | public void bindDisable(){ 48 | setPortEnable(0); 49 | } 50 | 51 | /** 52 | * change state to preparing 53 | */ 54 | public void bindPreparing(){ 55 | setPortEnable(2); 56 | } 57 | 58 | 59 | } 60 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/resources/conf/config.template.yml: -------------------------------------------------------------------------------- 1 | # 服务端密钥,用于加密通信,请务必修改为安全的随机字符串 2 | secrete: "your-secret-key-here" 3 | 4 | # 日志级别: debug, info, warn, error 5 | loglevel: "info" 6 | 7 | # IP访问控制 8 | blackList: # 禁止访问的IP地址列表 9 | #- "192.168.1.1" 10 | whiteList: # 允许访问的IP地址列表 11 | #- "192.168.1.2" 12 | 13 | # 服务端基础配置 14 | servicePort: 81 # JNDC服务端监听端口 15 | bindIp: "127.0.0.1" # JNDC服务端绑定IP地址 16 | 17 | # 数据库配置 18 | dbConfig: 19 | type: "mysql" # 数据库类型:mysql 或 sqlite 20 | #type: "sqlite" # 使用sqlite数据库 21 | url: "jdbc:mysql://localhost:3306/your_database?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true" 22 | name: "your_username" # 数据库用户名 23 | password: "your_password" # 数据库密码 24 | flywayEnable: true # 是否启用数据库版本控制 25 | 26 | # 管理后台配置 27 | manageConfig: 28 | managementApiPort: 777 # 管理后台API服务端口 29 | useSsl: false # 是否启用SSL加密 30 | jksPath: "path/to/your/certificate.jks" # SSL证书路径 31 | jksPass: "your_jks_password" # SSL证书密码 32 | loginName: "your_admin_username" # 管理后台登录用户名 33 | loginPassWord: "your_admin_password" # 管理后台登录密码 34 | adminEnable: true # 是否启用管理后台 35 | 36 | # Web服务配置 37 | webConfig: 38 | notFoundPage: "path/to/your/404.html" # 404错误页面路径 39 | httpPort: 80 # HTTP服务端口 40 | useSsl: false # 是否启用SSL加密 41 | jksPath: "path/to/your/certificate.jks" # SSL证书路径 42 | jksPass: "your_jks_password" # SSL证书密码 43 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/web_support/core/JNDCRequestDecoder.java: -------------------------------------------------------------------------------- 1 | package jndc.web_support.core; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.handler.codec.MessageToMessageDecoder; 5 | import io.netty.handler.codec.http.FullHttpRequest; 6 | import io.netty.handler.codec.http.HttpHeaderNames; 7 | 8 | import java.net.InetSocketAddress; 9 | import java.util.List; 10 | 11 | /** 12 | * jndc内http请求解码器 13 | */ 14 | public class JNDCRequestDecoder extends MessageToMessageDecoder { 15 | public static String NAME = "JNDC_REQUEST_DECODER"; 16 | 17 | 18 | @Override 19 | protected void decode(ChannelHandlerContext channelHandlerContext, FullHttpRequest fullHttpRequest, List list) throws Exception { 20 | 21 | if (fullHttpRequest.headers().get(HttpHeaderNames.UPGRADE) != null) { 22 | //todo not ignore header and upgrade is not null 23 | channelHandlerContext.fireChannelRead(fullHttpRequest.retain()); 24 | } else { 25 | //todo do http parse only 26 | JNDCHttpRequest ndcHttpRequest = new JNDCHttpRequest(fullHttpRequest); 27 | InetSocketAddress socketAddress = (InetSocketAddress) channelHandlerContext.channel().remoteAddress(); 28 | ndcHttpRequest.setRemoteAddress(socketAddress.getAddress()); 29 | list.add(ndcHttpRequest); 30 | } 31 | } 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/web_support/utils/AuthUtils.java: -------------------------------------------------------------------------------- 1 | package jndc.web_support.utils; 2 | 3 | import jndc.utils.AESUtils; 4 | import jndc.web_support.model.dto.LoginUser; 5 | 6 | import java.util.Base64; 7 | 8 | /** 9 | * simple password check,need to be replace with more Safer framework 10 | */ 11 | public class AuthUtils { 12 | 13 | 14 | public static String name = ""; 15 | 16 | public static String passWord = ""; 17 | 18 | /** 19 | * @param loginUser 20 | * @return 21 | */ 22 | public static boolean doLogin(LoginUser loginUser) { 23 | if (name.equals(loginUser.getName()) && passWord.equals(loginUser.getPassWord())) { 24 | return true; 25 | } 26 | return false; 27 | } 28 | 29 | 30 | /** 31 | * encode step with AESUtils 32 | * 33 | * @param uniqueBytes 34 | * @return 35 | */ 36 | public static String webAuthTokenEncode(byte[] uniqueBytes) { 37 | byte[] encode = AESUtils.encode(uniqueBytes); 38 | Base64.Encoder encoder = Base64.getEncoder(); 39 | String s1 = encoder.encodeToString(encode); 40 | return s1; 41 | } 42 | 43 | public static byte[] webAuthTokenDecode(String token) { 44 | Base64.Decoder decoder = Base64.getDecoder(); 45 | byte[] decode = decoder.decode(token); 46 | byte[] decode1 = AESUtils.decode(decode); 47 | return decode1; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/web_support/mapping/DevelopDebugMapping.java: -------------------------------------------------------------------------------- 1 | package jndc_server.web_support.mapping; 2 | 3 | 4 | import jndc.web_support.core.FrontProjectLoader; 5 | import jndc.web_support.core.JNDCHttpRequest; 6 | import jndc.web_support.core.WebMapping; 7 | import jndc.web_support.model.dto.ResponseMessage; 8 | import jndc_server.web_support.utils.ServerUrlConstant; 9 | 10 | import java.net.InetAddress; 11 | import java.util.HashMap; 12 | 13 | /** 14 | * singleton, thread unsafe 15 | */ 16 | public class DevelopDebugMapping { 17 | 18 | 19 | @WebMapping(path = ServerUrlConstant.DevelopDebug.reloadFront) 20 | public HashMap run(JNDCHttpRequest jndcHttpRequest) { 21 | FrontProjectLoader.jndcStaticProject.reloadProject(); 22 | HashMap objectObjectHashMap = new HashMap<>(); 23 | objectObjectHashMap.put("message", "success"); 24 | return objectObjectHashMap; 25 | 26 | } 27 | 28 | @WebMapping(path = ServerUrlConstant.DevelopDebug.getDeviceIp) 29 | public ResponseMessage getDeviceIp(JNDCHttpRequest jndcHttpRequest) { 30 | ResponseMessage responseMessage = new ResponseMessage(); 31 | 32 | InetAddress remoteAddress = jndcHttpRequest.getRemoteAddress(); 33 | String hostAddress = remoteAddress.getHostAddress(); 34 | responseMessage.setMessage("device ip:" + hostAddress); 35 | return responseMessage; 36 | 37 | 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/web_support/utils/AuthUtils.java: -------------------------------------------------------------------------------- 1 | package jndc_server.web_support.utils; 2 | 3 | import jndc.utils.AESUtils; 4 | import jndc.web_support.model.dto.LoginUser; 5 | 6 | import java.util.Base64; 7 | 8 | /** 9 | * simple password check,need to be replace with more Safer framework 10 | */ 11 | public class AuthUtils { 12 | 13 | 14 | public static String name=""; 15 | public static String passWord=""; 16 | 17 | /** 18 | * @param managementLoginUser 19 | * @return 20 | */ 21 | public static boolean doLogin(LoginUser managementLoginUser) { 22 | if (name.equals(managementLoginUser.getName()) && passWord.equals(managementLoginUser.getPassWord())) { 23 | return true; 24 | } 25 | return false; 26 | } 27 | 28 | 29 | /** 30 | * encode step with AESUtils 31 | * @param uniqueBytes 32 | * @return 33 | */ 34 | public static String webAuthTokenEncode(byte[] uniqueBytes){ 35 | byte[] encode = AESUtils.encode(uniqueBytes); 36 | Base64.Encoder encoder = Base64.getEncoder(); 37 | String s1 = encoder.encodeToString(encode); 38 | return s1; 39 | } 40 | 41 | public static byte[] webAuthTokenDecode(String token){ 42 | Base64.Decoder decoder = Base64.getDecoder(); 43 | byte[] decode = decoder.decode(token); 44 | byte[] decode1 = AESUtils.decode(decode); 45 | return decode1; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/web_support/model/dto/ServiceBindDTO.java: -------------------------------------------------------------------------------- 1 | package jndc_server.web_support.model.dto; 2 | 3 | public class ServiceBindDTO { 4 | private String remark; 5 | 6 | private String serverPortId; 7 | 8 | private String serviceId; 9 | 10 | private String enableDateRange; 11 | 12 | @Override 13 | public String toString() { 14 | return "ServiceBindDTO{" + 15 | "remark='" + remark + '\'' + 16 | ", serverPortId='" + serverPortId + '\'' + 17 | ", serviceId='" + serviceId + '\'' + 18 | ", enableDateRange='" + enableDateRange + '\'' + 19 | '}'; 20 | } 21 | 22 | public String getRemark() { 23 | return remark; 24 | } 25 | 26 | public void setRemark(String remark) { 27 | this.remark = remark; 28 | } 29 | 30 | public String getEnableDateRange() { 31 | return enableDateRange; 32 | } 33 | 34 | public void setEnableDateRange(String enableDateRange) { 35 | this.enableDateRange = enableDateRange; 36 | } 37 | 38 | public String getServerPortId() { 39 | return serverPortId; 40 | } 41 | 42 | public void setServerPortId(String serverPortId) { 43 | this.serverPortId = serverPortId; 44 | } 45 | 46 | public String getServiceId() { 47 | return serviceId; 48 | } 49 | 50 | public void setServiceId(String serviceId) { 51 | this.serviceId = serviceId; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/utils/UniqueInetTagProducer.java: -------------------------------------------------------------------------------- 1 | package jndc.utils; 2 | 3 | import java.net.InetAddress; 4 | import java.net.InetSocketAddress; 5 | 6 | public class UniqueInetTagProducer { 7 | 8 | 9 | public static String get4Server(InetAddress inetAddress, int port){ 10 | byte[] address = inetAddress.getAddress(); 11 | return new String(address)+port; 12 | } 13 | 14 | public static String get4Server(InetSocketAddress inetSocketAddress){ 15 | if (null==inetSocketAddress ||inetSocketAddress.getAddress()==null ||inetSocketAddress.getAddress().getAddress()==null){ 16 | throw new RuntimeException("not support for null"); 17 | } 18 | int port = inetSocketAddress.getPort(); 19 | 20 | byte[] address = inetSocketAddress.getAddress().getAddress(); 21 | return new String(address)+port; 22 | 23 | } 24 | public static String get4Client(InetAddress inetAddress, int port){ 25 | byte[] address = inetAddress.getAddress(); 26 | return new String(address)+port; 27 | } 28 | 29 | public static String get4Client(InetSocketAddress sender){ 30 | if (null==sender 31 | ||sender.getAddress()==null 32 | ||sender.getAddress().getAddress()==null){ 33 | throw new RuntimeException("not support for null"); 34 | } 35 | int port = sender.getPort(); 36 | 37 | byte[] address = sender.getAddress().getAddress(); 38 | return new String(address)+port; 39 | 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/web_support/config/ServeHTTPConfig.java: -------------------------------------------------------------------------------- 1 | package jndc.web_support.config; 2 | 3 | import jndc.web_support.utils.SslOneWayContextFactory; 4 | import lombok.Data; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.apache.commons.io.FileUtils; 7 | 8 | import javax.net.ssl.SSLContext; 9 | import java.io.ByteArrayInputStream; 10 | import java.io.File; 11 | 12 | /** 13 | * HTTP配置 14 | */ 15 | @Slf4j 16 | @Data 17 | public class ServeHTTPConfig { 18 | 19 | //http 端口 20 | private int httpPort; 21 | 22 | //使用ssl 23 | private boolean useSsl; 24 | 25 | //证书地址 26 | private String jksPath; 27 | 28 | //证书密码 29 | private String jksPass; 30 | 31 | 32 | //404 页面地址 33 | private String notFoundPage = "The page piu~ ,not found"; 34 | 35 | //证书上下文 36 | private SSLContext serverSSLContext; 37 | 38 | public void initSsl() { 39 | if (isUseSsl()) { 40 | //todo 判断是否使用ssl 41 | try { 42 | char[] keyStorePass = getJksPass().toCharArray(); 43 | byte[] keyStore = FileUtils.readFileToByteArray(new File(getJksPath())); 44 | serverSSLContext = SslOneWayContextFactory.getServerContext(new ByteArrayInputStream(keyStore), keyStorePass); 45 | log.info("open ssl in the web api"); 46 | } catch (Exception e) { 47 | setUseSsl(false); 48 | log.error("init ssl context fail cause:" + e); 49 | } 50 | 51 | 52 | } 53 | 54 | 55 | } 56 | 57 | 58 | } 59 | -------------------------------------------------------------------------------- /jndc_client/jndc-client-backend/src/main/java/jndc_client/core/JNDClientApp.java: -------------------------------------------------------------------------------- 1 | package jndc_client.core; 2 | 3 | import jndc.core.UniqueBeanManage; 4 | import jndc.utils.PathUtils; 5 | import jndc.web_support.config.ServeManageConfig; 6 | import jndc.web_support.http_module.ManagementServer; 7 | import lombok.extern.slf4j.Slf4j; 8 | 9 | import java.io.File; 10 | 11 | 12 | /** 13 | * 主服务 14 | */ 15 | @Slf4j 16 | public class JNDClientApp { 17 | 18 | 19 | public void createClient() { 20 | 21 | // JNDCClientConfig jndcClientConfig = UniqueBeanManage.getBean(JNDCClientConfig.class); 22 | // 23 | // 24 | // ServeManageConfig manageConfig = jndcClientConfig.getManageConfig(); 25 | // 26 | // if (manageConfig.isAdminEnable()) { 27 | // //todo 处理静态项目地址 28 | // String runTimePath = PathUtils.getRunTimePath(); 29 | // String p1 = runTimePath + File.separator + ".." + File.separator + "compare_dist"; 30 | // String p2 = System.getProperty("user.dir") + File.separator + "target" + File.separator + "jndc_client" + File.separator + "compare_dist"; 31 | // String runtimeDir = PathUtils.findExistPath(p1, p2); 32 | // manageConfig.setAdminProjectPath(runtimeDir); 33 | // } 34 | // 35 | // 36 | // //http管理端 37 | // ManagementServer managementServer = new ManagementServer(); 38 | // managementServer.start(manageConfig);//start 39 | 40 | //核心服务 41 | JNDCClient jndcClient = new JNDCClient(); 42 | jndcClient.start(); 43 | 44 | 45 | } 46 | 47 | 48 | } 49 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/resources/conf/db/migration_sqlite/V1__init_tables.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE "ip_filter_record" 2 | ( 3 | "id" text(32) NOT NULL, 4 | "ip" TEXT(16), 5 | "v_count" integer(32), 6 | "time_stamp" integer(64), 7 | "record_type" integer(2), 8 | PRIMARY KEY ("id") 9 | ); 10 | 11 | CREATE TABLE "http_host_route" 12 | ( 13 | "id" text(32) NOT NULL, 14 | "route_type" INTEGER(2), 15 | "host_key_word" text(200), 16 | "fixed_response" text(2000), 17 | "redirect_address" text(500), 18 | "fixed_content_type" text(100), 19 | "forward_host" text(100), 20 | "forward_protocol" text(30), 21 | "forward_port" INTEGER(20), 22 | PRIMARY KEY ("id") 23 | ); 24 | 25 | CREATE TABLE "channel_context_record" 26 | ( 27 | "id" text(32) NOT NULL, 28 | "ip" text(16), 29 | "channel_id" text(32), 30 | "port" integer(8), 31 | "time_stamp" integer(64), 32 | PRIMARY KEY ("id") 33 | ); 34 | 35 | CREATE TABLE "server_ip_filter_rule" 36 | ( 37 | "id" text(32) NOT NULL, 38 | "ip" text(32), 39 | "type" integer(1), 40 | PRIMARY KEY ("id") 41 | ); 42 | 43 | CREATE TABLE "server_port_bind" 44 | ( 45 | "id" text(32) NOT NULL, 46 | "name" text(50), 47 | "bind_client_id" text(32), 48 | "enable_date_range" text(50), 49 | "port" integer(10), 50 | "port_enable" integer(2), 51 | "route_to" text(16), 52 | PRIMARY KEY ("id") 53 | ); -------------------------------------------------------------------------------- /jndc_server/jndc-server-frontend/src/config/requestConfig.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import {Message} from 'element-ui' 3 | 4 | 5 | // create an axios instance 6 | const service = axios.create({ 7 | baseURL: window.runtimeConfig.BASE_REQUEST_PATH, // url = base url + request url 8 | timeout: 15 * 1000 // request timeout 9 | }) 10 | 11 | 12 | // request interceptor 13 | service.interceptors.request.use( 14 | config => { 15 | config.headers['auth-token'] = localStorage.getItem('auth-token') 16 | config.headers['Content-Type'] = 'application/json;charset=UTF-8'; 17 | return config 18 | }, 19 | error => { 20 | console.log(error) // for debug 21 | return Promise.reject(error) 22 | } 23 | ) 24 | 25 | // response interceptor 26 | service.interceptors.response.use( 27 | /** 28 | * If you want to get http information such as headers or status 29 | * Please return response => response 30 | */ 31 | 32 | /** 33 | * Determine the request status by custom code 34 | * Here is just an example 35 | * You can also judge the status by HTTP Status Code 36 | */ 37 | response => { 38 | const res = response.data 39 | return res 40 | }, 41 | error => { 42 | if (error.message.indexOf('403') != -1) { 43 | localStorage.removeItem('auth-token') 44 | window.location.reload() 45 | } 46 | 47 | Message({ 48 | message: error.message, 49 | type: 'error', 50 | duration: 5 * 1000 51 | }) 52 | return Promise.reject(error) 53 | } 54 | ) 55 | 56 | export default service 57 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/web_support/core/WebSocketHandle.java: -------------------------------------------------------------------------------- 1 | package jndc.web_support.core; 2 | 3 | import io.netty.channel.Channel; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.SimpleChannelInboundHandler; 6 | import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; 7 | import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; 8 | import jndc.core.UniqueBeanManage; 9 | import jndc.utils.LogPrint; 10 | 11 | /** 12 | * websocket处理器 13 | */ 14 | public class WebSocketHandle extends SimpleChannelInboundHandler { 15 | public static final String NAME = "WEB_SOCKET_HANDLE"; 16 | 17 | @Override 18 | protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame) throws Exception { 19 | LogPrint.info("channelRead0" + textWebSocketFrame); 20 | channelHandlerContext.writeAndFlush(textWebSocketFrame.retain()); 21 | } 22 | 23 | 24 | @Override 25 | public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { 26 | if (evt instanceof WebSocketServerProtocolHandler.HandshakeComplete) { 27 | Channel channel = ctx.channel(); 28 | MessageNotificationCenter messageNotificationCenter = UniqueBeanManage.getBean(MessageNotificationCenter.class); 29 | //通道注册 30 | messageNotificationCenter.websocketRegister(channel); 31 | } 32 | } 33 | 34 | @Override 35 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 36 | cause.printStackTrace(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /jndc_client/jndc-client-backend/src/main/java/jndc_client/core/ClientServiceDescription.java: -------------------------------------------------------------------------------- 1 | package jndc_client.core; 2 | 3 | 4 | import jndc.core.message.TcpServiceDescription; 5 | import jndc.utils.InetUtils; 6 | import lombok.Data; 7 | import lombok.extern.slf4j.Slf4j; 8 | 9 | import java.net.InetAddress; 10 | import java.net.InetSocketAddress; 11 | 12 | 13 | /** 14 | * 客户端服务 15 | */ 16 | @Slf4j 17 | @Data 18 | public class ClientServiceDescription extends TcpServiceDescription { 19 | 20 | private boolean serviceEnable; 21 | 22 | /* ---------prepare field-----*/ 23 | private InetAddress ipAddress; 24 | 25 | private InetSocketAddress ipSocketAddress; 26 | 27 | 28 | /** 29 | * 获取唯一标志位 30 | * 31 | * @return 32 | */ 33 | public String getUniqueTag() { 34 | return getServiceIp() + ":" + getServicePort(); 35 | } 36 | 37 | /** 38 | * 参数校验 39 | */ 40 | public void performParameterVerification() { 41 | ipAddress = InetUtils.getByStringIpAddress(getServiceIp()); 42 | ipSocketAddress = new InetSocketAddress(ipAddress, getServicePort()); 43 | } 44 | 45 | 46 | public TcpServiceDescription toTcpServiceDescription() { 47 | TcpServiceDescription tcpServiceDescription = new TcpServiceDescription(); 48 | tcpServiceDescription.setId(getId()); 49 | tcpServiceDescription.setServiceIp(getServiceIp()); 50 | tcpServiceDescription.setServiceName(getServiceName()); 51 | tcpServiceDescription.setServicePort(getServicePort()); 52 | tcpServiceDescription.setDescription(getServiceName()); 53 | return tcpServiceDescription; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /jndc_client/jndc-client-backend/src/main/java/jndc_client/core/ClientScheduledTaskCenter.java: -------------------------------------------------------------------------------- 1 | package jndc_client.core; 2 | 3 | import io.netty.channel.EventLoopGroup; 4 | import jndc.core.NettyComponentConfig; 5 | import jndc.core.UniqueBeanManage; 6 | import jndc_client.core.port_app.ClientServiceProvider; 7 | import jndc_client.core.port_app.ClientTCPDataHandle; 8 | import lombok.extern.slf4j.Slf4j; 9 | 10 | import java.util.Map; 11 | import java.util.concurrent.TimeUnit; 12 | 13 | /** 14 | * 定时组件 15 | */ 16 | @Slf4j 17 | public class ClientScheduledTaskCenter { 18 | private EventLoopGroup eventLoopGroup = NettyComponentConfig.getNioEventLoopGroup(); 19 | 20 | 21 | public void start() { 22 | 23 | JNDCClientConfigCenter bean = UniqueBeanManage.getBean(JNDCClientConfigCenter.class); 24 | Map portProtectorMap = bean.getPortProtectorMap(); 25 | 26 | //fix the problem of rebind operation fail 27 | eventLoopGroup.scheduleWithFixedDelay(() -> { 28 | 29 | //循环服务提供者 30 | portProtectorMap.forEach((k, v) -> { 31 | Map faceTCPMap = v.getFaceTCPMap(); 32 | 33 | //循环连接 34 | faceTCPMap.forEach((k2, v2) -> { 35 | if (v2.isTimeOut()) { 36 | //todo 连接超时 37 | log.info("release local client cause time out"); 38 | //释放连接 39 | v2.releaseRelatedResources(); 40 | } 41 | }); 42 | 43 | }); 44 | 45 | }, 0, 30, TimeUnit.SECONDS); 46 | 47 | 48 | } 49 | 50 | 51 | } 52 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/core/filter/IpAddressRule.java: -------------------------------------------------------------------------------- 1 | package jndc_server.core.filter; 2 | 3 | 4 | import io.netty.channel.ChannelHandlerContext; 5 | import jndc.core.UniqueBeanManage; 6 | import lombok.extern.slf4j.Slf4j; 7 | 8 | import java.net.InetAddress; 9 | import java.net.InetSocketAddress; 10 | import java.util.Arrays; 11 | 12 | @Slf4j 13 | public class IpAddressRule implements CustomRule { 14 | private volatile IpChecker ipChecker; 15 | 16 | 17 | @Override 18 | public String ruleCheck(ChannelHandlerContext ctx) { 19 | InetSocketAddress socketAddress = (InetSocketAddress) ctx.channel().remoteAddress(); 20 | InetAddress address = socketAddress.getAddress(); 21 | byte[] address1 = address.getAddress(); 22 | if (address1.length > 4) { 23 | log.debug("仅支持ipv4地址,当前地址:" + Arrays.toString(address1)); 24 | return getRuleName() + "仅支持ipv4地址,当前地址:" + Arrays.toString(address1); 25 | } 26 | String ipString = address.getHostAddress(); 27 | 28 | //lazy init 29 | if (ipChecker == null) { 30 | synchronized (IpAddressRule.class) { 31 | if (ipChecker == null) { 32 | ipChecker = UniqueBeanManage.getBean(IpChecker.class); 33 | } 34 | } 35 | } 36 | 37 | boolean b = ipChecker.checkIpAddress(ipString); 38 | if (b) { 39 | return null; 40 | } else { 41 | return getRuleName() + "发起端地址不被允许:" + ipString; 42 | } 43 | 44 | } 45 | 46 | @Override 47 | public String getRuleName() { 48 | return "Ip Address Rule"; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/web_support/http_module/LiteProxyHandle.java: -------------------------------------------------------------------------------- 1 | package jndc_server.web_support.http_module; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.channel.SimpleChannelInboundHandler; 5 | import io.netty.handler.codec.http.FullHttpResponse; 6 | import jndc_server.web_support.utils.HttpResponseBuilder; 7 | import lombok.extern.slf4j.Slf4j; 8 | 9 | @Slf4j 10 | public class LiteProxyHandle extends SimpleChannelInboundHandler { 11 | public static String NAME = "LITE_PROXY_HANDLE"; 12 | 13 | private LiteHttpProxy liteHttpProxy; 14 | 15 | public LiteProxyHandle(LiteHttpProxy liteHttpProxy) { 16 | this.liteHttpProxy = liteHttpProxy; 17 | } 18 | 19 | 20 | @Override 21 | protected void channelRead0(ChannelHandlerContext channelHandlerContext, FullHttpResponse fullHttpResponse) throws Exception { 22 | if (liteHttpProxy == null) { 23 | log.error("liteHttpProxy 为空"); 24 | return; 25 | } 26 | liteHttpProxy.writeData(fullHttpResponse.retain()); 27 | } 28 | 29 | @Override 30 | public void channelInactive(ChannelHandlerContext ctx) throws Exception { 31 | //客户端目标主动断开 32 | release(); 33 | 34 | } 35 | 36 | @Override 37 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 38 | //todo 异常直接返回异常信息 39 | log.error("proxy handle error " + cause); 40 | FullHttpResponse fullHttpResponse = HttpResponseBuilder.textResponse(cause.toString().getBytes()); 41 | liteHttpProxy.writeData(fullHttpResponse); 42 | } 43 | 44 | public void release() { 45 | if (liteHttpProxy != null) { 46 | liteHttpProxy.release(); 47 | liteHttpProxy = null; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/core/data_store_support/MysqlDataStore.java: -------------------------------------------------------------------------------- 1 | package jndc.core.data_store_support; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.flywaydb.core.Flyway; 5 | 6 | import java.io.File; 7 | import java.sql.Connection; 8 | import java.sql.DriverManager; 9 | import java.sql.SQLException; 10 | 11 | /** 12 | * mysql 13 | */ 14 | @Slf4j 15 | public class MysqlDataStore extends DataStoreAbstract { 16 | private String url; 17 | 18 | private String name; 19 | 20 | private String password; 21 | 22 | private volatile Connection connection; 23 | 24 | public MysqlDataStore(String url, String name, String password) { 25 | this.url = url; 26 | this.name = name; 27 | this.password = password; 28 | } 29 | 30 | @Override 31 | public Connection getConnection() { 32 | try { 33 | if (connection == null || connection.isClosed()) { 34 | synchronized (this) { 35 | if (connection == null || connection.isClosed()) { 36 | connection = DriverManager.getConnection(url, name, password); 37 | } 38 | } 39 | } 40 | } catch (SQLException sqlException) { 41 | log.error(sqlException + ""); 42 | } 43 | 44 | return connection; 45 | } 46 | 47 | @Override 48 | public void flywayInit() { 49 | String devPath = "filesystem:" + System.getProperty("user.dir") + File.separator + "jndc_server\\src\\main\\resources\\db\\migration_mysql"; 50 | Flyway flyway = Flyway.configure() 51 | .locations("classpath:db/migration_mysql", devPath) 52 | .baselineOnMigrate(true) 53 | .dataSource(url, name, password) 54 | .load(); 55 | 56 | flyway.migrate(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/test/java/jndc_server/exmaple/ServerTest.java: -------------------------------------------------------------------------------- 1 | package jndc_server.exmaple; 2 | 3 | import jndc.utils.ApplicationExit; 4 | import jndc.utils.PathUtils; 5 | import jndc.utils.YmlParser; 6 | import jndc_server.config.JNDCServerConfig; 7 | import jndc_server.core.JNDCServerApp; 8 | import jndc_server.web_support.http_module.ServerRuntimeConfig; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.junit.Test; 11 | 12 | import java.io.File; 13 | 14 | @Slf4j 15 | public class ServerTest { 16 | 17 | 18 | @Test 19 | public void start() { 20 | 21 | ServerRuntimeConfig.DEBUG_MODEL = true; 22 | 23 | String runTimePath = PathUtils.getRunTimePath(); 24 | log.info("读取运行目录: " + runTimePath); 25 | 26 | String devPath = System.getProperty("user.dir") + File.separator + "src\\main\\resources\\conf\\config.yml"; 27 | File file = new File(devPath); 28 | 29 | 30 | YmlParser ymlParser = new YmlParser(); 31 | JNDCServerConfig jndcServerConfig; 32 | try { 33 | jndcServerConfig = ymlParser.parseFile(file, JNDCServerConfig.class); 34 | jndcServerConfig.setRuntimeDir(runTimePath); 35 | jndcServerConfig.performParameterVerification(); 36 | jndcServerConfig.lazyInitAfterVerification(); 37 | } catch (Exception e) { 38 | e.printStackTrace(); 39 | log.error("config file parse fail:" + e); 40 | ApplicationExit.exit(); 41 | } 42 | JNDCServerApp serverTest = new JNDCServerApp(); 43 | 44 | serverTest.createServer();//start 45 | 46 | 47 | Thread thread = Thread.currentThread(); 48 | synchronized (thread) { 49 | try { 50 | thread.wait(); 51 | } catch (InterruptedException e) { 52 | e.printStackTrace(); 53 | } 54 | } 55 | 56 | 57 | } 58 | 59 | 60 | } 61 | -------------------------------------------------------------------------------- /jndc_client/jndc-client-backend/src/test/java/jndc_client/ClientTest.java: -------------------------------------------------------------------------------- 1 | package jndc_client; 2 | 3 | 4 | import jndc.utils.ApplicationExit; 5 | import jndc.utils.YmlParser; 6 | import jndc_client.core.ClientDirectManager; 7 | import jndc_client.core.JNDCClientConfig; 8 | import jndc_client.core.JNDClientApp; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.junit.Test; 11 | 12 | import java.io.File; 13 | 14 | 15 | @Slf4j 16 | public class ClientTest { 17 | 18 | @Test 19 | public void run() { 20 | 21 | ClientDirectManager.idPath = "C:\\Users\\liuqiwei\\Desktop\\client_id"; 22 | 23 | String devPath = System.getProperty("user.dir") + File.separator + "src\\main\\resources\\conf\\config.yml"; 24 | ClientDirectManager.ymlConfig = devPath; 25 | 26 | 27 | String ymlConfig = ClientDirectManager.ymlConfig; 28 | File file = new File(ymlConfig); 29 | 30 | 31 | YmlParser ymlParser = new YmlParser(); 32 | JNDCClientConfig jndcClientConfig; 33 | try { 34 | jndcClientConfig = ymlParser.parseFile(file, JNDCClientConfig.class); 35 | jndcClientConfig.performParameterVerification(); 36 | jndcClientConfig.loadClientId(); 37 | log.info("client time out--->" + jndcClientConfig.getAutoReleaseTimeOut()); 38 | } catch (Exception e) { 39 | e.printStackTrace(); 40 | log.error("config file:" + file + " parse fail:" + e); 41 | ApplicationExit.exit(); 42 | } 43 | 44 | 45 | JNDClientApp jndClientApp = new JNDClientApp(); 46 | jndClientApp.createClient(); 47 | 48 | 49 | Thread thread = Thread.currentThread(); 50 | synchronized (thread) { 51 | try { 52 | thread.wait(); 53 | } catch (InterruptedException e) { 54 | e.printStackTrace(); 55 | } 56 | } 57 | 58 | 59 | } 60 | 61 | 62 | } 63 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/utils/AESUtils.java: -------------------------------------------------------------------------------- 1 | package jndc.utils; 2 | 3 | 4 | import jndc.exception.SecreteDecodeFailException; 5 | import lombok.extern.slf4j.Slf4j; 6 | 7 | import javax.crypto.Cipher; 8 | import javax.crypto.spec.SecretKeySpec; 9 | import java.security.MessageDigest; 10 | import java.util.Arrays; 11 | 12 | 13 | /** 14 | * AESUtils 15 | */ 16 | @Slf4j 17 | public class AESUtils { 18 | 19 | private static final byte[] DEFAULT_KEY = "hi,view".getBytes(); 20 | 21 | private static SecretKeySpec secretKey; 22 | 23 | 24 | static { 25 | setKey(DEFAULT_KEY); 26 | } 27 | 28 | public static void setKey(byte[] key) { 29 | MessageDigest sha; 30 | try { 31 | sha = MessageDigest.getInstance("SHA-1"); 32 | key = sha.digest(key); 33 | key = Arrays.copyOf(key, 16); 34 | secretKey = new SecretKeySpec(key, "AES"); 35 | } catch (Exception e) { 36 | log.info("设置密钥异常" + e); 37 | throw new RuntimeException("set key error:" + e); 38 | } 39 | } 40 | 41 | public static byte[] encode(byte[] bytes) { 42 | try { 43 | Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 44 | cipher.init(Cipher.ENCRYPT_MODE, secretKey); 45 | return cipher.doFinal(bytes); 46 | } catch (Exception e) { 47 | log.info("编码异常" + e); 48 | throw new RuntimeException("encode error:" + e); 49 | } 50 | 51 | } 52 | 53 | public static byte[] decode(byte[] bytes) { 54 | try { 55 | Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING"); 56 | cipher.init(Cipher.DECRYPT_MODE, secretKey); 57 | return cipher.doFinal(bytes); 58 | } catch (Exception e) { 59 | log.error("解码异常" + e + ",即将断开链接..."); 60 | throw new SecreteDecodeFailException(); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/web_support/config/ServeManageConfig.java: -------------------------------------------------------------------------------- 1 | package jndc.web_support.config; 2 | 3 | import jndc.web_support.utils.SslOneWayContextFactory; 4 | import lombok.Data; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.apache.commons.io.FileUtils; 7 | 8 | import javax.net.ssl.SSLContext; 9 | import java.io.ByteArrayInputStream; 10 | import java.io.File; 11 | 12 | /** 13 | * HTTP配置 14 | */ 15 | @Slf4j 16 | @Data 17 | public class ServeManageConfig { 18 | 19 | //管理页面api 端口 20 | private int managementApiPort; 21 | 22 | //登录用户名 23 | private String loginName; 24 | 25 | //登录密码 26 | private String loginPassWord; 27 | 28 | //使用ssl 29 | private boolean useSsl; 30 | 31 | //证书地址 32 | private String jksPath; 33 | 34 | //证书密码 35 | private String jksPass; 36 | 37 | //证书上下文 38 | private SSLContext serverSSLContext; 39 | 40 | //是否扫描目录 41 | private boolean adminEnable = false; 42 | 43 | 44 | private String adminProjectPath; 45 | 46 | 47 | public void initSsl() { 48 | if (isUseSsl()) { 49 | try { 50 | try { 51 | char[] keyStorePass = getJksPass().toCharArray(); 52 | byte[] keyStore = FileUtils.readFileToByteArray(new File(getJksPath())); 53 | serverSSLContext = SslOneWayContextFactory.getServerContext(new ByteArrayInputStream(keyStore), keyStorePass); 54 | log.info("open ssl in the manage api"); 55 | } catch (Exception e) { 56 | setUseSsl(false); 57 | log.error("load ssl context fail cause:" + e); 58 | throw new RuntimeException(e); 59 | } 60 | } catch (Exception e) { 61 | setUseSsl(false); 62 | log.error("init ssl context fail cause:" + e); 63 | } 64 | 65 | 66 | } 67 | 68 | 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /jndc_core/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | jndc 7 | org.view 8 | 1.0 9 | 10 | 4.0.0 11 | 12 | jndc_core 13 | 14 | 15 | 16 | 17 | org.projectlombok 18 | lombok 19 | 20 | 21 | 22 | io.netty 23 | netty-all 24 | 25 | 26 | 27 | org.yaml 28 | snakeyaml 29 | 30 | 31 | 32 | 33 | com.fasterxml.jackson.core 34 | jackson-databind 35 | 36 | 37 | 38 | ch.qos.logback 39 | logback-classic 40 | 41 | 42 | 43 | org.flywaydb 44 | flyway-core 45 | 46 | 47 | 48 | org.flywaydb 49 | flyway-mysql 50 | 51 | 52 | 53 | commons-io 54 | commons-io 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/utils/JSONUtils.java: -------------------------------------------------------------------------------- 1 | package jndc.utils; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import lombok.extern.slf4j.Slf4j; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | @Slf4j 11 | public class JSONUtils { 12 | 13 | private static final ObjectMapper objectMapper = new ObjectMapper(); 14 | 15 | public static byte[] object2JSON(Object invoke) { 16 | 17 | try { 18 | return objectMapper.writeValueAsBytes(invoke); 19 | } catch (JsonProcessingException e) { 20 | throw new RuntimeException(e); 21 | } 22 | } 23 | 24 | public static String object2JSONString(Object invoke) { 25 | 26 | try { 27 | return objectMapper.writeValueAsString(invoke); 28 | } catch (JsonProcessingException e) { 29 | throw new RuntimeException(e); 30 | } 31 | } 32 | 33 | 34 | public static T str2Object(String str, Class tClass) { 35 | try { 36 | return objectMapper.readValue(str, tClass); 37 | } catch (JsonProcessingException e) { 38 | e.printStackTrace(); 39 | log.error("deserialization fail ,cause" + e); 40 | throw new RuntimeException(e); 41 | } 42 | } 43 | 44 | 45 | public static List str2ObjectArray(String s, Class tClass) { 46 | Class arrayClass = ReflectionCache.getClassCache(tClass).getArrayClass(); 47 | try { 48 | T[] array = (T[]) objectMapper.readValue(s, arrayClass); 49 | List list = new ArrayList<>(); 50 | for (int i = 0; i < array.length; i++) { 51 | list.add(array[i]); 52 | } 53 | return list; 54 | } catch (JsonProcessingException e) { 55 | log.error("deserialization array fail ,cause", e); 56 | throw new RuntimeException(e); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /jndc_client/jndc-client-backend/src/main/java/jndc_client/web_support/mapping/ManageMapping.java: -------------------------------------------------------------------------------- 1 | package jndc_client.web_support.mapping; 2 | 3 | 4 | import jndc.utils.JSONUtils; 5 | import jndc.web_support.core.JNDCHttpRequest; 6 | import jndc.web_support.core.WebMapping; 7 | import jndc.web_support.model.dto.LoginUser; 8 | import jndc.web_support.model.dto.ResponseMessage; 9 | import jndc.web_support.utils.AuthUtils; 10 | import jndc_client.web_support.utils.ClientUrlConstant; 11 | import lombok.extern.slf4j.Slf4j; 12 | 13 | import java.net.InetAddress; 14 | import java.nio.ByteBuffer; 15 | 16 | /** 17 | * singleton, thread unsafe 18 | */ 19 | @Slf4j 20 | public class ManageMapping { 21 | 22 | /** 23 | * 登录 24 | * 25 | * @param jndcHttpRequest 26 | * @return 27 | */ 28 | @WebMapping(path = ClientUrlConstant.Management.login) 29 | public ResponseMessage login(JNDCHttpRequest jndcHttpRequest) { 30 | 31 | 32 | byte[] body = jndcHttpRequest.getBody(); 33 | String s = new String(body); 34 | LoginUser loginUser = JSONUtils.str2Object(s, LoginUser.class); 35 | if (AuthUtils.doLogin(loginUser)) { 36 | InetAddress remoteAddress = jndcHttpRequest.getRemoteAddress(); 37 | byte[] address = remoteAddress.getAddress(); 38 | 39 | //时间戳 40 | ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES); 41 | buffer.putLong(System.currentTimeMillis() + 60 * 60 * 1000); 42 | byte[] array = buffer.array(); 43 | 44 | //mix data 45 | byte[] newByte = new byte[address.length + 8]; 46 | for (int i = 0; i < newByte.length; ++i) { 47 | newByte[i] = i < array.length ? array[i] : address[i - array.length]; 48 | } 49 | 50 | //编码 51 | String s1 = AuthUtils.webAuthTokenEncode(newByte); 52 | return ResponseMessage.success(s1); 53 | 54 | } else { 55 | return ResponseMessage.fail("密码错误"); 56 | } 57 | } 58 | 59 | 60 | 61 | 62 | } 63 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/utils/PathUtils.java: -------------------------------------------------------------------------------- 1 | package jndc.utils; 2 | 3 | import javax.swing.filechooser.FileSystemView; 4 | import java.io.File; 5 | 6 | public class PathUtils { 7 | private static final ClassLoader classLoader = PathUtils.class.getClassLoader(); 8 | 9 | private static volatile String RUN_TIME_PATH; 10 | 11 | public static String getDesktopPath() { 12 | return getDesktopPath(File.separator); 13 | } 14 | 15 | 16 | /** 17 | * 从多个地址中获取至少一个有效地址 18 | * 19 | * @param address 20 | * @return 21 | */ 22 | public static String findExistPath(String... address) { 23 | for (int i = 0; i < address.length; i++) { 24 | if (new File(address[i]).exists()) { 25 | return (address[i]); 26 | } 27 | } 28 | throw new RuntimeException("数组中没有有效地址"); 29 | } 30 | 31 | 32 | /** 33 | * 获取运行时路径 34 | * 35 | * @return 36 | */ 37 | public static String getRunTimePath() { 38 | if (RUN_TIME_PATH == null) { 39 | RUN_TIME_PATH = System.getProperty("user.dir"); 40 | if (OSUtils.isLinux()) { 41 | if (!RUN_TIME_PATH.startsWith("/")) { 42 | RUN_TIME_PATH = "/" + RUN_TIME_PATH; 43 | } 44 | } 45 | } 46 | 47 | 48 | return RUN_TIME_PATH; 49 | 50 | } 51 | 52 | 53 | public static String getDesktopPath(String singleDir) { 54 | FileSystemView fsv = FileSystemView.getFileSystemView(); 55 | File com = fsv.getHomeDirectory(); 56 | String Desktop = com.getPath(); 57 | return Desktop + File.separator + singleDir + File.separator; 58 | } 59 | 60 | public static String systemPath2JavaPackagePath(String systemPath) { 61 | String s = systemPath.replaceAll("/", ".").replaceAll("\\\\", "."); 62 | return s; 63 | 64 | } 65 | 66 | public static String javaPackagePath2SystemPath(String javaPackage) { 67 | String s = javaPackage.replaceAll("\\.", "/"); 68 | return s; 69 | 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/web_support/http_module/HostRouterComponent.java: -------------------------------------------------------------------------------- 1 | package jndc_server.web_support.http_module; 2 | 3 | import io.netty.util.internal.StringUtil; 4 | import jndc.core.data_store_support.DBWrapper; 5 | import jndc_server.web_support.model.d_o.HttpHostRoute; 6 | 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.concurrent.ConcurrentHashMap; 10 | 11 | /** 12 | * 域名路由 13 | */ 14 | public class HostRouterComponent { 15 | private final Map map = new ConcurrentHashMap<>(); 16 | private volatile boolean initFinished = false; 17 | 18 | public void addRule(HttpHostRoute newRule) { 19 | map.put(newRule.getHostKeyWord(), newRule); 20 | } 21 | 22 | public void removeRule(HttpHostRoute oldRule) { 23 | map.remove(oldRule.getHostKeyWord()); 24 | } 25 | 26 | public void updateRule(HttpHostRoute oldRule, HttpHostRoute newRule) { 27 | removeRule(oldRule); 28 | addRule(newRule); 29 | 30 | } 31 | 32 | 33 | public static String parseHost(String host) { 34 | String[] split = host.split("\\."); 35 | if (split.length<3){ 36 | return ""; 37 | } 38 | 39 | return split[0]; 40 | 41 | 42 | } 43 | 44 | public HttpHostRoute matchHost(String host) { 45 | if (StringUtil.isNullOrEmpty(host)) { 46 | return null; 47 | } 48 | 49 | if (!initFinished) { 50 | init(); 51 | } 52 | return map.get(parseHost(host)); 53 | } 54 | 55 | 56 | public void init() { 57 | synchronized (HostRouterComponent.class) { 58 | if (!initFinished) { 59 | DBWrapper dbWrapper = DBWrapper.getDBWrapper(HttpHostRoute.class); 60 | List httpHostRoutes = dbWrapper.listAll(); 61 | httpHostRoutes.forEach(x -> { 62 | map.put(x.getHostKeyWord(), x); 63 | }); 64 | initFinished=true; 65 | } 66 | } 67 | 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/resources/conf/db/migration_mysql/V1__init_tables.sql: -------------------------------------------------------------------------------- 1 | 2 | CREATE TABLE IF NOT EXISTS `jndc`.`server_port_bind` ( 3 | `id` varchar(128) NOT NULL COMMENT '编号', 4 | `name` varchar(255) NULL COMMENT '名称', 5 | `bind_client_id` varchar(255) NULL COMMENT '客户端id', 6 | `enable_date_range` varchar(255) NULL COMMENT '可用时间范围', 7 | `port` int(11) NULL COMMENT '端口', 8 | `port_enable` int(1) NULL COMMENT '端口是否可用', 9 | `route_to` varchar(255) NULL COMMENT '路由链路', 10 | PRIMARY KEY (`id`) 11 | ) COMMENT = '端口绑定记录表'; 12 | 13 | CREATE TABLE IF NOT EXISTS `jndc`.`channel_context_record` ( 14 | `id` varchar(128) NOT NULL COMMENT '编号', 15 | `ip` varchar(255) NULL COMMENT 'ip地址', 16 | `channel_id` varchar(255) NULL COMMENT '隧道id', 17 | `port` int(8) NULL COMMENT '端口', 18 | `time_stamp` bigint(20) NULL COMMENT '时间戳', 19 | PRIMARY KEY (`id`) 20 | ) COMMENT = '隧道记录表'; 21 | 22 | CREATE TABLE IF NOT EXISTS `jndc`.`server_ip_filter_rule` ( 23 | `id` varchar(32) NOT NULL COMMENT '编号', 24 | `ip` varchar(16) NULL COMMENT 'ip地址', 25 | `type` int(1) NULL COMMENT '类型', 26 | PRIMARY KEY (`id`) 27 | ) COMMENT = 'ip过滤规则表'; 28 | 29 | CREATE TABLE IF NOT EXISTS `jndc`.`http_host_route` ( 30 | `id` varchar(128) NOT NULL COMMENT '编号', 31 | `route_type` int NULL COMMENT '路由类型', 32 | `host_key_word` varchar(255) NULL COMMENT '路由域', 33 | `fixed_response` varchar(2000) NULL COMMENT '固定返回', 34 | `redirect_address` varchar(255) NULL COMMENT '重定向地址', 35 | `fixed_content_type` varchar(255) NULL COMMENT '固定返回类型content-type', 36 | `forward_host` varchar(255) NULL COMMENT '转发地址', 37 | `forward_protocol` varchar(255) NULL COMMENT '转发协议', 38 | `forward_port` int NULL COMMENT '转发端口', 39 | PRIMARY KEY (`id`) 40 | ) COMMENT = 'http域名配置表'; 41 | 42 | CREATE TABLE IF NOT EXISTS `jndc`.`ip_filter_record` ( 43 | `id` varchar(32) NOT NULL COMMENT '编号', 44 | `ip` varchar(255) NULL COMMENT 'ip地址', 45 | `v_count` int(32) NULL COMMENT '记录值', 46 | `time_stamp` bigint(20) NULL COMMENT '时间', 47 | `record_type` int(1) NULL COMMENT '记录类型', 48 | PRIMARY KEY (`id`) 49 | ) COMMENT = 'IP过滤记录表'; -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/core/data_store_support/DBOperationI.java: -------------------------------------------------------------------------------- 1 | package jndc.core.data_store_support; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * 基础数据库操作 7 | * 8 | * @param 9 | */ 10 | public interface DBOperationI { 11 | /** 12 | * 插入 13 | * 14 | * @param t 15 | */ 16 | public void insert(T t); 17 | 18 | /** 19 | * 批量新增 20 | * 21 | * @param t 22 | */ 23 | public void insertBatch(List t); 24 | 25 | /** 26 | * 主键更新 27 | * 28 | * @param t 29 | */ 30 | public void updateByPrimaryKey(T t); 31 | 32 | /** 33 | * 主键删除 34 | * 35 | * @param t 36 | */ 37 | public void deleteByPrimaryKey(T t); 38 | 39 | /** 40 | * 查询所有 41 | * 42 | * @return 43 | */ 44 | public List listAll(); 45 | 46 | /** 47 | * 自定义查询 48 | * 49 | * @param sql 50 | * @param params 51 | * @return 52 | */ 53 | public List customQuery(String sql, Object... params); 54 | 55 | /** 56 | * 自定义分页查询 57 | * 58 | * @param sql 59 | * @param page 60 | * @param rows 61 | * @param params 62 | * @return 63 | */ 64 | public PageResult customQueryByPage(String sql, int page, int rows, Object... params); 65 | 66 | /** 67 | * 计数 68 | * 69 | * @return 70 | */ 71 | public Integer count(); 72 | 73 | /** 74 | * 自定义查询单对象 75 | * 76 | * @param sql 77 | * @param params 78 | * @return 79 | */ 80 | public T customQuerySingle(String sql, Object... params); 81 | 82 | /** 83 | * 自定义查询单值 84 | * 85 | * @param valueKey 86 | * @param sql 87 | * @param f 88 | * @param params 89 | * @param 90 | * @return 91 | */ 92 | public V customQuerySingleValue(String valueKey, String sql, Class f, Object... params); 93 | 94 | /** 95 | * 自定义检索 96 | * 97 | * @param sql 98 | * @param params 99 | */ 100 | public void customExecute(String sql, Object[] params); 101 | } 102 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-frontend/src/views/item_detail/edg_operation/action_edg.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 60 | 61 | 64 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/utils/InetUtils.java: -------------------------------------------------------------------------------- 1 | package jndc.utils; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import sun.net.util.IPAddressUtil; 5 | 6 | import java.net.InetAddress; 7 | import java.net.UnknownHostException; 8 | 9 | @Slf4j 10 | public class InetUtils { 11 | 12 | public static InetAddress localInetAddress; 13 | 14 | public static String uniqueInetTag; 15 | 16 | static { 17 | loadMacAddress(); 18 | loadLocalInetAddress(); 19 | } 20 | 21 | 22 | 23 | public static InetAddress getInetAddressByHost(String host) { 24 | try { 25 | InetAddress address = InetAddress.getByName(host); 26 | return address; 27 | } catch (UnknownHostException e) { 28 | e.printStackTrace(); 29 | throw new RuntimeException("can not know the host: " + host); 30 | } 31 | } 32 | 33 | public static InetAddress getByStringIpAddress(String ipAddress) { 34 | InetAddress byAddress = null; 35 | try { 36 | byte[] bytes = IPAddressUtil.textToNumericFormatV4(ipAddress); 37 | if (bytes == null) { 38 | byAddress = getInetAddressByHost(ipAddress); 39 | } else { 40 | byAddress = InetAddress.getByAddress(bytes); 41 | } 42 | } catch (Exception e) { 43 | log.error("un know host :" + ipAddress); 44 | ApplicationExit.exit(); 45 | } 46 | return byAddress; 47 | } 48 | 49 | 50 | /** 51 | * get local address 52 | */ 53 | private static void loadLocalInetAddress() { 54 | try { 55 | localInetAddress = InetAddress.getByName("0.0.0.0"); 56 | } catch (UnknownHostException e) { 57 | log.error("get local adress error"); 58 | ApplicationExit.exit(); 59 | 60 | } 61 | } 62 | 63 | /** 64 | * get local mac address 65 | */ 66 | private static void loadMacAddress() { 67 | try { 68 | uniqueInetTag = GetNetworkAddress.GetAddress("ip") + "/" + GetNetworkAddress.GetAddress("mac"); 69 | } catch (Exception e) { 70 | uniqueInetTag = "0.0.0.0/" + UUIDSimple.id(); 71 | } 72 | } 73 | 74 | 75 | } 76 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/web_support/core/MessageNotificationCenter.java: -------------------------------------------------------------------------------- 1 | package jndc.web_support.core; 2 | 3 | import io.netty.channel.Channel; 4 | import io.netty.channel.group.ChannelGroup; 5 | import io.netty.channel.group.DefaultChannelGroup; 6 | import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; 7 | import io.netty.util.concurrent.ImmediateEventExecutor; 8 | import jndc.utils.JSONUtils; 9 | import jndc.utils.ThreadQueue; 10 | 11 | /** 12 | * broadcast message notification to the web 13 | */ 14 | public class MessageNotificationCenter { 15 | private static final int TYPE_DATA_REFRESH = 1; 16 | 17 | private static final int TYPE_NOTICE_MESSAGE = 2; 18 | 19 | private ChannelGroup channelGroup = new DefaultChannelGroup(ImmediateEventExecutor.INSTANCE); 20 | 21 | private ThreadQueue threadQueue; 22 | 23 | public MessageNotificationCenter() { 24 | threadQueue = new ThreadQueue(); 25 | } 26 | 27 | public void websocketRegister(Channel channel) { 28 | channelGroup.add(channel); 29 | } 30 | 31 | public void noticeMessage(String msg) { 32 | threadQueue.submit(() -> { 33 | channelGroup.writeAndFlush(new TextWebSocketFrame(new NoticeMessage(TYPE_NOTICE_MESSAGE, msg).toJSON())); 34 | }); 35 | 36 | } 37 | 38 | public void dateRefreshMessage(String msg) { 39 | threadQueue.submit(() -> { 40 | channelGroup.writeAndFlush(new TextWebSocketFrame(new NoticeMessage(TYPE_DATA_REFRESH, msg).toJSON())); 41 | }); 42 | } 43 | 44 | public class NoticeMessage { 45 | private int type; 46 | private String data; 47 | 48 | 49 | public String toJSON() { 50 | return JSONUtils.object2JSONString(this); 51 | } 52 | 53 | public NoticeMessage(int type, String data) { 54 | this.type = type; 55 | this.data = data; 56 | } 57 | 58 | public int getType() { 59 | return type; 60 | } 61 | 62 | public void setType(int type) { 63 | this.type = type; 64 | } 65 | 66 | public String getData() { 67 | return data; 68 | } 69 | 70 | public void setData(String data) { 71 | this.data = data; 72 | } 73 | } 74 | 75 | 76 | } 77 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/core/filter/AllowTimeRule.java: -------------------------------------------------------------------------------- 1 | package jndc_server.core.filter; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import jndc.core.UniqueBeanManage; 5 | import jndc_server.config.JNDCServerConfig; 6 | import jndc_server.core.AsynchronousEventCenter; 7 | import jndc_server.core.NDCServerConfigCenter; 8 | import jndc_server.core.port_app.ServerPortProtector; 9 | import lombok.extern.slf4j.Slf4j; 10 | 11 | import java.net.InetSocketAddress; 12 | import java.util.Map; 13 | 14 | @Slf4j 15 | public class AllowTimeRule implements CustomRule { 16 | 17 | private volatile NDCServerConfigCenter ndcServerConfigCenter; 18 | 19 | private volatile int ignorePort; 20 | 21 | @Override 22 | public String ruleCheck(ChannelHandlerContext ctx) { 23 | InetSocketAddress remoteAddress = (InetSocketAddress) ctx.channel().remoteAddress(); 24 | InetSocketAddress socketAddress = (InetSocketAddress) ctx.channel().localAddress(); 25 | int port = socketAddress.getPort(); 26 | if (ndcServerConfigCenter == null) { 27 | synchronized (AllowTimeRule.class) { 28 | if (ndcServerConfigCenter == null) { 29 | ndcServerConfigCenter = UniqueBeanManage.getBean(NDCServerConfigCenter.class); 30 | ignorePort = UniqueBeanManage.getBean(JNDCServerConfig.class).getServicePort(); 31 | } 32 | } 33 | } 34 | 35 | if (port == ignorePort) { 36 | //todo 通过 37 | return null; 38 | } 39 | 40 | Map tcpRouter = ndcServerConfigCenter.getTcpRouter(); 41 | AsynchronousEventCenter.ServerPortBindContext serverPortBindContext = tcpRouter.get(port); 42 | ServerPortProtector serverPortProtector = serverPortBindContext.getServerPortProtector(); 43 | //确认时间 44 | boolean b = serverPortProtector.checkBetweenEnableTimeRange(); 45 | if (!b) { 46 | //todo false 47 | log.error("reject request from " + remoteAddress + " ,because out of service available time"); 48 | return getRuleName() + "端口非可用时段"; 49 | } 50 | return null; 51 | } 52 | 53 | @Override 54 | public String getRuleName() { 55 | return "Allow Time Rule"; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/core/app/JndcCoreServer.java: -------------------------------------------------------------------------------- 1 | package jndc_server.core.app; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.Channel; 5 | import io.netty.channel.ChannelInitializer; 6 | import io.netty.channel.ChannelPipeline; 7 | import io.netty.channel.EventLoopGroup; 8 | import io.netty.channel.socket.nio.NioServerSocketChannel; 9 | import jndc.core.NDCPCodec; 10 | import jndc.core.NettyComponentConfig; 11 | import jndc.core.SecreteCodec; 12 | import jndc.core.UniqueBeanManage; 13 | import jndc_server.config.JNDCServerConfig; 14 | import jndc_server.core.filter.CustomRulesFilter; 15 | import lombok.extern.slf4j.Slf4j; 16 | 17 | /** 18 | * jndc server core functions 19 | */ 20 | @Slf4j 21 | public class JndcCoreServer implements ServerApp{ 22 | private EventLoopGroup eventLoopGroup = NettyComponentConfig.getNioEventLoopGroup(); 23 | 24 | @Override 25 | public void start() { 26 | JNDCServerConfig serverConfig = UniqueBeanManage.getBean(JNDCServerConfig.class); 27 | 28 | ChannelInitializer channelInitializer = new ChannelInitializer() { 29 | 30 | @Override 31 | protected void initChannel(Channel channel) throws Exception { 32 | ChannelPipeline pipeline = channel.pipeline(); 33 | 34 | 35 | pipeline.addFirst(NDCPCodec.NAME, new NDCPCodec()); 36 | pipeline.addAfter(NDCPCodec.NAME, SecreteCodec.NAME, new SecreteCodec()); 37 | pipeline.addAfter(SecreteCodec.NAME, CustomRulesFilter.NAME, CustomRulesFilter.STATIC_INSTANCE); 38 | pipeline.addAfter(CustomRulesFilter.NAME, JNDCServerMessageHandle.NAME, new JNDCServerMessageHandle()); 39 | } 40 | }; 41 | 42 | ServerBootstrap b = new ServerBootstrap(); 43 | b.group(eventLoopGroup) 44 | .channel(NioServerSocketChannel.class)// 45 | .localAddress(serverConfig.getInetSocketAddress())//  46 | .childHandler(channelInitializer); 47 | 48 | b.bind().addListener(x -> { 49 | if (x.isSuccess()) { 50 | log.info("核心服务: jndc://" + serverConfig.getInetSocketAddress() + " 启动成功"); 51 | } else { 52 | log.error("核心服务: jndc://" + serverConfig.getInetSocketAddress() + " 启动失败"); 53 | } 54 | 55 | }); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/core/filter/CustomRulesFilter.java: -------------------------------------------------------------------------------- 1 | package jndc_server.core.filter; 2 | 3 | import io.netty.channel.ChannelFutureListener; 4 | import io.netty.channel.ChannelHandler; 5 | import io.netty.channel.ChannelHandlerContext; 6 | import io.netty.channel.ChannelInboundHandlerAdapter; 7 | import jndc.core.NDCMessageProtocol; 8 | import jndc.core.message.UserError; 9 | import jndc.utils.ObjectSerializableUtils; 10 | import lombok.extern.slf4j.Slf4j; 11 | 12 | import java.net.InetAddress; 13 | import java.util.ArrayList; 14 | import java.util.Iterator; 15 | import java.util.List; 16 | 17 | 18 | /** 19 | * 自定义规则过滤器 20 | */ 21 | @Slf4j 22 | @ChannelHandler.Sharable 23 | public class CustomRulesFilter extends ChannelInboundHandlerAdapter { 24 | 25 | public static String NAME = "CUSTOM_RULES_FILTER"; 26 | 27 | public static final CustomRulesFilter STATIC_INSTANCE = new CustomRulesFilter(); 28 | 29 | private static List customRuleList = new ArrayList<>(); 30 | 31 | static { 32 | //添加过滤器 33 | customRuleList.add(new IpAddressRule()); 34 | customRuleList.add(new AllowTimeRule()); 35 | } 36 | 37 | @Override 38 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 39 | Iterator iterator = customRuleList.iterator(); 40 | while (iterator.hasNext()) { 41 | CustomRule next = iterator.next(); 42 | String errMsg = next.ruleCheck(ctx); 43 | if (errMsg != null) { 44 | //todo not pass 45 | log.debug("拦截请求 :" + errMsg); 46 | 47 | UserError userError = new UserError(); 48 | userError.setDescription(errMsg); 49 | byte[] bytes = ObjectSerializableUtils.object2bytes(userError); 50 | 51 | 52 | //发送异常信息 53 | InetAddress unused = InetAddress.getLocalHost(); 54 | NDCMessageProtocol tqs = NDCMessageProtocol.of(unused, unused, NDCMessageProtocol.UN_USED_PORT, NDCMessageProtocol.UN_USED_PORT, NDCMessageProtocol.UN_USED_PORT, NDCMessageProtocol.USER_ERROR); 55 | tqs.setData(bytes); 56 | ctx.writeAndFlush(tqs).addListeners(ChannelFutureListener.CLOSE); 57 | return; 58 | } 59 | } 60 | 61 | //通过,进入下一环节 62 | ctx.fireChannelActive(); 63 | } 64 | 65 | 66 | } 67 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-frontend/src/config/routeConfig.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import {Message} from 'element-ui' 4 | 5 | Vue.use(Router) 6 | 7 | const originalPush = Router.prototype.push 8 | 9 | Router.prototype.push = function push(location) { 10 | return originalPush.call(this, location).catch(err => err) 11 | } 12 | 13 | const router = new Router({ 14 | 15 | routes: [ 16 | { 17 | path: '*', 18 | component: () => import('@/views/resourceNotFound') 19 | }, 20 | { 21 | path: '/', 22 | component: () => import('@/views/login') 23 | }, 24 | { 25 | path: '/dag', 26 | component: () => import('@/views/dag') 27 | }, 28 | { 29 | path: '/management', 30 | component: () => import('@/views/management'), 31 | children: [ 32 | { 33 | path: 'channel', 34 | component: () => import('@/views/channelList') 35 | }, 36 | { 37 | path: 'services', 38 | component: () => import('@/views/serviceList') 39 | }, 40 | { 41 | path: 'serverPortList', 42 | component: () => import('@/views/serverPortList') 43 | }, 44 | { 45 | path: 'ipFilter', 46 | component: () => import('@/views/ipFilter') 47 | }, 48 | { 49 | path: 'httpApp', 50 | component: () => import('@/views/HttpApp') 51 | } 52 | ] 53 | 54 | } 55 | ] 56 | }) 57 | 58 | let unAuthUrl = ['/', '/login', '/rtc', '/dag'] 59 | 60 | function isInUnAuthList(url) { 61 | let rs = false 62 | unAuthUrl.forEach(x => { 63 | if (url == x) { 64 | rs = true 65 | } 66 | }) 67 | return rs 68 | } 69 | 70 | router.beforeEach((to, from, next) => { 71 | if (isInUnAuthList(to.path)) { 72 | next() 73 | } else { 74 | let auth = localStorage.getItem('auth-token') 75 | if (null == auth) { 76 | Message.error('凭证过期,请重新登录'); 77 | next({path: '/'}) 78 | } else { 79 | next() 80 | } 81 | } 82 | }) 83 | 84 | export default router 85 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/core/AsynchronousEventCenter.java: -------------------------------------------------------------------------------- 1 | package jndc_server.core; 2 | 3 | import jndc.core.NDCMessageProtocol; 4 | import jndc.utils.ThreadQueue; 5 | import jndc_server.core.port_app.ServerPortProtector; 6 | import lombok.Data; 7 | 8 | /** 9 | * 异步事件中心 10 | */ 11 | public class AsynchronousEventCenter { 12 | 13 | //数据库事件运行队列 14 | private static ThreadQueue dbAsynchronousEventQueue; 15 | 16 | //系统事件运行队列 17 | private static ThreadQueue systemRunningEventQueue; 18 | 19 | //流量分析队列 20 | private static ThreadQueue dataFlowAnalyseRunningEventQueue; 21 | 22 | static { 23 | dbAsynchronousEventQueue = new ThreadQueue("DB_ASYNC_QUEUE"); 24 | systemRunningEventQueue = new ThreadQueue("SYSTEM_QUEUE"); 25 | dataFlowAnalyseRunningEventQueue = new ThreadQueue("ANALYSE_QUEUE"); 26 | } 27 | 28 | 29 | public void dbJob(Runnable runnable) { 30 | dbAsynchronousEventQueue.submit(runnable); 31 | } 32 | 33 | public void systemRunningJob(Runnable runnable) { 34 | systemRunningEventQueue.submit(runnable); 35 | } 36 | 37 | public void dataAnalyseJob(Runnable runnable) { 38 | dataFlowAnalyseRunningEventQueue.submit(runnable); 39 | } 40 | 41 | /** 42 | * 端口绑定上下文 43 | */ 44 | @Data 45 | public static class ServerPortBindContext { 46 | private int port; 47 | 48 | //0 物理端口 1 虚拟端口 49 | private int virtualTag; 50 | 51 | //端口监听对象,接收端口所有tcp请求(对外) 52 | private ServerPortProtector serverPortProtector; 53 | 54 | //端口绑定服务描述(对内) 55 | private ServerServiceDescription serverServiceDescription; 56 | 57 | 58 | public ServerPortBindContext(int port) { 59 | this.port = port; 60 | } 61 | 62 | public void releaseRelatedResources() { 63 | //判断是否为物理端口 64 | if (isPhysics()) { 65 | //todo 释放端口监听器 66 | serverPortProtector.releaseRelatedResources(); 67 | } 68 | } 69 | 70 | public boolean isPhysics() { 71 | return getVirtualTag() == 0; 72 | } 73 | 74 | 75 | public void receiveMessage(NDCMessageProtocol ndcMessageProtocol) { 76 | serverPortProtector.receiveMessage(ndcMessageProtocol); 77 | } 78 | 79 | public void connectionInterrupt(NDCMessageProtocol ndcMessageProtocol) { 80 | serverPortProtector.connectionInterrupt(ndcMessageProtocol); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /jndc_client/jndc-client-backend/src/main/java/jndc_client/start/ClientStart.java: -------------------------------------------------------------------------------- 1 | package jndc_client.start;//package jndc.core; 2 | 3 | 4 | import jndc.utils.ApplicationExit; 5 | import jndc.utils.PathUtils; 6 | import jndc.utils.YmlParser; 7 | import jndc_client.core.JNDCClientConfig; 8 | import jndc_client.core.JNDClientApp; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.apache.commons.io.IOUtils; 11 | 12 | import java.io.File; 13 | import java.io.FileInputStream; 14 | 15 | 16 | @Slf4j 17 | public class ClientStart { 18 | //全局id 19 | public static String CLIENT_ID; 20 | 21 | public static final YmlParser ymlParser = new YmlParser(); 22 | 23 | public static void main(String[] args) { 24 | 25 | Runtime.getRuntime().addShutdownHook(new Thread(() -> { 26 | log.info("Good night everyone "); 27 | })); 28 | 29 | 30 | String runTimePath = PathUtils.getRunTimePath(); 31 | log.info("读取运行目录: " + runTimePath); 32 | 33 | String configPath = runTimePath + File.separator + ".." + File.separator + "conf" + File.separator + "config.yml"; 34 | 35 | 36 | //读取启动指令配置文件地址 37 | if (args.length>0){ 38 | String typeConfigPath = args[0]; 39 | if (typeConfigPath.endsWith(".yml")){ 40 | configPath= typeConfigPath; 41 | } 42 | } 43 | 44 | File file = new File(configPath); 45 | if (!file.exists()) { 46 | log.error("读取配置文件失败,请检查 " + configPath + " 目录下是否存在"); 47 | ApplicationExit.exit(); 48 | } 49 | 50 | 51 | JNDCClientConfig jndcClientConfig = null; 52 | try { 53 | jndcClientConfig = ymlParser.parseFile(file, JNDCClientConfig.class); 54 | if (jndcClientConfig == null) { 55 | log.error("please check the content:\n=====content_start=====\n" + new String(IOUtils.toByteArray(new FileInputStream(file))) + "\n=====content_end=====\n on config.yml"); 56 | ApplicationExit.exit(); 57 | } 58 | jndcClientConfig.performParameterVerification(); 59 | jndcClientConfig.loadClientId(); 60 | log.info("client time out--->" + jndcClientConfig.getAutoReleaseTimeOut()); 61 | } catch (Exception e) { 62 | e.printStackTrace(); 63 | log.error("parse config file fail" + e); 64 | ApplicationExit.exit(); 65 | } 66 | 67 | 68 | JNDClientApp jndClientApp = new JNDClientApp(); 69 | jndClientApp.createClient(); 70 | 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/core/SecreteCodec.java: -------------------------------------------------------------------------------- 1 | package jndc.core; 2 | 3 | 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.handler.codec.MessageToMessageCodec; 6 | import jndc.exception.SecreteDecodeFailException; 7 | import jndc.utils.AESDataEncryption; 8 | import jndc.utils.DataEncryption; 9 | import jndc.utils.InetUtils; 10 | import lombok.extern.slf4j.Slf4j; 11 | 12 | import java.util.List; 13 | 14 | 15 | /** 16 | * 加解密 17 | */ 18 | @Slf4j 19 | public class SecreteCodec extends MessageToMessageCodec { 20 | public static final String NAME = "SECRETE_CODEC"; 21 | 22 | //对称加密 23 | private static DataEncryption dataEncryption = new AESDataEncryption(); 24 | 25 | /** 26 | * 加密 27 | * 28 | * @param channelHandlerContext 29 | * @param ndcMessageProtocol 30 | * @param list 31 | * @throws Exception 32 | */ 33 | @Override 34 | protected void encode(ChannelHandlerContext channelHandlerContext, NDCMessageProtocol ndcMessageProtocol, List list) throws Exception { 35 | //仅针对数据部分做处理 36 | byte[] data = ndcMessageProtocol.getData(); 37 | ndcMessageProtocol.setData(dataEncryption.encode(data)); 38 | list.add(ndcMessageProtocol); 39 | } 40 | 41 | /** 42 | * 解密 43 | * 44 | * @param channelHandlerContext 45 | * @param ndcMessageProtocol 46 | * @param list 47 | * @throws Exception 48 | */ 49 | @Override 50 | protected void decode(ChannelHandlerContext channelHandlerContext, NDCMessageProtocol ndcMessageProtocol, List list) throws Exception { 51 | if (ndcMessageProtocol.NO_ACCESS == ndcMessageProtocol.getType()) { 52 | log.error("连接密码错误..."); 53 | System.exit(1); 54 | } 55 | 56 | //仅针对数据部分做处理 57 | byte[] data = ndcMessageProtocol.getData(); 58 | try { 59 | ndcMessageProtocol.setData(dataEncryption.decode(data)); 60 | list.add(ndcMessageProtocol); 61 | } catch (SecreteDecodeFailException exception) { 62 | //todo 解码异常 63 | 64 | //发送异常提示消息 65 | NDCMessageProtocol err = NDCMessageProtocol.of(InetUtils.localInetAddress, InetUtils.localInetAddress, NDCMessageProtocol.UN_USED_PORT, NDCMessageProtocol.UN_USED_PORT, NDCMessageProtocol.UN_USED_PORT, NDCMessageProtocol.NO_ACCESS); 66 | ndcMessageProtocol.setData(NDCMessageProtocol.BLANK); 67 | channelHandlerContext.writeAndFlush(err); 68 | channelHandlerContext.close();//关闭链接 69 | } 70 | 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/core/NDCPCodec.java: -------------------------------------------------------------------------------- 1 | package jndc.core; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.handler.codec.ByteToMessageCodec; 6 | import io.netty.util.ResourceLeakDetector; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * 接编码器 12 | */ 13 | public class NDCPCodec extends ByteToMessageCodec { 14 | 15 | public static final String NAME="NDC"; 16 | 17 | private volatile NDCMessageProtocol ndcMessageProtocol; 18 | 19 | 20 | static { 21 | //设置Netty泄露检测的级别 22 | ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.ADVANCED); 23 | } 24 | 25 | @Override 26 | protected void encode(ChannelHandlerContext channelHandlerContext, NDCMessageProtocol NDCMessageProtocol, ByteBuf byteBuf) { 27 | //auto unpack 28 | List list = NDCMessageProtocol.autoUnpack(); 29 | list.forEach(x -> { 30 | byteBuf.writeBytes(x.toByteArray()); 31 | }); 32 | 33 | } 34 | 35 | @Override 36 | protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List list) { 37 | int i = byteBuf.readableBytes(); 38 | if (ndcMessageProtocol == null) { 39 | //todo 未完成报文填充 40 | if (i >= NDCMessageProtocol.FIX_LENGTH) { 41 | //todo 固定长度获取完成 42 | byte[] bytes = new byte[NDCMessageProtocol.FIX_LENGTH]; 43 | byteBuf.readBytes(bytes); 44 | ndcMessageProtocol = NDCMessageProtocol.parseFixInfo(bytes);//解析定长信息 45 | if (ndcMessageProtocol.getDataSize() == 0) { 46 | list.add(ndcMessageProtocol); 47 | ndcMessageProtocol=null; 48 | //丢弃已读字节 49 | byteBuf.discardReadBytes(); 50 | } 51 | }else { 52 | //todo 固定长度未获取完成 53 | } 54 | }else { 55 | //todo 获取到固定长度 56 | int dataSize = ndcMessageProtocol.getDataSize();//获取变长报文长度 57 | if (i >= dataSize) { 58 | //todo 获取到足够动态长度 59 | byte[] bytes = new byte[dataSize]; 60 | byteBuf.readBytes(bytes); 61 | ndcMessageProtocol.setDataWithVerification(bytes); 62 | list.add(ndcMessageProtocol); 63 | ndcMessageProtocol = null; 64 | 65 | //丢弃已读字节 66 | byteBuf.discardReadBytes(); 67 | }else { 68 | //todo 未获取到足够动态长度 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/web_support/model/d_o/HttpHostRoute.java: -------------------------------------------------------------------------------- 1 | package jndc_server.web_support.model.d_o; 2 | 3 | 4 | import jndc.core.data_store_support.DSFiled; 5 | import jndc.core.data_store_support.DSKey; 6 | import jndc.core.data_store_support.DSTable; 7 | import jndc_server.web_support.model.dto.HostRouteDTO; 8 | import lombok.Data; 9 | 10 | @Data 11 | @DSTable(name = "http_host_route") 12 | public class HttpHostRoute { 13 | @DSKey 14 | private String id; 15 | 16 | @DSFiled(name = "host_key_word") 17 | private String hostKeyWord; 18 | 19 | //0 redirect 20 | //1 fixed value 21 | //2 forward 22 | @DSFiled(name = "route_type") 23 | private int routeType; 24 | 25 | @DSFiled(name = "fixed_response") 26 | private String fixedResponse; 27 | 28 | @DSFiled(name = "fixed_content_type") 29 | private String fixedContentType; 30 | 31 | @DSFiled(name = "redirect_address") 32 | private String redirectAddress; 33 | 34 | @DSFiled(name = "forward_host") 35 | private String forwardHost; 36 | 37 | @DSFiled(name = "forward_port") 38 | private int forwardPort; 39 | 40 | @DSFiled(name = "forward_protocol") 41 | private String forwardProtocol; 42 | 43 | public String getForwardProtocol() { 44 | return forwardProtocol; 45 | } 46 | 47 | public void setForwardProtocol(String forwardProtocol) { 48 | this.forwardProtocol = forwardProtocol; 49 | } 50 | 51 | 52 | public boolean fixValueType(){ 53 | //todo 1 54 | return routeType ==1; 55 | } 56 | 57 | public boolean redirectType(){ 58 | //todo 0 59 | return routeType ==0; 60 | } 61 | 62 | public boolean forwardType(){ 63 | //todo 2 64 | return routeType ==2; 65 | } 66 | 67 | public static HttpHostRoute of(HostRouteDTO hostRouteDTO) { 68 | HttpHostRoute httpHostRoute = new HttpHostRoute(); 69 | httpHostRoute.setFixedContentType(hostRouteDTO.getFixedContentType()); 70 | httpHostRoute.setFixedResponse(hostRouteDTO.getFixedResponse()); 71 | httpHostRoute.setHostKeyWord(hostRouteDTO.getHostKeyWord()); 72 | httpHostRoute.setRedirectAddress(hostRouteDTO.getRedirectAddress()); 73 | httpHostRoute.setRouteType(hostRouteDTO.getRouteType()); 74 | httpHostRoute.setForwardHost(hostRouteDTO.getForwardHost()); 75 | httpHostRoute.setForwardPort(hostRouteDTO.getForwardPort()); 76 | httpHostRoute.setForwardProtocol(hostRouteDTO.getForwardProtocol()); 77 | return httpHostRoute; 78 | 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/core/JNDCServerApp.java: -------------------------------------------------------------------------------- 1 | package jndc_server.core; 2 | 3 | import jndc.core.UniqueBeanManage; 4 | import jndc.core.data_store_support.DBWrapper; 5 | import jndc.utils.PathUtils; 6 | import jndc.web_support.config.ServeManageConfig; 7 | import jndc.web_support.http_module.ManagementServer; 8 | import jndc_server.config.JNDCServerConfig; 9 | import jndc_server.core.app.JndcCoreServer; 10 | import jndc_server.databases_object.ServerPortBind; 11 | import jndc_server.web_support.http_module.JNDCHttpServer; 12 | 13 | import java.io.File; 14 | 15 | /** 16 | * 主服务 17 | */ 18 | public class JNDCServerApp { 19 | 20 | public JNDCServerApp() { 21 | } 22 | 23 | 24 | /** 25 | * do some init operation only for server 26 | */ 27 | public void initBelongOnlyInServer() { 28 | ScheduledTaskCenter scheduledTaskCenter = UniqueBeanManage.getBean(ScheduledTaskCenter.class); 29 | scheduledTaskCenter.start(); 30 | } 31 | 32 | 33 | public void createServer() { 34 | //服务端初始化事件 35 | initBelongOnlyInServer(); 36 | 37 | 38 | //重置所有端口使用信息 39 | DBWrapper dbWrapper = DBWrapper.getDBWrapper(ServerPortBind.class); 40 | dbWrapper.customExecute("update server_port_bind set port_enable = 0", null); 41 | 42 | 43 | JNDCServerConfig jndcServerConfig = UniqueBeanManage.getBean(JNDCServerConfig.class); 44 | ServeManageConfig manageConfig = jndcServerConfig.getManageConfig(); 45 | 46 | //处理静态项目地址 47 | if (manageConfig.isAdminEnable()) { 48 | //todo 确认静态项目地址 49 | String runTimePath = PathUtils.getRunTimePath(); 50 | String p1 = runTimePath + File.separator + ".." + File.separator + "compare_dist"; 51 | String p2 = System.getProperty("user.dir") + File.separator + "target" + File.separator + "jndc_server" + File.separator + "compare_dist"; 52 | String p3 = "F:\\java_workspace\\jndc\\jndc_server\\jndc-server-frontend\\compare_dist"; 53 | String runtimeDir = PathUtils.findExistPath(p1, p2,p3); 54 | manageConfig.setAdminProjectPath(runtimeDir); 55 | } 56 | 57 | 58 | //admin管理页面 59 | ManagementServer managementServer = new ManagementServer(); 60 | managementServer.start(manageConfig);//start 61 | 62 | //核心服务 63 | JndcCoreServer jndcCoreServer = new JndcCoreServer(); 64 | jndcCoreServer.start(); 65 | 66 | //http层服务 67 | JNDCHttpServer jndcHttpServer = new JNDCHttpServer(); 68 | jndcHttpServer.start(); 69 | 70 | 71 | } 72 | 73 | 74 | } 75 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/core/data_store_support/SQLiteDataStore.java: -------------------------------------------------------------------------------- 1 | package jndc.core.data_store_support; 2 | 3 | 4 | import jndc.utils.PathUtils; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.flywaydb.core.Flyway; 7 | 8 | import java.io.File; 9 | import java.sql.Connection; 10 | import java.sql.DriverManager; 11 | import java.sql.SQLException; 12 | 13 | /** 14 | * for sqlite only 15 | */ 16 | @Slf4j 17 | public class SQLiteDataStore extends DataStoreAbstract { 18 | 19 | /** 20 | * 连接地址 21 | */ 22 | private String url; 23 | 24 | private static final String SQL_LITE_DB = "jnc_db.db"; 25 | 26 | private static final String PROTOCOL = "jdbc:sqlite:"; 27 | 28 | /** 29 | * 存储目录 30 | */ 31 | private String dbWorkDirect; 32 | 33 | private volatile Connection connection; 34 | 35 | public SQLiteDataStore(String dbWorkDirect) { 36 | this.dbWorkDirect = dbWorkDirect; 37 | if (!this.dbWorkDirect.endsWith(File.separator)) { 38 | this.dbWorkDirect += File.separator; 39 | } 40 | 41 | url = PROTOCOL + this.dbWorkDirect + SQL_LITE_DB; 42 | log.info("SQLite 工作目录:" + url); 43 | } 44 | 45 | 46 | /** 47 | * 获取连接 48 | * 49 | * @return 50 | */ 51 | @Override 52 | public Connection getConnection() { 53 | try { 54 | if (connection == null || connection.isClosed()) { 55 | synchronized (this) { 56 | if (connection == null || connection.isClosed()) { 57 | connection = DriverManager.getConnection(url); 58 | } 59 | } 60 | } 61 | } catch (SQLException sqlException) { 62 | log.error(sqlException + ""); 63 | } 64 | 65 | return connection; 66 | } 67 | 68 | @Override 69 | public void flywayInit() { 70 | String p1 = System.getProperty("user.dir") + File.separator + ".." + File.separator + "conf" + File.separator + "db" + File.separator + "migration_sqlite"; 71 | String p2 = System.getProperty("user.dir") + File.separator + "src" + File.separator + "main" + File.separator + "resources" + File.separator + "conf" + File.separator + "db" + File.separator + "migration_sqlite"; 72 | String devPath = "filesystem:" + PathUtils.findExistPath(p1, p2); 73 | log.info("flyway 读取路径:" + devPath); 74 | Flyway flyway = Flyway.configure() 75 | .locations("classpath:db/migration_sqlite", devPath) 76 | .baselineOnMigrate(true) 77 | .dataSource(url, "", "") 78 | .load(); 79 | flyway.migrate(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/web_support/utils/UriUtils.java: -------------------------------------------------------------------------------- 1 | package jndc.web_support.utils; 2 | 3 | import java.util.Arrays; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | 7 | public class UriUtils { 8 | 9 | 10 | public static ParseResult parseUri(String uri) { 11 | ParseResult parseResult = new ParseResult(); 12 | parseResult.setFullUri(uri); 13 | 14 | StringBuilder stringBuilder = new StringBuilder(); 15 | char[] chars = uri.toCharArray(); 16 | 17 | boolean validString = false; 18 | String key = ""; 19 | String value; 20 | for (int i = 0; i < chars.length; i++) { 21 | if (chars[i] == '?') { 22 | parseResult.setReduceUri(new String(Arrays.copyOfRange(chars, 0, i))); 23 | validString = true; 24 | continue; 25 | } 26 | if (!validString) { 27 | continue; 28 | } 29 | 30 | if (chars[i] == '=' && "".equals(key)) { 31 | key = stringBuilder.toString(); 32 | stringBuilder.setLength(0); 33 | } else if (chars[i] == '&') { 34 | if ("".equals(key)) { 35 | stringBuilder.setLength(0); 36 | continue; 37 | } 38 | value = stringBuilder.toString(); 39 | stringBuilder.setLength(0); 40 | parseResult.put(key, value); 41 | } else { 42 | stringBuilder.append(chars[i]); 43 | } 44 | } 45 | 46 | if (stringBuilder.length() > 0) { 47 | value = stringBuilder.toString(); 48 | parseResult.put(key, value); 49 | } 50 | return parseResult; 51 | } 52 | 53 | public static class ParseResult { 54 | private Map queryMap = new HashMap<>(); 55 | private String reduceUri; 56 | private String fullUri; 57 | 58 | public String getFullUri() { 59 | return fullUri; 60 | } 61 | 62 | public void setFullUri(String fullUri) { 63 | this.fullUri = fullUri; 64 | } 65 | 66 | public String getReduceUri() { 67 | return reduceUri; 68 | } 69 | 70 | public void setReduceUri(String reduceUri) { 71 | this.reduceUri = reduceUri; 72 | } 73 | 74 | public Map getQueryMap() { 75 | return queryMap; 76 | } 77 | 78 | public void setQueryMap(Map queryMap) { 79 | this.queryMap = queryMap; 80 | } 81 | 82 | public void put(String k, String v) { 83 | queryMap.put(k, v); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-frontend/src/views/rtc.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 71 | 72 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/web_support/utils/ServerUrlConstant.java: -------------------------------------------------------------------------------- 1 | package jndc_server.web_support.utils; 2 | 3 | public class ServerUrlConstant { 4 | public interface DevelopDebug { 5 | public static final String reloadFront = "/reloadFront";//reload front project 6 | 7 | public static final String getDeviceIp = "/getDeviceIp";//get device ip 8 | } 9 | 10 | 11 | public interface ServerHttp { 12 | public static final String saveHostRouteRule = "/saveHostRouteRule";// 13 | 14 | public static final String updateHostRouteRule = "/updateHostRouteRule";// 15 | 16 | public static final String deleteHostRouteRule = "/deleteHostRouteRule";// 17 | 18 | public static final String listHostRouteRule = "/listHostRouteRule";// 19 | 20 | } 21 | 22 | public interface ServerManage { 23 | public static final String login = "/login";//登录 24 | 25 | public static final String getServerChannelTable = "/getServerChannelTable";//渠道列表 26 | 27 | public static final String getChannelRecord = "/getChannelRecord";// 28 | 29 | public static final String clearChannelRecord = "/clearChannelRecord";// 30 | 31 | public static final String sendHeartBeat = "/sendHeartBeat";// 32 | 33 | public static final String closeChannelByServer = "/closeChannelByServer";// 34 | 35 | public static final String getServiceList="/getServiceList";// 36 | 37 | public static final String getServerPortList="/getServerPortList";// 38 | 39 | public static final String createPortMonitoring="/createPortMonitoring";// 40 | 41 | public static final String doServiceBind="/doServiceBind";// 42 | 43 | public static final String doDateRangeEdit="/doDateRangeEdit";// 44 | 45 | public static final String deleteServiceBindRecord="/deleteServiceBindRecord";// 46 | 47 | public static final String resetBindRecord="/resetBindRecord";// 48 | 49 | public static final String stopServiceBind="/stopServiceBind";// 50 | 51 | public static final String blackList="/blackList";// 52 | 53 | public static final String whiteList="/whiteList";// 54 | 55 | public static final String addToIpWhiteList="/addToIpWhiteList";// 56 | 57 | public static final String addToIpBlackList="/addToIpBlackList";// 58 | 59 | public static final String deleteIpRuleByPrimaryKey="/deleteIpRuleByPrimaryKey";// 60 | 61 | public static final String releaseRecord="/releaseRecord";// 62 | 63 | public static final String blockRecord="/blockRecord";// 64 | 65 | public static final String getCurrentDeviceIp="/getCurrentDeviceIp";//获取当前设备IP 66 | 67 | public static final String clearIpRecord="/clearIpRecord";//清空ip记录 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/web_support/model/dto/HostRouteDTO.java: -------------------------------------------------------------------------------- 1 | package jndc_server.web_support.model.dto; 2 | 3 | public class HostRouteDTO { 4 | private String id; 5 | 6 | private String hostKeyWord; 7 | 8 | //0 redirect 9 | //1 fixed value 10 | //2 forward 11 | private int routeType; 12 | 13 | private String fixedResponse; 14 | 15 | private String fixedContentType; 16 | 17 | private String redirectAddress; 18 | 19 | private String forwardHost; 20 | 21 | private int forwardPort; 22 | 23 | private int page; 24 | 25 | private int rows; 26 | 27 | 28 | private String forwardProtocol; 29 | 30 | public String getForwardProtocol() { 31 | return forwardProtocol; 32 | } 33 | 34 | public void setForwardProtocol(String forwardProtocol) { 35 | this.forwardProtocol = forwardProtocol; 36 | } 37 | 38 | public String getForwardHost() { 39 | return forwardHost; 40 | } 41 | 42 | public void setForwardHost(String forwardHost) { 43 | this.forwardHost = forwardHost; 44 | } 45 | 46 | public int getForwardPort() { 47 | return forwardPort; 48 | } 49 | 50 | public void setForwardPort(int forwardPort) { 51 | this.forwardPort = forwardPort; 52 | } 53 | 54 | public String getId() { 55 | return id; 56 | } 57 | 58 | public void setId(String id) { 59 | this.id = id; 60 | } 61 | 62 | public int getPage() { 63 | return page; 64 | } 65 | 66 | public void setPage(int page) { 67 | this.page = page; 68 | } 69 | 70 | public int getRows() { 71 | return rows; 72 | } 73 | 74 | public void setRows(int rows) { 75 | this.rows = rows; 76 | } 77 | 78 | public String getFixedContentType() { 79 | return fixedContentType; 80 | } 81 | 82 | public void setFixedContentType(String fixedContentType) { 83 | this.fixedContentType = fixedContentType; 84 | } 85 | 86 | public String getHostKeyWord() { 87 | return hostKeyWord; 88 | } 89 | 90 | public void setHostKeyWord(String hostKeyWord) { 91 | this.hostKeyWord = hostKeyWord; 92 | } 93 | 94 | public int getRouteType() { 95 | return routeType; 96 | } 97 | 98 | public void setRouteType(int routeType) { 99 | this.routeType = routeType; 100 | } 101 | 102 | public String getFixedResponse() { 103 | return fixedResponse; 104 | } 105 | 106 | public void setFixedResponse(String fixedResponse) { 107 | this.fixedResponse = fixedResponse; 108 | } 109 | 110 | public String getRedirectAddress() { 111 | return redirectAddress; 112 | } 113 | 114 | public void setRedirectAddress(String redirectAddress) { 115 | this.redirectAddress = redirectAddress; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/resources/conf/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | ${operationLog.pattern} 12 | 13 | 14 | 15 | 16 | 17 | ${operationLog.path}/info.operationLog 18 | 19 | 20 | 21 | ${operationLog.path}/info.%d{yyyy-MM-dd}.operationLog 22 | 23 | 60 24 | 25 | 26 | ${operationLog.pattern} 27 | 28 | 29 | 30 | INFO 31 | 32 | ACCEPT 33 | 34 | DENY 35 | 36 | 37 | 38 | 39 | ${operationLog.path}/error.operationLog 40 | 41 | 42 | 43 | ${operationLog.path}/error.%d{yyyy-MM-dd}.operationLog 44 | 45 | 60 46 | 47 | 48 | ${operationLog.pattern} 49 | 50 | 51 | 52 | ERROR 53 | 54 | ACCEPT 55 | 56 | DENY 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/web_support/http_module/HostRouteHandle.java: -------------------------------------------------------------------------------- 1 | package jndc_server.web_support.http_module; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.channel.SimpleChannelInboundHandler; 5 | import io.netty.handler.codec.http.FullHttpRequest; 6 | import io.netty.handler.codec.http.FullHttpResponse; 7 | import io.netty.handler.codec.http.HttpHeaderNames; 8 | import io.netty.handler.codec.http.HttpHeaders; 9 | import jndc.core.UniqueBeanManage; 10 | import jndc.web_support.core.JNDCHttpRequest; 11 | import jndc_server.web_support.model.d_o.HttpHostRoute; 12 | import jndc_server.web_support.utils.HttpResponseBuilder; 13 | import lombok.extern.slf4j.Slf4j; 14 | 15 | /** 16 | * 服务器路由 17 | */ 18 | @Slf4j 19 | public class HostRouteHandle extends SimpleChannelInboundHandler { 20 | public static String NAME = "HOST_ROUTE_HANDLE"; 21 | 22 | 23 | @Override 24 | protected void channelRead0(ChannelHandlerContext channelHandlerContext, FullHttpRequest fullHttpRequest) throws Exception { 25 | 26 | HttpHeaders headers = fullHttpRequest.headers(); 27 | 28 | HostRouterComponent hostRouterComponent = UniqueBeanManage.getBean(HostRouterComponent.class); 29 | //提取host头 30 | String host = headers.get(HttpHeaderNames.HOST); 31 | // host="blog.ab.com"; 32 | HttpHostRoute httpHostRoute = hostRouterComponent.matchHost(host); 33 | FullHttpResponse fullHttpResponse = null; 34 | if (httpHostRoute != null) { 35 | 36 | 37 | if (httpHostRoute.fixValueType()) { 38 | //todo 固定值 39 | fullHttpResponse = HttpResponseBuilder.defaultResponse(httpHostRoute.getFixedResponse().getBytes(), httpHostRoute.getFixedContentType() + ";charset=utf-8"); 40 | } 41 | 42 | if (httpHostRoute.redirectType()) { 43 | //todo 重定向 44 | fullHttpResponse = HttpResponseBuilder.redirectResponse(httpHostRoute.getForwardProtocol() + httpHostRoute.getRedirectAddress()); 45 | } 46 | 47 | 48 | if (httpHostRoute.forwardType()) { 49 | //todo 转发 50 | 51 | //从连接器池中获取访问客户端 52 | LiteHttpProxy liteHttpProxy = LiteHttpProxyPool.getLiteHttpProxy(); 53 | new JNDCHttpRequest(fullHttpRequest.copy()); 54 | fullHttpResponse = liteHttpProxy.forward(httpHostRoute, fullHttpRequest.retain()); 55 | if (fullHttpResponse == null) { 56 | //todo 超时的直接断开 57 | channelHandlerContext.close(); 58 | return; 59 | } 60 | } 61 | 62 | } else { 63 | fullHttpResponse = HttpResponseBuilder.htmlResponse(ServerRuntimeConfig.ROUTE_NOT_FOUND_CONTENT.getBytes()); 64 | } 65 | 66 | channelHandlerContext.writeAndFlush(fullHttpResponse); 67 | 68 | 69 | } 70 | 71 | @Override 72 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 73 | cause.printStackTrace(); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-frontend/src/config/webSocketTool.js: -------------------------------------------------------------------------------- 1 | import {Notification} from 'element-ui' 2 | 3 | let websocket4v = {} 4 | let store = {} 5 | 6 | // eslint-disable-next-line no-unused-vars 7 | let currentPage 8 | 9 | let pageEventArray = [] 10 | 11 | websocket4v.registerPage = (page, pageDescription, callBack) => { 12 | pageEventArray.push({'pageName': page, 'pageDescription': pageDescription, 'callBack': callBack}) 13 | } 14 | 15 | websocket4v.parseMessage = (x) => { 16 | let obj = JSON.parse(x) 17 | if (1 == obj.type) { 18 | //refresh page 19 | pageEventArray.forEach(x => { 20 | if (x.pageName == obj.data) { 21 | x.callBack() 22 | console.log(x.pageDescription + '数据刷新') 23 | // Notification.success({ 24 | // title: '通知', 25 | // message: x.pageDescription+'数据刷新', 26 | // position: 'bottom-right' 27 | // }) 28 | } 29 | }) 30 | } else { 31 | console.log("数据", x); 32 | Notification.info({ 33 | title: '通知', 34 | message: obj.data, 35 | position: 'bottom-right' 36 | }) 37 | } 38 | } 39 | 40 | 41 | websocket4v.find = (name) => { 42 | return store[name] 43 | } 44 | 45 | 46 | websocket4v.create = (name, url) => { 47 | if (typeof (store[name]) != 'undefined') { 48 | console.error('the object:' + name + ' exist,the older socket has been covered') 49 | } 50 | 51 | 52 | let singleWebSocketHolder = {'name': name} 53 | singleWebSocketHolder.onmessage = (x) => { 54 | console.log('default action: receive ' + x) 55 | } 56 | singleWebSocketHolder.onopen = () => { 57 | console.log('default action: open ws ') 58 | } 59 | singleWebSocketHolder.onclose = () => { 60 | console.log('default action: close ws ') 61 | } 62 | 63 | 64 | let wsURL = "ws://" + window.location.host + '/' + url + '?auth-token=' + localStorage.getItem('auth-token') 65 | console.log(wsURL, wsURL) 66 | 67 | let inner = new WebSocket(wsURL); 68 | 69 | 70 | inner.onopen = () => { 71 | try { 72 | singleWebSocketHolder.onopen() 73 | } catch (e) { 74 | console.error('can not found the method onopen() by singleWebSocketHolder') 75 | } 76 | }; 77 | 78 | inner.onmessage = (evt) => { 79 | let received_msg = evt.data 80 | try { 81 | singleWebSocketHolder.onmessage(received_msg) 82 | } catch (e) { 83 | console.error(e) 84 | } 85 | }; 86 | 87 | 88 | inner.onclose = () => { 89 | try { 90 | singleWebSocketHolder.onclose() 91 | } catch (e) { 92 | console.error('can not found the method onclose() by singleWebSocketHolder') 93 | } 94 | }; 95 | singleWebSocketHolder['object'] = inner 96 | 97 | store[name] = singleWebSocketHolder 98 | 99 | return singleWebSocketHolder 100 | } 101 | 102 | export default websocket4v 103 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-frontend/src/views/management.vue: -------------------------------------------------------------------------------- 1 | 36 | 37 | 85 | 86 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-frontend/src/views/item_detail/data_source/db_vertex.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 94 | 95 | 98 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/web_support/core/MappingRegisterCenter.java: -------------------------------------------------------------------------------- 1 | package jndc.web_support.core; 2 | 3 | import jndc.utils.JSONUtils; 4 | import jndc.web_support.model.dto.ResponseMessage; 5 | import lombok.extern.slf4j.Slf4j; 6 | 7 | import java.lang.reflect.Method; 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | import java.util.stream.Stream; 11 | 12 | /** 13 | * singleton 14 | */ 15 | @Slf4j 16 | public class MappingRegisterCenter { 17 | private Map mappingMap = new HashMap<>(); 18 | 19 | 20 | 21 | 22 | public void registerMapping(Object mappingBean) { 23 | if (mappingBean == null) { 24 | throw new RuntimeException("unSupport null register"); 25 | } 26 | Class aClass = mappingBean.getClass(); 27 | Method[] declaredMethods = aClass.getDeclaredMethods(); 28 | Stream.of(declaredMethods).forEach(x -> { 29 | WebMapping annotation = x.getAnnotation(WebMapping.class); 30 | if (annotation != null) { 31 | String path = annotation.path(); 32 | if (mappingMap.containsKey(path)) { 33 | throw new RuntimeException("duplicate path"); 34 | } 35 | MappingMethodDescription mappingMethodDescription = new MappingMethodDescription(annotation, x, mappingBean); 36 | mappingMap.put(path, mappingMethodDescription); 37 | } 38 | 39 | }); 40 | 41 | } 42 | 43 | public byte[] invokeMapping(JNDCHttpRequest jndcHttpRequest) { 44 | String fullPath = jndcHttpRequest.getFullPath(); 45 | MappingMethodDescription mappingMethodDescription = mappingMap.get(fullPath); 46 | if (mappingMethodDescription == null) { 47 | return null; 48 | } 49 | return mappingMethodDescription.invoke(jndcHttpRequest); 50 | } 51 | 52 | 53 | public class MappingMethodDescription { 54 | private WebMapping webMapping; 55 | private Method method; 56 | private Object object; 57 | 58 | public MappingMethodDescription(WebMapping webMapping, Method method, Object object) { 59 | this.webMapping = webMapping; 60 | this.method = method; 61 | this.object = object; 62 | } 63 | 64 | public byte[] invoke(JNDCHttpRequest jndcHttpRequest) { 65 | try { 66 | Object invoke = method.invoke(object, jndcHttpRequest); 67 | 68 | if (invoke instanceof byte[]) { 69 | return (byte[]) invoke; 70 | } else if (invoke instanceof String) { 71 | return invoke.toString().getBytes(); 72 | } else { 73 | return JSONUtils.object2JSON(invoke); 74 | } 75 | } catch (Exception e) { 76 | log.error("执行控制层异常 ", e); 77 | ResponseMessage responseMessage = new ResponseMessage(); 78 | responseMessage.error(e.getCause().getMessage()); 79 | return JSONUtils.object2JSON(responseMessage); 80 | } 81 | } 82 | 83 | public WebMapping getWebMapping() { 84 | return webMapping; 85 | } 86 | 87 | public void setWebMapping(WebMapping webMapping) { 88 | this.webMapping = webMapping; 89 | } 90 | 91 | public Method getMethod() { 92 | return method; 93 | } 94 | 95 | public void setMethod(Method method) { 96 | this.method = method; 97 | } 98 | } 99 | 100 | 101 | } 102 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/utils/GetNetworkAddress.java: -------------------------------------------------------------------------------- 1 | package jndc.utils; 2 | 3 | import java.net.*; 4 | import java.util.Enumeration; 5 | 6 | public class GetNetworkAddress { 7 | 8 | public static String GetAddress(String addressType) { 9 | String address = ""; 10 | InetAddress lanIp = null; 11 | try { 12 | 13 | String ipAddress = null; 14 | Enumeration net = null; 15 | net = NetworkInterface.getNetworkInterfaces(); 16 | 17 | while (net.hasMoreElements()) { 18 | NetworkInterface element = net.nextElement(); 19 | Enumeration addresses = element.getInetAddresses(); 20 | 21 | while (addresses.hasMoreElements() &&!isVMMac(element.getHardwareAddress())) { 22 | InetAddress ip = addresses.nextElement(); 23 | if (ip instanceof Inet4Address) { 24 | 25 | if (ip.isSiteLocalAddress()) { 26 | ipAddress = ip.getHostAddress(); 27 | lanIp = InetAddress.getByName(ipAddress); 28 | } 29 | 30 | } 31 | 32 | } 33 | } 34 | 35 | if (lanIp == null) 36 | return null; 37 | 38 | if (addressType.equals("ip")) { 39 | 40 | address = lanIp.toString().replaceAll("^/+", ""); 41 | 42 | } else if (addressType.equals("mac")) { 43 | 44 | address = getMacAddress(lanIp); 45 | 46 | } else { 47 | 48 | throw new Exception("Specify \"ip\" or \"mac\""); 49 | 50 | } 51 | 52 | } catch (UnknownHostException ex) { 53 | 54 | ex.printStackTrace(); 55 | 56 | } catch (SocketException ex) { 57 | 58 | ex.printStackTrace(); 59 | 60 | } catch (Exception ex) { 61 | 62 | ex.printStackTrace(); 63 | 64 | } 65 | 66 | return address; 67 | 68 | } 69 | 70 | private static String getMacAddress(InetAddress ip) { 71 | String address = null; 72 | try { 73 | 74 | NetworkInterface network = NetworkInterface.getByInetAddress(ip); 75 | byte[] mac = network.getHardwareAddress(); 76 | 77 | StringBuilder sb = new StringBuilder(); 78 | for (int i = 0; i < mac.length; i++) { 79 | sb.append(String.format("%02X%s", mac[i], (i < mac.length - 1) ? "-" : "")); 80 | } 81 | address = sb.toString(); 82 | 83 | } catch (SocketException ex) { 84 | 85 | ex.printStackTrace(); 86 | 87 | } 88 | 89 | return address; 90 | } 91 | 92 | private static boolean isVMMac(byte[] mac) { 93 | if(null == mac) return false; 94 | byte invalidMacs[][] = { 95 | {0x00, 0x05, 0x69}, //VMWare 96 | {0x00, 0x1C, 0x14}, //VMWare 97 | {0x00, 0x0C, 0x29}, //VMWare 98 | {0x00, 0x50, 0x56}, //VMWare 99 | {0x08, 0x00, 0x27}, //Virtualbox 100 | {0x0A, 0x00, 0x27}, //Virtualbox 101 | {0x00, 0x03, (byte)0xFF}, //Virtual-PC 102 | {0x00, 0x15, 0x5D} //Hyper-V 103 | }; 104 | 105 | for (byte[] invalid: invalidMacs){ 106 | if (invalid[0] == mac[0] && invalid[1] == mac[1] && invalid[2] == mac[2]) return true; 107 | } 108 | 109 | return false; 110 | } 111 | 112 | } -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/start/ServerStart.java: -------------------------------------------------------------------------------- 1 | package jndc_server.start;//package jndc.core; 2 | 3 | 4 | import jndc.utils.ApplicationExit; 5 | import jndc.utils.PathUtils; 6 | import jndc.utils.YmlParser; 7 | import jndc_server.config.JNDCServerConfig; 8 | import jndc_server.core.JNDCServerApp; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.apache.commons.io.IOUtils; 11 | 12 | import java.io.File; 13 | import java.io.FileInputStream; 14 | 15 | @Slf4j 16 | public class ServerStart { 17 | 18 | public static final YmlParser ymlParser = new YmlParser(); 19 | 20 | public static void main(String[] args) { 21 | 22 | Runtime.getRuntime().addShutdownHook(new Thread(() -> { 23 | log.info("Good night everyone "); 24 | })); 25 | 26 | 27 | String tag = "\n" + 28 | " _ _ _ _____ _____ _____ ______ _______ ________ _____ \n" + 29 | " | | | \\ | | __ \\ / ____| / ____| ____| __ \\ \\ / / ____| __ \\ \n" + 30 | " | | | \\| | | | | | ______ | (___ | |__ | |__) \\ \\ / /| |__ | |__) |\n" + 31 | " _ | | | . ` | | | | | |______| \\___ \\| __| | _ / \\ \\/ / | __| | _ / \n" + 32 | " | |__| | | |\\ | |__| | |____ ____) | |____| | \\ \\ \\ / | |____| | \\ \\ \n" + 33 | " \\____/ |_| \\_|_____/ \\_____| |_____/|______|_| \\_\\ \\/ |______|_| \\_\\\n" + 34 | " \n" + 35 | " "; 36 | log.info(tag); 37 | 38 | 39 | 40 | String runTimePath = PathUtils.getRunTimePath(); 41 | log.info("读取运行目录: " + runTimePath); 42 | String configPath = runTimePath + File.separator + ".." + File.separator + "conf" + File.separator + "config.yml"; 43 | 44 | //读取启动指令配置文件地址 45 | if (args.length>0){ 46 | String typeConfigPath = args[0]; 47 | if (typeConfigPath.endsWith(".yml")){ 48 | configPath= typeConfigPath; 49 | } 50 | } 51 | 52 | 53 | // String configPath = "F:\\java_workspace\\jndc\\jndc_server\\jndc-server-backend\\src\\main\\resources\\conf\\config.yml"; 54 | File file = new File(configPath); 55 | if (!file.exists()) { 56 | log.error("读取配置文件失败,请检查 " + configPath + " 目录下是否存在"); 57 | ApplicationExit.exit(); 58 | } 59 | 60 | 61 | JNDCServerConfig jndcServerConfig; 62 | try { 63 | jndcServerConfig = ymlParser.parseFile(file, JNDCServerConfig.class); 64 | if (jndcServerConfig == null) { 65 | // String configContent = FileUtils.readFileToString(file, "utf-8"); 66 | log.error("please check the content:\n=====content_start=====\n" + new String(IOUtils.toByteArray(new FileInputStream(file))) + "\n=====content_end=====\n on config.yml"); 67 | // log.error("yml配置文件解析异常"); 68 | ApplicationExit.exit(); 69 | } 70 | //设置运行目录 71 | jndcServerConfig.setRuntimeDir(runTimePath); 72 | 73 | //参数校验 74 | jndcServerConfig.performParameterVerification(); 75 | 76 | //懒加载组件 77 | jndcServerConfig.lazyInitAfterVerification(); 78 | } catch (Exception e) { 79 | log.error("解析配置文件失败", e); 80 | ApplicationExit.exit(); 81 | } 82 | 83 | 84 | //启动相关服务 85 | JNDCServerApp serverTest = new JNDCServerApp(); 86 | serverTest.createServer(); 87 | 88 | 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/web_support/http_module/LiteHttpProxyPool.java: -------------------------------------------------------------------------------- 1 | package jndc_server.web_support.http_module; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | import java.util.concurrent.BlockingQueue; 6 | import java.util.concurrent.LinkedBlockingQueue; 7 | import java.util.concurrent.atomic.AtomicInteger; 8 | import java.util.function.Consumer; 9 | import java.util.stream.IntStream; 10 | 11 | @Slf4j 12 | public class LiteHttpProxyPool { 13 | 14 | 15 | private static final Integer FIX_SIZE = 1; 16 | 17 | private static final Integer INCREASE_STEP = 5; 18 | 19 | private static volatile AtomicInteger freeNum = new AtomicInteger(0); 20 | 21 | private static BlockingQueue blockingQueue = new LinkedBlockingQueue<>(); 22 | 23 | 24 | static { 25 | //5个请求器对象 26 | IntStream.generate(() -> 1).limit(FIX_SIZE).forEach(x -> { 27 | try { 28 | LiteHttpProxy liteHttpProxy = new LiteHttpProxy(getConsumer(), true); 29 | liteHttpProxy.setId("INIT_CLIENT"); 30 | blockingQueue.put(liteHttpProxy); 31 | log.debug("初始化,可用计数可用:" + freeNum.incrementAndGet() + "实际可用:" + blockingQueue.size()); 32 | } catch (InterruptedException e) { 33 | throw new RuntimeException("获取请求器异常" + e); 34 | } 35 | }); 36 | } 37 | 38 | 39 | private static Consumer getConsumer() { 40 | Consumer tConsumer = (x) -> { 41 | try { 42 | if (x.canBeReuse()) { 43 | 44 | //同步 45 | if (x.canBePut()) { 46 | synchronized (x) { 47 | if (x.canBePut()) { 48 | //todo 可重用且未被回收 49 | freeNum.incrementAndGet(); 50 | blockingQueue.put(x); 51 | x.putOption(); 52 | log.debug("客户端回收,当前可用客户端计数:" + freeNum.get() + "实际可用:" + blockingQueue.size()); 53 | } 54 | } 55 | } 56 | 57 | 58 | } 59 | } catch (InterruptedException e) { 60 | throw new RuntimeException("获取请求器异常" + e); 61 | } 62 | }; 63 | return tConsumer; 64 | } 65 | 66 | /** 67 | * 获取请求客户端 68 | * 69 | * @return 70 | */ 71 | public static LiteHttpProxy getLiteHttpProxy() { 72 | try { 73 | blockCheck(freeNum.get()); 74 | LiteHttpProxy take = blockingQueue.take(); 75 | take.takeOption(); 76 | log.debug("客户端使用,当前可用客户端计数:" + freeNum.decrementAndGet() + "实际可用:" + blockingQueue.size()); 77 | 78 | return take; 79 | } catch (InterruptedException e) { 80 | throw new RuntimeException("获取请求器异常" + e); 81 | } 82 | } 83 | 84 | /** 85 | * 阻塞检查 86 | * 87 | * @param free 88 | */ 89 | public static void blockCheck(int free) { 90 | if (free == 0) { 91 | //todo 增加不可回收工作者 92 | IntStream.generate(() -> 1).limit(INCREASE_STEP).parallel().forEach(x -> { 93 | try { 94 | freeNum.incrementAndGet(); 95 | blockingQueue.put(new LiteHttpProxy(getConsumer(), false)); 96 | } catch (InterruptedException e) { 97 | throw new RuntimeException("扩充请求器异常" + e); 98 | } 99 | }); 100 | log.info("扩容后,可用客户端计数:" + freeNum.get() + "实际可用:" + blockingQueue.size()); 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-frontend/src/config/toolbar.js: -------------------------------------------------------------------------------- 1 | import mxgraph from "@/config/mxgraph"; 2 | import Vue from 'vue'; 3 | 4 | import agg_vertex from "@/views/item_detail/agg/agg_vertex"; 5 | import average_vertex from "@/views/item_detail/agg/average_vertex"; 6 | import max_vertex from "@/views/item_detail/agg/max_vertex"; 7 | import merge_vertex from "@/views/item_detail/agg/merge_vertex"; 8 | import min_vertex from "@/views/item_detail/agg/min_vertex"; 9 | import sum_vertex from "@/views/item_detail/agg/sum_vertex"; 10 | 11 | 12 | import db_vertex from "@/views/item_detail/data_source/db_vertex"; 13 | 14 | import action_edg from "@/views/item_detail/edg_operation/action_edg"; 15 | 16 | 17 | Vue.component('agg_vertex', agg_vertex) 18 | Vue.component('average_vertex', average_vertex) 19 | Vue.component('max_vertex', max_vertex) 20 | Vue.component('merge_vertex', merge_vertex) 21 | Vue.component('min_vertex', min_vertex) 22 | Vue.component('sum_vertex', sum_vertex) 23 | 24 | Vue.component('db_vertex', db_vertex) 25 | Vue.component('action_edg', action_edg) 26 | 27 | let toolbarGroup = [ 28 | { 29 | name: "数据源", 30 | dataArray: [ 31 | { 32 | icon: '/tool_bar_icon/database.png', 33 | component: 'db_vertex', 34 | title: '数据', 35 | } 36 | ], 37 | graphArray: [] 38 | }, 39 | { 40 | name: "聚合操作", 41 | dataArray: [ 42 | { 43 | icon: '/tool_bar_icon/agg.png', 44 | component: 'agg_vertex', 45 | title: '聚合', 46 | }, 47 | { 48 | icon: '/tool_bar_icon/max.png', 49 | component: 'max_vertex', 50 | title: '最大值', 51 | }, 52 | { 53 | icon: '/tool_bar_icon/min.png', 54 | component: 'min_vertex', 55 | title: '最小值', 56 | }, 57 | { 58 | icon: '/tool_bar_icon/sum.png', 59 | component: 'sum_vertex', 60 | title: '求和', 61 | }, 62 | { 63 | icon: '/tool_bar_icon/average.png', 64 | component: 'average_vertex', 65 | title: '平均值', 66 | }, 67 | { 68 | icon: '/tool_bar_icon/merge.png', 69 | component: 'merge_vertex', 70 | title: '合并', 71 | } 72 | ], 73 | graphArray: [] 74 | } 75 | 76 | ] 77 | 78 | 79 | const width_config = 128 80 | const height_config = 128 81 | 82 | for (let i = 0; i < toolbarGroup.length; i++) { 83 | let graphArray = toolbarGroup[i].graphArray 84 | let innerArray = toolbarGroup[i].dataArray 85 | for (let j = 0; j < innerArray.length; j++) { 86 | let fs = innerArray[j] 87 | let sg = { 88 | icon: fs.icon, 89 | title: fs.title, 90 | width: width_config, 91 | height: height_config, 92 | component: fs.component, 93 | style: { 94 | fillColor: 'transparent', 95 | strokeColor: 'transparent', 96 | strokeWidth: '1', 97 | shape: mxgraph.mxConstants.SHAPE_IMAGE, 98 | align: mxgraph.mxConstants.ALIGN_CENTER, 99 | verticalAlign: mxgraph.mxConstants.ALIGN_CENTER, 100 | imageAlign: mxgraph.mxConstants.ALIGN_CENTER, 101 | imageVerticalAlign: mxgraph.mxConstants.ALIGN_CENTER, 102 | width: width_config, 103 | height: height_config, 104 | image: fs.icon 105 | } 106 | } 107 | graphArray.push(sg) 108 | } 109 | 110 | 111 | } 112 | 113 | export default toolbarGroup 114 | -------------------------------------------------------------------------------- /README_zh_cn.md: -------------------------------------------------------------------------------- 1 | ![J NDC](https://s1.ax1x.com/2020/11/04/B6HETJ.png) 2 | ![jdk12](https://img.shields.io/badge/jdk-8-orange.svg) 3 | 4 | 5 | ## [English Document](https://github.com/qiweiview/jndc/blob/master/README.md) 6 | 7 | 8 | 9 | ## 项目介绍 10 | * "J NDC" 是 "java no distance connection"的缩写,意在提供简便易用的可视化内网穿透应用,应用基于java netty编写。 11 | * 应用以Client/Server架构构建,通过"服务注册"思路,由本地client端向server端提供本地服务,由server端管理暴露对应服务 12 | * 应用核心由ndc私有协议支撑,提供了"传输数据加密","ip黑白名单","客户端可视化","服务端口定时","域名路由"功能 13 | * 项目源码目录结构 14 | ``` 15 | - jndc 16 | - jndc_core # 核心公共实现 17 | - jndc_server # 服务端实现 18 | - jndc_client # 客户端实现 19 | ``` 20 | 21 | * TCP数据流向 22 | ``` 23 | broser -------> (tunnel) ---------->local_app 24 | client -------> jndc server <----------> jndc client ---------->local_app 25 | other -------> ---------->local_app 26 | ``` 27 | 28 | ## 项目使用范例 29 | * [范例](https://github.com/qiweiview/jndc/blob/master/tutorial.md) 30 | 31 | 32 | ## 协议说明 33 | * NDC协议 34 | * 协议设计为仅支持ipv4 35 | * 单包数据长度限制,超出将自动拆包 36 | ``` 37 | public static final int AUTO_UNPACK_LENGTH = 5 * 1024 * 1024 38 | ``` 39 | 40 | * 协议说明: 41 | ``` 42 | -------------------------------- 43 | 3byte 1byte 1byte 44 | | ndc | version | type | 45 | -------------------------------- 46 | 4byte 47 | | local ip | 48 | -------------------------------- 49 | 4byte 50 | | remote ip | 51 | -------------------------------- 52 | 4byte 53 | | local port | 54 | -------------------------------- 55 | 4byte 56 | | server port | 57 | -------------------------------- 58 | 4byte 59 | | remote port | 60 | -------------------------------- 61 | 4byte 62 | | data length | 63 | -------------------------------- 64 | data length byte 65 | | data | 66 | -------------------------------- 67 | ``` 68 | 69 | ## 配置文件说明 70 | 71 | ### server 配置 72 | ```yaml 73 | secrete: "xxx" # 服务端密钥,非常重要务必在使用前更改 74 | loglevel: "info" 75 | blackList: # ip访问黑名单 76 | #- "192.168.1.1" 77 | whiteList: # 白名单 78 | #- "192.168.1.2" 79 | servicePort: 81 # jndc服务端运行监听端口 80 | bindIp: "127.0.0.1" # jndc服务端运行ip 81 | 82 | dbConfig: 83 | type: "mysql" # 可选值:mysql和sqlite 84 | # type: "sqlite" # 可选值:mysql和sqlite 85 | url: "jdbc:mysql://127.0.0.1:3306/jndc?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true" 86 | name: "root" 87 | password: "xxx" 88 | 89 | manageConfig: # 管理端api服务 90 | managementApiPort: 777 #管理api端口 91 | useSsl: false # 是否使用ssl 92 | jksPath: "/xx.jks" #jks 证书地址 93 | jksPass: "xxx" # jks 证书密码 94 | loginName: "xxx" # 登录用户名 95 | loginPassWord: "xxx" # 登录密码 96 | adminEnable: true # 是否启动静态页面 97 | 98 | webConfig: # http web服务 99 | notFoundPage: "/404.html" 100 | httpPort: 80 # http应用端口 101 | useSsl: false # 是否使用ssl 102 | jksPath: "/xx.jks" #jks 证书地址 103 | jksPass: "ddd" # jks 证书密码 104 | ``` 105 | 106 | ### client 配置 107 | ```yaml 108 | secrete: "xxx1" # 服务端密钥,很重要务必在使用前更改 109 | loglevel: "info" # 日志打印等级 110 | serverIp: "127.0.0.1" # 服务端运行监听ip 111 | serverPort: "81" # 服务端运行端口 112 | openGui: false 113 | autoReleaseTimeOut: 600000 # 客户端自动断开时间(毫秒) 114 | clientServiceDescriptions: # 注册服务 115 | - serviceName: "xx" 116 | serviceIp: "xx.com" 117 | servicePort: "80" 118 | serviceEnable: true 119 | ``` 120 | 121 | ## 小结 122 | * 如若有好的功能需求,或代码存在的bug欢迎在issue里提出 123 | 124 | ## 开发计划 125 | * http证书配置支持 126 | * 流量监控 127 | * 查询语法优化 128 | 129 | ## supporting 130 | * Thanks to jetbrains for supporting this open source project 131 | * [OpenSourceSupport](https://jb.gg/OpenSourceSupport) 132 | ![jetbrains](https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.png?_ga=2.159595956.84150952.1649035676-1273448.1647342519&_gl=1*1v0d1hp*_ga*MTI3MzQ0OC4xNjQ3MzQyNTE5*_ga_V0XZL7QHEB*MTY0OTAzNTY3NS4xLjEuMTY0OTAzODA2Ni42MA..) 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/web_support/http_module/LiteHttpProxy.java: -------------------------------------------------------------------------------- 1 | package jndc_server.web_support.http_module; 2 | 3 | import io.netty.bootstrap.Bootstrap; 4 | import io.netty.channel.*; 5 | import io.netty.channel.socket.SocketChannel; 6 | import io.netty.channel.socket.nio.NioSocketChannel; 7 | import io.netty.handler.codec.http.FullHttpRequest; 8 | import io.netty.handler.codec.http.FullHttpResponse; 9 | import io.netty.handler.codec.http.HttpClientCodec; 10 | import io.netty.handler.codec.http.HttpObjectAggregator; 11 | import jndc.core.NettyComponentConfig; 12 | import jndc.utils.InetUtils; 13 | import jndc_server.web_support.model.d_o.HttpHostRoute; 14 | import jndc_server.web_support.utils.BlockValueFeature; 15 | import lombok.Data; 16 | import lombok.extern.slf4j.Slf4j; 17 | 18 | import java.util.UUID; 19 | import java.util.function.Consumer; 20 | 21 | 22 | @Slf4j 23 | @Data 24 | public class LiteHttpProxy { 25 | 26 | private String id = UUID.randomUUID().toString(); 27 | 28 | private volatile boolean canBeReUse; 29 | 30 | private volatile boolean hasBeenPut = false; 31 | 32 | //回收操作 33 | private Consumer recycleOption; 34 | 35 | private EventLoopGroup eventLoopGroup = NettyComponentConfig.getNioEventLoopGroup(); 36 | 37 | private BlockValueFeature completeFeature; 38 | 39 | public LiteHttpProxy(Consumer recycleOption, boolean canBeReUse) { 40 | this.recycleOption = recycleOption; 41 | this.canBeReUse = canBeReUse; 42 | } 43 | 44 | public boolean canBePut() { 45 | return hasBeenPut == false; 46 | } 47 | 48 | public boolean canBeReuse() { 49 | return canBeReUse; 50 | } 51 | 52 | public void takeOption() { 53 | hasBeenPut = false; 54 | } 55 | 56 | public void putOption() { 57 | hasBeenPut = true; 58 | } 59 | 60 | public void release() { 61 | eventLoopGroup.shutdownGracefully(); 62 | eventLoopGroup = NettyComponentConfig.getNioEventLoopGroup(); 63 | 64 | if (recycleOption != null) { 65 | //todo 能被继续使用 66 | recycleOption.accept(this); 67 | } 68 | } 69 | 70 | 71 | public FullHttpResponse forward(HttpHostRoute httpHostRoute, FullHttpRequest fullHttpRequest) { 72 | LiteHttpProxy liteHttpProxy = this; 73 | ChannelInitializer channelInitializer = new ChannelInitializer() { 74 | @Override 75 | protected void initChannel(SocketChannel socketChannel) throws Exception { 76 | ChannelPipeline pipeline = socketChannel.pipeline(); 77 | 78 | 79 | pipeline.addLast(new HttpClientCodec()); 80 | pipeline.addLast(new HttpObjectAggregator(20 * 1024 * 1024));//限制缓冲最大值为2mb 81 | pipeline.addLast(new LiteProxyHandle(liteHttpProxy)); 82 | } 83 | }; 84 | 85 | 86 | Bootstrap b = new Bootstrap(); 87 | b.group(eventLoopGroup) 88 | .channel(NioSocketChannel.class) 89 | .handler(channelInitializer); 90 | ChannelFuture sync = null; 91 | try { 92 | sync = b.connect(InetUtils.getInetAddressByHost(httpHostRoute.getForwardHost()), httpHostRoute.getForwardPort()).sync(); 93 | Channel channel = sync.channel(); 94 | channel.writeAndFlush(fullHttpRequest); 95 | completeFeature = new BlockValueFeature<>(); 96 | FullHttpResponse fullHttpResponse = completeFeature.get(10); 97 | return fullHttpResponse; 98 | } catch (Exception e) { 99 | throw new RuntimeException("目标uri" + fullHttpRequest.uri() + "使用规则" + httpHostRoute + "过程发生转发请求异常:" + e); 100 | } finally { 101 | release(); 102 | } 103 | 104 | 105 | } 106 | 107 | 108 | public void writeData(FullHttpResponse data) { 109 | //todo 完成阻塞请求 110 | this.completeFeature.complete(data); 111 | } 112 | 113 | 114 | } 115 | -------------------------------------------------------------------------------- /jndc_core/src/main/java/jndc/utils/ReflectionCache.java: -------------------------------------------------------------------------------- 1 | package jndc.utils; 2 | 3 | import java.lang.reflect.Field; 4 | import java.lang.reflect.Method; 5 | import java.util.ArrayList; 6 | import java.util.HashMap; 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.concurrent.ConcurrentHashMap; 10 | import java.util.stream.Stream; 11 | 12 | /** 13 | * Reflection Cache Utils 14 | */ 15 | public class ReflectionCache { 16 | private static Map map = new ConcurrentHashMap<>(); 17 | 18 | public static List getMethods(Class tClass) { 19 | return getClassCache(tClass).getMethods(); 20 | 21 | } 22 | 23 | public static ClassCache getClassCache(Class tClass) { 24 | ClassCache classCache = map.get(tClass); 25 | if (classCache == null) { 26 | classCache = initClassCache(tClass); 27 | } 28 | return classCache; 29 | } 30 | 31 | public static List getFields(Class tClass) { 32 | 33 | return getClassCache(tClass).getFieldList(); 34 | 35 | } 36 | 37 | private static ClassCache initClassCache(Class tc) { 38 | ClassCache classCache = new ClassCache(); 39 | Stream.of(tc.getDeclaredFields()).forEach(x -> { 40 | classCache.addField(x); 41 | }); 42 | Stream.of(tc.getDeclaredMethods()).forEach(x -> { 43 | classCache.addMethod(x); 44 | }); 45 | classCache.setInnerClass(tc); 46 | 47 | 48 | map.put(tc, classCache); 49 | return classCache; 50 | } 51 | 52 | 53 | public static class ClassCache { 54 | private Class innerClass; 55 | private Class arrayClass; 56 | private List fieldList = new ArrayList<>(); 57 | private List methods = new ArrayList<>(); 58 | private Map fieldMap = new HashMap<>(); 59 | private Map methodMap = new HashMap<>(); 60 | 61 | 62 | public void addField(Field field) { 63 | fieldMap.put(field.getName(), field); 64 | fieldList.add(field); 65 | } 66 | 67 | public void addMethod(Method method) { 68 | methodMap.put(method.getName(), method); 69 | methods.add(method); 70 | } 71 | 72 | public void createArrayType() { 73 | if (!innerClass.isArray()) { 74 | try { 75 | arrayClass = Class.forName("[L" + innerClass.getCanonicalName() + ";"); 76 | } catch (ClassNotFoundException e) { 77 | throw new RuntimeException("class cache create error: " + e); 78 | } 79 | } 80 | } 81 | 82 | 83 | public Class getArrayClass() { 84 | return arrayClass; 85 | } 86 | 87 | public void setArrayClass(Class arrayClass) { 88 | this.arrayClass = arrayClass; 89 | } 90 | 91 | public Class getInnerClass() { 92 | return innerClass; 93 | } 94 | 95 | public void setInnerClass(Class innerClass) { 96 | this.innerClass = innerClass; 97 | createArrayType(); 98 | } 99 | 100 | public List getFieldList() { 101 | return fieldList; 102 | } 103 | 104 | public void setFieldList(List fieldList) { 105 | this.fieldList = fieldList; 106 | } 107 | 108 | public List getMethods() { 109 | return methods; 110 | } 111 | 112 | public void setMethods(List methods) { 113 | this.methods = methods; 114 | } 115 | 116 | public Map getFieldMap() { 117 | return fieldMap; 118 | } 119 | 120 | public void setFieldMap(Map fieldMap) { 121 | this.fieldMap = fieldMap; 122 | } 123 | 124 | public Map getMethodMap() { 125 | return methodMap; 126 | } 127 | 128 | public void setMethodMap(Map methodMap) { 129 | this.methodMap = methodMap; 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-frontend/src/views/item_detail/agg/max_vertex.vue: -------------------------------------------------------------------------------- 1 | 36 | 37 | 113 | 114 | 117 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-frontend/src/views/item_detail/agg/min_vertex.vue: -------------------------------------------------------------------------------- 1 | 36 | 37 | 113 | 114 | 117 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-frontend/src/views/item_detail/agg/sum_vertex.vue: -------------------------------------------------------------------------------- 1 | 36 | 37 | 113 | 114 | 117 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-frontend/src/views/item_detail/agg/average_vertex.vue: -------------------------------------------------------------------------------- 1 | 36 | 37 | 113 | 114 | 117 | -------------------------------------------------------------------------------- /jndc_server/jndc-server-backend/src/main/java/jndc_server/web_support/http_module/JNDCHttpServer.java: -------------------------------------------------------------------------------- 1 | package jndc_server.web_support.http_module; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.Channel; 5 | import io.netty.channel.ChannelInitializer; 6 | import io.netty.channel.ChannelPipeline; 7 | import io.netty.channel.EventLoopGroup; 8 | import io.netty.channel.socket.nio.NioServerSocketChannel; 9 | import io.netty.handler.codec.http.HttpObjectAggregator; 10 | import io.netty.handler.codec.http.HttpServerCodec; 11 | import jndc.core.NettyComponentConfig; 12 | import jndc.core.UniqueBeanManage; 13 | import jndc.web_support.core.CustomSslHandler; 14 | import jndc_server.config.JNDCServerConfig; 15 | import jndc_server.core.app.ServerApp; 16 | import lombok.extern.slf4j.Slf4j; 17 | import org.apache.commons.io.FileUtils; 18 | 19 | import javax.net.ssl.SSLContext; 20 | import javax.net.ssl.SSLEngine; 21 | import java.io.File; 22 | import java.io.IOException; 23 | import java.nio.charset.StandardCharsets; 24 | 25 | /** 26 | * jndc server core functions 27 | */ 28 | @Slf4j 29 | public class JNDCHttpServer implements ServerApp { 30 | private EventLoopGroup eventLoopGroup = NettyComponentConfig.getNioEventLoopGroup(); 31 | 32 | @Override 33 | public void start() { 34 | JNDCServerConfig serverConfig = UniqueBeanManage.getBean(JNDCServerConfig.class); 35 | 36 | ChannelInitializer channelInitializer = new ChannelInitializer() { 37 | 38 | @Override 39 | protected void initChannel(Channel channel) throws Exception { 40 | ChannelPipeline pipeline = channel.pipeline(); 41 | 42 | String http = "http";//HttpServerCodec 43 | String oag = "oag";//HttpObjectAggregator 44 | 45 | if (serverConfig.getWebConfig().isUseSsl()) { 46 | SSLContext serverSSLContext = serverConfig.getWebConfig().getServerSSLContext(); 47 | SSLEngine sslEngine = serverSSLContext.createSSLEngine(); 48 | sslEngine.setUseClientMode(false);//设置为服务器模式 49 | pipeline.addFirst(CustomSslHandler.NAME, new CustomSslHandler(sslEngine)); 50 | } 51 | 52 | 53 | pipeline.addLast(http, new HttpServerCodec()); 54 | pipeline.addAfter(http, oag, new HttpObjectAggregator(2 * 1024 * 1024));//限制缓冲最大值为2mb 55 | pipeline.addAfter(oag, HostRouteHandle.NAME, new HostRouteHandle()); 56 | } 57 | }; 58 | 59 | ServerBootstrap b = new ServerBootstrap(); 60 | b.group(eventLoopGroup) 61 | .channel(NioServerSocketChannel.class)// 62 | .localAddress(serverConfig.getHttpInetSocketAddress())//  63 | .childHandler(channelInitializer); 64 | 65 | b.bind().addListener(x -> { 66 | String protocol = "http"; 67 | if (serverConfig.getWebConfig().isUseSsl()) { 68 | protocol = "https"; 69 | } 70 | if (x.isSuccess()) { 71 | log.info("启动web服务 " + protocol + "://" + serverConfig.getHttpInetSocketAddress() + " 成功"); 72 | } else { 73 | log.error("启动web服务 " + protocol + "://" + serverConfig.getHttpInetSocketAddress() + " 失败"); 74 | } 75 | 76 | }); 77 | 78 | //the page for "route not found" 79 | loadRouteNotFoundPage(); 80 | 81 | } 82 | 83 | /** 84 | * 加载404页面 85 | */ 86 | public void loadRouteNotFoundPage() { 87 | JNDCServerConfig serverConfig = UniqueBeanManage.getBean(JNDCServerConfig.class); 88 | File file = new File(serverConfig.getWebConfig().getNotFoundPage()); 89 | if (file.exists()) { 90 | try { 91 | String s = FileUtils.readFileToString(file, StandardCharsets.UTF_8); 92 | ServerRuntimeConfig.ROUTE_NOT_FOUND_CONTENT = s; 93 | log.info("使用外部配置404页面:" + file.getName()); 94 | } catch (IOException e) { 95 | log.error("加载404页面失败 ,cause:" + e); 96 | } 97 | } else { 98 | log.info("没有找到配置的404页面,使用默认页面"); 99 | } 100 | 101 | } 102 | } 103 | --------------------------------------------------------------------------------