packetfu 1.1.8 → 1.1.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. data/README.rdoc +11 -12
  2. data/bench/octets.rb +9 -9
  3. data/examples/100kpackets.rb +13 -12
  4. data/examples/ackscan.rb +17 -16
  5. data/examples/arp.rb +36 -35
  6. data/examples/arphood.rb +37 -36
  7. data/examples/dissect_thinger.rb +7 -6
  8. data/examples/ethernet.rb +1 -0
  9. data/examples/examples.rb +1 -0
  10. data/examples/ifconfig.rb +1 -0
  11. data/examples/new-simple-stats.rb +24 -23
  12. data/examples/packetfu-shell.rb +26 -25
  13. data/examples/simple-sniffer.rb +10 -9
  14. data/examples/simple-stats.rb +24 -23
  15. data/examples/slammer.rb +4 -3
  16. data/lib/packetfu.rb +128 -127
  17. data/lib/packetfu/capture.rb +170 -169
  18. data/lib/packetfu/config.rb +53 -52
  19. data/lib/packetfu/inject.rb +57 -56
  20. data/lib/packetfu/packet.rb +529 -528
  21. data/lib/packetfu/pcap.rb +580 -579
  22. data/lib/packetfu/protos/arp.rb +91 -90
  23. data/lib/packetfu/protos/arp/header.rb +159 -158
  24. data/lib/packetfu/protos/arp/mixin.rb +37 -36
  25. data/lib/packetfu/protos/eth.rb +45 -44
  26. data/lib/packetfu/protos/eth/header.rb +244 -243
  27. data/lib/packetfu/protos/eth/mixin.rb +4 -3
  28. data/lib/packetfu/protos/hsrp.rb +70 -69
  29. data/lib/packetfu/protos/hsrp/header.rb +108 -107
  30. data/lib/packetfu/protos/hsrp/mixin.rb +30 -29
  31. data/lib/packetfu/protos/icmp.rb +72 -71
  32. data/lib/packetfu/protos/icmp/header.rb +83 -82
  33. data/lib/packetfu/protos/icmp/mixin.rb +15 -14
  34. data/lib/packetfu/protos/invalid.rb +50 -49
  35. data/lib/packetfu/protos/ip.rb +70 -69
  36. data/lib/packetfu/protos/ip/header.rb +292 -291
  37. data/lib/packetfu/protos/ip/mixin.rb +41 -40
  38. data/lib/packetfu/protos/ipv6.rb +51 -50
  39. data/lib/packetfu/protos/ipv6/header.rb +189 -188
  40. data/lib/packetfu/protos/ipv6/mixin.rb +30 -29
  41. data/lib/packetfu/protos/lldp.rb +3 -1
  42. data/lib/packetfu/protos/lldp/header.rb +1 -0
  43. data/lib/packetfu/protos/lldp/mixin.rb +1 -0
  44. data/lib/packetfu/protos/tcp.rb +177 -176
  45. data/lib/packetfu/protos/tcp/ecn.rb +36 -35
  46. data/lib/packetfu/protos/tcp/flags.rb +75 -74
  47. data/lib/packetfu/protos/tcp/header.rb +269 -268
  48. data/lib/packetfu/protos/tcp/hlen.rb +33 -32
  49. data/lib/packetfu/protos/tcp/mixin.rb +47 -46
  50. data/lib/packetfu/protos/tcp/option.rb +322 -321
  51. data/lib/packetfu/protos/tcp/options.rb +96 -95
  52. data/lib/packetfu/protos/tcp/reserved.rb +36 -35
  53. data/lib/packetfu/protos/udp.rb +117 -116
  54. data/lib/packetfu/protos/udp/header.rb +92 -91
  55. data/lib/packetfu/protos/udp/mixin.rb +4 -3
  56. data/lib/packetfu/structfu.rb +281 -280
  57. data/lib/packetfu/utils.rb +211 -208
  58. data/lib/packetfu/version.rb +42 -41
  59. data/packetfu.gemspec +1 -1
  60. data/spec/ethpacket_spec.rb +48 -48
  61. data/spec/packet_spec.rb +57 -57
  62. data/spec/packet_subclasses_spec.rb +8 -8
  63. data/spec/packetfu_spec.rb +59 -59
  64. data/spec/structfu_spec.rb +268 -268
  65. data/spec/tcp_spec.rb +75 -75
  66. data/test/all_tests.rb +13 -13
  67. data/test/func_lldp.rb +3 -3
  68. data/test/ptest.rb +2 -2
  69. data/test/test_arp.rb +116 -116
  70. data/test/test_capture.rb +45 -45
  71. data/test/test_eth.rb +68 -68
  72. data/test/test_hsrp.rb +9 -9
  73. data/test/test_icmp.rb +52 -52
  74. data/test/test_inject.rb +18 -18
  75. data/test/test_invalid.rb +16 -16
  76. data/test/test_ip.rb +36 -36
  77. data/test/test_ip6.rb +48 -48
  78. data/test/test_octets.rb +21 -21
  79. data/test/test_packet.rb +154 -154
  80. data/test/test_pcap.rb +170 -170
  81. data/test/test_structfu.rb +97 -97
  82. data/test/test_tcp.rb +320 -320
  83. data/test/test_udp.rb +76 -76
  84. metadata +2 -2
