packetgen 4.0.0 → 4.1.0

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 (105) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/lib/packetgen/deprecation.rb +7 -1
  4. data/lib/packetgen/header/arp.rb +6 -7
  5. data/lib/packetgen/header/asn1_base.rb +2 -1
  6. data/lib/packetgen/header/base.rb +27 -24
  7. data/lib/packetgen/header/bootp.rb +14 -14
  8. data/lib/packetgen/header/dhcp/option.rb +8 -8
  9. data/lib/packetgen/header/dhcp/options.rb +2 -2
  10. data/lib/packetgen/header/dhcp.rb +6 -7
  11. data/lib/packetgen/header/dhcpv6/duid.rb +1 -1
  12. data/lib/packetgen/header/dhcpv6/option.rb +37 -15
  13. data/lib/packetgen/header/dhcpv6/options.rb +3 -3
  14. data/lib/packetgen/header/dhcpv6/relay.rb +1 -0
  15. data/lib/packetgen/header/dhcpv6.rb +13 -14
  16. data/lib/packetgen/header/dns/name.rb +9 -8
  17. data/lib/packetgen/header/dns/opt.rb +3 -0
  18. data/lib/packetgen/header/dns/option.rb +7 -7
  19. data/lib/packetgen/header/dns/qdsection.rb +2 -2
  20. data/lib/packetgen/header/dns/question.rb +1 -0
  21. data/lib/packetgen/header/dns/rrsection.rb +2 -2
  22. data/lib/packetgen/header/dns.rb +76 -60
  23. data/lib/packetgen/header/dot11/control.rb +5 -5
  24. data/lib/packetgen/header/dot11/data.rb +11 -10
  25. data/lib/packetgen/header/dot11/element.rb +1 -1
  26. data/lib/packetgen/header/dot11/management.rb +18 -15
  27. data/lib/packetgen/header/dot11/sub_mngt.rb +22 -21
  28. data/lib/packetgen/header/dot11.rb +38 -38
  29. data/lib/packetgen/header/dot1q.rb +5 -4
  30. data/lib/packetgen/header/dot1x.rb +8 -8
  31. data/lib/packetgen/header/eap/fast.rb +3 -3
  32. data/lib/packetgen/header/eap/md5.rb +11 -3
  33. data/lib/packetgen/header/eap/tls.rb +9 -8
  34. data/lib/packetgen/header/eap/ttls.rb +13 -10
  35. data/lib/packetgen/header/eap.rb +58 -33
  36. data/lib/packetgen/header/eth.rb +26 -12
  37. data/lib/packetgen/header/gre.rb +26 -2
  38. data/lib/packetgen/header/http/headers.rb +6 -5
  39. data/lib/packetgen/header/http/request.rb +24 -16
  40. data/lib/packetgen/header/http/response.rb +22 -15
  41. data/lib/packetgen/header/icmp.rb +10 -10
  42. data/lib/packetgen/header/icmpv6.rb +10 -9
  43. data/lib/packetgen/header/igmp.rb +21 -10
  44. data/lib/packetgen/header/igmpv3/group_record.rb +7 -2
  45. data/lib/packetgen/header/igmpv3/mq.rb +1 -1
  46. data/lib/packetgen/header/igmpv3/mr.rb +1 -1
  47. data/lib/packetgen/header/igmpv3.rb +11 -10
  48. data/lib/packetgen/header/ip/addr.rb +6 -2
  49. data/lib/packetgen/header/ip/option.rb +18 -5
  50. data/lib/packetgen/header/ip.rb +52 -35
  51. data/lib/packetgen/header/ipv6/addr.rb +14 -13
  52. data/lib/packetgen/header/ipv6/extension.rb +9 -7
  53. data/lib/packetgen/header/ipv6/hop_by_hop.rb +26 -7
  54. data/lib/packetgen/header/ipv6.rb +31 -22
  55. data/lib/packetgen/header/llc.rb +20 -13
  56. data/lib/packetgen/header/mdns.rb +9 -2
  57. data/lib/packetgen/header/mld.rb +11 -9
  58. data/lib/packetgen/header/mldv2/mcast_address_record.rb +6 -1
  59. data/lib/packetgen/header/mldv2/mlq.rb +8 -8
  60. data/lib/packetgen/header/mldv2/mlr.rb +4 -4
  61. data/lib/packetgen/header/mldv2.rb +1 -1
  62. data/lib/packetgen/header/ospfv2/db_description.rb +10 -10
  63. data/lib/packetgen/header/ospfv2/hello.rb +11 -10
  64. data/lib/packetgen/header/ospfv2/ls_ack.rb +5 -6
  65. data/lib/packetgen/header/ospfv2/ls_request.rb +7 -6
  66. data/lib/packetgen/header/ospfv2/ls_update.rb +7 -7
  67. data/lib/packetgen/header/ospfv2/lsa.rb +33 -10
  68. data/lib/packetgen/header/ospfv2/lsa_header.rb +3 -2
  69. data/lib/packetgen/header/ospfv2.rb +31 -26
  70. data/lib/packetgen/header/ospfv3/db_description.rb +12 -13
  71. data/lib/packetgen/header/ospfv3/hello.rb +10 -9
  72. data/lib/packetgen/header/ospfv3/ipv6_prefix.rb +6 -2
  73. data/lib/packetgen/header/ospfv3/ls_ack.rb +5 -6
  74. data/lib/packetgen/header/ospfv3/ls_request.rb +10 -10
  75. data/lib/packetgen/header/ospfv3/ls_update.rb +7 -7
  76. data/lib/packetgen/header/ospfv3/lsa.rb +23 -9
  77. data/lib/packetgen/header/ospfv3/lsa_header.rb +3 -2
  78. data/lib/packetgen/header/ospfv3.rb +38 -34
  79. data/lib/packetgen/header/sctp/chunk.rb +38 -17
  80. data/lib/packetgen/header/sctp/error.rb +169 -197
  81. data/lib/packetgen/header/sctp/padded32.rb +3 -3
  82. data/lib/packetgen/header/sctp/parameter.rb +85 -132
  83. data/lib/packetgen/header/sctp.rb +14 -3
  84. data/lib/packetgen/header/snmp.rb +108 -7
  85. data/lib/packetgen/header/tcp/option.rb +7 -0
  86. data/lib/packetgen/header/tcp/options.rb +11 -3
  87. data/lib/packetgen/header/tcp.rb +33 -26
  88. data/lib/packetgen/header/tftp.rb +16 -10
  89. data/lib/packetgen/header/udp.rb +15 -13
  90. data/lib/packetgen/header.rb +19 -13
  91. data/lib/packetgen/headerable.rb +9 -3
  92. data/lib/packetgen/inspect.rb +2 -7
  93. data/lib/packetgen/packet.rb +94 -36
  94. data/lib/packetgen/pcapng/block.rb +2 -1
  95. data/lib/packetgen/pcapng/file.rb +41 -14
  96. data/lib/packetgen/pcapng/idb.rb +2 -1
  97. data/lib/packetgen/pcapng/shb.rb +2 -1
  98. data/lib/packetgen/pcapng/spb.rb +1 -1
  99. data/lib/packetgen/pcapng.rb +2 -0
  100. data/lib/packetgen/proto.rb +4 -0
  101. data/lib/packetgen/unknown_packet.rb +3 -3
  102. data/lib/packetgen/utils.rb +2 -1
  103. data/lib/packetgen/version.rb +1 -1
  104. data/lib/packetgen.rb +8 -2
  105. metadata +4 -4
