ffi-packets 0.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.
@@ -0,0 +1,74 @@
1
+
2
+ module FFI::Packets
3
+
4
+ module Eth
5
+ class EthAddr < ::FFI::Struct
6
+ include ::FFI::DRY::StructHelper
7
+
8
+ # struct eth_addr { ... } eth_addr_t;
9
+ dsl_layout{ array :data, [:uchar, Constants::ETH_ADDR_LEN] }
10
+
11
+ # Adds the ability to initialize a new EthAddr with a mac address
12
+ # string such as 'de:ad:be:ef:ba:be'. This argument is only parsed
13
+ # if it is passed as the only String argument.
14
+ def initialize(*args)
15
+ if args.size == 1 and (s=args[0]).is_a? String
16
+ super()
17
+ self.addr = s
18
+ else
19
+ super(*args)
20
+ end
21
+ end
22
+
23
+ def addr=(val)
24
+ unless val.to_s =~ /^#{Util::RX_MAC_ADDR}$/
25
+ raise(ArgumentError, "invalid mac address #{val.inspect}")
26
+ end
27
+ raw = Util.unhexify(val, /[:-]/)
28
+ self[:data].to_ptr.write_string(raw, ETH_ADDR_LEN)
29
+ end
30
+
31
+ # Returns the MAC address as an array of unsigned char values.
32
+ def chars; self[:data].to_a ; end
33
+
34
+ # Returns the MAC address as a string with colon-separated hex-bytes.
35
+ def string; chars.map {|x| "%0.2x" % x }.join(':'); end
36
+ end
37
+
38
+
39
+ #
40
+ # struct :dst, EthAddr, :desc => 'destination address'
41
+ # struct :src, EthAddr, :desc => 'source address'
42
+ # field :etype, :ushort, :desc => 'ethernet payload type'
43
+ #
44
+ class Hdr < ::FFI::Struct
45
+ include ::FFI::DRY::NetStructHelper
46
+
47
+ module Etype
48
+ include ::FFI::DRY::ConstMap
49
+ slurp_constants Constants, "ETH_TYPE_"
50
+ def list; @@list ||= super(); end
51
+ end
52
+
53
+ dsl_layout do
54
+ struct :dst, EthAddr, :desc => 'destination address'
55
+ struct :src, EthAddr, :desc => 'source address'
56
+ field :etype, :ushort, :desc => 'ethernet payload type'
57
+ end
58
+
59
+ def lookup_etype
60
+ Etype[ self.etype ]
61
+ end
62
+
63
+ alias _divert_set_eth etype=
64
+
65
+ def etype=(val)
66
+ if val.kind_of? String or val.kind_of? Symbol
67
+ val = Etype[ val ] or raise(ArgumentError, "invalid eth type #{val}")
68
+ end
69
+ _divert_set_eth(val)
70
+ end
71
+ end
72
+
73
+ end
74
+ end
@@ -0,0 +1,294 @@
1
+
2
+ module FFI::Packets
3
+ module Icmp
4
+
5
+ # ICMP header structure
6
+ #
7
+ # struct icmp_hdr {
8
+ # uint8_t icmp_type; /* type of message */
9
+ # uint8_t icmp_code; /* type sub code */
10
+ # uint16_t icmp_cksum; /* ones complement cksum of struct */
11
+ # };
12
+ #
13
+ class Hdr < ::FFI::Struct
14
+ include ::FFI::DRY::NetStructHelper
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(Constants, "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(Constants, "ICMP_UNREACH_")
32
+ def list; @@list ||= super(); end
33
+ end
34
+
35
+ module REDIRECT
36
+ include ::FFI::DRY::ConstFlagsMap
37
+ slurp_constants(Constants, "ICMP_REDIRECT_")
38
+ def list; @@list ||= super(); end
39
+ end
40
+
41
+ module RTRADVERT
42
+ include ::FFI::DRY::ConstFlagsMap
43
+ slurp_constants(Constants, "ICMP_RTRADVERT_")
44
+ def list; @@list ||= super(); end
45
+ end
46
+
47
+ module TIMEEXCEED
48
+ include ::FFI::DRY::ConstFlagsMap
49
+ slurp_constants(Constants, "ICMP_TIMEEXCEED_")
50
+ def list; @@list ||= super(); end
51
+ end
52
+
53
+ module PARAMPROB
54
+ include ::FFI::DRY::ConstFlagsMap
55
+ slurp_constants(Constants, "ICMP_PARAMPROB_")
56
+ def list; @@list ||= super(); end
57
+ end
58
+
59
+ module PHOTURIS
60
+ include ::FFI::DRY::ConstFlagsMap
61
+ slurp_constants(Constants, "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::NetStructHelper
80
+
81
+ dsl_layout do
82
+ field :icmp_id, :uint16
83
+ field :seq, :uint16
84
+ field :data, :uint8 # flexarr ... optional data
85
+ end
86
+ end
87
+
88
+ # Fragmentation-needed (unreachable) message data structure
89
+ #
90
+ # struct icmp_msg_needfrag {
91
+ # uint16_t icmp_void; /* must be zero */
92
+ # uint16_t icmp_mtu; /* MTU of next-hop network */
93
+ # uint8_t icmp_ip __flexarr; /* IP hdr + 8 bytes of pkt */
94
+ # };
95
+ #
96
+ class NeedFrag < ::FFI::Struct
97
+ include ::FFI::DRY::NetStructHelper
98
+
99
+ dsl_layout do
100
+ field :icmp_void, :uint16
101
+ field :mtu, :uint16
102
+ field :ip, :uint8 # flexarr ... IP hdr + 8 bytes of pkt
103
+ end
104
+ end
105
+
106
+ # Unreachable, source quench, redirect, time exceeded,
107
+ # parameter problem message data structure
108
+ #
109
+ # struct icmp_msg_quote {
110
+ # uint32_t icmp_void; /* must be zero */
111
+ # uint8_t icmp_ip __flexarr; /* IP hdr + 8 bytes of pkt */
112
+ # };
113
+ #
114
+ class Quote < ::FFI::Struct
115
+ include ::FFI::DRY::NetStructHelper
116
+
117
+ dsl_layout do
118
+ field :icmp_void, :uint32
119
+ field :ip, :uint8 # flexxarr ... IP hdr + 8 bytes of pkt
120
+ end
121
+ end
122
+
123
+ # Router advertisement message data structure, RFC 1256
124
+ #
125
+ # struct icmp_msg_rtradvert {
126
+ # uint8_t icmp_num_addrs; /* # of address / pref pairs */
127
+ # uint8_t icmp_wpa; /* words / address == 2 */
128
+ # uint16_t icmp_lifetime; /* route lifetime in seconds */
129
+ # struct icmp_msg_rtr_data {
130
+ # uint32_t icmp_void;
131
+ # uint32_t icmp_pref; /* router preference (usu 0) */
132
+ # } icmp_rtr __flexarr; /* variable # of routers */
133
+ # };
134
+ #
135
+ class RtrAdvert < ::FFI::Struct
136
+ include ::FFI::DRY::NetStructHelper
137
+
138
+ class RtrData < ::FFI::Struct
139
+ include ::FFI::DRY::NetStructHelper
140
+
141
+ dsl_layout do
142
+ field :icmp_void, :uint32
143
+ field :pref, :uint32
144
+ end
145
+ end
146
+
147
+ dsl_layout do
148
+ field :num_addrs, :uint8
149
+ field :wpa, :uint8
150
+ field :lifetime, :uint16
151
+ struct :router, RtrData # flexarr ... variable # of routers
152
+ end
153
+ end
154
+
155
+ # Timestamp message data structure
156
+ #
157
+ # struct icmp_msg_tstamp {
158
+ # uint32_t icmp_id; /* identifier */
159
+ # uint32_t icmp_seq; /* sequence number */
160
+ # uint32_t icmp_ts_orig; /* originate timestamp */
161
+ # uint32_t icmp_ts_rx; /* receive timestamp */
162
+ # uint32_t icmp_ts_tx; /* transmit timestamp */
163
+ # };
164
+ #
165
+ class Timestamp < ::FFI::Struct
166
+ include ::FFI::DRY::NetStructHelper
167
+
168
+ dsl_layout do
169
+ field :icmp_id, :uint32
170
+ field :seq, :uint32
171
+ field :ts_orig, :uint32
172
+ field :ts_rx, :uint32
173
+ field :ts_tx, :uint32
174
+ end
175
+ end
176
+
177
+ # Address mask message data structure, RFC 950
178
+ #
179
+ # struct icmp_msg_mask {
180
+ # uint32_t icmp_id; /* identifier */
181
+ # uint32_t icmp_seq; /* sequence number */
182
+ # uint32_t icmp_mask; /* address mask */
183
+ # };
184
+ #
185
+ class Mask < ::FFI::Struct
186
+ include ::FFI::DRY::NetStructHelper
187
+
188
+ dsl_layout do
189
+ field :icmp_id, :uint32
190
+ field :seq, :uint32
191
+ field :mask, :uint32
192
+ end
193
+ end
194
+
195
+ # Traceroute message data structure, RFC 1393, RFC 1812
196
+ #
197
+ # struct icmp_msg_traceroute {
198
+ # uint16_t icmp_id; /* identifier */
199
+ # uint16_t icmp_void; /* unused */
200
+ # uint16_t icmp_ohc; /* outbound hop count */
201
+ # uint16_t icmp_rhc; /* return hop count */
202
+ # uint32_t icmp_speed; /* link speed, bytes/sec */
203
+ # uint32_t icmp_mtu; /* MTU in bytes */
204
+ # };
205
+ #
206
+ class Traceroute < ::FFI::Struct
207
+ include ::FFI::DRY::NetStructHelper
208
+
209
+ dsl_layout do
210
+ field :icmp_id, :uint16
211
+ field :icmp_void, :uint16
212
+ field :ohc, :uint16
213
+ field :rhc, :uint16
214
+ field :speed, :uint16
215
+ field :mtu, :uint16
216
+ end
217
+ end
218
+
219
+ # Domain name reply message data structure, RFC 1788
220
+ #
221
+ # struct icmp_msg_dnsreply {
222
+ # uint16_t icmp_id; /* identifier */
223
+ # uint16_t icmp_seq; /* sequence number */
224
+ # uint32_t icmp_ttl; /* time-to-live */
225
+ # uint8_t icmp_names __flexarr; /* variable number of names */
226
+ # };
227
+ #
228
+ class DnsReply < ::FFI::Struct
229
+ include ::FFI::DRY::NetStructHelper
230
+
231
+ dsl_layout do
232
+ field :icmp_id, :uint16
233
+ field :seq, :uint16
234
+ field :ttl, :uint16
235
+ field :names, :uint8 # flexarr ... variable # of names
236
+ end
237
+ end
238
+
239
+ # Generic identifier, sequence number data structure
240
+ #
241
+ # struct icmp_msg_idseq {
242
+ # uint16_t icmp_id;
243
+ # uint16_t icmp_seq;
244
+ # };
245
+ #
246
+ class IdSeq < ::FFI::Struct
247
+ include ::FFI::DRY::NetStructHelper
248
+
249
+ dsl_layout do
250
+ field :icmp_id, :uint16
251
+ field :seq, :uint16
252
+ end
253
+ end
254
+
255
+ end # module Msg
256
+ end
257
+
258
+ # /*
259
+ # * ICMP message union
260
+ # */
261
+ # union icmp_msg {
262
+ # struct icmp_msg_echo echo; /* ICMP_ECHO{REPLY} */
263
+ # struct icmp_msg_quote unreach; /* ICMP_UNREACH */
264
+ # struct icmp_msg_needfrag needfrag; /* ICMP_UNREACH_NEEDFRAG */
265
+ # struct icmp_msg_quote srcquench; /* ICMP_SRCQUENCH */
266
+ # struct icmp_msg_quote redirect; /* ICMP_REDIRECT (set to 0) */
267
+ # uint32_t rtrsolicit; /* ICMP_RTRSOLICIT */
268
+ # struct icmp_msg_rtradvert rtradvert; /* ICMP_RTRADVERT */
269
+ # struct icmp_msg_quote timexceed; /* ICMP_TIMEXCEED */
270
+ # struct icmp_msg_quote paramprob; /* ICMP_PARAMPROB */
271
+ # struct icmp_msg_tstamp tstamp; /* ICMP_TSTAMP{REPLY} */
272
+ # struct icmp_msg_idseq info; /* ICMP_INFO{REPLY} */
273
+ # struct icmp_msg_mask mask; /* ICMP_MASK{REPLY} */
274
+ # struct icmp_msg_traceroute traceroute; /* ICMP_TRACEROUTE */
275
+ # struct icmp_msg_idseq dns; /* ICMP_DNS */
276
+ # struct icmp_msg_dnsreply dnsreply; /* ICMP_DNSREPLY */
277
+ # };
278
+
279
+ # #define icmp_pack_hdr(hdr, type, code) do { \
280
+ # struct icmp_hdr *icmp_pack_p = (struct icmp_hdr *)(hdr); \
281
+ # icmp_pack_p->icmp_type = type; icmp_pack_p->icmp_code = code; \
282
+ # } while (0)
283
+
284
+ # #define icmp_pack_hdr_echo(hdr, type, code, id, seq, data, len) do { \
285
+ # struct icmp_msg_echo *echo_pack_p = (struct icmp_msg_echo *) \
286
+ # ((uint8_t *)(hdr) + ICMP_HDR_LEN); \
287
+ # icmp_pack_hdr(hdr, type, code); \
288
+ # echo_pack_p->icmp_id = htons(id); \
289
+ # echo_pack_p->icmp_seq = htons(seq); \
290
+ # memmove(echo_pack_p->icmp_data, data, len); \
291
+ # } while (0)
292
+ end
293
+
294
+ end
@@ -0,0 +1,227 @@
1
+
2
+ module FFI::Packets
3
+
4
+ module Ip
5
+ # Protocols (proto) - http://www.iana.org/assignments/protocol-numbers
6
+ #
7
+ # Contains mappings for all the IP_PROTO_[A-Z].* constants
8
+ # (defined in constants.rb)
9
+ module Proto
10
+ include ::FFI::DRY::ConstMap
11
+ slurp_constants(Constants, "IP_PROTO_")
12
+ def self.list; @@list ||= super(); end
13
+ end
14
+
15
+ # IP header, without options
16
+ #
17
+ # field :v_hl, :uint8, :desc => 'v=vers(. & 0xf0) / '+
18
+ # 'hl=hdr len(. & 0x0f)'
19
+ # field :tos, :uint8, :desc => 'type of service'
20
+ # field :len, :uint16, :desc => 'total length (incl header)'
21
+ # field :id, :uint16, :desc => 'identification'
22
+ # field :off, :uint16, :desc => 'fragment offset and flags'
23
+ # field :ttl, :uint8, :desc => 'time to live'
24
+ # field :proto, :uint8, :desc => 'protocol'
25
+ # field :sum, :uint16, :desc => 'checksum'
26
+ # field :src, :uint32, :desc => 'source address'
27
+ # field :dst, :uint32, :desc => 'destination address'
28
+ #
29
+ class Hdr < ::FFI::Struct
30
+ include ::FFI::DRY::NetStructHelper
31
+
32
+ dsl_layout do
33
+ field :v_hl, :uint8, :desc => 'v=vers(. & 0xf0) / '+
34
+ 'hl=hdr len(. & 0x0f)'
35
+ field :tos, :uint8, :desc => 'type of service'
36
+ field :len, :uint16, :desc => 'total length (incl header)'
37
+ field :id, :uint16, :desc => 'identification'
38
+ field :off, :uint16, :desc => 'fragment offset and flags'
39
+ field :ttl, :uint8, :desc => 'time to live'
40
+ field :proto, :uint8, :desc => 'protocol'
41
+ field :sum, :uint16, :desc => 'checksum'
42
+ field :src, :uint32, :desc => 'source address'
43
+ field :dst, :uint32, :desc => 'destination address'
44
+ end
45
+
46
+ # Overrides set_fields to supply a default value for the 'v_hl' field.
47
+ #
48
+ # v = 4
49
+ # hl = 5 # number of 32-bit words - 20 bytes (size of hdr without opts)
50
+ #
51
+ def set_fields(params=nil)
52
+ params ||= {}
53
+ super({:v_hl => 0x45}.merge(params))
54
+ end
55
+
56
+ # Sets the value of the hl field. This field is a 4-bit value occupying
57
+ # the lower 4 bits of the 'v_hl' field.
58
+ #
59
+ # This value is the size of the IP header (including opts if present)
60
+ # in 32-bit words. The byte size maximum is 15*4 - 60 bytes.
61
+ def hl=(val)
62
+ raise(ArgumentError, "value for header length too high") if val > 0xf
63
+ self[:v_hl] &= 0xf0
64
+ self[:v_hl] += val
65
+ end
66
+
67
+ # Returns the value of the hl field. This field is a 4-bit value occupying
68
+ # the lower 4 bits of the 'v_hl' field.
69
+ #
70
+ # This value is the size of the IP header (including opts if present)
71
+ # in 32-bit words. The byte size maximum is 15*4 - 60 bytes.
72
+ def hl
73
+ self[:v_hl] & 0x0f
74
+ end
75
+
76
+ # Type of service (ip_tos), RFC 1349 ("obsoleted by RFC 2474")
77
+ #
78
+ # Contains mappings for all the IP_TOS_[A-Z].* flags constants
79
+ module Tos
80
+ include ::FFI::DRY::ConstFlagsMap
81
+ slurp_constants(Constants, "IP_TOS_")
82
+ def self.list; @@list ||= super(); end
83
+ end
84
+
85
+ def lookup_tos; Tos[ self.tos ]; end
86
+
87
+ # Alias to Ip::Proto
88
+ Proto = Ip::Proto
89
+
90
+ def lookup_proto; Proto[ self.proto ]; end
91
+
92
+ # Sets source IP address in the header from an IPv4 address string or
93
+ # 32-bit number.
94
+ def src=(val)
95
+ val = Util.ipv4_atol(val) if val.kind_of? String
96
+ self[:src] = Util.htonl(val)
97
+ end
98
+
99
+ # Returns the source IP address as an IPv4 address string as an IPv4
100
+ # address string.
101
+ def src
102
+ Util.ipv4_ltoa( Util.ntohl( self[:src] ))
103
+ end
104
+
105
+ # Sets destination IP address in the header from an IPv4 address string
106
+ # or 32-bit number.
107
+ def dst=(val)
108
+ val = Util.ipv4_atol(val) if val.kind_of? String
109
+ self[:dst] = Util.htonl(val)
110
+ end
111
+
112
+ # Returns the destination IP address from the header as an IPv4 address
113
+ # string.
114
+ def dst
115
+ Util.ipv4_ltoa( Util.ntohl( self[:dst] ))
116
+ end
117
+
118
+ end # class Hdr
119
+
120
+
121
+ # IP option (following IP header)
122
+ #
123
+ # array :otype, :uint8, :desc => 'option type'
124
+ # array :len, :uint8, :desc => 'option length >= IP_OPE_LEN'
125
+ # array :data, [:uint8, DATA_LEN], :desc => 'option message data '
126
+ #
127
+ class Opt < ::FFI::Struct
128
+ include ::FFI::DRY::NetStructHelper
129
+
130
+ IP_OPT_LEN = Constants::IP_OPT_LEN
131
+ IP_OPT_LEN_MAX = Constants::IP_OPT_LEN_MAX
132
+
133
+ DATA_LEN = IP_OPT_LEN_MAX - IP_OPT_LEN
134
+
135
+ dsl_layout do
136
+ field :otype, :uint8, :desc => 'option type'
137
+ field :len, :uint8, :desc => 'option length >= IP_OPE_LEN'
138
+ array :data, [:uint8, DATA_LEN], :desc => 'option message data '
139
+ end
140
+
141
+ # Option types (otype) - http://www.iana.org/assignments/ip-parameters
142
+ #
143
+ # Contains mappings for all the IP_OTYPE_[A-Z].* constants
144
+ module Otype
145
+ include ::FFI::DRY::ConstMap
146
+ slurp_constants(Constants, "IP_OTYPE_")
147
+ def self.list; @@list ||= super(); end
148
+ end
149
+
150
+ # Security option data - RFC 791, 3.1
151
+ #
152
+ # field :sec, :uint16, :desc => 'security'
153
+ # field :cpt, :uint16, :desc => 'compartments'
154
+ # field :hr, :uint16, :desc => 'handling restrictions'
155
+ # array :tcc, [:uint8, 3], :desc => 'transmission control code'
156
+ #
157
+ class DataSEC < ::FFI::Struct
158
+ include ::FFI::DRY::NetStructHelper
159
+
160
+ dsl_layout do
161
+ field :sec, :uint16, :desc => 'security'
162
+ field :cpt, :uint16, :desc => 'compartments'
163
+ field :hr, :uint16, :desc => 'handling restrictions'
164
+ array :tcc, [:uint8, 3], :desc => 'transmission control code'
165
+ end
166
+
167
+ end
168
+
169
+ # Timestamp option data - RFC 791, 3.1
170
+ #
171
+ # field :ptr, :uint8, :desc => 'from start of option'
172
+ # field :oflw_flg, :uint8, :desc => 'oflw = number of IPs skipped /'+
173
+ # 'flg = address/timestamp flag'
174
+ # field :iptspairs, :uint32, :desc => 'IP addr/ts pairs, var-length'
175
+ #
176
+ class DataTS < ::FFI::Struct
177
+ include ::FFI::DRY::NetStructHelper
178
+
179
+ dsl_layout do
180
+ field :ptr, :uint8, :desc => 'from start of option'
181
+ field :oflw_flg, :uint8, :desc => 'oflw = number of IPs skipped /'+
182
+ 'flg = address/timestamp flag'
183
+ field :iptspairs, :uint32, :desc => 'IP addr/ts pairs, var-length'
184
+ end
185
+
186
+ end
187
+
188
+ # (Loose Source/Record/Strict Source) Route option data - RFC 791, 3.1
189
+ #
190
+ # field :ptr, :uint8, :desc => 'from start of option'
191
+ # field :iplist, :uint32, :desc => 'var-length list of IPs'
192
+ #
193
+ class DataRR < ::FFI::Struct
194
+ include ::FFI::DRY::NetStructHelper
195
+
196
+ dsl_layout do
197
+ field :ptr, :uint8, :desc => 'from start of option'
198
+ field :iplist, :uint32, :desc => 'var-length list of IPs'
199
+ end
200
+
201
+ end
202
+
203
+ # Traceroute option data - RFC 1393, 2.2
204
+ #
205
+ # struct ip_opt_data_tr {
206
+ # uint16_t id; /* ID number */
207
+ # uint16_t ohc; /* outbound hop count */
208
+ # uint16_t rhc; /* return hop count */
209
+ # uint32_t origip; /* originator IP address */
210
+ # } __attribute__((__packed__));
211
+ #
212
+ class DataTR < ::FFI::Struct
213
+ include ::FFI::DRY::NetStructHelper
214
+
215
+ dsl_layout do
216
+ field :id, :uint16, :desc => 'ID number'
217
+ field :ohc, :uint16, :desc => 'outbound hop count'
218
+ field :rhc, :uint16, :desc => 'return hop count'
219
+ field :origip, :uint32, :desc => 'originator IP address'
220
+ end
221
+ end
222
+
223
+ end # class Opt
224
+
225
+ end # module Ip
226
+ end
227
+