2 * Copyright (c) 2016 Inocybe Technologies and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.netconf.ssh;
10 import io.netty.channel.ChannelFuture;
11 import io.netty.channel.EventLoopGroup;
12 import io.netty.channel.local.LocalAddress;
13 import io.netty.util.concurrent.EventExecutor;
14 import java.io.IOException;
15 import java.net.InetSocketAddress;
16 import java.util.concurrent.Executors;
17 import org.opendaylight.netconf.auth.AuthProvider;
18 import org.opendaylight.netconf.server.api.NetconfServerDispatcher;
19 import org.opendaylight.netconf.shaded.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
20 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil;
21 import org.osgi.service.component.annotations.Activate;
22 import org.osgi.service.component.annotations.Component;
23 import org.osgi.service.component.annotations.Deactivate;
24 import org.osgi.service.component.annotations.Reference;
25 import org.osgi.service.metatype.annotations.AttributeDefinition;
26 import org.osgi.service.metatype.annotations.Designate;
27 import org.osgi.service.metatype.annotations.ObjectClassDefinition;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
32 * NETCONF server for MD-SAL (listening by default on port 2830).
34 @Component(service = { }, configurationPid = "org.opendaylight.netconf.ssh")
35 @Designate(ocd = NetconfNorthboundSshServer.Configuration.class)
36 public final class NetconfNorthboundSshServer implements AutoCloseable {
37 @ObjectClassDefinition
38 public @interface Configuration {
40 String bindingAddress() default "0.0.0.0";
41 @AttributeDefinition(min = "1", max = "65535")
42 int portNumber() default 2830;
45 private static final Logger LOG = LoggerFactory.getLogger(NetconfNorthboundSshServer.class);
47 private final ChannelFuture localServer;
48 private final SshProxyServer sshProxyServer;
51 public NetconfNorthboundSshServer(
52 @Reference final NetconfServerDispatcher netconfServerDispatcher,
53 @Reference(target = "(type=global-worker-group)") final EventLoopGroup workerGroup,
54 @Reference(target = "(type=global-event-executor)") final EventExecutor eventExecutor,
55 @Reference(target = "(type=netconf-auth-provider)") final AuthProvider authProvider,
56 final Configuration configuration) {
57 this(netconfServerDispatcher, workerGroup, eventExecutor, authProvider, configuration.bindingAddress(),
58 configuration.portNumber());
61 public NetconfNorthboundSshServer(final NetconfServerDispatcher netconfServerDispatcher,
62 final EventLoopGroup workerGroup, final EventExecutor eventExecutor, final AuthProvider authProvider,
63 final String bindingAddress, final int portNumber) {
64 final LocalAddress localAddress = new LocalAddress(String.valueOf(portNumber));
65 final var sshProxyServerConfiguration = new SshProxyServerConfigurationBuilder()
66 .setBindingAddress(getInetAddress(bindingAddress, portNumber))
67 .setLocalAddress(localAddress)
68 .setAuthenticator(authProvider)
69 .setIdleTimeout(Integer.MAX_VALUE)
70 .setKeyPairProvider(new SimpleGeneratorHostKeyProvider())
71 .createSshProxyServerConfiguration();
73 localServer = netconfServerDispatcher.createLocalServer(localAddress);
74 sshProxyServer = new SshProxyServer(Executors.newScheduledThreadPool(1), workerGroup, eventExecutor);
76 localServer.addListener(future -> {
77 if (future.isDone() && !future.isCancelled()) {
79 sshProxyServer.bind(sshProxyServerConfiguration);
80 } catch (final IOException e) {
81 throw new IllegalStateException("Unable to start SSH netconf server", e);
83 LOG.info("Netconf SSH endpoint started successfully at {}", bindingAddress);
85 LOG.warn("Unable to start SSH netconf server at {}", bindingAddress, future.cause());
86 throw new IllegalStateException("Unable to start SSH netconf server", future.cause());
93 public void close() throws IOException {
94 sshProxyServer.close();
96 if (localServer.isDone()) {
97 localServer.channel().close();
99 localServer.cancel(true);
103 private static InetSocketAddress getInetAddress(final String bindingAddress, final int portNumber) {
104 final var ipAddress = IetfInetUtil.ipAddressFor(bindingAddress);
105 return new InetSocketAddress(IetfInetUtil.INSTANCE.inetAddressFor(ipAddress), portNumber);