@@ -29,50 +29,56 @@ module PacketGen
29
29
  # | data |
30
30
  # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
31
31
  # A TCP header consists of:
32
- # * a source port ({#sport}, {BinStruct::Int16} type),
33
- # * a destination port ({#dport}, +Int16+ type),
34
- # * a sequence number ({#seqnum}, {BinStruct::Int32} type),
35
- # * an acknownledge number ({#acknum}, +Int32+ type),
36
- # * a 16-bit field ({#u16}, +Int16+ type) composed of:
37
- # * a 4-bit {#data_offset} self[attr],
32
+ # * a source port ({#sport}, +BinStruct::Int16+ type),
33
+ # * a destination port ({#dport}, +BinStruct::Int16+ type),
34
+ # * a sequence number ({#seqnum}, +BinStruct::Int32+ type),
35
+ # * an acknownledge number ({#acknum}, +BinStruct::Int32+ type),
36
+ # * a 16-bit field ({#u16}, +BinStruct::Int16+ type) composed of:
37
+ # * a 4-bit {#data_offset},
38
38
  # * a 3-bit {#reserved} field,
39
39
  # * a 9-bit {#flags} field,
40
- # * a {#window} field (+Int16+ type),
41
- # * a {#checksum} field (+Int16+ type),
42
- # * a urgent pointer ({#urg_pointer}, +Int16+ type),
40
+ # * a {#window} field (+BinStruct::Int16+ type),
41
+ # * a {#checksum} field (+BinStruct::Int16+ type),
42
+ # * a urgent pointer ({#urg_pointer}, +BinStruct::Int16+ type),
43
43
  # * an optional {#options} field ({Options} type),
