netconf ssh
NETCONF协议详解https://blog.csdn.net/anzheangel/article/details/78885880Hi Viraj,our software consists of 2 main packages:libnetconf is a library that is meant for building NETCONF servers and cli...
NETCONF协议详解
NETCONF协议详解_anzheangel的博客-CSDN博客_netconf
Hi Viraj,
our software consists of 2 main packages:
libnetconf is a library that is meant for building NETCONF servers and clients with everything that is required.
netopeer is an implementation of a full NETCONF server (netopeer-server) and a NETCONF client (netopeer-cli). It is build using libnetconf and is ready to be deployed and used.
However, libnetconf is now quite old and no longer updated, only maintained. There are several known issues (which will not be fixed) and it often does things ineffectively and is generally quite complex. That is why we started from scratch and are working on a new generation of this software:
libnetconf2 is a NETCONF library just like libnetconf, but excludes YANG module processing and a datastore implementation, these are provided separately.
libyang is a library for YANG module processing, as mentioned previously, required by libnetconf2.
sysrepo is a complex datastore implementation, but it is actually meant to manage and interconnect all the applications and their configuration files on a system. This is not developed by us, but we cooperate with its development team.
netopeer2 is again a NETCONF server and a client, which uses libnetconf2 and sysrepo for a fully working NETCONF solution.
The new generation is usable and offers some basic functionality, but it is still work-in-progress and definitely not ready for deployment.
Regards,
Michal
GitHub - CESNET/netopeer2: NETCONF toolset
SSH协议详解
ssh协议的原理,你有可能还不知道
ssh协议的原理,你有可能还不知道_somezz的专栏-CSDN博客
如何使用Apache MINA SSHD构建一个netconf服务端
一、添加依赖
首先,在你的 Maven pom.xml 中添加 Apache MINA SSHD 的依赖:
<dependencies>
<!-- Apache MINA SSHD Core -->
<dependency>
<groupId>org.apache.sshd</groupId>
<artifactId>sshd-core</artifactId>
<version>2.9.2</version> <!-- 请使用最新稳定版 -->
</dependency>
<!-- 可选:用于密码认证的工具 -->
<dependency>
<groupId>org.apache.sshd</groupId>
<artifactId>sshd-common</artifactId>
<version>2.9.2</version>
</dependency>
<!-- 日志支持(如 SLF4J + Logback) -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.14</version>
</dependency>
</dependencies>
二、实现 NETCONF Shell(Command)
NETCONF over SSH 使用一个名为 netconf 的子系统(subsystem)或通过执行 netconf 命令启动。我们这里模拟通过执行 netconf 命令进入 NETCONF 会话。
创建一个实现 Command 接口的类,用于处理 NETCONF 会话:
// NetconfCommand.java
import org.apache.sshd.server.command.Command;
import org.apache.sshd.server.Environment;
import org.apache.sshd.server.ExitCallback;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.atomic.AtomicBoolean;
public class NetconfCommand implements Command {
private static final Logger logger = LoggerFactory.getLogger(NetconfCommand.class);
private InputStream input;
private OutputStream output;
private OutputStream error;
private ExitCallback callback;
private Thread processingThread;
private final AtomicBoolean running = new AtomicBoolean(false);
@Override
public void setInputStream(InputStream in) {
this.input = in;
}
@Override
public void setOutputStream(OutputStream out) {
this.output = out;
}
@Override
public void setErrorStream(OutputStream err) {
this.error = err;
}
@Override
public void setExitCallback(ExitCallback callback) {
this.callback = callback;
}
@Override
public void start(Environment env) throws IOException {
if (running.compareAndSet(false, true)) {
logger.info("Starting NETCONF session...");
// 发送 NETCONF Hello 消息
String helloMessage = """
<?xml version="1.0" encoding="UTF-8"?>
<hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<capabilities>
<capability>urn:ietf:params:netconf:base:1.0</capability>
</capabilities>
</hello>]]>]]>
""";
output.write(helloMessage.getBytes(StandardCharsets.UTF_8));
output.flush();
// 启动处理线程
processingThread = new Thread(this::processNetconfSession, "NetconfSession");
processingThread.start();
}
}
private void processNetconfSession() {
BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));
PrintWriter writer = new PrintWriter(new OutputStreamWriter(output, StandardCharsets.UTF_8), true);
try {
String line;
StringBuilder messageBuffer = new StringBuilder();
while (running.get() && (line = reader.readLine()) != null) {
messageBuffer.append(line).append("\n");
// 检查是否收到消息结束标记
if (line.trim().equals("]]>]]>")) {
String fullMessage = messageBuffer.toString();
messageBuffer.setLength(0); // 清空缓冲区
logger.debug("Received NETCONF message:\n{}", fullMessage);
// 简单回显响应(实际应解析并处理 RPC)
String response = """
<?xml version="1.0" encoding="UTF-8"?>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="101">
<ok/>
</rpc-reply>]]>]]>
""";
writer.print(response);
writer.flush();
}
}
} catch (IOException e) {
logger.error("Error in NETCONF session", e);
} finally {
close();
}
}
@Override
public void destroy() {
close();
}
private void close() {
if (running.compareAndSet(true, false)) {
if (processingThread != null && processingThread.isAlive()) {
processingThread.interrupt();
}
if (callback != null) {
callback.onExit(0);
}
logger.info("NETCONF session ended.");
}
}
}
三、配置 SSH 服务器并注册命令
接下来,创建并配置 SSH 服务器,注册 netconf 命令:
// NetconfServer.java
import org.apache.sshd.server.SshServer;
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
import org.apache.sshd.server.password.PasswordAuthenticator;
import org.apache.sshd.server.session.ServerSession;
import org.apache.sshd.server.shell.ProcessShellFactory;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.Collections;
public class NetconfServer {
public static void main(String[] args) throws IOException, InterruptedException {
int port = 830; // NETCONF 默认端口
SshServer sshd = SshServer.setUpDefaultServer();
sshd.setPort(port);
sshd.setHost("0.0.0.0");
// 设置主机密钥(首次运行会生成)
sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(
Paths.get("hostkey.ser")));
// 设置密码认证(示例中允许任何密码,实际应验证)
sshd.setPasswordAuthenticator(new PasswordAuthenticator() {
@Override
public boolean authenticate(String username, String password, ServerSession session) {
System.out.println("Authenticating user: " + username);
return "admin".equals(username) && "password".equals(password); // 简单认证
}
});
// 注册 "netconf" 命令
sshd.setCommandFactory((channel, command) -> {
if ("netconf".equals(command)) {
return new NetconfCommand();
}
// 可选:支持其他命令如 "exit", "help" 等
return new ProcessShellFactory(command).create();
});
// 启动服务器
sshd.start();
System.out.println("NETCONF SSH server started on port " + port);
// 保持主线程运行
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
try {
sshd.stop();
System.out.println("Server stopped.");
} catch (IOException e) {
e.printStackTrace();
}
}));
Thread.currentThread().join();
}
}
四、测试你的 NETCONF 服务端
你可以使用支持 NETCONF 的客户端进行测试,例如 netconf-console(Python)或 yang-explorer,或者直接使用 SSH 客户端手动测试:
ssh admin@localhost -p 830 -s netconf
连接后,你应该看到服务端发送的 Hello 消息。然后你可以手动输入 NETCONF RPC 请求(以 ]]>]]> 结尾),例如:
<?xml version="1.0" encoding="UTF-8"?>
<rpc message-id="100" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<get-config>
<source><running/></source>
</get-config>
</rpc>]]>]]>
服务端会返回一个简单的 <ok/> 响应。
五、后续增强建议
完整 NETCONF 协议支持:
解析接收到的 XML RPC 请求。
根据请求操作数据存储(如配置数据库)。
返回符合标准的 <rpc-reply>。
支持 NETCONF Subsystem:
实现 Command 并注册为 subsystem:sshd.setSubsystemFactories(...)
客户端使用 ssh -s netconf 连接。
支持公钥认证、ACL、日志审计等。
集成 YANG 模型解析器(如使用 sysrepo、libyang 或 Java 的 mdsal)。
使用线程池或异步处理提高并发性能。
六、注意事项
NETCONF over SSH 使用端口 830(IANA 标准)。
消息以 ]]>]]> 作为分隔符(RFC 6242)。
所有通信必须是格式良好的 XML。
生产环境需加强认证、授权、加密和错误处理。
通过以上步骤,你已经使用 Apache MINA SSHD 成功构建了一个基础的 NETCONF 服务端。你可以在此基础上逐步扩展功能,实现完整的 NETCONF 协议栈。
NETCONF Subsystem 和 sshd.setCommandFactory的区别
这是一个非常好的问题!在使用 Apache MINA SSHD 构建 NETCONF 服务端时,理解 Subsystem 和 CommandFactory 的区别至关重要,因为 NETCONF 协议标准推荐(甚至要求)使用 Subsystem 方式。
也就是说,标准的 NETCONF 客户端(如 libnetconf2、ncclient、YangExplorer)默认都是通过 -s netconf 调用子系统方式连接的。如果你只实现 CommandFactory,很多标准客户端将无法连接!
正确方式:使用 Subsystem(推荐)
// 1. 创建 NetconfCommand(实现 Command 接口,同之前)
public class NetconfCommand implements Command { ... } // 内容与之前相同
// 2. 创建 SubsystemFactory
public class NetconfSubsystemFactory implements SubsystemFactory {
@Override
public String getName() {
return "netconf"; // 必须是 "netconf" —— RFC 要求
}
@Override
public Command createSubsystem(ChannelSession channel) throws IOException {
return new NetconfCommand(); // 返回你的 NETCONF 处理命令
}
}
// 3. 在服务器中注册 Subsystem
sshd.setSubsystemFactories(Collections.singletonList(new NetconfSubsystemFactory()));
客户端连接方式:
ssh admin@localhost -p 830 -s netconf
四、协议层面的区别(SSH 报文)
当你使用 -s netconf:
SSH_MSG_CHANNEL_REQUEST
channel: N
request: "subsystem"
want_reply: 1
subsystem name: "netconf"
当你使用 ssh user@host netconf:
SSH_MSG_CHANNEL_REQUEST
channel: N
request: "exec"
want_reply: 1
command: "netconf"
→ NETCONF 客户端库(如 Python ncclient)默认发送的是 subsystem 请求,不是 exec 请求。所以如果你的服务端只支持 exec,客户端会报错:
Subsystem request 'netconf' failed
使用apache sshd,构建一个sshd server
<dependency>
<groupId>org.apache.sshd</groupId>
<artifactId>sshd-core</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.26</version>
</dependency>
package gaofeng.netconf;
import java.io.IOException;
import java.nio.file.Paths;
import org.apache.sshd.server.SshServer;
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
import org.apache.sshd.server.shell.ProcessShellFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class App {
private static Logger log = LoggerFactory.getILoggerFactory().getLogger(App.class.getName());
public static void main(String[] args) throws IOException, InterruptedException {
System.out.println("Hello World!");
log.info("hello,gaofeng");
SshServer sshd = SshServer.setUpDefaultServer();
sshd.setHost("127.0.0.1");
sshd.setPort(2222);
sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(Paths.get( "key.ser")));
//服务器第一次启动,产生一个随机密钥,存储在这里。下次重启,继续使用这个密钥。否则客户端需要删除known_hosts中保存的服务器公钥。
sshd.setPasswordAuthenticator(
(username, password, session) ->
{ log.info(username + " " + password); return true;}
);
// sshd.setShellFactory(new ProcessShellFactory(new String[] { "/bin/sh.exe", "-i", "-l" }));
sshd.setShellFactory( new ProcessShellFactory(new String[] { "cmd.exe" }));
sshd.start();
Thread.sleep(300*1000);
}
}
控制台打印
Hello World!
[main] INFO gaofeng.netconf.App - hello,gaofeng
[main] INFO org.apache.sshd.common.io.DefaultIoServiceFactoryFactory - No detected/configured IoServiceFactoryFactory using Nio2ServiceFactoryFactory
[sshd-SshServer[12c72c2](port=2222)-nio2-thread-5] INFO gaofeng.netconf.App - root yy
[sshd-SshServer[12c72c2](port=2222)-nio2-thread-5] INFO org.apache.sshd.server.session.ServerUserAuthService - Session root@/127.0.0.1:61274 authenticated
通过研究sshd的代码,可以看到sshd用的也是 连接服务+异步处理模式,可以用nio2,也可以用mina,还可以用jetty。
默认用的是NIO2
if (factory == null) {
factory = BuiltinIoServiceFactoryFactories.NIO2.create();
log.info("No detected/configured " + IoServiceFactoryFactory.class.getSimpleName()
+ " using " + factory.getClass().getSimpleName());
}
另外,sshd
增加一个异常打印,可以看到,sshd是先解码(解密),然后将数据交给具体的应用进行处理的。
比如上面的ssh服务,我输入dir三个字母,每个字母都会调用到下面的调用链。
at org.apache.sshd.common.channel.AbstractChannel.handleData(AbstractChannel.java:802)
at org.apache.sshd.common.session.helpers.AbstractConnectionService.channelData(AbstractConnectionService.java:584)
at org.apache.sshd.common.session.helpers.AbstractConnectionService.process(AbstractConnectionService.java:465)
at org.apache.sshd.common.session.helpers.AbstractSession.doHandleMessage(AbstractSession.java:503)
at org.apache.sshd.common.session.helpers.AbstractSession.handleMessage(AbstractSession.java:429)
at org.apache.sshd.common.session.helpers.AbstractSession.decode(AbstractSession.java:1466)
at org.apache.sshd.common.session.helpers.AbstractSession.messageReceived(AbstractSession.java:389)
at org.apache.sshd.common.session.helpers.AbstractSessionIoHandler.messageReceived(AbstractSessionIoHandler.java:64)
at org.apache.sshd.common.io.nio2.Nio2Session.handleReadCycleCompletion(Nio2Session.java:359)
at org.apache.sshd.common.io.nio2.Nio2Session$1.onCompleted(Nio2Session.java:336)
at org.apache.sshd.common.io.nio2.Nio2Session$1.onCompleted(Nio2Session.java:1)
at org.apache.sshd.common.io.nio2.Nio2CompletionHandler.lambda$0(Nio2CompletionHandler.java:38)
at java.security.AccessController.doPrivileged(Native Method)
at org.apache.sshd.common.io.nio2.Nio2CompletionHandler.completed(Nio2CompletionHandler.java:37)
at sun.nio.ch.Invoker.invokeUnchecked(Invoker.java:126)
at sun.nio.ch.Invoker$2.run(Invoker.java:218)
at sun.nio.ch.AsynchronousChannelGroupImpl$1.run(AsynchronousChannelGroupImpl.java:112)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
注意下面的解密器 inCipher
protected void decode() throws Exception {
// Decoding loop
for (;;) {
int authSize = inCipher != null ? inCipher.getAuthenticationTagSize() : 0;
boolean authMode = authSize > 0;
int macSize = inMac != null ? inMacSize : 0;
boolean etmMode = inMac != null && inMac.isEncryptThenMac();
// Wait for beginning of packet
if (decoderState == 0) {
// The read position should always be 0 at this point because we have compacted this buffer
assert decoderBuffer.rpos() == 0;
/*
* Note: according to RFC-4253 section 6:
*
* Implementations SHOULD decrypt the length after receiving the first 8 (or cipher block size whichever
* is larger) bytes
*
* However, we currently do not have ciphers with a block size of less than 8 we avoid un-necessary
* Math.max(minBufLen, 8) for each and every packet
*/
int minBufLen = etmMode || authMode ? Integer.BYTES : inCipherSize;
// If we have received enough bytes, start processing those
if (decoderBuffer.available() > minBufLen) {
if (authMode) {
// RFC 5647: packet length encoded in additional data
inCipher.updateAAD(decoderBuffer.array(), 0, Integer.BYTES);
} else if ((inCipher != null) && (!etmMode)) {
// Decrypt the first bytes so we can extract the packet length
inCipher.update(decoderBuffer.array(), 0, inCipherSize);
int blocksCount = inCipherSize / inCipher.getCipherBlockSize();
inBlocksCount.addAndGet(Math.max(1, blocksCount));
}
// Read packet length
decoderLength = decoderBuffer.getInt();
/*
* Check packet length validity - we allow 8 times the minimum required packet length support in
* order to be aligned with some OpenSSH versions that allow up to 256k
*/
if ((decoderLength < SshConstants.SSH_PACKET_HEADER_LEN)
|| (decoderLength > (8 * SshConstants.SSH_REQUIRED_PAYLOAD_PACKET_LENGTH_SUPPORT))) {
log.warn("decode({}) Error decoding packet(invalid length): {}", this, decoderLength);
decoderBuffer.dumpHex(getSimplifiedLogger(), Level.FINEST,
"decode(" + this + ") invalid length packet", this);
throw new SshException(
SshConstants.SSH2_DISCONNECT_PROTOCOL_ERROR,
"Invalid packet length: " + decoderLength);
}
// Ok, that's good, we can go to the next step
decoderState = 1;
} else {
// need more data
break;
}
// We have received the beginning of the packet
} else if (decoderState == 1) {
// The read position should always be after reading the packet length at this point
assert decoderBuffer.rpos() == Integer.BYTES;
// Check if the packet has been fully received
if (decoderBuffer.available() >= (decoderLength + macSize + authSize)) {
byte[] data = decoderBuffer.array();
if (authMode) {
inCipher.update(data, Integer.BYTES /* packet length is handled by AAD */, decoderLength);
int blocksCount = decoderLength / inCipherSize;
inBlocksCount.addAndGet(Math.max(1, blocksCount));
} else if (etmMode) {
validateIncomingMac(data, 0, decoderLength + Integer.BYTES);
if (inCipher != null) {
inCipher.update(data, Integer.BYTES /* packet length is unencrypted */, decoderLength);
int blocksCount = decoderLength / inCipherSize;
inBlocksCount.addAndGet(Math.max(1, blocksCount));
}
} else {
/*
* Decrypt the remaining of the packet - skip the block we already decoded in order to extract
* the packet length
*/
if (inCipher != null) {
int updateLen = decoderLength + Integer.BYTES - inCipherSize;
inCipher.update(data, inCipherSize, updateLen);
int blocksCount = updateLen / inCipherSize;
inBlocksCount.addAndGet(Math.max(1, blocksCount));
}
validateIncomingMac(data, 0, decoderLength + Integer.BYTES);
}
// Increment incoming packet sequence number
seqi = (seqi + 1L) & 0x0ffffffffL;
// Get padding
int pad = decoderBuffer.getUByte();
Buffer packet;
int wpos = decoderBuffer.wpos();
// Decompress if needed
if ((inCompression != null)
&& inCompression.isCompressionExecuted()
&& (isAuthenticated() || (!inCompression.isDelayed()))) {
if (uncompressBuffer == null) {
uncompressBuffer = new SessionWorkBuffer(this);
} else {
uncompressBuffer.forceClear(true);
}
decoderBuffer.wpos(decoderBuffer.rpos() + decoderLength - 1 - pad);
inCompression.uncompress(decoderBuffer, uncompressBuffer);
packet = uncompressBuffer;
} else {
decoderBuffer.wpos(decoderLength + Integer.BYTES - pad);
packet = decoderBuffer;
}
if (log.isTraceEnabled()) {
packet.dumpHex(getSimplifiedLogger(), Level.FINEST,
"decode(" + this + ") packet #" + seqi, this);
}
// Update counters used to track re-keying
inPacketsCount.incrementAndGet();
inBytesCount.addAndGet(packet.available());
// Process decoded packet
handleMessage(packet);
// Set ready to handle next packet
decoderBuffer.rpos(decoderLength + Integer.BYTES + macSize + authSize);
decoderBuffer.wpos(wpos);
decoderBuffer.compact();
decoderState = 0;
} else {
// need more data
break;
}
}
}
}
这些不同类型的通道,有什么区别?
@Override
public ClientChannel createChannel(String type, String subType) throws IOException {
if (Channel.CHANNEL_SHELL.equals(type)) {
return createShellChannel();
} else if (Channel.CHANNEL_EXEC.equals(type)) {
return createExecChannel(subType);
} else if (Channel.CHANNEL_SUBSYSTEM.equals(type)) {
return createSubsystemChannel(subType);
} else {
throw new IllegalArgumentException("Unsupported channel type " + type);
}
}
java方面还有其它的ssh库
比如 netconf4j,用的是ganymed-ssh2
还有jsch库
在sshd中,也可以创建netconf子系统,比如
/**
* Netconf Subsystem
*
* @author Julio Carlos Barrera
*/
@Slf4j
public class NetconfSubsystem implements Command, SessionAware {
private ExitCallback callback;
@Getter
private InputStream in;
@Getter
private OutputStream out;
@Getter
private OutputStream err;
private Environment env;
@Getter
private ServerSession session;
private String nfIp;
private NetconfSSHProcessor netconfSSHProcessor;
public NetconfSubsystem() {
}
@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 setSession(ServerSession session) {
this.session = session;
String sessionString = session.getIoSession().getLocalAddress().toString();
String remoteSessionInfo = session.getIoSession().getRemoteAddress().toString();
log.info("session is: {}", session.toString());
this.nfIp = NetconfServer.getIpFromAddress(sessionString + remoteSessionInfo);
}
@Override
public void start(Environment env) {
this.env = env;
netconfSSHProcessor = new NetconfSSHProcessor(session, in, out, callback);
netconfSSHProcessor.startNetconfMessageProcessor();
netconfSSHProcessor.startNetconfMessageReader();
MessageExecutors.connectExec.schedule(new HelloTimeOutTask(netconfSSHProcessor), 30, TimeUnit.SECONDS);
}
@Override
public void destroy() {
netconfSSHProcessor.sessionClosed();
}
/**
* Netconf Subsystem Factory
*
* @author Julio Carlos Barrera
*/
public static class Factory implements NamedFactory<Command> {
private Factory() {
}
public static Factory createFactory() {
return new Factory();
}
@Override
public Command create() {
return new NetconfSubsystem();
}
@Override
public String getName() {
return "netconf";
}
}
}
private static void initDefaultValues() {
instance.setKeyExchangeFactories(Arrays.asList(
DHGServer.newFactory(BuiltinDHFactories.ecdhp521)
, DHGServer.newFactory(BuiltinDHFactories.ecdhp384)
, DHGServer.newFactory(BuiltinDHFactories.ecdhp256)
, DHGServer.newFactory(BuiltinDHFactories.dhgex256)));
instance.setSignatureFactories(BaseBuilder.setUpDefaultSignatures(false));
instance.setRandomFactory(new SingletonRandomFactory(SecurityUtils.getRandomFactory()));
instance.setCipherFactories(BaseBuilder.setUpDefaultCiphers(false));
instance.setCompressionFactories(NamedFactory.setUpBuiltinFactories(false, DEFAULT_COMPRESSION_FACTORIES));
instance.setMacFactories(BaseBuilder.setUpDefaultMacs(false));
instance.setChannelFactories(DEFAULT_CHANNEL_FACTORIES);
instance.setFileSystemFactory(BaseBuilder.DEFAULT_FILE_SYSTEM_FACTORY);
instance.setForwardingFilter(BaseBuilder.DEFAULT_FORWARDING_FILTER);
instance.setForwarderFactory(BaseBuilder.DEFAULT_FORWARDER_FACTORY);
instance.setGlobalRequestHandlers(ServerBuilder.DEFAULT_GLOBAL_REQUEST_HANDLERS);
instance.setUnknownChannelReferenceHandler(BaseBuilder.DEFAULT_UNKNOWN_CHANNEL_REFERENCE_HANDLER);
instance.setPublickeyAuthenticator(ServerBuilder.DEFAULT_PUBLIC_KEY_AUTHENTICATOR);
instance.setKeyboardInteractiveAuthenticator(ServerBuilder.DEFAULT_INTERACTIVE_AUTHENTICATOR);
}
private static void initConfiguredValues() {
log.info("Configuring server...");
PropertyResolverUtils.updateProperty(instance, "idle-timeout", 300000);
PropertyResolverUtils.updateProperty(instance, ServerAuthenticationManager.MAX_AUTH_REQUESTS, 1000);
setAuthTimeout();
PropertyResolverUtils.updateProperty(instance, "auth-timeout", authTimeout);
instance.setPasswordAuthenticator(new SimulatorSshPasswordAuthenticator());
instance.setPublickeyAuthenticator(AcceptAllPublickeyAuthenticator.INSTANCE);
instance.setGSSAuthenticator(new GSSAuthenticator());
AbstractGeneratorHostKeyProvider hostKeyProvider = new SimpleGeneratorHostKeyProvider(new File("key.ser"));
hostKeyProvider.setAlgorithm("EC");
instance.setKeyPairProvider(hostKeyProvider);
List<NamedFactory<Command>> subsystemFactories = new ArrayList<>();
subsystemFactories.add(NetconfSubsystem.Factory.createFactory());
instance.setSubsystemFactories(subsystemFactories);
log.info("Server configured.");
}
Linux ssh命令详解
使用2222端口登陆 ssh -p2222 root@127.0.0.1
ssh原理
SSH与SSL比较
相同点
如果按五层协议来划分的话,那SSH与SSL都可以算是应用层协议,他们都使用了非对称加密,将应用层进行了加密,另外,他们其实都是比较基础的应用层协议,即它们上面还可以再放其它应用层协议,如FTP协议等
不同点
SSH不需要证书,即不需要公证机构(从这点来说,SSH的安全性要比SSH弱一些,貌似SSH无法解决中间人攻击),SSH实现了主机用户名和密码的认证,这是SSH的SSH-TRANS部分完成的,而SSL没有这个功能。
适用场景
SSL一般用于私有访问,它提供了主机用户名和密码的验证功能,当然用户也可以通过在服务端保存自己的公钥来让服务端验证你,Github等就是通过这种方式;而对于Web等这种提供公共服务的访问呢?这种情况下,我并不想让用户登录主机的,这种情况下,也要求保证数据传输的安全,这时我们用SSL/TLS,我们会在自己设计的应用层(即应用程序)中验证用户的身份。
更通俗的说,SSH可以让用户以某个主机用户的身份登录主机,并对主机执行操作(即执行一些命令),目前用的最多的就是远程登录和SFTP(还有简易版的SCP);而SSL和主机用户名登录没有任何关系,它本身并不实现主机登录的功能,它只的一个单纯的加密功能。为了方便理解,可以简单的认为SSH=SSL+主机用户登录功能等应用层协议.
更多推荐
所有评论(0)