forked from KNEMC/KLALB
1003 lines
32 KiB
Java
1003 lines
32 KiB
Java
package org.kne.cloud.network.klalb;
|
|
|
|
import java.io.IOException;
|
|
import java.net.BindException;
|
|
import java.net.Inet4Address;
|
|
import java.net.Inet6Address;
|
|
import java.net.InetAddress;
|
|
import java.net.InetSocketAddress;
|
|
import java.net.NetworkInterface;
|
|
import java.net.SocketException;
|
|
import java.net.SocketTimeoutException;
|
|
import java.net.UnknownHostException;
|
|
import java.util.ArrayList;
|
|
import java.util.Enumeration;
|
|
import java.util.HashSet;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
import java.util.Timer;
|
|
import java.util.TimerTask;
|
|
import java.util.UUID;
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
import java.util.concurrent.CopyOnWriteArrayList;
|
|
import java.util.concurrent.Executors;
|
|
import java.util.concurrent.ScheduledExecutorService;
|
|
import java.util.concurrent.ThreadFactory;
|
|
import java.util.concurrent.locks.Lock;
|
|
import java.util.concurrent.locks.ReadWriteLock;
|
|
import java.util.concurrent.locks.ReentrantLock;
|
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
|
import java.util.function.Consumer;
|
|
|
|
import org.kne.cloud.clock.HighAccuracyClock;
|
|
import org.kne.cloud.network.IPMulticastDiscovery;
|
|
import org.kne.cloud.network.MultiProtocolSocketAddress;
|
|
import org.kne.cloud.network.PortPair;
|
|
import org.kne.cloud.network.SocketType;
|
|
import org.kne.cloud.network.ThreadTool;
|
|
import org.kne.cloud.network.ipv6.IPv6Address;
|
|
import org.kne.cloud.network.ipv6.IPv6AddressGroup;
|
|
import org.kne.cloud.network.ipv6.IPv6NetworkLink;
|
|
import org.kne.cloud.network.ipv6.IPv6Packet;
|
|
import org.kne.cloud.network.ipv6.IPv6TUNLoopbackNetworkLink;
|
|
import org.kne.cloud.network.ipv6.Neighbor;
|
|
import org.kne.cloud.network.kltp.KLTPPacket;
|
|
import org.kne.cloud.network.kltp.KLTPProtocolRegister;
|
|
import org.kne.cloud.network.monitor.HashMapTimestampMonitor;
|
|
import org.kne.cloud.network.monitor.SpeedAndTrafficMonitorDataImpl;
|
|
import org.kne.cloud.network.ntp.NTPContext;
|
|
import org.kne.cloud.network.ntp.NTPv4Packet;
|
|
import org.kne.cloud.network.ntp.NTPv4Protocol;
|
|
import org.kne.cloud.network.ntp.NTPv4Protocol.NTPPeer;
|
|
import org.kne.cloud.network.srv6.KLALBRoutingProtocol;
|
|
import org.kne.cloud.network.srv6.KLALBRoutingProtocolAPIClient;
|
|
import org.kne.cloud.network.srv6.KLALBRoutingProtocolAPIServer;
|
|
import org.kne.cloud.network.srv6.SRv6Router;
|
|
import org.kne.cloud.network.srv6.SRv6RouterListener;
|
|
import org.kne.cloud.network.tcp.UDPPacket;
|
|
import org.kne.cloud.network.tcp.UDPProtocolRegister;
|
|
import org.kne.cloud.network.te.BandwidthDistributer;
|
|
|
|
public class KLALBController {
|
|
private UUID nodeuuid=UUID.randomUUID();
|
|
private HighAccuracyClock clock = new HighAccuracyClock();
|
|
|
|
public HighAccuracyClock getClock() {
|
|
return clock;
|
|
}
|
|
private final long TIME_WINDOW=2000000000L;
|
|
private SpeedAndTrafficMonitorDataImpl linkMonitor = new SpeedAndTrafficMonitorDataImpl(
|
|
new HashMapTimestampMonitor<UUID>(HighAccuracyClock.SYSTEM_CLOCK, "up", 100,TIME_WINDOW ),
|
|
new HashMapTimestampMonitor<UUID>(HighAccuracyClock.SYSTEM_CLOCK, "down", 100, TIME_WINDOW));
|
|
|
|
private SpeedAndTrafficMonitorDataImpl datatMonitor = new SpeedAndTrafficMonitorDataImpl(
|
|
new HashMapTimestampMonitor<UUID>(HighAccuracyClock.SYSTEM_CLOCK, "up", 100, TIME_WINDOW),
|
|
new HashMapTimestampMonitor<UUID>(HighAccuracyClock.SYSTEM_CLOCK, "down", 100, TIME_WINDOW));
|
|
|
|
private List<MultiProtocolSocketAddress> externalEndpoints = new ArrayList<>();
|
|
|
|
private List<MultiProtocolSocketAddress> listensSocketAddress = new CopyOnWriteArrayList<>();
|
|
|
|
public List<MultiProtocolSocketAddress> getListenSocketAddress() {
|
|
return listensSocketAddress;
|
|
}
|
|
private static final boolean debug=false;
|
|
private static final boolean showpacket = false;
|
|
|
|
private static final int PREFIX = 128;
|
|
private static final int DISCOVERY_PORT = 4569;
|
|
|
|
private static List<IPMulticastDiscovery> ipmd = new ArrayList<>();
|
|
|
|
private NetworkInterfaceManager networkInterfaceManager=new NetworkInterfaceManager();
|
|
public NetworkInterfaceManager getNetworkInterfaceManager() {
|
|
return networkInterfaceManager;
|
|
}
|
|
public List<NetworkInterface> getNetworkInterfaceExcept() {
|
|
return networkInterfaceManager.getNetworkInterfaceExcept();
|
|
}
|
|
|
|
private List<InetAddress> dnsAddresses = new ArrayList<>();
|
|
|
|
public List<InetAddress> getDnsAddresses() {
|
|
return dnsAddresses;
|
|
}
|
|
private ScheduledExecutorService scheduleTimer=Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors(),new ThreadFactory() {
|
|
|
|
@Override
|
|
public Thread newThread(Runnable r) {
|
|
return ThreadTool.makeVDaemonThreadIfSupport("计时器线程", r);
|
|
}
|
|
});
|
|
|
|
public ScheduledExecutorService getScheduleTimer() {
|
|
return scheduleTimer;
|
|
}
|
|
|
|
private Timer twk = new Timer("网卡检测扫描计时器", true);
|
|
|
|
|
|
|
|
private TimerTask tsk1 = new TimerTask() {
|
|
|
|
@Override
|
|
public void run() {
|
|
try {
|
|
List<InetAddress> localaddress = networkInterfaceManager.getAllNetworkInterfaceAddress();
|
|
|
|
for (InetAddress inetAddress : localaddress) {
|
|
for (Iterator<MultiProtocolSocketAddress> iterator = listensSocketAddress.iterator(); iterator.hasNext();) {
|
|
MultiProtocolSocketAddress tcpl = (MultiProtocolSocketAddress) iterator.next();
|
|
|
|
try {
|
|
if (tcpl.getInetAddress().isAnyLocalAddress()
|
|
|| tcpl.getInetAddress().equals(inetAddress)) {
|
|
MultiProtocolSocketAddress bind = new MultiProtocolSocketAddress(tcpl.getProtocol(),
|
|
inetAddress.getHostAddress(), tcpl.getPort());
|
|
// System.out.println(bind);
|
|
synchronized (externalEndpoints) {
|
|
if (!externalEndpoints.contains(bind)) {
|
|
externalEndpoints.add(bind);
|
|
}
|
|
}
|
|
}
|
|
} catch (UnknownHostException e) {
|
|
// TODO 自动生成的 catch 块
|
|
e.printStackTrace();
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
lineslock.writeLock().lock();
|
|
try {
|
|
|
|
|
|
Set<MultiProtocolSocketAddress> st = new HashSet<>();
|
|
for (IPv6NetworkLink link : srv6Router.getLinkTabel()) {
|
|
if (link instanceof KLALBRemoteLink) {
|
|
KLALBRemoteLink multipurposeSocketAddress = (KLALBRemoteLink) link;
|
|
if (multipurposeSocketAddress.getSocketAddress() != null)
|
|
st.add(multipurposeSocketAddress.getSocketAddress());
|
|
}
|
|
}
|
|
|
|
for (MultiProtocolSocketAddress target : st) {
|
|
addRemoteLines(target);
|
|
}
|
|
|
|
/*
|
|
for (IPv6NetworkLink link : srv6Router.getLinkTabel()) {
|
|
if (link instanceof KLALBRemoteLink) {
|
|
KLALBRemoteLink reml = (KLALBRemoteLink) link;
|
|
if (reml.getSocketAddress() != null) {
|
|
if (reml.getBindAddress() != null || reml.getRemoteVaddr() != null)
|
|
try {
|
|
MultipurposeSocketAddress iadr = reml.getBindAddress();
|
|
if (iadr != null) {
|
|
if (!localaddress.contains(iadr.getInetAddress())) {
|
|
reml.close();
|
|
srv6Router.getLinkTabel().remove(reml);
|
|
}
|
|
} else {
|
|
|
|
reml.close();
|
|
}
|
|
} catch (UnknownHostException e) {
|
|
reml.close();
|
|
srv6Router.getLinkTabel().remove(reml);
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
} finally {
|
|
lineslock.writeLock().unlock();
|
|
}
|
|
|
|
|
|
updateBroadcastNetworkInterface();
|
|
} catch (SocketException e) {
|
|
}catch (Exception e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
private void updateBroadcastNetworkInterface() throws SocketException {
|
|
for (Iterator<IPMulticastDiscovery> iterator = ipmd.iterator(); iterator.hasNext(); ) {
|
|
IPMulticastDiscovery ipMulticastDiscovery = (IPMulticastDiscovery) iterator.next();
|
|
if (ipMulticastDiscovery.isClosed() || (!ipMulticastDiscovery.getInterface().isUp())
|
|
|| (configItem != null && configItem.isDenyExternalEndpointBroadcast())) {
|
|
iterator.remove();
|
|
try {
|
|
ipMulticastDiscovery.close();
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
}
|
|
if (debug)
|
|
System.out.println("关闭网卡地址广播:" + ipMulticastDiscovery.getInterface());
|
|
}
|
|
}
|
|
|
|
if (configItem != null && configItem.isDenyExternalEndpointBroadcast()) {
|
|
|
|
} else {
|
|
List<NetworkInterface> interfaceList = networkInterfaceManager.getAllAvaliableNetworkInterface();
|
|
for(NetworkInterface networkInterface:interfaceList){
|
|
List<InetAddress> addressList= networkInterfaceManager.getNetworkInterfaceAddress(networkInterface);
|
|
loop:for (InetAddress bidr:addressList) {
|
|
|
|
for (IPMulticastDiscovery ipMulticastDiscovery : ipmd) {
|
|
if (networkInterface.equals(ipMulticastDiscovery.getInterface())
|
|
&& bidr.equals(ipMulticastDiscovery.getBind().getAddress())) {
|
|
continue loop;
|
|
}
|
|
}
|
|
|
|
try {
|
|
// InetAddress bidr=InetAddress.getByName("::0");
|
|
|
|
if (bidr instanceof Inet6Address) {
|
|
IPMulticastDiscovery ipd = new IPMulticastDiscovery(new InetSocketAddress(bidr,DISCOVERY_PORT),
|
|
new InetSocketAddress(InetAddress.getByName("ff02::2486"),
|
|
DISCOVERY_PORT),
|
|
networkInterface, listensSocketAddress, nodeuuid, 10000L);
|
|
ipd.setCon((mpa) -> {
|
|
if (debug)
|
|
System.out.println("添加本地IPv6链路:" + mpa);
|
|
try {
|
|
if (!checkIsSelf(mpa))
|
|
addRemoteLines(mpa);
|
|
} catch (UnknownHostException e) {
|
|
}
|
|
});
|
|
ipd.start();
|
|
ipmd.add(ipd);
|
|
} else if (bidr instanceof Inet4Address) {
|
|
// bidr=InetAddress.getByName("0.0.0.0");
|
|
IPMulticastDiscovery ipd2 = new IPMulticastDiscovery(new InetSocketAddress(bidr,DISCOVERY_PORT),
|
|
new InetSocketAddress(InetAddress.getByName("224.0.0.86"),
|
|
DISCOVERY_PORT),
|
|
networkInterface, listensSocketAddress, nodeuuid, 10000L);
|
|
ipd2.setCon((mpa) -> {
|
|
if (debug)
|
|
System.out.println("添加本地IPv4链路:" + mpa);
|
|
try {
|
|
if (!checkIsSelf(mpa))
|
|
addRemoteLines(mpa);
|
|
} catch (UnknownHostException e) {
|
|
}
|
|
});
|
|
ipd2.start();
|
|
ipmd.add(ipd2);
|
|
}
|
|
if (debug)
|
|
System.out.println("开启网卡地址广播:" + networkInterface);
|
|
} catch (BindException e) {
|
|
// e.printStackTrace();
|
|
} catch (UnknownHostException e) {
|
|
e.printStackTrace();
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
}
|
|
|
|
|
|
// }
|
|
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
private boolean checkIsSelf(MultiProtocolSocketAddress inetAddress) throws UnknownHostException {
|
|
|
|
return inetAddress.getInetAddress().isAnyLocalAddress() || inetAddress.getInetAddress().isLoopbackAddress()
|
|
|| externalEndpoints.contains(inetAddress);
|
|
}
|
|
|
|
private boolean checkIsSelfLocator(InetAddress inetAddress) {
|
|
return srv6Router.getLocator().getAddress().toInet6Address().equals(inetAddress);
|
|
}
|
|
|
|
private TimerTask tsk2 = new TimerTask() {
|
|
|
|
@Override
|
|
public void run() {
|
|
|
|
List<MultiProtocolSocketAddress> nt = ntptable;
|
|
// System.out.println("srv6 ip"+nb);
|
|
if (nvc2 != null) {
|
|
Set<NTPPeer> sp = nvc2.getPeers();
|
|
for (MultiProtocolSocketAddress server : nt) {
|
|
sp.add(new NTPPeer(server, NTPv4Packet.NTP_CLIENT));
|
|
|
|
}
|
|
sp.removeIf((p) -> {
|
|
for (MultiProtocolSocketAddress server : nt) {
|
|
if (server.equals(p.getAddress())) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
public void tryConnectMore(){
|
|
if (srv6Router != null && routingProtocol != null) {
|
|
Set<IPv6AddressGroup> nb = srv6Router.getLocators();
|
|
for (Iterator<IPv6AddressGroup> iterator = nb.iterator(); iterator.hasNext();) {
|
|
IPv6AddressGroup neighbor = (IPv6AddressGroup) iterator.next();
|
|
try {
|
|
InetSocketAddress iaddr = new InetSocketAddress(neighbor.getAddress().toInet6Address(),
|
|
KLALBRoutingProtocol.DEFAULT_PORT);
|
|
apiClient.requestNodeInfoFull(iaddr, (v) -> {
|
|
ThreadTool.makeVDaemonThreadIfSupport("线路添加任务", () -> {
|
|
for (MultiProtocolSocketAddress msa : v.getOpenLines()) {
|
|
// System.out.print(msa);
|
|
addRemoteLines(msa);
|
|
}
|
|
}).start();
|
|
});
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public SpeedAndTrafficMonitorDataImpl getLinkMonitor() {
|
|
return linkMonitor;
|
|
}
|
|
|
|
public SpeedAndTrafficMonitorDataImpl getDatatMonitor() {
|
|
return datatMonitor;
|
|
}
|
|
|
|
private SocketType streamSocketType = new KLALBStreamSocketType();
|
|
|
|
|
|
|
|
public class KLALBStreamSocketType extends SocketType {
|
|
|
|
public KLALBStreamSocketType() {
|
|
super(new KLALBVirtualSocketFactory(KLALBController.this),
|
|
new KLALBVirtualServerSocketFactory(KLALBController.this),
|
|
new KLALBVirtualSocketChannelFactory(KLALBController.this),
|
|
new KLALBVirtualServerSocketChannelFactory(KLALBController.this));
|
|
}
|
|
|
|
}
|
|
|
|
public SocketType getStreamSocketType() {
|
|
return streamSocketType;
|
|
}
|
|
|
|
private SocketType datagramSocketType = new KLALBDatagramSocketType();
|
|
|
|
public class KLALBDatagramSocketType extends SocketType {
|
|
|
|
public KLALBDatagramSocketType() {
|
|
super(new KLALBVirtualDatagramSocketFactory(KLALBController.this),
|
|
new KLALBVirtualDatagramServerSocketFactory(KLALBController.this));
|
|
// new KLALBVirtualDatagramSocketChannelFactory(KLALBController.this),
|
|
// new KLALBVirtualDatagramServerSocketChannelFactory(KLALBController.this));
|
|
}
|
|
|
|
}
|
|
|
|
public SocketType getDatagramSocketType() {
|
|
return datagramSocketType;
|
|
}
|
|
|
|
|
|
public List<MultiProtocolSocketAddress> getExternalEndpoints() {
|
|
return externalEndpoints;
|
|
}
|
|
|
|
|
|
public IPv6AddressGroup getSelf() {
|
|
return srv6Router.getLocator();
|
|
}
|
|
|
|
private ReadWriteLock lineslock = new ReentrantReadWriteLock();
|
|
|
|
public List<IPv6NetworkLink> getLines() {
|
|
return srv6Router.getLinkTabel();
|
|
}
|
|
|
|
|
|
|
|
public void reconnectImmediately() {
|
|
for (Iterator<IPv6NetworkLink> iterator = srv6Router.getLinkTabel().iterator(); iterator.hasNext();) {
|
|
IPv6NetworkLink val = iterator.next();
|
|
if (val instanceof KLALBRemoteLink) {
|
|
|
|
KLALBRemoteLink klalbRemoteLine = (KLALBRemoteLink) val;
|
|
klalbRemoteLine.reconnectImmediately();
|
|
}
|
|
}
|
|
}
|
|
|
|
private NTPv4Protocol nvc2;
|
|
|
|
private KLALBRoutingProtocolAPIServer apiServer;
|
|
|
|
private KLALBRoutingProtocolAPIClient apiClient;
|
|
|
|
private KLALBControllerConfigItem configItem;
|
|
|
|
public void addRemoteLines(List<MultiProtocolSocketAddress> select) {
|
|
for (MultiProtocolSocketAddress target : select) {
|
|
addRemoteLines(target);
|
|
}
|
|
}
|
|
|
|
public List<KLALBRemoteLink> addRemoteLines(MultiProtocolSocketAddress target) {
|
|
lineslock.writeLock().lock();
|
|
try {
|
|
List<KLALBRemoteLink> added = new ArrayList<>();
|
|
try {
|
|
Enumeration<NetworkInterface> eu = NetworkInterface.getNetworkInterfaces();
|
|
while (eu.hasMoreElements()) {
|
|
NetworkInterface networkInterface = (NetworkInterface) eu.nextElement();
|
|
if (networkInterface.isUp()) {
|
|
// System.out.println(networkInterface+" "+networkInterface.isUp());
|
|
Enumeration<InetAddress> ei = networkInterface.getInetAddresses();
|
|
while (ei.hasMoreElements()) {
|
|
InetAddress inetAddress = (InetAddress) ei.nextElement();
|
|
try {
|
|
MultiProtocolSocketAddress bind = new MultiProtocolSocketAddress(
|
|
inetAddress.getHostAddress(), 0);
|
|
try {
|
|
if (target.getInetAddress().isLoopbackAddress()
|
|
&& (!bind.getInetAddress().isLoopbackAddress())) {
|
|
continue;
|
|
}
|
|
if ((!target.getInetAddress().isLoopbackAddress())
|
|
&& bind.getInetAddress().isLoopbackAddress()) {
|
|
continue;
|
|
}
|
|
if (target.getInetAddress() instanceof Inet4Address
|
|
&& bind.getInetAddress() instanceof Inet6Address) {
|
|
continue;
|
|
}
|
|
if (target.getInetAddress() instanceof Inet6Address
|
|
&& bind.getInetAddress() instanceof Inet4Address) {
|
|
continue;
|
|
}
|
|
// System.out.println(target+"->"+bind);
|
|
} catch (UnknownHostException e) {
|
|
if (e.getMessage().trim().toLowerCase().contains("no scope_id found")) {
|
|
throw e;
|
|
}
|
|
// e.printStackTrace();
|
|
}
|
|
if (!checkContainsTargetAndBind(target, bind)) {
|
|
int count=1;
|
|
if(configItem!=null) {
|
|
count=configItem.getLinkConnectionsCount();
|
|
}
|
|
if(count<=0) {
|
|
count=1;
|
|
}
|
|
for(int i=0;i<count;i++) {
|
|
KLALBRemoteLink line = new KLALBRemoteLink(this, target, bind);
|
|
addRemoteLine(line);
|
|
added.add(line);
|
|
}
|
|
}
|
|
} catch (UnknownHostException e) {
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} catch (SocketException e) {
|
|
if (!checkContainsTarget(target)) {
|
|
KLALBRemoteLink line = new KLALBRemoteLink(this, target);
|
|
addRemoteLine(line);
|
|
added.add(line);
|
|
}
|
|
// throw e;
|
|
}
|
|
|
|
return added;
|
|
} finally {
|
|
lineslock.writeLock().unlock();
|
|
}
|
|
}
|
|
|
|
public List<KLALBRemoteLink> removeRemoteLines(MultiProtocolSocketAddress mpsa) {
|
|
|
|
List<KLALBRemoteLink> rmved = new ArrayList<>();
|
|
for (Iterator<IPv6NetworkLink> iterator = srv6Router.getLinkTabel().iterator(); iterator.hasNext();) {
|
|
IPv6NetworkLink link = iterator.next();
|
|
if (link instanceof KLALBRemoteLink) {
|
|
KLALBRemoteLink klalbRemoteLine = (KLALBRemoteLink) link;
|
|
if (mpsa.equals(klalbRemoteLine.getSocketAddress())) {
|
|
klalbRemoteLine.close();
|
|
rmved.add(klalbRemoteLine);
|
|
}
|
|
}
|
|
}
|
|
return rmved;
|
|
}
|
|
|
|
public Inet6Address getRemoteVaddrBySocketAddress(MultiProtocolSocketAddress target) throws SocketTimeoutException {
|
|
KLALBRemoteLink kr = null;
|
|
for (Iterator<IPv6NetworkLink> iterator = srv6Router.getLinkTabel().iterator(); iterator.hasNext();) {
|
|
IPv6NetworkLink link = iterator.next();
|
|
if (link instanceof KLALBRemoteLink) {
|
|
KLALBRemoteLink klalbRemoteLine = (KLALBRemoteLink) link;
|
|
if (target.equals(klalbRemoteLine.getSocketAddress()) && klalbRemoteLine.getBindAddress() == null) {
|
|
kr = klalbRemoteLine;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (kr == null) {
|
|
kr = new KLALBRemoteLink(this, target);
|
|
addRemoteLine(kr);
|
|
kr.waitForRemoteVaddrAvaliable(20000);
|
|
} else {
|
|
kr.reconnectImmediately();
|
|
kr.waitForRemoteVaddrAvaliable(20000);
|
|
}
|
|
return kr.getRemoteVaddr().getAddress().toInet6Address();
|
|
}
|
|
|
|
private boolean checkContainsTargetAndBind(MultiProtocolSocketAddress target, MultiProtocolSocketAddress bind) {
|
|
boolean b = false;
|
|
for (Iterator<IPv6NetworkLink> iterator = srv6Router.getLinkTabel().iterator(); iterator.hasNext();) {
|
|
IPv6NetworkLink link = iterator.next();
|
|
if (link instanceof KLALBRemoteLink) {
|
|
KLALBRemoteLink klalbRemoteLine = (KLALBRemoteLink) link;
|
|
if (bind.equals2(klalbRemoteLine.getBindAddress())
|
|
&& target.equals2(klalbRemoteLine.getSocketAddress())) {
|
|
b = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return b;
|
|
}
|
|
|
|
private boolean checkContainsTarget(MultiProtocolSocketAddress target) {
|
|
boolean b = false;
|
|
for (Iterator<IPv6NetworkLink> iterator = srv6Router.getLinkTabel().iterator(); iterator.hasNext();) {
|
|
IPv6NetworkLink link = iterator.next();
|
|
if (link instanceof KLALBRemoteLink) {
|
|
KLALBRemoteLink klalbRemoteLine = (KLALBRemoteLink) link;
|
|
if (target.equals(klalbRemoteLine.getSocketAddress())) {
|
|
b = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return b;
|
|
}
|
|
|
|
public void addRemoteLine(KLALBRemoteLink krs) {
|
|
lineslock.writeLock().lock();
|
|
try {
|
|
krs.startIO();
|
|
String externalEndpointsText = generateExternalEndpointsString();
|
|
if (externalEndpointsText != null && !externalEndpointsText.equals(""))
|
|
krs.sendPacket(new ADDLINESPacket(externalEndpointsText));
|
|
srv6Router.getLinkTabel().add(krs);
|
|
} finally {
|
|
lineslock.writeLock().unlock();
|
|
}
|
|
}
|
|
|
|
private String generateExternalEndpointsString() {
|
|
StringBuilder sbd = new StringBuilder();
|
|
for (Iterator<MultiProtocolSocketAddress> iterator = externalEndpoints.iterator(); iterator.hasNext();) {
|
|
MultiProtocolSocketAddress klalbRemoteLine = (MultiProtocolSocketAddress) iterator.next();
|
|
sbd.append(klalbRemoteLine.toString());
|
|
sbd.append('\n');
|
|
}
|
|
return sbd.toString();
|
|
}
|
|
|
|
|
|
|
|
|
|
private UDPProtocolRegister udpr;
|
|
public UDPProtocolRegister getUDPregister() {
|
|
return udpr;
|
|
}
|
|
|
|
private KLTPProtocolRegister kltpr;
|
|
public KLTPProtocolRegister getKLTPregister() {
|
|
return kltpr;
|
|
}
|
|
|
|
|
|
private PortBinder rawPortBinder ;
|
|
|
|
protected PortBinder getRawPortBinder() {
|
|
return rawPortBinder;
|
|
}
|
|
|
|
private void loadSRv6ProtocolStack(IPv6AddressGroup selfx, boolean enableVirtualAdapter) {
|
|
networkInterfaceManager.getInetAddressesExcept().add(selfx.getAddress().toInet6Address());
|
|
IPv6AddressGroup group=new IPv6AddressGroup(selfx.getAddress(),32);
|
|
srv6Router = new SRv6Router(selfx,group, clock);
|
|
if(configItem!=null) {
|
|
srv6Router.setPerformanceStrategy(PerformanceStrategy.fromDescription(configItem.getPerformanceStrategy()));
|
|
srv6Router.setDeviceName(configItem.getDeviceName());
|
|
}
|
|
srv6Router.runKLALBRouteProtocol();
|
|
routingProtocol = srv6Router.getKlalbRouteProtol();
|
|
routingProtocol.addReceiver((addr, packet) -> {
|
|
|
|
});
|
|
rawPortBinder= new PortBinder(this.getSelf().getAddress());
|
|
System.out.println(" Loaded: SRv6 Stack");
|
|
|
|
String name = (configItem != null && configItem.getTUNName() != null) ? configItem.getTUNName() : CONST.KLALB_S_RV6;
|
|
boolean isEnabled = configItem == null || configItem.isEnableTUN();
|
|
boolean enableTUN = enableVirtualAdapter && isEnabled && (name != null) && !name.trim().isEmpty() && !name.trim().equalsIgnoreCase("null");
|
|
if (enableTUN) {
|
|
Thread t=new Thread(()->{
|
|
try {
|
|
IPv6TUNLoopbackNetworkLink tunlink = new IPv6TUNLoopbackNetworkLink(name.trim(),group, SRv6Router.MTU, dnsAddresses);
|
|
tunlink.setMonitor(datatMonitor);
|
|
// srv6Router.getLinkTabel().add(tunlink);
|
|
srv6Router.getinLoopback().setFallbackLink(tunlink);
|
|
System.out.println(" Mounted: Tun Adapter");
|
|
|
|
} catch (Exception e) {
|
|
System.err.println("挂载虚拟网卡失败,可能是无管理员权限?请尝试使用管理员权限运行软件");
|
|
e.printStackTrace();
|
|
}
|
|
});
|
|
t.start();
|
|
}else {
|
|
System.out.println(" Tun Adapter Disabled");
|
|
|
|
}
|
|
udpr=new UDPProtocolRegister(this);
|
|
srv6Router.getinLoopback().getProtocolNumberRegister()[UDPPacket.UDP_PROTOCOL_NUMBER]=
|
|
udpr;
|
|
System.out.println(" Loaded: UDP Protocol");
|
|
kltpr=new KLTPProtocolRegister(this);
|
|
srv6Router.getinLoopback().getProtocolNumberRegister()[KLTPPacket.KLTP_PROTOCOL_NUMBER]=
|
|
kltpr;
|
|
System.out.println(" Loaded: KLTP Protocol");
|
|
String iproxyname = "KLALB_" + UUID.randomUUID();
|
|
registerToProxyTypeAs(iproxyname);
|
|
System.out.println(" Loaded: KLALB Protocol");
|
|
|
|
NTPContext context = new NTPContext(clock);
|
|
context.syncToSystem();
|
|
// System.out.println(context);
|
|
try {
|
|
NTPv4Protocol nvc = new NTPv4Protocol(context,
|
|
new MultiProtocolSocketAddress(iproxyname + "datagram","0.0.0.0",123));
|
|
srv6Router.addSRv6RouterListener(new SRv6RouterListener() {
|
|
|
|
@Override
|
|
public void onLinkChanged(SRv6Router router, IPv6NetworkLink link) {
|
|
|
|
List<Neighbor> nb = router.getNeighbors();
|
|
Set<NTPPeer> sp = nvc.getPeers();
|
|
for (Neighbor neighbor : nb) {
|
|
if (neighbor.getLocator() != null)
|
|
sp.add(new NTPPeer(
|
|
new MultiProtocolSocketAddress(iproxyname + "datagram",
|
|
neighbor.getLocator().getAddress().toString(), 123),
|
|
NTPv4Packet.NTP_SYMMETRIC_ACTIVE));
|
|
|
|
}
|
|
sp.removeIf((p) -> {
|
|
for (Neighbor neighbor : nb) {
|
|
try {
|
|
if (neighbor.getLocator() != null)
|
|
if (neighbor.getLocator().getAddress().toInet6Address()
|
|
.equals(p.getAddress().getInetAddress())) {
|
|
return false;
|
|
}
|
|
} catch (UnknownHostException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
});
|
|
nvc2 = new NTPv4Protocol(context, new MultiProtocolSocketAddress("udp","0.0.0.0",0));
|
|
|
|
System.out.println(" Loaded: NTP Module");
|
|
} catch (UnknownHostException e) {
|
|
// TODO 自动生成的 catch 块
|
|
e.printStackTrace();
|
|
} catch (IOException e) {
|
|
// TODO 自动生成的 catch 块
|
|
e.printStackTrace();
|
|
} // 106.55.184.199
|
|
}
|
|
|
|
private void loadController() {
|
|
this.apiServer = new KLALBRoutingProtocolAPIServer(routingProtocol, this);
|
|
this.apiClient = new KLALBRoutingProtocolAPIClient(routingProtocol);
|
|
twk.schedule(tsk1, 5000, 5000);
|
|
twk.schedule(tsk2, 5000, 5000);
|
|
}
|
|
|
|
public KLALBController() {
|
|
this(true, null);
|
|
}
|
|
|
|
public KLALBController(Inet6Address self) {
|
|
this(self, true, null);
|
|
}
|
|
|
|
public KLALBController(Inet6Address self, boolean enableVirtualAdapter, List<InetAddress> dnsaddr) {
|
|
this.dnsAddresses = dnsaddr;
|
|
IPv6AddressGroup selfg = new IPv6AddressGroup(IPv6Address.valueOf(self), PREFIX);
|
|
initKLALB(enableVirtualAdapter, selfg);
|
|
}
|
|
|
|
protected void initKLALB(boolean enableVirtualAdapter, IPv6AddressGroup selfg) {
|
|
ThreadTool.makeVDaemonThread("线路性能采样线程", ()->{
|
|
while(true) {
|
|
linkMonitor.update();
|
|
datatMonitor.update();
|
|
try {
|
|
Thread.sleep(1);
|
|
} catch (InterruptedException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
}).start();
|
|
loadSRv6ProtocolStack(selfg, enableVirtualAdapter);
|
|
loadController();
|
|
}
|
|
|
|
public KLALBController(boolean enableVirtualAdapter, List<InetAddress> dnsaddr) {
|
|
this.dnsAddresses = dnsaddr;
|
|
|
|
IPv6AddressGroup selfx = new IPv6AddressGroup(KLALBUtils.randomKLALBIPv6Address(), PREFIX);
|
|
initKLALB(enableVirtualAdapter, selfx);
|
|
}
|
|
|
|
public KLALBController(KLALBControllerConfigItem configItem) {
|
|
this.configItem = configItem;
|
|
String vase = configItem.getVirtualAddress();
|
|
this.dnsAddresses = new ArrayList<InetAddress>();
|
|
List<InetAddress> vdns = configItem.getDNS();
|
|
if (vdns != null) {
|
|
dnsAddresses.addAll(vdns);
|
|
}
|
|
IPv6AddressGroup selfx = null;
|
|
if (vase != null) {
|
|
try {
|
|
selfx = new IPv6AddressGroup(IPv6Address.valueOf(vase), PREFIX);
|
|
} catch (UnknownHostException e) {
|
|
e.printStackTrace();
|
|
}
|
|
} else {
|
|
selfx = new IPv6AddressGroup(KLALBUtils.randomKLALBIPv6Address(), PREFIX);
|
|
|
|
}
|
|
|
|
initKLALB(true, selfx);
|
|
Long vasn = configItem.getVirtualASN();
|
|
if (vasn != null) {
|
|
getIpv6Router().setASN(vasn);
|
|
}
|
|
|
|
List<MultiProtocolSocketAddress> linele = configItem.getExternalEndpoints();
|
|
if (linele != null) {
|
|
getExternalEndpoints().addAll(linele);
|
|
}
|
|
List<MultiProtocolSocketAddress> linetoc = configItem.getAutoConnections();
|
|
if (linetoc != null) {
|
|
linetoc.forEach((aline) -> {
|
|
addRemoteLines(aline);
|
|
});
|
|
}
|
|
|
|
List<MultiProtocolSocketAddress> ntps = configItem.getNtpServers();
|
|
if (ntps != null) {
|
|
getNTPTable().addAll(ntps);
|
|
}
|
|
|
|
List<String> strexc = configItem.getNetworkInterfaceExcepts();
|
|
getNetworkInterfaceExcept().clear();
|
|
if (strexc != null) {
|
|
for (String strexci : strexc) {
|
|
try {
|
|
getNetworkInterfaceExcept().add(NetworkInterface.getByName(strexci));
|
|
} catch (SocketException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public KLALBController(List<InetAddress> daddr) {
|
|
this(true, daddr);
|
|
}
|
|
|
|
public KLALBController(Inet6Address self, List<InetAddress> daddr) {
|
|
this(self, true, daddr);
|
|
}
|
|
|
|
public KLALBController(boolean enableVirtualAdapter) {
|
|
this(enableVirtualAdapter, null);
|
|
}
|
|
|
|
protected KLALBVirtualSocketImpl createVirtualSocketImpl() {
|
|
return new KLALBVirtualSocketImpl(this);
|
|
}
|
|
|
|
protected KLALBVirtualDatagramSocketImpl createVirtualDatagramSocketImpl() {
|
|
return new KLALBVirtualDatagramSocketImpl(this);
|
|
}
|
|
|
|
private SRv6Router srv6Router;
|
|
|
|
public SRv6Router getIpv6Router() {
|
|
return srv6Router;
|
|
}
|
|
|
|
private Timer trtr = new Timer("路由表刷新计时器", true);
|
|
{
|
|
trtr.scheduleAtFixedRate(new TimerTask() {
|
|
|
|
@Override
|
|
public void run() {
|
|
if (srv6Router != null) {
|
|
srv6Router.getLinkTabel().removeIf((v) -> {
|
|
return (v instanceof KLALBRemoteLink) && ((KLALBRemoteLink) v).isClosed();
|
|
});
|
|
srv6Router.updateRouteTabel();
|
|
}
|
|
}
|
|
}, 100, 100);
|
|
|
|
trtr.scheduleAtFixedRate(new TimerTask() {
|
|
|
|
@Override
|
|
public void run() {
|
|
if (srv6Router != null) {
|
|
srv6Router.sortRouteTabel();
|
|
}
|
|
|
|
}
|
|
}, 10, 10);
|
|
}
|
|
|
|
public IPv6Packet createPacketToAddress(IPv6Address addr, int flowlabel, IPv6Packet.IPv6Payload packet) {
|
|
return createPacketToAddress(addr, flowlabel, packet, 1);
|
|
}
|
|
|
|
public IPv6Packet createPacketToAddress(IPv6Address addr, int flowlabel, IPv6Packet.IPv6Payload packet,
|
|
int count) {
|
|
|
|
IPv6Packet ipv = new IPv6Packet();
|
|
|
|
if (showpacket)
|
|
System.out.println("KLALB_TX:" + packet);
|
|
|
|
ipv.setVersion(6);
|
|
ipv.setTrafficClass(0b10);
|
|
ipv.setFlowLabel(flowlabel);
|
|
ipv.setHopLimit(255);
|
|
ipv.setSourceAddress(getSelf().getAddress());
|
|
ipv.setDestinationAddress(addr);
|
|
|
|
ipv.setPayload(packet);
|
|
packet.setParent(ipv);
|
|
|
|
|
|
|
|
return ipv;
|
|
}
|
|
|
|
private Map<IPv6Address, BandwidthDistributer<PortPair>> bandwidthDistrmap = new ConcurrentHashMap<>();
|
|
|
|
private Lock bdmLock = new ReentrantLock();
|
|
|
|
protected Map<IPv6Address, BandwidthDistributer<PortPair>> getBandwidthDistrmap() {
|
|
return bandwidthDistrmap;
|
|
}
|
|
|
|
protected void registerDistUpdateConsumer(IPv6Address targetaAddress, PortPair portp,
|
|
Consumer<Long> updateConsumer) {
|
|
if (updateConsumer == null) {
|
|
System.out.println("连接" + targetaAddress + " " + portp + " 释放带宽!");
|
|
bdmLock.lock();
|
|
try {
|
|
BandwidthDistributer<PortPair> bdr = bandwidthDistrmap.get(targetaAddress);
|
|
if (bdr != null) {
|
|
bdr.setDistrUpdateConsumer(portp, updateConsumer);
|
|
bdr.setBandwidthRequest(portp, 0L);
|
|
if (bdr.getDistrUpdateConsumerMap().isEmpty()) {
|
|
bandwidthDistrmap.remove(targetaAddress);
|
|
}
|
|
}
|
|
} finally {
|
|
bdmLock.unlock();
|
|
}
|
|
} else {
|
|
System.out.println("连接" + targetaAddress + " " + portp + " 申请带宽!");
|
|
bdmLock.lock();
|
|
try {
|
|
BandwidthDistributer<PortPair> bdr = bandwidthDistrmap.get(targetaAddress);
|
|
if (bdr == null) {
|
|
bdr = new BandwidthDistributer<>(1024 * 20000L * 1024);
|
|
bdr.setTotalRequestUpdateConsumer((treq) -> {
|
|
KLALBRoutingProtocol krp = srv6Router.getKlalbRouteProtol();
|
|
krp.updateTotalRequestBandwidth(targetaAddress, treq);
|
|
});
|
|
bandwidthDistrmap.put(targetaAddress, bdr);
|
|
}
|
|
|
|
bdr.setDistrUpdateConsumer(portp, updateConsumer);
|
|
} finally {
|
|
bdmLock.unlock();
|
|
}
|
|
}
|
|
}
|
|
|
|
protected void updateBandwidthRequest(IPv6Address targetaAddress, PortPair portp, long bandwidth) {
|
|
if (bandwidth < 0) {
|
|
throw new IllegalArgumentException(bandwidth + "<0");
|
|
}
|
|
// System.out.println("连接"+targetaAddress.getHostAddress()+" "+portp+"
|
|
// 调整带宽到"+bandwidth/1024 +"KB/s!");
|
|
BandwidthDistributer<PortPair> bdr = bandwidthDistrmap.get(targetaAddress);
|
|
|
|
if (bdr != null) {
|
|
bdr.setBandwidthRequest(portp, bandwidth);
|
|
} else {
|
|
throw new NullPointerException("连接" + targetaAddress + " " + portp + " 未申请带宽!");
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void registerToProxyTypeAs(String proxyname) {
|
|
MultiProtocolSocketAddress.getSocketTypeRegister().put(proxyname + "stream", streamSocketType);
|
|
MultiProtocolSocketAddress.getSocketTypeRegister().put(proxyname + "datagram", datagramSocketType);
|
|
// ProxyProfileEntry.getRegister().put(proxyname, this);
|
|
}
|
|
|
|
private List<MultiProtocolSocketAddress> ntptable = new CopyOnWriteArrayList();
|
|
|
|
private KLALBRoutingProtocol routingProtocol;
|
|
|
|
public List<MultiProtocolSocketAddress> getNTPTable() {
|
|
return ntptable;
|
|
}
|
|
|
|
public KLALBControllerConfigItem getConfigItem() {
|
|
return configItem;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|