44
- # * and a {#body} ({BinStruct::String} type).
44
+ # * and a {#body} (+BinStruct::String+ type).
45
45
  #
46
- # == Create a TCP header
46
+ # @example Create a TCP header
47
47
  # # standalone
48
48
  # tcph = PacketGen::Header::TCP.new
49
49
  # # in a IP packet
50
50
  # pkt = PacketGen.gen('IP').add('TCP')
51
51
  # # access to TCP header
52
- # pkt.tcp # => PacketGen::Header::TCP
52
+ # pkt.tcp.class # => PacketGen::Header::TCP
53
53
  #
54
- # == TCP attributes
54
+ # @example TCP attributes
55
+ # tcph = PacketGen::Header::TCP.new
55
56
  # tcph.sport = 4500
56
57
  # tcph.dport = 80
57
58
  # tcph.seqnum = 43
58
59
  # tcph.acknum = 0x45678925
59
60
  # tcph.wsize = 0x240
60
61
  # tcph.urg_pointer = 0x40
61
- # tcph.body.read 'this is a body'
62
+ # tcph.body = 'this is a body'
62
63
  #
63
- # == Flags
64
- # TCP flags may be accesed as a 9-bit integer:
64
+ # @example TCP Flags
65
+ # tcph = PacketGen::Header::TCP.new
66
+ # # TCP flags may be accesed as a 9-bit integer:
65
67
  # tcph.flags = 0x1002
66
- # Each flag may be accessed independently:
67
- # tcph.flag_syn? # => Boolean
68
+ # # Each flag may be accessed independently:
69
+ # tcph.flag_syn? # => true
68
70
  # tcph.flag_rst = true
69
71
  #
70
- # == Options
71
- # {#options} TCP attribute is a {Options}. {Option} may added to it:
72
- # tcph.options << PacketGen::Header::TCP::MSS.new(1250)
73
- # or:
74
- # tcph.options << { opt: 'MSS', self[attr]: 1250 }
72
+ # @example TCP Options
73
+ # tcph = PacketGen::Header::TCP.new
74
+ # # options TCP attribute is a PacketGen::Header::TCP::Options.
75
+ # # PacketGen::Header::TCP::Option may added to it:
76
+ # tcph.options << PacketGen::Header::TCP::MSS.new(value: 1250)
77
+ # # or
78
+ # tcph.options << { kind: 'MSS', value: 1250 }
79
+ # tcph.options.last.class #=> PacketGen::Header::TCP::MSS
75
80
  # @author Sylvain Daubert
81
+ # @author LemonTree55
76
82
  class TCP < Base
77
83
  end
78
84
  end
@@ -151,7 +157,8 @@ module PacketGen
151
157
  # @return [Options]
152
158
  define_attr :options, TCP::Options, builder: ->(h, t) { t.new(length_from: -> { h.data_offset > 5 ? (h.data_offset - 5) * 4 : 0 }) }
153
159
  # @!attribute body
154
- # @return [BinStruct::String,Header::Base]
160
+ # TCP body
161
+ # @return [BinStruct::String,Headerable]
155
162
  define_attr :body, BinStruct::String
156
163
 
157
164
  alias source_port sport
@@ -181,7 +188,7 @@ module PacketGen
181
188
  # @option options [Integer] :window
182
189
  # @option options [Integer] :checksum
183
190
  # @option options [Integer] :urg_pointer
184
- # @option options [String] :body
191
+ # @option options [String, Headerable] :body
185
192
  def initialize(options={})
186
193
  opts = { data_offset: 5 }.merge!(options)
187
194
  super(opts)
@@ -195,7 +202,7 @@ module PacketGen
195
202
  end
196
203
 
197
204
  # Set all flags at once
198
- # @parameter [Integer] value
205
+ # @param [Integer] value
199
206
  # @return [Integer]
200
207
  def flags=(value)
201
208
  new_u16 = (self.u16 & 0xfe00) | (value & 0x1ff)
@@ -10,25 +10,26 @@ module PacketGen
10
10
  module Header
11
11
  # A TFTP (Trivial File Transfer Protocol,
12
12
  # {https://tools.ietf.org/html/rfc1350 RFC 1350}) header consists of:
13
- # * a {#opcode} ({BinStruct::Int16Enum}),
13
+ # * an {#opcode} (+BinStruct::Int16Enum+),
14
14
  # * and a body. Its content depends on opcode.
15
15
  #
