1 ----------------------------------------
2 -- script-name: proto.lua
3 -- Test the Proto/ProtoField API
4 ----------------------------------------
6 ------------- general test helper funcs ------------
7 local testlib
= require("testlib")
11 -- expected number of runs per type
12 -- # of fields test doesn't work on Lua 5.4
16 testlib
.init(taptests
)
19 -- the following are so we can use pcall (which needs a function to call)
20 local function callFunc(func
,...)
24 local function callObjFuncGetter(vart
,varn
,tobj
,name
,...)
25 vart
[varn
] = tobj
[name
](...)
28 local function setValue(tobj
,name
,value
)
32 local function getValue(tobj
,name
)
33 local foo
= tobj
[name
]
36 ------------- test script ------------
38 ----------------------------------------
39 -- creates a Proto object, but doesn't register it yet
40 testlib
.testing(OTHER
,"Proto creation")
42 testlib
.test(OTHER
,"Proto.__call", pcall(callFunc
,Proto
,"foo","Foo Protocol"))
43 testlib
.test(OTHER
,"Proto.__call", pcall(callFunc
,Proto
,"foo1","Foo1 Protocol"))
44 testlib
.test(OTHER
,"Proto.__call", not pcall(callFunc
,Proto
,"","Bar Protocol"))
45 testlib
.test(OTHER
,"Proto.__call", not pcall(callFunc
,Proto
,nil,"Bar Protocol"))
46 testlib
.test(OTHER
,"Proto.__call", not pcall(callFunc
,Proto
,"bar",""))
47 testlib
.test(OTHER
,"Proto.__call", not pcall(callFunc
,Proto
,"bar",nil))
50 local dns
= Proto("mydns","MyDNS Protocol")
52 testlib
.test(OTHER
,"Proto.__tostring", tostring(dns
) == "Proto: MYDNS")
54 ----------------------------------------
55 -- multiple ways to do the same thing: create a protocol field (but not register it yet)
56 -- the abbreviation should always have "<myproto>." before the specific abbreviation, to avoid collisions
57 testlib
.testing(OTHER
,"ProtoField creation")
59 local pfields
= {} -- a table to hold fields, so we can pass them back/forth through pcall()
60 --- variable -- what dissector.lua did, so we almost match it
61 local pf_trasaction_id
= 1 -- ProtoField.new("Transaction ID", "mydns.trans_id", ftypes.UINT16)
62 local pf_flags
= 2 -- ProtoField.new("Flags", "mydns.flags", ftypes.UINT16, nil, base.HEX)
63 local pf_num_questions
= 3 -- ProtoField.uint16("mydns.num_questions", "Number of Questions")
64 local pf_num_answers
= 4 -- ProtoField.uint16("mydns.num_answers", "Number of Answer RRs")
65 local pf_num_authority_rr
= 5 -- ProtoField.uint16("mydns.num_authority_rr", "Number of Authority RRs")
66 local pf_num_additional_rr
= 6 -- ProtoField.uint16("mydns.num_additional_rr", "Number of Additional RRs")
68 testlib
.test(OTHER
,"ProtoField.new",pcall(callObjFuncGetter
, pfields
,pf_trasaction_id
, ProtoField
,"new", "Transaction ID", "mydns.trans_id", ftypes
.INT16
,nil,"base.DEC"))
69 testlib
.test(OTHER
,"ProtoField.new",pcall(callObjFuncGetter
, pfields
,pf_flags
, ProtoField
,"new", "Flags", "mydns.flags", ftypes
.UINT16
, nil, "base.HEX"))
71 -- tries to register a field that already exists (from the real dns proto dissector) but with incompatible type
72 testlib
.test(OTHER
,"ProtoField.new_duplicate_bad",not pcall(callObjFuncGetter
, pfields
,10, ProtoField
,"new", "Flags", "dns.flags", ftypes
.INT16
, nil, "base.HEX"))
73 testlib
.test(OTHER
,"ProtoField.int16_duplicate_bad",not pcall(callObjFuncGetter
, pfields
,10, ProtoField
,"int16", "dns.id","Transaction ID"))
74 -- now compatible (but different type)
75 testlib
.test(OTHER
,"ProtoField.new_duplicate_ok",pcall(callObjFuncGetter
, pfields
,10, ProtoField
,"new", "Flags", "dns.flags", ftypes
.UINT32
, nil, "base.HEX"))
76 testlib
.test(OTHER
,"ProtoField.uint16_duplicate_ok",pcall(callObjFuncGetter
, pfields
,10, ProtoField
,"uint16", "dns.id","Transaction ID"))
78 -- invalid valuestring arg
79 testlib
.test(OTHER
,"ProtoField.new_invalid_valuestring",not pcall(callObjFuncGetter
, pfields
,10, ProtoField
,"new", "Transaction ID", "mydns.trans_id", ftypes
.INT16
,"howdy","base.DEC"))
81 testlib
.test(OTHER
,"ProtoField.new_invalid_ftype",not pcall(callObjFuncGetter
, pfields
,10, ProtoField
,"new", "Transaction ID", "mydns.trans_id", 9999))
82 -- invalid description
83 --testlib.test(OTHER,"ProtoField.new_invalid_description",not pcall(callObjFuncGetter, pfields,10, ProtoField,"new", "", "mydns.trans_id", ftypes.INT16))
84 testlib
.test(OTHER
,"ProtoField.new_invalid_description",not pcall(callObjFuncGetter
, pfields
,10, ProtoField
,"new", nil, "mydns.trans_id", ftypes
.INT16
))
86 testlib
.test(OTHER
,"ProtoField.new_invalid_abbr",not pcall(callObjFuncGetter
, pfields
,10, ProtoField
,"new", "trans id", "", ftypes
.INT16
))
87 testlib
.test(OTHER
,"ProtoField.new_invalid_abbr",not pcall(callObjFuncGetter
, pfields
,10, ProtoField
,"new", "trans id", nil, ftypes
.INT16
))
89 testlib
.test(OTHER
,"ProtoField.int16",pcall(callObjFuncGetter
, pfields
,pf_num_questions
, ProtoField
,"int16", "mydns.num_questions", "Number of Questions"))
90 testlib
.test(OTHER
,"ProtoField.int16",pcall(callObjFuncGetter
, pfields
,pf_num_answers
, ProtoField
,"int16", "mydns.num_answers", "Number of Answer RRs",base
.DEC
))
91 testlib
.test(OTHER
,"ProtoField.int16",pcall(callObjFuncGetter
, pfields
,pf_num_authority_rr
, ProtoField
,"int16", "mydns.num_authority_rr", "Number of Authority RRs",base
.DEC
))
92 testlib
.test(OTHER
,"ProtoField.int16",pcall(callObjFuncGetter
, pfields
,pf_num_additional_rr
, ProtoField
,"int16", "mydns.num_additional_rr", "Number of Additional RRs"))
94 -- now undo the table thingy
95 pf_trasaction_id
= pfields
[pf_trasaction_id
]
96 pf_flags
= pfields
[pf_flags
]
97 pf_num_questions
= pfields
[pf_num_questions
]
98 pf_num_answers
= pfields
[pf_num_answers
]
99 pf_num_authority_rr
= pfields
[pf_num_authority_rr
]
100 pf_num_additional_rr
= pfields
[pf_num_additional_rr
]
102 -- within the flags field, we want to parse/show the bits separately
103 -- note the "base" argument becomes the size of the bitmask'ed field when ftypes.BOOLEAN is used
104 -- the "mask" argument is which bits we want to use for this field (e.g., base=16 and mask=0x8000 means we want the top bit of a 16-bit field)
105 -- again the following shows different ways of doing the same thing basically
106 local pf_flag_response
= ProtoField
.new("Response", "mydns.flags.response", ftypes
.BOOLEAN
, {"this is a response","this is a query"}, 16, 0x8000, "is the message a response?")
107 local pf_flag_opcode
= ProtoField
.new("Opcode", "mydns.flags.opcode", ftypes
.UINT16
, nil, base
.DEC
, 0x7800, "operation code")
108 local pf_flag_authoritative
= ProtoField
.new("Authoritative", "mydns.flags.authoritative", ftypes
.BOOLEAN
, nil, 16, 0x0400, "is the response authoritative?")
109 local pf_flag_truncated
= ProtoField
.bool("mydns.flags.truncated", "Truncated", 16, nil, 0x0200, "is the message truncated?")
110 local pf_flag_recursion_desired
= ProtoField
.bool("mydns.flags.recursion_desired", "Recursion desired", 16, {"yes","no"}, 0x0100, "do the query recursivley?")
111 local pf_flag_recursion_available
= ProtoField
.bool("mydns.flags.recursion_available", "Recursion available", 16, nil, 0x0080, "does the server support recursion?")
112 local pf_flag_z
= ProtoField
.uint16("mydns.flags.z", "World War Z - Reserved for future use", base
.HEX
, nil, 0x0040, "when is it the future?")
113 local pf_flag_authenticated
= ProtoField
.bool("mydns.flags.authenticated", "Authenticated", 16, {"yes","no"}, 0x0020, "did the server DNSSEC authenticate?")
114 local pf_flag_checking_disabled
= ProtoField
.bool("mydns.flags.checking_disabled", "Checking disabled", 16, nil, 0x0010)
116 -- no, these aren't all the DNS response codes - this is just an example
119 [1] = "Format Error",
120 [2] = "Server Failure",
121 [3] = "Non-Existent Domain",
122 [9] = "Server Not Authoritative for zone"
124 -- the above rcodes table is used in this next ProtoField
125 local pf_flag_rcode
= ProtoField
.uint16("mydns.flags.rcode", "Response code", base
.DEC
, rcodes
, 0x000F)
126 local pf_query
= ProtoField
.new("Query", "mydns.query", ftypes
.BYTES
)
127 local pf_query_name
= ProtoField
.new("Name", "mydns.query.name", ftypes
.STRING
)
128 local pf_query_name_len
= ProtoField
.new("Name Length", "mydns.query.name.len", ftypes
.UINT8
)
129 local pf_query_label_count
= ProtoField
.new("Label Count", "mydns.query.label.count", ftypes
.UINT8
)
130 local rrtypes
= { [1] = "A (IPv4 host address)", [2] = "NS (authoritative name server)", [28] = "AAAA (for geeks only)" }
131 local pf_query_type
= ProtoField
.uint16("mydns.query.type", "Type", base
.DEC
, rrtypes
)
132 -- again, not all class types are listed here
135 [1] = "IN (Internet)",
138 [6] = "Business class",
139 [65535] = "Cattle class"
141 local pf_query_class
= ProtoField
.uint16("mydns.query.class", "Class", base
.DEC
, classes
, nil, "keep it classy folks")
144 testlib
.testing(OTHER
,"Proto functions")
146 ----------------------------------------
147 -- this actually registers the ProtoFields above, into our new Protocol
148 -- in a real script I wouldn't do it this way; I'd build a table of fields programaticaly
149 -- and then set dns.fields to it, so as to avoid forgetting a field
150 local myfields
= { pf_trasaction_id
, pf_flags
,
151 pf_num_questions
, pf_num_answers
, pf_num_authority_rr
, pf_num_additional_rr
,
152 pf_flag_response
, pf_flag_opcode
, pf_flag_authoritative
,
153 pf_flag_truncated
, pf_flag_recursion_desired
, pf_flag_recursion_available
,
154 pf_flag_z
, pf_flag_authenticated
, pf_flag_checking_disabled
, pf_flag_rcode
,
155 pf_query
, pf_query_name
, pf_query_name_len
, pf_query_label_count
, pf_query_type
, pf_query_class
}
157 --dns.fields = myfields
158 testlib
.test(OTHER
,"Proto.fields-set", pcall(setValue
,dns
,"fields",myfields
))
159 testlib
.test(OTHER
,"Proto.fields-get", pcall(getValue
,dns
,"fields"))
160 -- This test doesn't work on Lua 5.4 because the # operator includes the
161 -- reference(s) that are the linked list of allocated and free keys,
162 -- starting with LUA_RIDX_LAST + 1 == 3.
163 -- testlib.test(OTHER,"Proto.fields-get", #dns.fields == #myfields)
165 local pf_foo
= ProtoField
.uint16("myfoo.com", "Fooishly", base
.DEC
, rcodes
, 0x000F)
167 local foo
= Proto("myfoo","MyFOO Protocol")
168 local bar
= Proto("mybar","MyBAR Protocol")
170 testlib
.test(OTHER
,"Proto.fields-set", pcall(setValue
,foo
,"fields",pf_foo
))
171 testlib
.test(OTHER
,"Proto.fields-get", #foo
.fields
== 1)
172 testlib
.test(OTHER
,"Proto.fields-get", foo
.fields
[1] == pf_foo
)
174 testlib
.test(OTHER
,"Proto.fields-set", not pcall(setValue
,bar
,"fields","howdy"))
175 testlib
.test(OTHER
,"Proto.fields-set", not pcall(setValue
,bar
,"fields",nil))
176 testlib
.test(OTHER
,"Proto.fields-get", #bar
.fields
== 0)
178 testlib
.test(OTHER
,"Proto.name-get", foo
.name
== "MYFOO")
179 testlib
.test(OTHER
,"Proto.name-set", not pcall(setValue
,foo
,"name","howdy"))
181 testlib
.test(OTHER
,"Proto.description-get", foo
.description
== "MyFOO Protocol")
182 testlib
.test(OTHER
,"Proto.description-set", not pcall(setValue
,foo
,"description","howdy"))
184 testlib
.test(OTHER
,"Proto.prefs-get", typeof(foo
.prefs
) == "Prefs")
185 testlib
.test(OTHER
,"Proto.prefs-set", not pcall(setValue
,foo
,"prefs","howdy"))
187 local function dummy()
189 error("dummy function called!")
193 -- can't get this because we haven't set it yet
194 testlib
.test(OTHER
,"Proto.dissector-get", not pcall(getValue
,foo
,"dissector"))
196 testlib
.test(OTHER
,"Proto.dissector-set", pcall(setValue
,foo
,"dissector",dummy
))
197 testlib
.test(OTHER
,"Proto.dissector-set", not pcall(setValue
,foo
,"dissector","howdy"))
198 testlib
.test(OTHER
,"Proto.dissector-get", pcall(getValue
,foo
,"dissector"))
200 testlib
.test(OTHER
,"Proto.prefs_changed-set", pcall(setValue
,foo
,"prefs_changed",dummy
))
201 testlib
.test(OTHER
,"Proto.prefs_changed-get", not pcall(getValue
,foo
,"prefs_changed"))
202 testlib
.test(OTHER
,"Proto.prefs_changed-set", not pcall(setValue
,foo
,"prefs_changed","howdy"))
204 local function dummy_init()
205 testlib
.test(OTHER
,"Proto.init-called",true)
208 testlib
.test(OTHER
,"Proto.init-set", pcall(setValue
,foo
,"init",dummy_init
))
209 testlib
.test(OTHER
,"Proto.init-set", pcall(setValue
,bar
,"init",dummy_init
))
211 testlib
.test(OTHER
,"Proto.init-get", not pcall(getValue
,foo
,"init"))
212 testlib
.test(OTHER
,"Proto.init-set", not pcall(setValue
,foo
,"init","howdy"))