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/.document +5 -0
- data/.gitignore +7 -0
- data/LICENSE +20 -0
- data/README.rdoc +37 -0
- data/Rakefile +64 -0
- data/VERSION +1 -0
- data/dnet-ffi.gemspec +99 -0
- data/lib/dnet.rb +35 -0
- data/lib/dnet/addr.rb +204 -0
- data/lib/dnet/arp.rb +168 -0
- data/lib/dnet/blob.rb +246 -0
- data/lib/dnet/bsd.rb +123 -0
- data/lib/dnet/constants.rb +555 -0
- data/lib/dnet/eth.rb +143 -0
- data/lib/dnet/fw.rb +106 -0
- data/lib/dnet/helpers.rb +164 -0
- data/lib/dnet/icmp.rb +304 -0
- data/lib/dnet/intf.rb +194 -0
- data/lib/dnet/ip.rb +315 -0
- data/lib/dnet/ip6.rb +59 -0
- data/lib/dnet/rand.rb +33 -0
- data/lib/dnet/route.rb +103 -0
- data/lib/dnet/tcp.rb +103 -0
- data/lib/dnet/tun.rb +24 -0
- data/lib/dnet/typedefs.rb +12 -0
- data/lib/dnet/udp.rb +31 -0
- data/lib/dnet/util.rb +70 -0
- data/samples/eth_send_raw.rb +29 -0
- data/samples/ifconfig-alike.rb +44 -0
- data/samples/udp_send_raw.rb +74 -0
- data/spec/addr_spec.rb +15 -0
- data/spec/arp_spec.rb +95 -0
- data/spec/blob_spec.rb +15 -0
- data/spec/bsd_spec.rb +60 -0
- data/spec/dnet-ffi_spec.rb +31 -0
- data/spec/eth_spec.rb +47 -0
- data/spec/fw_spec.rb +15 -0
- data/spec/intf_spec.rb +98 -0
- data/spec/ip6_spec.rb +15 -0
- data/spec/ip_spec.rb +15 -0
- data/spec/rand_spec.rb +15 -0
- data/spec/route_spec.rb +94 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/tun_spec.rb +15 -0
- metadata +121 -0
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
|
data/lib/dnet/helpers.rb
ADDED
@@ -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
|