16
16
  # Specialized subclasses exists to handle {TFTP::RRQ Read Request},
17
17
  # {TFTP::WRQ Write Request}, {TFTP::DATA DATA}, {TFTP::ACK ACK} and
18
18
  # {TFTP::ERROR ERROR} packets.
19
19
  #
20
- # == Create a TFTP header
20
+ # @example Create a TFTP header
21
21
  # # standalone
22
22
  # tftp = PacketGen::Header::TFTP.new
23
23
  # # in a packet
24
24
  # pkt = PacketGen.gen('IP').add('UDP').add('TFTP')
25
25
  # # access to TFTP header
26
- # pkt.tftp # => PacketGen::Header::TFTP
26
+ # pkt.tftp.class # => PacketGen::Header::TFTP
27
27
  #
28
- # == TFTP attributes
28
+ # @example TFTP attributes
29
+ # tftp = PacketGen::Header::TFTP.new
29
30
  # tftp.opcode = 'RRQ'
30
31
  # tftp.opcode = 1
31
- # tftp.body.read 'this is a body'
32
+ # tftp.body = 'this is a body'
32
33
  #
33
34
  # == TFTP parsing
34
35
  # When parsing, only first packet (read or write request) should be decoded
@@ -46,6 +47,7 @@ module PacketGen
46
47
  # packets[0].tftp.decode!(packets[1..-1])
47
48
  # packets.map { |pkt| pkt.headers.last.class.to_s }.join(',') # => TFTP::RRQ,TFTP::DATA,UDP,TFTP::ACK
48
49
  # @author Sylvain Daubert
50
+ # @author LemonTree55
49
51
  # @since 2.3.0
50
52
  class TFTP < Base
51
53
  # Known opcodes
@@ -63,7 +65,8 @@ module PacketGen
63
65
  define_attr :opcode, BinStruct::Int16Enum, enum: OPCODES
64
66
 
65
67
  # @!attribute body
66
- # @return [String]
68
+ # TFTP body, if opcode is unknown
69
+ # @return [String,Headerable]
67
70
  define_attr :body, BinStruct::String
68
71
 
69
72
  def initialize(options={})
@@ -85,7 +88,7 @@ module PacketGen
85
88
  def read(str)
86
89
  if self.instance_of? TFTP
87
90
  super
88
- if OPCODES.value? opcode
91
+ if OPCODES.value?(opcode)
89
92
  TFTP.const_get(human_opcode).new.read(str)
90
93
  else
91
94
  self
@@ -145,7 +148,8 @@ module PacketGen
145
148
  pkt.udp.dport = udp_dport
146
149
  end
147
150
 
148
- # TFTP Read Request header
151
+ # TFTP Read Request header.
152
+ # This header remove {#body} attribute and repalces it with {#filename} and {#mode}.
149
153
  class RRQ < TFTP
150
154
  remove_attr :body
151
155
 
@@ -171,7 +175,8 @@ module PacketGen
171
175
  define_attr_before :body, :block_num, BinStruct::Int16
172
176
  end
173
177
 
174
- # TFTP ACK header
178
+ # TFTP ACK header.
179
+ # This header remove {#body} attribute and repalces it with {#block_num}.
175
180
  class ACK < TFTP
176
181
  remove_attr :body
177
182
 
@@ -181,7 +186,8 @@ module PacketGen
181
186
  define_attr :block_num, BinStruct::Int16
182
187
  end
183
188
 
184
- # TFTP ERROR header
189
+ # TFTP ERROR header.
190
+ # This header remove {#body} attribute and repalces it with {#error_code} and {#error_msg}.
185
191
  class ERROR < TFTP
186
192
  remove_attr :body
187
193
 
@@ -17,28 +17,30 @@ module PacketGen
17
17
  # | Length | Checksum |
18
18
  # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19
19
  # A UDP header consists of:
20
- # * a source port field ({#sport}, {BinStruct::Int16} type),
21
- # * a destination port field ({#dport}, +Int16+ type),
22
- # * a UDP length field ({#length}, +Int16+ type),
23
- # * a {#checksum} field (+Int16+ type),
20
+ # * a source port field ({#sport}, +BinStruct::Int16+ type),
21
+ # * a destination port field ({#dport}, +BinStruct:Int16+ type),
22
+ # * a UDP length field ({#length}, +BinStruct:Int16+ type),
23
+ # * a {#checksum} field (+BinStruct:Int16+ type),
24
24
  # * and a {#body}.
25
25
  #
26
- # == Create a UDP header
26
+ # @example Create a UDP header
27
27
  # # standalone
