diff --git a/conf/echo-component.json b/conf/echo-component.json new file mode 100644 index 0000000..426306d --- /dev/null +++ b/conf/echo-component.json @@ -0,0 +1,8 @@ +{ + "subdomainPrefix": "echo", + "domain": "vidconnect.cyou", + "host": "localhost", + "port": 5270, + "secretKey": "user-admin_secret", + "startEncrypted": false +} \ No newline at end of file diff --git a/conf/springboot.yml b/conf/springboot.yml index 70f792f..3bbd273 100644 --- a/conf/springboot.yml +++ b/conf/springboot.yml @@ -6,7 +6,8 @@ ssh-server: location: "conf/hash-replies.properties" regex-mapping: location: "conf/regex-mapping.properties" - +xmpp-component: + config-json: "conf/echo-component.json" spring: datasource: url: "jdbc:h2:file:./data/remote-ip-info-db" \ No newline at end of file diff --git a/pom.xml b/pom.xml index d0f4e0d..e1e09c3 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 com.example.sshd echo-sshd-server - 1.5.0 + 2.0.0 ECHO SSH SERVER Learning Apache Mina SSHD library @@ -16,10 +16,23 @@ 17 2.0.25 0.14.0 + 2.0.1 + 2.17.1 2.17.0 1.4.0 3.17.0 + + + + com.fasterxml.jackson + jackson-bom + 2.16.1 + import + pom + + + org.springframework.boot @@ -31,6 +44,18 @@ + + com.fasterxml.jackson.core + jackson-core + + + com.fasterxml.jackson.core + jackson-annotations + + + com.fasterxml.jackson.core + jackson-databind + org.springframework.boot spring-boot-starter-log4j2 @@ -45,13 +70,13 @@ runtime - org.apache.commons - commons-exec - ${commons-exec.version} + org.apache.commons + commons-exec + ${commons-exec.version} - org.apache.commons - commons-lang3 + org.apache.commons + commons-lang3 commons-codec @@ -73,12 +98,13 @@ ${commons-io.version} - org.apache.commons - commons-lang3 + org.apache.httpcomponents.client5 + httpclient5 - org.apache.httpcomponents.client5 - httpclient5 + org.igniterealtime.whack + core + ${whack.version} junit diff --git a/src/main/java/com/example/sshd/Boot.java b/src/main/java/com/example/sshd/Boot.java index 35947ce..74bb9ef 100644 --- a/src/main/java/com/example/sshd/Boot.java +++ b/src/main/java/com/example/sshd/Boot.java @@ -10,22 +10,22 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Boot { - private static final Logger logger = LoggerFactory.getLogger(Boot.class); + private static final Logger logger = LoggerFactory.getLogger(Boot.class); - @Autowired - protected SshServer sshd; + @Autowired + protected SshServer sshd; - public static void main(String[] args) throws Exception { - String configDirectory = "conf"; - if (args.length > 0) { - configDirectory = args[0]; - } - logger.info("config directory: {}", configDirectory); + public static void main(String[] args) throws Exception { + String configDirectory = "conf"; + if (args.length > 0) { + configDirectory = args[0]; + } + logger.info("config directory: {}", configDirectory); - if (new java.io.File(configDirectory).exists() && new java.io.File(configDirectory).isDirectory()) { - System.setProperty("spring.config.location", configDirectory + "/springboot.yml"); - System.setProperty("logging.config", configDirectory + "/log4j2.xml"); - } - SpringApplication.run(Boot.class, args); + if (new java.io.File(configDirectory).exists() && new java.io.File(configDirectory).isDirectory()) { + System.setProperty("spring.config.location", configDirectory + "/springboot.yml"); + System.setProperty("logging.config", configDirectory + "/log4j2.xml"); } + SpringApplication.run(Boot.class, args); + } } diff --git a/src/main/java/com/example/sshd/config/AppConfig.java b/src/main/java/com/example/sshd/config/AppConfig.java index 0ed9afb..e13ac8d 100644 --- a/src/main/java/com/example/sshd/config/AppConfig.java +++ b/src/main/java/com/example/sshd/config/AppConfig.java @@ -1,5 +1,6 @@ package com.example.sshd.config; +import java.io.IOException; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -9,36 +10,50 @@ import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; import org.apache.hc.client5.http.impl.classic.HttpClients; import org.apache.hc.core5.reactor.IOReactorConfig; import org.apache.sshd.common.Session; +import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope; +import com.fasterxml.jackson.core.exc.StreamReadException; +import com.fasterxml.jackson.databind.DatabindException; +import com.fasterxml.jackson.databind.ObjectMapper; + @Configuration public class AppConfig { - @Bean - @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) - public Map remoteSessionMapping() { - return new ConcurrentHashMap<>(); - } - - @Bean - @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) - public Map ipInfoMapping() { - return new ConcurrentHashMap<>(); - } - - @Bean - public CloseableHttpAsyncClient asyncClient() { - final IOReactorConfig ioReactorConfig = IOReactorConfig.custom().build(); - final CloseableHttpAsyncClient client = HttpAsyncClients.custom().setIOReactorConfig(ioReactorConfig).build(); - client.start(); - return client; - } - - @Bean - public CloseableHttpClient httpClient() { - return HttpClients.createDefault(); - } + @Value("${xmpp-component.config-json}") + private String xmppComponentConfigJson; + + @Bean + @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) + public XmppComponentConfig xmppComponentConfig() throws StreamReadException, DatabindException, IOException { + return new ObjectMapper().readValue(new java.io.File(xmppComponentConfigJson), XmppComponentConfig.class); + } + + @Bean + @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) + public Map remoteSessionMapping() { + return new ConcurrentHashMap<>(); + } + + @Bean + @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) + public Map ipInfoMapping() { + return new ConcurrentHashMap<>(); + } + + @Bean + public CloseableHttpAsyncClient asyncClient() { + final IOReactorConfig ioReactorConfig = IOReactorConfig.custom().build(); + final CloseableHttpAsyncClient client = HttpAsyncClients.custom().setIOReactorConfig(ioReactorConfig).build(); + client.start(); + return client; + } + + @Bean + public CloseableHttpClient httpClient() { + return HttpClients.createDefault(); + } } diff --git a/src/main/java/com/example/sshd/config/SshConfig.java b/src/main/java/com/example/sshd/config/SshConfig.java index e8b2259..a68ad48 100644 --- a/src/main/java/com/example/sshd/config/SshConfig.java +++ b/src/main/java/com/example/sshd/config/SshConfig.java @@ -29,72 +29,72 @@ import com.example.sshd.core.OnetimeCommand; @Configuration public class SshConfig { - private static final Logger loginLogger = LoggerFactory.getLogger("login"); - - @Value("${ssh-server.port}") - private int port; - - @Value("${ssh-server.private-key.location}") - private String pkLocation; - - @Value("${ssh-server.login.usernames:root}") - private String[] usernames; - - @Value("${ssh-server.hash-replies.location}") - private String hashReplies; - - @Value("${ssh-server.regex-mapping.location}") - private String regexMapping; - - @Autowired - ApplicationContext applicationContext; - - @Bean - public SshServer sshd() throws IOException, NoSuchAlgorithmException { - SshServer sshd = SshServer.setUpDefaultServer(); - sshd.setPort(port); - sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(new File(pkLocation).getPath(), "RSA", 2048)); - - sshd.setPasswordAuthenticator(new PasswordAuthenticator() { - @Override - public boolean authenticate(final String username, final String password, final ServerSession session) { - if (session.getIoSession().getRemoteAddress() instanceof InetSocketAddress) { - InetSocketAddress remoteAddress = (InetSocketAddress) session.getIoSession().getRemoteAddress(); - String remoteIpAddress = remoteAddress.getAddress().getHostAddress(); - loginLogger.info("[{}] Login Attempt: username = {}, password = {}", remoteIpAddress, username, - password); - } else { - loginLogger.info("[{}] Login Attempt: username = {}, password = {}", - session.getIoSession().getRemoteAddress(), username, password); - } - return Arrays.asList(usernames).contains(username); - } - }); - sshd.setShellFactory(applicationContext.getBean(EchoShellFactory.class)); - sshd.setCommandFactory(command -> applicationContext.getBean(OnetimeCommand.class, command)); - - sshd.start(); - sshd.getSessionFactory().addListener(applicationContext.getBean(EchoSessionListener.class)); - return sshd; - } - - @Bean - @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) - public Properties hashReplies() throws IOException { - Properties prop = new Properties(); - File configFile = new File(hashReplies); - FileInputStream stream = new FileInputStream(configFile); - prop.load(stream); - return prop; - } - - @Bean - @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) - public Properties regexMapping() throws IOException { - Properties prop = new Properties(); - File configFile = new File(regexMapping); - FileInputStream stream = new FileInputStream(configFile); - prop.load(stream); - return prop; - } + private static final Logger loginLogger = LoggerFactory.getLogger("login"); + + @Value("${ssh-server.port}") + private int port; + + @Value("${ssh-server.private-key.location}") + private String pkLocation; + + @Value("${ssh-server.login.usernames:root}") + private String[] usernames; + + @Value("${ssh-server.hash-replies.location}") + private String hashReplies; + + @Value("${ssh-server.regex-mapping.location}") + private String regexMapping; + + @Autowired + ApplicationContext applicationContext; + + @Bean + public SshServer sshd() throws IOException, NoSuchAlgorithmException { + SshServer sshd = SshServer.setUpDefaultServer(); + sshd.setPort(port); + sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(new File(pkLocation).getPath(), "RSA", 2048)); + + sshd.setPasswordAuthenticator(new PasswordAuthenticator() { + @Override + public boolean authenticate(final String username, final String password, final ServerSession session) { + if (session.getIoSession().getRemoteAddress() instanceof InetSocketAddress) { + InetSocketAddress remoteAddress = (InetSocketAddress) session.getIoSession().getRemoteAddress(); + String remoteIpAddress = remoteAddress.getAddress().getHostAddress(); + loginLogger.info("[{}] Login Attempt: username = {}, password = {}", remoteIpAddress, username, + password); + } else { + loginLogger.info("[{}] Login Attempt: username = {}, password = {}", + session.getIoSession().getRemoteAddress(), username, password); + } + return Arrays.asList(usernames).contains(username); + } + }); + sshd.setShellFactory(applicationContext.getBean(EchoShellFactory.class)); + sshd.setCommandFactory(command -> applicationContext.getBean(OnetimeCommand.class, command)); + + sshd.start(); + sshd.getSessionFactory().addListener(applicationContext.getBean(EchoSessionListener.class)); + return sshd; + } + + @Bean + @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) + public Properties hashReplies() throws IOException { + Properties prop = new Properties(); + File configFile = new File(hashReplies); + FileInputStream stream = new FileInputStream(configFile); + prop.load(stream); + return prop; + } + + @Bean + @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) + public Properties regexMapping() throws IOException { + Properties prop = new Properties(); + File configFile = new File(regexMapping); + FileInputStream stream = new FileInputStream(configFile); + prop.load(stream); + return prop; + } } diff --git a/src/main/java/com/example/sshd/config/XmppComponentConfig.java b/src/main/java/com/example/sshd/config/XmppComponentConfig.java new file mode 100644 index 0000000..8b63476 --- /dev/null +++ b/src/main/java/com/example/sshd/config/XmppComponentConfig.java @@ -0,0 +1,78 @@ +package com.example.sshd.config; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class XmppComponentConfig { + + private static final Logger logger = LoggerFactory.getLogger(XmppComponentConfig.class); + + private String subdomainPrefix; + private String domain; + private String host; + private int port; + private String secretKey; + private boolean startEncrypted; + + public String getSubdomainPrefix() { + return subdomainPrefix; + } + + public void setSubdomainPrefix(String subdomainPrefix) { + this.subdomainPrefix = subdomainPrefix; + } + + public String getDomain() { + return domain; + } + + public void setDomain(String domain) { + this.domain = domain; + } + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + public String getSecretKey() { + return secretKey; + } + + public void setSecretKey(String secretKey) { + this.secretKey = secretKey; + } + + public boolean isStartEncrypted() { + return startEncrypted; + } + + public void setStartEncrypted(boolean startEncrypted) { + this.startEncrypted = startEncrypted; + } + + @Override + @JsonIgnore + public String toString() { + try { + return new ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(this); + } catch (JsonProcessingException e) { + logger.error("convert to json error!", e); + } + return "{}"; + } +} diff --git a/src/main/java/com/example/sshd/core/EchoSessionListener.java b/src/main/java/com/example/sshd/core/EchoSessionListener.java index aecf521..244382a 100644 --- a/src/main/java/com/example/sshd/core/EchoSessionListener.java +++ b/src/main/java/com/example/sshd/core/EchoSessionListener.java @@ -17,66 +17,66 @@ import com.example.sshd.service.JdbcService; @Component public class EchoSessionListener implements SessionListener { - private static final Logger logger = LoggerFactory.getLogger(EchoSessionListener.class); - private static final Logger ipInfoLogger = LoggerFactory.getLogger("ip_info"); + private static final Logger logger = LoggerFactory.getLogger(EchoSessionListener.class); + private static final Logger ipInfoLogger = LoggerFactory.getLogger("ip_info"); - @Autowired - Map remoteSessionMapping; + @Autowired + Map remoteSessionMapping; - @Autowired - Map ipInfoMapping; + @Autowired + Map ipInfoMapping; - @Autowired - GeoIpLocator geoIpLocator; + @Autowired + GeoIpLocator geoIpLocator; - @Autowired - JdbcService jdbcService; + @Autowired + JdbcService jdbcService; - @Override - public void sessionCreated(Session session) { - logger.info("sessionCreated: {}", session); - if (session.getIoSession().getRemoteAddress() instanceof InetSocketAddress) { - InetSocketAddress remoteAddress = (InetSocketAddress) session.getIoSession().getRemoteAddress(); - String remoteIpAddress = remoteAddress.getAddress().getHostAddress(); - if (remoteSessionMapping.containsKey(remoteIpAddress)) { - logger.info("kill old session: {} -> {}", remoteIpAddress, remoteSessionMapping.get(remoteIpAddress)); - remoteSessionMapping.get(remoteIpAddress).close(false); - } - logger.info("new session: {} -> {}", remoteIpAddress, session); - remoteSessionMapping.put(remoteIpAddress, session); - if (!ipInfoMapping.containsKey(remoteIpAddress)) { - List> ipInfoList = jdbcService.getAllRemoteIpInfo(remoteIpAddress); - if (!ipInfoList.isEmpty()) { - ipInfoMapping.put(remoteIpAddress, (String) ipInfoList.get(0).get("remote_ip_info")); - } - } + @Override + public void sessionCreated(Session session) { + logger.info("sessionCreated: {}", session); + if (session.getIoSession().getRemoteAddress() instanceof InetSocketAddress) { + InetSocketAddress remoteAddress = (InetSocketAddress) session.getIoSession().getRemoteAddress(); + String remoteIpAddress = remoteAddress.getAddress().getHostAddress(); + if (remoteSessionMapping.containsKey(remoteIpAddress)) { + logger.info("kill old session: {} -> {}", remoteIpAddress, remoteSessionMapping.get(remoteIpAddress)); + remoteSessionMapping.get(remoteIpAddress).close(false); + } + logger.info("new session: {} -> {}", remoteIpAddress, session); + remoteSessionMapping.put(remoteIpAddress, session); + if (!ipInfoMapping.containsKey(remoteIpAddress)) { + List> ipInfoList = jdbcService.getAllRemoteIpInfo(remoteIpAddress); + if (!ipInfoList.isEmpty()) { + ipInfoMapping.put(remoteIpAddress, (String) ipInfoList.get(0).get("remote_ip_info")); } + } } + } - @Override - public void sessionEvent(Session session, Event event) { - logger.info("sessionEvent: {}, event: {}", session, event); - if (session.getIoSession().getRemoteAddress() instanceof InetSocketAddress && event == Event.KexCompleted) { - InetSocketAddress remoteAddress = (InetSocketAddress) session.getIoSession().getRemoteAddress(); - String remoteIpAddress = remoteAddress.getAddress().getHostAddress(); - if (!ipInfoMapping.containsKey(remoteIpAddress)) { - geoIpLocator.asyncUpdateIpLocationInfo(remoteIpAddress); - } else { - ipInfoLogger.debug("[{}] {}", remoteIpAddress, ipInfoMapping.get(remoteIpAddress)); - } - } + @Override + public void sessionEvent(Session session, Event event) { + logger.info("sessionEvent: {}, event: {}", session, event); + if (session.getIoSession().getRemoteAddress() instanceof InetSocketAddress && event == Event.KexCompleted) { + InetSocketAddress remoteAddress = (InetSocketAddress) session.getIoSession().getRemoteAddress(); + String remoteIpAddress = remoteAddress.getAddress().getHostAddress(); + if (!ipInfoMapping.containsKey(remoteIpAddress)) { + geoIpLocator.asyncUpdateIpLocationInfo(remoteIpAddress); + } else { + ipInfoLogger.debug("[{}] {}", remoteIpAddress, ipInfoMapping.get(remoteIpAddress)); + } } + } - @Override - public void sessionClosed(Session session) { - logger.info("sessionClosed: {}", session); - if (session.getIoSession().getRemoteAddress() instanceof InetSocketAddress) { - InetSocketAddress remoteAddress = (InetSocketAddress) session.getIoSession().getRemoteAddress(); - String remoteIpAddress = remoteAddress.getAddress().getHostAddress(); - logger.info("removing session: {} -> {}", remoteIpAddress, remoteSessionMapping.get(remoteIpAddress)); - remoteSessionMapping.remove(remoteIpAddress); - ipInfoMapping.remove(remoteIpAddress); - } + @Override + public void sessionClosed(Session session) { + logger.info("sessionClosed: {}", session); + if (session.getIoSession().getRemoteAddress() instanceof InetSocketAddress) { + InetSocketAddress remoteAddress = (InetSocketAddress) session.getIoSession().getRemoteAddress(); + String remoteIpAddress = remoteAddress.getAddress().getHostAddress(); + logger.info("removing session: {} -> {}", remoteIpAddress, remoteSessionMapping.get(remoteIpAddress)); + remoteSessionMapping.remove(remoteIpAddress); + ipInfoMapping.remove(remoteIpAddress); } + } } diff --git a/src/main/java/com/example/sshd/core/EchoShell.java b/src/main/java/com/example/sshd/core/EchoShell.java index b961777..cdc11bc 100644 --- a/src/main/java/com/example/sshd/core/EchoShell.java +++ b/src/main/java/com/example/sshd/core/EchoShell.java @@ -28,119 +28,119 @@ import com.example.sshd.service.ReplyService; @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class EchoShell implements Command, Runnable, SessionAware { - private static final Logger logger = LoggerFactory.getLogger(EchoShell.class); - - @Autowired - ReplyService replyUtil; - - @Autowired - Properties hashReplies; - - protected InputStream in; - protected OutputStream out; - protected OutputStream err; - protected ExitCallback callback; - protected Environment environment; - protected Thread thread; - protected ServerSession session; - - @Override - public void setInputStream(InputStream in) { - this.in = in; - } - - @Override - public void setOutputStream(OutputStream out) { - this.out = out; - } - - @Override - public void setErrorStream(OutputStream err) { - this.err = err; - } - - @Override - public void setExitCallback(ExitCallback callback) { - this.callback = callback; + private static final Logger logger = LoggerFactory.getLogger(EchoShell.class); + + @Autowired + ReplyService replyUtil; + + @Autowired + Properties hashReplies; + + protected InputStream in; + protected OutputStream out; + protected OutputStream err; + protected ExitCallback callback; + protected Environment environment; + protected Thread thread; + protected ServerSession session; + + @Override + public void setInputStream(InputStream in) { + this.in = in; + } + + @Override + public void setOutputStream(OutputStream out) { + this.out = out; + } + + @Override + public void setErrorStream(OutputStream err) { + this.err = err; + } + + @Override + public void setExitCallback(ExitCallback callback) { + this.callback = callback; + } + + @Override + public void start(Environment env) throws IOException { + environment = env; + thread = new Thread(this, remoteIpAddress()); + logger.info("environment: {}, thread-name: {}", environment.getEnv(), thread.getName()); + thread.start(); + } + + protected String remoteIpAddress() { + String remoteIpAddress = ""; + + if (session.getIoSession().getRemoteAddress() instanceof InetSocketAddress) { + InetSocketAddress remoteAddress = (InetSocketAddress) session.getIoSession().getRemoteAddress(); + remoteIpAddress = remoteAddress.getAddress().getHostAddress(); + } else { + remoteIpAddress = session.getIoSession().getRemoteAddress().toString(); } + return remoteIpAddress; + } + + @Override + public void destroy() { + thread.interrupt(); + } + + @Override + public void run() { + String prompt = hashReplies.getProperty("prompt", "$ ").replace("{user}", environment.getEnv().get("USER")); + try { + out.write(prompt.getBytes()); + out.flush(); + + BufferedReader r = new BufferedReader(new InputStreamReader(in)); + String command = ""; + + while (!Thread.currentThread().isInterrupted()) { + int s = r.read(); + if (s == 13 || s == 10) { + + boolean containsExit = Arrays.asList(StringUtils.split(command, ";|&")).stream().map(cmd -> { + boolean wantsExit = false; + try { + wantsExit = replyUtil.replyToCommand(cmd.trim(), out, prompt, session); + out.flush(); + } catch (Exception e) { + logger.error("run error!", e); + } + return wantsExit; + }).reduce((a, b) -> a || b).get(); - @Override - public void start(Environment env) throws IOException { - environment = env; - thread = new Thread(this, remoteIpAddress()); - logger.info("environment: {}, thread-name: {}", environment.getEnv(), thread.getName()); - thread.start(); - } - - protected String remoteIpAddress() { - String remoteIpAddress = ""; - - if (session.getIoSession().getRemoteAddress() instanceof InetSocketAddress) { - InetSocketAddress remoteAddress = (InetSocketAddress) session.getIoSession().getRemoteAddress(); - remoteIpAddress = remoteAddress.getAddress().getHostAddress(); + if (containsExit) { + break; + } + command = ""; } else { - remoteIpAddress = session.getIoSession().getRemoteAddress().toString(); - } - return remoteIpAddress; - } - - @Override - public void destroy() { - thread.interrupt(); - } - - @Override - public void run() { - String prompt = hashReplies.getProperty("prompt", "$ ").replace("{user}", environment.getEnv().get("USER")); - try { - out.write(prompt.getBytes()); - out.flush(); - - BufferedReader r = new BufferedReader(new InputStreamReader(in)); - String command = ""; - - while (!Thread.currentThread().isInterrupted()) { - int s = r.read(); - if (s == 13 || s == 10) { - - boolean containsExit = Arrays.asList(StringUtils.split(command, ";|&")).stream().map(cmd -> { - boolean wantsExit = false; - try { - wantsExit = replyUtil.replyToCommand(cmd.trim(), out, prompt, session); - out.flush(); - } catch (Exception e) { - logger.error("run error!", e); - } - return wantsExit; - }).reduce((a, b) -> a || b).get(); - - if (containsExit) { - break; - } - command = ""; - } else { - logger.trace("input character: {}", s); - if (s == 127) { - if (command.length() > 0) { - command = command.substring(0, command.length() - 1); - out.write(s); - } - } else if (s >= 32 && s < 127) { - command += (char) s; - out.write(s); - } - } - out.flush(); + logger.trace("input character: {}", s); + if (s == 127) { + if (command.length() > 0) { + command = command.substring(0, command.length() - 1); + out.write(s); } - } catch (Exception e) { - logger.error("run error!", e); - } finally { - callback.onExit(0); + } else if (s >= 32 && s < 127) { + command += (char) s; + out.write(s); + } } + out.flush(); + } + } catch (Exception e) { + logger.error("run error!", e); + } finally { + callback.onExit(0); } + } - @Override - public void setSession(ServerSession session) { - this.session = session; - } + @Override + public void setSession(ServerSession session) { + this.session = session; + } } \ No newline at end of file diff --git a/src/main/java/com/example/sshd/core/EchoShellFactory.java b/src/main/java/com/example/sshd/core/EchoShellFactory.java index a00cd69..ef98872 100644 --- a/src/main/java/com/example/sshd/core/EchoShellFactory.java +++ b/src/main/java/com/example/sshd/core/EchoShellFactory.java @@ -9,12 +9,12 @@ import org.springframework.stereotype.Component; @Component public class EchoShellFactory implements Factory { - @Autowired - ApplicationContext applicationContext; + @Autowired + ApplicationContext applicationContext; - @Override - public Command create() { - return (Command) applicationContext.getBean("echoShell"); - } + @Override + public Command create() { + return (Command) applicationContext.getBean("echoShell"); + } } \ No newline at end of file diff --git a/src/main/java/com/example/sshd/core/OnetimeCommand.java b/src/main/java/com/example/sshd/core/OnetimeCommand.java index ad22f68..b183ccd 100644 --- a/src/main/java/com/example/sshd/core/OnetimeCommand.java +++ b/src/main/java/com/example/sshd/core/OnetimeCommand.java @@ -13,29 +13,29 @@ import org.springframework.stereotype.Component; @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class OnetimeCommand extends EchoShell { - private static final Logger logger = LoggerFactory.getLogger(OnetimeCommand.class); + private static final Logger logger = LoggerFactory.getLogger(OnetimeCommand.class); - private String command; + private String command; - public OnetimeCommand(String cmd) { - command = cmd; - } + public OnetimeCommand(String cmd) { + command = cmd; + } - @Override - public void run() { + @Override + public void run() { + try { + Arrays.asList(StringUtils.split(command, ";|&")).stream().forEach(cmd -> { try { - Arrays.asList(StringUtils.split(command, ";|&")).stream().forEach(cmd -> { - try { - replyUtil.replyToCommand(cmd.trim(), out, "", session); - out.flush(); - } catch (Exception e) { - logger.error("run error!", e); - } - }); + replyUtil.replyToCommand(cmd.trim(), out, "", session); + out.flush(); } catch (Exception e) { - logger.error("run error!", e); - } finally { - callback.onExit(0); + logger.error("run error!", e); } + }); + } catch (Exception e) { + logger.error("run error!", e); + } finally { + callback.onExit(0); } + } } diff --git a/src/main/java/com/example/sshd/service/EchoComponent.java b/src/main/java/com/example/sshd/service/EchoComponent.java new file mode 100644 index 0000000..fdeb1dc --- /dev/null +++ b/src/main/java/com/example/sshd/service/EchoComponent.java @@ -0,0 +1,66 @@ +package com.example.sshd.service; + +import org.apache.commons.lang3.StringUtils; +import org.jivesoftware.whack.ExternalComponentManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.xmpp.component.AbstractComponent; +import org.xmpp.component.ComponentException; +import org.xmpp.packet.Message; + +import com.example.sshd.config.XmppComponentConfig; + +import jakarta.annotation.PostConstruct; + +@Component +public class EchoComponent extends AbstractComponent { + + private static final Logger logger = LoggerFactory.getLogger(EchoComponent.class); + + @Autowired + XmppComponentConfig xmppComponentConfig; + + ExternalComponentManager externalComponentManager = null; + + @PostConstruct + public void init() throws ComponentException { + logger.info("Starting up {} ...", xmppComponentConfig); + externalComponentManager = new ExternalComponentManager(xmppComponentConfig.getHost(), + xmppComponentConfig.getPort(), xmppComponentConfig.isStartEncrypted()); + externalComponentManager.setMultipleAllowed(xmppComponentConfig.getSubdomainPrefix(), false); + externalComponentManager.setServerName(xmppComponentConfig.getDomain()); + externalComponentManager.setSecretKey(xmppComponentConfig.getSubdomainPrefix(), + xmppComponentConfig.getSecretKey()); + externalComponentManager.addComponent(xmppComponentConfig.getSubdomainPrefix(), this, + xmppComponentConfig.getPort()); + } + + @Override + public String getDescription() { + return "XMPP component for doing ECHO"; + } + + @Override + public String getName() { + return this.getClass().getName(); + } + + protected void handleMessage(final Message inMsg) { + logger.info("-- RECEIVED -- {}", inMsg); + Message outMsg = new Message(); + outMsg.setType(inMsg.getType()); + outMsg.setFrom(inMsg.getTo()); + if (StringUtils.endsWith(inMsg.getSubject(), "@" + xmppComponentConfig.getDomain())) { + outMsg.setTo(inMsg.getSubject()); + } else { + outMsg.setTo(inMsg.getFrom()); + } + outMsg.setSubject(inMsg.getSubject()); + outMsg.setBody(inMsg.getBody()); + externalComponentManager.sendPacket(this, outMsg); + logger.info("-- SENT -- {}", outMsg); + } + +} diff --git a/src/main/java/com/example/sshd/service/GeoIpLocator.java b/src/main/java/com/example/sshd/service/GeoIpLocator.java index a8976dd..ff84d8b 100644 --- a/src/main/java/com/example/sshd/service/GeoIpLocator.java +++ b/src/main/java/com/example/sshd/service/GeoIpLocator.java @@ -22,74 +22,74 @@ import org.springframework.stereotype.Service; @Service public class GeoIpLocator { - private static final Logger logger = LoggerFactory.getLogger(GeoIpLocator.class); - private static final Logger ipInfoLogger = LoggerFactory.getLogger("ip_info"); - - @Autowired - Map ipInfoMapping; - - @Autowired - JdbcService jdbcService; - - @Autowired - CloseableHttpAsyncClient asyncClient; - - @Autowired - CloseableHttpClient httpClient; - - @Value("${ssh-server.ip-info-api.url:http://ip-api.com/json/%s}") - private String ipInfoApiUrl; - - @Value("${ssh-server.ip-info-api.method:GET}") - private String ipInfoApiMethod; - - public String getIpLocationInfo(String remoteIpAddress) { - HttpGet httpGet = new HttpGet(String.format(ipInfoApiUrl, remoteIpAddress)); - try { - return httpClient.execute(httpGet, new HttpClientResponseHandler() { - - @Override - public String handleResponse(ClassicHttpResponse result) throws HttpException, IOException { - String body = new String(result.getEntity().getContent().readAllBytes(), StandardCharsets.UTF_8); - logger.info("[{}] httpClient.execute completed, response code: {}, body: {}", remoteIpAddress, - result.getCode(), body); - ipInfoMapping.put(remoteIpAddress, body); - int inserted = jdbcService.insertRemoteIpInfo(remoteIpAddress, body); - ipInfoLogger.info("[{}] {}, inserted = {}", remoteIpAddress, ipInfoMapping.get(remoteIpAddress), - inserted); - return body; - } - - }); - } catch (IOException e) { - logger.error("[getIpLocationInfo] IO Exception has occurred!", e); - return null; + private static final Logger logger = LoggerFactory.getLogger(GeoIpLocator.class); + private static final Logger ipInfoLogger = LoggerFactory.getLogger("ip_info"); + + @Autowired + Map ipInfoMapping; + + @Autowired + JdbcService jdbcService; + + @Autowired + CloseableHttpAsyncClient asyncClient; + + @Autowired + CloseableHttpClient httpClient; + + @Value("${ssh-server.ip-info-api.url:http://ip-api.com/json/%s}") + private String ipInfoApiUrl; + + @Value("${ssh-server.ip-info-api.method:GET}") + private String ipInfoApiMethod; + + public String getIpLocationInfo(String remoteIpAddress) { + HttpGet httpGet = new HttpGet(String.format(ipInfoApiUrl, remoteIpAddress)); + try { + return httpClient.execute(httpGet, new HttpClientResponseHandler() { + + @Override + public String handleResponse(ClassicHttpResponse result) throws HttpException, IOException { + String body = new String(result.getEntity().getContent().readAllBytes(), StandardCharsets.UTF_8); + logger.info("[{}] httpClient.execute completed, response code: {}, body: {}", remoteIpAddress, + result.getCode(), body); + ipInfoMapping.put(remoteIpAddress, body); + int inserted = jdbcService.insertRemoteIpInfo(remoteIpAddress, body); + ipInfoLogger.info("[{}] {}, inserted = {}", remoteIpAddress, ipInfoMapping.get(remoteIpAddress), + inserted); + return body; } - } - public void asyncUpdateIpLocationInfo(String remoteIpAddress) { - asyncClient.execute(SimpleHttpRequest.create(ipInfoApiMethod, String.format(ipInfoApiUrl, remoteIpAddress)), - new FutureCallback() { - - @Override - public void completed(SimpleHttpResponse result) { - logger.info("[{}] asyncClient.execute completed, result: {}, content-type: {}, body: {}", - remoteIpAddress, result, result.getContentType(), result.getBodyText()); - ipInfoMapping.put(remoteIpAddress, result.getBodyText()); - int inserted = jdbcService.insertRemoteIpInfo(remoteIpAddress, result.getBodyText()); - ipInfoLogger.info("[{}] {}, inserted = {}", remoteIpAddress, ipInfoMapping.get(remoteIpAddress), - inserted); - } - - @Override - public void failed(Exception exception) { - logger.info("[{}] asyncClient.execute failed, exception: {}", remoteIpAddress, exception); - } - - @Override - public void cancelled() { - logger.info("[{}] asyncClient.execute cancelled.", remoteIpAddress); - } - }); + }); + } catch (IOException e) { + logger.error("[getIpLocationInfo] IO Exception has occurred!", e); + return null; } + } + + public void asyncUpdateIpLocationInfo(String remoteIpAddress) { + asyncClient.execute(SimpleHttpRequest.create(ipInfoApiMethod, String.format(ipInfoApiUrl, remoteIpAddress)), + new FutureCallback() { + + @Override + public void completed(SimpleHttpResponse result) { + logger.info("[{}] asyncClient.execute completed, result: {}, content-type: {}, body: {}", + remoteIpAddress, result, result.getContentType(), result.getBodyText()); + ipInfoMapping.put(remoteIpAddress, result.getBodyText()); + int inserted = jdbcService.insertRemoteIpInfo(remoteIpAddress, result.getBodyText()); + ipInfoLogger.info("[{}] {}, inserted = {}", remoteIpAddress, ipInfoMapping.get(remoteIpAddress), + inserted); + } + + @Override + public void failed(Exception exception) { + logger.info("[{}] asyncClient.execute failed, exception: {}", remoteIpAddress, exception); + } + + @Override + public void cancelled() { + logger.info("[{}] asyncClient.execute cancelled.", remoteIpAddress); + } + }); + } } diff --git a/src/main/java/com/example/sshd/service/JdbcService.java b/src/main/java/com/example/sshd/service/JdbcService.java index 883c580..70f9c46 100644 --- a/src/main/java/com/example/sshd/service/JdbcService.java +++ b/src/main/java/com/example/sshd/service/JdbcService.java @@ -16,59 +16,59 @@ import jakarta.annotation.PostConstruct; @Service public class JdbcService { - private static final String createRemoteIpLookupTableSql = "CREATE TABLE IF NOT EXISTS public.remote_ip_lookup (id BIGINT not null, " - + "remote_ip_address CHARACTER VARYING not null, remote_ip_info CHARACTER VARYING not null, PRIMARY KEY (id));"; - private static final String createRemoteIpLookupIndexSql = "CREATE INDEX IF NOT EXISTS public.remote_ip_lookup_idx ON " - + "public.remote_ip_lookup (remote_ip_address);"; + private static final String createRemoteIpLookupTableSql = "CREATE TABLE IF NOT EXISTS public.remote_ip_lookup (id BIGINT not null, " + + "remote_ip_address CHARACTER VARYING not null, remote_ip_info CHARACTER VARYING not null, PRIMARY KEY (id));"; + private static final String createRemoteIpLookupIndexSql = "CREATE INDEX IF NOT EXISTS public.remote_ip_lookup_idx ON " + + "public.remote_ip_lookup (remote_ip_address);"; - @Autowired - private JdbcTemplate jdbcTemplate; + @Autowired + private JdbcTemplate jdbcTemplate; - @PostConstruct - private void init() { - jdbcTemplate.execute(createRemoteIpLookupTableSql); - jdbcTemplate.execute(createRemoteIpLookupIndexSql); - } + @PostConstruct + private void init() { + jdbcTemplate.execute(createRemoteIpLookupTableSql); + jdbcTemplate.execute(createRemoteIpLookupIndexSql); + } - public String getRemoteIpInfo(String remoteIp) { - var result = jdbcTemplate.query( - "SELECT id, remote_ip_address, remote_ip_info from public.remote_ip_lookup WHERE remote_ip_address = ? ", - new RowMapper() { - @Override - public String mapRow(ResultSet rs, int rowNum) throws SQLException { - return rs.getString(3); - } - }, remoteIp); - return result.isEmpty() ? null : result.get(0); - } + public String getRemoteIpInfo(String remoteIp) { + var result = jdbcTemplate.query( + "SELECT id, remote_ip_address, remote_ip_info from public.remote_ip_lookup WHERE remote_ip_address = ? ", + new RowMapper() { + @Override + public String mapRow(ResultSet rs, int rowNum) throws SQLException { + return rs.getString(3); + } + }, remoteIp); + return result.isEmpty() ? null : result.get(0); + } - public List> getAllRemoteIpInfo(String remoteIp) { - return jdbcTemplate.query( - "SELECT id, remote_ip_address, remote_ip_info from public.remote_ip_lookup WHERE remote_ip_address = ? ", - new RowMapper>() { - @Override - public Map mapRow(ResultSet rs, int rowNum) throws SQLException { - return Map.of("insert_time", new Date(rs.getLong(1)), "remote_ip_address", rs.getString(2), - "remote_ip_info", rs.getString(3)); - } - }, remoteIp); - } + public List> getAllRemoteIpInfo(String remoteIp) { + return jdbcTemplate.query( + "SELECT id, remote_ip_address, remote_ip_info from public.remote_ip_lookup WHERE remote_ip_address = ? ", + new RowMapper>() { + @Override + public Map mapRow(ResultSet rs, int rowNum) throws SQLException { + return Map.of("insert_time", new Date(rs.getLong(1)), "remote_ip_address", rs.getString(2), + "remote_ip_info", rs.getString(3)); + } + }, remoteIp); + } - public List> getAllRemoteIpInfo() { - return jdbcTemplate.query( - "SELECT id, remote_ip_address, remote_ip_info from public.remote_ip_lookup order by id", - new RowMapper>() { - @Override - public Map mapRow(ResultSet rs, int rowNum) throws SQLException { - return Map.of("insert_time", new Date(rs.getLong(1)), "remote_ip_address", rs.getString(2), - "remote_ip_info", rs.getString(3)); - } - }); - } + public List> getAllRemoteIpInfo() { + return jdbcTemplate.query( + "SELECT id, remote_ip_address, remote_ip_info from public.remote_ip_lookup order by id", + new RowMapper>() { + @Override + public Map mapRow(ResultSet rs, int rowNum) throws SQLException { + return Map.of("insert_time", new Date(rs.getLong(1)), "remote_ip_address", rs.getString(2), + "remote_ip_info", rs.getString(3)); + } + }); + } - public int insertRemoteIpInfo(String remoteIpAddress, String remoteIpInfo) { - return jdbcTemplate.update( - "INSERT INTO public.remote_ip_lookup (id, remote_ip_address, remote_ip_info) VALUES (?, ?, ?)", - System.currentTimeMillis(), remoteIpAddress, remoteIpInfo); - } + public int insertRemoteIpInfo(String remoteIpAddress, String remoteIpInfo) { + return jdbcTemplate.update( + "INSERT INTO public.remote_ip_lookup (id, remote_ip_address, remote_ip_info) VALUES (?, ?, ?)", + System.currentTimeMillis(), remoteIpAddress, remoteIpInfo); + } } diff --git a/src/main/java/com/example/sshd/service/JmxClientService.java b/src/main/java/com/example/sshd/service/JmxClientService.java index e3ddad6..688a96c 100644 --- a/src/main/java/com/example/sshd/service/JmxClientService.java +++ b/src/main/java/com/example/sshd/service/JmxClientService.java @@ -24,64 +24,65 @@ import org.springframework.stereotype.Service; @Service public class JmxClientService { - private static final Logger logger = LoggerFactory.getLogger(ReplyService.class); + private static final Logger logger = LoggerFactory.getLogger(ReplyService.class); - public String process(String[] args) { - // Example - // 1st parameter: service:jmx:rmi:///jndi/rmi://127.0.0.1:2020/jmxrmi - // 2nd parameter: java.lang:type=Memory + public String process(String[] args) { + // Example + // 1st parameter: service:jmx:rmi:///jndi/rmi://127.0.0.1:2020/jmxrmi + // 2nd parameter: java.lang:type=Memory - StringBuilder output = new StringBuilder(); - try { - if (args.length > 2) { - Runtime.getRuntime().freeMemory(); - System.out.println("Connection to JMX kafka..."); - JMXServiceURL url = new JMXServiceURL(args[1]); - JMXConnector jmxc = JMXConnectorFactory.connect(url, null); - MBeanServerConnection mbsc = jmxc.getMBeanServerConnection(); + StringBuilder output = new StringBuilder(); + try { + if (args.length > 2) { + Runtime.getRuntime().freeMemory(); + System.out.println("Connection to JMX kafka..."); + JMXServiceURL url = new JMXServiceURL(args[1]); + JMXConnector jmxc = JMXConnectorFactory.connect(url, null); + MBeanServerConnection mbsc = jmxc.getMBeanServerConnection(); - ObjectName mbeanName = new ObjectName(args[2]); + ObjectName mbeanName = new ObjectName(args[2]); - MBeanInfo info = mbsc.getMBeanInfo(mbeanName); - MBeanAttributeInfo[] attribute = info.getAttributes(); + MBeanInfo info = mbsc.getMBeanInfo(mbeanName); + MBeanAttributeInfo[] attribute = info.getAttributes(); - logger.info("[process] args.length: {}", args.length); - if (args.length > 3) { - for (MBeanAttributeInfo attr : attribute) { - List alist = mbsc.getAttributes(mbeanName, new String[] { attr.getName() }).asList(); - if (args[3].equals(attr.getName())) { - Optional> opt = alist.stream().filter(a -> a.getName().equals(args[3])) - .map(a -> toMap((CompositeData) a.getValue())).findFirst(); - if (opt.isPresent()) { - output.append(attr.getName() + ": " + opt.get() + "\r\n"); - } - } - } - } else { - for (MBeanAttributeInfo attr : attribute) { - List alist = mbsc.getAttributes(mbeanName, new String[] { attr.getName() }).asList(); - output.append(attr.getName() + ": " + alist + "\r\n"); - } - } - jmxc.close(); - } else { - output.append("Example: jmx_client service:jmx:rmi:///jndi/rmi://127.0.0.1:2020/jmxrmi java.lang:type=Memory HeapMemoryUsage\r\n"); + logger.info("[process] args.length: {}", args.length); + if (args.length > 3) { + for (MBeanAttributeInfo attr : attribute) { + List alist = mbsc.getAttributes(mbeanName, new String[] { attr.getName() }).asList(); + if (args[3].equals(attr.getName())) { + Optional> opt = alist.stream().filter(a -> a.getName().equals(args[3])) + .map(a -> toMap((CompositeData) a.getValue())).findFirst(); + if (opt.isPresent()) { + output.append(attr.getName() + ": " + opt.get() + "\r\n"); + } } - } catch (Exception e) { - logger.error("process cmd failed: {}", Arrays.asList(args), e); + } + } else { + for (MBeanAttributeInfo attr : attribute) { + List alist = mbsc.getAttributes(mbeanName, new String[] { attr.getName() }).asList(); + output.append(attr.getName() + ": " + alist + "\r\n"); + } } - return output.toString(); + jmxc.close(); + } else { + output.append( + "Example: jmx_client service:jmx:rmi:///jndi/rmi://127.0.0.1:2020/jmxrmi java.lang:type=Memory HeapMemoryUsage\r\n"); + } + } catch (Exception e) { + logger.error("process cmd failed: {}", Arrays.asList(args), e); } + return output.toString(); + } - public static Map toMap(CompositeData cd) { - if (cd == null) - throw new IllegalArgumentException("composite data should not be null"); - Map map = new HashMap(); - Set itemNames = cd.getCompositeType().keySet(); - for (String itemName : itemNames) { - Object item = cd.get(itemName); - map.put(itemName, item); - } - return map; + public static Map toMap(CompositeData cd) { + if (cd == null) + throw new IllegalArgumentException("composite data should not be null"); + Map map = new HashMap(); + Set itemNames = cd.getCompositeType().keySet(); + for (String itemName : itemNames) { + Object item = cd.get(itemName); + map.put(itemName, item); } + return map; + } } diff --git a/src/main/java/com/example/sshd/service/ReplyService.java b/src/main/java/com/example/sshd/service/ReplyService.java index fe5f4bd..f74bd73 100644 --- a/src/main/java/com/example/sshd/service/ReplyService.java +++ b/src/main/java/com/example/sshd/service/ReplyService.java @@ -25,118 +25,118 @@ import org.springframework.stereotype.Service; @Service public class ReplyService { - private static final Logger logger = LoggerFactory.getLogger(ReplyService.class); - private static final Logger notFoundLogger = LoggerFactory.getLogger("not_found"); - - @Autowired - Properties hashReplies; - - @Autowired - Properties regexMapping; - - @Autowired - Map ipInfoMapping; - - @Autowired - JdbcService jdbcService; - - @Autowired - GeoIpLocator geoIpLocator; - - @Autowired - JmxClientService jmxClientService; - - public boolean replyToCommand(String command, OutputStream out, String prompt, ServerSession session) - throws IOException { - - String cmdHash = DigestUtils.md5Hex(command.trim()).toUpperCase(); - if (StringUtils.equalsIgnoreCase(command.trim(), "my_geolocation")) { - logger.info("[{}] my_geolocation command detected: {}", cmdHash, command.trim()); - out.write(String.format("\r\n%s\r\n%s", ipInfoMapping.get(Thread.currentThread().getName()), prompt) - .getBytes()); - - } else if (StringUtils.equalsIgnoreCase(command.trim(), "whoami")) { - logger.info("[{}] whoami command detected: {}", cmdHash, command.trim()); - out.write(String.format("\r\n%s\r\n%s", session.getUsername(), prompt).getBytes()); - - } else if (StringUtils.equalsIgnoreCase(command.trim(), "online_geolocations")) { - logger.info("[{}] online_geolocations command detected: {}", cmdHash, command.trim()); - out.write(String.format("\r\n%s\r\n%s", ipInfoMapping.toString(), prompt).getBytes()); - - } else if (StringUtils.equalsIgnoreCase(StringUtils.split(command.trim(), " ")[0], "jmx_client")) { - String remoteJmxResponse = jmxClientService.process(StringUtils.split(command.trim(), " ")); - logger.info("[{}] jmx_client command detected: {}", cmdHash, command.trim()); - out.write(String.format("\r\n%s\r\n%s", remoteJmxResponse, prompt).getBytes()); - - } else if (StringUtils.split(command.trim(), " ").length == 2 - && StringUtils.equalsIgnoreCase(StringUtils.split(command.trim(), " ")[0], "get_geolocation")) { - String remoteIpInfo = StringUtils.getIfBlank( - jdbcService.getRemoteIpInfo(StringUtils.split(command.trim(), " ")[1]), - () -> geoIpLocator.getIpLocationInfo(StringUtils.split(command.trim(), " ")[1])); - logger.info("[{}] get_geolocation command detected: {}", cmdHash, command.trim()); - out.write(String.format("\r\n%s\r\n%s", remoteIpInfo, prompt).getBytes()); - - } else if (StringUtils.equalsIgnoreCase(command.trim(), "all_geolocations")) { - logger.info("[{}] all_geolocations command detected: {}", cmdHash, command.trim()); - out.write(String.format("\r\n%s\r\n%s", jdbcService.getAllRemoteIpInfo(), prompt).getBytes()); - - } else if (StringUtils.equalsIgnoreCase(command.trim(), "exit") - || StringUtils.equalsIgnoreCase(command.trim(), "quit")) { - logger.info("[{}] Exiting command detected: {}", cmdHash, command.trim()); - out.write(String.format("\r\nExiting...\r\n%s", prompt).getBytes()); - return true; - - } else if (hashReplies.containsKey(command.trim())) { - logger.info("[{}] Known command detected: {}", cmdHash, command.trim()); - String reply = hashReplies.getProperty(command.trim()).replace("\\r", "\r").replace("\\n", "\n") - .replace("\\t", "\t"); - out.write(String.format("\r\n%s\r\n%s", reply, prompt).getBytes()); - - } else if (hashReplies.containsKey(cmdHash)) { - logger.info("[{}] Known command-hash detected: {}", cmdHash, command.trim()); - String reply = hashReplies.getProperty(cmdHash).replace("\\r", "\r").replace("\\n", "\n").replace("\\t", - "\t"); - out.write(String.format("\r\n%s\r\n%s", reply, prompt).getBytes()); - - } else if (hashReplies.containsKey(String.format("base64(%s)", cmdHash))) { - logger.info("[{}] Known base64-hash detected: {}", cmdHash, command.trim()); - String reply = hashReplies.getProperty(String.format("base64(%s)", cmdHash)); - reply = new String(Base64.decodeBase64(reply)); - out.write(String.format("\r\n%s\r\n%s", reply, prompt).getBytes()); - + private static final Logger logger = LoggerFactory.getLogger(ReplyService.class); + private static final Logger notFoundLogger = LoggerFactory.getLogger("not_found"); + + @Autowired + Properties hashReplies; + + @Autowired + Properties regexMapping; + + @Autowired + Map ipInfoMapping; + + @Autowired + JdbcService jdbcService; + + @Autowired + GeoIpLocator geoIpLocator; + + @Autowired + JmxClientService jmxClientService; + + public boolean replyToCommand(String command, OutputStream out, String prompt, ServerSession session) + throws IOException { + + String cmdHash = DigestUtils.md5Hex(command.trim()).toUpperCase(); + if (StringUtils.equalsIgnoreCase(command.trim(), "my_geolocation")) { + logger.info("[{}] my_geolocation command detected: {}", cmdHash, command.trim()); + out.write(String.format("\r\n%s\r\n%s", ipInfoMapping.get(Thread.currentThread().getName()), prompt) + .getBytes()); + + } else if (StringUtils.equalsIgnoreCase(command.trim(), "whoami")) { + logger.info("[{}] whoami command detected: {}", cmdHash, command.trim()); + out.write(String.format("\r\n%s\r\n%s", session.getUsername(), prompt).getBytes()); + + } else if (StringUtils.equalsIgnoreCase(command.trim(), "online_geolocations")) { + logger.info("[{}] online_geolocations command detected: {}", cmdHash, command.trim()); + out.write(String.format("\r\n%s\r\n%s", ipInfoMapping.toString(), prompt).getBytes()); + + } else if (StringUtils.equalsIgnoreCase(StringUtils.split(command.trim(), " ")[0], "jmx_client")) { + String remoteJmxResponse = jmxClientService.process(StringUtils.split(command.trim(), " ")); + logger.info("[{}] jmx_client command detected: {}", cmdHash, command.trim()); + out.write(String.format("\r\n%s\r\n%s", remoteJmxResponse, prompt).getBytes()); + + } else if (StringUtils.split(command.trim(), " ").length == 2 + && StringUtils.equalsIgnoreCase(StringUtils.split(command.trim(), " ")[0], "get_geolocation")) { + String remoteIpInfo = StringUtils.getIfBlank( + jdbcService.getRemoteIpInfo(StringUtils.split(command.trim(), " ")[1]), + () -> geoIpLocator.getIpLocationInfo(StringUtils.split(command.trim(), " ")[1])); + logger.info("[{}] get_geolocation command detected: {}", cmdHash, command.trim()); + out.write(String.format("\r\n%s\r\n%s", remoteIpInfo, prompt).getBytes()); + + } else if (StringUtils.equalsIgnoreCase(command.trim(), "all_geolocations")) { + logger.info("[{}] all_geolocations command detected: {}", cmdHash, command.trim()); + out.write(String.format("\r\n%s\r\n%s", jdbcService.getAllRemoteIpInfo(), prompt).getBytes()); + + } else if (StringUtils.equalsIgnoreCase(command.trim(), "exit") + || StringUtils.equalsIgnoreCase(command.trim(), "quit")) { + logger.info("[{}] Exiting command detected: {}", cmdHash, command.trim()); + out.write(String.format("\r\nExiting...\r\n%s", prompt).getBytes()); + return true; + + } else if (hashReplies.containsKey(command.trim())) { + logger.info("[{}] Known command detected: {}", cmdHash, command.trim()); + String reply = hashReplies.getProperty(command.trim()).replace("\\r", "\r").replace("\\n", "\n") + .replace("\\t", "\t"); + out.write(String.format("\r\n%s\r\n%s", reply, prompt).getBytes()); + + } else if (hashReplies.containsKey(cmdHash)) { + logger.info("[{}] Known command-hash detected: {}", cmdHash, command.trim()); + String reply = hashReplies.getProperty(cmdHash).replace("\\r", "\r").replace("\\n", "\n").replace("\\t", + "\t"); + out.write(String.format("\r\n%s\r\n%s", reply, prompt).getBytes()); + + } else if (hashReplies.containsKey(String.format("base64(%s)", cmdHash))) { + logger.info("[{}] Known base64-hash detected: {}", cmdHash, command.trim()); + String reply = hashReplies.getProperty(String.format("base64(%s)", cmdHash)); + reply = new String(Base64.decodeBase64(reply)); + out.write(String.format("\r\n%s\r\n%s", reply, prompt).getBytes()); + + } else { + Optional> o = regexMapping.entrySet().stream() + .filter(e -> command.trim().matches(((String) e.getKey()))) + .map(e -> Pair.of((String) e.getKey(), (String) e.getValue())).findAny(); + if (o.isPresent()) { + String reply = hashReplies.getProperty(o.get().getRight(), "").replace("\\r", "\r").replace("\\n", "\n") + .replace("\\t", "\t"); + if (reply.isEmpty()) { + logger.info("[{}] Execute cmd for real: {} ({})", cmdHash, command.trim(), o.get()); + ByteArrayOutputStream tempOut = new ByteArrayOutputStream(); + try { + CommandLine cmdLine = CommandLine.parse(command.trim()); + DefaultExecutor executor = DefaultExecutor.builder().get(); + PumpStreamHandler streamHandler = new PumpStreamHandler(tempOut); + executor.setStreamHandler(streamHandler); + int exitValue = executor.execute(cmdLine); + logger.info("[{}] Result: {} ({})", cmdHash, command.trim(), exitValue); + reply = new String(tempOut.toByteArray()).replace("\n", "\r\n"); + } catch (ExecuteException e) { + logger.info("[{}] Execute cmd failed: {} ({})", cmdHash, command.trim(), o.get(), e); + } + out.write(String.format("\r\n%s\r\n%s", reply, prompt).getBytes()); } else { - Optional> o = regexMapping.entrySet().stream() - .filter(e -> command.trim().matches(((String) e.getKey()))) - .map(e -> Pair.of((String) e.getKey(), (String) e.getValue())).findAny(); - if (o.isPresent()) { - String reply = hashReplies.getProperty(o.get().getRight(), "").replace("\\r", "\r").replace("\\n", "\n") - .replace("\\t", "\t"); - if (reply.isEmpty()) { - logger.info("[{}] Execute cmd for real: {} ({})", cmdHash, command.trim(), o.get()); - ByteArrayOutputStream tempOut = new ByteArrayOutputStream(); - try { - CommandLine cmdLine = CommandLine.parse(command.trim()); - DefaultExecutor executor = DefaultExecutor.builder().get(); - PumpStreamHandler streamHandler = new PumpStreamHandler(tempOut); - executor.setStreamHandler(streamHandler); - int exitValue = executor.execute(cmdLine); - logger.info("[{}] Result: {} ({})", cmdHash, command.trim(), exitValue); - reply = new String(tempOut.toByteArray()).replace("\n", "\r\n"); - } catch (ExecuteException e) { - logger.info("[{}] Execute cmd failed: {} ({})", cmdHash, command.trim(), o.get(), e); - } - out.write(String.format("\r\n%s\r\n%s", reply, prompt).getBytes()); - } else { - logger.info("[{}] Known pattern detected: {} ({})", cmdHash, command.trim(), o.get()); - out.write(String.format("\r\n%s\r\n%s", reply, prompt).getBytes()); - } - } else { - logger.info("[{}] Command not found: {}", cmdHash, command.trim()); - notFoundLogger.info("[{}] Command not found: {}", cmdHash, command.trim()); - out.write(String.format("\r\nCommand '%s' not found. Try 'exit'.\r\n%s", command.trim(), prompt) - .getBytes()); - } + logger.info("[{}] Known pattern detected: {} ({})", cmdHash, command.trim(), o.get()); + out.write(String.format("\r\n%s\r\n%s", reply, prompt).getBytes()); } - return false; + } else { + logger.info("[{}] Command not found: {}", cmdHash, command.trim()); + notFoundLogger.info("[{}] Command not found: {}", cmdHash, command.trim()); + out.write(String.format("\r\nCommand '%s' not found. Try 'exit'.\r\n%s", command.trim(), prompt) + .getBytes()); + } } + return false; + } }