From f379b02e618e9b80c54720510696c825b234d16b Mon Sep 17 00:00:00 2001 From: xking Date: Sun, 1 Dec 2024 16:33:51 +0800 Subject: [PATCH] =?UTF-8?q?fix=20=20=20=20=20=20=E4=BF=AE=E5=A4=8D=20rip?= =?UTF-8?q?=20v1=20=E5=93=8D=E5=BA=94=E5=8C=85=20=E4=B8=8D=E6=AD=A3?= =?UTF-8?q?=E7=A1=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/cn/x47/RIPService.java | 2 +- src/main/java/cn/x47/config/Config.java | 2 +- .../java/cn/x47/handle/RIPPacketEncoder.java | 9 +- src/main/java/cn/x47/model/RIPEntry.java | 1 + src/main/java/cn/x47/model/RIPPacket.java | 2 +- src/main/java/cn/x47/service/RIPClient.java | 8 +- src/test/java/RipV1PacketBuilder.java | 85 +++++++++++++++++++ src/test/java/RipV1Response.java | 66 ++++++++++++++ 8 files changed, 169 insertions(+), 6 deletions(-) create mode 100644 src/test/java/RipV1PacketBuilder.java create mode 100644 src/test/java/RipV1Response.java diff --git a/src/main/java/cn/x47/RIPService.java b/src/main/java/cn/x47/RIPService.java index efc847f..088570e 100644 --- a/src/main/java/cn/x47/RIPService.java +++ b/src/main/java/cn/x47/RIPService.java @@ -50,7 +50,7 @@ public class RIPService { // 示例:添加本地路由条目 InetAddress localAddress = InetAddress.getByName("10.47.54.0"); InetAddress subnetMask = InetAddress.getByName("255.255.255.0"); - InetAddress nextHop = InetAddress.getByName("192.168.192.10"); + InetAddress nextHop = InetAddress.getByName("0.0.0.0"); RIPEntry entry = new RIPEntry(); entry.setAddressFamily((short) 2); // AF_INET diff --git a/src/main/java/cn/x47/config/Config.java b/src/main/java/cn/x47/config/Config.java index 2340d09..bfd55d7 100644 --- a/src/main/java/cn/x47/config/Config.java +++ b/src/main/java/cn/x47/config/Config.java @@ -2,5 +2,5 @@ package cn.x47.config; public class Config { // 设置协议版本,1 表示 RIP v1,2 表示 RIP v2 - public static final byte RIP_VERSION = 2; + public static final byte RIP_VERSION = 1; } diff --git a/src/main/java/cn/x47/handle/RIPPacketEncoder.java b/src/main/java/cn/x47/handle/RIPPacketEncoder.java index 2cae983..574ce6b 100644 --- a/src/main/java/cn/x47/handle/RIPPacketEncoder.java +++ b/src/main/java/cn/x47/handle/RIPPacketEncoder.java @@ -5,8 +5,8 @@ import cn.x47.model.RIPEntry; import cn.x47.model.RIPPacket; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.MessageToMessageEncoder; import io.netty.channel.socket.DatagramPacket; +import io.netty.handler.codec.MessageToMessageEncoder; import java.net.InetSocketAddress; import java.util.List; @@ -21,18 +21,23 @@ public class RIPPacketEncoder extends MessageToMessageEncoder { // 编码命令和版本 buf.writeByte(msg.getCommand()); buf.writeByte(msg.getVersion()); - buf.writeShort(0); // unused 字段 + buf.writeShort(msg.getUnused()); // unused 字段 // 编码路由条目 for (RIPEntry entry : msg.getEntries()) { buf.writeShort(entry.getAddressFamily()); if (msg.getVersion() == 2) { buf.writeShort(entry.getRouteTag()); + } else if (msg.getVersion() == 1) { + buf.writeShort(0); } buf.writeBytes(entry.getIpAddress().getAddress()); if (msg.getVersion() == 2) { buf.writeBytes(entry.getSubnetMask().getAddress()); buf.writeBytes(entry.getNextHop().getAddress()); + } else if (msg.getVersion() == 1) { + buf.writeInt(0); + buf.writeInt(0); } buf.writeInt(entry.getMetric()); } diff --git a/src/main/java/cn/x47/model/RIPEntry.java b/src/main/java/cn/x47/model/RIPEntry.java index 087bdd7..d944384 100644 --- a/src/main/java/cn/x47/model/RIPEntry.java +++ b/src/main/java/cn/x47/model/RIPEntry.java @@ -6,6 +6,7 @@ import java.net.InetAddress; @Data public class RIPEntry { + // private short addressFamily; private short routeTag; // RIP v2 特有 private InetAddress ipAddress; diff --git a/src/main/java/cn/x47/model/RIPPacket.java b/src/main/java/cn/x47/model/RIPPacket.java index f7f49d6..457e60e 100644 --- a/src/main/java/cn/x47/model/RIPPacket.java +++ b/src/main/java/cn/x47/model/RIPPacket.java @@ -12,7 +12,7 @@ import java.util.List; public class RIPPacket { private byte command; // 1=Request, 2=Response private byte version; // 1=RIP v1, 2=RIP v2 - private short unused; // 未使用,设置为 0 + private short unused = 0; // 未使用,设置为 0 private List entries; // 添加构造方法和 Getter/Setter diff --git a/src/main/java/cn/x47/service/RIPClient.java b/src/main/java/cn/x47/service/RIPClient.java index c3a1a19..cd06cb9 100644 --- a/src/main/java/cn/x47/service/RIPClient.java +++ b/src/main/java/cn/x47/service/RIPClient.java @@ -11,6 +11,9 @@ import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.DatagramChannel; import io.netty.channel.socket.nio.NioDatagramChannel; +import java.net.InetAddress; +import java.net.UnknownHostException; + public class RIPClient { @@ -33,11 +36,14 @@ public class RIPClient { public void sendRipPacket(RIPPacket packet) { try { - ChannelFuture future = bootstrap.bind(0).sync(); + ChannelFuture future = bootstrap.bind(InetAddress.getByName("192.168.123.45"), 520) + .sync(); future.channel().writeAndFlush(packet).sync(); future.channel().close(); } catch (InterruptedException e) { e.printStackTrace(); + } catch (UnknownHostException e) { + throw new RuntimeException(e); } } diff --git a/src/test/java/RipV1PacketBuilder.java b/src/test/java/RipV1PacketBuilder.java new file mode 100644 index 0000000..da5c38f --- /dev/null +++ b/src/test/java/RipV1PacketBuilder.java @@ -0,0 +1,85 @@ +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(); + } +} diff --git a/src/test/java/RipV1Response.java b/src/test/java/RipV1Response.java new file mode 100644 index 0000000..c27705c --- /dev/null +++ b/src/test/java/RipV1Response.java @@ -0,0 +1,66 @@ +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(); + } +}