28
28
  # udp = PacketGen::Header::UDP.new
29
29
  # # in a packet
30
- # pkt = PAcketGen.gen('IP').eadd('UDP')
30
+ # pkt = PacketGen.gen('IP').add('UDP')
31
31
  # # access to IP header
32
- # pkt.udp # => PacketGen::Header::UDP
32
+ # pkt.udp.class # => PacketGen::Header::UDP
33
33
  #
34
- # == UDP attributes
34
+ # @example UDP attributes
35
+ # udp = PacketGen::Header::UDP.new
35
36
  # udp.sport = 65432
36
37
  # udp.dport = 53
37
38
  # udp.length = 43
38
39
  # udp.checksum = 0xffff
39
- # udp.body.read 'this is a UDP body'
40
+ # udp.body = 'this is a UDP body'
40
41
  #
41
42
  # @author Sylvain Daubert
43
+ # @author LemonTree55
42
44
  class UDP < Base
43
45
  # IP protocol number for UDP
44
46
  IP_PROTOCOL = 17
@@ -60,7 +62,8 @@ module PacketGen
60
62
  # @return [Integer]
61
63
  define_attr :checksum, BinStruct::Int16
62
64
  # @!attribute body
63
- # @return [BinStruct::String,Header::Base]
65
+ # UDP body
66
+ # @return [BinStruct::String,Headerable]
64
67
  define_attr :body, BinStruct::String
65
68
 
66
69
  alias source_port sport
@@ -75,7 +78,7 @@ module PacketGen
75
78
  self.length += self[:body].sz if self[:body].sz.positive?
76
79
  end
77
80
 
78
- # Compute checksum and set +checksum+ field
81
+ # Compute checksum and set {#checksum} field
79
82
  # @return [Integer]
80
83
  def calc_checksum
81
84
  ip = ip_header(self)
@@ -86,7 +89,7 @@ module PacketGen
86
89
  self.checksum = IP.reduce_checksum(sum)
87
90
  end
88
91
 
89
- # Compute length and set +length+ field
92
+ # Compute length and set {#length} field
90
93
  # @return [Integer]
91
94
  def calc_length
92
95
  Base.calculate_and_set_length(self)
@@ -100,7 +103,6 @@ module PacketGen
100
103
  self
101
104
  end
102
105
  end
103
-
104
106
  self.add_class UDP
105
107
 
106
108
  IP.bind UDP, protocol: UDP::IP_PROTOCOL
@@ -14,21 +14,27 @@ module PacketGen
14
14
  #
15
15
  # == Add a foreign header class
16
16
  # PacketGen permits adding your own header classes.
17
- # First, define the new header class. By example:
18
- # module MyModule
19
- # class MyHeader < PacketGen::Header::Base
20
- # define_attr :field1, BinStruct::Int32
21
- # define_attr :field2, BinStruct::Int32
22
- # end
17
+ # First, define the new header class. Then, this class must be declared to PacketGen using {Header.add_class}.
18
+ # Finally, bindings must be declared.
19
+ #
20
+ # @example Foreign header class
21
+ # # Define a new header
22
+ # module MyModule
23
+ # class MyHeader < PacketGen::Header::Base
24
+ # define_attr :field1, BinStruct::Int32
25
+ # define_attr :field2, BinStruct::Int32
26
+ # end
23
27
  # end
24
- # Then, class must be declared to PacketGen:
25
- # PacketGen::Header.add_class(MyModule::MyHeader)
26
- # Finally, bindings must be declared:
27
- # # bind MyHeader as IP protocol number 254 (needed by Packet#parse and Packet#add)
28
- # PacketGen::Header::IP.bind_header(MyModule::MyHeader, protocol: 254)
29
- # And use it:
30
- # pkt = Packet.gen('IP').add('MyHeader', field1: 0x12345678, field3: 0x87654321)
28
+ #
29
+ # # Declare the new header to PacketGen
30
+ # PacketGen::Header.add_class(MyModule::MyHeader)
31
+ # # bind it as IP protocol number 254 (needed by Packet#parse and Packet#add)
32
+ # PacketGen::Header::IP.bind(MyModule::MyHeader, protocol: 254)
33
+ #
34
+ # # Use it
35
+ # pkt = PacketGen.gen('IP').add('MyModule::MyHeader', field1: 0x12345678, field3: 0x87654321)
31
36
  # @author Sylvain Daubert
37
+ # @author LemonTree55
32
38
  module Header
33
39
  @added_header_classes = {}
34
40
 
