packetfu 1.1.1 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. data/{README → README.rdoc} +2 -2
  2. metadata +58 -94
  3. data/INSTALL +0 -40
  4. data/LICENSE +0 -28
  5. data/examples/100kpackets.rb +0 -41
  6. data/examples/ackscan.rb +0 -38
  7. data/examples/arp.rb +0 -60
  8. data/examples/arphood.rb +0 -59
  9. data/examples/dissect_thinger.rb +0 -22
  10. data/examples/ethernet.rb +0 -10
  11. data/examples/examples.rb +0 -3
  12. data/examples/ids.rb +0 -4
  13. data/examples/idsv2.rb +0 -6
  14. data/examples/new-simple-stats.rb +0 -52
  15. data/examples/oui.txt +0 -84177
  16. data/examples/packetfu-shell.rb +0 -113
  17. data/examples/simple-sniffer.rb +0 -40
  18. data/examples/simple-stats.rb +0 -50
  19. data/examples/slammer.rb +0 -33
  20. data/examples/uniqpcap.rb +0 -15
  21. data/lib/packetfu.rb +0 -147
  22. data/lib/packetfu/capture.rb +0 -169
  23. data/lib/packetfu/config.rb +0 -58
  24. data/lib/packetfu/inject.rb +0 -65
  25. data/lib/packetfu/packet.rb +0 -533
  26. data/lib/packetfu/pcap.rb +0 -594
  27. data/lib/packetfu/protos/arp.rb +0 -268
  28. data/lib/packetfu/protos/eth.rb +0 -296
  29. data/lib/packetfu/protos/hsrp.rb +0 -206
  30. data/lib/packetfu/protos/icmp.rb +0 -179
  31. data/lib/packetfu/protos/invalid.rb +0 -55
  32. data/lib/packetfu/protos/ip.rb +0 -378
  33. data/lib/packetfu/protos/ipv6.rb +0 -250
  34. data/lib/packetfu/protos/tcp.rb +0 -1127
  35. data/lib/packetfu/protos/udp.rb +0 -240
  36. data/lib/packetfu/structfu.rb +0 -294
  37. data/lib/packetfu/utils.rb +0 -194
  38. data/lib/packetfu/version.rb +0 -50
  39. data/test/all_tests.rb +0 -41
  40. data/test/arp_test.pcap +0 -0
  41. data/test/eth_test.pcap +0 -0
  42. data/test/ethpacket_spec.rb +0 -74
  43. data/test/icmp_test.pcap +0 -0
  44. data/test/ip_test.pcap +0 -0
  45. data/test/packet_spec.rb +0 -73
  46. data/test/packet_subclasses_spec.rb +0 -13
  47. data/test/packetfu_spec.rb +0 -90
  48. data/test/ptest.rb +0 -16
  49. data/test/sample-ipv6.pcap +0 -0
  50. data/test/sample.pcap +0 -0
  51. data/test/sample2.pcap +0 -0
  52. data/test/sample_hsrp_pcapr.cap +0 -0
  53. data/test/structfu_spec.rb +0 -335
  54. data/test/tcp_spec.rb +0 -101
  55. data/test/tcp_test.pcap +0 -0
  56. data/test/test_arp.rb +0 -135
  57. data/test/test_eth.rb +0 -91
  58. data/test/test_hsrp.rb +0 -20
  59. data/test/test_icmp.rb +0 -54
  60. data/test/test_inject.rb +0 -31
  61. data/test/test_invalid.rb +0 -28
  62. data/test/test_ip.rb +0 -69
  63. data/test/test_ip6.rb +0 -68
  64. data/test/test_octets.rb +0 -37
  65. data/test/test_packet.rb +0 -174
  66. data/test/test_pcap.rb +0 -209
  67. data/test/test_structfu.rb +0 -112
  68. data/test/test_tcp.rb +0 -327
  69. data/test/test_udp.rb +0 -73
  70. data/test/udp_test.pcap +0 -0
  71. data/test/vlan-pcapr.cap +0 -0