@@ -1,31 +1,32 @@
1
+ # -*- coding: binary -*-
1
2
  module PacketFu
2
- # This Mixin simplifies access to the IPv6Headers. Mix this in with your
3
- # packet interface, and it will add methods that essentially delegate to
4
- # the 'ipv6_header' method (assuming that it is a IPv6Header object)
5
- module IPv6HeaderMixin
6
- def ipv6_v=(v); self.ipv6_header.ipv6_v= v; end
7
- def ipv6_v; self.ipv6_header.ipv6_v; end
8
- def ipv6_class=(v); self.ipv6_header.ipv6_class= v; end
9
- def ipv6_class; self.ipv6_header.ipv6_class; end
10
- def ipv6_label=(v); self.ipv6_header.ipv6_label= v; end
11
- def ipv6_label; self.ipv6_header.ipv6_label; end
12
- def ipv6_len=(v); self.ipv6_header.ipv6_len= v; end
13
- def ipv6_len; self.ipv6_header.ipv6_len; end
14
- def ipv6_next=(v); self.ipv6_header.ipv6_next= v; end
15
- def ipv6_next; self.ipv6_header.ipv6_next; end
16
- def ipv6_hop=(v); self.ipv6_header.ipv6_hop= v; end
17
- def ipv6_hop; self.ipv6_header.ipv6_hop; end
18
- def ipv6_src=(v); self.ipv6_header.ipv6_src= v; end
19
- def ipv6_src; self.ipv6_header.ipv6_src; end
20
- def ipv6_dst=(v); self.ipv6_header.ipv6_dst= v; end
21
- def ipv6_dst; self.ipv6_header.ipv6_dst; end
22
- def ipv6_calc_len; self.ipv6_header.ipv6_calc_len; end
23
- def ipv6_recalc(*v); self.ipv6_header.ipv6_recalc(*v); end
24
- def ipv6_saddr; self.ipv6_header.ipv6_saddr; end
25
- def ipv6_saddr=(v); self.ipv6_header.ipv6_saddr= v; end
26
- def ipv6_daddr; self.ipv6_header.ipv6_daddr; end
27
- def ipv6_daddr=(v); self.ipv6_header.ipv6_daddr= v; end
28
- def ipv6_src_readable; self.ipv6_header.ipv6_src_readable; end
29
- def ipv6_dst_readable; self.ipv6_header.ipv6_dst_readable; end
30
- end
3
+ # This Mixin simplifies access to the IPv6Headers. Mix this in with your
4
+ # packet interface, and it will add methods that essentially delegate to
5
+ # the 'ipv6_header' method (assuming that it is a IPv6Header object)
6
+ module IPv6HeaderMixin
7
+ def ipv6_v=(v); self.ipv6_header.ipv6_v= v; end
8
+ def ipv6_v; self.ipv6_header.ipv6_v; end
9
+ def ipv6_class=(v); self.ipv6_header.ipv6_class= v; end
10
+ def ipv6_class; self.ipv6_header.ipv6_class; end
11
+ def ipv6_label=(v); self.ipv6_header.ipv6_label= v; end
12
+ def ipv6_label; self.ipv6_header.ipv6_label; end
13
+ def ipv6_len=(v); self.ipv6_header.ipv6_len= v; end
14
+ def ipv6_len; self.ipv6_header.ipv6_len; end
15
+ def ipv6_next=(v); self.ipv6_header.ipv6_next= v; end
16
+ def ipv6_next; self.ipv6_header.ipv6_next; end
17
+ def ipv6_hop=(v); self.ipv6_header.ipv6_hop= v; end
18
+ def ipv6_hop; self.ipv6_header.ipv6_hop; end
19
+ def ipv6_src=(v); self.ipv6_header.ipv6_src= v; end
20
+ def ipv6_src; self.ipv6_header.ipv6_src; end
21
+ def ipv6_dst=(v); self.ipv6_header.ipv6_dst= v; end
22
+ def ipv6_dst; self.ipv6_header.ipv6_dst; end
23
+ def ipv6_calc_len; self.ipv6_header.ipv6_calc_len; end
24
+ def ipv6_recalc(*v); self.ipv6_header.ipv6_recalc(*v); end
25
+ def ipv6_saddr; self.ipv6_header.ipv6_saddr; end
26
+ def ipv6_saddr=(v); self.ipv6_header.ipv6_saddr= v; end
27
+ def ipv6_daddr; self.ipv6_header.ipv6_daddr; end
28
+ def ipv6_daddr=(v); self.ipv6_header.ipv6_daddr= v; end
29
+ def ipv6_src_readable; self.ipv6_header.ipv6_src_readable; end
30
+ def ipv6_dst_readable; self.ipv6_header.ipv6_dst_readable; end
31
+ end
31
32
  end
