Add support for RFC2385 on Linux
Motivation: There are protocols (BGP, SXP), which are typically deployed with TCP MD5 authentication to protect sessions from being hijacked/torn down by third parties. This facility is not available on most operating systems, but is typically present on Linux. Modifications: - add a new EpollChannelOption, which is write-only - teach Epoll(Server)SocketChannel to track which addresses have keys associated - teach Native how to set the MD5 signature keys for a socket Result: Users of the native-epoll transport can set MD5 signature keys and thus leverage RFC-2385 protection on TCP connections.
This commit is contained in:
parent
34de2667c7
commit
30a7701616
@ -1736,3 +1736,51 @@ JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_splice0(JNIEnv* env, j
|
||||
JNIEXPORT jlong JNICALL Java_io_netty_channel_epoll_Native_ssizeMax(JNIEnv* env, jclass clazz) {
|
||||
return SSIZE_MAX;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_tcpMd5SigMaxKeyLen(JNIEnv* env, jclass clazz) {
|
||||
struct tcp_md5sig md5sig;
|
||||
|
||||
// Defensive size check
|
||||
if (sizeof(md5sig.tcpm_key) < TCP_MD5SIG_MAXKEYLEN) {
|
||||
return sizeof(md5sig.tcpm_key);
|
||||
}
|
||||
|
||||
return TCP_MD5SIG_MAXKEYLEN;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_io_netty_channel_epoll_Native_setTcpMd5Sig0(JNIEnv* env, jclass clazz, jint fd, jbyteArray address, jint scopeId, jbyteArray key) {
|
||||
struct sockaddr_storage addr;
|
||||
if (init_sockaddr(env, address, scopeId, 0, &addr) == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct tcp_md5sig md5sig;
|
||||
memset(&md5sig, 0, sizeof(md5sig));
|
||||
md5sig.tcpm_addr.ss_family = addr.ss_family;
|
||||
|
||||
struct sockaddr_in* ipaddr;
|
||||
struct sockaddr_in6* ip6addr;
|
||||
|
||||
switch (addr.ss_family) {
|
||||
case AF_INET:
|
||||
ipaddr = (struct sockaddr_in*) &addr;
|
||||
memcpy(&((struct sockaddr_in *) &md5sig.tcpm_addr)->sin_addr, &ipaddr->sin_addr, sizeof(ipaddr->sin_addr));
|
||||
break;
|
||||
case AF_INET6:
|
||||
ip6addr = (struct sockaddr_in6*) &addr;
|
||||
memcpy(&((struct sockaddr_in6 *) &md5sig.tcpm_addr)->sin6_addr, &ip6addr->sin6_addr, sizeof(ip6addr->sin6_addr));
|
||||
break;
|
||||
}
|
||||
|
||||
if (key != NULL) {
|
||||
md5sig.tcpm_keylen = (*env)->GetArrayLength(env, key);
|
||||
(*env)->GetByteArrayRegion(env, key, 0, md5sig.tcpm_keylen, (void *) &md5sig.tcpm_key);
|
||||
if ((*env)->ExceptionCheck(env) == JNI_TRUE) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_MD5SIG, &md5sig, sizeof(md5sig)) < 0) {
|
||||
throwChannelExceptionErrorNo(env, "setsockopt() failed: ", errno);
|
||||
}
|
||||
}
|
||||
|
@ -129,3 +129,6 @@ jint Java_io_netty_channel_epoll_Native_offsetofEpollData(JNIEnv* env, jclass cl
|
||||
|
||||
jlong Java_io_netty_channel_epoll_Native_pipe0(JNIEnv* env, jclass clazz);
|
||||
jint Java_io_netty_channel_epoll_Native_splice0(JNIEnv* env, jclass clazz, jint fd, jint offIn, jint fdOut, jint offOut, jint len);
|
||||
|
||||
jint Java_io_netty_channel_epoll_Native_tcpMd5SigMaxKeyLen(JNIEnv* env, jclass clazz);
|
||||
void Java_io_netty_channel_epoll_Native_setTcpMd5Sig0(JNIEnv* env, jclass clazz, jint fd, jbyteArray address, jint scopeId, jbyteArray key);
|
||||
|
@ -18,6 +18,9 @@ package io.netty.channel.epoll;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.unix.DomainSocketReadMode;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.Map;
|
||||
|
||||
public final class EpollChannelOption<T> extends ChannelOption<T> {
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static final Class<EpollChannelOption> T = EpollChannelOption.class;
|
||||
@ -36,6 +39,8 @@ public final class EpollChannelOption<T> extends ChannelOption<T> {
|
||||
public static final ChannelOption<EpollMode> EPOLL_MODE =
|
||||
ChannelOption.valueOf(T, "EPOLL_MODE");
|
||||
|
||||
public static final ChannelOption<Map<InetAddress, byte[]>> TCP_MD5SIG = valueOf("TCP_MD5SIG");
|
||||
|
||||
@SuppressWarnings({ "unused", "deprecation" })
|
||||
private EpollChannelOption() {
|
||||
super(null);
|
||||
|
@ -21,11 +21,13 @@ import io.netty.channel.MessageSizeEstimator;
|
||||
import io.netty.channel.RecvByteBufAllocator;
|
||||
import io.netty.util.NetUtil;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.Map;
|
||||
|
||||
import static io.netty.channel.ChannelOption.SO_BACKLOG;
|
||||
import static io.netty.channel.ChannelOption.SO_RCVBUF;
|
||||
import static io.netty.channel.ChannelOption.SO_REUSEADDR;
|
||||
import static io.netty.channel.epoll.EpollChannelOption.TCP_MD5SIG;;
|
||||
|
||||
public class EpollServerChannelConfig extends EpollChannelConfig {
|
||||
protected final AbstractEpollChannel channel;
|
||||
@ -66,6 +68,10 @@ public class EpollServerChannelConfig extends EpollChannelConfig {
|
||||
setReuseAddress((Boolean) value);
|
||||
} else if (option == SO_BACKLOG) {
|
||||
setBacklog((Integer) value);
|
||||
} else if (option == TCP_MD5SIG) {
|
||||
@SuppressWarnings("unchecked")
|
||||
final Map<InetAddress, byte[]> m = (Map<InetAddress, byte[]>) value;
|
||||
((EpollServerSocketChannel) channel).setTcpMd5Sig(m);
|
||||
} else {
|
||||
return super.setOption(option, value);
|
||||
}
|
||||
|
@ -20,8 +20,12 @@ import io.netty.channel.EventLoop;
|
||||
import io.netty.channel.socket.ServerSocketChannel;
|
||||
import io.netty.channel.unix.FileDescriptor;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* {@link ServerSocketChannel} implementation that uses linux EPOLL Edge-Triggered Mode for
|
||||
@ -31,6 +35,7 @@ public final class EpollServerSocketChannel extends AbstractEpollServerChannel i
|
||||
|
||||
private final EpollServerSocketChannelConfig config;
|
||||
private volatile InetSocketAddress local;
|
||||
private volatile Collection<InetAddress> tcpMd5SigAddresses = Collections.emptyList();
|
||||
|
||||
public EpollServerSocketChannel() {
|
||||
super(Native.socketStreamFd());
|
||||
@ -89,4 +94,12 @@ public final class EpollServerSocketChannel extends AbstractEpollServerChannel i
|
||||
protected Channel newChildChannel(int fd, byte[] address, int offset, int len) throws Exception {
|
||||
return new EpollSocketChannel(this, fd, Native.address(address, offset, len));
|
||||
}
|
||||
|
||||
Collection<InetAddress> tcpMd5SigAddresses() {
|
||||
return tcpMd5SigAddresses;
|
||||
}
|
||||
|
||||
void setTcpMd5Sig(Map<InetAddress, byte[]> keys) {
|
||||
this.tcpMd5SigAddresses = TcpMd5Util.newTcpMd5Sigs(this, tcpMd5SigAddresses, keys);
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ import io.netty.channel.MessageSizeEstimator;
|
||||
import io.netty.channel.RecvByteBufAllocator;
|
||||
import io.netty.channel.socket.ServerSocketChannelConfig;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.Map;
|
||||
|
||||
public final class EpollServerSocketChannelConfig extends EpollServerChannelConfig
|
||||
@ -60,6 +61,10 @@ public final class EpollServerSocketChannelConfig extends EpollServerChannelConf
|
||||
setReusePort((Boolean) value);
|
||||
} else if (option == EpollChannelOption.IP_FREEBIND) {
|
||||
setFreeBind((Boolean) value);
|
||||
} else if (option == EpollChannelOption.TCP_MD5SIG) {
|
||||
@SuppressWarnings("unchecked")
|
||||
final Map<InetAddress, byte[]> m = (Map<InetAddress, byte[]>) value;
|
||||
setTcpMd5Sig(m);
|
||||
} else {
|
||||
return super.setOption(option, value);
|
||||
}
|
||||
@ -145,6 +150,16 @@ public final class EpollServerSocketChannelConfig extends EpollServerChannelConf
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@code TCP_MD5SIG} option on the socket. See {@code linux/tcp.h} for more details.
|
||||
* Keys can only be set on, not read to prevent a potential leak, as they are confidential.
|
||||
* Allowing them being read would mean anyone with access to the channel could get them.
|
||||
*/
|
||||
public EpollServerSocketChannelConfig setTcpMd5Sig(Map<InetAddress, byte[]> keys) {
|
||||
((EpollServerSocketChannel) channel).setTcpMd5Sig(keys);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the SO_REUSEPORT option is set.
|
||||
*/
|
||||
|
@ -25,8 +25,12 @@ import io.netty.channel.unix.FileDescriptor;
|
||||
import io.netty.util.concurrent.GlobalEventExecutor;
|
||||
import io.netty.util.internal.OneTimeTask;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
@ -39,6 +43,7 @@ public final class EpollSocketChannel extends AbstractEpollStreamChannel impleme
|
||||
|
||||
private volatile InetSocketAddress local;
|
||||
private volatile InetSocketAddress remote;
|
||||
private volatile Collection<InetAddress> tcpMd5SigAddresses = Collections.emptyList();
|
||||
|
||||
EpollSocketChannel(Channel parent, int fd, InetSocketAddress remote) {
|
||||
super(parent, fd);
|
||||
@ -47,6 +52,10 @@ public final class EpollSocketChannel extends AbstractEpollStreamChannel impleme
|
||||
// See https://github.com/netty/netty/issues/2359
|
||||
this.remote = remote;
|
||||
local = Native.localAddress(fd);
|
||||
|
||||
if (parent instanceof EpollServerSocketChannel) {
|
||||
tcpMd5SigAddresses = ((EpollServerSocketChannel) parent).tcpMd5SigAddresses();
|
||||
}
|
||||
}
|
||||
|
||||
public EpollSocketChannel() {
|
||||
@ -205,4 +214,8 @@ public final class EpollSocketChannel extends AbstractEpollStreamChannel impleme
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
void setTcpMd5Sig(Map<InetAddress, byte[]> keys) {
|
||||
this.tcpMd5SigAddresses = TcpMd5Util.newTcpMd5Sigs(this, tcpMd5SigAddresses, keys);
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import io.netty.channel.RecvByteBufAllocator;
|
||||
import io.netty.channel.socket.SocketChannelConfig;
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.Map;
|
||||
|
||||
import static io.netty.channel.ChannelOption.*;
|
||||
@ -49,7 +50,8 @@ public final class EpollSocketChannelConfig extends EpollChannelConfig implement
|
||||
super.getOptions(),
|
||||
SO_RCVBUF, SO_SNDBUF, TCP_NODELAY, SO_KEEPALIVE, SO_REUSEADDR, SO_LINGER, IP_TOS,
|
||||
ALLOW_HALF_CLOSURE, EpollChannelOption.TCP_CORK, EpollChannelOption.TCP_NOTSENT_LOWAT,
|
||||
EpollChannelOption.TCP_KEEPCNT, EpollChannelOption.TCP_KEEPIDLE, EpollChannelOption.TCP_KEEPINTVL);
|
||||
EpollChannelOption.TCP_KEEPCNT, EpollChannelOption.TCP_KEEPIDLE, EpollChannelOption.TCP_KEEPINTVL,
|
||||
EpollChannelOption.TCP_MD5SIG);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@ -132,6 +134,10 @@ public final class EpollSocketChannelConfig extends EpollChannelConfig implement
|
||||
setTcpKeepIntvl((Integer) value);
|
||||
} else if (option == EpollChannelOption.TCP_USER_TIMEOUT) {
|
||||
setTcpUserTimeout((Integer) value);
|
||||
} else if (option == EpollChannelOption.TCP_MD5SIG) {
|
||||
@SuppressWarnings("unchecked")
|
||||
final Map<InetAddress, byte[]> m = (Map<InetAddress, byte[]>) value;
|
||||
setTcpMd5Sig(m);
|
||||
} else {
|
||||
return super.setOption(option, value);
|
||||
}
|
||||
@ -317,6 +323,16 @@ public final class EpollSocketChannelConfig extends EpollChannelConfig implement
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the {@code TCP_MD5SIG} option on the socket. See {@code linux/tcp.h} for more details.
|
||||
* Keys can only be set on, not read to prevent a potential leak, as they are confidential.
|
||||
* Allowing them being read would mean anyone with access to the channel could get them.
|
||||
*/
|
||||
public EpollSocketChannelConfig setTcpMd5Sig(Map<InetAddress, byte[]> keys) {
|
||||
channel.setTcpMd5Sig(keys);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowHalfClosure() {
|
||||
return allowHalfClosure;
|
||||
|
@ -62,6 +62,8 @@ public final class Native {
|
||||
public static final int UIO_MAX_IOV = uioMaxIov();
|
||||
public static final boolean IS_SUPPORTING_SENDMMSG = isSupportingSendmmsg();
|
||||
public static final long SSIZE_MAX = ssizeMax();
|
||||
public static final int TCP_MD5SIG_MAXKEYLEN = tcpMd5SigMaxKeyLen();
|
||||
|
||||
private static final byte[] IPV4_MAPPED_IPV6_PREFIX = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0xff, (byte) 0xff };
|
||||
|
||||
@ -661,6 +663,13 @@ public final class Native {
|
||||
|
||||
private static native void tcpInfo0(int fd, int[] array);
|
||||
|
||||
public static void setTcpMd5Sig(int fd, InetAddress address, byte[] key) {
|
||||
final NativeInetAddress a = toNativeInetAddress(address);
|
||||
setTcpMd5Sig0(fd, a.address, a.scopeId, key);
|
||||
}
|
||||
|
||||
private static native void setTcpMd5Sig0(int fd, byte[] address, int scopeId, byte[] key);
|
||||
|
||||
private static NativeInetAddress toNativeInetAddress(InetAddress addr) {
|
||||
byte[] bytes = addr.getAddress();
|
||||
if (addr instanceof Inet6Address) {
|
||||
@ -709,6 +718,8 @@ public final class Native {
|
||||
private static native int epollerr();
|
||||
|
||||
private static native long ssizeMax();
|
||||
private static native int tcpMd5SigMaxKeyLen();
|
||||
|
||||
private Native() {
|
||||
// utility
|
||||
}
|
||||
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2015 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.channel.epoll;
|
||||
|
||||
import io.netty.util.internal.ObjectUtil;
|
||||
import java.net.InetAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
final class TcpMd5Util {
|
||||
|
||||
static Collection<InetAddress> newTcpMd5Sigs(AbstractEpollChannel channel, Collection<InetAddress> current,
|
||||
Map<InetAddress, byte[]> newKeys) {
|
||||
ObjectUtil.checkNotNull(channel, "channel");
|
||||
ObjectUtil.checkNotNull(current, "current");
|
||||
ObjectUtil.checkNotNull(newKeys, "newKeys");
|
||||
|
||||
// Validate incoming values
|
||||
for (Entry<InetAddress, byte[]> e : newKeys.entrySet()) {
|
||||
final byte[] key = e.getValue();
|
||||
if (e.getKey() == null) {
|
||||
throw new IllegalArgumentException("newKeys contains an entry with null address: " + newKeys);
|
||||
}
|
||||
if (key == null) {
|
||||
throw new NullPointerException("newKeys[" + e.getKey() + ']');
|
||||
}
|
||||
if (key.length == 0) {
|
||||
throw new IllegalArgumentException("newKeys[" + e.getKey() + "] has an empty key.");
|
||||
}
|
||||
if (key.length > Native.TCP_MD5SIG_MAXKEYLEN) {
|
||||
throw new IllegalArgumentException("newKeys[" + e.getKey() +
|
||||
"] has a key with invalid length; should not exceed the maximum length (" +
|
||||
Native.TCP_MD5SIG_MAXKEYLEN + ')');
|
||||
}
|
||||
}
|
||||
|
||||
// Remove mappings not present in the new set.
|
||||
for (InetAddress addr : current) {
|
||||
if (!newKeys.containsKey(addr)) {
|
||||
Native.setTcpMd5Sig(channel.fd().intValue(), addr, null);
|
||||
}
|
||||
}
|
||||
|
||||
if (newKeys.isEmpty()) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
// Set new mappings and store addresses which we set.
|
||||
final Collection<InetAddress> addresses = new ArrayList<InetAddress>(newKeys.size());
|
||||
for (Entry<InetAddress, byte[]> e : newKeys.entrySet()) {
|
||||
Native.setTcpMd5Sig(channel.fd().intValue(), e.getKey(), e.getValue());
|
||||
addresses.add(e.getKey());
|
||||
}
|
||||
|
||||
return addresses;
|
||||
}
|
||||
|
||||
private TcpMd5Util() {
|
||||
}
|
||||
}
|
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright 2015 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.channel.epoll;
|
||||
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.channel.ConnectTimeoutException;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
public class EpollSocketTcpMd5Test {
|
||||
private static final byte[] SERVER_KEY = "abc".getBytes(CharsetUtil.US_ASCII);
|
||||
private static final byte[] BAD_KEY = "def".getBytes(CharsetUtil.US_ASCII);
|
||||
private static EventLoopGroup GROUP;
|
||||
private EpollServerSocketChannel server;
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
GROUP = new EpollEventLoopGroup(1);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() {
|
||||
GROUP.shutdownGracefully();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
Bootstrap bootstrap = new Bootstrap();
|
||||
server = (EpollServerSocketChannel) bootstrap.group(GROUP)
|
||||
.channel(EpollServerSocketChannel.class)
|
||||
.handler(new ChannelInboundHandlerAdapter())
|
||||
.bind(new InetSocketAddress(0)).syncUninterruptibly().channel();
|
||||
}
|
||||
|
||||
@After
|
||||
public void teardown() {
|
||||
server.close().syncUninterruptibly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerSocketChannelOption() throws Exception {
|
||||
server.config().setOption(EpollChannelOption.TCP_MD5SIG, Collections.singletonMap(InetAddress.getLocalHost(),
|
||||
SERVER_KEY));
|
||||
server.config().setOption(EpollChannelOption.TCP_MD5SIG, Collections.<InetAddress, byte[]>emptyMap());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerOption() throws Exception {
|
||||
Bootstrap bootstrap = new Bootstrap();
|
||||
EpollServerSocketChannel ch = (EpollServerSocketChannel) bootstrap.group(GROUP)
|
||||
.channel(EpollServerSocketChannel.class)
|
||||
.handler(new ChannelInboundHandlerAdapter())
|
||||
.bind(new InetSocketAddress(0)).syncUninterruptibly().channel();
|
||||
|
||||
ch.config().setOption(EpollChannelOption.TCP_MD5SIG, Collections.singletonMap(InetAddress.getLocalHost(),
|
||||
SERVER_KEY));
|
||||
ch.config().setOption(EpollChannelOption.TCP_MD5SIG, Collections.<InetAddress, byte[]>emptyMap());
|
||||
|
||||
ch.close().syncUninterruptibly();
|
||||
}
|
||||
|
||||
@Test(expected = ConnectTimeoutException.class)
|
||||
public void testKeyMismatch() throws Exception {
|
||||
server.config().setOption(EpollChannelOption.TCP_MD5SIG, Collections.singletonMap(InetAddress.getLocalHost(),
|
||||
SERVER_KEY));
|
||||
|
||||
EpollSocketChannel client = (EpollSocketChannel) new Bootstrap().group(GROUP)
|
||||
.channel(EpollSocketChannel.class)
|
||||
.handler(new ChannelInboundHandlerAdapter())
|
||||
.option(EpollChannelOption.TCP_MD5SIG,
|
||||
Collections.singletonMap(InetAddress.getLocalHost(), BAD_KEY))
|
||||
.connect(server.localAddress()).syncUninterruptibly().channel();
|
||||
client.close().syncUninterruptibly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testKeyMatch() throws Exception {
|
||||
server.config().setOption(EpollChannelOption.TCP_MD5SIG, Collections.singletonMap(InetAddress.getLocalHost(),
|
||||
SERVER_KEY));
|
||||
|
||||
EpollSocketChannel client = (EpollSocketChannel) new Bootstrap().group(GROUP)
|
||||
.channel(EpollSocketChannel.class)
|
||||
.handler(new ChannelInboundHandlerAdapter())
|
||||
.option(EpollChannelOption.TCP_MD5SIG,
|
||||
Collections.singletonMap(InetAddress.getLocalHost(), SERVER_KEY))
|
||||
.connect(server.localAddress()).syncUninterruptibly().channel();
|
||||
client.close().syncUninterruptibly();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user