@@ -1,250 +0,0 @@
1
- module PacketFu
2
-
3
- # AddrIpv6 handles addressing for IPv6Header
4
- #
5
- # ==== Header Definition
6
- #
7
- # Int32 :a1
8
- # Int32 :a2
9
- # Int32 :a3
10
- # Int32 :a4
11
- class AddrIpv6 < Struct.new(:a1, :a2, :a3, :a4)
12
-
13
- include StructFu
14
-
15
- def initialize(args={})
16
- super(
17
- Int32.new(args[:a1]),
18
- Int32.new(args[:a2]),
19
- Int32.new(args[:a3]),
20
- Int32.new(args[:a4]))
21
- end
22
-
23
- # Returns the address in string format.
24
- def to_s
25
- self.to_a.map {|x| x.to_s}.join
26
- end
27
-
28
- # Returns the address as a fairly ginormous integer.
29
- def to_i
30
- (a1.to_i << 96) + (a2.to_i << 64) + (a3.to_i << 32) + a4.to_i
31
- end
32
-
33
- # Returns the address as a colon-delimited hex string.
34
- def to_x
35
- IPAddr.new(self.to_i, Socket::AF_INET6).to_s
36
- end
37
-
38
- # Reads in a string and casts it as an IPv6 address
39
- def read(str)
40
- force_binary(str)
41
- return self if str.nil?
42
- self[:a1].read str[0,4]
43
- self[:a2].read str[4,4]
44
- self[:a3].read str[8,4]
45
- self[:a4].read str[12,4]
46
- self
47
- end
48
-
49
- # Reads in a colon-delimited hex string and casts it as an IPv6 address.
50
- def read_x(str)
51
- addr = IPAddr.new(str).to_i
52
- self[:a1]=Int32.new(addr >> 96)
53
- self[:a2]=Int32.new((addr & 0x00000000ffffffff0000000000000000) >> 64)
54
- self[:a3]=Int32.new((addr & 0x0000000000000000ffffffff00000000) >> 32)
55
- self[:a4]=Int32.new(addr & 0x000000000000000000000000ffffffff)
56
- self
57
- end
58
-
59
- end
60
-
61
- # IPv6Header is complete IPv6 struct, used in IPv6Packet.
62
- #
63
- # ==== Header Definition
64
- #
65
- # Fixnum (4 bits) :ipv6_v Default: 6 # Versiom
66
- # Fixnum (8 bits) :ipv6_class Defualt: 0 # Class
67
- # Fixnum (20 bits) :ipv6_label Defualt: 0 # Label
68
- # Int16 :ipv6_len Default: calc # Payload length
69
- # Int8 :ipv6_next # Next Header
70
- # Int8 :ipv6_hop Default: 0xff # Hop limit
71
- # AddrIpv6 :ipv6_src
72
- # AddrIpv6 :ipv6_dst
73
- # String :body
74
- class IPv6Header < Struct.new(:ipv6_v, :ipv6_class, :ipv6_label,
75
- :ipv6_len, :ipv6_next, :ipv6_hop,
76
- :ipv6_src, :ipv6_dst, :body)
77
- include StructFu
78
-
79
- def initialize(args={})
80
- super(
81
- (args[:ipv6_v] || 6),
82
- (args[:ipv6_class] || 0),
83
- (args[:ipv6_label] || 0),
84
- Int16.new(args[:ipv6_len]),
85
- Int8.new(args[:ipv6_next]),
86
- Int8.new(args[:ipv6_hop] || 0xff),
87
- AddrIpv6.new.read(args[:ipv6_src] || ("\x00" * 16)),
88
- AddrIpv6.new.read(args[:ipv6_dst] || ("\x00" * 16)),
89
- StructFu::String.new.read(args[:body])
90
- )
91
- end
92
-
93
- # Returns the object in string form.
94
- def to_s
95
- bytes_v_class_label = [(self.ipv6_v << 28) +
96
- (self.ipv6_class << 20) +
97
- self.ipv6_label].pack("N")
98
- bytes_v_class_label + (self.to_a[3,6].map {|x| x.to_s}.join)
99
- end
100
-
101
- # Reads a string to populate the object.
102
- def read(str)
103
- force_binary(str)
104
- return self if str.nil?
105
- self[:ipv6_v] = str[0,1].unpack("C").first >> 4
106
- self[:ipv6_class] = (str[0,2].unpack("n").first & 0x0ff0) >> 4
107
- self[:ipv6_label] = str[0,4].unpack("N").first & 0x000fffff
108
- self[:ipv6_len].read(str[4,2])
109
- self[:ipv6_next].read(str[6,1])
110
- self[:ipv6_hop].read(str[7,1])
111
- self[:ipv6_src].read(str[8,16])
112
- self[:ipv6_dst].read(str[24,16])
113
- self[:body].read(str[40,str.size]) if str.size > 40
114
- self
115
- end
116
-
117
- # Setter for the version (usually, 6).
118
- def ipv6_v=(i); self[:ip_v] = i.to_i; end
119
- # Getter for the version (usually, 6).
120
- def ipv6_v; self[:ipv6_v].to_i; end
121
- # Setter for the traffic class.
122
- def ipv6_class=(i); self[:ip_class] = i.to_i; end
123
- # Getter for the traffic class.
124
- def ipv6_class; self[:ipv6_class].to_i; end
125
- # Setter for the flow label.
126
- def ipv6_label=(i); self[:ip_label] = i.to_i; end
127
- # Getter for the flow label.
128
- def ipv6_label; self[:ipv6_label].to_i; end
129
- # Setter for the payload length.
130
- def ipv6_len=(i); typecast i; end
131
- # Getter for the payload length.
132
- def ipv6_len; self[:ipv6_len].to_i; end
133
- # Setter for the next protocol header.
134
- def ipv6_next=(i); typecast i; end
135
- # Getter for the next protocol header.
136
- def ipv6_next; self[:ipv6_next].to_i; end
137
- # Setter for the hop limit.
138
- def ipv6_hop=(i); typecast i; end
139
- # Getter for the hop limit.
140
- def ipv6_hop; self[:ipv6_hop].to_i; end
141
- # Setter for the source address.
142
- def ipv6_src=(i); typecast i; end
143
- # Getter for the source address.
144
- def ipv6_src; self[:ipv6_src].to_i; end
145
- # Setter for the destination address.
146
- def ipv6_dst=(i); typecast i; end
147
- # Getter for the destination address.
148
- def ipv6_dst; self[:ipv6_dst].to_i; end
149
-
150
- # Calculates the payload length.
151
- def ipv6_calc_len
152
- self[:ipv6_len] = body.to_s.length
153
- end
154
-
155
- # Recalculates the calculatable fields for this object.
156
- def ipv6_recalc(arg=:all)
157
- case arg
158
- when :ipv6_len
159
- ipv6_calc_len
160
- when :all
161
- ipv6_recalc(:len)
162
- end
163
- end
164
-
165
- # Get the source address in a more readable form.
166
- def ipv6_saddr
167
- self[:ipv6_src].to_x
168
- end
169
-
170
- # Set the source address in a more readable form.
171
- def ipv6_saddr=(str)
172
- self[:ipv6_src].read_x(str)
173
- end
174
-
175
- # Get the destination address in a more readable form.
176
- def ipv6_daddr
177
- self[:ipv6_dst].to_x
178
- end
179
-
180
- # Set the destination address in a more readable form.
181
- def ipv6_daddr=(str)
182
- self[:ipv6_dst].read_x(str)
183
- end
184
-
185
- # Readability aliases
186
-
187
- alias :ipv6_src_readable :ipv6_saddr
188
- alias :ipv6_dst_readable :ipv6_daddr
189
-
190
- end # class IPv6Header
191
-
192
- # IPv6Packet is used to construct IPv6 Packets. They contain an EthHeader and an IPv6Header, and in
193
- # the distant, unknowable future, will take interesting IPv6ish payloads.
194
- #
195
- # This mostly complete, but not very useful. It's intended primarily as an example protocol.
196
- #
197
- # == Parameters
198
- #
199
- # :eth
200
- # A pre-generated EthHeader object.
201
- # :ip
202
- # A pre-generated IPHeader object.
203
- # :flavor
204
- # TODO: Sets the "flavor" of the IPv6 packet. No idea what this will look like, haven't done much IPv6 fingerprinting.
205
- # :config
206
- # A hash of return address details, often the output of Utils.whoami?
207
- class IPv6Packet < Packet
208
-
209
- attr_accessor :eth_header, :ipv6_header
210
-
211
- def self.can_parse?(str)
212
- return false unless EthPacket.can_parse? str
213
- return false unless str.size >= 54
214
- return false unless str[12,2] == "\x86\xdd"
215
- true
216
- end
217
-
218
- def read(str=nil,args={})
219
- raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
220
- @eth_header.read(str)
221
- @ipv6_header.read(str[14,str.size])
222
- @eth_header.body = @ipv6_header
223
- super(args)
224
- self
225
- end
226
-
227
- def initialize(args={})
228
- @eth_header = (args[:eth] || EthHeader.new)
229
- @ipv6_header = (args[:ipv6] || IPv6Header.new)
230
- @eth_header.eth_proto = 0x86dd
231
- @eth_header.body=@ipv6_header
232
- @headers = [@eth_header, @ipv6_header]
233
- super
234
- end
235
-
236
- # Peek provides summary data on packet contents.
237
- def peek(args={})
238
- peek_data = ["6 "]
239
- peek_data << "%-5d" % self.to_s.size
240
- peek_data << "%-31s" % self.ipv6_saddr
241
- peek_data << "-> "
242
- peek_data << "%-31s" % self.ipv6_daddr
243
- peek_data << " N:"
244
- peek_data << self.ipv6_next.to_s(16)
245
- peek_data.join
246
- end
247
-
248
- end
249
-
250
- end
@@ -1,1127 +0,0 @@
1
- module PacketFu
2
-
3
- # Implements the Explict Congestion Notification for TCPHeader.
4
- #
5
- # ==== Header Definition
6
- #
7
- #
8
- # Fixnum (1 bit) :n
9
- # Fixnum (1 bit) :c
10
- # Fixnum (1 bit) :e
11
- class TcpEcn < Struct.new(:n, :c, :e)
12
-
13
- include StructFu
14
-
15
- def initialize(args={})
16
- super(args[:n], args[:c], args[:e]) if args
17
- end
18
-
19
- # Returns the TcpEcn field as an integer... even though it's going
20
- # to be split across a byte boundary.
21
- def to_i
22
- (n.to_i << 2) + (c.to_i << 1) + e.to_i
23
- end
24
-
25
- # Reads a string to populate the object.
26
- def read(str)
27
- force_binary(str)
28
- return self if str.nil? || str.size < 2
29
- if 1.respond_to? :ord
30
- byte1 = str[0].ord
31
- byte2 = str[1].ord
32
- else
33
- byte1 = str[0]
34
- byte2 = str[1]
35
- end
36
- self[:n] = byte1 & 0b00000001 == 0b00000001 ? 1 : 0
37
- self[:c] = byte2 & 0b10000000 == 0b10000000 ? 1 : 0
38
- self[:e] = byte2 & 0b01000000 == 0b01000000 ? 1 : 0
39
- self
40
- end
41
-
42
- end
43
-
44
- # Implements the Header Length for TCPHeader.
45
- #
46
- # ==== Header Definition
47
- #
48
- # Fixnum (4 bits) :hlen
49
- class TcpHlen < Struct.new(:hlen)
50
-
51
- include StructFu
52
-
53
- def initialize(args={})
54
- super(args[:hlen])
55
- end
56
-
57
- # Returns the TcpHlen field as an integer. Note these will become the high
58
- # bits at the TCP header's offset, even though the lower 4 bits
59
- # will be further chopped up.
60
- def to_i
61
- hlen.to_i & 0b1111
62
- end
63
-
64
- # Reads a string to populate the object.
65
- def read(str)
66
- force_binary(str)
67
- return self if str.nil? || str.size.zero?
68
- if 1.respond_to? :ord
69
- self[:hlen] = (str[0].ord & 0b11110000) >> 4
70
- else
71
- self[:hlen] = (str[0] & 0b11110000) >> 4
72
- end
73
- self
74
- end
75
-
76
- # Returns the object in string form.
77
- def to_s
78
- [self.to_i].pack("C")
79
- end
80
-
81
- end
82
-
83
- # Implements the Reserved bits for TCPHeader.
84
- #
85
- # ==== Header Definition
86
- #
87
- #
88
- # Fixnum (1 bit) :r1
89
- # Fixnum (1 bit) :r2
90
- # Fixnum (1 bit) :r3
91
- class TcpReserved < Struct.new(:r1, :r2, :r3)
92
-
93
- include StructFu
94
-
95
- def initialize(args={})
96
- super(
97
- args[:r1] || 0,
98
- args[:r2] || 0,
99
- args[:r3] || 0) if args.kind_of? Hash
100
- end
101
-
102
- # Returns the Reserved field as an integer.
103
- def to_i
104
- (r1.to_i << 2) + (r2.to_i << 1) + r3.to_i
105
- end
106
-
107
- # Reads a string to populate the object.
108
- def read(str)
109
- force_binary(str)
110
- return self if str.nil? || str.size.zero?
111
- if 1.respond_to? :ord
112
- byte = str[0].ord
113
- else
114
- byte = str[0]
115
- end
116
- self[:r1] = byte & 0b00000100 == 0b00000100 ? 1 : 0
117
- self[:r2] = byte & 0b00000010 == 0b00000010 ? 1 : 0
118
- self[:r3] = byte & 0b00000001 == 0b00000001 ? 1 : 0
119
- self
120
- end
121
-
122
- end
123
-
124
- # Implements flags for TCPHeader.
125
- #
126
- # ==== Header Definition
127
- #
128
- # Fixnum (1 bit) :urg
129
- # Fixnum (1 bit) :ack
130
- # Fixnum (1 bit) :psh
131
- # Fixnum (1 bit) :rst
132
- # Fixnum (1 bit) :syn
133
- # Fixnum (1 bit) :fin
134
- #
135
- # Flags can typically be set by setting them either to 1 or 0, or to true or false.
136
- class TcpFlags < Struct.new(:urg, :ack, :psh, :rst, :syn, :fin)
137
-
138
- include StructFu
139
-
140
- def initialize(args={})
141
- # This technique attemts to ensure that flags are always 0 (off)
142
- # or 1 (on). Statements like nil and false shouldn't be lurking in here.
143
- if args.nil? || args.size.zero?
144
- super( 0, 0, 0, 0, 0, 0)
145
- else
146
- super(
147
- (args[:urg] ? 1 : 0),
148
- (args[:ack] ? 1 : 0),
149
- (args[:psh] ? 1 : 0),
150
- (args[:rst] ? 1 : 0),
151
- (args[:syn] ? 1 : 0),
152
- (args[:fin] ? 1 : 0)
153
- )
154
- end
155
- end
156
-
157
- # Returns the TcpFlags as an integer.
158
- # Also not a great candidate for to_s due to the short bitspace.
159
- def to_i
160
- (urg.to_i << 5) + (ack.to_i << 4) + (psh.to_i << 3) +
161
- (rst.to_i << 2) + (syn.to_i << 1) + fin.to_i
162
- end
163
-
164
- # Helper to determine if this flag is a 1 or a 0.
165
- def zero_or_one(i=0)
166
- if i == 0 || i == false || i == nil
167
- 0
168
- else
169
- 1
170
- end
171
- end
172
-
173
- # Setter for the Urgent flag.
174
- def urg=(i); self[:urg] = zero_or_one(i); end
175
- # Setter for the Acknowlege flag.
176
- def ack=(i); self[:ack] = zero_or_one(i); end
177
- # Setter for the Push flag.
178
- def psh=(i); self[:psh] = zero_or_one(i); end
179
- # Setter for the Reset flag.
180
- def rst=(i); self[:rst] = zero_or_one(i); end
181
- # Setter for the Synchronize flag.
182
- def syn=(i); self[:syn] = zero_or_one(i); end
183
- # Setter for the Finish flag.
184
- def fin=(i); self[:fin] = zero_or_one(i); end
185
-
186
- # Reads a string to populate the object.
187
- def read(str)
188
- force_binary(str)
189
- return self if str.nil?
190
- if 1.respond_to? :ord
191
- byte = str[0].ord
192
- else
193
- byte = str[0]
194
- end
195
- self[:urg] = byte & 0b00100000 == 0b00100000 ? 1 : 0
196
- self[:ack] = byte & 0b00010000 == 0b00010000 ? 1 : 0
197
- self[:psh] = byte & 0b00001000 == 0b00001000 ? 1 : 0
198
- self[:rst] = byte & 0b00000100 == 0b00000100 ? 1 : 0
199
- self[:syn] = byte & 0b00000010 == 0b00000010 ? 1 : 0
200
- self[:fin] = byte & 0b00000001 == 0b00000001 ? 1 : 0
201
- self
202
- end
203
-
204
- end
205
-
206
- end
207
-
208
- module PacketFu
209
-
210
- # TcpOption is the base class for all TCP options. Note that TcpOption#len
211
- # returns the size of the entire option, while TcpOption#optlen is the struct
212
- # for the TCP Option Length field.
213
- #
214
- # Subclassed options should set the correct TcpOption#kind by redefining
215
- # initialize. They should also deal with various value types there by setting
216
- # them explicitly with an accompanying StructFu#typecast for the setter.
217
- #
218
- # By default, values are presumed to be strings, unless they are Numeric, in
219
- # which case a guess is made to the width of the Numeric based on the given
220
- # optlen.
221
- #
222
- # Note that normally, optlen is /not/ enforced for directly setting values,
223
- # so the user is perfectly capable of setting incorrect lengths.
224
- class TcpOption < Struct.new(:kind, :optlen, :value)
225
-
226
- include StructFu
227
-
228
- def initialize(args={})
229
- super(
230
- Int8.new(args[:kind]),
231
- Int8.new(args[:optlen])
232
- )
233
- if args[:value].kind_of? Numeric
234
- self[:value] = case args[:optlen]
235
- when 3; Int8.new(args[:value])
236
- when 4; Int16.new(args[:value])
237
- when 6; Int32.new(args[:value])
238
- else; StructFu::String.new.read(args[:value])
239
- end
240
- else
241
- self[:value] = StructFu::String.new.read(args[:value])
242
- end
243
- end
244
-
245
- # Returns the object in string form.
246
- def to_s
247
- self[:kind].to_s +
248
- (self[:optlen].value.nil? ? nil : self[:optlen]).to_s +
249
- (self[:value].nil? ? nil : self[:value]).to_s
250
- end
251
-
252
- # Reads a string to populate the object.
253
- def read(str)
254
- force_binary(str)
255
- return self if str.nil?
256
- self[:kind].read(str[0,1])
257
- if str[1,1]
258
- self[:optlen].read(str[1,1])
259
- if str[2,1] && optlen.value > 2
260
- self[:value].read(str[2,optlen.value-2])
261
- end
262
- end
263
- self
264
- end
265
-
266
- # The default decode for an unknown option. Known options should redefine this.
267
- def decode
268
- unk = "unk-#{self.kind.to_i}"
269
- (self[:optlen].to_i > 2 && self[:value].to_s.size > 1) ? [unk,self[:value]].join(":") : unk
270
- end
271
-
272
- # Setter for the "kind" byte of this option.
273
- def kind=(i); typecast i; end
274
- # Setter for the "option length" byte for this option.
275
- def optlen=(i); typecast i; end
276
-
277
- # Setter for the value of this option.
278
- def value=(i)
279
- if i.kind_of? Numeric
280
- typecast i
281
- elsif i.respond_to? :to_s
282
- self[:value] = i
283
- else
284
- self[:value] = ''
285
- end
286
- end
287
-
288
- # Generally, encoding a value is going to be just a read. Some
289
- # options will treat things a little differently; TS for example,
290
- # takes two values and concatenates them.
291
- def encode(str)
292
- self[:value] = self.class.new(:value => str).value
293
- end
294
-
295
- # Returns true if this option has an optlen. Some don't.
296
- def has_optlen?
297
- (kind.value && kind.value < 2) ? false : true
298
- end
299
-
300
- # Returns true if this option has a value. Some don't.
301
- def has_value?
302
- (value.respond_to? :to_s && value.to_s.size > 0) ? false : true
303
- end
304
-
305
- # End of Line option. Usually used to terminate a string of options.
306
- #
307
- # http://www.networksorcery.com/enp/protocol/tcp/option000.htm
308
- class EOL < TcpOption
309
- def initialize(args={})
310
- super(
311
- args.merge(:kind => 0)
312
- )
313
- end
314
-
315
- def decode
316
- "EOL"
317
- end
318
-
319
- end
320
-
321
- # No Operation option. Usually used to pad out options to fit a 4-byte alignment.
322
- #
323
- # http://www.networksorcery.com/enp/protocol/tcp/option001.htm
324
- class NOP < TcpOption
325
- def initialize(args={})
326
- super(
327
- args.merge(:kind => 1)
328
- )
329
- end
330
-
331
- def decode
332
- "NOP"
333
- end
334
-
335
- end
336
-
337
- # Maximum Segment Size option.
338
- #
339
- # http://www.networksorcery.com/enp/protocol/tcp/option002.htm
340
- class MSS < TcpOption
341
- def initialize(args={})
342
- super(
343
- args.merge(:kind => 2,
344
- :optlen => 4
345
- )
346
- )
347
- self[:value] = Int16.new(args[:value])
348
- end
349
-
350
- def value=(i); typecast i; end
351
-
352
- # MSS options with lengths other than 4 are malformed.
353
- def decode
354
- if self[:optlen].to_i == 4
355
- "MSS:#{self[:value].to_i}"
356
- else
357
- "MSS-bad:#{self[:value]}"
358
- end
359
- end
360
-
361
- end
362
-
363
- # Window Size option.
364
- #
365
- # http://www.networksorcery.com/enp/protocol/tcp/option003.htm
366
- class WS < TcpOption
367
- def initialize(args={})
368
- super(
369
- args.merge(:kind => 3,
370
- :optlen => 3
371
- )
372
- )
373
- self[:value] = Int8.new(args[:value])
374
- end
375
-
376
- def value=(i); typecast i; end
377
-
378
- # WS options with lengths other than 3 are malformed.
379
- def decode
380
- if self[:optlen].to_i == 3
381
- "WS:#{self[:value].to_i}"
382
- else
383
- "WS-bad:#{self[:value]}"
384
- end
385
- end
386
-
387
- end
388
-
389
- # Selective Acknowlegment OK option.
390
- #
391
- # http://www.networksorcery.com/enp/protocol/tcp/option004.htm
392
- class SACKOK < TcpOption
393
- def initialize(args={})
394
- super(
395
- args.merge(:kind => 4,
396
- :optlen => 2)
397
- )
398
- end
399
-
400
- # SACKOK options with sizes other than 2 are malformed.
401
- def decode
402
- if self[:optlen].to_i == 2
403
- "SACKOK"
404
- else
405
- "SACKOK-bad:#{self[:value]}"
406
- end
407
- end
408
-
409
- end
410
-
411
- # Selective Acknowledgement option.
412
- #
413
- # http://www.networksorcery.com/enp/protocol/tcp/option004.htm
414
- #
415
- # Note that SACK always takes its optlen from the size of the string.
416
- class SACK < TcpOption
417
- def initialize(args={})
418
- super(
419
- args.merge(:kind => 5,
420
- :optlen => ((args[:value] || "").size + 2)
421
- )
422
- )
423
- end
424
-
425
- def optlen=(i); typecast i; end
426
-
427
- def value=(i)
428
- self[:optlen] = Int8.new(i.to_s.size + 2)
429
- self[:value] = StructFu::String.new(i)
430
- end
431
-
432
- def decode
433
- "SACK:#{self[:value]}"
434
- end
435
-
436
- def encode(str)
437
- temp_obj = self.class.new(:value => str)
438
- self[:value] = temp_obj.value
439
- self[:optlen] = temp_obj.optlen.value
440
- self
441
- end
442
-
443
- end
444
-
445
- # Echo option.
446
- #
447
- # http://www.networksorcery.com/enp/protocol/tcp/option006.htm
448
- class ECHO < TcpOption
449
- def initialize(args={})
450
- super(
451
- args.merge(:kind => 6,
452
- :optlen => 6
453
- )
454
- )
455
- end
456
-
457
- # ECHO options with lengths other than 6 are malformed.
458
- def decode
459
- if self[:optlen].to_i == 6
460
- "ECHO:#{self[:value]}"
461
- else
462
- "ECHO-bad:#{self[:value]}"
463
- end
464
- end
465
-
466
- end
467
-
468
- # Echo Reply option.
469
- #
470
- # http://www.networksorcery.com/enp/protocol/tcp/option007.htm
471
- class ECHOREPLY < TcpOption
472
- def initialize(args={})
473
- super(
474
- args.merge(:kind => 7,
475
- :optlen => 6
476
- )
477
- )
478
- end
479
-
480
- # ECHOREPLY options with lengths other than 6 are malformed.
481
- def decode
482
- if self[:optlen].to_i == 6
483
- "ECHOREPLY:#{self[:value]}"
484
- else
485
- "ECHOREPLY-bad:#{self[:value]}"
486
- end
487
- end
488
-
489
- end
490
-
491
- # Timestamp option
492
- #
493
- # http://www.networksorcery.com/enp/protocol/tcp/option008.htm
494
- class TS < TcpOption
495
- def initialize(args={})
496
- super(
497
- args.merge(:kind => 8,
498
- :optlen => 10
499
- )
500
- )
501
- self[:value] = StructFu::String.new.read(args[:value] || "\x00" * 8)
502
- end
503
-
504
- # TS options with lengths other than 10 are malformed.
505
- def decode
506
- if self[:optlen].to_i == 10
507
- val1,val2 = self[:value].unpack("NN")
508
- "TS:#{val1};#{val2}"
509
- else
510
- "TS-bad:#{self[:value]}"
511
- end
512
- end
513
-
514
- # TS options are in the format of "TS:[timestamp value];[timestamp secret]" Both
515
- # should be written as decimal numbers.
516
- def encode(str)
517
- if str =~ /^([0-9]+);([0-9]+)$/
518
- tsval,tsecr = str.split(";").map {|x| x.to_i}
519
- if tsval <= 0xffffffff && tsecr <= 0xffffffff
520
- self[:value] = StructFu::String.new([tsval,tsecr].pack("NN"))
521
- else
522
- self[:value] = StructFu::String.new(str)
523
- end
524
- else
525
- self[:value] = StructFu::String.new(str)
526
- end
527
- end
528
-
529
- end
530
-
531
- end
532
-
533
- class TcpOptions < Array
534
-
535
- include StructFu
536
-
537
- # If args[:pad] is set, the options line is automatically padded out
538
- # with NOPs.
539
- def to_s(args={})
540
- opts = self.map {|x| x.to_s}.join
541
- if args[:pad]
542
- unless (opts.size % 4).zero?
543
- (4 - (opts.size % 4)).times { opts << "\x01" }
544
- end
545
- end
546
- opts
547
- end
548
-
549
- # Reads a string to populate the object.
550
- def read(str)
551
- self.clear
552
- PacketFu.force_binary(str)
553
- return self if(!str.respond_to? :to_s || str.nil?)
554
- i = 0
555
- while i < str.to_s.size
556
- this_opt = case str[i,1].unpack("C").first
557
- when 0; TcpOption::EOL.new
558
- when 1; TcpOption::NOP.new
559
- when 2; TcpOption::MSS.new
560
- when 3; TcpOption::WS.new
561
- when 4; TcpOption::SACKOK.new
562
- when 5; TcpOption::SACK.new
563
- when 6; TcpOption::ECHO.new
564
- when 7; TcpOption::ECHOREPLY.new
565
- when 8; TcpOption::TS.new
566
- else; TcpOption.new
567
- end
568
- this_opt.read str[i,str.size]
569
- unless this_opt.has_optlen?
570
- this_opt.value = nil
571
- this_opt.optlen = nil
572
- end
573
- self << this_opt
574
- i += this_opt.sz
575
- end
576
- self
577
- end
578
-
579
- # Decode parses the TcpOptions object's member options, and produces a
580
- # human-readable string by iterating over each element's decode() function.
581
- # If TcpOptions elements were not initially created as TcpOptions, an
582
- # attempt will be made to convert them.
583
- #
584
- # The output of decode is suitable as input for TcpOptions#encode.
585
- def decode
586
- decoded = self.map do |x|
587
- if x.kind_of? TcpOption
588
- x.decode
589
- else
590
- x = TcpOptions.new.read(x).decode
591
- end
592
- end
593
- decoded.join(",")
594
- end
595
-
596
- # Encode takes a human-readable string and appends the corresponding
597
- # binary options to the TcpOptions object. To completely replace the contents
598
- # of the object, use TcpOptions#encode! instead.
599
- #
600
- # Options are comma-delimited, and are identical to the output of the
601
- # TcpOptions#decode function. Note that the syntax can be unforgiving, so
602
- # it may be easier to create the subclassed TcpOptions themselves directly,
603
- # but this method can be less typing if you know what you're doing.
604
- #
605
- # Note that by using TcpOptions#encode, strings supplied as values which
606
- # can be converted to numbers will be converted first.
607
- #
608
- # === Example
609
- #
610
- # t = TcpOptions.new
611
- # t.encode("MS:1460,WS:6")
612
- # t.to_s # => "\002\004\005\264\002\003\006"
613
- # t.encode("NOP")
614
- # t.to_s # => "\002\004\005\264\002\003\006\001"
615
- def encode(str)
616
- opts = str.split(/[\s]*,[\s]*/)
617
- opts.each do |o|
618
- kind,value = o.split(/[\s]*:[\s]*/)
619
- klass = TcpOption.const_get(kind.upcase)
620
- value = value.to_i if value =~ /^[0-9]+$/
621
- this_opt = klass.new
622
- this_opt.encode(value)
623
- self << this_opt
624
- end
625
- self
626
- end
627
-
628
- # Like TcpOption#encode, except the entire contents are replaced.
629
- def encode!(str)
630
- self.clear if self.size > 0
631
- encode(str)
632
- end
633
-
634
- end
635
-
636
- end
637
-
638
- module PacketFu
639
-
640
- # TCPHeader is a complete TCP struct, used in TCPPacket. Most IP traffic is TCP-based, by
641
- # volume.
642
- #
643
- # For more on TCP packets, see http://www.networksorcery.com/enp/protocol/tcp.htm
644
- #
645
- # ==== Header Definition
646
- #
647
- # Int16 :tcp_src Default: random
648
- # Int16 :tcp_dst
649
- # Int32 :tcp_seq Default: random
650
- # Int32 :tcp_ack
651
- # TcpHlen :tcp_hlen Default: 5 # Must recalc as options are set.
652
- # TcpReserved :tcp_reserved Default: 0
653
- # TcpEcn :tcp_ecn
654
- # TcpFlags :tcp_flags
655
- # Int16 :tcp_win, Default: 0 # WinXP's default syn packet
656
- # Int16 :tcp_sum, Default: calculated # Must set this upon generation.
657
- # Int16 :tcp_urg
658
- # TcpOptions :tcp_opts
659
- # String :body
660
- #
661
- # See also TcpHlen, TcpReserved, TcpEcn, TcpFlags, TcpOpts
662
- class TCPHeader < Struct.new(:tcp_src, :tcp_dst,
663
- :tcp_seq,
664
- :tcp_ack,
665
- :tcp_hlen, :tcp_reserved, :tcp_ecn, :tcp_flags, :tcp_win,
666
- :tcp_sum, :tcp_urg,
667
- :tcp_opts, :body)
668
- include StructFu
669
-
670
- def initialize(args={})
671
- @random_seq = rand(0xffffffff)
672
- @random_src = rand_port
673
- super(
674
- Int16.new(args[:tcp_src] || tcp_calc_src),
675
- Int16.new(args[:tcp_dst]),
676
- Int32.new(args[:tcp_seq] || tcp_calc_seq),
677
- Int32.new(args[:tcp_ack]),
678
- TcpHlen.new(:hlen => (args[:tcp_hlen] || 5)),
679
- TcpReserved.new(args[:tcp_reserved] || 0),
680
- TcpEcn.new(args[:tcp_ecn]),
681
- TcpFlags.new(args[:tcp_flags]),
682
- Int16.new(args[:tcp_win] || 0x4000),
683
- Int16.new(args[:tcp_sum] || 0),
684
- Int16.new(args[:tcp_urg]),
685
- TcpOptions.new.read(args[:tcp_opts]),
686
- StructFu::String.new.read(args[:body])
687
- )
688
- end
689
-
690
- attr_accessor :flavor
691
-
692
- # Helper function to create the string for Hlen, Reserved, ECN, and Flags.
693
- def bits_to_s
694
- bytes = []
695
- bytes[0] = (self[:tcp_hlen].to_i << 4) +
696
- (self[:tcp_reserved].to_i << 1) +
697
- self[:tcp_ecn].n.to_i
698
- bytes[1] = (self[:tcp_ecn].c.to_i << 7) +
699
- (self[:tcp_ecn].e.to_i << 6) +
700
- self[:tcp_flags].to_i
701
- bytes.pack("CC")
702
- end
703
-
704
- # Returns the object in string form.
705
- def to_s
706
- hdr = self.to_a.map do |x|
707
- if x.kind_of? TcpHlen
708
- bits_to_s
709
- elsif x.kind_of? TcpReserved
710
- next
711
- elsif x.kind_of? TcpEcn
712
- next
713
- elsif x.kind_of? TcpFlags
714
- next
715
- else
716
- x.to_s
717
- end
718
- end
719
- hdr.flatten.join
720
- end
721
-
722
- # Reads a string to populate the object.
723
- def read(str)
724
- force_binary(str)
725
- return self if str.nil?
726
- self[:tcp_src].read(str[0,2])
727
- self[:tcp_dst].read(str[2,2])
728
- self[:tcp_seq].read(str[4,4])
729
- self[:tcp_ack].read(str[8,4])
730
- self[:tcp_hlen].read(str[12,1])
731
- self[:tcp_reserved].read(str[12,1])
732
- self[:tcp_ecn].read(str[12,2])
733
- self[:tcp_flags].read(str[13,1])
734
- self[:tcp_win].read(str[14,2])
735
- self[:tcp_sum].read(str[16,2])
736
- self[:tcp_urg].read(str[18,2])
737
- self[:tcp_opts].read(str[20,((self[:tcp_hlen].to_i * 4) - 20)])
738
- self[:body].read(str[(self[:tcp_hlen].to_i * 4),str.size])
739
- self
740
- end
741
-
742
- # Setter for the TCP source port.
743
- def tcp_src=(i); typecast i; end
744
- # Getter for the TCP source port.
745
- def tcp_src; self[:tcp_src].to_i; end
746
- # Setter for the TCP destination port.
747
- def tcp_dst=(i); typecast i; end
748
- # Getter for the TCP destination port.
749
- def tcp_dst; self[:tcp_dst].to_i; end
750
- # Setter for the TCP sequence number.
751
- def tcp_seq=(i); typecast i; end
752
- # Getter for the TCP sequence number.
753
- def tcp_seq; self[:tcp_seq].to_i; end
754
- # Setter for the TCP ackowlegement number.
755
- def tcp_ack=(i); typecast i; end
756
- # Getter for the TCP ackowlegement number.
757
- def tcp_ack; self[:tcp_ack].to_i; end
758
- # Setter for the TCP window size number.
759
- def tcp_win=(i); typecast i; end
760
- # Getter for the TCP window size number.
761
- def tcp_win; self[:tcp_win].to_i; end
762
- # Setter for the TCP checksum.
763
- def tcp_sum=(i); typecast i; end
764
- # Getter for the TCP checksum.
765
- def tcp_sum; self[:tcp_sum].to_i; end
766
- # Setter for the TCP urgent field.
767
- def tcp_urg=(i); typecast i; end
768
- # Getter for the TCP urgent field.
769
- def tcp_urg; self[:tcp_urg].to_i; end
770
-
771
- # Getter for the TCP Header Length value.
772
- def tcp_hlen; self[:tcp_hlen].to_i; end
773
- # Setter for the TCP Header Length value. Can take
774
- # either a string or an integer. Note that if it's
775
- # a string, the top four bits are used.
776
- def tcp_hlen=(i)
777
- case i
778
- when PacketFu::TcpHlen
779
- self[:tcp_hlen] = i
780
- when Numeric
781
- self[:tcp_hlen] = TcpHlen.new(:hlen => i.to_i)
782
- else
783
- self[:tcp_hlen].read(i)
784
- end
785
- end
786
-
787
- # Getter for the TCP Reserved field.
788
- def tcp_reserved; self[:tcp_reserved].to_i; end
789
- # Setter for the TCP Reserved field.
790
- def tcp_reserved=(i)
791
- case i
792
- when PacketFu::TcpReserved
793
- self[:tcp_reserved]=i
794
- when Numeric
795
- args = {}
796
- args[:r1] = (i & 0b100) >> 2
797
- args[:r2] = (i & 0b010) >> 1
798
- args[:r3] = (i & 0b001)
799
- self[:tcp_reserved] = TcpReserved.new(args)
800
- else
801
- self[:tcp_reserved].read(i)
802
- end
803
- end
804
-
805
- # Getter for the ECN bits.
806
- def tcp_ecn; self[:tcp_ecn].to_i; end
807
- # Setter for the ECN bits.
808
- def tcp_ecn=(i)
809
- case i
810
- when PacketFu::TcpEcn
811
- self[:tcp_ecn]=i
812
- when Numeric
813
- args = {}
814
- args[:n] = (i & 0b100) >> 2
815
- args[:c] = (i & 0b010) >> 1
816
- args[:e] = (i & 0b001)
817
- self[:tcp_ecn] = TcpEcn.new(args)
818
- else
819
- self[:tcp_ecn].read(i)
820
- end
821
- end
822
-
823
- # Getter for TCP Options.
824
- def tcp_opts; self[:tcp_opts].to_s; end
825
- # Setter for TCP Options.
826
- def tcp_opts=(i)
827
- case i
828
- when PacketFu::TcpOptions
829
- self[:tcp_opts]=i
830
- else
831
- self[:tcp_opts].read(i)
832
- end
833
- end
834
-
835
- # Resets the sequence number to a new random number.
836
- def tcp_calc_seq; @random_seq; end
837
- # Resets the source port to a new random number.
838
- def tcp_calc_src; @random_src; end
839
-
840
- # Returns the actual length of the TCP options.
841
- def tcp_opts_len
842
- self[:tcp_opts].to_s.size
843
- end
844
-
845
- # Sets and returns the true length of the TCP Header.
846
- # TODO: Think about making all the option stuff safer.
847
- def tcp_calc_hlen
848
- self[:tcp_hlen] = TcpHlen.new(:hlen => ((20 + tcp_opts_len) / 4))
849
- end
850
-
851
- # Generates a random high port. This is affected by packet flavor.
852
- def rand_port
853
- rand(0xffff - 1025) + 1025
854
- end
855
-
856
- # Gets a more readable option list.
857
- def tcp_options
858
- self[:tcp_opts].decode
859
- end
860
-
861
- # Gets a more readable flags list
862
- def tcp_flags_dotmap
863
- dotmap = tcp_flags.members.map do |flag|
864
- status = self.tcp_flags.send flag
865
- status == 0 ? "." : flag.to_s.upcase[0].chr
866
- end
867
- dotmap.join
868
- end
869
-
870
- # Sets a more readable option list.
871
- def tcp_options=(arg)
872
- self[:tcp_opts].encode arg
873
- end
874
-
875
- # Equivalent to tcp_src.
876
- def tcp_sport
877
- self.tcp_src.to_i
878
- end
879
-
880
- # Equivalent to tcp_src=.
881
- def tcp_sport=(arg)
882
- self.tcp_src=(arg)
883
- end
884
-
885
- # Equivalent to tcp_dst.
886
- def tcp_dport
887
- self.tcp_dst.to_i
888
- end
889
-
890
- # Equivalent to tcp_dst=.
891
- def tcp_dport=(arg)
892
- self.tcp_dst=(arg)
893
- end
894
-
895
- # Recalculates calculated fields for TCP (except checksum which is at the Packet level).
896
- def tcp_recalc(arg=:all)
897
- case arg
898
- when :tcp_hlen
899
- tcp_calc_hlen
900
- when :tcp_src
901
- @random_tcp_src = rand_port
902
- when :tcp_sport
903
- @random_tcp_src = rand_port
904
- when :tcp_seq
905
- @random_tcp_seq = rand(0xffffffff)
906
- when :all
907
- tcp_calc_hlen
908
- @random_tcp_src = rand_port
909
- @random_tcp_seq = rand(0xffffffff)
910
- else
911
- raise ArgumentError, "No such field `#{arg}'"
912
- end
913
- end
914
-
915
- # Readability aliases
916
-
917
- alias :tcp_flags_readable :tcp_flags_dotmap
918
-
919
- def tcp_ack_readable
920
- "0x%08x" % tcp_ack
921
- end
922
-
923
- def tcp_seq_readable
924
- "0x%08x" % tcp_seq
925
- end
926
-
927
- def tcp_sum_readable
928
- "0x%04x" % tcp_sum
929
- end
930
-
931
- def tcp_opts_readable
932
- tcp_options
933
- end
934
-
935
- end
936
-
937
- # TCPPacket is used to construct TCP packets. They contain an EthHeader, an IPHeader, and a TCPHeader.
938
- #
939
- # == Example
940
- #
941
- # tcp_pkt = PacketFu::TCPPacket.new
942
- # tcp_pkt.tcp_flags.syn=1
943
- # tcp_pkt.tcp_dst=80
944
- # tcp_pkt.tcp_win=5840
945
- # tcp_pkt.tcp_options="mss:1460,sack.ok,ts:#{rand(0xffffffff)};0,nop,ws:7"
946
- #
947
- # tcp_pkt.ip_saddr=[rand(0xff),rand(0xff),rand(0xff),rand(0xff)].join('.')
948
- # tcp_pkt.ip_daddr=[rand(0xff),rand(0xff),rand(0xff),rand(0xff)].join('.')
949
- #
950
- # tcp_pkt.recalc
951
- # tcp_pkt.to_f('/tmp/tcp.pcap')
952
- #
953
- # == Parameters
954
- # :eth
955
- # A pre-generated EthHeader object.
956
- # :ip
957
- # A pre-generated IPHeader object.
958
- # :flavor
959
- # TODO: Sets the "flavor" of the TCP packet. This will include TCP options and the initial window
960
- # size, per stack. There is a lot of variety here, and it's one of the most useful methods to
961
- # remotely fingerprint devices. :flavor will span both ip and tcp for consistency.
962
- # :type
963
- # TODO: Set up particular types of packets (syn, psh_ack, rst, etc). This can change the initial flavor.
964
- # :config
965
- # A hash of return address details, often the output of Utils.whoami?
966
- class TCPPacket < Packet
967
-
968
- attr_accessor :eth_header, :ip_header, :tcp_header
969
-
970
- def self.can_parse?(str)
971
- return false unless str.size >= 54
972
- return false unless EthPacket.can_parse? str
973
- return false unless IPPacket.can_parse? str
974
- return false unless str[23,1] == "\x06"
975
- return true
976
- end
977
-
978
- def read(str=nil, args={})
979
- raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
980
- @eth_header.read(str)
981
- @ip_header.read(str[14,str.size])
982
- @eth_header.body = @ip_header
983
- if args[:strip]
984
- tcp_len = str[16,2].unpack("n")[0] - 20
985
- @tcp_header.read(str[14+(@ip_header.ip_hlen),tcp_len])
986
- else
987
- @tcp_header.read(str[14+(@ip_header.ip_hlen),str.size])
988
- end
989
- @ip_header.body = @tcp_header
990
- super(args)
991
- self
992
- end
993
-
994
- def initialize(args={})
995
- @eth_header = (args[:eth] || EthHeader.new)
996
- @ip_header = (args[:ip] || IPHeader.new)
997
- @tcp_header = (args[:tcp] || TCPHeader.new)
998
- @tcp_header.flavor = args[:flavor].to_s.downcase
999
-
1000
- @ip_header.body = @tcp_header
1001
- @eth_header.body = @ip_header
1002
- @headers = [@eth_header, @ip_header, @tcp_header]
1003
-
1004
- @ip_header.ip_proto=0x06
1005
- super
1006
- if args[:flavor]
1007
- tcp_calc_flavor(@tcp_header.flavor)
1008
- else
1009
- tcp_calc_sum
1010
- end
1011
- end
1012
-
1013
- # Sets the correct flavor for TCP Packets. Recognized flavors are:
1014
- # windows, linux, freebsd
1015
- def tcp_calc_flavor(str)
1016
- ts_val = Time.now.to_i + rand(0x4fffffff)
1017
- ts_sec = rand(0xffffff)
1018
- case @tcp_header.flavor = str.to_s.downcase
1019
- when "windows" # WinXP's default syn
1020
- @tcp_header.tcp_win = 0x4000
1021
- @tcp_header.tcp_options="MSS:1460,NOP,NOP,SACKOK"
1022
- @tcp_header.tcp_src = rand(5000 - 1026) + 1026
1023
- @ip_header.ip_ttl = 64
1024
- when "linux" # Ubuntu Linux 2.6.24-19-generic default syn
1025
- @tcp_header.tcp_win = 5840
1026
- @tcp_header.tcp_options="MSS:1460,SACKOK,TS:#{ts_val};0,NOP,WS:7"
1027
- @tcp_header.tcp_src = rand(61_000 - 32_000) + 32_000
1028
- @ip_header.ip_ttl = 64
1029
- when "freebsd" # Freebsd
1030
- @tcp_header.tcp_win = 0xffff
1031
- @tcp_header.tcp_options="MSS:1460,NOP,WS:3,NOP,NOP,TS:#{ts_val};#{ts_sec},SACKOK,EOL,EOL"
1032
- @ip_header.ip_ttl = 64
1033
- else
1034
- @tcp_header.tcp_options="MSS:1460,NOP,NOP,SACKOK"
1035
- end
1036
- tcp_calc_sum
1037
- end
1038
-
1039
- # tcp_calc_sum() computes the TCP checksum, and is called upon intialization. It usually
1040
- # should be called just prior to dropping packets to a file or on the wire.
1041
- #--
1042
- # This is /not/ delegated down to @tcp_header since we need info
1043
- # from the IP header, too.
1044
- #++
1045
- def tcp_calc_sum
1046
- checksum = (ip_src.to_i >> 16)
1047
- checksum += (ip_src.to_i & 0xffff)
1048
- checksum += (ip_dst.to_i >> 16)
1049
- checksum += (ip_dst.to_i & 0xffff)
1050
- checksum += 0x06 # TCP Protocol.
1051
- checksum += (ip_len.to_i - ((ip_hl.to_i) * 4))
1052
- checksum += tcp_src
1053
- checksum += tcp_dst
1054
- checksum += (tcp_seq.to_i >> 16)
1055
- checksum += (tcp_seq.to_i & 0xffff)
1056
- checksum += (tcp_ack.to_i >> 16)
1057
- checksum += (tcp_ack.to_i & 0xffff)
1058
- checksum += ((tcp_hlen << 12) +
1059
- (tcp_reserved << 9) +
1060
- (tcp_ecn.to_i << 6) +
1061
- tcp_flags.to_i
1062
- )
1063
- checksum += tcp_win
1064
- checksum += tcp_urg
1065
-
1066
- chk_tcp_opts = (tcp_opts.to_s.size % 2 == 0 ? tcp_opts.to_s : tcp_opts.to_s + "\x00")
1067
- chk_tcp_opts.unpack("n*").each {|x| checksum = checksum + x }
1068
- if (ip_len - ((ip_hl + tcp_hlen) * 4)) >= 0
1069
- real_tcp_payload = payload[0,( ip_len - ((ip_hl + tcp_hlen) * 4) )] # Can't forget those pesky FCSes!
1070
- else
1071
- real_tcp_payload = payload # Something's amiss here so don't bother figuring out where the real payload is.
1072
- end
1073
- chk_payload = (real_tcp_payload.size % 2 == 0 ? real_tcp_payload : real_tcp_payload + "\x00") # Null pad if it's odd.
1074
- chk_payload.unpack("n*").each {|x| checksum = checksum+x }
1075
- checksum = checksum % 0xffff
1076
- checksum = 0xffff - checksum
1077
- checksum == 0 ? 0xffff : checksum
1078
- @tcp_header.tcp_sum = checksum
1079
- end
1080
-
1081
- # Recalculates various fields of the TCP packet.
1082
- #
1083
- # ==== Parameters
1084
- #
1085
- # :all
1086
- # Recomputes all calculated fields.
1087
- # :tcp_sum
1088
- # Recomputes the TCP checksum.
1089
- # :tcp_hlen
1090
- # Recomputes the TCP header length. Useful after options are added.
1091
- def tcp_recalc(arg=:all)
1092
- case arg
1093
- when :tcp_sum
1094
- tcp_calc_sum
1095
- when :tcp_hlen
1096
- @tcp_header.tcp_recalc :tcp_hlen
1097
- when :all
1098
- @tcp_header.tcp_recalc :all
1099
- tcp_calc_sum
1100
- else
1101
- raise ArgumentError, "No such field `#{arg}'"
1102
- end
1103
- end
1104
-
1105
- # TCP packets are denoted by a "T ", followed by size,
1106
- # source and dest information, packet flags, sequence
1107
- # number, and IPID.
1108
- def peek_format
1109
- peek_data = ["T "]
1110
- peek_data << "%-5d" % self.to_s.size
1111
- peek_data << "%-21s" % "#{self.ip_saddr}:#{self.tcp_src}"
1112
- peek_data << "->"
1113
- peek_data << "%21s" % "#{self.ip_daddr}:#{self.tcp_dst}"
1114
- flags = ' ['
1115
- flags << self.tcp_flags_dotmap
1116
- flags << '] '
1117
- peek_data << flags
1118
- peek_data << "S:"
1119
- peek_data << "%08x" % self.tcp_seq
1120
- peek_data << "|I:"
1121
- peek_data << "%04x" % self.ip_id
1122
- peek_data.join
1123
- end
1124
-
1125
- end
1126
-
1127
- end