@@ -9,7 +9,13 @@
9
9
  module PacketGen
10
10
  # This mixin module defines minimal API for a class to act as a header
11
11
  # in {Packet}.
12
+ #
13
+ # Some others methods may optionally be defined by a {Headerable} object:
14
+ # * +#calc_length+ to calculate length from content. It should be defined if header as a length attribute.
15
+ # * +#calc_checksum+ to calculate checksum. It should be defined if header as a checksum attriibute.
16
+ # * +#reply+ to invert fields in header for a reply.
12
17
  # @author Sylvain Daubert
18
+ # @author LemonTree55
13
19
  # @since 3.0.2
14
20
  module Headerable
15
21
  # This modules handles class methods for {Headerable headerable classes}.
@@ -51,7 +57,7 @@ module PacketGen
51
57
  end
52
58
 
53
59
  # @abstract Should be redefined by subclasses. This method should check invariant
54
- # attributes.from header.
60
+ # attributes from header.
55
61
  # Called by {Packet#parse} when guessing first header to check if header is correct
56
62
  # @return [Boolean]
57
63
  def parse?
@@ -74,8 +80,8 @@ module PacketGen
74
80
  @packet
75
81
  end
76
82
 
77
- # @abstract This method is called when a header is added to a packet.
78
- # This base method does nothing but may be overriden by subclasses.
83
+ # @abstract This base method does nothing but may be overriden by subclasses.
84
+ # This method is called when a header is added to a packet.
79
85
  # @param [Packet] packet packet to which self is added
80
86
  # @return [void]
81
87
  def added_to_packet(packet) end
@@ -61,18 +61,13 @@ module PacketGen
61
61
  str << Inspect::FMT_ATTR % [type, attr, value]
62
62
  end
63
63
 
64
- # Format an attribute for +#inspect+.
65
- # 3 cases are handled:
66
- # * attribute value is a {BinStruct::Int}: show value as integer and in
67
- # hexdecimal format,
68
- # * attribute value responds to +#to_human+: call it,
69
- # * else, +#to_s+ is used to format attribute value.
64
+ # Format an attribute for +#inspect+. Call +#format_inspect} on +value+.
70
65
  # @param [Symbol] attr attribute name
71
66
  # @param [Object] value attribute value
72
67
  # @param [Integer] level
73
68
  # @return [String]
74
69
  def self.inspect_attribute(attr, value, level=1)
75
- type = value.class.to_s.sub(/.*::/, '')
70
+ type = value.type_name
76
71
  self.format(type, attr, value.format_inspect, level)
77
72
  end
78
73
 
@@ -7,50 +7,58 @@
7
7
  # Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
8
8
  # This program is published under MIT license.
9
9
 
10
- # rubocop:disable Metrics/ClassLength
11
-
12
10
  module PacketGen
13
11
  # An object of type {Packet} handles a network packet. This packet may contain
14
12
  # multiple protocol headers, starting from MAC layer or from Network (OSI) layer.
15
13
  #
16
- # Creating a packet is fairly simple:
17
- # Packet.gen 'IP', src: '192.168.1.1', dst: '192.168.1.2'
14
+ # A Packet is created using {.gen} method. Headers may be added to this packet using {#add}.
15
+ # It may also be created from parsing a binary string, using {.parse} method.
16
+ #
17
+ # @example Very simple packet
18
+ # # Create a packet with a single IP header. IP source and destination addresses are set.
19
+ # pkt = PacketGen::Packet.gen('IP', src: '192.168.1.1', dst: '192.168.1.2')
18
20
  #
19
- # == Create a packet
20
- # Packets may be hand-made or parsed from a binary string:
21
- # Packet.gen('IP', src: '192.168.1.1', dst: '192.168.1.2').add('UDP', sport: 45000, dport: 23)
22
- # Packet.parse(binary_string)
21
+ # @example Parsing a binary string
22
+ # # a IP/ICMP packet, as binary string
23
+ # binary_string = "E\x00\x00\x1C\xAA`\x00\x00@\x01M-\xC0\xA8\x01\x01\xC0\xA8\x01\x02\x00\b;1abcd".b
24
+ # pkt = PacketGen::Packet.parse(binary_string)
25
+ # pkt.is?('IP') #=> true
26
+ # pkt.is?('ICMP') #=> true
23
27
  #
24
- # == Access packet information
25
- # pkt = Packet.gen('IP').add('UDP')
26
- # # read information
27
- # pkt.udp.sport
28
- # pkt.ip.ttl
29
- # # set information
30
- # pkt.udp.dport = 2323
31
- # pkt.ip.ttl = 1
32
- # pkt.ip(ttl: 1, id: 1234)
28
+ # Information for each level is accessible through the associated header. Header is accessible through a
29
+ # method defined with its name at packet level (i.e. +#ip+ for a IP header).
33
30
  #