@@ -1,3 +1,4 @@
1
+ # -*- coding: binary -*-
1
2
  require 'packetfu/protos/eth/header'
2
3
  require 'packetfu/protos/eth/mixin'
3
4
 
@@ -7,6 +8,7 @@ require 'packetfu/protos/lldp/mixin'
7
8
  module PacketFu
8
9
 
9
10
  class LLDPPacket < Packet
11
+ MAGIC = Regexp.new("^\x01\x80\xc2\x00\x00[\x0e\x03\x00]", nil, "n")
10
12
  include ::PacketFu::EthHeaderMixin
11
13
  include ::PacketFu::LLDPHeaderMixin
12
14
 
@@ -16,7 +18,7 @@ module PacketFu
16
18
  return false unless EthPacket.can_parse? str
17
19
  return false unless str.size >= 6
18
20
  return false unless str[12,2] == "\x88\xcc"
19
- return false unless str =~ /^\x01\x80\xc2\x00\x00[\x0e\x03\x00]/
21
+ return false unless str =~ MAGIC
20
22
  true
21
23
  end
22
24
 
@@ -1,3 +1,4 @@
1
+ # -*- coding: binary -*-
1
2
  module PacketFu
2
3
  # LLDPHeader is a complete LLDP struct, used in LLDPPacket.
3
4
 
@@ -1,3 +1,4 @@
1
+ # -*- coding: binary -*-
1
2
  module PacketFu
2
3
  # This Mixin simplifies access to the LLDPHeaders. Mix this in with your
3
4
  # packet interface, and it will add methods that essentially delegate to
@@ -1,3 +1,4 @@
1
+ # -*- coding: binary -*-
1
2
  require 'packetfu/protos/eth/header'
2
3
  require 'packetfu/protos/eth/mixin'
3
4
 
@@ -8,194 +9,194 @@ require 'packetfu/protos/ip/header'
8
9
  require 'packetfu/protos/ip/mixin'
9
10
 
10
11
  module PacketFu
11
- # TCPPacket is used to construct TCP packets. They contain an EthHeader, an IPHeader, and a TCPHeader.
12
- #
13
- # == Example
14
- #
12
+ # TCPPacket is used to construct TCP packets. They contain an EthHeader, an IPHeader, and a TCPHeader.
13
+ #
14
+ # == Example
15
+ #
15
16
  # tcp_pkt = PacketFu::TCPPacket.new
16
17
  # tcp_pkt.tcp_flags.syn=1
17
18
  # tcp_pkt.tcp_dst=80
18
19
  # tcp_pkt.tcp_win=5840
