-
Notifications
You must be signed in to change notification settings - Fork 55
/
tcp_ip.rb
177 lines (150 loc) · 3.34 KB
/
tcp_ip.rb
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
require 'bindata'
# This is a simple protocol analyser for examining IPv4 packets
# captured with libpcap on an ethernet network.
#
# The dump file can be obtained like this:
#
# sudo tcpdump -i eth0 -s 0 -n -w dump.pcap
#
# Present MAC addresses in a human readable way
class MacAddr < BinData::Primitive
array :octets, :type => :uint8, :initial_length => 6
def set(val)
ints = val.split(/\./).collect { |int| int.to_i }
self.octets = ints
end
def get
self.octets.collect { |octet| "%02x" % octet }.join(":")
end
end
# Present IP addresses in a human readable way
class IPAddr < BinData::Primitive
array :octets, :type => :uint8, :initial_length => 4
def set(val)
ints = val.split(/\./).collect { |int| int.to_i }
self.octets = ints
end
def get
self.octets.collect { |octet| "%d" % octet }.join(".")
end
end
# TCP Protocol Data Unit
class TCP_PDU < BinData::Record
endian :big
uint16 :src_port
uint16 :dst_port
uint32 :seq
uint32 :ack_seq
bit4 :doff
bit4 :res1
bit2 :res2
bit1 :urg
bit1 :ack
bit1 :psh
bit1 :rst
bit1 :syn
bit1 :fin
uint16 :window
uint16 :checksum
uint16 :urg_ptr
string :options, :read_length => :options_length_in_bytes
rest :payload
def options_length_in_bytes
(doff - 5 ) * 4
end
end
# UDP Protocol Data Unit
class UDP_PDU < BinData::Record
endian :big
uint16 :src_port
uint16 :dst_port
uint16 :len
uint16 :checksum
rest :payload
end
# IP Protocol Data Unit
class IP_PDU < BinData::Record
endian :big
bit4 :version, :asserted_value => 4
bit4 :header_length
uint8 :tos
uint16 :total_length
uint16 :ident
bit3 :flags
bit13 :frag_offset
uint8 :ttl
uint8 :protocol
uint16 :checksum
ip_addr :src_addr
ip_addr :dest_addr
string :options, :read_length => :options_length_in_bytes
buffer :payload, :length => :payload_length_in_bytes do
choice :payload, :selection => :protocol do
tcp_pdu 6
udp_pdu 17
rest :default
end
end
def header_length_in_bytes
header_length * 4
end
def options_length_in_bytes
header_length_in_bytes - options.rel_offset
end
def payload_length_in_bytes
total_length - header_length_in_bytes
end
end
# Ethernet Frame - NOTE only ipv4 is supported
class Ether < BinData::Record
IPV4 = 0x0800
endian :big
mac_addr :dst
mac_addr :src
uint16 :ether_type
choice :payload, :selection => :ether_type do
ip_pdu IPV4
rest :default
end
end
class Pcap
def initialize(filename)
@filename = filename
end
def each_record
File.open(@filename) do |io|
file = PcapFile.read(io)
file.records.each do |rec|
yield rec.data
end
end
end
class PcapFile < BinData::Record
endian :little
struct :head do
uint32 :magic
uint16 :major
uint16 :minor
int32 :this_zone
uint32 :sig_figs
uint32 :snaplen
uint32 :linktype
end
array :records, :read_until => :eof do
uint32 :ts_sec
uint32 :ts_usec
uint32 :incl_len
uint32 :orig_len
string :data, :length => :incl_len
end
end
end
require 'pp'
unless File.exist?('dump.pcap')
puts "No dump file found. Create one with: sudo tcpdump -i eth0 -s 0 -n -w dump.pcap"
exit 1
end
cap = Pcap.new('dump.pcap')
cap.each_record do |str|
pp Ether.read(str)
end