forked from iovisor/bcc
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathproto.lua
More file actions
505 lines (474 loc) · 15.7 KB
/
proto.lua
File metadata and controls
505 lines (474 loc) · 15.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
--[[
Copyright 2016 Marek Vavrusa <mvavrusa@cloudflare.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
]]
local ffi = require('ffi')
local BPF = ffi.typeof('struct bpf')
ffi.cdef [[
struct sk_buff {
uint32_t len;
uint32_t pkt_type;
uint32_t mark;
uint32_t queue_mapping;
uint32_t protocol;
uint32_t vlan_present;
uint32_t vlan_tci;
uint32_t vlan_proto;
uint32_t priority;
uint32_t ingress_ifindex;
uint32_t ifindex;
uint32_t tc_index;
uint32_t cb[5];
uint32_t hash;
uint32_t tc_classid;
};
struct net_off_t {
uint8_t ver:4;
} __attribute__((packed));
struct eth_t {
uint8_t dst[6];
uint8_t src[6];
uint16_t type;
} __attribute__((packed));
struct dot1q_t {
uint16_t pri:3;
uint16_t cfi:1;
uint16_t vlanid:12;
uint16_t type;
} __attribute__((packed));
struct arp_t {
uint16_t htype;
uint16_t ptype;
uint8_t hlen;
uint8_t plen;
uint16_t oper;
uint8_t sha[6];
uint32_t spa;
uint8_t tha[6];
uint32_t tpa;
} __attribute__((packed));
struct ip_t {
uint8_t ver:4;
uint8_t hlen:4;
uint8_t tos;
uint16_t tlen;
uint16_t identification;
uint16_t ffo_unused:1;
uint16_t df:1;
uint16_t mf:1;
uint16_t foffset:13;
uint8_t ttl;
uint8_t proto;
uint16_t hchecksum;
uint32_t src;
uint32_t dst;
} __attribute__((packed));
struct icmp_t {
uint8_t type;
uint8_t code;
uint16_t checksum;
} __attribute__((packed));
struct ip6_t {
uint32_t ver:4;
uint32_t priority:8;
uint32_t flow_label:20;
uint16_t payload_len;
uint8_t next_header;
uint8_t hop_limit;
uint64_t src_hi;
uint64_t src_lo;
uint64_t dst_hi;
uint64_t dst_lo;
} __attribute__((packed));
struct ip6_opt_t {
uint8_t next_header;
uint8_t ext_len;
uint8_t pad[6];
} __attribute__((packed));
struct icmp6_t {
uint8_t type;
uint8_t code;
uint16_t checksum;
} __attribute__((packed));
struct udp_t {
uint16_t src_port;
uint16_t dst_port;
uint16_t length;
uint16_t crc;
} __attribute__((packed));
struct tcp_t {
uint16_t src_port;
uint16_t dst_port;
uint32_t seq_num;
uint32_t ack_num;
uint8_t offset:4;
uint8_t reserved:4;
uint8_t flag_cwr:1;
uint8_t flag_ece:1;
uint8_t flag_urg:1;
uint8_t flag_ack:1;
uint8_t flag_psh:1;
uint8_t flag_rst:1;
uint8_t flag_syn:1;
uint8_t flag_fin:1;
uint16_t rcv_wnd;
uint16_t cksum;
uint16_t urg_ptr;
} __attribute__((packed));
struct vxlan_t {
uint32_t rsv1:4;
uint32_t iflag:1;
uint32_t rsv2:3;
uint32_t rsv3:24;
uint32_t key:24;
uint32_t rsv4:8;
} __attribute__((packed));
]]
-- Architecture-specific ptrace register layout
local S = require('syscall')
local arch = S.abi.arch
local parm_to_reg = {}
if arch == 'x64' then
ffi.cdef [[
struct pt_regs {
unsigned long r15;
unsigned long r14;
unsigned long r13;
unsigned long r12;
unsigned long bp;
unsigned long bx;
unsigned long r11;
unsigned long r10;
unsigned long r9;
unsigned long r8;
unsigned long ax;
unsigned long cx;
unsigned long dx;
unsigned long si;
unsigned long di;
unsigned long orig_ax;
unsigned long ip;
unsigned long cs;
unsigned long flags;
unsigned long sp;
unsigned long ss;
};]]
parm_to_reg = {parm1='di', parm2='si', parm3='dx', parm4='cx', parm5='r8', ret='sp', fp='bp'}
else
ffi.cdef 'struct pt_regs {};'
end
-- Map symbolic registers to architecture ABI
ffi.metatype('struct pt_regs', {
__index = function (t,k)
return assert(parm_to_reg[k], 'no such register: '..k)
end,
})
local M = {}
-- Dissector interface
local function dissector(type, e, dst, src, field)
local parent = e.V[src].const
-- Create new dissector variable
e.vcopy(dst, src)
-- Compute and materialize new dissector offset from parent
e.V[dst].const = {off=e.V[src].const.off, __dissector=e.V[src].const.__dissector}
parent.__dissector[field](e, dst)
e.V[dst].const.__dissector = type
end
M.dissector = dissector
-- Get current effective offset, load field value at an offset relative to it and
-- add its value to compute next effective offset (e.g. udp_off = ip_off + pkt[ip_off].hlen)
local function next_offset(e, var, type, off, mask, shift)
local d = e.V[var].const
-- Materialize relative offset value in R0
local dst_reg, tmp_reg
if d.off then
dst_reg = e.vreg(var, 0, true)
tmp_reg = dst_reg -- Use target register to avoid copy
e.emit(BPF.LD + BPF.ABS + e.const_width[ffi.sizeof(type)], tmp_reg, 0, 0, d.off + off or 0)
else
tmp_reg = e.vreg(e.tmpvar, 0, true, type) -- Reserve R0 for temporary relative offset
dst_reg = e.vreg(var) -- Must rematerialize (if it was spilled by tmp var)
e.emit(BPF.LD + BPF.IND + e.const_width[ffi.sizeof(type)], tmp_reg, dst_reg, 0, off or 0)
end
-- Finalize relative offset
if mask then
e.emit(BPF.ALU + BPF.AND + BPF.K, tmp_reg, 0, 0, mask)
end
if shift then
local op = BPF.LSH
if shift < 0 then
op = BPF.RSH
shift = -shift
end
e.emit(BPF.ALU + op + BPF.K, tmp_reg, 0, 0, shift)
end
-- Add to base offset to turn it into effective address
if dst_reg ~= tmp_reg then
e.emit(BPF.ALU + BPF.ADD + BPF.X, dst_reg, tmp_reg, 0, 0)
else
e.emit(BPF.ALU + BPF.ADD + BPF.K, dst_reg, 0, 0, d.off)
end
-- Discard temporary allocations
d.off = nil
e.V[e.tmpvar].reg = nil
end
local function next_skip(e, var, off)
local d = e.V[var].const
if not d.off then
local dst_reg = e.vreg(var)
e.emit(BPF.ALU64 + BPF.ADD + BPF.K, dst_reg, 0, 0, off)
else
d.off = d.off + off
end
end
local function skip_eth(e, dst)
-- IP starts right after ETH header (fixed size)
local d = e.V[dst].const
d.off = d.off + ffi.sizeof('struct eth_t')
end
-- Export types
M.type = function(typestr, t)
t = t or {}
t.__dissector=ffi.typeof(typestr)
return t
end
M.skb = M.type('struct sk_buff', {__base=true})
M.pt_regs = M.type('struct pt_regs', {__base=true, source='probe'})
M.pkt = {off=0, __dissector=ffi.typeof('struct eth_t')} -- skb needs special accessors
-- M.eth = function (...) return dissector(ffi.typeof('struct eth_t'), ...) end
M.dot1q = function (...) return dissector(ffi.typeof('struct dot1q_t'), ...) end
M.arp = function (...) return dissector(ffi.typeof('struct arp_t'), ...) end
M.icmp = function (...) return dissector(ffi.typeof('struct icmp_t'), ...) end
M.ip = function (...) return dissector(ffi.typeof('struct ip_t'), ...) end
M.icmp6 = function (...) return dissector(ffi.typeof('struct icmp6_t'), ...) end
M.ip6 = function (...) return dissector(ffi.typeof('struct ip6_t'), ...) end
M.ip6_opt = function (...) return dissector(ffi.typeof('struct ip6_opt_t'), ...) end
M.udp = function (...) return dissector(ffi.typeof('struct udp_t'), ...) end
M.tcp = function (...) return dissector(ffi.typeof('struct tcp_t'), ...) end
M.vxlan = function (...) return dissector(ffi.typeof('struct vxlan_t'), ...) end
M.data = function (...) return dissector(ffi.typeof('uint8_t'), ...) end
M.net_off = function (...) return dissector(ffi.typeof('struct net_off_t'), ...) end
-- Metatables
ffi.metatype(ffi.typeof('struct eth_t'), {
__index = {
ip = skip_eth,
ip6 = skip_eth,
net_off = function (e, dst)
next_skip(e, dst, BPF.NET_OFF)
end,
}
})
ffi.metatype(ffi.typeof('struct net_off_t'), {
__index = {
ip = function () end,
ip6 = function () end,
}
})
ffi.metatype(ffi.typeof('struct ip_t'), {
__index = {
-- Skip IP header length (stored as number of words)
-- e.g. hlen = 5, Header Length = 5 x sizeof(u32) = 20 octets
-- Mask first nibble and shift by 2 (multiplication by 4)
icmp = function(e, dst) next_offset(e, dst, ffi.typeof('uint8_t'), 0, 0x0f, 2) end,
udp = function(e, dst) next_offset(e, dst, ffi.typeof('uint8_t'), 0, 0x0f, 2) end,
tcp = function(e, dst) next_offset(e, dst, ffi.typeof('uint8_t'), 0, 0x0f, 2) end,
}
})
ffi.metatype(ffi.typeof('struct tcp_t'), {
__index = {
-- Skip TCP header length (stored as number of words)
-- e.g. hlen = 5, Header Length = 5 x sizeof(u32) = 20 octets
data = function(e, dst)
next_offset(e, dst, ffi.typeof('uint8_t'), ffi.offsetof('struct tcp_t', 'offset'), 0xf0, -2)
end,
}
})
ffi.metatype(ffi.typeof('struct udp_t'), {
__index = {
-- Skip UDP header length (8 octets)
data = function(e, dst)
next_skip(e, dst, ffi.sizeof('struct udp_t'))
end,
}
})
-- Constants
M.c = {
eth = { -- Constants http://standards.ieee.org/regauth/ethertype
ip = 0x0800, -- IP (v4) protocol
ip6 = 0x86dd, -- IP (v6) protocol
arp = 0x0806, -- Address resolution protocol
revarp = 0x8035, -- Reverse addr resolution protocol
vlan = 0x8100, -- IEEE 802.1Q VLAN tagging
},
ip = {
-- Reserved Addresses
addr_any = 0x00000000, -- 0.0.0.0
addr_broadcast = 0xffffffff, -- 255.255.255.255
addr_loopback = 0x7f000001, -- 127.0.0.1
addr_mcast_all = 0xe0000001, -- 224.0.0.1
addr_mcast_local = 0xe00000ff, -- 224.0.0.255
-- Type of service (ip_tos), RFC 1349 ("obsoleted by RFC 2474")
tos_default = 0x00, -- default
tos_lowdelay = 0x10, -- low delay
tos_throughput = 0x08, -- high throughput
tos_reliability = 0x04, -- high reliability
tos_lowcost = 0x02, -- low monetary cost - XXX
tos_ect = 0x02, -- ECN-capable transport
tos_ce = 0x01, -- congestion experienced
-- Fragmentation flags (ip_off)
rf = 0x8000, -- reserved
df = 0x4000, -- don't fragment
mf = 0x2000, -- more fragments (not last frag)
offmask = 0x1fff, -- mask for fragment offset
-- Time-to-live (ip_ttl), seconds
ttl_default = 64, -- default ttl, RFC 1122, RFC 1340
ttl_max = 255, -- maximum ttl
-- Protocol (ip_p) - http://www.iana.org/assignments/protocol-numbers
proto_ip = 0, -- dummy for IP
proto_hopopts = 0, -- IPv6 hop-by-hop options
proto_icmp = 1, -- ICMP
proto_igmp = 2, -- IGMP
proto_ggp = 3, -- gateway-gateway protocol
proto_ipip = 4, -- IP in IP
proto_st = 5, -- ST datagram mode
proto_tcp = 6, -- TCP
proto_cbt = 7, -- CBT
proto_egp = 8, -- exterior gateway protocol
proto_igp = 9, -- interior gateway protocol
proto_bbnrcc = 10, -- BBN RCC monitoring
proto_nvp = 11, -- Network Voice Protocol
proto_pup = 12, -- PARC universal packet
proto_argus = 13, -- ARGUS
proto_emcon = 14, -- EMCON
proto_xnet = 15, -- Cross Net Debugger
proto_chaos = 16, -- Chaos
proto_udp = 17, -- UDP
proto_mux = 18, -- multiplexing
proto_dcnmeas = 19, -- DCN measurement
proto_hmp = 20, -- Host Monitoring Protocol
proto_prm = 21, -- Packet Radio Measurement
proto_idp = 22, -- Xerox NS IDP
proto_trunk1 = 23, -- Trunk-1
proto_trunk2 = 24, -- Trunk-2
proto_leaf1 = 25, -- Leaf-1
proto_leaf2 = 26, -- Leaf-2
proto_rdp = 27, -- "Reliable Datagram" proto
proto_irtp = 28, -- Inet Reliable Transaction
proto_tp = 29, -- ISO TP class 4
proto_netblt = 30, -- Bulk Data Transfer
proto_mfpnsp = 31, -- MFE Network Services
proto_meritinp= 32, -- Merit Internodal Protocol
proto_sep = 33, -- Sequential Exchange proto
proto_3pc = 34, -- Third Party Connect proto
proto_idpr = 35, -- Interdomain Policy Route
proto_xtp = 36, -- Xpress Transfer Protocol
proto_ddp = 37, -- Datagram Delivery Proto
proto_cmtp = 38, -- IDPR Ctrl Message Trans
proto_tppp = 39, -- TP++ Transport Protocol
proto_il = 40, -- IL Transport Protocol
proto_ip6 = 41, -- IPv6
proto_sdrp = 42, -- Source Demand Routing
proto_routing = 43, -- IPv6 routing header
proto_fragment= 44, -- IPv6 fragmentation header
proto_rsvp = 46, -- Reservation protocol
proto_gre = 47, -- General Routing Encap
proto_mhrp = 48, -- Mobile Host Routing
proto_ena = 49, -- ENA
proto_esp = 50, -- Encap Security Payload
proto_ah = 51, -- Authentication Header
proto_inlsp = 52, -- Integated Net Layer Sec
proto_swipe = 53, -- SWIPE
proto_narp = 54, -- NBMA Address Resolution
proto_mobile = 55, -- Mobile IP, RFC 2004
proto_tlsp = 56, -- Transport Layer Security
proto_skip = 57, -- SKIP
proto_icmp6 = 58, -- ICMP for IPv6
proto_none = 59, -- IPv6 no next header
proto_dstopts = 60, -- IPv6 destination options
proto_anyhost = 61, -- any host internal proto
proto_cftp = 62, -- CFTP
proto_anynet = 63, -- any local network
proto_expak = 64, -- SATNET and Backroom EXPAK
proto_kryptolan = 65, -- Kryptolan
proto_rvd = 66, -- MIT Remote Virtual Disk
proto_ippc = 67, -- Inet Pluribus Packet Core
proto_distfs = 68, -- any distributed fs
proto_satmon = 69, -- SATNET Monitoring
proto_visa = 70, -- VISA Protocol
proto_ipcv = 71, -- Inet Packet Core Utility
proto_cpnx = 72, -- Comp Proto Net Executive
proto_cphb = 73, -- Comp Protocol Heart Beat
proto_wsn = 74, -- Wang Span Network
proto_pvp = 75, -- Packet Video Protocol
proto_brsatmon= 76, -- Backroom SATNET Monitor
proto_sunnd = 77, -- SUN ND Protocol
proto_wbmon = 78, -- WIDEBAND Monitoring
proto_wbexpak = 79, -- WIDEBAND EXPAK
proto_eon = 80, -- ISO CNLP
proto_vmtp = 81, -- Versatile Msg Transport
proto_svmtp = 82, -- Secure VMTP
proto_vines = 83, -- VINES
proto_ttp = 84, -- TTP
proto_nsfigp = 85, -- NSFNET-IGP
proto_dgp = 86, -- Dissimilar Gateway Proto
proto_tcf = 87, -- TCF
proto_eigrp = 88, -- EIGRP
proto_ospf = 89, -- Open Shortest Path First
proto_spriterpc= 90, -- Sprite RPC Protocol
proto_larp = 91, -- Locus Address Resolution
proto_mtp = 92, -- Multicast Transport Proto
proto_ax25 = 93, -- AX.25 Frames
proto_ipipencap= 94, -- yet-another IP encap
proto_micp = 95, -- Mobile Internet Ctrl
proto_sccsp = 96, -- Semaphore Comm Sec Proto
proto_etherip = 97, -- Ethernet in IPv4
proto_encap = 98, -- encapsulation header
proto_anyenc = 99, -- private encryption scheme
proto_gmtp = 100, -- GMTP
proto_ifmp = 101, -- Ipsilon Flow Mgmt Proto
proto_pnni = 102, -- PNNI over IP
proto_pim = 103, -- Protocol Indep Multicast
proto_aris = 104, -- ARIS
proto_scps = 105, -- SCPS
proto_qnx = 106, -- QNX
proto_an = 107, -- Active Networks
proto_ipcomp = 108, -- IP Payload Compression
proto_snp = 109, -- Sitara Networks Protocol
proto_compaqpeer= 110, -- Compaq Peer Protocol
proto_ipxip = 111, -- IPX in IP
proto_vrrp = 112, -- Virtual Router Redundancy
proto_pgm = 113, -- PGM Reliable Transport
proto_any0hop = 114, -- 0-hop protocol
proto_l2tp = 115, -- Layer 2 Tunneling Proto
proto_ddx = 116, -- D-II Data Exchange (DDX)
proto_iatp = 117, -- Interactive Agent Xfer
proto_stp = 118, -- Schedule Transfer Proto
proto_srp = 119, -- SpectraLink Radio Proto
proto_uti = 120, -- UTI
proto_smp = 121, -- Simple Message Protocol
proto_sm = 122, -- SM
proto_ptp = 123, -- Performance Transparency
proto_isis = 124, -- ISIS over IPv4
proto_fire = 125, -- FIRE
proto_crtp = 126, -- Combat Radio Transport
proto_crudp = 127, -- Combat Radio UDP
proto_sscopmce= 128, -- SSCOPMCE
proto_iplt = 129, -- IPLT
proto_sps = 130, -- Secure Packet Shield
proto_pipe = 131, -- Private IP Encap in IP
proto_sctp = 132, -- Stream Ctrl Transmission
proto_fc = 133, -- Fibre Channel
proto_rsvpign = 134, -- RSVP-E2E-IGNORE
proto_raw = 255, -- Raw IP packets
proto_reserved= 255, -- Reserved
},
}
return M