init
This commit is contained in:
@ -1,6 +1,5 @@
|
|||||||
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 io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
@ -28,14 +27,12 @@ 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((short) buf.readUnsignedShort());
|
entry.setAddressFamily(buf.readShort());
|
||||||
|
|
||||||
if (ripPacket.getVersion() == 2) {
|
if (ripPacket.getVersion() == 2) {
|
||||||
entry.setRouteTag((short) buf.readUnsignedShort());
|
entry.setRouteTag(buf.readShort());
|
||||||
} 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));
|
||||||
@ -50,15 +47,10 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -21,22 +21,20 @@ public class RIPPacketEncoder extends MessageToMessageEncoder<RIPPacket> {
|
|||||||
// 编码命令和版本
|
// 编码命令和版本
|
||||||
buf.writeByte(msg.getCommand());
|
buf.writeByte(msg.getCommand());
|
||||||
buf.writeByte(msg.getVersion());
|
buf.writeByte(msg.getVersion());
|
||||||
buf.writeShort(msg.getUnused()); // unused 字段
|
buf.writeShort(0); // unused 字段
|
||||||
|
|
||||||
// 编码路由条目
|
// 编码路由条目
|
||||||
for (RIPEntry entry : msg.getEntries()) {
|
for (RIPEntry entry : msg.getEntries()) {
|
||||||
buf.writeShort(entry.getAddressFamily() & 0xFFFF);
|
buf.writeShort(entry.getAddressFamily());
|
||||||
if (msg.getVersion() == 2) {
|
if (msg.getVersion() == 2) {
|
||||||
buf.writeShort(entry.getRouteTag() & 0xFFFF);
|
buf.writeShort(entry.getRouteTag());
|
||||||
}
|
}
|
||||||
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());
|
||||||
}
|
}
|
||||||
|
buf.writeInt(entry.getMetric());
|
||||||
buf.writeInt((int) entry.getMetric() & 0xFFFFFFFF);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据版本选择目标地址
|
// 根据版本选择目标地址
|
||||||
@ -49,5 +47,4 @@ public class RIPPacketEncoder extends MessageToMessageEncoder<RIPPacket> {
|
|||||||
|
|
||||||
out.add(new DatagramPacket(buf, recipient));
|
out.add(new DatagramPacket(buf, recipient));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,185 +1,35 @@
|
|||||||
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 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 {
|
||||||
InetSocketAddress senderAddress = msg.getSenderAddress();
|
System.out.println(msg);
|
||||||
byte version = msg.getVersion();
|
if (msg.getCommand() == 2) { // Response
|
||||||
System.out.println(msg.toString());
|
for (RIPEntry entry : msg.getEntries()) {
|
||||||
|
// 更新本地路由表
|
||||||
// if (msg.getCommand() == 2) { // Response
|
updateRoutingTable(entry);
|
||||||
// for (RIPEntry entry : msg.getEntries()) {
|
|
||||||
// // 更新本地路由表
|
|
||||||
// updateRoutingTable(entry, senderAddress, version);
|
|
||||||
// }
|
|
||||||
// } else if (msg.getCommand() == 1) { // Request
|
|
||||||
// // 处理请求,发送响应包
|
|
||||||
// handleRequest(ctx, msg);
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
} else if (msg.getCommand() == 1) {
|
||||||
|
for (RIPEntry entry : msg.getEntries()) {
|
||||||
RIPPacket responsePacket = new RIPPacket();
|
// 更新本地路由表
|
||||||
responsePacket.setCommand((byte) 2); // Response
|
updateRoutingTable(entry);
|
||||||
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 {
|
private void updateRoutingTable(RIPEntry entry) {
|
||||||
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);
|
// 这里只是示例,实际需要处理路由添加、更新、超时等逻辑
|
||||||
System.out.println("Updated route: " + entry.getIpAddress().getHostAddress() +
|
System.out.println("Received route: " + entry.getIpAddress().getHostAddress() +
|
||||||
" via " + entry.getNextHop().getHostAddress() +
|
" via " + entry.getNextHop().getHostAddress() +
|
||||||
" metric: " + entry.getMetric());
|
" metric: " + entry.getMetric());
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ public class RIPEntry {
|
|||||||
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 long metric;
|
private int metric;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,13 +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.*;
|
import io.netty.channel.ChannelFuture;
|
||||||
import io.netty.channel.socket.nio.NioDatagramChannel;
|
import io.netty.channel.ChannelInitializer;
|
||||||
import io.netty.channel.socket.DatagramChannel;
|
import io.netty.channel.ChannelOption;
|
||||||
|
|
||||||
import io.netty.channel.nio.NioEventLoopGroup;
|
import io.netty.channel.nio.NioEventLoopGroup;
|
||||||
|
import io.netty.channel.socket.DatagramChannel;
|
||||||
|
import io.netty.channel.socket.nio.NioDatagramChannel;
|
||||||
|
|
||||||
public class RIPClient {
|
public class RIPClient {
|
||||||
|
|
||||||
@ -33,14 +32,21 @@ public class RIPClient {
|
|||||||
|
|
||||||
public void sendRipPacket(RIPPacket packet) {
|
public void sendRipPacket(RIPPacket packet) {
|
||||||
try {
|
try {
|
||||||
ChannelFuture future = bootstrap.bind(0).sync();
|
ChannelFuture future = bootstrap.bind(600).sync(); // 部分环境下需不同端口尝试
|
||||||
future.channel().writeAndFlush(packet).sync();
|
future.channel().writeAndFlush(packet).addListener(f -> {
|
||||||
future.channel().close();
|
if (f.isSuccess()) {
|
||||||
|
System.out.println("Packet sent successfully");
|
||||||
|
} else {
|
||||||
|
System.err.println("Failed to send packet: " + f.cause().getMessage());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
future.channel().closeFuture().sync(); // 等待,保持通道开启
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
group.shutdownGracefully();
|
group.shutdownGracefully();
|
||||||
}
|
}
|
||||||
|
@ -1,38 +0,0 @@
|
|||||||
package cn.x47.service;
|
|
||||||
|
|
||||||
|
|
||||||
import cn.x47.model.RIPEntry;
|
|
||||||
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
public class RoutingTable {
|
|
||||||
private static RoutingTable instance = new RoutingTable();
|
|
||||||
private Map<InetAddress, RIPEntry> routes;
|
|
||||||
|
|
||||||
private RoutingTable() {
|
|
||||||
routes = new ConcurrentHashMap<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static RoutingTable getInstance() {
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateRoute(RIPEntry entry) {
|
|
||||||
// 简单地将新路由添加或更新到路由表中
|
|
||||||
routes.put(entry.getIpAddress(), entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeRoute(InetAddress ipAddress) {
|
|
||||||
routes.remove(ipAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<InetAddress, RIPEntry> getRoutes() {
|
|
||||||
return routes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RIPEntry getRoute(InetAddress ipAddress) {
|
|
||||||
return routes.get(ipAddress);
|
|
||||||
}
|
|
||||||
}
|
|
Reference in New Issue
Block a user