1# SPDX-License-Identifier: GPL-2.0-only
2# This file is part of Scapy
3# See https://scapy.net/ for more information
4# Copyright (C) Philippe Biondi <phil@secdev.org>
5
6"""
7RIP (Routing Information Protocol).
8"""
9
10from scapy.packet import Packet, bind_layers, bind_bottom_up
11from scapy.fields import ByteEnumField, ByteField, ConditionalField, \
12 IPField, IntEnumField, IntField, ShortEnumField, ShortField, \
13 StrFixedLenField, StrLenField
14from scapy.layers.inet import UDP
15
16
17class RIP(Packet):
18 name = "RIP header"
19 fields_desc = [
20 ByteEnumField("cmd", 1, {1: "req", 2: "resp", 3: "traceOn", 4: "traceOff", # noqa: E501
21 5: "sun", 6: "trigReq", 7: "trigResp", 8: "trigAck", # noqa: E501
22 9: "updateReq", 10: "updateResp", 11: "updateAck"}), # noqa: E501
23 ByteField("version", 1),
24 ShortField("null", 0),
25 ]
26
27 def guess_payload_class(self, payload):
28 if payload[:2] == b"\xff\xff":
29 return RIPAuth
30 else:
31 return Packet.guess_payload_class(self, payload)
32
33
34class RIPEntry(RIP):
35 name = "RIP entry"
36 fields_desc = [
37 ShortEnumField("AF", 2, {2: "IP"}),
38 ShortField("RouteTag", 0),
39 IPField("addr", "0.0.0.0"),
40 IPField("mask", "0.0.0.0"),
41 IPField("nextHop", "0.0.0.0"),
42 IntEnumField("metric", 1, {16: "Unreach"}),
43 ]
44
45
46class RIPAuth(Packet):
47 name = "RIP authentication"
48 fields_desc = [
49 ShortEnumField("AF", 0xffff, {0xffff: "Auth"}),
50 ShortEnumField("authtype", 2, {1: "md5authdata", 2: "simple", 3: "md5"}), # noqa: E501
51 ConditionalField(StrFixedLenField("password", None, 16),
52 lambda pkt: pkt.authtype == 2),
53 ConditionalField(ShortField("digestoffset", 0),
54 lambda pkt: pkt.authtype == 3),
55 ConditionalField(ByteField("keyid", 0),
56 lambda pkt: pkt.authtype == 3),
57 ConditionalField(ByteField("authdatalen", 0),
58 lambda pkt: pkt.authtype == 3),
59 ConditionalField(IntField("seqnum", 0),
60 lambda pkt: pkt.authtype == 3),
61 ConditionalField(StrFixedLenField("zeropad", None, 8),
62 lambda pkt: pkt.authtype == 3),
63 ConditionalField(StrLenField("authdata", None,
64 length_from=lambda pkt: pkt.md5datalen),
65 lambda pkt: pkt.authtype == 1)
66 ]
67
68 def pre_dissect(self, s):
69 if s[2:4] == b"\x00\x01":
70 self.md5datalen = len(s) - 4
71
72 return s
73
74
75bind_bottom_up(UDP, RIP, dport=520)
76bind_bottom_up(UDP, RIP, sport=520)
77bind_layers(UDP, RIP, sport=520, dport=520)
78bind_layers(RIP, RIPEntry,)
79bind_layers(RIPEntry, RIPEntry,)
80bind_layers(RIPAuth, RIPEntry,)