netconf ssh

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协议详解_梦想专栏-CSDN博客_ssh协议

ssh协议的原理,你有可能还不知道

ssh协议的原理,你有可能还不知道_somezz的专栏-CSDN博客

使用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服务与优化_vic的博客-CSDN博客_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
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值