dnet-ffi 0.1.3

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.
data/lib/dnet/eth.rb ADDED
@@ -0,0 +1,143 @@
1
+ # Bindings for dnet(3)'s eth_* API
2
+
3
+ module Dnet
4
+
5
+ # FFI implementation of dnet(3)'s eth_addr struct.
6
+ class EthAddr < ::FFI::Struct
7
+ include ::FFI::DRY::StructHelper
8
+
9
+ # struct eth_addr { ... } eth_addr_t;
10
+ dsl_layout{ array :data, [:uchar, ETH_ADDR_LEN] }
11
+
12
+ # Adds the ability to initialize a new EthAddr with a mac address
13
+ # string such as 'de:ad:be:ef:ba:be'. This argument is only parsed
14
+ # if it is passed as the only String argument.
15
+ def initialize(*args)
16
+ if args.size == 1 and (s=args[0]).is_a? String
17
+ super()
18
+ self.addr = s
19
+ else
20
+ super(*args)
21
+ end
22
+ end
23
+
24
+ def addr=(val)
25
+ unless val.to_s =~ /^#{Dnet::Util::RX_MAC_ADDR}$/
26
+ raise(ArgumentError, "invalid mac address #{val.inspect}")
27
+ end
28
+ raw = ::Dnet::Util.unhexify(val, /[:-]/)
29
+ self[:data].to_ptr.write_string(raw, ETH_ADDR_LEN)
30
+ end
31
+
32
+ # Returns the MAC address as an array of unsigned char values.
33
+ def chars; self[:data].to_a ; end
34
+
35
+ # Returns the MAC address as a string with colon-separated hex-bytes.
36
+ def string; chars.map {|x| "%0.2x" % x }.join(':'); end
37
+ end
38
+
39
+
40
+ module Eth
41
+ #
42
+ # struct :dst, EthAddr, :desc => 'destination address'
43
+ # struct :src, EthAddr, :desc => 'source address'
44
+ # field :etype, :ushort, :desc => 'ethernet payload type'
45
+ #
46
+ class Hdr < ::FFI::Struct
47
+ include ::FFI::DRY::StructHelper
48
+ include ::Dnet::NetEndianHelper
49
+
50
+ module Etype
51
+ include ::FFI::DRY::ConstMap
52
+ slurp_constants ::Dnet, "ETH_TYPE_"
53
+ def list; @@list ||= super(); end
54
+ end
55
+
56
+ dsl_layout do
57
+ struct :dst, EthAddr, :desc => 'destination address'
58
+ struct :src, EthAddr, :desc => 'source address'
59
+ field :etype, :ushort, :desc => 'ethernet payload type'
60
+ end
61
+
62
+ def lookup_etype
63
+ Etype[ self.etype ]
64
+ end
65
+
66
+ alias _divert_set_eth etype=
67
+
68
+ def etype=(val)
69
+ if val.kind_of? String or val.kind_of? Symbol
70
+ val = Etype[ val ] or raise(ArgumentError, "invalid eth type #{val}")
71
+ end
72
+ _divert_set_eth(val)
73
+ end
74
+ end
75
+
76
+ # Obtains a new handle to transmit raw Ethernet frames via the specified
77
+ # network device.
78
+ #
79
+ class Handle < ::Dnet::Handle
80
+ # Uses dnet(3)'s eth_open under the hood:
81
+ def initialize(dev)
82
+ @handle=Dnet.eth_open(dev.to_s)
83
+ if @handle.address == 0
84
+ raise H_ERR.new("Unable to open device: #{dev.inspect}")
85
+ end
86
+ _handle_opened!
87
+ end
88
+
89
+ # Closes the handle. Uses dnet(3)'s eth_close() under the hood:
90
+ def close
91
+ _do_if_open { _handle_closed!; Dnet.eth_close(@handle) }
92
+ end
93
+
94
+ # Retrieves the hardware MAC address for this interface and returns it
95
+ # as a EthAddr object. Uses dnet(3)'s eth_get() function under the hood.
96
+ def macaddr()
97
+ _check_open!
98
+ ea = EthAddr.new
99
+ return nil unless Dnet.eth_get(@handle, ea) == 0
100
+ return ea
101
+ end
102
+
103
+ # Configures the hardware MAC address for this interface to the specified
104
+ # address supplied as a string of colon-separated hex-bytes (example:
105
+ # "de:ad:be:ef:01"). Uses dnet(3)'s addr_aton() to parse ea_str and
106
+ # eth_set() to set the address under the hood.
107
+ def macaddr=(ea_str)
108
+ _check_open!
109
+ if ( ea=EthAddr.new(ea_str.to_s) and Dnet.eth_set(@handle, ea) == 0 )
110
+ return true
111
+ end
112
+ end
113
+
114
+ # Transmits an ethernet frame (supplied as a String, sbuf). Uses dnet(3)'s
115
+ # eth_send() function under the hood.
116
+ def eth_send(sbuf)
117
+ _check_open!
118
+ sbuf = sbuf.to_s
119
+ (buf = ::FFI::MemoryPointer.from_string(sbuf)).autorelease = true
120
+ Dnet.eth_send(@handle, buf, sbuf.size)
121
+ end
122
+
123
+ end # Handle
124
+
125
+ def self.open(*args)
126
+ Handle.open(*args){|*y| yield(*y) if block_given? }
127
+ end
128
+
129
+ def self.eth_send(dev, *args)
130
+ Handle.open(dev){|h| h.eth_send(*args) }
131
+ end
132
+ end # Eth
133
+
134
+ # This is just an alias for ::Dnet::Eth::Handle
135
+ EthHandle = Eth::Handle
136
+
137
+ attach_function :eth_open, [:string], :eth_t
138
+ attach_function :eth_get, [:eth_t, EthAddr], :int
139
+ attach_function :eth_set, [:eth_t, EthAddr], :int
140
+ attach_function :eth_send, [:eth_t, :pointer, :size_t], :ssize_t
141
+ attach_function :eth_close, [:eth_t], :eth_t
142
+
143
+ end # Dnet
data/lib/dnet/fw.rb ADDED
@@ -0,0 +1,106 @@
1
+
2
+ ### dnet(3)'s firewalling interface
3
+
4
+ module Dnet
5
+
6
+ module Fw
7
+ #
8
+ # array :device, [:uint8, INTF_NAME_LEN], :desc => 'interface name'
9
+ # field :op, :uint8, :desc => 'operation'
10
+ # field :dir, :uint8, :desc => 'direction'
11
+ # field :proto, :uint8, :desc => 'IP protocol'
12
+ # struct :src, ::Dnet::Addr, :desc => 'src address / net'
13
+ # struct :dst, ::Dnet::Addr, :desc => 'dst address / net'
14
+ # array :sport, [:uint16, 2], :desc => 'src port-range / ICMP type'
15
+ # array :dport, [:uint16, 2], :desc => 'dst port-range / ICMP code'
16
+ #
17
+ class Rule < ::FFI::Struct
18
+ include ::FFI::DRY::StructHelper
19
+
20
+ dsl_layout do
21
+ array :device, [:uint8, INTF_NAME_LEN], :desc => 'interface name'
22
+ field :op, :uint8, :desc => 'operation'
23
+ field :dir, :uint8, :desc => 'direction'
24
+ field :proto, :uint8, :desc => 'IP protocol'
25
+ struct :src, ::Dnet::Addr, :desc => 'src address / net'
26
+ struct :dst, ::Dnet::Addr, :desc => 'dst address / net'
27
+ array :sport, [:uint16, 2], :desc => 'src port-range / ICMP type'
28
+ array :dport, [:uint16, 2], :desc => 'dst port-range / ICMP code'
29
+ end
30
+
31
+ # Alias to ::Dnet::Ip::Proto
32
+ Proto = ::Dnet::Ip::Proto
33
+
34
+ module Op
35
+ include ::FFI::DRY::ConstFlagsMap
36
+ ALLOW = 1
37
+ BLOCK = 2
38
+ def self.list ; @@list ||= super(); end
39
+ end
40
+
41
+ module Dir
42
+ include ::FFI::DRY::ConstFlagsMap
43
+ IN = 1
44
+ OUT = 2
45
+ def self.list ; @@list ||= super(); end
46
+ end
47
+
48
+ def device; self[:device].to_ptr.read_string ; end
49
+
50
+ def device=(val)
51
+ dev = ::Dnet.truncate_cstr(val.to_s, INTF_NAME_LEN)
52
+ self[:device].to_ptr.write_string(dev, dev.size)
53
+ end
54
+ end
55
+
56
+ # Fw::Handle is used to obtain a handle to access the local network
57
+ # firewall configuration.
58
+ class Handle < ::Dnet::LoopableHandle
59
+
60
+ # Uses dnet(3)'s fw_open() function under the hood.
61
+ def initialize
62
+ if (@handle = Dnet.fw_open()).address == 0
63
+ raise H_ERR.new("unable to open fw handle")
64
+ end
65
+ _handle_opened!
66
+ end
67
+
68
+ # Closes the firewall handle. Uses dnet(3)'s fw_close() under the hood.
69
+ def close
70
+ _do_if_open { _handle_closed! ; Dnet.fw_close(@handle) }
71
+ end
72
+
73
+ # Iterates over the active firewall ruleset, invoking the specified
74
+ # block with each rule cast as a Rule object. Uses dnet(3)'s fw_loop()
75
+ # function under the hood.
76
+ def loop &block
77
+ _loop ::Dnet, :fw_loop, Rule, &block
78
+ end
79
+
80
+ # Adds the specified Rule entry to the ruleset. Uses dnet(3)'s
81
+ # fw_add() function under the hood.
82
+ def add(fw_rule)
83
+ Dnet.fw_add @handle, fw_rule
84
+ end
85
+
86
+ # Deletes the specified firewall rule. Uses dnet(3)'s fw_delete() function
87
+ # under the hood.
88
+ def delete(fw_rule)
89
+ Dnet.fw_delete @handle, fw_rule
90
+ end
91
+ end
92
+
93
+ # an alias for Fw::Handle
94
+ FwHandle = Fw::Handle
95
+
96
+ end
97
+
98
+ callback :fw_handler, [Fw::Rule, :ulong], :int
99
+
100
+ attach_function :fw_open, [], :fw_t
101
+ attach_function :fw_add, [:fw_t, Fw::Rule], :int
102
+ attach_function :fw_delete, [:fw_t, Fw::Rule], :int
103
+ attach_function :fw_loop, [:fw_t, :fw_handler, :ulong], :int
104
+ attach_function :fw_close, [:fw_t], :fw_t
105
+
106
+ end
@@ -0,0 +1,164 @@
1
+ # This file contains various helper methods, modules, and classes used
2
+ # throughout the Dnet FFI bindings.
3
+
4
+ module Dnet
5
+ attach_function :htons, [:uint16], :uint16
6
+ attach_function :ntohs, [:uint16], :uint16
7
+ attach_function :htonl, [:uint32], :uint32
8
+ attach_function :ntohl, [:uint32], :uint32
9
+
10
+
11
+ # Produces a null-terminated string from 'val', if max is supplied,
12
+ # it is taken as a maximum length. If 'val' is longer than max, it will
13
+ # be truncated to max-1 with a terminating null.
14
+ def self.truncate_cstr(val, max=nil)
15
+ ret = (max and val.size > (max-1))? val[0,max-1] : val
16
+ ret << "\x00"
17
+ return ret
18
+ end
19
+
20
+ # An exception class raised on Handle related errors.
21
+ class HandleError < Exception; end
22
+
23
+ # A helper used for maintaining open/close state on libdnet's handles and
24
+ # volatile objects.
25
+ module HandleHelpers
26
+
27
+ # shorthand for the HandleError exception class
28
+ H_ERR = HandleError
29
+
30
+ def open? ; _handle_open? ; end
31
+ def closed? ; (not _handle_open?) ; end
32
+
33
+ private
34
+ def _handle_opened!
35
+ @handle_open = true
36
+ end
37
+
38
+ def _handle_closed!
39
+ @handle_open = false
40
+ end
41
+
42
+ def _check_open!
43
+ raise H_ERR.new("handle is closed") unless @handle_open
44
+ end
45
+
46
+ def _handle_open?
47
+ @handle_open
48
+ end
49
+
50
+ def _do_if_open
51
+ yield if @handle_open
52
+ end
53
+ end
54
+
55
+ class Handle
56
+ include HandleHelpers
57
+
58
+ attr_reader :handle
59
+
60
+ # Opens a new handle object, optionally yielding it to a block.
61
+ #
62
+ # If a block is supplied, the handle will be closed after completion
63
+ # and the result of the block returned. Otherwise, the new handle is
64
+ # returned in an open state.
65
+ def self.open(*args)
66
+ o=new(*args)
67
+ return o unless block_given?
68
+ begin yield(o) ensure o.close end
69
+ end
70
+ end
71
+
72
+ class LoopableHandle < Handle
73
+
74
+ def entries
75
+ ary = []
76
+ self.loop {|e| ary << e.copy }
77
+ return ary
78
+ end
79
+
80
+ # Yields each entry via a new instance through loop() to a block
81
+ def self.each_entry(*args)
82
+ open(*args) {|a| a.loop {|e| yield e } }
83
+ end
84
+
85
+ # Returns all entries as an array.
86
+ def self.entries(*args)
87
+ open(*args) {|a| a.entries }
88
+ end
89
+
90
+ private
91
+ # Generic helper for libdnet's *_loop method interfaces.
92
+ # Calls Dnet."loop_meth" to loop through some sort of entry which is cast
93
+ # to a new instance of 'entry_cast' class and yielded to a block.
94
+ def _loop(nspace, loop_meth, entry_cast)
95
+ _check_open!
96
+ b = lambda {|e, i| yield entry_cast.new(e); nil }
97
+ nspace.__send__ loop_meth, @handle, b, self.object_id
98
+ end
99
+
100
+ end # LoopableHandle
101
+
102
+ # A special helper for network packet structures which use big-endian or
103
+ # "network" byte-order. This helper generates read/write accessors that
104
+ # automatically call the appropriate byte conversion function, ntohs/ntohl
105
+ # for 'reading' a 16/32 bit field, and htons/htonl for writing to one.
106
+ #
107
+ # NOTE this helper does not currently do anything special for 64-bit values
108
+ # at all.
109
+ #
110
+ # This helper relies on a included loaded FFI::DRY::StructHelper module
111
+ # to do its magic. Always include this module as follows:
112
+ #
113
+ # class YourStruct < ::FFI::Struct # or ::FFI::ManagedStruct, (or Union?)
114
+ # include ::FFI::DRY::StructHelper
115
+ # include ::Dnet::NetEndianHelper
116
+ # ...
117
+ #
118
+ module NetEndianHelper
119
+
120
+ I16_convert = [::Dnet.method(:ntohs), ::Dnet.method(:htons)]
121
+ U16_convert = [::Dnet.method(:ntohs), ::Dnet.method(:htons)]
122
+ I32_convert = [::Dnet.method(:ntohl), ::Dnet.method(:htonl)]
123
+ U32_convert = [::Dnet.method(:ntohl), ::Dnet.method(:htonl)]
124
+
125
+ BYTE_ORDER_METH = {
126
+ Dnet.find_type(:uint16) => I16_convert,
127
+ Dnet.find_type(:int16) => I16_convert,
128
+ Dnet.find_type(:int32) => I32_convert,
129
+ Dnet.find_type(:uint32) => I32_convert,
130
+ }
131
+
132
+ module ClassMethods
133
+ private
134
+ def _class_meths_from_dsl_metadata(meta)
135
+ (@dsl_metadata = meta).each do |spec|
136
+ name = spec[:name]
137
+ type = spec[:type]
138
+ if type.kind_of? Symbol and mp=BYTE_ORDER_METH[ Dnet.find_type(type) ]
139
+ unless instance_methods.include?(:"#{name}")
140
+ define_method(:"#{name}"){ mp[0].call(self[name]) }
141
+ end
142
+ unless instance_methods.include?(:"#{name}=")
143
+ define_method(:"#{name}="){|val| self[name] = mp[1].call(val) }
144
+ end
145
+ else
146
+ unless instance_methods.include?(:"#{name}")
147
+ define_method(:"#{name}"){ self[name] }
148
+ end
149
+ unless instance_methods.include?(:"#{name}=")
150
+ define_method(:"#{name}="){|val| self[name]=val }
151
+ end
152
+ end
153
+ end
154
+ end
155
+ end
156
+
157
+ def self.included(base)
158
+ base.extend(ClassMethods)
159
+ end
160
+
161
+ end
162
+
163
+ end
164
+
data/lib/dnet/icmp.rb ADDED
@@ -0,0 +1,304 @@
1
+
2
+ module Dnet::Icmp
3
+
4
+ # ICMP header structure
5
+ #
6
+ # struct icmp_hdr {
7
+ # uint8_t icmp_type; /* type of message */
8
+ # uint8_t icmp_code; /* type sub code */
9
+ # uint16_t icmp_cksum; /* ones complement cksum of struct */
10
+ # };
11
+ #
12
+ class Hdr < ::FFI::Struct
13
+ include ::FFI::DRY::StructHelper
14
+ include ::Dnet::NetEndianHelper
15
+
16
+ dsl_layout do
17
+ field :icmp_type, :uint8
18
+ field :icmp_code, :uint8
19
+ field :icmp_cksum, :uint16
20
+ end
21
+
22
+ module IcmpType
23
+ include ::FFI::DRY::ConstFlagsMap
24
+ slurp_constants(::Dnet, "ICMP_TYPE_")
25
+ def list; @@list ||= super(); end
26
+ end
27
+
28
+ module IcmpCode
29
+ module UNREACH
30
+ include ::FFI::DRY::ConstFlagsMap
31
+ slurp_constants(::Dnet, "ICMP_UNREACH_")
32
+ def list; @@list ||= super(); end
33
+ end
34
+
35
+ module REDIRECT
36
+ include ::FFI::DRY::ConstFlagsMap
37
+ slurp_constants(::Dnet, "ICMP_REDIRECT_")
38
+ def list; @@list ||= super(); end
39
+ end
40
+
41
+ module RTRADVERT
42
+ include ::FFI::DRY::ConstFlagsMap
43
+ slurp_constants(::Dnet, "ICMP_RTRADVERT_")
44
+ def list; @@list ||= super(); end
45
+ end
46
+
47
+ module TIMEEXCEED
48
+ include ::FFI::DRY::ConstFlagsMap
49
+ slurp_constants(::Dnet, "ICMP_TIMEEXCEED_")
50
+ def list; @@list ||= super(); end
51
+ end
52
+
53
+ module PARAMPROB
54
+ include ::FFI::DRY::ConstFlagsMap
55
+ slurp_constants(::Dnet, "ICMP_PARAMPROB_")
56
+ def list; @@list ||= super(); end
57
+ end
58
+
59
+ module PHOTURIS
60
+ include ::FFI::DRY::ConstFlagsMap
61
+ slurp_constants(::Dnet, "ICMP_PHOTURIS_")
62
+ def list; @@list ||= super(); end
63
+ end
64
+
65
+ end # module IcmpCode
66
+
67
+ # Various ICMP message structures
68
+ module Msg
69
+
70
+ # Echo message data structure
71
+ #
72
+ # struct icmp_msg_echo {
73
+ # uint16_t icmp_id;
74
+ # uint16_t icmp_seq;
75
+ # uint8_t icmp_data __flexarr; /* optional data */
76
+ # };
77
+ #
78
+ class Echo < ::FFI::Struct
79
+ include ::FFI::DRY::StructHelper
80
+ include ::Dnet::NetEndianHelper
81
+
82
+ dsl_layout do
83
+ field :icmp_id, :uint16
84
+ field :seq, :uint16
85
+ field :data, :uint8 # flexarr ... optional data
86
+ end
87
+ end
88
+
89
+ # Fragmentation-needed (unreachable) message data structure
90
+ #
91
+ # struct icmp_msg_needfrag {
92
+ # uint16_t icmp_void; /* must be zero */
93
+ # uint16_t icmp_mtu; /* MTU of next-hop network */
94
+ # uint8_t icmp_ip __flexarr; /* IP hdr + 8 bytes of pkt */
95
+ # };
96
+ #
97
+ class NeedFrag < ::FFI::Struct
98
+ include ::FFI::DRY::StructHelper
99
+ include ::Dnet::NetEndianHelper
100
+
101
+ dsl_layout do
102
+ field :icmp_void, :uint16
103
+ field :mtu, :uint16
104
+ field :ip, :uint8 # flexarr ... IP hdr + 8 bytes of pkt
105
+ end
106
+ end
107
+
108
+ # Unreachable, source quench, redirect, time exceeded,
109
+ # parameter problem message data structure
110
+ #
111
+ # struct icmp_msg_quote {
112
+ # uint32_t icmp_void; /* must be zero */
113
+ # uint8_t icmp_ip __flexarr; /* IP hdr + 8 bytes of pkt */
114
+ # };
115
+ #
116
+ class Quote < ::FFI::Struct
117
+ include ::FFI::DRY::StructHelper
118
+ include ::Dnet::NetEndianHelper
119
+
120
+ dsl_layout do
121
+ field :icmp_void, :uint32
122
+ field :ip, :uint8 # flexxarr ... IP hdr + 8 bytes of pkt
123
+ end
124
+ end
125
+
126
+ # Router advertisement message data structure, RFC 1256
127
+ #
128
+ # struct icmp_msg_rtradvert {
129
+ # uint8_t icmp_num_addrs; /* # of address / pref pairs */
130
+ # uint8_t icmp_wpa; /* words / address == 2 */
131
+ # uint16_t icmp_lifetime; /* route lifetime in seconds */
132
+ # struct icmp_msg_rtr_data {
133
+ # uint32_t icmp_void;
134
+ # uint32_t icmp_pref; /* router preference (usu 0) */
135
+ # } icmp_rtr __flexarr; /* variable # of routers */
136
+ # };
137
+ #
138
+ class RtrAdvert < ::FFI::Struct
139
+ include ::FFI::DRY::StructHelper
140
+ include ::Dnet::NetEndianHelper
141
+
142
+ class RtrData < ::FFI::Struct
143
+ include ::FFI::DRY::StructHelper
144
+ include ::Dnet::NetEndianHelper
145
+
146
+ dsl_layout do
147
+ field :icmp_void, :uint32
148
+ field :pref, :uint32
149
+ end
150
+ end
151
+
152
+ dsl_layout do
153
+ field :num_addrs, :uint8
154
+ field :wpa, :uint8
155
+ field :lifetime, :uint16
156
+ struct :router, RtrData # flexarr ... variable # of routers
157
+ end
158
+ end
159
+
160
+ # Timestamp message data structure
161
+ #
162
+ # struct icmp_msg_tstamp {
163
+ # uint32_t icmp_id; /* identifier */
164
+ # uint32_t icmp_seq; /* sequence number */
165
+ # uint32_t icmp_ts_orig; /* originate timestamp */
166
+ # uint32_t icmp_ts_rx; /* receive timestamp */
167
+ # uint32_t icmp_ts_tx; /* transmit timestamp */
168
+ # };
169
+ #
170
+ class Timestamp < ::FFI::Struct
171
+ include ::FFI::DRY::StructHelper
172
+ include ::Dnet::NetEndianHelper
173
+
174
+ dsl_layout do
175
+ field :icmp_id, :uint32
176
+ field :seq, :uint32
177
+ field :ts_orig, :uint32
178
+ field :ts_rx, :uint32
179
+ field :ts_tx, :uint32
180
+ end
181
+ end
182
+
183
+ # Address mask message data structure, RFC 950
184
+ #
185
+ # struct icmp_msg_mask {
186
+ # uint32_t icmp_id; /* identifier */
187
+ # uint32_t icmp_seq; /* sequence number */
188
+ # uint32_t icmp_mask; /* address mask */
189
+ # };
190
+ #
191
+ class Mask < ::FFI::Struct
192
+ include ::FFI::DRY::StructHelper
193
+ include ::Dnet::NetEndianHelper
194
+
195
+ dsl_layout do
196
+ field :icmp_id, :uint32
197
+ field :seq, :uint32
198
+ field :mask, :uint32
199
+ end
200
+ end
201
+
202
+ # Traceroute message data structure, RFC 1393, RFC 1812
203
+ #
204
+ # struct icmp_msg_traceroute {
205
+ # uint16_t icmp_id; /* identifier */
206
+ # uint16_t icmp_void; /* unused */
207
+ # uint16_t icmp_ohc; /* outbound hop count */
208
+ # uint16_t icmp_rhc; /* return hop count */
209
+ # uint32_t icmp_speed; /* link speed, bytes/sec */
210
+ # uint32_t icmp_mtu; /* MTU in bytes */
211
+ # };
212
+ #
213
+ class Traceroute < ::FFI::Struct
214
+ include ::FFI::DRY::StructHelper
215
+ include ::Dnet::NetEndianHelper
216
+
217
+ dsl_layout do
218
+ field :icmp_id, :uint16
219
+ field :icmp_void, :uint16
220
+ field :ohc, :uint16
221
+ field :rhc, :uint16
222
+ field :speed, :uint16
223
+ field :mtu, :uint16
224
+ end
225
+ end
226
+
227
+ # Domain name reply message data structure, RFC 1788
228
+ #
229
+ # struct icmp_msg_dnsreply {
230
+ # uint16_t icmp_id; /* identifier */
231
+ # uint16_t icmp_seq; /* sequence number */
232
+ # uint32_t icmp_ttl; /* time-to-live */
233
+ # uint8_t icmp_names __flexarr; /* variable number of names */
234
+ # };
235
+ #
236
+ class DnsReply < ::FFI::Struct
237
+ include ::FFI::DRY::StructHelper
238
+ include ::Dnet::NetEndianHelper
239
+
240
+ dsl_layout do
241
+ field :icmp_id, :uint16
242
+ field :seq, :uint16
243
+ field :ttl, :uint16
244
+ field :names, :uint8 # flexarr ... variable # of names
245
+ end
246
+ end
247
+
248
+ # Generic identifier, sequence number data structure
249
+ #
250
+ # struct icmp_msg_idseq {
251
+ # uint16_t icmp_id;
252
+ # uint16_t icmp_seq;
253
+ # };
254
+ #
255
+ class IdSeq < ::FFI::Struct
256
+ include ::FFI::DRY::StructHelper
257
+ include ::Dnet::NetEndianHelper
258
+
259
+ dsl_layout do
260
+ field :icmp_id, :uint16
261
+ field :seq, :uint16
262
+ end
263
+ end
264
+
265
+ end # module Msg
266
+ end
267
+
268
+ # /*
269
+ # * ICMP message union
270
+ # */
271
+ # union icmp_msg {
272
+ # struct icmp_msg_echo echo; /* ICMP_ECHO{REPLY} */
273
+ # struct icmp_msg_quote unreach; /* ICMP_UNREACH */
274
+ # struct icmp_msg_needfrag needfrag; /* ICMP_UNREACH_NEEDFRAG */
275
+ # struct icmp_msg_quote srcquench; /* ICMP_SRCQUENCH */
276
+ # struct icmp_msg_quote redirect; /* ICMP_REDIRECT (set to 0) */
277
+ # uint32_t rtrsolicit; /* ICMP_RTRSOLICIT */
278
+ # struct icmp_msg_rtradvert rtradvert; /* ICMP_RTRADVERT */
279
+ # struct icmp_msg_quote timexceed; /* ICMP_TIMEXCEED */
280
+ # struct icmp_msg_quote paramprob; /* ICMP_PARAMPROB */
281
+ # struct icmp_msg_tstamp tstamp; /* ICMP_TSTAMP{REPLY} */
282
+ # struct icmp_msg_idseq info; /* ICMP_INFO{REPLY} */
283
+ # struct icmp_msg_mask mask; /* ICMP_MASK{REPLY} */
284
+ # struct icmp_msg_traceroute traceroute; /* ICMP_TRACEROUTE */
285
+ # struct icmp_msg_idseq dns; /* ICMP_DNS */
286
+ # struct icmp_msg_dnsreply dnsreply; /* ICMP_DNSREPLY */
287
+ # };
288
+
289
+ # #define icmp_pack_hdr(hdr, type, code) do { \
290
+ # struct icmp_hdr *icmp_pack_p = (struct icmp_hdr *)(hdr); \
291
+ # icmp_pack_p->icmp_type = type; icmp_pack_p->icmp_code = code; \
292
+ # } while (0)
293
+
294
+ # #define icmp_pack_hdr_echo(hdr, type, code, id, seq, data, len) do { \
295
+ # struct icmp_msg_echo *echo_pack_p = (struct icmp_msg_echo *) \
296
+ # ((uint8_t *)(hdr) + ICMP_HDR_LEN); \
297
+ # icmp_pack_hdr(hdr, type, code); \
298
+ # echo_pack_p->icmp_id = htons(id); \
299
+ # echo_pack_p->icmp_seq = htons(seq); \
300
+ # memmove(echo_pack_p->icmp_data, data, len); \
301
+ # } while (0)
302
+
303
+
304
+ end # module Dnet::Icmp