34
- # == Save a packet to a file
35
- # pkt.write('file.pcapng')
31
+ # @example Accessing header information
32
+ # pkt = PacketGen::Packet.gen('IP').add('UDP')
33
+ # # read information
34
+ # pkt.udp.sport #=> 0
35
+ # pkt.ip.ttl #=> 64
36
+ # # set information
37
+ # pkt.udp.dport = 2323
38
+ # pkt.ip.ttl = 1
39
+ # # Set multiple attributes at once
40
+ # pkt.ip(ttl: 1, id: 1234)
36
41
  #
37
- # == Get packets
38
- # Packets may be captured from wire:
39
- # Packet.capture do |packet|
40
- # do_some_stuffs
41
- # end
42
- # packets = Packet.capture(iface: 'eth0', max: 5) # get 5 packets from eth0
42
+ # Packets may be written to files using {#write}:
43
+ # pkt = PacketGen::Packet.gen('Eth')
44
+ # pkt.write('file.pcapng')
43
45
  #
44
- # Packets may also be read from a file:
45
- # packets = Packet.read(file.pcapng)
46
+ # Packets may be captured from network interfaces:
47
+ # # Capture all packets from default interface. Never end.
48
+ # PacketGen::Packet.capture do |packet|
49
+ # do_some_stuffs
50
+ # end
46
51
  #
47
- # == Save packets to a file
48
- # Packet.write 'file.pcapng', packets
52
+ # # Get 5 packets from eth0 interface
53
+ # packets = Packet.capture(iface: 'eth0', max: 5)
49
54
  #
55
+ # Finally, packets may also be read from a file:
56
+ # packets = Packet.read(file.pcapng)
50
57
  # @author Sylvain Daubert
58
+ # @author LemonTree55
51
59
  class Packet
52
60
  # Get packet headers, ordered as they appear in the packet.
53
- # @return [Array<Header::Base>]
61
+ # @return [Array<Headerable>]
54
62
  attr_reader :headers
55
63
  # Activaye or deactivate header cache (activated by default)
56
64
  # @return [Boolean]
@@ -142,7 +150,15 @@ module PacketGen
142
150
  # @param [String] protocol
143
151
  # @param [Hash] options protocol specific options
144
152
  # @return [self]
145
- # @raise [BindingError] unknown protocol
153
+ # @raise [ArgumentError] unknown protocol
154
+ # @raise [BindingError] unknown binding
155
+ # @see #<<
156
+ # @example
157
+ # pkt = PacketGen::Packet.gen('Eth')
158
+ # # Add a IP header
159
+ # pkt.add('IP')
160
+ # # Add a TCP header, with some attributes and body set
161
+ # pkt.add('TCP', dport: 80, seqnum: 123456, body: "abcd".b)
146
162
  def add(protocol, options={})
147
163
  klass = check_protocol(protocol)
148
164
 
@@ -174,6 +190,7 @@ module PacketGen
174
190
  end
175
191
 
176
192
  # Check if a protocol header is embedded in packet.
193
+ # @example
177
194
  # pkt = PacketGen.gen('IP').add('UDP')
178
195
  # pkt.is?('IP') #=> true
179
196
  # pkt.is?('TCP') #=> false
@@ -210,16 +227,22 @@ module PacketGen
210
227
  end
211
228
  end
212
229
 
213
- # Get packet body
214
- # @return [Types]
230
+ # Get packet body. If packet (i.e. last header) has no +:body+ field, return +nil+.
231
+ # @return [Headerable,BinStruct::String,nil]
215
232
  def body
216
233
  last_header[:body] if last_header.respond_to?(:body)
217
234
  end
218
235
 
219
236
  # Set packet body
220
- # @param [String] str
237
+ # @param [String] str Binary string
221
238
  # @return [void]
239
+ # @raise [Error] Packet (i.e. last header) has no +:body+ field.
240
+ # @note To set a {Headerable} object, prefer #{<<}
241
+ # @see #<<
242
+ # @since 4.1.0 raise {Error} if no body on packet
222
243
  def body=(str)
244
+ raise Error, 'no body in last headeré' unless last_header.respond_to?(:body)
245
+
223
246
  last_header.body = str
224
247
  end
225
248
 
@@ -270,6 +293,13 @@ module PacketGen
270
293
  # @return [self] +self+ updated with new headers from +other+