19
20
  # tcp_pkt.tcp_options="mss:1460,sack.ok,ts:#{rand(0xffffffff)};0,nop,ws:7"
20
- #
21
+ #
21
22
  # tcp_pkt.ip_saddr=[rand(0xff),rand(0xff),rand(0xff),rand(0xff)].join('.')
22
23
  # tcp_pkt.ip_daddr=[rand(0xff),rand(0xff),rand(0xff),rand(0xff)].join('.')
23
- #
24
+ #
24
25
  # tcp_pkt.recalc
25
26
  # tcp_pkt.to_f('/tmp/tcp.pcap')
26
- #
27
- # == Parameters
28
- # :eth
29
- # A pre-generated EthHeader object.
30
- # :ip
31
- # A pre-generated IPHeader object.
32
- # :flavor
33
- # TODO: Sets the "flavor" of the TCP packet. This will include TCP options and the initial window
34
- # size, per stack. There is a lot of variety here, and it's one of the most useful methods to
35
- # remotely fingerprint devices. :flavor will span both ip and tcp for consistency.
36
- # :type
37
- # TODO: Set up particular types of packets (syn, psh_ack, rst, etc). This can change the initial flavor.
38
- # :config
39
- # A hash of return address details, often the output of Utils.whoami?
40
- class TCPPacket < Packet
27
+ #
28
+ # == Parameters
29
+ # :eth
30
+ # A pre-generated EthHeader object.
31
+ # :ip
32
+ # A pre-generated IPHeader object.
33
+ # :flavor
34
+ # TODO: Sets the "flavor" of the TCP packet. This will include TCP options and the initial window
35
+ # size, per stack. There is a lot of variety here, and it's one of the most useful methods to
36
+ # remotely fingerprint devices. :flavor will span both ip and tcp for consistency.
37
+ # :type
38
+ # TODO: Set up particular types of packets (syn, psh_ack, rst, etc). This can change the initial flavor.
39
+ # :config
40
+ # A hash of return address details, often the output of Utils.whoami?
41
+ class TCPPacket < Packet
41
42
  include ::PacketFu::EthHeaderMixin
42
43
  include ::PacketFu::IPHeaderMixin
43
44
  include ::PacketFu::TCPHeaderMixin
44
45
 
