V1.1.3 Gather more info on remote ip address using free ip-info api

master
Ng Yat Yan 1 month ago
parent 1373bdcddd
commit f57a7c780d

@ -23,11 +23,23 @@
<TimeBasedTriggeringPolicy interval="1" modulate="true" />
</Policies>
</RollingFile>
<RollingFile name="LogToIpInfo"
filePattern="logs/ip_info.%d{yyyy-MM-dd}.log"
immediateFlush="true">
<PatternLayout
pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %p [%t] %c : %m%n" />
<Policies>
<TimeBasedTriggeringPolicy interval="1" modulate="true" />
</Policies>
</RollingFile>
</Appenders>
<Loggers>
<Logger name="not_found" level="info" additivity="false">
<AppenderRef ref="LogToConsole" />
</Logger>
<Logger name="ip_info" level="info" additivity="false">
<AppenderRef ref="LogToIpInfo" />
</Logger>
<Root level="info">
<AppenderRef ref="LogToConsole" />
</Root>

@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.example.sshd</groupId>
<artifactId>echo-sshd-server</artifactId>
<version>1.1.2</version>
<version>1.1.3</version>
<name>ECHO SSH SERVER</name>
<description>Learning Apache Mina SSHD library</description>
<parent>
@ -66,6 +66,10 @@
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
</dependency>
</dependencies>
<build>
<plugins>

@ -8,4 +8,4 @@ I share this project so that others can learn this as well.
mvn clean package
## How to run
java -jar echo-sshd-server-<version>.jar
java -jar echo-sshd-server-{version}.jar

@ -4,6 +4,9 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
import org.apache.hc.core5.reactor.IOReactorConfig;
import org.apache.sshd.common.Session;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
@ -18,4 +21,18 @@ public class AppConfig {
public Map<String, Session> remoteSessionMapping() {
return Collections.synchronizedMap(new HashMap<>());
}
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
public Map<String, String> ipInfoMapping() {
return Collections.synchronizedMap(new HashMap<>());
}
@Bean
public CloseableHttpAsyncClient asyncClient() {
final IOReactorConfig ioReactorConfig = IOReactorConfig.custom().build();
final CloseableHttpAsyncClient client = HttpAsyncClients.custom().setIOReactorConfig(ioReactorConfig).build();
client.start();
return client;
}
}

@ -3,21 +3,39 @@ package com.example.sshd.core;
import java.net.InetSocketAddress;
import java.util.Map;
import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
import org.apache.hc.core5.concurrent.FutureCallback;
import org.apache.sshd.common.Session;
import org.apache.sshd.common.SessionListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class EchoSessionListener implements SessionListener {
private static final Logger logger = LoggerFactory.getLogger(EchoSessionListener.class);
private static final Logger ipInfoLogger = LoggerFactory.getLogger("ip_info");
@Autowired
Map<String, Session> remoteSessionMapping;
@Autowired
Map<String, String> ipInfoMapping;
@Autowired
CloseableHttpAsyncClient asyncClient;
@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;
@Override
public void sessionCreated(Session session) {
logger.info("sessionCreated: {}", session);
@ -36,6 +54,36 @@ public class EchoSessionListener implements SessionListener {
@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)) {
asyncClient.execute(
SimpleHttpRequest.create(ipInfoApiMethod, String.format(ipInfoApiUrl, remoteIpAddress)),
new FutureCallback<SimpleHttpResponse>() {
@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());
ipInfoLogger.info("[{}] {}", remoteIpAddress, ipInfoMapping.get(remoteIpAddress));
}
@Override
public void failed(Exception exception) {
logger.info("[{}] asyncClient.execute failed, exception: {}", remoteIpAddress, exception);
}
@Override
public void cancelled() {
logger.info("[{}] asyncClient.execute cancelled.", remoteIpAddress);
}
});
} else {
ipInfoLogger.debug("[{}] {}", remoteIpAddress, ipInfoMapping.get(remoteIpAddress));
}
}
}
@Override

@ -15,7 +15,6 @@ import org.apache.sshd.server.ExitCallback;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import com.example.sshd.util.ReplyUtil;
@ -26,13 +25,10 @@ public class EchoShellFactory implements Factory<Command> {
private static final Logger logger = LoggerFactory.getLogger(EchoShellFactory.class);
@Autowired
Properties hashReplies;
@Autowired
Properties regexMapping;
ReplyUtil replyUtil;
@Autowired
ApplicationContext applicationContext;
Properties hashReplies;
@Override
public Command create() {
@ -41,28 +37,12 @@ public class EchoShellFactory implements Factory<Command> {
public class EchoShell implements Command, Runnable {
private InputStream in;
private OutputStream out;
private OutputStream err;
private ExitCallback callback;
private Environment environment;
private Thread thread;
public InputStream getIn() {
return in;
}
public OutputStream getOut() {
return out;
}
public OutputStream getErr() {
return err;
}
public Environment getEnvironment() {
return environment;
}
protected InputStream in;
protected OutputStream out;
protected OutputStream err;
protected ExitCallback callback;
protected Environment environment;
protected Thread thread;
@Override
public void setInputStream(InputStream in) {
@ -87,6 +67,7 @@ public class EchoShellFactory implements Factory<Command> {
@Override
public void start(Environment env) throws IOException {
environment = env;
logger.info("environment: {}", environment.getEnv());
thread = new Thread(this, UUID.randomUUID().toString());
thread.start();
}
@ -109,7 +90,7 @@ public class EchoShellFactory implements Factory<Command> {
while (!Thread.currentThread().isInterrupted()) {
int s = r.read();
if (s == 13 || s == 10) {
if (!ReplyUtil.replyToCommand(command, out, prompt, hashReplies, regexMapping)) {
if (!replyUtil.replyToCommand(command, out, prompt)) {
out.flush();
return;
}

@ -3,7 +3,6 @@ package com.example.sshd.core;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Properties;
import org.apache.sshd.server.Command;
import org.apache.sshd.server.Environment;
@ -20,10 +19,7 @@ import com.example.sshd.util.ReplyUtil;
public class OnetimeCommand implements Command {
@Autowired
Properties hashReplies;
@Autowired
Properties regexMapping;
ReplyUtil replyUtil;
private InputStream in;
private OutputStream out;
@ -75,7 +71,7 @@ public class OnetimeCommand implements Command {
@Override
public void start(Environment env) throws IOException {
environment = env;
ReplyUtil.replyToCommand(command, out, "", hashReplies, regexMapping);
replyUtil.replyToCommand(command, out, "");
out.flush();
callback.onExit(0);
}

@ -10,14 +10,22 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class ReplyUtil {
private static final Logger logger = LoggerFactory.getLogger(ReplyUtil.class);
private static final Logger notFoundLogger = LoggerFactory.getLogger("not_found");
public static boolean replyToCommand(String command, OutputStream out, String prompt, Properties hashReplies,
Properties regexMapping) throws IOException {
@Autowired
Properties hashReplies;
@Autowired
Properties regexMapping;
public boolean replyToCommand(String command, OutputStream out, String prompt) throws IOException {
String cmdHash = DigestUtils.md5Hex(command.trim()).toUpperCase();

Loading…
Cancel
Save