ffi-packets 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+