271
294
  # @raise [BindingError] do not known how to encapsulate
272
295
  # @since 1.1.0
296
+ # @example
297
+ # # Create a first IP packet
298
+ # ip1 = PacketGen::Packet.gen('IP', id: 1)
299
+ # # Create second IP packet, to encapsulate in first
300
+ # ip2 = PacketGen.gen('IP', id: 2)
301
+ # ip1.encapsulate(ip2)
302
+ # ip1.ip(2) == ip2.ip
273
303
  def encapsulate(other, parsing: false)
274
304
  other.headers.each_with_index do |h, i|
275
305
  add_header(h, parsing: i.positive? || parsing)
@@ -282,6 +312,12 @@ module PacketGen
282
312
  # @raise [FormatError] any headers not in +self+
283
313
  # @raise [BindingError] removed headers result in an unknown binding
284
314
  # @since 1.1.0
315
+ # @example
316
+ # # IP/IP encapsulation
317
+ # pkt = PacketGen::Packet.gen('IP', id: 1).add('IP', id:2)
318
+ # # Remove outer IP header
319
+ # pkt.decapsulate(pkt.ip(1))
320
+ # pkt.ip.id #=> 2
285
321
  def decapsulate(*hdrs)
286
322
  hdrs.each do |hdr|
287
323
  prev_hdr = previous_header(hdr)
@@ -290,6 +326,7 @@ module PacketGen
290
326
  add_header(next_hdr, previous_header: prev_hdr) if prev_hdr && next_hdr
291
327
  end
292
328
  invalidate_header_cache
329
+ self
293
330
  rescue ArgumentError => e
294
331
  raise FormatError, e.message
295
332
  end
@@ -334,7 +371,7 @@ module PacketGen
334
371
  to_s == other.to_s
335
372
  end
336
373
 
337
- # +true+ is {#==} is +true+ with another packet, or if +other+ is a protocol name String, whose protocol is in Packet.
374
+ # +true+ if {#==} is +true+ with another packet, or if +other+ is a protocol name String, whose protocol is in Packet.
338
375
  # @param [Packet] other
339
376
  # @return [Boolean]
340
377
  # @since 3.1.2
@@ -349,8 +386,9 @@ module PacketGen
349
386
  end
350
387
  end
351
388
 
352
- # Invert all possible attributes.in packet to create a reply.
389
+ # Invert all possible attributes in packet to create a reply.
353
390
  # @return [self]
391
+ # @note Only modify headers responding to +#reply!+.
354
392
  # @since 2.7.0
355
393
  def reply!
356
394
  headers.each do |header|
@@ -362,12 +400,32 @@ module PacketGen
362
400
  # Forge a new packet from current one with all possible fields
363
401
  # inverted. The new packet may be a reply to current one.
364
402
  # @return [Packet]
403
+ # @note Only modify headers responding to +#reply!+.
365
404
  # @since 2.7.0
366
405
  def reply
367
406
  pkt = dup
368
407
  pkt.reply!
369
408
  end
370
409
 
410
+ # Append an already defined header to packet
411
+ # @param [Headerable] header
412
+ # @return [self]
413
+ # @raise [ArgumentError] unknown protocol
414
+ # @raise [BindingError] unknown binding
415
+ # @example
416
+ # pkt = PacketGen.gen('Eth')
417
+ # # Add a new header from its type
418
+ # pkt.add('IP')
419
+ # # Add a new pre-generated header
420
+ # pkt << PacketGen::Header::TCP.new
421
+ # @see #add
422
+ # @since 4.1.0
423
+ # @author LemonTree55
424
+ def <<(header)
425
+ add_header(header)
426
+ self
427
+ end
428
+
371
429
  private
372
430
 
373
431
  # Dup +@headers+ instance variable. Internally used by +#dup+ and +#clone+
@@ -10,6 +10,7 @@ module PacketGen
10
10
  module PcapNG
11
11
  # @abstract Base class for all block types
12
12
  # @author Sylvain Daubert
13
+ # @author LemonTree55
13
14
  class Block < BinStruct::Struct
14
15
  # @return [:little, :big]
15
16
  attr_accessor :endian
@@ -78,7 +79,7 @@ module PacketGen
78
79
  def to_io(str_or_io)
79
80
  return str_or_io if str_or_io.respond_to?(:read)
80
81
 
81
- StringIO.new(force_binary(str_or_io.to_s))
82
+ StringIO.new(str_or_io.to_s.b)
82
83
  end
83
84
 
84
85
  def remove_padding(io, data_len)