Compare commits
No commits in common. "a9afea0603edbd7639ef0eb827046abceacfff66" and "2d3d7d64d5565753b4bb51e2e2fd0732667f3d88" have entirely different histories.
a9afea0603
...
2d3d7d64d5
@ -10,15 +10,12 @@ import cn.x47.service.RIPServer;
|
|||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.*;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
public class RIPService {
|
public class RIPService {
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
// 启动服务器
|
// 启动服务器
|
||||||
if (Config.startServer) {
|
|
||||||
RIPServer server = new RIPServer();
|
RIPServer server = new RIPServer();
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
@ -27,20 +24,16 @@ public class RIPService {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
System.out.println("服务端已经启动");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Config.startClient) {
|
|
||||||
// 启动客户端
|
// 启动客户端
|
||||||
RIPClient client = new RIPClient();
|
RIPClient client = new RIPClient();
|
||||||
|
|
||||||
// 定期发送路由更新
|
// 定期发送路由更新
|
||||||
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
|
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
|
||||||
scheduler.scheduleAtFixedRate(() -> {
|
scheduler.scheduleAtFixedRate(() -> {
|
||||||
RIPPacket packet = createRipResponsePacket(Config.RIP_VERSION);
|
RIPPacket packet = createRipResponsePacket(Config.RIP_VERSION);
|
||||||
client.sendRipPacket(packet);
|
client.sendRipPacket(packet);
|
||||||
}, 0, 10, TimeUnit.SECONDS);
|
}, 0, 30, TimeUnit.SECONDS);
|
||||||
System.out.println("客户端已经启动");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 主线程等待
|
// 主线程等待
|
||||||
Thread.currentThread().join();
|
Thread.currentThread().join();
|
||||||
@ -51,9 +44,9 @@ public class RIPService {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// 示例:添加本地路由条目
|
// 示例:添加本地路由条目
|
||||||
InetAddress localAddress = InetAddress.getByName("10.47.54.0");
|
InetAddress localAddress = InetAddress.getByName("192.168.100.0");
|
||||||
InetAddress subnetMask = InetAddress.getByName("255.255.255.0");
|
InetAddress subnetMask = InetAddress.getByName("255.255.255.0");
|
||||||
InetAddress nextHop = InetAddress.getByName("0.0.0.0");
|
InetAddress nextHop = InetAddress.getByName("192.168.123.45");
|
||||||
|
|
||||||
RIPEntry entry = new RIPEntry();
|
RIPEntry entry = new RIPEntry();
|
||||||
entry.setAddressFamily((short) 2); // AF_INET
|
entry.setAddressFamily((short) 2); // AF_INET
|
||||||
|
@ -3,6 +3,4 @@ package cn.x47.config;
|
|||||||
public class Config {
|
public class Config {
|
||||||
// 设置协议版本,1 表示 RIP v1,2 表示 RIP v2
|
// 设置协议版本,1 表示 RIP v1,2 表示 RIP v2
|
||||||
public static final byte RIP_VERSION = 2;
|
public static final byte RIP_VERSION = 2;
|
||||||
public static final boolean startServer = true;
|
|
||||||
public static final boolean startClient = true;
|
|
||||||
}
|
}
|
||||||
|
@ -28,12 +28,14 @@ public class RIPPacketDecoder extends MessageToMessageDecoder<DatagramPacket> {
|
|||||||
List<RIPEntry> entries = new ArrayList<>();
|
List<RIPEntry> entries = new ArrayList<>();
|
||||||
while (buf.readableBytes() >= 20) {
|
while (buf.readableBytes() >= 20) {
|
||||||
RIPEntry entry = new RIPEntry();
|
RIPEntry entry = new RIPEntry();
|
||||||
entry.setAddressFamily(buf.readShort());
|
entry.setAddressFamily((short) buf.readUnsignedShort());
|
||||||
|
|
||||||
if (ripPacket.getVersion() == 2) {
|
if (ripPacket.getVersion() == 2) {
|
||||||
entry.setRouteTag(buf.readShort());
|
entry.setRouteTag((short) buf.readUnsignedShort());
|
||||||
} else {
|
} else {
|
||||||
entry.setRouteTag((short) 0);
|
entry.setRouteTag((short) 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] ipBytes = new byte[4];
|
byte[] ipBytes = new byte[4];
|
||||||
buf.readBytes(ipBytes);
|
buf.readBytes(ipBytes);
|
||||||
entry.setIpAddress(InetAddress.getByAddress(ipBytes));
|
entry.setIpAddress(InetAddress.getByAddress(ipBytes));
|
||||||
@ -48,10 +50,15 @@ public class RIPPacketDecoder extends MessageToMessageDecoder<DatagramPacket> {
|
|||||||
entry.setSubnetMask(InetAddress.getByName("255.255.255.0")); // 示例,实际应根据 IP 类推断
|
entry.setSubnetMask(InetAddress.getByName("255.255.255.0")); // 示例,实际应根据 IP 类推断
|
||||||
entry.setNextHop(packet.sender().getAddress());
|
entry.setNextHop(packet.sender().getAddress());
|
||||||
}
|
}
|
||||||
entry.setMetric(buf.readInt());
|
|
||||||
|
long metric = buf.readUnsignedInt();
|
||||||
|
entry.setMetric(metric);
|
||||||
|
|
||||||
entries.add(entry);
|
entries.add(entry);
|
||||||
}
|
}
|
||||||
ripPacket.setEntries(entries);
|
ripPacket.setEntries(entries);
|
||||||
|
ripPacket.setSenderAddress(packet.sender()); // 设置发送者地址
|
||||||
out.add(ripPacket);
|
out.add(ripPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -25,21 +25,18 @@ public class RIPPacketEncoder extends MessageToMessageEncoder<RIPPacket> {
|
|||||||
|
|
||||||
// 编码路由条目
|
// 编码路由条目
|
||||||
for (RIPEntry entry : msg.getEntries()) {
|
for (RIPEntry entry : msg.getEntries()) {
|
||||||
buf.writeShort(entry.getAddressFamily());
|
buf.writeShort(entry.getAddressFamily() & 0xFFFF);
|
||||||
if (msg.getVersion() == 2) {
|
if (msg.getVersion() == 2) {
|
||||||
buf.writeShort(entry.getRouteTag());
|
buf.writeShort(entry.getRouteTag() & 0xFFFF);
|
||||||
} else if (msg.getVersion() == 1) {
|
|
||||||
buf.writeShort(0);
|
|
||||||
}
|
}
|
||||||
buf.writeBytes(entry.getIpAddress().getAddress());
|
buf.writeBytes(entry.getIpAddress().getAddress());
|
||||||
|
|
||||||
if (msg.getVersion() == 2) {
|
if (msg.getVersion() == 2) {
|
||||||
buf.writeBytes(entry.getSubnetMask().getAddress());
|
buf.writeBytes(entry.getSubnetMask().getAddress());
|
||||||
buf.writeBytes(entry.getNextHop().getAddress());
|
buf.writeBytes(entry.getNextHop().getAddress());
|
||||||
} else if (msg.getVersion() == 1) {
|
|
||||||
buf.writeInt(0);
|
|
||||||
buf.writeInt(0);
|
|
||||||
}
|
}
|
||||||
buf.writeInt(entry.getMetric());
|
|
||||||
|
buf.writeInt((int) entry.getMetric() & 0xFFFFFFFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据版本选择目标地址
|
// 根据版本选择目标地址
|
||||||
@ -52,4 +49,5 @@ public class RIPPacketEncoder extends MessageToMessageEncoder<RIPPacket> {
|
|||||||
|
|
||||||
out.add(new DatagramPacket(buf, recipient));
|
out.add(new DatagramPacket(buf, recipient));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,34 +1,186 @@
|
|||||||
package cn.x47.handle;
|
package cn.x47.handle;
|
||||||
|
|
||||||
|
|
||||||
import cn.x47.model.RIPEntry;
|
import cn.x47.model.RIPEntry;
|
||||||
import cn.x47.model.RIPPacket;
|
import cn.x47.model.RIPPacket;
|
||||||
import cn.x47.service.RoutingTable;
|
import cn.x47.service.RoutingTable;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.channel.SimpleChannelInboundHandler;
|
import io.netty.channel.SimpleChannelInboundHandler;
|
||||||
|
import io.netty.channel.socket.DatagramPacket;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class RIPServerHandler extends SimpleChannelInboundHandler<RIPPacket> {
|
public class RIPServerHandler extends SimpleChannelInboundHandler<RIPPacket> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void channelRead0(ChannelHandlerContext ctx, RIPPacket msg) throws Exception {
|
protected void channelRead0(ChannelHandlerContext ctx, RIPPacket msg) throws Exception {
|
||||||
if (msg.getCommand() == 2) { // Response
|
InetSocketAddress senderAddress = msg.getSenderAddress();
|
||||||
for (RIPEntry entry : msg.getEntries()) {
|
byte version = msg.getVersion();
|
||||||
// 更新本地路由表
|
System.out.println(msg.toString());
|
||||||
updateRoutingTable(entry);
|
|
||||||
|
// if (msg.getCommand() == 2) { // Response
|
||||||
|
// for (RIPEntry entry : msg.getEntries()) {
|
||||||
|
// // 更新本地路由表
|
||||||
|
// updateRoutingTable(entry, senderAddress, version);
|
||||||
|
// }
|
||||||
|
// } else if (msg.getCommand() == 1) { // Request
|
||||||
|
// // 处理请求,发送响应包
|
||||||
|
// handleRequest(ctx, msg);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
} else if (msg.getCommand() == 1) { // Request
|
|
||||||
// 处理请求,可能需要发送响应包
|
private void handleRequest(ChannelHandlerContext ctx, RIPPacket requestPacket) throws Exception {
|
||||||
// ...
|
List<RIPEntry> requestEntries = requestPacket.getEntries();
|
||||||
|
byte version = requestPacket.getVersion();
|
||||||
|
|
||||||
|
boolean isGeneralRequest = false;
|
||||||
|
|
||||||
|
// 检查是否为一般请求
|
||||||
|
if (requestEntries.size() == 1) {
|
||||||
|
RIPEntry entry = requestEntries.get(0);
|
||||||
|
if (entry.getIpAddress().getHostAddress().equals("0.0.0.0") && entry.getMetric() == 16) {
|
||||||
|
isGeneralRequest = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateRoutingTable(RIPEntry entry) {
|
RIPPacket responsePacket = new RIPPacket();
|
||||||
|
responsePacket.setCommand((byte) 2); // Response
|
||||||
|
responsePacket.setVersion(version); // 与请求的版本一致
|
||||||
|
responsePacket.setUnused((short) 0);
|
||||||
|
List<RIPEntry> responseEntries = new ArrayList<>();
|
||||||
|
|
||||||
|
if (isGeneralRequest) {
|
||||||
|
// 一般请求,返回整个路由表
|
||||||
|
responseEntries.addAll(getAllRoutingEntries(version));
|
||||||
|
} else {
|
||||||
|
// 特定请求,逐一处理请求的条目
|
||||||
|
for (RIPEntry requestEntry : requestEntries) {
|
||||||
|
RIPEntry route = getRoutingEntry(requestEntry.getIpAddress());
|
||||||
|
if (route != null) {
|
||||||
|
responseEntries.add(route);
|
||||||
|
} else {
|
||||||
|
// 如果没有该路由,返回度量值为 16(无限)
|
||||||
|
RIPEntry unreachableEntry = new RIPEntry();
|
||||||
|
unreachableEntry.setAddressFamily(requestEntry.getAddressFamily());
|
||||||
|
unreachableEntry.setIpAddress(requestEntry.getIpAddress());
|
||||||
|
unreachableEntry.setMetric(16);
|
||||||
|
|
||||||
|
if (version == 2) {
|
||||||
|
unreachableEntry.setRouteTag((short) 0);
|
||||||
|
unreachableEntry.setSubnetMask(requestEntry.getSubnetMask());
|
||||||
|
unreachableEntry.setNextHop(InetAddress.getByName("0.0.0.0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
responseEntries.add(unreachableEntry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建响应包
|
||||||
|
responsePacket.setEntries(responseEntries);
|
||||||
|
|
||||||
|
// 获取发送者的地址
|
||||||
|
InetSocketAddress recipient = requestPacket.getSenderAddress();
|
||||||
|
|
||||||
|
// 发送响应包
|
||||||
|
ByteBuf buf = ctx.alloc().buffer().order(ByteOrder.BIG_ENDIAN); // 确保使用大端序
|
||||||
|
encodeRIPPacket(responsePacket, buf);
|
||||||
|
|
||||||
|
DatagramPacket responseDatagram = new DatagramPacket(buf, recipient);
|
||||||
|
ctx.writeAndFlush(responseDatagram);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void encodeRIPPacket(RIPPacket msg, ByteBuf buf) throws Exception {
|
||||||
|
// 编码命令和版本
|
||||||
|
buf.writeByte(msg.getCommand());
|
||||||
|
buf.writeByte(msg.getVersion());
|
||||||
|
buf.writeShort(0); // unused 字段
|
||||||
|
|
||||||
|
// 编码路由条目
|
||||||
|
for (RIPEntry entry : msg.getEntries()) {
|
||||||
|
buf.writeShort(entry.getAddressFamily());
|
||||||
|
if (msg.getVersion() == 2) {
|
||||||
|
buf.writeShort(entry.getRouteTag());
|
||||||
|
}
|
||||||
|
buf.writeBytes(entry.getIpAddress().getAddress());
|
||||||
|
|
||||||
|
if (msg.getVersion() == 2) {
|
||||||
|
buf.writeBytes(entry.getSubnetMask().getAddress());
|
||||||
|
buf.writeBytes(entry.getNextHop().getAddress());
|
||||||
|
}
|
||||||
|
buf.writeInt((int) (entry.getMetric() & 0xFFFFFFFFL));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<RIPEntry> getAllRoutingEntries(byte version) throws Exception {
|
||||||
|
List<RIPEntry> entries = new ArrayList<>();
|
||||||
|
// 从路由表中获取所有的路由条目
|
||||||
|
for (RIPEntry route : RoutingTable.getInstance().getRoutes().values()) {
|
||||||
|
RIPEntry entry = new RIPEntry();
|
||||||
|
entry.setAddressFamily(route.getAddressFamily());
|
||||||
|
entry.setIpAddress(route.getIpAddress());
|
||||||
|
entry.setMetric(route.getMetric());
|
||||||
|
|
||||||
|
if (version == 2) {
|
||||||
|
entry.setRouteTag(route.getRouteTag());
|
||||||
|
entry.setSubnetMask(route.getSubnetMask());
|
||||||
|
entry.setNextHop(route.getNextHop());
|
||||||
|
}
|
||||||
|
|
||||||
|
entries.add(entry);
|
||||||
|
}
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
private RIPEntry getRoutingEntry(InetAddress ipAddress) throws Exception {
|
||||||
|
RIPEntry route = RoutingTable.getInstance().getRoute(ipAddress);
|
||||||
|
if (route != null) {
|
||||||
|
RIPEntry entry = new RIPEntry();
|
||||||
|
entry.setAddressFamily(route.getAddressFamily());
|
||||||
|
entry.setIpAddress(route.getIpAddress());
|
||||||
|
entry.setMetric(route.getMetric());
|
||||||
|
|
||||||
|
entry.setRouteTag(route.getRouteTag());
|
||||||
|
entry.setSubnetMask(route.getSubnetMask());
|
||||||
|
entry.setNextHop(route.getNextHop());
|
||||||
|
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateRoutingTable(RIPEntry entry, InetSocketAddress senderAddress, byte version) throws Exception {
|
||||||
|
if (version == 1) {
|
||||||
|
// 推断下一跳为发送者的地址
|
||||||
|
entry.setNextHop(senderAddress.getAddress());
|
||||||
|
// 根据 IP 地址类别推断子网掩码
|
||||||
|
InetAddress ipAddress = entry.getIpAddress();
|
||||||
|
byte[] addressBytes = ipAddress.getAddress();
|
||||||
|
int firstOctet = addressBytes[0] & 0xFF;
|
||||||
|
|
||||||
|
if (firstOctet >= 0 && firstOctet <= 127) {
|
||||||
|
// A 类地址
|
||||||
|
entry.setSubnetMask(InetAddress.getByName("255.0.0.0"));
|
||||||
|
} else if (firstOctet >= 128 && firstOctet <= 191) {
|
||||||
|
// B 类地址
|
||||||
|
entry.setSubnetMask(InetAddress.getByName("255.255.0.0"));
|
||||||
|
} else if (firstOctet >= 192 && firstOctet <= 223) {
|
||||||
|
// C 类地址
|
||||||
|
entry.setSubnetMask(InetAddress.getByName("255.255.255.0"));
|
||||||
|
} else {
|
||||||
|
// 非法地址,忽略
|
||||||
|
System.out.println("Invalid IP address in RIP Entry: " + ipAddress.getHostAddress());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
// 实现路由表更新逻辑
|
// 实现路由表更新逻辑
|
||||||
// 这里只是示例,实际需要处理路由添加、更新、超时等逻辑
|
|
||||||
RoutingTable.getInstance().updateRoute(entry);
|
RoutingTable.getInstance().updateRoute(entry);
|
||||||
System.out.println("Updated route: " + entry.getIpAddress().getHostAddress() +
|
System.out.println("Updated route: " + entry.getIpAddress().getHostAddress() +
|
||||||
" via " + entry.getNextHop().getHostAddress() +
|
" via " + entry.getNextHop().getHostAddress() +
|
||||||
" metric: " + entry.getMetric());
|
" metric: " + entry.getMetric());
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,13 +6,12 @@ import java.net.InetAddress;
|
|||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class RIPEntry {
|
public class RIPEntry {
|
||||||
//
|
|
||||||
private short addressFamily;
|
private short addressFamily;
|
||||||
private short routeTag; // RIP v2 特有
|
private short routeTag; // RIP v2 特有
|
||||||
private InetAddress ipAddress;
|
private InetAddress ipAddress;
|
||||||
private InetAddress subnetMask; // RIP v2 特有
|
private InetAddress subnetMask; // RIP v2 特有
|
||||||
private InetAddress nextHop; // RIP v2 特有
|
private InetAddress nextHop; // RIP v2 特有
|
||||||
private int metric;
|
private long metric;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import lombok.AllArgsConstructor;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@ -14,6 +15,7 @@ public class RIPPacket {
|
|||||||
private byte version; // 1=RIP v1, 2=RIP v2
|
private byte version; // 1=RIP v1, 2=RIP v2
|
||||||
private short unused = 0; // 未使用,设置为 0
|
private short unused = 0; // 未使用,设置为 0
|
||||||
private List<RIPEntry> entries;
|
private List<RIPEntry> entries;
|
||||||
|
private InetSocketAddress senderAddress;
|
||||||
|
|
||||||
// 添加构造方法和 Getter/Setter
|
// 添加构造方法和 Getter/Setter
|
||||||
public RIPPacket(byte command, byte version, List<RIPEntry> entries) {
|
public RIPPacket(byte command, byte version, List<RIPEntry> entries) {
|
||||||
|
@ -4,15 +4,12 @@ package cn.x47.service;
|
|||||||
import cn.x47.handle.RIPPacketEncoder;
|
import cn.x47.handle.RIPPacketEncoder;
|
||||||
import cn.x47.model.RIPPacket;
|
import cn.x47.model.RIPPacket;
|
||||||
import io.netty.bootstrap.Bootstrap;
|
import io.netty.bootstrap.Bootstrap;
|
||||||
import io.netty.channel.ChannelFuture;
|
import io.netty.channel.*;
|
||||||
import io.netty.channel.ChannelInitializer;
|
|
||||||
import io.netty.channel.ChannelOption;
|
|
||||||
import io.netty.channel.nio.NioEventLoopGroup;
|
|
||||||
import io.netty.channel.socket.DatagramChannel;
|
|
||||||
import io.netty.channel.socket.nio.NioDatagramChannel;
|
import io.netty.channel.socket.nio.NioDatagramChannel;
|
||||||
|
import io.netty.channel.socket.DatagramChannel;
|
||||||
|
|
||||||
|
import io.netty.channel.nio.NioEventLoopGroup;
|
||||||
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.UnknownHostException;
|
|
||||||
|
|
||||||
|
|
||||||
public class RIPClient {
|
public class RIPClient {
|
||||||
@ -36,8 +33,7 @@ public class RIPClient {
|
|||||||
|
|
||||||
public void sendRipPacket(RIPPacket packet) {
|
public void sendRipPacket(RIPPacket packet) {
|
||||||
try {
|
try {
|
||||||
ChannelFuture future = bootstrap.bind(0)
|
ChannelFuture future = bootstrap.bind(0).sync();
|
||||||
.sync();
|
|
||||||
future.channel().writeAndFlush(packet).sync();
|
future.channel().writeAndFlush(packet).sync();
|
||||||
future.channel().close();
|
future.channel().close();
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package cn.x47.service;
|
package cn.x47.service;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import cn.x47.model.RIPEntry;
|
import cn.x47.model.RIPEntry;
|
||||||
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
@ -32,4 +31,8 @@ public class RoutingTable {
|
|||||||
public Map<InetAddress, RIPEntry> getRoutes() {
|
public Map<InetAddress, RIPEntry> getRoutes() {
|
||||||
return routes;
|
return routes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RIPEntry getRoute(InetAddress ipAddress) {
|
||||||
|
return routes.get(ipAddress);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,285 +0,0 @@
|
|||||||
import java.io.IOException;
|
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.io.ObjectOutputStream;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.ServerSocket;
|
|
||||||
import java.net.Socket;
|
|
||||||
import java.net.UnknownHostException;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Connection class takes input from the user
|
|
||||||
* and creates threads for the client and server
|
|
||||||
*
|
|
||||||
* @author Ankit
|
|
||||||
*/
|
|
||||||
public class Connection {
|
|
||||||
|
|
||||||
// Stores destination and cost to reach
|
|
||||||
public static HashMap<String, Integer> table;
|
|
||||||
// Stores local ip address
|
|
||||||
static String[] localIP;
|
|
||||||
// Stores it's neighbors
|
|
||||||
static ArrayList<String> neighbors;
|
|
||||||
//Stores destination and next hop
|
|
||||||
public static HashMap<String, String> hop;
|
|
||||||
// Subnet mask
|
|
||||||
public static String subnetMask = "255.255.255.0";
|
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
|
||||||
table = new HashMap<>();
|
|
||||||
hop = new HashMap<>();
|
|
||||||
neighbors = new ArrayList<>();
|
|
||||||
System.out.println(InetAddress.getLocalHost() + " connection started");
|
|
||||||
localIP = InetAddress.getLocalHost().toString().split("/");
|
|
||||||
System.out.println("Updated position 1");
|
|
||||||
table.put(localIP[1], 0);
|
|
||||||
hop.put(localIP[1], localIP[1]);
|
|
||||||
// Starts the server
|
|
||||||
Server server = new Server();
|
|
||||||
server.start();
|
|
||||||
|
|
||||||
int length = args.length;
|
|
||||||
// User input for the neighbor ip and cost
|
|
||||||
Scanner scan = new Scanner(System.in);
|
|
||||||
for (int i = 0; i < length; i++) {
|
|
||||||
System.out.println("Enter the cost for " + args[i].toString());
|
|
||||||
int cost = scan.nextInt();
|
|
||||||
new Client(args[i], cost).start();
|
|
||||||
}
|
|
||||||
scan.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the destination cost and the next hop
|
|
||||||
*
|
|
||||||
* @param temp - routing table of neighbor
|
|
||||||
* @param senderIP - sender ip address
|
|
||||||
* @param tempHop - Next hops of the sender
|
|
||||||
*/
|
|
||||||
public static void updateTable(Map<String, Integer> temp, String senderIP, Map<String, String> tempHop) {
|
|
||||||
// updates the table if neighbor has smaller value
|
|
||||||
if (table.containsKey(senderIP) && temp.containsKey(localIP[1])) {
|
|
||||||
if (table.get(senderIP) > temp.get(localIP[1])) {
|
|
||||||
table.put(senderIP, temp.get(localIP[1]));
|
|
||||||
if (tempHop.get(localIP[1]).equals(localIP[1])) {
|
|
||||||
hop.put(senderIP, senderIP);
|
|
||||||
} else {
|
|
||||||
for (int i = 0; i < neighbors.size(); i++) {
|
|
||||||
if (!neighbors.get(i).equals(senderIP)) {
|
|
||||||
hop.put(senderIP, neighbors.get(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the neighbor if neighbor has its entry
|
|
||||||
if (!table.containsKey(senderIP)) {
|
|
||||||
table.put(senderIP, temp.get(localIP[1]));
|
|
||||||
hop.put(senderIP, senderIP);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
|
||||||
Iterator it = temp.entrySet().iterator();
|
|
||||||
while (it.hasNext()) {
|
|
||||||
@SuppressWarnings("rawtypes")
|
|
||||||
Map.Entry pair = (Map.Entry) it.next();
|
|
||||||
String ip = pair.getKey().toString();
|
|
||||||
if (!table.containsKey(ip)) {
|
|
||||||
table.put(ip, Integer.parseInt(pair.getValue().toString())
|
|
||||||
+ table.get(senderIP));
|
|
||||||
hop.put(ip, senderIP);
|
|
||||||
} else {
|
|
||||||
if (table.get(ip) > (Integer.parseInt(pair.getValue()
|
|
||||||
.toString()) + table.get(senderIP))) {
|
|
||||||
table.put(
|
|
||||||
ip,
|
|
||||||
(Integer.parseInt(pair.getValue().toString()) + table
|
|
||||||
.get(senderIP)));
|
|
||||||
hop.put(ip, senderIP);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Displays the desired output i.e.
|
|
||||||
* Destination, subnet mask, cost and next hop
|
|
||||||
*/
|
|
||||||
public static void display() {
|
|
||||||
@SuppressWarnings("rawtypes")
|
|
||||||
Iterator it = table.entrySet().iterator();
|
|
||||||
System.out.println("------ UPDATED TABLE -----");
|
|
||||||
System.out.println("Destination" + '\t' + "Subnet Mask" + '\t' + "Cost" + '\t' + "Next Hop");
|
|
||||||
while (it.hasNext()) {
|
|
||||||
@SuppressWarnings("rawtypes")
|
|
||||||
Map.Entry pair = (Map.Entry) it.next();
|
|
||||||
String[] ipSubParts = pair.getKey().toString().split("\\.");
|
|
||||||
String[] subnetSubParts = subnetMask.split("\\.");
|
|
||||||
String[] netID = new String[4];
|
|
||||||
for (int i = 0; i < ipSubParts.length; i++) {
|
|
||||||
netID[i] = Integer.toString((Integer.parseInt(ipSubParts[i]) & Integer.parseInt(subnetSubParts[i])));
|
|
||||||
}
|
|
||||||
String networkID = netID[0] + "." + netID[1] + "." + netID[2] + "." + netID[3];
|
|
||||||
// Desired output displayed
|
|
||||||
System.out.println(networkID + '\t' + subnetMask + '\t' + pair.getValue() + '\t' + hop.get(pair.getKey().toString()));
|
|
||||||
}
|
|
||||||
System.out.println();
|
|
||||||
System.out.println("----------------------------------------------");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Server class accepts the connection from the neighbors
|
|
||||||
* It waits for neighbors input, updates table
|
|
||||||
* and sends updated table
|
|
||||||
*
|
|
||||||
* @author Ankit
|
|
||||||
*/
|
|
||||||
class Server extends Thread {
|
|
||||||
|
|
||||||
private static ServerSocket server;
|
|
||||||
private Socket connection;
|
|
||||||
ObjectInputStream input;
|
|
||||||
ObjectOutputStream output;
|
|
||||||
|
|
||||||
public Server() throws IOException {
|
|
||||||
server = new ServerSocket(6969);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
accept();
|
|
||||||
} catch (UnknownHostException | ClassNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void accept() throws UnknownHostException, ClassNotFoundException {
|
|
||||||
try {
|
|
||||||
int count = 0;
|
|
||||||
while (count < 2) {
|
|
||||||
count++;
|
|
||||||
System.out.println(InetAddress.getLocalHost()
|
|
||||||
+ " is waiting for connection " + count);
|
|
||||||
// accepts the connection from the neighbors
|
|
||||||
connection = server.accept();
|
|
||||||
System.out.println(InetAddress.getLocalHost()
|
|
||||||
+ " connected to " + connection.getInetAddress());
|
|
||||||
String[] connectionIP = connection.getInetAddress().toString()
|
|
||||||
.split("/");
|
|
||||||
Connection.neighbors.add(connectionIP[1]);
|
|
||||||
output = new ObjectOutputStream(connection.getOutputStream());
|
|
||||||
input = new ObjectInputStream(connection.getInputStream());
|
|
||||||
|
|
||||||
// Creates new thread to interact with the client
|
|
||||||
new Thread(new Runnable() {
|
|
||||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
while (true) {
|
|
||||||
try {
|
|
||||||
HashMap<HashMap<String, Integer>, HashMap<String, String>> receiver;
|
|
||||||
// reads the input from the neighbor
|
|
||||||
receiver = (HashMap<HashMap<String, Integer>, HashMap<String, String>>) input.readObject();
|
|
||||||
HashMap<String, Integer> temp = (HashMap<String, Integer>) receiver.keySet().toArray()[0];
|
|
||||||
HashMap<String, String> tempHop = receiver.get(temp);
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
Iterator it = temp.entrySet().iterator();
|
|
||||||
Connection.updateTable(temp, connectionIP[1], tempHop);
|
|
||||||
HashMap<HashMap<String, Integer>, HashMap<String, String>> sender;
|
|
||||||
sender = new HashMap<HashMap<String, Integer>, HashMap<String, String>>();
|
|
||||||
sender.put(Connection.table, Connection.hop);
|
|
||||||
// sends the updated table to its neighbors
|
|
||||||
output.writeObject(sender);
|
|
||||||
output.reset();
|
|
||||||
Connection.display();
|
|
||||||
Thread.sleep(1000);
|
|
||||||
} catch (Exception e) {
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).start();
|
|
||||||
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Client asks for the connection to the server
|
|
||||||
* It sends current routing table and recieves the updated routing table
|
|
||||||
*
|
|
||||||
* @author Ankit
|
|
||||||
*/
|
|
||||||
class Client extends Thread {
|
|
||||||
|
|
||||||
Socket connection;
|
|
||||||
String ipAddress = "";
|
|
||||||
int cost;
|
|
||||||
ObjectInputStream input;
|
|
||||||
ObjectOutputStream output;
|
|
||||||
|
|
||||||
public Client(String ip, int cost) throws IOException {
|
|
||||||
ipAddress = ip;
|
|
||||||
this.cost = cost;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings({"unused", "unchecked"})
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
// connects to the server
|
|
||||||
connection = new Socket(ipAddress, 6969);
|
|
||||||
Connection.neighbors.add(ipAddress);
|
|
||||||
output = new ObjectOutputStream(connection.getOutputStream());
|
|
||||||
input = new ObjectInputStream(connection.getInputStream());
|
|
||||||
System.out.println(InetAddress.getLocalHost().toString()
|
|
||||||
+ " Connected to: " + ipAddress + " with cost: " + cost);
|
|
||||||
if (Connection.table.containsKey(ipAddress)) {
|
|
||||||
if (Connection.table.get(ipAddress) > cost) {
|
|
||||||
Connection.table.put(ipAddress, cost);
|
|
||||||
Connection.hop.put(ipAddress, ipAddress);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Connection.table.put(ipAddress, cost);
|
|
||||||
Connection.hop.put(ipAddress, ipAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
Connection.display();
|
|
||||||
HashMap<HashMap<String, Integer>, HashMap<String, String>> sender;
|
|
||||||
sender = new HashMap<HashMap<String, Integer>, HashMap<String, String>>();
|
|
||||||
sender.put(Connection.table, Connection.hop);
|
|
||||||
// sends updated cost and next hop table to the neighbor
|
|
||||||
output.writeObject(sender);
|
|
||||||
output.reset();
|
|
||||||
|
|
||||||
HashMap<HashMap<String, Integer>, HashMap<String, String>> receiver;
|
|
||||||
// reads updated cost and next hop table from neighbor
|
|
||||||
receiver = (HashMap<HashMap<String, Integer>, HashMap<String, String>>) input.readObject();
|
|
||||||
HashMap<String, Integer> temp = (HashMap<String, Integer>) receiver.keySet().toArray()[0];
|
|
||||||
HashMap<String, String> tempHop = receiver.get(temp);
|
|
||||||
@SuppressWarnings("rawtypes")
|
|
||||||
Iterator it = temp.entrySet().iterator();
|
|
||||||
Connection.updateTable(temp, ipAddress, tempHop);
|
|
||||||
Thread.sleep(1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (UnknownHostException e) {
|
|
||||||
System.out.println("Cannot connect to the network: "
|
|
||||||
+ e.getMessage());
|
|
||||||
} catch (IOException e) {
|
|
||||||
System.exit(0);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,85 +0,0 @@
|
|||||||
import java.net.InetAddress;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class RipV1PacketBuilder {
|
|
||||||
|
|
||||||
public static byte[] buildRipV1RequestPacket() throws IOException {
|
|
||||||
// 使用 ByteArrayOutputStream 和 DataOutputStream 来构建数据包
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
DataOutputStream dos = new DataOutputStream(baos);
|
|
||||||
|
|
||||||
// 1. Command (8比特) - 请求报文,值为 1
|
|
||||||
dos.writeByte(1); // 请求报文
|
|
||||||
|
|
||||||
// 2. Version (8比特) - RIP v1,值为 1
|
|
||||||
dos.writeByte(1); // RIP v1
|
|
||||||
|
|
||||||
// 3. Must be zero (16比特) - 保留字段,必须为零
|
|
||||||
dos.writeShort(0); // 保留字段,填充为零
|
|
||||||
|
|
||||||
// 4. Address Family Identifier (AFI) - 请求报文中为 0
|
|
||||||
dos.writeShort(0); // 请求报文的 AFI 为 0
|
|
||||||
|
|
||||||
// 5. IP Address (32比特) - 目标 IP 地址,RIP 请求报文中通常为 0.0.0.0
|
|
||||||
InetAddress byName = InetAddress.getByName("200.0.2.0");
|
|
||||||
|
|
||||||
// 6. Metric (32比特) - 请求报文的 Metric 为 16,表示不可达
|
|
||||||
dos.writeInt(16); // Metric = 16
|
|
||||||
|
|
||||||
// 转换成字节数组
|
|
||||||
return baos.toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] buildRipV1ResponsePacket() throws IOException {
|
|
||||||
// 使用 ByteArrayOutputStream 和 DataOutputStream 来构建数据包
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
DataOutputStream dos = new DataOutputStream(baos);
|
|
||||||
|
|
||||||
// 1. Command (8比特) - 响应报文,值为 2
|
|
||||||
dos.writeByte(2); // 响应报文
|
|
||||||
|
|
||||||
// 2. Version (8比特) - RIP v1,值为 1
|
|
||||||
dos.writeByte(1); // RIP v1
|
|
||||||
|
|
||||||
// 3. Must be zero (16比特) - 保留字段,必须为零
|
|
||||||
dos.writeShort(0); // 保留字段,填充为零
|
|
||||||
|
|
||||||
// 4. Address Family Identifier (AFI) - 请求报文中为 0
|
|
||||||
dos.writeShort(2); // 响应报文的 AFI 对于 IPv4 为 2
|
|
||||||
|
|
||||||
dos.writeShort(0);
|
|
||||||
|
|
||||||
// 5. IP Address (32比特) - 目标 IP 地址,假设响应报文中为某个 IP
|
|
||||||
InetAddress byName = InetAddress.getByName("200.0.2.0");
|
|
||||||
printByteArray(byName.getAddress());
|
|
||||||
|
|
||||||
dos.write(byName.getAddress()); // 192.168.0.1(IPv4 地址)
|
|
||||||
|
|
||||||
// 6. Metric (32比特) - 路由的 Metric
|
|
||||||
dos.writeInt(1); // 假设 Metric 为 1
|
|
||||||
|
|
||||||
// 转换成字节数组
|
|
||||||
return baos.toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
|
||||||
byte[] requestPacket = buildRipV1RequestPacket();
|
|
||||||
byte[] responsePacket = buildRipV1ResponsePacket();
|
|
||||||
|
|
||||||
System.out.println("RIP v1 Request Packet: ");
|
|
||||||
printByteArray(requestPacket);
|
|
||||||
|
|
||||||
System.out.println("RIP v1 Response Packet: ");
|
|
||||||
printByteArray(responsePacket);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 打印字节数组的辅助函数
|
|
||||||
private static void printByteArray(byte[] byteArray) {
|
|
||||||
for (byte b : byteArray) {
|
|
||||||
System.out.printf("%02X ", b);
|
|
||||||
}
|
|
||||||
System.out.println();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,66 +0,0 @@
|
|||||||
import java.net.*;
|
|
||||||
import java.io.*;
|
|
||||||
|
|
||||||
public class RipV1Response {
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
try {
|
|
||||||
// 创建一个数据包
|
|
||||||
byte[] packet = createRipV1ResponsePacket();
|
|
||||||
|
|
||||||
// 创建一个UDP Socket
|
|
||||||
// DatagramSocket socket = new DatagramSocket();
|
|
||||||
// 创建一个UDP Socket,并将其绑定到指定的 IP 地址
|
|
||||||
DatagramSocket socket = new DatagramSocket(null);
|
|
||||||
socket.bind(new InetSocketAddress(InetAddress.getByName("192.168.123.45"), 520)); // 使用特定的本地 IP 地址绑定端口
|
|
||||||
|
|
||||||
|
|
||||||
InetAddress address = InetAddress.getByName("224.0.0.9"); // RIPv1 默认的多播地址
|
|
||||||
|
|
||||||
// 创建一个DatagramPacket并发送
|
|
||||||
DatagramPacket sendPacket = new DatagramPacket(packet, packet.length, address, 520); // RIPv1 默认端口 520
|
|
||||||
socket.send(sendPacket);
|
|
||||||
|
|
||||||
System.out.println("RIP v1 Response packet sent!");
|
|
||||||
socket.close();
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 构建RIP v1 响应数据包
|
|
||||||
public static byte[] createRipV1ResponsePacket() {
|
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
|
||||||
DataOutputStream dos = new DataOutputStream(bos);
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 1. Command (8比特) - 响应报文 (Response)
|
|
||||||
dos.writeByte(2); // Command = 2,表示响应报文
|
|
||||||
|
|
||||||
// 2. Version (8比特) - RIP版本号 (RIP-1)
|
|
||||||
dos.writeByte(1); // Version = 1,RIP-1
|
|
||||||
|
|
||||||
// 3. Must be zero (16比特) - 保留字段,必须为零
|
|
||||||
dos.writeShort(0); // 16比特的保留字段,填充0
|
|
||||||
|
|
||||||
// 4. AFI (Address Family Identifier) (16比特) - 地址族标识符
|
|
||||||
dos.writeShort(2); // AFI = 2,表示 IPv4 地址
|
|
||||||
|
|
||||||
dos.writeShort(0);
|
|
||||||
|
|
||||||
InetAddress byName = InetAddress.getByName("200.0.2.0");
|
|
||||||
// 5. IP Address (32比特) - 路由目标 IP 地址
|
|
||||||
dos.write(byName.getAddress()); // 192.168.0.1 的 IP 地址(32位)
|
|
||||||
|
|
||||||
dos.writeInt(0);
|
|
||||||
dos.writeInt(0);
|
|
||||||
// 6. Metric (32比特) - 路由开销
|
|
||||||
dos.writeInt(1); // Metric = 1,表示一个跳数
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
return bos.toByteArray();
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user