| 1 |
|
|---|
| 2 |
""" |
|---|
| 3 |
|
|---|
| 4 |
|
|---|
| 5 |
|
|---|
| 6 |
|
|---|
| 7 |
|
|---|
| 8 |
|
|---|
| 9 |
|
|---|
| 10 |
|
|---|
| 11 |
|
|---|
| 12 |
|
|---|
| 13 |
|
|---|
| 14 |
|
|---|
| 15 |
|
|---|
| 16 |
|
|---|
| 17 |
|
|---|
| 18 |
|
|---|
| 19 |
|
|---|
| 20 |
|
|---|
| 21 |
|
|---|
| 22 |
|
|---|
| 23 |
|
|---|
| 24 |
|
|---|
| 25 |
|
|---|
| 26 |
|
|---|
| 27 |
|
|---|
| 28 |
from scapy import * |
|---|
| 29 |
|
|---|
| 30 |
class EigrpIPField(StrField): |
|---|
| 31 |
""" |
|---|
| 32 |
This is a special field type for handling ip addresses of destination networks in internal and |
|---|
| 33 |
external route updates. |
|---|
| 34 |
|
|---|
| 35 |
EIGRP removes zeros from the host portion of the ip address if the netmask is 8, 16 or 24 bits. |
|---|
| 36 |
""" |
|---|
| 37 |
|
|---|
| 38 |
def __init__(self, name, default, fld=None, length_from=None, shift=0): |
|---|
| 39 |
StrField.__init__(self, name, default, shift=shift) |
|---|
| 40 |
self.length_from = length_from |
|---|
| 41 |
if fld is not None or shift != 0: |
|---|
| 42 |
FIELD_LENGTH_MANAGEMENT_DEPRECATION(self.__class__.__name__) |
|---|
| 43 |
self.length_from = lambda pkt,fld=fld,shift=shift: getattr(pkt,fld)-shift |
|---|
| 44 |
|
|---|
| 45 |
def h2i(self, pkt, x): |
|---|
| 46 |
if type(x) is str: |
|---|
| 47 |
try: |
|---|
| 48 |
inet_aton(x) |
|---|
| 49 |
except socket.error: |
|---|
| 50 |
print x |
|---|
| 51 |
x = Net(x) |
|---|
| 52 |
elif type(x) is list: |
|---|
| 53 |
x = [self.h2i(pkt, n) for n in x] |
|---|
| 54 |
return x |
|---|
| 55 |
|
|---|
| 56 |
def i2m(self, pkt, x): |
|---|
| 57 |
x = inet_aton(x) |
|---|
| 58 |
l = self.length_from(pkt) |
|---|
| 59 |
if l <= 8: |
|---|
| 60 |
return x[:1] |
|---|
| 61 |
elif l <= 16: |
|---|
| 62 |
return x[:2] |
|---|
| 63 |
elif l <= 24: |
|---|
| 64 |
return x[:3] |
|---|
| 65 |
else: |
|---|
| 66 |
return x |
|---|
| 67 |
|
|---|
| 68 |
def m2i(self, pkt, x): |
|---|
| 69 |
l = self.length_from(pkt) |
|---|
| 70 |
if l <= 8: |
|---|
| 71 |
x += "\x00\x00\x00" |
|---|
| 72 |
elif l <= 16: |
|---|
| 73 |
x += "\x00\x00" |
|---|
| 74 |
elif l <= 24: |
|---|
| 75 |
x += "\x00" |
|---|
| 76 |
|
|---|
| 77 |
return inet_ntoa(x) |
|---|
| 78 |
|
|---|
| 79 |
def getfield(self, pkt, s): |
|---|
| 80 |
l = self.length_from(pkt) |
|---|
| 81 |
if l <= 8: |
|---|
| 82 |
l = 8 |
|---|
| 83 |
elif l <= 16: |
|---|
| 84 |
l = 16 |
|---|
| 85 |
elif l <= 24: |
|---|
| 86 |
l = 24 |
|---|
| 87 |
else: |
|---|
| 88 |
l = 32 |
|---|
| 89 |
|
|---|
| 90 |
return s[l:], self.m2i(pkt,s[:l]) |
|---|
| 91 |
|
|---|
| 92 |
class EIGRPParam(Packet): |
|---|
| 93 |
name = "EIGRP Parameters" |
|---|
| 94 |
fields_desc = [ XShortField("type", 0x0001), |
|---|
| 95 |
ShortField("len", 12), |
|---|
| 96 |
ByteField("k1", 1), |
|---|
| 97 |
ByteField("k2", 0), |
|---|
| 98 |
ByteField("k3", 1), |
|---|
| 99 |
ByteField("k4", 0), |
|---|
| 100 |
ByteField("k5", 0), |
|---|
| 101 |
ByteField("reserved", 0), |
|---|
| 102 |
ShortField("holdtime", 15) |
|---|
| 103 |
] |
|---|
| 104 |
|
|---|
| 105 |
def guess_payload_class(self, p): |
|---|
| 106 |
return Padding |
|---|
| 107 |
|
|---|
| 108 |
class EIGRPAuthData(Packet): |
|---|
| 109 |
name = "EIGRP Authentication Data" |
|---|
| 110 |
fields_desc = [ XShortField("type", 0x0002), |
|---|
| 111 |
FieldLenField("len", None, "authdata", "!H", adjust=lambda pkt,x: x + 4), |
|---|
| 112 |
ShortField("authtype", 2), |
|---|
| 113 |
ShortField("keysize", 16), |
|---|
| 114 |
IntField("keyid", 1), |
|---|
| 115 |
StrFixedLenField("nullpad", "\x00" * 12, 12), |
|---|
| 116 |
StrLenField("authdata", RandString(36), length_from=lambda pkt: pkt.len - 24), |
|---|
| 117 |
] |
|---|
| 118 |
|
|---|
| 119 |
def guess_payload_class(self, p): |
|---|
| 120 |
return Padding |
|---|
| 121 |
|
|---|
| 122 |
class EIGRPSeq(Packet): |
|---|
| 123 |
name = "EIGRP Sequence" |
|---|
| 124 |
fields_desc = [ XShortField("type", 0x0003), |
|---|
| 125 |
ShortField("len", 9), |
|---|
| 126 |
ByteField("addrlen", 4), |
|---|
| 127 |
IPField("ipaddr", "192.168.0.1") |
|---|
| 128 |
] |
|---|
| 129 |
|
|---|
| 130 |
def guess_payload_class(self, p): |
|---|
| 131 |
return Padding |
|---|
| 132 |
|
|---|
| 133 |
class ShortVersionField(ShortField): |
|---|
| 134 |
def i2repr(self, pkt, x): |
|---|
| 135 |
try: |
|---|
| 136 |
minor = x & 0xff |
|---|
| 137 |
major = (x >> 8) & 0xff |
|---|
| 138 |
except TypeError: |
|---|
| 139 |
return "unknown" |
|---|
| 140 |
else: |
|---|
| 141 |
|
|---|
| 142 |
return "v%s.%s" % (major, minor) |
|---|
| 143 |
|
|---|
| 144 |
|
|---|
| 145 |
class EIGRPSwVer(Packet): |
|---|
| 146 |
name = "EIGRP Software Version" |
|---|
| 147 |
fields_desc = [ XShortField("type", 0x0004), |
|---|
| 148 |
ShortField("len", 8), |
|---|
| 149 |
ShortVersionField("ios", 3072), |
|---|
| 150 |
ShortVersionField("eigrp", 258) |
|---|
| 151 |
] |
|---|
| 152 |
|
|---|
| 153 |
def guess_payload_class(self, p): |
|---|
| 154 |
return Padding |
|---|
| 155 |
|
|---|
| 156 |
class EIGRPNms(Packet): |
|---|
| 157 |
name = "EIGRP Next Multicast Sequence" |
|---|
| 158 |
fields_desc = [ XShortField("type", 0x0005), |
|---|
| 159 |
ShortField("len", 8), |
|---|
| 160 |
IntField("nms", 144) |
|---|
| 161 |
] |
|---|
| 162 |
|
|---|
| 163 |
def guess_payload_class(self, p): |
|---|
| 164 |
return Padding |
|---|
| 165 |
|
|---|
| 166 |
class EIGRPIntRoute(Packet): |
|---|
| 167 |
name = "EIGRP Internal Route" |
|---|
| 168 |
fields_desc = [ XShortField("type", 0x0102), |
|---|
| 169 |
FieldLenField("len", None, "dst", "!H", adjust=lambda pkt,x: x + 25), |
|---|
| 170 |
IPField("nexthop", "192.168.0.0"), |
|---|
| 171 |
IntField("delay", 0), |
|---|
| 172 |
IntField("bandwidth", 0), |
|---|
| 173 |
X3BytesField("MTU", 1500), |
|---|
| 174 |
ByteField("hopcount", 0), |
|---|
| 175 |
ByteField("reliability", 0), |
|---|
| 176 |
ByteField("load", 0), |
|---|
| 177 |
XShortField("reserved", 0), |
|---|
| 178 |
ByteField("prefixlen", 24), |
|---|
| 179 |
EigrpIPField("dst", "", length_from=lambda pkt: pkt.prefixlen), |
|---|
| 180 |
] |
|---|
| 181 |
|
|---|
| 182 |
def guess_payload_class(self, p): |
|---|
| 183 |
return Padding |
|---|
| 184 |
|
|---|
| 185 |
class EIGRPExtRoute(Packet): |
|---|
| 186 |
name = "EIGRP External Route" |
|---|
| 187 |
fields_desc = [ XShortField("type", 0x0103), |
|---|
| 188 |
FieldLenField("len", None, "dst", "!H", adjust=lambda pkt,x: x + 25), |
|---|
| 189 |
IPField("nexthop", "192.168.0.0"), |
|---|
| 190 |
IPField("originrouter", "192.168.0.1"), |
|---|
| 191 |
IntField("originasn", 0), |
|---|
| 192 |
IntField("tag", 0), |
|---|
| 193 |
IntField("externalmetric", 0), |
|---|
| 194 |
ShortField("reserved", 0), |
|---|
| 195 |
ByteField("extprotocolid", 3), |
|---|
| 196 |
XByteField("flags", 0x0), |
|---|
| 197 |
IntField("delay", 0), |
|---|
| 198 |
IntField("bandwidth", 256), |
|---|
| 199 |
X3BytesField("MTU", 1500), |
|---|
| 200 |
ByteField("hopcount", 0), |
|---|
| 201 |
ByteField("reliability", 0), |
|---|
| 202 |
ByteField("load", 0), |
|---|
| 203 |
XShortField("reserved", 0), |
|---|
| 204 |
ByteField("prefixlen", 24), |
|---|
| 205 |
EigrpIPField("dst", "", length_from=lambda pkt: pkt.prefixlen) |
|---|
| 206 |
] |
|---|
| 207 |
|
|---|
| 208 |
def guess_payload_class(self, p): |
|---|
| 209 |
return Padding |
|---|
| 210 |
|
|---|
| 211 |
|
|---|
| 212 |
|
|---|
| 213 |
_eigrp_tlv_cls = { |
|---|
| 214 |
0x0001: "EIGRPParam", |
|---|
| 215 |
0x0002: "EIGRPAuthData", |
|---|
| 216 |
0x0003: "EIGRPSeq", |
|---|
| 217 |
0x0004: "EIGRPSwVer", |
|---|
| 218 |
0x0005: "EIGRPNms", |
|---|
| 219 |
0x0102: "EIGRPIntRoute", |
|---|
| 220 |
0x0103: "EIGRPExtRoute" |
|---|
| 221 |
} |
|---|
| 222 |
|
|---|
| 223 |
class RepeatedTlvListField(PacketListField): |
|---|
| 224 |
def __init__(self, name, default, cls): |
|---|
| 225 |
PacketField.__init__(self, name, default, cls) |
|---|
| 226 |
|
|---|
| 227 |
def getfield(self, pkt, s): |
|---|
| 228 |
lst = [] |
|---|
| 229 |
remain = s |
|---|
| 230 |
while len(remain) > 0: |
|---|
| 231 |
p = self.m2i(pkt,remain) |
|---|
| 232 |
if Padding in p: |
|---|
| 233 |
pad = p[Padding] |
|---|
| 234 |
remain = pad.load |
|---|
| 235 |
del(pad.underlayer.payload) |
|---|
| 236 |
else: |
|---|
| 237 |
remain = "" |
|---|
| 238 |
lst.append(p) |
|---|
| 239 |
return remain,lst |
|---|
| 240 |
|
|---|
| 241 |
def addfield(self, pkt, s, val): |
|---|
| 242 |
return s+reduce(str.__add__, map(str, val),"") |
|---|
| 243 |
|
|---|
| 244 |
def _EIGRPGuessPayloadClass(p, **kargs): |
|---|
| 245 |
cls = Raw |
|---|
| 246 |
if len(p) >= 2: |
|---|
| 247 |
t = struct.unpack("!H", p[:2])[0] |
|---|
| 248 |
clsname = _eigrp_tlv_cls.get(t, "Raw") |
|---|
| 249 |
cls = globals()[clsname] |
|---|
| 250 |
return cls(p, **kargs) |
|---|
| 251 |
|
|---|
| 252 |
_EIGRP_OPCODES = { 1 : "Update", |
|---|
| 253 |
2 : "Request", |
|---|
| 254 |
3 : "Query", |
|---|
| 255 |
4 : "Replay", |
|---|
| 256 |
5 : "Hello" } |
|---|
| 257 |
|
|---|
| 258 |
class EIGRP(Packet): |
|---|
| 259 |
name = "EIGRP" |
|---|
| 260 |
fields_desc = [ ByteField("ver", 2), |
|---|
| 261 |
ByteEnumField("opcode", 5, _EIGRP_OPCODES), |
|---|
| 262 |
XShortField("chksum", None), |
|---|
| 263 |
XIntField("flags", 0), |
|---|
| 264 |
IntField("seq", 0), |
|---|
| 265 |
IntField("ack", 0), |
|---|
| 266 |
IntField("asn", 100), |
|---|
| 267 |
RepeatedTlvListField("tlvlist", [], _EIGRPGuessPayloadClass) |
|---|
| 268 |
] |
|---|
| 269 |
|
|---|
| 270 |
def post_build(self, p, pay): |
|---|
| 271 |
p += pay |
|---|
| 272 |
if self.chksum is None: |
|---|
| 273 |
c = checksum(p) |
|---|
| 274 |
p = p[:2] + chr((c>>8)&0xff)+chr(c&0xff) + p[4:] |
|---|
| 275 |
return p |
|---|
| 276 |
|
|---|
| 277 |
def mysummary(self): |
|---|
| 278 |
return self.sprintf("EIGRP (AS=%EIGRP.asn% Opcode=%EIGRP.opcode% Flags=%EIGRP.flags%)") |
|---|
| 279 |
|
|---|
| 280 |
|
|---|
| 281 |
bind_layers( IP, EIGRP, proto=88) |
|---|
| 282 |
|
|---|
| 283 |
if __name__ == "__main__": |
|---|
| 284 |
interact(mydict=globals(), mybanner="EIGRP") |
|---|
| 285 |
|
|---|