45
- attr_accessor :eth_header, :ip_header, :tcp_header
46
-
47
- def self.can_parse?(str)
48
- return false unless str.size >= 54
49
- return false unless EthPacket.can_parse? str
50
- return false unless IPPacket.can_parse? str
51
- return false unless str[23,1] == "\x06"
52
- return true
53
- end
54
-
55
- def read(str=nil, args={})
56
- raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
57
- @eth_header.read(str)
58
-
59
- # Strip off any extra data, if we are asked to do so.
60
- if args[:strip]
61
- tcp_body_len = self.ip_len - self.ip_hlen - (self.tcp_hlen * 4)
62
- @tcp_header.body.read(@tcp_header.body.to_s[0,tcp_body_len])
63
- end
64
- super(args)
65
- self
66
- end
67
-
68
- def initialize(args={})
69
- @eth_header = (args[:eth] || EthHeader.new)
70
- @ip_header = (args[:ip] || IPHeader.new)
71
- @tcp_header = (args[:tcp] || TCPHeader.new)
72
- @tcp_header.flavor = args[:flavor].to_s.downcase
73
-
74
- @ip_header.body = @tcp_header
75
- @eth_header.body = @ip_header
76
- @headers = [@eth_header, @ip_header, @tcp_header]
77
-
78
- @ip_header.ip_proto=0x06
79
- super
80
- if args[:flavor]
81
- tcp_calc_flavor(@tcp_header.flavor)
82
- else
83
- tcp_calc_sum
84
- end
85
- end
86
-
87
- # Sets the correct flavor for TCP Packets. Recognized flavors are:
88
- # windows, linux, freebsd
89
- def tcp_calc_flavor(str)
90
- ts_val = Time.now.to_i + rand(0x4fffffff)
91
- ts_sec = rand(0xffffff)
92
- case @tcp_header.flavor = str.to_s.downcase
93
- when "windows" # WinXP's default syn
94
- @tcp_header.tcp_win = 0x4000
95
- @tcp_header.tcp_options="MSS:1460,NOP,NOP,SACKOK"
96
- @tcp_header.tcp_src = rand(5000 - 1026) + 1026
97
- @ip_header.ip_ttl = 64
98
- when "linux" # Ubuntu Linux 2.6.24-19-generic default syn
99
- @tcp_header.tcp_win = 5840
100
- @tcp_header.tcp_options="MSS:1460,SACKOK,TS:#{ts_val};0,NOP,WS:7"
101
- @tcp_header.tcp_src = rand(61_000 - 32_000) + 32_000
102
- @ip_header.ip_ttl = 64
103
- when "freebsd" # Freebsd
104
- @tcp_header.tcp_win = 0xffff
105
- @tcp_header.tcp_options="MSS:1460,NOP,WS:3,NOP,NOP,TS:#{ts_val};#{ts_sec},SACKOK,EOL,EOL"
106
- @ip_header.ip_ttl = 64
107
- else
108
- @tcp_header.tcp_options="MSS:1460,NOP,NOP,SACKOK"
109
- end
110
- tcp_calc_sum
111
- end
112
-
113
- # tcp_calc_sum() computes the TCP checksum, and is called upon intialization. It usually
114
- # should be called just prior to dropping packets to a file or on the wire.
115
- #--
116
- # This is /not/ delegated down to @tcp_header since we need info
117
- # from the IP header, too.
118
- #++
119
- def tcp_calc_sum
120
- checksum = (ip_src.to_i >> 16)
121
- checksum += (ip_src.to_i & 0xffff)
122
- checksum += (ip_dst.to_i >> 16)
123
- checksum += (ip_dst.to_i & 0xffff)
124
- checksum += 0x06 # TCP Protocol.
125
- checksum += (ip_len.to_i - ((ip_hl.to_i) * 4))
126
- checksum += tcp_src
127
- checksum += tcp_dst
128
- checksum += (tcp_seq.to_i >> 16)
129
- checksum += (tcp_seq.to_i & 0xffff)
130
- checksum += (tcp_ack.to_i >> 16)
131
- checksum += (tcp_ack.to_i & 0xffff)
132
- checksum += ((tcp_hlen << 12) +
133
- (tcp_reserved << 9) +
134
- (tcp_ecn.to_i << 6) +
135
- tcp_flags.to_i
136
- )
137
- checksum += tcp_win
138
- checksum += tcp_urg
139
-
140
- chk_tcp_opts = (tcp_opts.to_s.size % 2 == 0 ? tcp_opts.to_s : tcp_opts.to_s + "\x00")
141
- chk_tcp_opts.unpack("n*").each {|x| checksum = checksum + x }
142
- if (ip_len - ((ip_hl + tcp_hlen) * 4)) >= 0
143
- real_tcp_payload = payload[0,( ip_len - ((ip_hl + tcp_hlen) * 4) )] # Can't forget those pesky FCSes!
144
- else
145
- real_tcp_payload = payload # Something's amiss here so don't bother figuring out where the real payload is.
146
- end
147
- chk_payload = (real_tcp_payload.size % 2 == 0 ? real_tcp_payload : real_tcp_payload + "\x00") # Null pad if it's odd.
148
- chk_payload.unpack("n*").each {|x| checksum = checksum+x }
149
- checksum = checksum % 0xffff
150
- checksum = 0xffff - checksum
151
- checksum == 0 ? 0xffff : checksum
152
- @tcp_header.tcp_sum = checksum
153
- end
154
-
155
- # Recalculates various fields of the TCP packet.
156
- #
157
- # ==== Parameters
158
- #
159
- # :all
160
- # Recomputes all calculated fields.
161
- # :tcp_sum
162
- # Recomputes the TCP checksum.
163
- # :tcp_hlen
164
- # Recomputes the TCP header length. Useful after options are added.
165
- def tcp_recalc(arg=:all)
166
- case arg
167
- when :tcp_sum
168
- tcp_calc_sum
169
- when :tcp_hlen
170
- @tcp_header.tcp_recalc :tcp_hlen
171
- when :all
172
- @tcp_header.tcp_recalc :all
173
- tcp_calc_sum
174
- else
175
- raise ArgumentError, "No such field `#{arg}'"
176
- end
177
- end
178
-
179
- # TCP packets are denoted by a "T ", followed by size,
180
- # source and dest information, packet flags, sequence
181
- # number, and IPID.
182
- def peek_format
183
- peek_data = ["T "]
184
- peek_data << "%-5d" % self.to_s.size
185
- peek_data << "%-21s" % "#{self.ip_saddr}:#{self.tcp_src}"
186
- peek_data << "->"
187
- peek_data << "%21s" % "#{self.ip_daddr}:#{self.tcp_dst}"
188
- flags = ' ['
189
- flags << self.tcp_flags_dotmap
190
- flags << '] '
191
- peek_data << flags
192
- peek_data << "S:"
193
- peek_data << "%08x" % self.tcp_seq
194
- peek_data << "|I:"
195
- peek_data << "%04x" % self.ip_id
196
- peek_data.join
197
- end
198
-
199
- end
46
+ attr_accessor :eth_header, :ip_header, :tcp_header
47
+
48
+ def self.can_parse?(str)
49
+ return false unless str.size >= 54
50
+ return false unless EthPacket.can_parse? str
51
+ return false unless IPPacket.can_parse? str
52
+ return false unless str[23,1] == "\x06"
53
+ return true
54
+ end
55
+
56
+ def read(str=nil, args={})
57
+ raise "Cannot parse `#{str}'" unless self.class.can_parse?(str)
58
+ @eth_header.read(str)
59
+
60
+ # Strip off any extra data, if we are asked to do so.
61
+ if args[:strip]
62
+ tcp_body_len = self.ip_len - self.ip_hlen - (self.tcp_hlen * 4)
63
+ @tcp_header.body.read(@tcp_header.body.to_s[0,tcp_body_len])
64
+ end
65
+ super(args)
66
+ self
67
+ end
68
+
69
+ def initialize(args={})
70
+ @eth_header = (args[:eth] || EthHeader.new)
71
+ @ip_header = (args[:ip] || IPHeader.new)
72
+ @tcp_header = (args[:tcp] || TCPHeader.new)
73
+ @tcp_header.flavor = args[:flavor].to_s.downcase
74
+
75
+ @ip_header.body = @tcp_header
76
+ @eth_header.body = @ip_header
77
+ @headers = [@eth_header, @ip_header, @tcp_header]
78
+
79
+ @ip_header.ip_proto=0x06
80
+ super
81
+ if args[:flavor]
82
+ tcp_calc_flavor(@tcp_header.flavor)
83
+ else
84
+ tcp_calc_sum
85
+ end
86
+ end
87
+
88
+ # Sets the correct flavor for TCP Packets. Recognized flavors are:
89
+ # windows, linux, freebsd
90
+ def tcp_calc_flavor(str)
91
+ ts_val = Time.now.to_i + rand(0x4fffffff)
92
+ ts_sec = rand(0xffffff)
93
+ case @tcp_header.flavor = str.to_s.downcase
94
+ when "windows" # WinXP's default syn
95
+ @tcp_header.tcp_win = 0x4000
96
+ @tcp_header.tcp_options="MSS:1460,NOP,NOP,SACKOK"
97
+ @tcp_header.tcp_src = rand(5000 - 1026) + 1026
98
+ @ip_header.ip_ttl = 64
99
+ when "linux" # Ubuntu Linux 2.6.24-19-generic default syn
100
+ @tcp_header.tcp_win = 5840
101
+ @tcp_header.tcp_options="MSS:1460,SACKOK,TS:#{ts_val};0,NOP,WS:7"
102
+ @tcp_header.tcp_src = rand(61_000 - 32_000) + 32_000
103
+ @ip_header.ip_ttl = 64
104
+ when "freebsd" # Freebsd
105
+ @tcp_header.tcp_win = 0xffff
106
+ @tcp_header.tcp_options="MSS:1460,NOP,WS:3,NOP,NOP,TS:#{ts_val};#{ts_sec},SACKOK,EOL,EOL"
107
+ @ip_header.ip_ttl = 64
108
+ else
109
+ @tcp_header.tcp_options="MSS:1460,NOP,NOP,SACKOK"
110
+ end
111
+ tcp_calc_sum
112
+ end
113
+
114
+ # tcp_calc_sum() computes the TCP checksum, and is called upon intialization. It usually
115
+ # should be called just prior to dropping packets to a file or on the wire.
116
+ #--
117
+ # This is /not/ delegated down to @tcp_header since we need info
118
+ # from the IP header, too.
119
+ #++
120
+ def tcp_calc_sum
121
+ checksum = (ip_src.to_i >> 16)
122
+ checksum += (ip_src.to_i & 0xffff)
123
+ checksum += (ip_dst.to_i >> 16)
124
+ checksum += (ip_dst.to_i & 0xffff)
125
+ checksum += 0x06 # TCP Protocol.
126
+ checksum += (ip_len.to_i - ((ip_hl.to_i) * 4))
127
+ checksum += tcp_src
128
+ checksum += tcp_dst
129
+ checksum += (tcp_seq.to_i >> 16)
130
+ checksum += (tcp_seq.to_i & 0xffff)
131
+ checksum += (tcp_ack.to_i >> 16)
132
+ checksum += (tcp_ack.to_i & 0xffff)
133
+ checksum += ((tcp_hlen << 12) +
134
+ (tcp_reserved << 9) +
135
+ (tcp_ecn.to_i << 6) +
136
+ tcp_flags.to_i
137
+ )
138
+ checksum += tcp_win
139
+ checksum += tcp_urg
140
+
141
+ chk_tcp_opts = (tcp_opts.to_s.size % 2 == 0 ? tcp_opts.to_s : tcp_opts.to_s + "\x00")
142
+ chk_tcp_opts.unpack("n*").each {|x| checksum = checksum + x }
143
+ if (ip_len - ((ip_hl + tcp_hlen) * 4)) >= 0
144
+ real_tcp_payload = payload[0,( ip_len - ((ip_hl + tcp_hlen) * 4) )] # Can't forget those pesky FCSes!
145
+ else
146
+ real_tcp_payload = payload # Something's amiss here so don't bother figuring out where the real payload is.
147
+ end
148
+ chk_payload = (real_tcp_payload.size % 2 == 0 ? real_tcp_payload : real_tcp_payload + "\x00") # Null pad if it's odd.
149
+ chk_payload.unpack("n*").each {|x| checksum = checksum+x }
150
+ checksum = checksum % 0xffff
151
+ checksum = 0xffff - checksum
152
+ checksum == 0 ? 0xffff : checksum
153
+ @tcp_header.tcp_sum = checksum
154
+ end
155
+
156
+ # Recalculates various fields of the TCP packet.
157
+ #
158
+ # ==== Parameters
159
+ #
160
+ # :all
161
+ # Recomputes all calculated fields.
162
+ # :tcp_sum
163
+ # Recomputes the TCP checksum.
164
+ # :tcp_hlen
165
+ # Recomputes the TCP header length. Useful after options are added.
166
+ def tcp_recalc(arg=:all)
167
+ case arg
168
+ when :tcp_sum
169
+ tcp_calc_sum
170
+ when :tcp_hlen
171
+ @tcp_header.tcp_recalc :tcp_hlen
172
+ when :all
173
+ @tcp_header.tcp_recalc :all
174
+ tcp_calc_sum
175
+ else
176
+ raise ArgumentError, "No such field `#{arg}'"
177
+ end
178
+ end
179
+
180
+ # TCP packets are denoted by a "T ", followed by size,
181
+ # source and dest information, packet flags, sequence
182
+ # number, and IPID.
183
+ def peek_format
184
+ peek_data = ["T "]
185
+ peek_data << "%-5d" % self.to_s.size
186
+ peek_data << "%-21s" % "#{self.ip_saddr}:#{self.tcp_src}"
187
+ peek_data << "->"
188
+ peek_data << "%21s" % "#{self.ip_daddr}:#{self.tcp_dst}"
189
+ flags = ' ['
190
+ flags << self.tcp_flags_dotmap
191
+ flags << '] '
192
+ peek_data << flags
193
+ peek_data << "S:"
194
+ peek_data << "%08x" % self.tcp_seq
195
+ peek_data << "|I:"
196
+ peek_data << "%04x" % self.ip_id
197
+ peek_data.join
198
+ end
199
+
200
+ end
200
201
 
201
202
  end