├── .gitignore ├── LICENSE ├── README.md ├── after ├── indent │ └── lua.vim └── syntax │ └── lua.vim └── tests ├── basic ├── basic_001.OUT.lua ├── basic_001.in.lua ├── basic_001.ok.lua ├── basic_002.OUT.lua ├── basic_002.in.lua ├── basic_002.ok.lua ├── basic_003.OUT.lua ├── basic_003.in.lua ├── basic_003.ok.lua ├── basic_004.OUT.lua ├── basic_004.in.lua ├── basic_004.ok.lua ├── comment_001.OUT.lua ├── comment_001.in.lua ├── test_001.OUT.lua ├── test_001.in.lua ├── test_001.ok.lua ├── test_002.OUT.lua ├── test_002.in.lua ├── test_002.ok.lua ├── test_003.OUT.lua ├── test_003.in.lua ├── test_003.ok.lua ├── test_004.OUT.lua ├── test_004.in.lua ├── test_004.ok.lua ├── test_005.OUT.lua ├── test_005.in.lua ├── test_005.ok.lua ├── tricky_001.OUT.lua ├── tricky_001.in.lua ├── tricky_001.ok.lua ├── tricky_002.OUT.lua ├── tricky_002.in.lua ├── tricky_002.ok.lua ├── tricky_003.OUT.lua ├── tricky_003.in.lua └── tricky_003.ok.lua ├── basic_passthrough ├── comment_001.OUT.lua ├── comment_001.in.lua └── comment_001.ok.lua ├── nmap ├── COPYING ├── afp.ok.lua ├── ajp.ok.lua ├── amqp.ok.lua ├── anyconnect.ok.lua ├── asn1.ok.lua ├── base32.ok.lua ├── base64.ok.lua ├── bitcoin.ok.lua ├── bittorrent.ok.lua ├── bjnp.ok.lua ├── brute.ok.lua ├── cassandra.ok.lua ├── citrixxml.ok.lua ├── comm.ok.lua ├── creds.ok.lua ├── cvs.ok.lua ├── datafiles.ok.lua ├── dhcp.ok.lua ├── dhcp6.ok.lua ├── dns.ok.lua ├── dnsbl.ok.lua ├── dnssd.ok.lua ├── drda.ok.lua ├── eap.ok.lua ├── eigrp.ok.lua ├── formulas.ok.lua ├── ftp.ok.lua ├── giop.ok.lua ├── gps.ok.lua ├── http.ok.lua ├── httpspider.ok.lua ├── iax2.ok.lua ├── ike.ok.lua ├── imap.ok.lua ├── informix.ok.lua ├── ipOps.ok.lua ├── ipp.ok.lua ├── iscsi.ok.lua ├── isns.ok.lua ├── jdwp.ok.lua ├── json.ok.lua ├── ldap.ok.lua ├── listop.ok.lua ├── lpeg-utility.ok.lua ├── match.ok.lua ├── membase.ok.lua ├── mobileme.ok.lua ├── mongodb.ok.lua ├── msrpc.ok.lua ├── msrpcperformance.ok.lua ├── msrpctypes.ok.lua ├── mssql.ok.lua ├── mysql.ok.lua ├── natpmp.ok.lua ├── ncp.ok.lua ├── ndmp.ok.lua ├── netbios.ok.lua ├── nrpc.ok.lua ├── nsedebug.ok.lua ├── omp2.ok.lua ├── ospf.ok.lua ├── packet.ok.lua ├── pgsql.ok.lua ├── pop3.ok.lua ├── pppoe.ok.lua ├── proxy.ok.lua ├── rdp.ok.lua ├── re.ok.lua ├── redis.ok.lua ├── rmi.ok.lua ├── rpc.ok.lua ├── rpcap.ok.lua ├── rsync.ok.lua ├── rtsp.ok.lua ├── sasl.ok.lua ├── shortport.ok.lua ├── sip.ok.lua ├── slaxml.ok.lua ├── smb.ok.lua ├── smbauth.ok.lua ├── smtp.ok.lua ├── snmp.ok.lua ├── socks.ok.lua ├── srvloc.ok.lua ├── ssh1.ok.lua ├── ssh2.ok.lua ├── sslcert.ok.lua ├── stdnse.ok.lua ├── strbuf.ok.lua ├── strict.ok.lua ├── stun.ok.lua ├── tab.ok.lua ├── target.ok.lua ├── tftp.ok.lua ├── tls.ok.lua ├── tns.ok.lua ├── unicode.ok.lua ├── unittest.ok.lua ├── unpwdb.ok.lua ├── upnp.ok.lua ├── url.ok.lua ├── versant.ok.lua ├── vnc.ok.lua ├── vulns.ok.lua ├── vuzedht.ok.lua ├── wsdd.ok.lua ├── xdmcp.ok.lua └── xmpp.ok.lua ├── results.diff ├── run.sh └── tsukuyomi ├── tsukuyomi_001.OUT.lua ├── tsukuyomi_001.in.lua ├── tsukuyomi_001.ok.lua ├── tsukuyomi_002.OUT.lua ├── tsukuyomi_002.in.lua ├── tsukuyomi_002.ok.lua ├── tsukuyomi_003.OUT.lua ├── tsukuyomi_003.in.lua ├── tsukuyomi_003.ok.lua ├── tsukuyomi_004.OUT.lua ├── tsukuyomi_004.in.lua ├── tsukuyomi_004.ok.lua ├── tsukuyomi_005.OUT.lua ├── tsukuyomi_005.in.lua ├── tsukuyomi_005.ok.lua ├── tsukuyomi_006.OUT.lua ├── tsukuyomi_006.in.lua └── tsukuyomi_006.ok.lua /.gitignore: -------------------------------------------------------------------------------- 1 | /tests/basic/*.in.lua 2 | /tests/basic/*.OUT.lua 3 | 4 | /tests/basic_passthrough/*.in.lua 5 | /tests/basic_passthrough/*.OUT.lua 6 | 7 | /tests/tsukuyomi/*.in.lua 8 | /tests/tsukuyomi/*.OUT.lua 9 | 10 | /tests/nmap/*.in.lua 11 | /tests/nmap/*.OUT.lua 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Raymond W. Ko 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | vim-lua-indent 2 | ============== 3 | 4 | A somewhat better Lua indent script for Vim 5 | 6 | This is a hastily hacked on version of the lua.vim indent file that ships with 7 | Vim. It auto-indents much better than the default one, especially when you have 8 | function arguments that span multiple lines inside of conditionals or just a 9 | function's multi-line argument list itself. 10 | 11 | For an example of what it can accomplish, go here: 12 | https://gist.github.com/4208232 13 | 14 | INSTALL 15 | ------- 16 | Copy the lua.vim file into the indent/ folder of your $HOME/.vim/ or $HOME/vimfiles/ directory. 17 | Or, use vim-pathogen to manage it as a bundle (recommended). 18 | -------------------------------------------------------------------------------- /after/indent/lua.vim: -------------------------------------------------------------------------------- 1 | " Vim indent file 2 | " Language: Lua script 3 | " Maintainer: Raymond W. Ko 4 | " Former Maintainer: Marcus Aurelius Farias 5 | " First Author: Max Ischenko 6 | " Last Change: 2015 Aug 14 7 | " Report Issues At: https://github.com/raymond-w-ko/vim-lua-indent 8 | 9 | setlocal indentexpr=GetLuaIndent() 10 | setlocal autoindent 11 | 12 | " To make Vim call GetLuaIndent() when it finds '\s*end' or '\s*until' 13 | " on the current line ('else' is default and includes 'elseif'). 14 | setlocal indentkeys+=0=end,0=until,0=elseif,0=else,0=:,) 15 | 16 | " Only define the function once. 17 | if exists("g:lua_indent_version") && g:lua_indent_version == 2 18 | finish 19 | endif 20 | let g:lua_indent_version = 2 21 | 22 | function s:IsLineBlank(line) 23 | return a:line =~# '\m\v^\s*$' 24 | endfunction 25 | 26 | function s:FilterStrings(line) 27 | let line = a:line 28 | " remove string escape to avoid confusing following regexps 29 | let line = substitute(line, '\v\m\\\\', '', 'g') 30 | let line = substitute(line, '\v\m\\"', '', 'g') 31 | let line = substitute(line, '\v\m\\''', '', 'g') 32 | " remove strings from consideration 33 | let line = substitute(line, '\v\m".\{-}"', '', 'g') 34 | let line = substitute(line, '\v\m''.\{-}''', '', 'g') 35 | let line = substitute(line, '\v\m\[\[.*\]\]', '', 'g') 36 | return line 37 | endfunction 38 | 39 | function s:IsBlockBegin(line) 40 | if a:line =~# '\m\v^\s*%(if>|for>|while>|repeat>|else>|elseif>|do>|then>|function>|local\s*function>)' 41 | if a:line =~# '\m\v^.*.*' 42 | return 0 43 | else 44 | return 1 45 | end 46 | endif 47 | 48 | let line = s:FilterStrings(a:line) 49 | 50 | if line =~# '\m\v^.*\s*\=\s*function>.*' 51 | return 1 52 | elseif line =~# '\m\vreturn\s+function>' && !(line =~# '\m\v.*') 53 | return 1 54 | endif 55 | 56 | return 0 57 | endfunction 58 | 59 | function s:IsBlockEnd(line) 60 | return a:line =~# '\m\v^\s*%(end>|else>|elseif>|until>|\})' 61 | endfunction 62 | function s:HasImmediateBlockEnd(line) 63 | return a:line =~# '\m\v%(|until>)' 64 | endfunction 65 | 66 | function s:IsAssignmentAndRvalue(line) 67 | return a:line =~# '\m\v^\s*\=' 68 | endfunction 69 | 70 | function s:IsTableBegin(line) 71 | let line = s:FilterStrings(a:line) 72 | 73 | if (line =~# '\m.*{.*}.*') 74 | return 0 75 | elseif (line =~# '\m.*{.*') 76 | return 1 77 | else 78 | return 0 79 | endif 80 | endfunction 81 | 82 | function s:HasFuncCall(line) 83 | return a:line =~# '\m\v\S+\(.*' 84 | endfunction 85 | 86 | function s:IsSingleLineComment(line) 87 | return a:line =~# '\m\v^\s*--.*' 88 | endfunction 89 | 90 | function s:synname(...) abort 91 | return synIDattr(synID(a:1, a:2, 1), 'name') 92 | endfunction 93 | 94 | function s:IsMultiLineString() 95 | return s:synname(v:lnum, 1) == 'luaString2' 96 | endfunction 97 | 98 | function s:IsMultiLineComment() 99 | if getline('.') =~# '\m\v^\s*--.*' 100 | return 0 101 | endif 102 | return s:synname(v:lnum, 1) == 'luaComment' 103 | endfunction 104 | 105 | function s:GetStringIndent(str) 106 | let indent = 0 107 | for i in range(len(a:str)) 108 | if a:str[i] == "\t" 109 | let indent += &shiftwidth 110 | elseif a:str[i] == " " 111 | let indent += 1 112 | else 113 | break 114 | endif 115 | endfor 116 | return indent 117 | endfunction 118 | 119 | function s:LinesParenBalanced(lines) 120 | let balance = 0 121 | for line in a:lines 122 | for i in range(len(line)) 123 | if line[i] == '(' 124 | let balance += 1 125 | elseif line[i] == ')' 126 | let balance -= 1 127 | endif 128 | endfor 129 | endfor 130 | 131 | return balance == 0 132 | endfunction 133 | 134 | function s:IsParenBalanced(line) 135 | return s:LinesParenBalanced([a:line]) 136 | endfunction 137 | 138 | function s:ParenthesizedRvalue(line) 139 | return a:line =~# '\m\v\s*\=\s*\(\s*.+' 140 | endfunction 141 | 142 | " Retrieve the previous relevants lines used to determine indenting. 143 | " 144 | " Hopefully most of the times it will be a single line like: 145 | " ....foo = bar + 1 146 | " ....foo() 147 | " 148 | " But sometimes it can get complicated like: 149 | " func(arg1, 150 | " .....arg2, 151 | " .....arg3, 152 | " 153 | " or even 154 | " if (long_func_call(arg1, 155 | " ...................arg2, 156 | " ...................arg3)) 157 | " ....return foo 158 | " end 159 | function! s:GetPrevLines() 160 | let lines = [] 161 | 162 | let i = line('.') 163 | let multiline = 0 164 | while 1 165 | let i -= 1 166 | if i <= 0 167 | return 0 168 | endif 169 | " $DEITY help you if your function calls span more than 8 lines 170 | " avoid O(n^2) problem in long data tables 171 | if len(lines) > 8 172 | break 173 | endif 174 | 175 | let line = getline(i) 176 | let line = substitute(line, '\v\m\[\[.*\]\]', '', 'g') 177 | 178 | if multiline 179 | if !(line =~# '\m\v.*\[\[.*') 180 | continue 181 | else 182 | let multiline = 0 183 | endif 184 | endif 185 | " consider case where you are indexing with an index that itself is an 186 | " index like return nmap.registry.args[argument_frags[2]] 187 | if (line =~# '\m\v.*\]\].*') && !(line =~# '\m\v.*\[.+\[.*') 188 | let multiline = 1 189 | continue 190 | endif 191 | 192 | if s:IsLineBlank(line) 193 | continue 194 | endif 195 | 196 | call insert(lines, line, 0) 197 | 198 | if s:IsBlockBegin(line) || s:IsBlockEnd(line) || s:IsSingleLineComment(line) 199 | break 200 | endif 201 | 202 | " part of a function call argument list, or table 203 | if match(line, '\v^.+,\s*') > -1 204 | continue 205 | endif 206 | 207 | if s:IsParenBalanced(line) || s:IsTableBegin(line) || s:HasFuncCall(line) 208 | break 209 | endif 210 | endwhile 211 | 212 | return lines 213 | endfunction 214 | " TODO: remove this 215 | function! LuaGetPrevLines() 216 | return s:GetPrevLines() 217 | endfunction 218 | 219 | " Tries the best effort to the find the opening '(' which marks a multi line 220 | " expression. However, sometimes it well balanced, meaning there is not such 221 | " opening locally, or such an opening would give too much indent (immediate 222 | " anonymous function as argument) 223 | function! s:FindFirstUnbalancedParen(lines) 224 | let balance = 0 225 | let line_indent = 0 226 | let multiline = 0 227 | 228 | for line_index in range(v:lnum - 1, 0, -1) 229 | let line = getline(line_index) 230 | 231 | if multiline 232 | if !(line =~# '\m\v.*\[\[.*') 233 | continue 234 | else 235 | let multiline = 0 236 | endif 237 | endif 238 | if (line =~# '\m\v.*\]\].*') 239 | let multiline = 1 240 | continue 241 | endif 242 | 243 | " remove comments from consideration 244 | let line = substitute(line, '\v\m--.*$', '', 'g') 245 | let line = substitute(line, '\v\m\[\[.*$', '', 'g') 246 | 247 | let line = s:FilterStrings(line) 248 | 249 | for i in range(strlen(line) - 1, 0, -1) 250 | if line[i] == ')' 251 | let balance += 1 252 | elseif line[i] == '(' 253 | let balance -= 1 254 | if balance < 0 255 | if match(line, '\v^.+\(.*' ) > -1 256 | return s:GetStringIndent(line) + &shiftwidth 257 | else 258 | return i + 1 259 | endif 260 | endif 261 | endif 262 | endfor 263 | 264 | " turns out it was not so unbalanced 265 | if balance == 0 266 | if s:IsLineBlank(line) 267 | continue 268 | endif 269 | return s:GetStringIndent(line) 270 | endif 271 | endfor 272 | 273 | return 0 274 | endfunction 275 | 276 | function s:NumClosingParentheses(line) 277 | if a:line !~# '\v\m^\s*[)]\+\s*$' 278 | return 0 279 | endif 280 | return strlen(substitute(a:line, '\v\m[^\)]', '', 'g')) 281 | endfunction 282 | 283 | function! GetLuaIndent() 284 | " base case or first line 285 | if v:lnum - 1 <= 0 286 | return 0 287 | endif 288 | 289 | if s:IsMultiLineString() || s:IsMultiLineComment() 290 | return indent(v:lnum) 291 | endif 292 | 293 | let cur_line = getline(v:lnum) 294 | 295 | let prev_lines = s:GetPrevLines() 296 | let prev_lines_len = len(prev_lines) 297 | if prev_lines_len == 0 298 | return 0 299 | elseif prev_lines_len == 1 300 | let indent = s:GetStringIndent(prev_lines[0]) 301 | else 302 | let indent = s:GetStringIndent(prev_lines[0]) 303 | endif 304 | 305 | " if the previous "line" has a block begin, start a new indent 306 | if s:LinesParenBalanced(prev_lines) 307 | if s:IsSingleLineComment(prev_lines[0]) 308 | " pass 309 | elseif s:IsBlockBegin(prev_lines[0]) || s:IsTableBegin(prev_lines[0]) 310 | let indent += &shiftwidth 311 | if s:HasImmediateBlockEnd(prev_lines[0]) 312 | let indent -= &shiftwidth 313 | endif 314 | endif 315 | else 316 | if s:IsSingleLineComment(prev_lines[-1]) 317 | return s:GetStringIndent(prev_lines[-1]) 318 | endif 319 | if !s:ParenthesizedRvalue(prev_lines[-1]) && !s:IsParenBalanced(prev_lines[-1]) 320 | " function( 321 | " ....shiftwidth, 322 | if match(prev_lines[-1], '\v^.*\(\s*$') > -1 323 | let indent = s:GetStringIndent(prev_lines[-1]) + &shiftwidth 324 | else 325 | " function(arg1, 326 | " .........X 327 | let indent = s:FindFirstUnbalancedParen(prev_lines) 328 | endif 329 | else 330 | let indent = s:GetStringIndent(prev_lines[-1]) 331 | endif 332 | endif 333 | 334 | if s:IsBlockEnd(cur_line) 335 | let indent -= &shiftwidth 336 | endif 337 | if s:IsAssignmentAndRvalue(cur_line) 338 | let indent += &shiftwidth 339 | endif 340 | let indent -= s:NumClosingParentheses(cur_line) * &shiftwidth 341 | 342 | return indent 343 | endfunction 344 | -------------------------------------------------------------------------------- /after/syntax/lua.vim: -------------------------------------------------------------------------------- 1 | " LuaJIT BitOp functions by Mike Pall 2 | " 3 | " Rationale: LuaJIT is fairly popular among Lua users due to the speed 4 | " increases provided by the JIT compiler. I don't see why this shouldn't be 5 | " included. These fit in the spirit of basic language ops anyways. 6 | " 7 | if lua_version > 5 || (lua_version == 5 && lua_subversion >= 1) 8 | syn match luaFunc /\/ 9 | syn match luaFunc /\/ 10 | syn match luaFunc /\/ 11 | syn match luaFunc /\/ 12 | syn match luaFunc /\/ 13 | syn match luaFunc /\/ 14 | syn match luaFunc /\/ 15 | syn match luaFunc /\/ 16 | syn match luaFunc /\/ 17 | syn match luaFunc /\/ 18 | syn match luaFunc /\/ 19 | syn match luaFunc /\/ 20 | end 21 | -------------------------------------------------------------------------------- /tests/basic/basic_001.OUT.lua: -------------------------------------------------------------------------------- 1 | if cond then 2 | func() 3 | end 4 | 5 | if condition == true then 6 | end 7 | 8 | if condition == true then 9 | local t = { 10 | } 11 | 12 | local t = { 13 | asdf 14 | } 15 | 16 | local t = { 17 | asdf, 18 | foo, 19 | } 20 | end 21 | -- vim: et sw=4 sts=4 ts=4 22 | -------------------------------------------------------------------------------- /tests/basic/basic_001.in.lua: -------------------------------------------------------------------------------- 1 | if cond then 2 | func() 3 | end 4 | 5 | if condition == true then 6 | end 7 | 8 | if condition == true then 9 | local t = { 10 | } 11 | 12 | local t = { 13 | asdf 14 | } 15 | 16 | local t = { 17 | asdf, 18 | foo, 19 | } 20 | end 21 | -- vim: et sw=4 sts=4 ts=4 22 | -------------------------------------------------------------------------------- /tests/basic/basic_001.ok.lua: -------------------------------------------------------------------------------- 1 | if cond then 2 | func() 3 | end 4 | 5 | if condition == true then 6 | end 7 | 8 | if condition == true then 9 | local t = { 10 | } 11 | 12 | local t = { 13 | asdf 14 | } 15 | 16 | local t = { 17 | asdf, 18 | foo, 19 | } 20 | end 21 | -- vim: et sw=4 sts=4 ts=4 22 | -------------------------------------------------------------------------------- /tests/basic/basic_002.OUT.lua: -------------------------------------------------------------------------------- 1 | function foo() 2 | return bar 3 | end 4 | -- vim: et sw=4 sts=4 ts=4 5 | -------------------------------------------------------------------------------- /tests/basic/basic_002.in.lua: -------------------------------------------------------------------------------- 1 | function foo() 2 | return bar 3 | end 4 | -- vim: et sw=4 sts=4 ts=4 5 | -------------------------------------------------------------------------------- /tests/basic/basic_002.ok.lua: -------------------------------------------------------------------------------- 1 | function foo() 2 | return bar 3 | end 4 | -- vim: et sw=4 sts=4 ts=4 5 | -------------------------------------------------------------------------------- /tests/basic/basic_003.OUT.lua: -------------------------------------------------------------------------------- 1 | if foo then 2 | bar() 3 | end 4 | 5 | for k, v in pairs(t) do 6 | bar() 7 | end 8 | 9 | while true do 10 | bar() 11 | end 12 | 13 | while foo() do 14 | bar() 15 | end 16 | 17 | if foo then 18 | bar() 19 | elseif true then 20 | fizz() 21 | end 22 | 23 | if foo then 24 | bar() 25 | elseif true then 26 | fizz() 27 | elseif true then 28 | buzz() 29 | end 30 | 31 | do 32 | stuff() 33 | end 34 | 35 | repeat 36 | download() 37 | until disk_full() 38 | 39 | -- vim: et sw=4 sts=4 ts=4 40 | -------------------------------------------------------------------------------- /tests/basic/basic_003.in.lua: -------------------------------------------------------------------------------- 1 | if foo then 2 | bar() 3 | end 4 | 5 | for k, v in pairs(t) do 6 | bar() 7 | end 8 | 9 | while true do 10 | bar() 11 | end 12 | 13 | while foo() do 14 | bar() 15 | end 16 | 17 | if foo then 18 | bar() 19 | elseif true then 20 | fizz() 21 | end 22 | 23 | if foo then 24 | bar() 25 | elseif true then 26 | fizz() 27 | elseif true then 28 | buzz() 29 | end 30 | 31 | do 32 | stuff() 33 | end 34 | 35 | repeat 36 | download() 37 | until disk_full() 38 | 39 | -- vim: et sw=4 sts=4 ts=4 40 | -------------------------------------------------------------------------------- /tests/basic/basic_003.ok.lua: -------------------------------------------------------------------------------- 1 | if foo then 2 | bar() 3 | end 4 | 5 | for k, v in pairs(t) do 6 | bar() 7 | end 8 | 9 | while true do 10 | bar() 11 | end 12 | 13 | while foo() do 14 | bar() 15 | end 16 | 17 | if foo then 18 | bar() 19 | elseif true then 20 | fizz() 21 | end 22 | 23 | if foo then 24 | bar() 25 | elseif true then 26 | fizz() 27 | elseif true then 28 | buzz() 29 | end 30 | 31 | do 32 | stuff() 33 | end 34 | 35 | repeat 36 | download() 37 | until disk_full() 38 | 39 | -- vim: et sw=4 sts=4 ts=4 40 | -------------------------------------------------------------------------------- /tests/basic/basic_004.OUT.lua: -------------------------------------------------------------------------------- 1 | if foo then 2 | bar() 3 | if fizz then 4 | buzz() 5 | end 6 | elseif true then 7 | fizz() 8 | if quux then 9 | bazz() 10 | end 11 | else 12 | fizz() 13 | 14 | if quux then 15 | 16 | bazz() 17 | 18 | end 19 | end 20 | 21 | -- vim: et sw=4 sts=4 ts=4 22 | -------------------------------------------------------------------------------- /tests/basic/basic_004.in.lua: -------------------------------------------------------------------------------- 1 | if foo then 2 | bar() 3 | if fizz then 4 | buzz() 5 | end 6 | elseif true then 7 | fizz() 8 | if quux then 9 | bazz() 10 | end 11 | else 12 | fizz() 13 | 14 | if quux then 15 | 16 | bazz() 17 | 18 | end 19 | end 20 | 21 | -- vim: et sw=4 sts=4 ts=4 22 | -------------------------------------------------------------------------------- /tests/basic/basic_004.ok.lua: -------------------------------------------------------------------------------- 1 | if foo then 2 | bar() 3 | if fizz then 4 | buzz() 5 | end 6 | elseif true then 7 | fizz() 8 | if quux then 9 | bazz() 10 | end 11 | else 12 | fizz() 13 | 14 | if quux then 15 | 16 | bazz() 17 | 18 | end 19 | end 20 | 21 | -- vim: et sw=4 sts=4 ts=4 22 | -------------------------------------------------------------------------------- /tests/basic/comment_001.OUT.lua: -------------------------------------------------------------------------------- 1 | -- basically a test to make sure it doesn't touch indents inside comments 2 | local comment = [[ 3 | asdf 4 | foobar 5 | fizzbuzz 6 | quux 7 | 42 8 | slide]] 9 | 10 | local comment = [[ 11 | asdf 12 | foobar 13 | fizzbuzz 14 | quux 15 | 42 16 | slide]] 17 | 18 | local comment = [[ 19 | asdf 20 | foobar 21 | fizzbuzz 22 | quux 23 | 42 24 | slide]] 25 | 26 | if condition == true then 27 | local comment = [[ 28 | asdf 29 | foobar 30 | fizzbuzz 31 | quux 32 | 42]] 33 | more_computation() 34 | end 35 | 36 | local a = "asdf" 37 | 38 | --asdf 39 | 40 | --[[ 41 | asdf 42 | foobar 43 | fizzbuzz 44 | quux 45 | 42 46 | slide]] 47 | 48 | 49 | -- vim: et sw=4 sts=4 ts=4 50 | -------------------------------------------------------------------------------- /tests/basic/comment_001.in.lua: -------------------------------------------------------------------------------- 1 | -- basically a test to make sure it doesn't touch indents inside comments 2 | local comment = [[ 3 | asdf 4 | foobar 5 | fizzbuzz 6 | quux 7 | 42 8 | slide]] 9 | 10 | local comment = [[ 11 | asdf 12 | foobar 13 | fizzbuzz 14 | quux 15 | 42 16 | slide]] 17 | 18 | local comment = [[ 19 | asdf 20 | foobar 21 | fizzbuzz 22 | quux 23 | 42 24 | slide]] 25 | 26 | if condition == true then 27 | local comment = [[ 28 | asdf 29 | foobar 30 | fizzbuzz 31 | quux 32 | 42]] 33 | more_computation() 34 | end 35 | 36 | local a = "asdf" 37 | 38 | --asdf 39 | 40 | --[[ 41 | asdf 42 | foobar 43 | fizzbuzz 44 | quux 45 | 42 46 | slide]] 47 | 48 | 49 | -- vim: et sw=4 sts=4 ts=4 50 | -------------------------------------------------------------------------------- /tests/basic/test_001.OUT.lua: -------------------------------------------------------------------------------- 1 | function foo(bar) 2 | a = {} 3 | end 4 | 5 | function foo(bar) 6 | a = { 7 | stuff, 8 | stasdtas, 9 | asdf 10 | } 11 | end 12 | 13 | function foo(long_variable_name, 14 | longer_variable_name, 15 | bar) 16 | stuff 17 | end 18 | 19 | function foo( 20 | long_variable_name, 21 | stuf) 22 | b = {} 23 | end 24 | 25 | -- vim: et sw=4 sts=4 ts=4 26 | -------------------------------------------------------------------------------- /tests/basic/test_001.in.lua: -------------------------------------------------------------------------------- 1 | function foo(bar) 2 | a = {} 3 | end 4 | 5 | function foo(bar) 6 | a = { 7 | stuff, 8 | stasdtas, 9 | asdf 10 | } 11 | end 12 | 13 | function foo(long_variable_name, 14 | longer_variable_name, 15 | bar) 16 | stuff 17 | end 18 | 19 | function foo( 20 | long_variable_name, 21 | stuf) 22 | b = {} 23 | end 24 | 25 | -- vim: et sw=4 sts=4 ts=4 26 | -------------------------------------------------------------------------------- /tests/basic/test_001.ok.lua: -------------------------------------------------------------------------------- 1 | function foo(bar) 2 | a = {} 3 | end 4 | 5 | function foo(bar) 6 | a = { 7 | stuff, 8 | stasdtas, 9 | asdf 10 | } 11 | end 12 | 13 | function foo(long_variable_name, 14 | longer_variable_name, 15 | bar) 16 | stuff 17 | end 18 | 19 | function foo( 20 | long_variable_name, 21 | stuf) 22 | b = {} 23 | end 24 | 25 | -- vim: et sw=4 sts=4 ts=4 26 | -------------------------------------------------------------------------------- /tests/basic/test_002.OUT.lua: -------------------------------------------------------------------------------- 1 | function foo(bar) 2 | if (something) then 3 | a:stuff() 4 | end 5 | end 6 | 7 | function foo(bar) 8 | a = { 9 | stuff, 10 | stasdtas, 11 | asdf 12 | } 13 | if (something) then 14 | a:stuff() 15 | end 16 | end 17 | 18 | function foo(long_variable_name, 19 | longer_variable_name, 20 | bar) 21 | if (stuff) then 22 | more_stuff() 23 | end 24 | end 25 | 26 | function foo(long_variable_name, 27 | longer_variable_name, 28 | bar) 29 | if (fn(very_very_very_long_condition, 30 | more_things, 31 | even_more_things)) then 32 | more_stuff() 33 | end 34 | end 35 | 36 | function foo(long_variable_name, 37 | longer_variable_name, 38 | bar) 39 | if (some_function(arg1, 40 | arg2)) then 41 | foobar(arg1) 42 | end 43 | end 44 | 45 | -- vim: et sw=4 sts=4 ts=4 46 | -------------------------------------------------------------------------------- /tests/basic/test_002.in.lua: -------------------------------------------------------------------------------- 1 | function foo(bar) 2 | if (something) then 3 | a:stuff() 4 | end 5 | end 6 | 7 | function foo(bar) 8 | a = { 9 | stuff, 10 | stasdtas, 11 | asdf 12 | } 13 | if (something) then 14 | a:stuff() 15 | end 16 | end 17 | 18 | function foo(long_variable_name, 19 | longer_variable_name, 20 | bar) 21 | if (stuff) then 22 | more_stuff() 23 | end 24 | end 25 | 26 | function foo(long_variable_name, 27 | longer_variable_name, 28 | bar) 29 | if (fn(very_very_very_long_condition, 30 | more_things, 31 | even_more_things)) then 32 | more_stuff() 33 | end 34 | end 35 | 36 | function foo(long_variable_name, 37 | longer_variable_name, 38 | bar) 39 | if (some_function(arg1, 40 | arg2)) then 41 | foobar(arg1) 42 | end 43 | end 44 | 45 | -- vim: et sw=4 sts=4 ts=4 46 | -------------------------------------------------------------------------------- /tests/basic/test_002.ok.lua: -------------------------------------------------------------------------------- 1 | function foo(bar) 2 | if (something) then 3 | a:stuff() 4 | end 5 | end 6 | 7 | function foo(bar) 8 | a = { 9 | stuff, 10 | stasdtas, 11 | asdf 12 | } 13 | if (something) then 14 | a:stuff() 15 | end 16 | end 17 | 18 | function foo(long_variable_name, 19 | longer_variable_name, 20 | bar) 21 | if (stuff) then 22 | more_stuff() 23 | end 24 | end 25 | 26 | function foo(long_variable_name, 27 | longer_variable_name, 28 | bar) 29 | if (fn(very_very_very_long_condition, 30 | more_things, 31 | even_more_things)) then 32 | more_stuff() 33 | end 34 | end 35 | 36 | function foo(long_variable_name, 37 | longer_variable_name, 38 | bar) 39 | if (some_function(arg1, 40 | arg2)) then 41 | foobar(arg1) 42 | end 43 | end 44 | 45 | -- vim: et sw=4 sts=4 ts=4 46 | -------------------------------------------------------------------------------- /tests/basic/test_003.OUT.lua: -------------------------------------------------------------------------------- 1 | function foo( 2 | long_variable_name, 3 | stuf) 4 | if (stuff) then 5 | more_stuff() 6 | end 7 | b = {} 8 | end 9 | 10 | function foo(bar) 11 | a = {} 12 | end 13 | 14 | function foo(bar) 15 | a = { 16 | stuff, 17 | stasdtas, 18 | asdf 19 | } 20 | end 21 | 22 | function foo(long_variable_name, 23 | longer_variable_name, 24 | bar) 25 | stuff 26 | end 27 | 28 | -- vim: et sw=4 sts=4 ts=4 29 | -------------------------------------------------------------------------------- /tests/basic/test_003.in.lua: -------------------------------------------------------------------------------- 1 | function foo( 2 | long_variable_name, 3 | stuf) 4 | if (stuff) then 5 | more_stuff() 6 | end 7 | b = {} 8 | end 9 | 10 | function foo(bar) 11 | a = {} 12 | end 13 | 14 | function foo(bar) 15 | a = { 16 | stuff, 17 | stasdtas, 18 | asdf 19 | } 20 | end 21 | 22 | function foo(long_variable_name, 23 | longer_variable_name, 24 | bar) 25 | stuff 26 | end 27 | 28 | -- vim: et sw=4 sts=4 ts=4 29 | -------------------------------------------------------------------------------- /tests/basic/test_003.ok.lua: -------------------------------------------------------------------------------- 1 | function foo( 2 | long_variable_name, 3 | stuf) 4 | if (stuff) then 5 | more_stuff() 6 | end 7 | b = {} 8 | end 9 | 10 | function foo(bar) 11 | a = {} 12 | end 13 | 14 | function foo(bar) 15 | a = { 16 | stuff, 17 | stasdtas, 18 | asdf 19 | } 20 | end 21 | 22 | function foo(long_variable_name, 23 | longer_variable_name, 24 | bar) 25 | stuff 26 | end 27 | 28 | -- vim: et sw=4 sts=4 ts=4 29 | -------------------------------------------------------------------------------- /tests/basic/test_004.OUT.lua: -------------------------------------------------------------------------------- 1 | function foo( 2 | long_variable_name, 3 | stuf) 4 | b = {} 5 | end 6 | 7 | function foo(bar) 8 | if (something) then 9 | a:stuff() 10 | end 11 | end 12 | 13 | function foo(bar) 14 | func2(handle, self:get_my_handle(), 15 | foo, bar, baz, fizz, buzz) 16 | end 17 | 18 | function foo(bar) 19 | function1(something, bit.bor(1, 2, 4, 8), 20 | some_var) 21 | end 22 | 23 | function foo(bar) 24 | function1( 25 | something, 26 | bit.bor(1, 2, 4, 8), 27 | some_var) 28 | end 29 | 30 | function foo(bar) 31 | function1( 32 | bit.bor(1, 2, 4, 8), 33 | something, 34 | some_var) 35 | end 36 | 37 | function ClassName:FunctionName(VariableName) 38 | local var = func1(something, something2) 39 | if (something ~= something_else) then 40 | return Find(VariableName, "text", more_stuff) 41 | end 42 | return -1 43 | end 44 | 45 | -- vim: et sw=4 sts=4 ts=4 46 | -------------------------------------------------------------------------------- /tests/basic/test_004.in.lua: -------------------------------------------------------------------------------- 1 | function foo( 2 | long_variable_name, 3 | stuf) 4 | b = {} 5 | end 6 | 7 | function foo(bar) 8 | if (something) then 9 | a:stuff() 10 | end 11 | end 12 | 13 | function foo(bar) 14 | func2(handle, self:get_my_handle(), 15 | foo, bar, baz, fizz, buzz) 16 | end 17 | 18 | function foo(bar) 19 | function1(something, bit.bor(1, 2, 4, 8), 20 | some_var) 21 | end 22 | 23 | function foo(bar) 24 | function1( 25 | something, 26 | bit.bor(1, 2, 4, 8), 27 | some_var) 28 | end 29 | 30 | function foo(bar) 31 | function1( 32 | bit.bor(1, 2, 4, 8), 33 | something, 34 | some_var) 35 | end 36 | 37 | function ClassName:FunctionName(VariableName) 38 | local var = func1(something, something2) 39 | if (something ~= something_else) then 40 | return Find(VariableName, "text", more_stuff) 41 | end 42 | return -1 43 | end 44 | 45 | -- vim: et sw=4 sts=4 ts=4 46 | -------------------------------------------------------------------------------- /tests/basic/test_004.ok.lua: -------------------------------------------------------------------------------- 1 | function foo( 2 | long_variable_name, 3 | stuf) 4 | b = {} 5 | end 6 | 7 | function foo(bar) 8 | if (something) then 9 | a:stuff() 10 | end 11 | end 12 | 13 | function foo(bar) 14 | func2(handle, self:get_my_handle(), 15 | foo, bar, baz, fizz, buzz) 16 | end 17 | 18 | function foo(bar) 19 | function1(something, bit.bor(1, 2, 4, 8), 20 | some_var) 21 | end 22 | 23 | function foo(bar) 24 | function1( 25 | something, 26 | bit.bor(1, 2, 4, 8), 27 | some_var) 28 | end 29 | 30 | function foo(bar) 31 | function1( 32 | bit.bor(1, 2, 4, 8), 33 | something, 34 | some_var) 35 | end 36 | 37 | function ClassName:FunctionName(VariableName) 38 | local var = func1(something, something2) 39 | if (something ~= something_else) then 40 | return Find(VariableName, "text", more_stuff) 41 | end 42 | return -1 43 | end 44 | 45 | -- vim: et sw=4 sts=4 ts=4 46 | -------------------------------------------------------------------------------- /tests/basic/test_005.OUT.lua: -------------------------------------------------------------------------------- 1 | if string:match([[pattern]]) then 2 | do_something() 3 | end 4 | -- vim: et sw=4 sts=4 ts=4 5 | -------------------------------------------------------------------------------- /tests/basic/test_005.in.lua: -------------------------------------------------------------------------------- 1 | if string:match([[pattern]]) then 2 | do_something() 3 | end 4 | -- vim: et sw=4 sts=4 ts=4 5 | -------------------------------------------------------------------------------- /tests/basic/test_005.ok.lua: -------------------------------------------------------------------------------- 1 | if string:match([[pattern]]) then 2 | do_something() 3 | end 4 | -- vim: et sw=4 sts=4 ts=4 5 | -------------------------------------------------------------------------------- /tests/basic/tricky_001.OUT.lua: -------------------------------------------------------------------------------- 1 | if conditon == true then 2 | callMyLongFunction( 3 | nestedFunction( 4 | argument 5 | )) 6 | asdf() 7 | end 8 | 9 | if conditon == true then 10 | callMyLongFunction(nestedFunction( 11 | argument)) 12 | end 13 | 14 | if conditon == true then 15 | callMyLongFunction( 16 | nestedFunction( 17 | argument 18 | ) 19 | ) 20 | end 21 | 22 | if conditon == true then 23 | callMyLongFunction( 24 | nestedFunction( 25 | argument 26 | ) 27 | ) 28 | end 29 | 30 | if conditon == true then 31 | callMyLongFunction( 32 | nestedFunction( 33 | argument 34 | ) 35 | ) 36 | stuff() 37 | end 38 | 39 | -- vim: et sw=4 sts=4 ts=4 40 | -------------------------------------------------------------------------------- /tests/basic/tricky_001.in.lua: -------------------------------------------------------------------------------- 1 | if conditon == true then 2 | callMyLongFunction( 3 | nestedFunction( 4 | argument 5 | )) 6 | asdf() 7 | end 8 | 9 | if conditon == true then 10 | callMyLongFunction(nestedFunction( 11 | argument)) 12 | end 13 | 14 | if conditon == true then 15 | callMyLongFunction( 16 | nestedFunction( 17 | argument 18 | ) 19 | ) 20 | end 21 | 22 | if conditon == true then 23 | callMyLongFunction( 24 | nestedFunction( 25 | argument 26 | ) 27 | ) 28 | end 29 | 30 | if conditon == true then 31 | callMyLongFunction( 32 | nestedFunction( 33 | argument 34 | ) 35 | ) 36 | stuff() 37 | end 38 | 39 | -- vim: et sw=4 sts=4 ts=4 40 | -------------------------------------------------------------------------------- /tests/basic/tricky_001.ok.lua: -------------------------------------------------------------------------------- 1 | if conditon == true then 2 | callMyLongFunction( 3 | nestedFunction( 4 | argument 5 | )) 6 | asdf() 7 | end 8 | 9 | if conditon == true then 10 | callMyLongFunction(nestedFunction( 11 | argument)) 12 | end 13 | 14 | if conditon == true then 15 | callMyLongFunction( 16 | nestedFunction( 17 | argument 18 | ) 19 | ) 20 | end 21 | 22 | if conditon == true then 23 | callMyLongFunction( 24 | nestedFunction( 25 | argument 26 | ) 27 | ) 28 | end 29 | 30 | if conditon == true then 31 | callMyLongFunction( 32 | nestedFunction( 33 | argument 34 | ) 35 | ) 36 | stuff() 37 | end 38 | 39 | -- vim: et sw=4 sts=4 ts=4 40 | -------------------------------------------------------------------------------- /tests/basic/tricky_002.OUT.lua: -------------------------------------------------------------------------------- 1 | setTimeout(function() 2 | if condition == true then 3 | return 1 4 | end 5 | end, 1000) 6 | 7 | if condition == true then 8 | setTimeout(function() 9 | if condition == true then 10 | return 1 11 | end 12 | end, 1000) 13 | end 14 | -- vim: et sw=4 sts=4 ts=4 15 | -------------------------------------------------------------------------------- /tests/basic/tricky_002.in.lua: -------------------------------------------------------------------------------- 1 | setTimeout(function() 2 | if condition == true then 3 | return 1 4 | end 5 | end, 1000) 6 | 7 | if condition == true then 8 | setTimeout(function() 9 | if condition == true then 10 | return 1 11 | end 12 | end, 1000) 13 | end 14 | -- vim: et sw=4 sts=4 ts=4 15 | -------------------------------------------------------------------------------- /tests/basic/tricky_002.ok.lua: -------------------------------------------------------------------------------- 1 | setTimeout(function() 2 | if condition == true then 3 | return 1 4 | end 5 | end, 1000) 6 | 7 | if condition == true then 8 | setTimeout(function() 9 | if condition == true then 10 | return 1 11 | end 12 | end, 1000) 13 | end 14 | -- vim: et sw=4 sts=4 ts=4 15 | -------------------------------------------------------------------------------- /tests/basic/tricky_003.OUT.lua: -------------------------------------------------------------------------------- 1 | -- tries to fool the indenter by having ( in the comments 2 | 3 | -- foo( 4 | -- this should not be indented, since the above is meaningless 5 | 6 | if true then 7 | local a = [[ 8 | here is how to call a Lua function: 9 | ....lua_func(arg1,]] 10 | foo() 11 | end 12 | 13 | if valid then 14 | emit("(") 15 | save() 16 | end 17 | 18 | if valid then 19 | emit('(') 20 | save() 21 | end 22 | 23 | if valid then 24 | emit("\"(") 25 | save() 26 | end 27 | 28 | if valid then 29 | emit('\'(') 30 | save() 31 | end 32 | 33 | -- vim: et sw=4 sts=4 ts=4 34 | -------------------------------------------------------------------------------- /tests/basic/tricky_003.in.lua: -------------------------------------------------------------------------------- 1 | -- tries to fool the indenter by having ( in the comments 2 | 3 | -- foo( 4 | -- this should not be indented, since the above is meaningless 5 | 6 | if true then 7 | local a = [[ 8 | here is how to call a Lua function: 9 | ....lua_func(arg1,]] 10 | foo() 11 | end 12 | 13 | if valid then 14 | emit("(") 15 | save() 16 | end 17 | 18 | if valid then 19 | emit('(') 20 | save() 21 | end 22 | 23 | if valid then 24 | emit("\"(") 25 | save() 26 | end 27 | 28 | if valid then 29 | emit('\'(') 30 | save() 31 | end 32 | 33 | -- vim: et sw=4 sts=4 ts=4 34 | -------------------------------------------------------------------------------- /tests/basic/tricky_003.ok.lua: -------------------------------------------------------------------------------- 1 | -- tries to fool the indenter by having ( in the comments 2 | 3 | -- foo( 4 | -- this should not be indented, since the above is meaningless 5 | 6 | if true then 7 | local a = [[ 8 | here is how to call a Lua function: 9 | ....lua_func(arg1,]] 10 | foo() 11 | end 12 | 13 | if valid then 14 | emit("(") 15 | save() 16 | end 17 | 18 | if valid then 19 | emit('(') 20 | save() 21 | end 22 | 23 | if valid then 24 | emit("\"(") 25 | save() 26 | end 27 | 28 | if valid then 29 | emit('\'(') 30 | save() 31 | end 32 | 33 | -- vim: et sw=4 sts=4 ts=4 34 | -------------------------------------------------------------------------------- /tests/basic_passthrough/comment_001.OUT.lua: -------------------------------------------------------------------------------- 1 | -- basically a test to make sure it doesn't touch indents inside comments 2 | local comment = [[ 3 | asdf 4 | foobar 5 | fizzbuzz 6 | quux 7 | 42 8 | slide]] 9 | 10 | local comment = [[ 11 | asdf 12 | foobar 13 | fizzbuzz 14 | quux 15 | 42 16 | slide]] 17 | 18 | local comment = [[ 19 | asdf 20 | foobar 21 | fizzbuzz 22 | quux 23 | 42 24 | slide]] 25 | 26 | if condition == true then 27 | local comment = [[ 28 | asdf 29 | foobar 30 | fizzbuzz 31 | quux 32 | 42]] 33 | more_computation() 34 | end 35 | 36 | local a = "asdf" 37 | 38 | --asdf 39 | 40 | --[[ 41 | asdf 42 | foobar 43 | fizzbuzz 44 | quux 45 | 42 46 | slide]] 47 | 48 | 49 | -- vim: et sw=4 sts=4 ts=4 50 | -------------------------------------------------------------------------------- /tests/basic_passthrough/comment_001.in.lua: -------------------------------------------------------------------------------- 1 | -- basically a test to make sure it doesn't touch indents inside comments 2 | local comment = [[ 3 | asdf 4 | foobar 5 | fizzbuzz 6 | quux 7 | 42 8 | slide]] 9 | 10 | local comment = [[ 11 | asdf 12 | foobar 13 | fizzbuzz 14 | quux 15 | 42 16 | slide]] 17 | 18 | local comment = [[ 19 | asdf 20 | foobar 21 | fizzbuzz 22 | quux 23 | 42 24 | slide]] 25 | 26 | if condition == true then 27 | local comment = [[ 28 | asdf 29 | foobar 30 | fizzbuzz 31 | quux 32 | 42]] 33 | more_computation() 34 | end 35 | 36 | local a = "asdf" 37 | 38 | --asdf 39 | 40 | --[[ 41 | asdf 42 | foobar 43 | fizzbuzz 44 | quux 45 | 42 46 | slide]] 47 | 48 | 49 | -- vim: et sw=4 sts=4 ts=4 50 | -------------------------------------------------------------------------------- /tests/basic_passthrough/comment_001.ok.lua: -------------------------------------------------------------------------------- 1 | -- basically a test to make sure it doesn't touch indents inside comments 2 | local comment = [[ 3 | asdf 4 | foobar 5 | fizzbuzz 6 | quux 7 | 42 8 | slide]] 9 | 10 | local comment = [[ 11 | asdf 12 | foobar 13 | fizzbuzz 14 | quux 15 | 42 16 | slide]] 17 | 18 | local comment = [[ 19 | asdf 20 | foobar 21 | fizzbuzz 22 | quux 23 | 42 24 | slide]] 25 | 26 | if condition == true then 27 | local comment = [[ 28 | asdf 29 | foobar 30 | fizzbuzz 31 | quux 32 | 42]] 33 | more_computation() 34 | end 35 | 36 | local a = "asdf" 37 | 38 | --asdf 39 | 40 | --[[ 41 | asdf 42 | foobar 43 | fizzbuzz 44 | quux 45 | 42 46 | slide]] 47 | 48 | 49 | -- vim: et sw=4 sts=4 ts=4 50 | -------------------------------------------------------------------------------- /tests/nmap/anyconnect.ok.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- This library implements HTTP requests used by the Cisco AnyConnect VPN Client 3 | -- 4 | -- @author "Patrik Karlsson " 5 | -- 6 | -- @args anyconnect.group AnyConnect tunnel group (default: VPN) 7 | -- @args anyconnect.mac MAC address of connecting client (default: random MAC) 8 | -- @args anyconnect.version Version of connecting client (default: 3.1.05160) 9 | -- @args anyconnect.ua User Agent of connecting client (default: AnyConnect Darwin_i386 3.1.05160) 10 | 11 | local http = require('http') 12 | local stdnse = require('stdnse') 13 | local url = require('url') 14 | local math = require('math') 15 | local table = require('table') 16 | local os = require('os') 17 | 18 | local args_group= stdnse.get_script_args('anyconnect.group') or "VPN" 19 | local args_mac= stdnse.get_script_args('anyconnect.mac') 20 | local args_ver = stdnse.get_script_args('anyconnect.version') or "3.1.05160" 21 | local args_ua = stdnse.get_script_args('anyconnect.ua') or ("AnyConnect Darwin_i386 %s"):format(args_ver) 22 | 23 | _ENV = stdnse.module("anyconnect", stdnse.seeall) 24 | 25 | Cisco = { 26 | 27 | Util = { 28 | 29 | generate_mac = function() 30 | math.randomseed(os.time()) 31 | local mac = {} 32 | for i=1,6 do 33 | mac[#mac + 1] = (("%x"):format(math.random(255))):gsub(' ', '0'); 34 | end 35 | return table.concat(mac,':') 36 | end, 37 | 38 | }, 39 | 40 | AnyConnect = { 41 | 42 | new = function(self, host, port) 43 | local o = { host = host, port = port } 44 | setmetatable(o, self) 45 | self.__index = self 46 | return o 47 | end, 48 | 49 | -- generate a random hex-string of length 'length' 50 | -- 51 | generate_random = function(length) 52 | return stdnse.generate_random_string(length * 2, '0123456789ABCDEF') 53 | end, 54 | 55 | connect = function(self) 56 | args_mac = args_mac or Cisco.Util.generate_mac() 57 | local headers = { 58 | ['User-Agent'] = args_ua, 59 | ['Accept'] = '*/*', 60 | ['Accept-Encoding'] = 'identity', 61 | ['X-Transcend-Version'] = 1, 62 | ['X-Aggregate-Auth'] = 1, 63 | ['X-AnyConnect-Platform'] = 'mac-intel' 64 | } 65 | 66 | local data = ([[ 67 | 68 | %s 69 | mac-intel 70 | 71 | %s 72 | %s 73 | https://%s:%s 74 | ]]):format(args_ver, self.generate_random(64), args_mac, args_group, self.host.ip, self.port.number) 75 | 76 | local options = { header=headers , no_cache=true, redirect_ok = function(host,port) 77 | local c = 5 78 | return function(url) 79 | if ( c==0 ) then return false end 80 | c = c - 1 81 | return true 82 | end 83 | end 84 | } 85 | 86 | local path = '/' 87 | local response = http.head(self.host, self.port, path, options) 88 | -- account for redirects 89 | if not response.status == 200 then 90 | return false, "Failed to connect to SSL VPN server" 91 | elseif response.location then 92 | local u = url.parse(response.location[#response.location]) 93 | if u.host then 94 | self.host = u.host 95 | end 96 | if u.path then 97 | path = u.path 98 | end 99 | end 100 | 101 | response = http.post(self.host, self.port, path, options, nil, data) 102 | 103 | if response.status ~= 200 or response.body == nil then 104 | return false, "Not a Cisco ASA or unsupported version" 105 | end 106 | 107 | local xmltags = { 108 | 'version', 109 | 'tunnel-group', 110 | 'group-alias', 111 | 'config-hash', 112 | 'host-scan-ticket', 113 | 'host-scan-token', 114 | 'host-scan-base-uri', 115 | 'host-scan-wait-uri', 116 | 'banner' 117 | } 118 | 119 | self.conn_attr = {} 120 | for _, tag in ipairs(xmltags) do 121 | local body = response.body:gsub('\r?\n', '') 122 | local filter = ("<%s.->(.*)"):format(tag:gsub('-', '%%-'), tag:gsub('-', '%%-')) 123 | local m = body:match(filter) 124 | if m then 125 | self.conn_attr[tag] = m 126 | end 127 | end 128 | 129 | if not self.conn_attr['version'] then 130 | return false, "Not a Cisco ASA or unsupported version" 131 | end 132 | 133 | -- in case we were redirected 134 | self.conn_attr['host'] = stdnse.get_hostname(self.host) 135 | return true 136 | end, 137 | 138 | --- 139 | -- Returns the version of the remote SSL VPN concentrator 140 | -- @return table containing major, minor and rev numeric values 141 | get_version = function(self) 142 | local ver = {} 143 | ver['major'], ver['minor'], ver['rev'] = self.conn_attr['version']:match('^(%d-)%.(%d-)%((.*)%)$') 144 | return ver 145 | end 146 | 147 | } 148 | } 149 | 150 | return _ENV 151 | -------------------------------------------------------------------------------- /tests/nmap/base32.ok.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- Base32 encoding and decoding. Follows RFC 4648. 3 | -- 4 | -- @author Philip Pickering 5 | -- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html 6 | -- @ported base64 to base32 7 | 8 | -- thanks to Patrick Donnelly for some optimizations 9 | 10 | --module(... or "base32",package.seeall) 11 | -- local bin = require 'bin' 12 | -- local stdnse = require 'stdnse' 13 | -- _ENV = stdnse.module("base32", stdnse.seeall) 14 | 15 | local bin = require "bin" 16 | local stdnse = require "stdnse" 17 | local string = require "string" 18 | local table = require "table" 19 | _ENV = stdnse.module("base32", stdnse.seeall) 20 | 21 | -- todo: make metatable/index --> '' for b32dctable 22 | 23 | 24 | local b32standard = { 25 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 26 | 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 27 | 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 28 | 'Y', 'Z', '2', '3', '4', '5', '6', '7', 29 | } 30 | 31 | local b32dcstandard = {} -- efficiency 32 | b32dcstandard['A'] = '00000' 33 | b32dcstandard['B'] = '00001' 34 | b32dcstandard['C'] = '00010' 35 | b32dcstandard['D'] = '00011' 36 | b32dcstandard['E'] = '00100' 37 | b32dcstandard['F'] = '00101' 38 | b32dcstandard['G'] = '00110' 39 | b32dcstandard['H'] = '00111' 40 | b32dcstandard['I'] = '01000' 41 | b32dcstandard['J'] = '01001' 42 | b32dcstandard['K'] = '01010' 43 | b32dcstandard['L'] = '01011' 44 | b32dcstandard['M'] = '01100' 45 | b32dcstandard['N'] = '01101' 46 | b32dcstandard['O'] = '01110' 47 | b32dcstandard['P'] = '01111' 48 | b32dcstandard['Q'] = '10000' 49 | b32dcstandard['R'] = '10001' 50 | b32dcstandard['S'] = '10010' 51 | b32dcstandard['T'] = '10011' 52 | b32dcstandard['U'] = '10100' 53 | b32dcstandard['V'] = '10101' 54 | b32dcstandard['W'] = '10110' 55 | b32dcstandard['X'] = '10111' 56 | b32dcstandard['Y'] = '11000' 57 | b32dcstandard['Z'] = '11001' 58 | b32dcstandard['2'] = '11010' 59 | b32dcstandard['3'] = '11011' 60 | b32dcstandard['4'] = '11100' 61 | b32dcstandard['5'] = '11101' 62 | b32dcstandard['6'] = '11110' 63 | b32dcstandard['7'] = '11111' 64 | 65 | local b32hexExtend = { 66 | '0', '1', '2', '3', '4', '5', '6', '7', 67 | '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 68 | 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 69 | 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 70 | } 71 | 72 | local b32dchexExtend = {} -- efficiency 73 | b32dchexExtend['0'] = '00000' 74 | b32dchexExtend['1'] = '00001' 75 | b32dchexExtend['2'] = '00010' 76 | b32dchexExtend['3'] = '00011' 77 | b32dchexExtend['4'] = '00100' 78 | b32dchexExtend['5'] = '00101' 79 | b32dchexExtend['6'] = '00110' 80 | b32dchexExtend['7'] = '00111' 81 | b32dchexExtend['8'] = '01000' 82 | b32dchexExtend['9'] = '01001' 83 | b32dchexExtend['A'] = '01010' 84 | b32dchexExtend['B'] = '01011' 85 | b32dchexExtend['C'] = '01100' 86 | b32dchexExtend['D'] = '01101' 87 | b32dchexExtend['E'] = '01110' 88 | b32dchexExtend['F'] = '01111' 89 | b32dchexExtend['G'] = '10000' 90 | b32dchexExtend['H'] = '10001' 91 | b32dchexExtend['I'] = '10010' 92 | b32dchexExtend['J'] = '10011' 93 | b32dchexExtend['K'] = '10100' 94 | b32dchexExtend['L'] = '10101' 95 | b32dchexExtend['M'] = '10110' 96 | b32dchexExtend['N'] = '10111' 97 | b32dchexExtend['O'] = '11000' 98 | b32dchexExtend['P'] = '11001' 99 | b32dchexExtend['Q'] = '11010' 100 | b32dchexExtend['R'] = '11011' 101 | b32dchexExtend['S'] = '11100' 102 | b32dchexExtend['T'] = '11101' 103 | b32dchexExtend['U'] = '11110' 104 | b32dchexExtend['V'] = '11111' 105 | 106 | local b32table = b32standard 107 | local b32dctable = b32dcstandard 108 | 109 | local append = table.insert 110 | local substr = string.sub 111 | local bpack = bin.pack 112 | local bunpack = bin.unpack 113 | local concat = table.concat 114 | 115 | --- 116 | -- Encode bits to a Base32-encoded character. 117 | -- @param bits String of five bits to be encoded. 118 | -- @return Encoded character. 119 | local function b32enc5bit(bits) 120 | local byte = tonumber(bits, 2) + 1 121 | return b32table[byte] 122 | end 123 | 124 | 125 | --- 126 | -- Decodes a Base32-encoded character into a string of binary digits. 127 | -- @param b32byte A single base32-encoded character. 128 | -- @return String of five decoded bits. 129 | local function b32dec5bit(b32byte) 130 | local bits = b32dctable[b32byte] 131 | if bits then return bits end 132 | return '' 133 | end 134 | 135 | 136 | --- 137 | -- Encodes a string to Base32. 138 | -- @param bdata Data to be encoded. 139 | -- @param hexExtend pass true to use the hex extended char set 140 | -- @return Base32-encoded string. 141 | function enc(bdata, hexExtend) 142 | local _, bitstring = bunpack(">B".. #bdata,bdata) 143 | local b32dataBuf = {} 144 | 145 | if hexExtend then 146 | b32table = b32hexExtend 147 | b32dctable = b32dchexExtend 148 | end 149 | 150 | while #bitstring > 4 do 151 | append(b32dataBuf,b32enc5bit(substr(bitstring,1,5))) 152 | bitstring = substr(bitstring,6) 153 | end 154 | if #bitstring == 1 then 155 | append(b32dataBuf, b32enc5bit(bitstring .. "0000")) 156 | append(b32dataBuf, '====') 157 | elseif #bitstring == 2 then 158 | append(b32dataBuf, b32enc5bit(bitstring .. "000") ) 159 | append(b32dataBuf, '=') 160 | elseif #bitstring == 3 then 161 | append(b32dataBuf, b32enc5bit(bitstring .. "00") ) 162 | append(b32dataBuf, "======") 163 | elseif #bitstring == 4 then 164 | append(b32dataBuf, b32enc5bit(bitstring .. "0") ) 165 | append(b32dataBuf, '===') 166 | end 167 | return concat(b32dataBuf) 168 | end 169 | 170 | 171 | --- 172 | -- Decodes Base32-encoded data. 173 | -- @param b32data Base32 encoded data. 174 | -- @param hexExtend pass true to use the hex extended char set 175 | -- @return Decoded data. 176 | function dec(b32data, hexExtend) 177 | local bdataBuf = {} 178 | local pos = 1 179 | local byte 180 | local nbyte = '' 181 | 182 | if hexExtend then 183 | b32table = b32hexExtend 184 | b32dctable = b32dchexExtend 185 | end 186 | 187 | for pos = 1, #b32data do -- while pos <= string.len(b32data) do 188 | byte = b32dec5bit(substr(b32data, pos, pos)) 189 | if not byte then return end 190 | nbyte = nbyte .. byte 191 | if #nbyte >= 8 then 192 | append(bdataBuf, bpack("B", substr(nbyte, 1, 8))) 193 | nbyte = substr(nbyte, 9) 194 | end 195 | -- pos = pos + 1 196 | end 197 | return concat(bdataBuf) 198 | end 199 | 200 | return _ENV; 201 | -------------------------------------------------------------------------------- /tests/nmap/base64.ok.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- Base64 encoding and decoding. Follows RFC 4648. 3 | -- 4 | -- @author Philip Pickering 5 | -- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html 6 | 7 | -- thanks to Patrick Donnelly for some optimizations 8 | 9 | local bin = require "bin" 10 | local stdnse = require "stdnse" 11 | local string = require "string" 12 | local table = require "table" 13 | _ENV = stdnse.module("base64", stdnse.seeall) 14 | 15 | -- todo: make metatable/index --> '' for b64dctable 16 | 17 | 18 | local b64table = { 19 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 20 | 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 21 | 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 22 | 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 23 | 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 24 | 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 25 | 'w', 'x', 'y', 'z', '0', '1', '2', '3', 26 | '4', '5', '6', '7', '8', '9', '+', '/' 27 | } 28 | 29 | local b64dctable = {} -- efficiency 30 | b64dctable['A'] = '000000' 31 | b64dctable['B'] = '000001' 32 | b64dctable['C'] = '000010' 33 | b64dctable['D'] = '000011' 34 | b64dctable['E'] = '000100' 35 | b64dctable['F'] = '000101' 36 | b64dctable['G'] = '000110' 37 | b64dctable['H'] = '000111' 38 | b64dctable['I'] = '001000' 39 | b64dctable['J'] = '001001' 40 | b64dctable['K'] = '001010' 41 | b64dctable['L'] = '001011' 42 | b64dctable['M'] = '001100' 43 | b64dctable['N'] = '001101' 44 | b64dctable['O'] = '001110' 45 | b64dctable['P'] = '001111' 46 | b64dctable['Q'] = '010000' 47 | b64dctable['R'] = '010001' 48 | b64dctable['S'] = '010010' 49 | b64dctable['T'] = '010011' 50 | b64dctable['U'] = '010100' 51 | b64dctable['V'] = '010101' 52 | b64dctable['W'] = '010110' 53 | b64dctable['X'] = '010111' 54 | b64dctable['Y'] = '011000' 55 | b64dctable['Z'] = '011001' 56 | b64dctable['a'] = '011010' 57 | b64dctable['b'] = '011011' 58 | b64dctable['c'] = '011100' 59 | b64dctable['d'] = '011101' 60 | b64dctable['e'] = '011110' 61 | b64dctable['f'] = '011111' 62 | b64dctable['g'] = '100000' 63 | b64dctable['h'] = '100001' 64 | b64dctable['i'] = '100010' 65 | b64dctable['j'] = '100011' 66 | b64dctable['k'] = '100100' 67 | b64dctable['l'] = '100101' 68 | b64dctable['m'] = '100110' 69 | b64dctable['n'] = '100111' 70 | b64dctable['o'] = '101000' 71 | b64dctable['p'] = '101001' 72 | b64dctable['q'] = '101010' 73 | b64dctable['r'] = '101011' 74 | b64dctable['s'] = '101100' 75 | b64dctable['t'] = '101101' 76 | b64dctable['u'] = '101110' 77 | b64dctable['v'] = '101111' 78 | b64dctable['w'] = '110000' 79 | b64dctable['x'] = '110001' 80 | b64dctable['y'] = '110010' 81 | b64dctable['z'] = '110011' 82 | b64dctable['0'] = '110100' 83 | b64dctable['1'] = '110101' 84 | b64dctable['2'] = '110110' 85 | b64dctable['3'] = '110111' 86 | b64dctable['4'] = '111000' 87 | b64dctable['5'] = '111001' 88 | b64dctable['6'] = '111010' 89 | b64dctable['7'] = '111011' 90 | b64dctable['8'] = '111100' 91 | b64dctable['9'] = '111101' 92 | b64dctable['+'] = '111110' 93 | b64dctable['/'] = '111111' 94 | 95 | 96 | local append = table.insert 97 | local substr = string.sub 98 | local bpack = bin.pack 99 | local bunpack = bin.unpack 100 | local concat = table.concat 101 | 102 | --- 103 | -- Encode six bits to a Base64-encoded character. 104 | -- @param bits String of six bits to be encoded. 105 | -- @return Encoded character. 106 | local function b64enc6bit(bits) 107 | -- local byte 108 | -- local _, byte = bunpack("C", bpack("B", "00" .. bits)) 109 | -- 110 | 111 | -- more efficient, does the same (nb: add one to byte moved up one line): 112 | local byte = tonumber(bits, 2) + 1 113 | return b64table[byte] 114 | end 115 | 116 | 117 | --- 118 | -- Decodes a Base64-encoded character into a string of binary digits. 119 | -- @param b64byte A single base64-encoded character. 120 | -- @return String of six decoded bits. 121 | local function b64dec6bit(b64byte) 122 | local bits = b64dctable[b64byte] 123 | if bits then return bits end 124 | return '' 125 | end 126 | 127 | 128 | --- 129 | -- Encodes a string to Base64. 130 | -- @param bdata Data to be encoded. 131 | -- @return Base64-encoded string. 132 | function enc(bdata) 133 | local pos = 1 134 | local byte 135 | local nbyte = '' 136 | -- local nbuffer = {} 137 | local b64dataBuf = {} 138 | while pos <= #bdata do 139 | pos, byte = bunpack("B1", bdata, pos) 140 | nbyte = nbyte .. byte 141 | append(b64dataBuf, b64enc6bit(substr(nbyte, 1, 6))) 142 | nbyte = substr(nbyte,7) 143 | if (#nbyte == 6) then 144 | append(b64dataBuf, b64enc6bit(nbyte)) 145 | nbyte = '' 146 | end 147 | end 148 | if #nbyte == 2 then 149 | append(b64dataBuf, b64enc6bit(nbyte .. "0000") ) 150 | append(b64dataBuf, "==") 151 | elseif #nbyte == 4 then 152 | append(b64dataBuf, b64enc6bit(nbyte .. "00")) 153 | append(b64dataBuf, '=') 154 | end 155 | return concat(b64dataBuf) 156 | end 157 | 158 | 159 | --- 160 | -- Decodes Base64-encoded data. 161 | -- @param b64data Base64 encoded data. 162 | -- @return Decoded data. 163 | function dec(b64data) 164 | local bdataBuf = {} 165 | local pos = 1 166 | local byte 167 | local nbyte = '' 168 | for pos = 1, #b64data do -- while pos <= #b64data do 169 | byte = b64dec6bit(substr(b64data, pos, pos)) 170 | if not byte then return end 171 | nbyte = nbyte .. byte 172 | if #nbyte >= 8 then 173 | append(bdataBuf, bpack("B", substr(nbyte, 1, 8))) 174 | nbyte = substr(nbyte, 9) 175 | end 176 | -- pos = pos + 1 177 | end 178 | return concat(bdataBuf) 179 | end 180 | 181 | 182 | return _ENV; 183 | -------------------------------------------------------------------------------- /tests/nmap/cassandra.ok.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- Library methods for handling Cassandra Thrift communication as client 3 | -- 4 | -- @author Vlatko Kosturjak 5 | -- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html 6 | -- 7 | -- Version 0.1 8 | -- 9 | 10 | local bin = require "bin" 11 | local nmap = require "nmap" 12 | local stdnse = require "stdnse" 13 | local string = require "string" 14 | _ENV = stdnse.module("cassandra", stdnse.seeall) 15 | 16 | --[[ 17 | 18 | Cassandra Thrift protocol implementation. 19 | 20 | For more information about Cassandra, see: 21 | 22 | http://cassandra.apache.org/ 23 | 24 | ]]-- 25 | 26 | -- Protocol magic strings 27 | CASSANDRAREQ = "\x80\x01\x00\x01" 28 | CASSANDRARESP = "\x80\x01\x00\x02" 29 | CASSLOGINMAGIC = "\x00\x00\x00\x01\x0c\x00\x01\x0d\x00\x01\x0b\x0b\x00\x00\x00\x02" 30 | LOGINSUCC = "\x00\x00\x00\x01\x00" 31 | LOGINFAIL = "\x00\x00\x00\x01\x0b" 32 | LOGINACC = "\x00\x00\x00\x01\x0c" 33 | 34 | --Returns string in cassandra format for login 35 | --@param username to put in format 36 | --@param password to put in format 37 | --@return str : string in cassandra format for login 38 | function loginstr (username, password) 39 | return bin.pack("A>aAaaaaA", 40 | CASSANDRAREQ, 41 | "login", 42 | CASSLOGINMAGIC, 43 | "username", 44 | username, 45 | "password", 46 | password, 47 | "\x00\x00" -- add two null on the end 48 | ) 49 | end 50 | 51 | --Invokes command over socket and returns the response 52 | --@param socket to connect to 53 | --@param command to invoke 54 | --@param cnt is protocol count 55 | --@return status : true if ok; false if bad 56 | --@return result : value if status ok, error msg if bad 57 | function cmdstr (command,cnt) 58 | return bin.pack("A>aIA", 59 | CASSANDRAREQ, 60 | command, 61 | cnt, 62 | "\x00" -- add null on the end 63 | ) 64 | end 65 | 66 | --Invokes command over socket and returns the response 67 | --@param socket to connect to 68 | --@param command to invoke 69 | --@param cnt is protocol count 70 | --@return status : true if ok; false if bad 71 | --@return result : value if status ok, error msg if bad 72 | function sendcmd (socket, command, cnt) 73 | local cmdstr = cmdstr (command,cnt) 74 | local response 75 | 76 | local status, err = socket:send(bin.pack(">I",string.len(cmdstr))) 77 | if ( not(status) ) then 78 | return false, "error sending packet length" 79 | end 80 | 81 | status, err = socket:send(cmdstr) 82 | if ( not(status) ) then 83 | return false, "error sending packet payload" 84 | end 85 | 86 | status, response = socket:receive_bytes(4) 87 | if ( not(status) ) then 88 | return false, "error receiving length" 89 | end 90 | local _,size = bin.unpack(">I",response,1) 91 | 92 | if (string.len(response) < size+4 ) then 93 | local resp2 94 | status, resp2 = socket:receive_bytes(size+4 - string.len(response)) 95 | if ( not(status) ) then 96 | return false, "error receiving payload" 97 | end 98 | response = response .. resp2 99 | end 100 | 101 | -- magic response starts at 5th byte for 4 bytes, 4 byte for length + length of string command 102 | if (string.sub(response,5,8+4+string.len(command)) ~= bin.pack("A>a", CASSANDRARESP, command)) then 103 | return false, "protocol response error" 104 | end 105 | 106 | return true, response 107 | end 108 | 109 | --Return Cluster Name 110 | --@param socket to connect to 111 | --@param cnt is protocol count 112 | --@return status : true if ok; false if bad 113 | --@return result : value if status ok, error msg if bad 114 | function describe_cluster_name (socket,cnt) 115 | local cname = "describe_cluster_name" 116 | local status,resp = sendcmd(socket,cname,cnt) 117 | 118 | if (not(status)) then 119 | stdnse.debug1("sendcmd"..resp) 120 | return false, "error in communication" 121 | end 122 | 123 | -- grab the size 124 | -- pktlen(4) + CASSANDRARESP(4) + lencmd(4) + lencmd(v) + params(7) + next byte position 125 | local position = 12+string.len(cname)+7+1 126 | local _,size = bin.unpack(">I",resp,position) 127 | 128 | -- read the string after the size 129 | local value = string.sub(resp,position+4,position+4+size-1) 130 | return true, value 131 | end 132 | 133 | --Return API version 134 | --@param socket to connect to 135 | --@param cnt is protocol count 136 | --@return status : true if ok; false if bad 137 | --@return result : value if status ok, error msg if bad 138 | function describe_version (socket,cnt) 139 | local cname = "describe_version" 140 | local status,resp = sendcmd(socket,cname,cnt) 141 | 142 | if (not(status)) then 143 | stdnse.debug1("sendcmd"..resp) 144 | return false, "error in communication" 145 | end 146 | 147 | -- grab the size 148 | -- pktlen(4) + CASSANDRARESP(4) + lencmd(4) + lencmd(v) + params(7) + next byte position 149 | local position = 12+string.len(cname)+7+1 150 | local _,size = bin.unpack(">I",resp,position) 151 | 152 | -- read the string after the size 153 | local value = string.sub(resp,position+4,position+4+size-1) 154 | return true, value 155 | end 156 | 157 | --Login to Cassandra 158 | --@param socket to connect to 159 | --@param username to connect to 160 | --@param password to connect to 161 | --@return status : true if ok; false if bad 162 | --@return result : table of status ok, error msg if bad 163 | --@return if status ok : remaining data read from socket but not used 164 | function login (socket,username,password) 165 | local loginstr = loginstr (username, password) 166 | local combo = username..":"..password 167 | 168 | local status, err = socket:send(bin.pack(">I",string.len(loginstr))) 169 | if ( not(status) ) then 170 | stdnse.debug3("cannot send len "..combo) 171 | return false, "Failed to connect to server" 172 | end 173 | 174 | status, err = socket:send(loginstr) 175 | if ( not(status) ) then 176 | stdnse.debug3("Sent packet for "..combo) 177 | return false, err 178 | end 179 | 180 | local response 181 | status, response = socket:receive_bytes(22) 182 | if ( not(status) ) then 183 | stdnse.debug3("Receive packet for "..combo) 184 | return false, err 185 | end 186 | local _, size = bin.unpack(">I", response, 1) 187 | 188 | local loginresp = string.sub(response,5,17) 189 | if (loginresp ~= bin.pack("A>a", CASSANDRARESP, "login")) then 190 | return false, "protocol error" 191 | end 192 | 193 | local magic = string.sub(response,18,22) 194 | stdnse.debug3("packet for "..combo) 195 | stdnse.debug3("packet hex: %s", stdnse.tohex(response) ) 196 | stdnse.debug3("size packet hex: %s", stdnse.tohex(size) ) 197 | stdnse.debug3("magic packet hex: %s", stdnse.tohex(magic) ) 198 | 199 | if (magic == LOGINSUCC) then 200 | return true 201 | else 202 | return false, "Login failed." 203 | end 204 | end 205 | 206 | return _ENV; 207 | -------------------------------------------------------------------------------- /tests/nmap/cvs.ok.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- A minimal CVS (Concurrent Versions System) pserver protocol implementation which currently only supports authentication. 3 | -- 4 | -- @author Patrik Karlsson 5 | -- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html 6 | -- 7 | 8 | -- Version 0.1 9 | -- Created 07/13/2011 - v0.1 - created by Patrik Karlsson 10 | 11 | 12 | local nmap = require "nmap" 13 | local stdnse = require "stdnse" 14 | local string = require "string" 15 | local table = require "table" 16 | _ENV = stdnse.module("cvs", stdnse.seeall) 17 | 18 | 19 | Helper = { 20 | 21 | new = function(self, host, port) 22 | local o = { host = host, port = port } 23 | setmetatable(o, self) 24 | self.__index = self 25 | return o 26 | end, 27 | 28 | connect = function(self) 29 | self.socket = nmap.new_socket() 30 | return self.socket:connect(self.host, self.port) 31 | end, 32 | 33 | login = function(self, repo, user, pass ) 34 | local auth_tab = {} 35 | assert(repo, "No repository was specified") 36 | assert(user, "No user was specified") 37 | assert(pass, "No pass was specified") 38 | 39 | -- Add a leading slash if it's missing 40 | if ( repo:sub(1,1) ~= "/" ) then repo = "/" .. repo end 41 | 42 | table.insert(auth_tab, "BEGIN AUTH REQUEST") 43 | table.insert(auth_tab, repo) 44 | table.insert(auth_tab, user) 45 | table.insert(auth_tab, Util.pwscramble(pass)) 46 | table.insert(auth_tab, "END AUTH REQUEST") 47 | 48 | local data = stdnse.strjoin("\n", auth_tab) .. "\n" 49 | local status = self.socket:send(data) 50 | if ( not(status) ) then return false, "Failed to send login request" end 51 | 52 | local status, response = self.socket:receive() 53 | if ( not(status) ) then return false, "Failed to read login response" end 54 | 55 | if ( response == "I LOVE YOU\n" ) then return true end 56 | return false, response 57 | end, 58 | 59 | close = function(self) 60 | return self.socket:close() 61 | end 62 | 63 | } 64 | 65 | Util = { 66 | 67 | --- Scrambles a password 68 | -- 69 | -- @param password string containing the password to scramble 70 | pwscramble = function(password) 71 | local shifts = { 72 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 73 | 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 74 | 114,120, 53, 79, 96,109, 72,108, 70, 64, 76, 67,116, 74, 68, 87, 75 | 111, 52, 75,119, 49, 34, 82, 81, 95, 65,112, 86,118,110,122,105, 76 | 41, 57, 83, 43, 46,102, 40, 89, 38,103, 45, 50, 42,123, 91, 35, 77 | 125, 55, 54, 66,124,126, 59, 47, 92, 71,115, 78, 88,107,106, 56, 78 | 36,121,117,104,101,100, 69, 73, 99, 63, 94, 93, 39, 37, 61, 48, 79 | 58,113, 32, 90, 44, 98, 60, 51, 33, 97, 62, 77, 84, 80, 85,223, 80 | 225,216,187,166,229,189,222,188,141,249,148,200,184,136,248,190, 81 | 199,170,181,204,138,232,218,183,255,234,220,247,213,203,226,193, 82 | 174,172,228,252,217,201,131,230,197,211,145,238,161,179,160,212, 83 | 207,221,254,173,202,146,224,151,140,196,205,130,135,133,143,246, 84 | 192,159,244,239,185,168,215,144,139,165,180,157,147,186,214,176, 85 | 227,231,219,169,175,156,206,198,129,164,150,210,154,177,134,127, 86 | 182,128,158,208,162,132,167,209,149,241,153,251,237,236,171,195, 87 | 243,233,253,240,194,250,191,155,142,137,245,235,163,242,178,152 }; 88 | 89 | return 'A' .. string.gsub(password, ".", 90 | function(c) return string.char(shifts[c:byte()+1]) end) 91 | end 92 | 93 | } 94 | 95 | return _ENV; 96 | -------------------------------------------------------------------------------- /tests/nmap/eap.ok.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- EAP (Extensible Authentication Protocol) library supporting a 3 | -- limited subset of features. 4 | -- 5 | -- The library was designed and tested against hostapd v0.6.10 6 | -- The EAP protocol names are the ones specified in: 7 | -- http://www.iana.org/assignments/eap-numbers/eap-numbers.xml 8 | -- 9 | -- Scripts can use the library to start an eap session and then to 10 | -- send identity and nak responses to identity and authentication 11 | -- requests made by AP authenticators to analyze their behaviour. 12 | -- 13 | -- The following sample code illustrates how to respond to an identity 14 | -- request: 15 | -- 16 | -- 17 | -- pcap:pcap_open(iface.device, 512, true, "ether proto 0x888e") 18 | -- ... 19 | -- local _, _, l2_data, l3_data, _ = pcap:pcap_receive() 20 | -- local packet = eap.parse(l2_data .. l3_data3) 21 | -- if packet then 22 | -- if packet.eap.type == eap.eap_t.IDENTITY and packet.eap.code == eap.code_t.REQUEST then 23 | -- eap.send_identity_response(iface, packet.eap.id, "anonymous") 24 | -- end 25 | -- end 26 | -- 27 | -- 28 | -- 29 | -- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html 30 | -- 31 | -- @author "Riccardo Cecolin " 32 | -- 33 | 34 | local bin = require "bin" 35 | local math = require "math" 36 | local nmap = require "nmap" 37 | local packet = require "packet" 38 | local stdnse = require "stdnse" 39 | _ENV = stdnse.module("eap", stdnse.seeall) 40 | 41 | -- Created 02/23/2012 - v0.1 42 | 43 | local ETHER_BROADCAST = "01:80:c2:00:00:03" 44 | local ETHER_TYPE_EAPOL_N = 0x888E 45 | local ETHER_TYPE_EAPOL = bin.pack(">S",ETHER_TYPE_EAPOL_N) 46 | local ETHER_HEADER_SIZE = 14 47 | local EAPOL_HEADER_SIZE = 4 48 | local EAP_HEADER_SIZE = 5 49 | 50 | eapol_t = { 51 | PACKET = 0, 52 | START = 1, 53 | LOGOFF = 2, 54 | KEY = 3, 55 | ASF = 4, 56 | } 57 | 58 | eapol_str = { 59 | [0] = "EAP Packet", 60 | [1] = "EAPOL Start", 61 | [2] = "EAPOL Logoff", 62 | [3] = "EAPOL Key", 63 | [4] = "EAPOL Encapsulated ASF Alert", 64 | } 65 | 66 | code_t = { 67 | REQUEST = 1, 68 | RESPONSE = 2, 69 | SUCCESS = 3, 70 | FAILURE = 4, 71 | INITIATE = 5, 72 | FINISH = 6, 73 | } 74 | 75 | code_str = { 76 | [1] = "Request", 77 | [2] = "Response", 78 | [3] = "Success", 79 | [4] = "Failure", 80 | [5] = "Initiate", 81 | [6] = "Finish", 82 | } 83 | 84 | eap_t = { 85 | IDENTITY = 1, 86 | NAK = 3, 87 | MD5 = 4, 88 | TLS = 13, 89 | TTLS = 21, 90 | PEAP = 25, 91 | MSCHAP = 29, 92 | } 93 | 94 | eap_str = { 95 | [0] = "Reserved", 96 | [1] = "Identity", 97 | [2] = "Notification", 98 | [3] = "Legacy Nak", 99 | [4] = "MD5-Challenge", 100 | [5] = "One-Time Password (OTP)", 101 | [6] = "Generic Token Card (GTC)", 102 | [7] = "Allocated", 103 | [8] = "Allocated", 104 | [9] = "RSA Public Key Authentication", 105 | [10] = "DSS Unilateral", 106 | [11] = "KEA", 107 | [12] = "KEA-VALIDATE", 108 | [13] = "EAP-TLS", 109 | [14] = "Defender Token (AXENT)", 110 | [15] = "RSA Security SecurID EAP", 111 | [16] = "Arcot Systems EAP", 112 | [17] = "EAP-Cisco Wireless", 113 | [18] = "GSM Subscriber Identity Modules (EAP-SIM)", 114 | [19] = "SRP-SHA1", 115 | [20] = "Unassigned", 116 | [21] = "EAP-TTLS", 117 | [22] = "Remote Access Service", 118 | [23] = "EAP-AKA Authentication", 119 | [24] = "EAP-3Com Wireless", 120 | [25] = "PEAP", 121 | [26] = "MS-EAP-Authentication", 122 | [27] = "Mutual Authentication w/Key Exchange (MAKE)", 123 | [28] = "CRYPTOCard", 124 | [29] = "EAP-MSCHAP-V2", 125 | [30] = "DynamID", 126 | [31] = "Rob EAP", 127 | [32] = "Protected One-Time Password", 128 | [33] = "MS-Authentication-TLV", 129 | [34] = "SentriNET", 130 | [35] = "EAP-Actiontec Wireless", 131 | [36] = "Cogent Systems Biometrics Authentication EAP", 132 | [37] = "AirFortress EAP", 133 | [38] = "EAP-HTTP Digest", 134 | [39] = "SecureSuite EAP", 135 | [40] = "DeviceConnect EAP", 136 | [41] = "EAP-SPEKE", 137 | [42] = "EAP-MOBAC", 138 | [43] = "EAP-FAST", 139 | [44] = "ZoneLabs EAP (ZLXEAP)", 140 | [45] = "EAP-Link", 141 | [46] = "EAP-PAX", 142 | [47] = "EAP-PSK", 143 | [48] = "EAP-SAKE", 144 | [49] = "EAP-IKEv2", 145 | [50] = "EAP-AKA'", 146 | [51] = "EAP-GPSK", 147 | [52] = "EAP-pwd", 148 | [53] = "EAP-EKE Version 1", 149 | -- 54-253 Unassigned 150 | [254] = "Reserved for the Expanded Type", 151 | [255] = "Experimental", 152 | } 153 | 154 | local make_eapol = function (arg) 155 | if not arg.type then arg.type = eapol_t.PACKET end 156 | if not arg.version then arg.version = 1 end 157 | if not arg.payload then arg.payload = "" end 158 | if not arg.src then return nil end 159 | 160 | local p = packet.Frame:new() 161 | p.mac_src = arg.src 162 | p.mac_dst = packet.mactobin(ETHER_BROADCAST) 163 | p.ether_type = ETHER_TYPE_EAPOL 164 | 165 | local bin_payload = bin.pack(">A",arg.payload) 166 | p.buf = bin.pack("C",arg.version) .. bin.pack("C",arg.type) .. bin.pack(">S",bin_payload:len()).. bin_payload 167 | p:build_ether_frame() 168 | return p.frame_buf 169 | end 170 | 171 | local make_eap = function (arg) 172 | 173 | if not arg.code then arg.code = code_t.REQUEST end 174 | if not arg.id then arg.id = math.random(0,255) end 175 | if not arg.type then arg.type = eap_t.IDENTITY end 176 | if not arg.payload then arg.payload = "" end 177 | if not arg.header then return nil end 178 | 179 | local bin_payload = bin.pack(">A",arg.payload) 180 | arg.header.payload = bin.pack("C",arg.code) .. bin.pack("C",arg.id) .. bin.pack(">S",bin_payload:len() + EAP_HEADER_SIZE).. bin.pack("C",arg.type) .. bin_payload 181 | 182 | local v = make_eapol(arg.header) 183 | stdnse.debug2("make eapol %s", arg.header.src) 184 | 185 | return v 186 | end 187 | 188 | parse = function (packet) 189 | local tb = {} 190 | local _ 191 | 192 | stdnse.debug2("packet size: 0x%x", #packet ) 193 | 194 | -- parsing ethernet header 195 | _, tb.mac_src, tb.mac_dst, tb.ether_type = bin.unpack(">A6A6S", packet) 196 | _, tb.mac_src_str, tb.mac_dst_str = bin.unpack(">H6H6", packet) 197 | 198 | -- parsing eapol header 199 | _, tb.version, tb.type, tb.length = bin.unpack(">CCS", packet, ETHER_HEADER_SIZE + 1) 200 | 201 | stdnse.debug1("mac_src: %s, mac_dest: %s, ether_type: 0x%X", 202 | tb.mac_src_str, tb.mac_dst_str, tb.ether_type) 203 | 204 | if tb.ether_type ~= ETHER_TYPE_EAPOL_N then return nil, "not an eapol packet" end 205 | 206 | stdnse.debug2("version: %X, type: %s, length: 0x%X", 207 | tb.version, eapol_str[tb.type] or "unknown", 208 | tb.length) 209 | 210 | tb.eap = {} 211 | 212 | if tb.length > 0 then 213 | -- parsing body 214 | 215 | _, tb.eap.code, tb.eap.id, tb.eap.length, tb.eap.type = bin.unpack(">CCSC", packet, 216 | ETHER_HEADER_SIZE + EAPOL_HEADER_SIZE + 1) 217 | stdnse.debug2("code: %s, id: 0x%X, length: 0x%X, type: %s", 218 | code_str[tb.eap.code] or "unknown", 219 | tb.eap.id, tb.eap.length, eap_str[tb.eap.type] or "unknown" ) 220 | if tb.length ~= tb.eap.length then 221 | stdnse.debug1("WARNING length mismatch: 0x%X and 0x%X", tb.length, tb.eap.length ) 222 | end 223 | end 224 | 225 | tb.eap.body = {} 226 | 227 | -- parsing payload 228 | if tb.length > 5 and tb.eap.type == eap_t.IDENTITY then 229 | _, tb.eap.body.identity = bin.unpack("z", packet, 230 | ETHER_HEADER_SIZE + EAPOL_HEADER_SIZE + EAP_HEADER_SIZE + 1) 231 | stdnse.debug1("identity: %s", tb.eap.body.identity ) 232 | end 233 | 234 | if tb.length > 5 and tb.eap.type == eap_t.MD5 then 235 | _, tb.eap.body.challenge = bin.unpack("p", packet, ETHER_HEADER_SIZE + EAPOL_HEADER_SIZE + EAP_HEADER_SIZE + 1) 236 | end 237 | 238 | return tb 239 | end 240 | 241 | send_identity_response = function (iface, id, identity) 242 | 243 | if not iface then 244 | stdnse.debug1("no interface given") 245 | return 246 | end 247 | 248 | local dnet = nmap.new_dnet() 249 | local tb = {src = iface.mac, type = eapol_t.PACKET} 250 | local response = make_eap{header = tb, code = code_t.RESPONSE, type = eap_t.IDENTITY, id = id, payload = identity} 251 | 252 | dnet:ethernet_open(iface.device) 253 | dnet:ethernet_send(response) 254 | dnet:ethernet_close() 255 | end 256 | 257 | send_nak_response = function (iface, id, auth) 258 | 259 | if not iface then 260 | stdnse.debug1("no interface given") 261 | return 262 | end 263 | 264 | local dnet = nmap.new_dnet() 265 | local tb = {src = iface.mac, type = eapol_t.PACKET} 266 | local response = make_eap{header = tb, code = code_t.RESPONSE, type = eap_t.NAK, id = id, payload = bin.pack("C",auth)} 267 | 268 | dnet:ethernet_open(iface.device) 269 | dnet:ethernet_send(response) 270 | dnet:ethernet_close() 271 | end 272 | 273 | 274 | send_start = function (iface) 275 | 276 | if not iface then 277 | stdnse.debug1("no interface given") 278 | return 279 | end 280 | 281 | local dnet = nmap.new_dnet() 282 | local start = make_eapol{type = eapol_t.START, src = iface.mac} 283 | 284 | dnet:ethernet_open(iface.device) 285 | dnet:ethernet_send(start) 286 | dnet:ethernet_close() 287 | 288 | end 289 | 290 | return _ENV; 291 | -------------------------------------------------------------------------------- /tests/nmap/formulas.ok.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- Formula functions for various calculations. 3 | -- 4 | -- The library lets scripts to use common mathematical functions to compute percentages, 5 | -- averages, entropy, randomness and other calculations. Scripts that generate statistics 6 | -- and metrics can also make use of this library. 7 | -- 8 | -- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html 9 | --- 10 | 11 | local bin = require "bin" 12 | local math = require "math" 13 | local stdnse = require "stdnse" 14 | local string = require "string" 15 | local table = require "table" 16 | 17 | _ENV = stdnse.module("formulas", stdnse.seeall) 18 | 19 | --- Calculate the entropy of a password. 20 | -- 21 | -- A random password's information entropy, H, is given by the formula: H = L * 22 | -- (logN) / (log2), where N is the number of possible symbols and L is the 23 | -- number of symbols in the password. Based on 24 | -- https://en.wikipedia.org/wiki/Password_strength 25 | -- @param value The password to check 26 | -- @return The entropy in bits 27 | calcPwdEntropy = function(value) 28 | 29 | local total, hasdigit, haslower, hasupper, hasspaces = 0, 0, 0, 0, false 30 | 31 | if string.find(value, "%d") then 32 | hasdigit = 1 33 | end 34 | if string.find(value, "%l") then 35 | haslower = 1 36 | end 37 | if string.find(value, "%u") then 38 | hasupper = 1 39 | end 40 | if string.find(value, ' ') then 41 | hasspaces = true 42 | end 43 | 44 | -- The values 10, 26, 26 have been taken from Wikipedia's entropy table. 45 | local total = hasdigit * 10 + hasupper * 26 + haslower * 26 46 | local entropy = math.floor(math.log(total) * #value / math.log(2)) 47 | 48 | return entropy 49 | end 50 | 51 | -- A chi-square test for the null hypothesis that the members of data are drawn 52 | -- from a uniform distribution over num_cats categories. 53 | local function chi2(data, num_cats) 54 | local bins = {} 55 | local x2, delta, expected 56 | 57 | for _, x in ipairs(data) do 58 | bins[x] = bins[x] or 0 59 | bins[x] = bins[x] + 1 60 | end 61 | 62 | expected = #data / num_cats 63 | x2 = 0.0 64 | for _, n in pairs(bins) do 65 | delta = n - expected 66 | x2 = x2 + delta * delta 67 | end 68 | x2 = x2 / expected 69 | 70 | return x2 71 | end 72 | 73 | -- Split a string into a sequence of bit strings of the given length. 74 | -- splitbits("abc", 5) --> {"01100", "00101", "10001", "00110"} 75 | -- Any short final group is omitted. 76 | local function splitbits(s, n) 77 | local seq 78 | 79 | local _, bits = bin.unpack("B" .. #s, s) 80 | seq = {} 81 | for i = 1, #bits - n, n do 82 | seq[#seq + 1] = bits:sub(i, i + n - 1) 83 | end 84 | 85 | return seq 86 | end 87 | 88 | -- chi-square cdf table at 0.95 confidence for different degrees of freedom. 89 | -- >>> import scipy.stats, scipy.optimize 90 | -- >>> scipy.optimize.newton(lambda x: scipy.stats.chi2(dof).cdf(x) - 0.95, dof) 91 | local CHI2_CDF = { 92 | [3] = 7.8147279032511738, 93 | [15] = 24.99579013972863, 94 | [255] = 293.2478350807001, 95 | } 96 | 97 | --- Checks whether a sample looks random 98 | -- 99 | -- Because our sample is so small (only 16 bytes), do a chi-square 100 | -- goodness of fit test across groups of 2, 4, and 8 bits. If using only 101 | -- 8 bits, for example, any sample whose bytes are all different would 102 | -- pass the test. Using 2 bits will tend to catch things like pure 103 | -- ASCII, where one out of every four samples never has its high bit 104 | -- set. 105 | -- @param data The data to check 106 | -- @return True if the data appears to be random, false otherwise 107 | function looksRandom(data) 108 | local x2 109 | 110 | 111 | x2 = chi2(splitbits(data, 2), 4) 112 | if x2 > CHI2_CDF[3] then 113 | return false 114 | end 115 | 116 | x2 = chi2(splitbits(data, 4), 16) 117 | if x2 > CHI2_CDF[15] then 118 | return false 119 | end 120 | 121 | x2 = chi2({string.byte(data, 1, -1)}, 256) 122 | if x2 > CHI2_CDF[255] then 123 | return false 124 | end 125 | 126 | return true 127 | end 128 | 129 | return _ENV 130 | -------------------------------------------------------------------------------- /tests/nmap/ftp.ok.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- FTP functions. 3 | -- 4 | -- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html 5 | 6 | local comm = require "comm" 7 | local stdnse = require "stdnse" 8 | local string = require "string" 9 | _ENV = stdnse.module("ftp", stdnse.seeall) 10 | 11 | local ERROR_MESSAGES = { 12 | ["EOF"] = "connection closed", 13 | ["TIMEOUT"] = "connection timeout", 14 | ["ERROR"] = "failed to receive data" 15 | } 16 | 17 | --- Connects to the FTP server based on the provided options. 18 | -- 19 | -- @param host The host table 20 | -- @param port The port table 21 | -- @param opts The connection option table, possible options: 22 | -- timeout: generic timeout value 23 | -- recv_before: receive data before returning 24 | -- @return socket The socket descriptor, or nil on errors 25 | -- @return response The response received on success and when 26 | -- the recv_before is set, or the error message on failures. 27 | connect = function(host, port, opts) 28 | local socket, _, _, ret = comm.tryssl(host, port, '', opts) 29 | if not socket then 30 | return socket, (ERROR_MESSAGES[ret] or 'unspecified error') 31 | end 32 | return socket, ret 33 | end 34 | 35 | --- 36 | -- Read an FTP reply and return the numeric code and the message. See RFC 959, 37 | -- section 4.2. 38 | -- @param buffer should have been created with 39 | -- stdnse.make_buffer(socket, "\r?\n"). 40 | -- @return numeric code or nil. 41 | -- @return text reply or error message. 42 | function read_reply(buffer) 43 | local readline 44 | local line, err 45 | local code, message 46 | local _, p, tmp 47 | 48 | line, err = buffer() 49 | if not line then 50 | return line, err 51 | end 52 | 53 | -- Single-line response? 54 | code, message = string.match(line, "^(%d%d%d) (.*)$") 55 | if code then 56 | return tonumber(code), message 57 | end 58 | 59 | -- Multi-line response? 60 | _, p, code, message = string.find(line, "^(%d%d%d)%-(.*)$") 61 | if p then 62 | while true do 63 | line, err = buffer() 64 | if not line then 65 | return line, err 66 | end 67 | tmp = string.match(line, "^%d%d%d (.*)$") 68 | if tmp then 69 | message = message .. "\n" .. tmp 70 | break 71 | end 72 | message = message .. "\n" .. line 73 | end 74 | 75 | return tonumber(code), message 76 | end 77 | 78 | return nil, string.format("Unparseable response: %q", line) 79 | end 80 | 81 | return _ENV; 82 | -------------------------------------------------------------------------------- /tests/nmap/gps.ok.lua: -------------------------------------------------------------------------------- 1 | local bit = require "bit" 2 | local os = require "os" 3 | local stdnse = require "stdnse" 4 | local string = require "string" 5 | _ENV = stdnse.module("gps", stdnse.seeall) 6 | 7 | --- 8 | -- A smallish gps parsing module. 9 | -- Currently does GPRMC NMEA decoding 10 | -- 11 | -- @author "Patrik Karlsson " 12 | -- 13 | -- 14 | 15 | NMEA = { 16 | 17 | -- Parser for the RMC sentence 18 | RMC = { 19 | 20 | parse = function(str) 21 | 22 | local time, status, latitude, ns_indicator, longitude, 23 | ew_indicator, speed, course, date, variation, 24 | ew_variation, checksum = str:match("^%$GPRMC,([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^%*]*)(.*)$") 25 | 26 | if ( not(latitude) or not(longitude) ) then 27 | return 28 | end 29 | 30 | local deg, min = latitude:match("^(..)(.*)$") 31 | if ( not(deg) or not(min) ) then 32 | return 33 | end 34 | latitude = tonumber(deg) + (tonumber(min)/60) 35 | 36 | deg, min = longitude:match("^(..)(.*)$") 37 | if ( not(deg) or not(min) ) then 38 | return 39 | end 40 | longitude = tonumber(deg) + (tonumber(min)/60) 41 | if ( ew_indicator == 'W' ) then 42 | longitude = -longitude 43 | end 44 | 45 | if ( ns_indicator == 'S' ) then 46 | latitude = -latitude 47 | end 48 | 49 | return { time = time, status = status, latitude = latitude, 50 | longitude = longitude, speed = speed, course = course, 51 | date = date, variation = variation, 52 | ew_variation = ew_variation } 53 | end, 54 | 55 | }, 56 | 57 | -- Calculates an verifies the message checksum 58 | -- 59 | -- @param str containing the GPS sentence 60 | -- @return status true on success, false if the checksum does not match 61 | -- @return err string if status is false 62 | checksum = function(str) 63 | local val = 0 64 | for c in str:sub(2,-4):gmatch(".") do 65 | val = bit.bxor(val, string.byte(c)) 66 | end 67 | 68 | if ( str:sub(-2):upper() ~= stdnse.tohex(string.char(val)):upper() ) then 69 | return false, ("Failed to verify checksum (got: %s; expected: %s)"):format(stdnse.tohex(string.char(val)), str:sub(-2)) 70 | end 71 | return true 72 | end, 73 | 74 | -- Parses a GPS sentence using the appropriate parser 75 | -- 76 | -- @param str containing the GPS sentence 77 | -- @return entry table containing the parsed response or 78 | -- err string if status is false 79 | -- @return status true on success, false on failure 80 | parse = function(str) 81 | 82 | local status, err = NMEA.checksum(str) 83 | if ( not(status) ) then 84 | return false, err 85 | end 86 | 87 | local prefix = str:match("^%$GP([^,]*)") 88 | if ( not(prefix) ) then 89 | return false, "Not a NMEA sentence" 90 | end 91 | 92 | if ( NMEA[prefix] and NMEA[prefix].parse ) then 93 | local e = NMEA[prefix].parse(str) 94 | if (not(e)) then 95 | return false, ("Failed to parse entry: %s"):format(str) 96 | end 97 | return true, e 98 | else 99 | local err = ("No parser for prefix: %s"):format(prefix) 100 | stdnse.debug2("%s", err) 101 | return false, err 102 | end 103 | 104 | end 105 | 106 | } 107 | 108 | Util = { 109 | 110 | convertTime = function(date, time) 111 | local d = {} 112 | d.hour, d.min, d.sec = time:match("(..)(..)(..)") 113 | d.day, d.month, d.year = date:match("(..)(..)(..)") 114 | d.year = d.year + 2000 115 | return os.time(d) 116 | end 117 | } 118 | 119 | return _ENV; 120 | -------------------------------------------------------------------------------- /tests/nmap/listop.ok.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- Functional-style list operations. 3 | -- 4 | -- People used to programming in functional languages, such as Lisp 5 | -- or Haskell, appreciate their handling of lists very much. The 6 | -- listop module tries to bring much of the functionality from 7 | -- functional languages to Lua using Lua's central data structure, the table, as 8 | -- a base for its list operations. Highlights include a map 9 | -- function applying a given function to each element of a list. 10 | -- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html 11 | 12 | local stdnse = require "stdnse" 13 | local table = require "table" 14 | _ENV = stdnse.module("listop", stdnse.seeall) 15 | 16 | --[[ 17 | -- 18 | Functional programming style 'list' operations 19 | 20 | bool is_empty(list) 21 | bool is_list(value) 22 | 23 | value apply(function, list) 24 | list map(function, list) 25 | list filter(function, list) 26 | list flatten(list) 27 | list append(list1, list2) 28 | list cons(value1, value2) 29 | list reverse(list) 30 | 31 | value car(list) 32 | value ncar(list, x) 33 | list cdr(list) 34 | list ncdr(list, x) 35 | 36 | where 'list' is an indexed table 37 | where 'value' is an lua datatype 38 | --]] 39 | 40 | --- Returns true if the given list is empty. 41 | -- @param l A list. 42 | -- @return True or false. 43 | function is_empty(l) 44 | return #l == 0 and true or false; 45 | end 46 | 47 | --- Returns true if the given value is a list (or rather a table). 48 | -- @param l Any value. 49 | -- @return True or false. 50 | function is_list(l) 51 | return type(l) == 'table' and true or false; 52 | end 53 | 54 | --- Calls f for each element in the list. The returned list 55 | --contains the results of each function call. 56 | -- @usage 57 | -- listop.map(tostring,{1,2,true}) --> {"1","2","true"} 58 | -- @param f The function to call. 59 | -- @param l A list. 60 | -- @return List of function results. 61 | function map(f, l) 62 | local results = {} 63 | for _, v in ipairs(l) do 64 | results[#results+1] = f(v); 65 | end 66 | return results; 67 | end 68 | 69 | --- Calls the function with all the elements in the list as the parameters. 70 | -- @usage 71 | -- listop.apply(math.max,{1,5,6,7,50000}) --> 50000 72 | -- @param f The function to call. 73 | -- @param l A list. 74 | -- @return Results from f. 75 | function apply(f, l) 76 | return f(table.unpack(l)) 77 | end 78 | 79 | --- Returns a list containing only those elements for which a predicate 80 | -- function returns true. 81 | -- 82 | -- The predicate has to be a function taking one argument and returning 83 | -- a Boolean. If it returns true, the argument is appended to the return value 84 | -- of filter. 85 | -- @usage 86 | -- listop.filter(isnumber,{1,2,3,"foo",4,"bar"}) --> {1,2,3,4} 87 | -- @param f The function. 88 | -- @param l The list. 89 | -- @return Filtered list. 90 | function filter(f, l) 91 | local results = {} 92 | for i, v in ipairs(l) do 93 | if(f(v)) then 94 | results[#results+1] = v; 95 | end 96 | end 97 | return results 98 | end 99 | 100 | --- Fetch the first element of a list. 101 | -- @param l The list. 102 | -- @return The first element. 103 | function car(l) 104 | return l[1] 105 | end 106 | 107 | --- Fetch all elements following the first in a new list. 108 | -- @param l The list. 109 | -- @return Elements after the first. 110 | function cdr(l) 111 | return {table.unpack(l, 2)} 112 | end 113 | 114 | --- Fetch element at index x from l. 115 | -- @param l The list. 116 | -- @param x Element index. 117 | -- @return Element at index x or at index 1 if 118 | -- x is not given. 119 | function ncar(l, x) 120 | return l[x or 1]; 121 | end 122 | 123 | --- Fetch all elements following the element at index x. 124 | -- @param l The list. 125 | -- @param x Element index. 126 | -- @return Elements after index x or after index 1 if 127 | -- x is not given. 128 | function ncdr(l, x) 129 | return {table.unpack(l, x or 2)}; 130 | end 131 | 132 | --- Prepend a value or list to another value or list. 133 | -- @param v1 value or list. 134 | -- @param v2 value or list. 135 | -- @return New list. 136 | function cons(v1, v2) 137 | return{ is_list(v1) and {table.unpack(v1)} or v1, is_list(v2) and {table.unpack(v2)} or v2} 138 | end 139 | 140 | --- Concatenate two lists and return the result. 141 | -- @param l1 List. 142 | -- @param l2 List. 143 | -- @return List. 144 | function append(l1, l2) 145 | local results = {table.unpack(l1)} 146 | 147 | for _, v in ipairs(l2) do 148 | results[#results+1] = v; 149 | end 150 | return results 151 | end 152 | 153 | --- Return a list in reverse order. 154 | -- @param l List. 155 | -- @return Reversed list. 156 | function reverse(l) 157 | local results = {} 158 | for i=#l, 1, -1 do 159 | results[#results+1] = l[i]; 160 | end 161 | return results 162 | end 163 | 164 | --- Return a flattened version of a list. The flattened list contains 165 | -- only non-list values. 166 | -- @usage 167 | -- listop.flatten({1,2,3,"foo",{4,5,{"bar"}}}) --> {1,2,3,"foo",4,5,"bar"} 168 | -- @param l The list to flatten. 169 | -- @return Flattened list. 170 | function flatten(l) 171 | local function flat(r, t) 172 | for i, v in ipairs(t) do 173 | if(type(v) == 'table') then 174 | flat(r, v) 175 | else 176 | table.insert(r, v) 177 | end 178 | end 179 | return r 180 | end 181 | return flat({}, l) 182 | end 183 | 184 | return _ENV; 185 | -------------------------------------------------------------------------------- /tests/nmap/lpeg-utility.ok.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- Utility functions for LPeg. 3 | -- 4 | -- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html 5 | -- @class module 6 | -- @name lpeg-utility 7 | 8 | local assert = assert 9 | 10 | local lpeg = require "lpeg" 11 | local stdnse = require "stdnse" 12 | local pairs = pairs 13 | local string = require "string" 14 | local tonumber = tonumber 15 | 16 | _ENV = {} 17 | 18 | --- 19 | -- Returns a pattern which matches the literal string caselessly. 20 | -- 21 | -- @param literal A literal string to match case-insensitively. 22 | -- @return An LPeg pattern. 23 | function caseless (literal) 24 | local caseless = lpeg.Cf((lpeg.P(1) / function (a) return lpeg.S(a:lower()..a:upper()) end)^1, function (a, b) return a * b end) 25 | return assert(caseless:match(literal)) 26 | end 27 | 28 | --- 29 | -- Returns a pattern which matches the input pattern anywhere on a subject string. 30 | -- 31 | -- @param patt Input pattern. 32 | -- @return An LPeg pattern. 33 | function anywhere (patt) 34 | return lpeg.P { 35 | patt + 1 * lpeg.V(1) 36 | } 37 | end 38 | 39 | --- 40 | -- Adds the current locale from lpeg.locale() to the grammar and returns the final pattern. 41 | -- 42 | -- @param grammar Input grammar. 43 | -- @return An LPeg pattern. 44 | function localize (grammar) 45 | return lpeg.P(lpeg.locale(grammar)) 46 | end 47 | 48 | --- 49 | -- Splits the input string on the input separator. 50 | -- 51 | -- @param str Input string to split. 52 | -- @param sep Input string/pattern to separate on. 53 | -- @return All splits. 54 | function split (str, sep) 55 | return lpeg.P { 56 | lpeg.V "elem" * (lpeg.V "sep" * lpeg.V "elem")^0, 57 | elem = lpeg.C((1 - lpeg.V "sep")^0), 58 | sep = sep, 59 | } :match(str) 60 | end 61 | 62 | --- 63 | -- Returns a pattern which only matches at a word boundary (beginning). 64 | -- 65 | -- Essentially the same as '\b' in a PCRE pattern. 66 | -- 67 | -- @param patt A pattern. 68 | -- @return A new LPeg pattern. 69 | function atwordboundary (patt) 70 | return _ENV.localize { 71 | patt + lpeg.V "alpha"^0 * (1 - lpeg.V "alpha")^1 * lpeg.V(1) 72 | } 73 | end 74 | 75 | --- 76 | -- Returns a pattern which captures the contents of a quoted string. 77 | -- 78 | -- This can handle embedded escaped quotes, and captures the unescaped string. 79 | -- 80 | -- @param quot The quote character to use. Default: '"' 81 | -- @param esc The escape character to use. Cannot be the same as quot. Default: "\" 82 | function escaped_quote (quot, esc) 83 | quot = quot or '"' 84 | esc = esc or '\\' 85 | return lpeg.P { 86 | lpeg.Cs(lpeg.V "quot" * lpeg.Cs((lpeg.V "simple_char" + lpeg.V "noesc" + lpeg.V "unesc")^0) * lpeg.V "quot"), 87 | quot = lpeg.P(quot)/"", 88 | esc = lpeg.P(esc), 89 | simple_char = (lpeg.P(1) - (lpeg.V "quot" + lpeg.V "esc")), 90 | unesc = (lpeg.V "esc" * lpeg.C( lpeg.V "esc" + lpeg.P(quot) ))/"%1", 91 | noesc = lpeg.V "esc" * lpeg.V "simple_char" 92 | } 93 | end 94 | 95 | --- 96 | -- Adds hooks to a grammar to print debugging information 97 | -- 98 | -- Debugging LPeg grammars can be difficult. Calling this function on your 99 | -- grammmar will cause it to print ENTER and LEAVE statements for each rule, as 100 | -- well as position and subject after each successful rule match. 101 | -- 102 | -- For convenience, the modified grammar is returned; a copy is not made 103 | -- though, and the original grammar is modified as well. 104 | -- 105 | -- @param grammar The LPeg grammar to modify 106 | -- @param printer A printf-style formatting printer function to use. 107 | -- Default: stdnse.debug1 108 | -- @return The modified grammar. 109 | function debug (grammar, printer) 110 | printer = printer or stdnse.debug1 111 | -- Original code credit: http://lua-users.org/lists/lua-l/2009-10/msg00774.html 112 | for k, p in pairs(grammar) do 113 | local enter = lpeg.Cmt(lpeg.P(true), function(s, p, ...) 114 | printer("ENTER %s", k) return p end) 115 | local leave = lpeg.Cmt(lpeg.P(true), function(s, p, ...) 116 | printer("LEAVE %s", k) return p end) * (lpeg.P("k") - lpeg.P "k"); 117 | grammar[k] = lpeg.Cmt(enter * p + leave, function(s, p, ...) 118 | printer("---%s---", k) printer("pos: %d, [%s]", p, s:sub(1, p-1)) return p end) 119 | end 120 | return grammar 121 | end 122 | 123 | do 124 | -- Cache the returned pattern 125 | local getquote = escaped_quote() 126 | 127 | -- Substitution pattern to unescape a string 128 | local unescape = lpeg.P { 129 | -- Substitute captures 130 | lpeg.Cs((lpeg.V "simple_char" + lpeg.V "unesc")^0), 131 | -- Escape char is '\' 132 | esc = lpeg.P "\\", 133 | -- Simple char is anything but escape char 134 | simple_char = lpeg.P(1) - lpeg.V "esc", 135 | -- If we hit an escape, process specials or hex code, otherwise remove the escape 136 | unesc = (lpeg.V "esc" * lpeg.Cs( lpeg.V "specials" + lpeg.V "code" + lpeg.P(1) ))/"%1", 137 | -- single-char escapes. These are the only ones service_scan uses 138 | specials = lpeg.S "trn0" / {t="\t", r="\r", n="\n", ["0"]="\0"}, 139 | -- hex escape: convert to char 140 | code = (lpeg.P "x" * lpeg.C(lpeg.S "0123456789abcdefABCDEF"^-2))/function(c) 141 | return string.char(tonumber(c,16)) end, 142 | } 143 | 144 | --- Turn the service fingerprint reply to a probe into a binary blob 145 | function get_response (fp, probe) 146 | fp = string.gsub(fp, "\nSF:", "") 147 | local i, e = string.find(fp, string.format("%s,%%x+,", probe)) 148 | if i == nil then return nil end 149 | return unescape:match(getquote:match(fp, e+1)) 150 | end 151 | end 152 | 153 | return _ENV 154 | -------------------------------------------------------------------------------- /tests/nmap/match.ok.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- Buffered network I/O helper functions. 3 | -- 4 | -- The functions in this module can be used for delimiting data received by the 5 | -- nmap.receive_buf function in the Network I/O API (which see). 6 | -- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html 7 | 8 | local stdnse = require "stdnse" 9 | _ENV = stdnse.module("match", stdnse.seeall) 10 | 11 | --various functions for use with NSE's nsock:receive_buf - function 12 | 13 | -- e.g. 14 | -- sock:receive_buf(numbytes(80), true) - is the buffered version of 15 | -- sock:receive_bytes(80) - i.e. it 16 | -- returns exactly 80 bytes and no more 17 | 18 | --- Return a function that allows delimiting at a certain number of bytes. 19 | -- 20 | -- This function can be used to get a buffered version of 21 | -- sock:receive_bytes(n) in case a script requires more than one 22 | -- fixed-size chunk, as the unbuffered version may return more bytes than 23 | -- requested and thus would require you to do the parsing on your own. 24 | -- 25 | -- The keeppattern parameter to receive_buf should be set to 26 | -- true, otherwise the string returned will be 1 less than 27 | -- num 28 | -- @param num Number of bytes. 29 | -- @usage sock:receive_buf(match.numbytes(80), true) 30 | -- @see nmap.receive_buf 31 | numbytes = function(num) 32 | local n = num 33 | return function(buf) 34 | if(#buf >=n) then 35 | return n, n 36 | end 37 | return nil 38 | end 39 | end 40 | 41 | 42 | return _ENV; 43 | -------------------------------------------------------------------------------- /tests/nmap/mobileme.ok.lua: -------------------------------------------------------------------------------- 1 | local http = require "http" 2 | local json = require "json" 3 | local stdnse = require "stdnse" 4 | local table = require "table" 5 | _ENV = stdnse.module("mobileme", stdnse.seeall) 6 | 7 | --- 8 | -- A MobileMe web service client that allows discovering Apple devices 9 | -- using the "find my iPhone" functionality. 10 | -- 11 | -- @author "Patrik Karlsson " 12 | -- 13 | 14 | MobileMe = { 15 | 16 | -- headers used in all requests 17 | headers = { 18 | ["Content-Type"] = "application/json; charset=utf-8", 19 | ["X-Apple-Find-Api-Ver"] = "2.0", 20 | ["X-Apple-Authscheme"] = "UserIdGuest", 21 | ["X-Apple-Realm-Support"] = "1.0", 22 | ["User-Agent"] = "Find iPhone/1.3 MeKit (iPad: iPhone OS/4.2.1)", 23 | ["X-Client-Name"] = "iPad", 24 | ["X-Client-UUID"] = "0cf3dc501ff812adb0b202baed4f37274b210853", 25 | ["Accept-Language"] = "en-us", 26 | ["Connection"] = "keep-alive" 27 | }, 28 | 29 | -- Creates a MobileMe instance 30 | -- @param username string containing the Apple ID username 31 | -- @param password string containing the Apple ID password 32 | -- @return o new instance of MobileMe 33 | new = function(self, username, password) 34 | local o = { 35 | host = "fmipmobile.icloud.com", 36 | port = 443, 37 | username = username, 38 | password = password 39 | } 40 | setmetatable(o, self) 41 | self.__index = self 42 | return o 43 | end, 44 | 45 | -- Sends a message to an iOS device 46 | -- @param devid string containing the device id to which the message should 47 | -- be sent 48 | -- @param subject string containing the message subject 49 | -- @param message string containing the message body 50 | -- @param alarm boolean true if alarm should be sounded, false if not 51 | -- @return status true on success, false on failure 52 | -- @return err string containing the error message (if status is false) 53 | sendMessage = function(self, devid, subject, message, alarm) 54 | local data = '{"clientContext":{"appName":"FindMyiPhone","appVersion":\z 55 | "1.3","buildVersion":"145","deviceUDID":\z 56 | "0000000000000000000000000000000000000000","inactiveTime":5911,\z 57 | "osVersion":"3.2","productType":"iPad1,1","selectedDevice":"%s",\z 58 | "shouldLocate":false},"device":"%s","serverContext":{\z 59 | "callbackIntervalInMS":3000,"clientId":\z 60 | "0000000000000000000000000000000000000000","deviceLoadStatus":"203",\z 61 | "hasDevices":true,"lastSessionExtensionTime":null,"maxDeviceLoadTime":\z 62 | 60000,"maxLocatingTime":90000,"preferredLanguage":"en","prefsUpdateTime":\z 63 | 1276872996660,"sessionLifespan":900000,"timezone":{"currentOffset":\z 64 | -25200000,"previousOffset":-28800000,"previousTransition":1268560799999,\z 65 | "tzCurrentName":"Pacific Daylight Time","tzName":"America/Los_Angeles"},\z 66 | "validRegion":true},"sound":%s,"subject":"%s","text":"%s"}' 67 | data = data:format(devid, devid, tostring(alarm), subject, message) 68 | 69 | local url = ("/fmipservice/device/%s/sendMessage"):format(self.username) 70 | local auth = { username = self.username, password = self.password } 71 | 72 | local response = http.post(self.host, self.port, url, { header = self.headers, auth = auth, timeout = 10000 }, nil, data) 73 | 74 | if ( response.status == 200 ) then 75 | local status, resp = json.parse(response.body) 76 | if ( not(status) ) then 77 | stdnse.debug2("Failed to parse JSON response from server") 78 | return false, "Failed to parse JSON response from server" 79 | end 80 | 81 | if ( resp.statusCode ~= "200" ) then 82 | stdnse.debug2("Failed to send message to server") 83 | return false, "Failed to send message to server" 84 | end 85 | end 86 | return true 87 | end, 88 | 89 | -- Updates location information for all devices controlled by the Apple ID 90 | -- @return status true on success, false on failure 91 | -- @return json parsed json table or string containing an error message on 92 | -- failure 93 | update = function(self) 94 | 95 | local auth = { 96 | username = self.username, 97 | password = self.password 98 | } 99 | 100 | local url = ("/fmipservice/device/%s/initClient"):format(self.username) 101 | local data= '{"clientContext":{"appName":"FindMyiPhone","appVersion":\z 102 | "1.3","buildVersion":"145","deviceUDID":\z 103 | "0000000000000000000000000000000000000000","inactiveTime":2147483647,\z 104 | "osVersion":"4.2.1","personID":0,"productType":"iPad1,1"}}' 105 | 106 | local retries = 2 107 | 108 | local response 109 | repeat 110 | response = http.post(self.host, self.port, url, { header = self.headers, auth = auth }, nil, data) 111 | if ( response.header["x-apple-mme-host"] ) then 112 | self.host = response.header["x-apple-mme-host"] 113 | end 114 | 115 | if ( response.status == 401 ) then 116 | return false, "Authentication failed" 117 | elseif ( response.status ~= 200 and response.status ~= 330 ) then 118 | return false, "An unexpected error occurred" 119 | end 120 | 121 | retries = retries - 1 122 | until ( 200 == response.status or 0 == retries) 123 | 124 | if ( response.status ~= 200 ) then 125 | return false, "Received unexpected response from server" 126 | end 127 | 128 | local status, parsed_json = json.parse(response.body) 129 | 130 | if ( not(status) or parsed_json.statusCode ~= "200" ) then 131 | return false, "Failed to parse JSON response from server" 132 | end 133 | 134 | -- cache the parsed_json.content as devices 135 | self.devices = parsed_json.content 136 | 137 | return true, parsed_json 138 | end, 139 | 140 | -- Gets a list of devices 141 | -- @return devices table containing a list of devices 142 | getDevices = function(self) 143 | if ( not(self.devices) ) then 144 | self:update() 145 | end 146 | return self.devices 147 | end 148 | } 149 | 150 | 151 | Helper = { 152 | 153 | 154 | -- Creates a Helper instance 155 | -- @param username string containing the Apple ID username 156 | -- @param password string containing the Apple ID password 157 | -- @return o new instance of Helper 158 | new = function(self, username, password) 159 | local o = { 160 | mm = MobileMe:new(username, password) 161 | } 162 | setmetatable(o, self) 163 | self.__index = self 164 | o.mm:update() 165 | return o 166 | end, 167 | 168 | -- Gets the geolocation from each device 169 | -- 170 | -- @return status true on success, false on failure 171 | -- @return result table containing a table of device locations 172 | -- the table is indexed based on the name of the device and 173 | -- contains a location table with the following fields: 174 | -- * longitude - the GPS longitude 175 | -- * latitude - the GPS latitude 176 | -- * accuracy - the location accuracy 177 | -- * timestamp - the time the location was acquired 178 | -- * postype - the position type (GPS or WiFi) 179 | -- * finished - 180 | -- or string containing an error message on failure 181 | getLocation = function(self) 182 | -- do 3 tries, with a 5 second timeout to allow the location to update 183 | -- there are two attributes, locationFinished and isLocating that seem 184 | -- to be good candidates to monitor, but so far, I haven't had any 185 | -- success with that. 186 | local tries, timeout = 3, 5 187 | local result = {} 188 | 189 | repeat 190 | local status, response = self.mm:update() 191 | 192 | if ( not(status) or not(response) ) then 193 | return false, "Failed to retrieve response from server" 194 | end 195 | for _, device in ipairs(response.content) do 196 | if ( device.location ) then 197 | result[device.name] = { 198 | longitude = device.location.longitude, 199 | latitude = device.location.latitude, 200 | accuracy = device.location.horizontalAccuracy, 201 | timestamp = device.location.timeStamp, 202 | postype = device.location.positionType, 203 | finished = device.location.locationFinished, 204 | } 205 | end 206 | end 207 | tries = tries - 1 208 | if ( tries > 0 ) then 209 | stdnse.sleep(timeout) 210 | end 211 | until( tries == 0 ) 212 | return true, result 213 | end, 214 | 215 | -- Gets a list of names and ids of devices associated with the Apple ID 216 | -- @return status true on success, false on failure 217 | -- @return table of devices containing the following fields: 218 | -- name and id 219 | getDevices = function(self) 220 | local devices = {} 221 | for _, dev in ipairs(self.mm:getDevices()) do 222 | table.insert(devices, { name = dev.name, id = dev.id }) 223 | end 224 | return true, devices 225 | end, 226 | 227 | -- Send a message to an iOS Device 228 | -- 229 | -- @param devid string containing the device id to which the message should 230 | -- be sent 231 | -- @param subject string containing the message subject 232 | -- @param message string containing the message body 233 | -- @param alarm boolean true if alarm should be sounded, false if not 234 | -- @return status true on success, false on failure 235 | -- @return err string containing the error message (if status is false) 236 | sendMessage = function(self, ...) 237 | return self.mm:sendMessage(...) 238 | end 239 | 240 | } 241 | 242 | return _ENV; 243 | -------------------------------------------------------------------------------- /tests/nmap/natpmp.ok.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- This library implements the basics of NAT-PMP as described in the 3 | -- NAT Port Mapping Protocol (NAT-PMP) draft: 4 | -- o http://tools.ietf.org/html/draft-cheshire-nat-pmp-03 5 | -- 6 | -- 7 | -- @author "Patrik Karlsson " 8 | -- 9 | local bin = require "bin" 10 | local ipOps = require "ipOps" 11 | local nmap = require "nmap" 12 | local stdnse = require "stdnse" 13 | _ENV = stdnse.module("natpmp", stdnse.seeall) 14 | 15 | local ResultCode = { 16 | SUCCESS = 0, 17 | UNSUPPORTED_VERSION = 1, 18 | NOT_AUTHORIZED = 2, 19 | NETWORK_FAILURE = 3, 20 | OUT_OF_RESOURCES = 4, 21 | UNSUPPORTED_OPCODE = 5, 22 | } 23 | 24 | local ErrorMessage = { 25 | [ResultCode.UNSUPPORTED_VERSION] = "The device did not support the protocol version", 26 | [ResultCode.NOT_AUTHORIZED] = "The operation was not authorized", 27 | [ResultCode.NETWORK_FAILURE] = "Network failure", 28 | [ResultCode.OUT_OF_RESOURCES] = "The device is out of resources", 29 | [ResultCode.UNSUPPORTED_OPCODE] = "The requested operation was not supported", 30 | } 31 | 32 | 33 | Request = { 34 | 35 | GetWANIP = { 36 | 37 | new = function(self) 38 | local o = { version = 0, op = 0 } 39 | setmetatable(o, self) 40 | self.__index = self 41 | return o 42 | end, 43 | 44 | __tostring = function(self) 45 | return bin.pack(">CC", self.version, self.op) 46 | end, 47 | 48 | }, 49 | 50 | MapPort = { 51 | 52 | new = function(self, pubport, privport, proto, lifetime) 53 | assert(proto == "udp" or proto == "tcp", "Unsupported protocol") 54 | local o = { 55 | version = 0, 56 | pubport = pubport, 57 | privport = privport, 58 | proto = proto, 59 | lifetime = lifetime or 3600 60 | } 61 | setmetatable(o, self) 62 | self.__index = self 63 | return o 64 | end, 65 | 66 | __tostring = function(self) 67 | return bin.pack(">CCSSSI", 68 | self.version, 69 | (self.proto=="udp" and 1 or 2), 70 | 0, -- reserved 71 | self.privport, self.pubport, 72 | self.lifetime) 73 | end, 74 | 75 | } 76 | 77 | } 78 | 79 | Response = { 80 | 81 | GetWANIP = { 82 | 83 | new = function(self, data) 84 | local o = { data = data } 85 | setmetatable(o, self) 86 | self.__index = self 87 | if ( o:parse() ) then 88 | return o 89 | end 90 | end, 91 | 92 | parse = function(self) 93 | if ( #self.data ~= 12 ) then 94 | return 95 | end 96 | 97 | local pos 98 | pos, self.version, self.op, self.rescode = bin.unpack("ISSI", self.data, pos) 136 | return true 137 | end, 138 | } 139 | 140 | 141 | } 142 | 143 | 144 | 145 | 146 | 147 | Helper = { 148 | 149 | new = function(self, host, port) 150 | local o = { host = host, port = port } 151 | setmetatable(o, self) 152 | self.__index = self 153 | return o 154 | end, 155 | 156 | exchPacket = function(self, data) 157 | local socket = nmap.new_socket("udp") 158 | socket:set_timeout(5000) 159 | 160 | local status = socket:sendto(self.host, self.port, data) 161 | if ( not(status) ) then 162 | socket:close() 163 | return false, "Failed to send request to device" 164 | end 165 | 166 | local response 167 | status, response = socket:receive() 168 | socket:close() 169 | if ( not(status) ) then 170 | return false, "Failed to receive response from router" 171 | end 172 | return true, response 173 | end, 174 | 175 | --- Gets the WAN ip of the router 176 | getWANIP = function(self) 177 | local packet = Request.GetWANIP:new() 178 | local status, response = self:exchPacket(tostring(packet)) 179 | if ( not(status) ) then 180 | return status, response 181 | end 182 | 183 | response = Response.GetWANIP:new(response) 184 | if ( not(response) ) then 185 | return false, "Failed to parse response from router" 186 | end 187 | 188 | return true, response 189 | end, 190 | 191 | --- Maps a public port to a private port 192 | -- @param pubport number containing the public external port to map 193 | -- @param privport number containing the private internal port to map 194 | -- @param protocol string containing the protocol to map (udp|tcp) 195 | -- @param lifetime [optional] number containing the lifetime in seconds 196 | mapPort = function(self, pubport, privport, protocol, lifetime) 197 | local packet = Request.MapPort:new(pubport, privport, protocol, lifetime) 198 | local status, response = self:exchPacket(tostring(packet)) 199 | if ( not(status) ) then 200 | return status, response 201 | end 202 | 203 | response = Response.MapPort:new(response) 204 | if ( not(response) ) then 205 | return false, "Failed to parse response from router" 206 | end 207 | 208 | return true, response 209 | end, 210 | 211 | unmapPort = function(self, pubport, privport) 212 | return self:mapPort(pubport, privport, 0) 213 | end, 214 | 215 | unmapAllPorts = function(self) 216 | return self.mapPort(0, 0, 0) 217 | end, 218 | 219 | } 220 | 221 | return _ENV; 222 | -------------------------------------------------------------------------------- /tests/nmap/nrpc.ok.lua: -------------------------------------------------------------------------------- 1 | --- A minimalistic library to support Domino RPC 2 | -- 3 | -- Summary 4 | -- ------- 5 | -- The library currently only supports user enumeration and uses chunks of 6 | -- captured data to do so. 7 | -- 8 | -- Overview 9 | -- -------- 10 | -- The library contains the following classes: 11 | -- 12 | -- o DominoPacket 13 | -- - The packet class holding the packets sent between the client and the 14 | -- IBM Lotus Domino server 15 | -- 16 | -- o Helper 17 | -- - A helper class that provides easy access to the rest of the library 18 | -- 19 | -- Example 20 | -- ------- 21 | -- The following sample code illustrates how scripts can use the Helper class 22 | -- to interface the library: 23 | -- 24 | -- 25 | -- helper = nrpc.Helper:new(host, port) 26 | -- status, err = nrpc:Connect() 27 | -- status, res = nrpc:isValidUser("Patrik Karlsson") 28 | -- status, err = nrpc:Close() 29 | -- 30 | -- 31 | -- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html 32 | -- @author "Patrik Karlsson " 33 | -- 34 | 35 | -- 36 | -- Version 0.1 37 | -- Created 07/23/2010 - v0.1 - created by Patrik Karlsson 38 | -- 39 | 40 | 41 | local bin = require "bin" 42 | local match = require "match" 43 | local nmap = require "nmap" 44 | local stdnse = require "stdnse" 45 | _ENV = stdnse.module("nrpc", stdnse.seeall) 46 | 47 | -- The Domino Packet 48 | DominoPacket = { 49 | 50 | --- Creates a new DominoPacket instance 51 | -- 52 | -- @param data string containing the packet data 53 | -- @return a new DominoPacket instance 54 | new = function( self, data ) 55 | local o = {} 56 | setmetatable(o, self) 57 | self.__index = self 58 | o.data = data 59 | return o 60 | end, 61 | 62 | --- Reads a packet from the socket 63 | -- 64 | -- @param domsock socket connected to the server 65 | -- @return Status (true or false). 66 | -- @return Error code (if status is false). 67 | read = function( self, domsock ) 68 | local status, data = domsock:receive_buf(match.numbytes(2), true) 69 | local pos, len = bin.unpack( " 0x7f then 84 | ch = string.byte(".", 1) 85 | end 86 | io.write(string.format("%c", ch)) 87 | end 88 | 89 | io.write("\n") 90 | end 91 | 92 | -- Prints out the final, partial line 93 | if (#str % 16 ~= 0) then 94 | local line = math.floor((#str/16)) + 1 95 | io.write(string.format("%08x ", (line - 1) * 16)) 96 | 97 | for char=1, #str % 16, 1 do 98 | local ch = string.byte(str, ((line - 1) * 16) + char) 99 | io.write(string.format("%02x ", ch)) 100 | end 101 | io.write(string.rep(" ", 16 - (#str % 16))); 102 | io.write(" ") 103 | 104 | for char=1, #str % 16, 1 do 105 | local ch = string.byte(str, ((line - 1) * 16) + char) 106 | if ch < 0x20 or ch > 0x7f then 107 | ch = string.byte(".", 1) 108 | end 109 | io.write(string.format("%c", ch)) 110 | end 111 | 112 | io.write("\n") 113 | end 114 | 115 | -- Print out the length 116 | io.write(string.format(" Length: %d [0x%x]\n", #str, #str)) 117 | 118 | end 119 | 120 | ---Print out a stacktrace. The stacktrace will naturally include this function call. 121 | function print_stack() 122 | local thread = coroutine.running() 123 | local trace = debug.traceback(thread); 124 | if trace ~= "stack traceback:" then 125 | print(thread, "\n", trace, "\n"); 126 | end 127 | end 128 | 129 | 130 | 131 | return _ENV; 132 | -------------------------------------------------------------------------------- /tests/nmap/omp2.ok.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- This library was written to ease interaction with OpenVAS Manager servers 3 | -- using OMP (OpenVAS Management Protocol) version 2. 4 | -- 5 | -- A very small subset of the protocol is implemented. 6 | -- * Connection/authentication 7 | -- * Targets enumeration 8 | -- 9 | -- The library can also store accounts in the registry to share them between 10 | -- scripts. 11 | -- 12 | -- The complete protocol documentation is available on the official OpenVAS 13 | -- website: http://www.openvas.org/omp-2-0.html 14 | -- 15 | -- Sample use: 16 | -- 17 | -- local session = omp2.Session:new() 18 | -- local status, err = session:connect(host, port) 19 | -- local status, err = session:authenticate(username, password) 20 | -- ... 21 | -- session:close() 22 | -- 23 | -- 24 | -- @author Henri Doreau 25 | -- @copyright Same as Nmap -- See http://nmap.org/book/man-legal.html 26 | -- 27 | -- @args omp2.username The username to use for authentication. 28 | -- @args omp2.password The password to use for authentication. 29 | -- 30 | 31 | local nmap = require "nmap" 32 | local stdnse = require "stdnse" 33 | local table = require "table" 34 | _ENV = stdnse.module("omp2", stdnse.seeall) 35 | 36 | local HAVE_SSL = false 37 | 38 | if pcall(require,'openssl') then 39 | HAVE_SSL = true 40 | end 41 | 42 | --- A Session class holds connection and interaction with the server 43 | Session = { 44 | 45 | --- Creates a new session object 46 | new = function(self, o) 47 | 48 | o = o or {} 49 | setmetatable(o, self) 50 | self.__index = self 51 | 52 | o.username = nmap.registry.args["omp2.username"] 53 | o.password = nmap.registry.args["omp2.password"] 54 | o.socket = nmap.new_socket() 55 | 56 | return o 57 | end, 58 | 59 | --- Establishes the (SSL) connection to the remote server 60 | connect = function(self, host, port) 61 | if not HAVE_SSL then 62 | return false, "The OMP2 module requires OpenSSL support" 63 | end 64 | 65 | return self.socket:connect(host, port, "ssl") 66 | end, 67 | 68 | --- Closes connection 69 | close = function(self) 70 | return self.socket:close() 71 | end, 72 | 73 | --- Attempts to authenticate on the current connection 74 | authenticate = function(self, username, password) 75 | local status, err, xmldata 76 | 77 | -- TODO escape credentials 78 | status, err = self.socket:send("" 79 | .. "" .. username .. "" 80 | .. "" .. password .. "" 81 | .. "") 82 | 83 | if not status then 84 | stdnse.debug1("ERROR: %s", err) 85 | return false, err 86 | end 87 | 88 | status, xmldata = self.socket:receive() 89 | if not status then 90 | stdnse.debug1("ERROR: %s", xmldata) 91 | return false, xmldata 92 | end 93 | 94 | return xmldata:match('status="200"') 95 | end, 96 | 97 | --- Lists targets defined on the remote server 98 | ls_targets = function(self) 99 | local status, err, xmldata 100 | local res, target_names, target_hosts = {}, {}, {} 101 | 102 | status, err = self.socket:send("") 103 | 104 | if not status then 105 | stdnse.debug1("ERROR: %s", err) 106 | return false, err 107 | end 108 | 109 | status, xmldata = self.socket:receive() 110 | if not status then 111 | stdnse.debug1("ERROR: %s", xmldata) 112 | return false, xmldata 113 | end 114 | 115 | -- As NSE has no XML parser yet, we use regexp to extract the data from the 116 | -- XML output. Targets are defined as a name and the corresponding host(s). 117 | -- Thus we gather both and return an associative array, using names as keys 118 | -- and hosts as values. 119 | 120 | local i = 0 121 | for name in xmldata:gmatch("(.-)") do 122 | -- XXX this is hackish: skip the second and third "" tags, as they 123 | -- describe other components than the targets. 124 | -- see: http://www.openvas.org/omp-2-0.html#command_get_targets 125 | if i % 3 == 0 then 126 | table.insert(target_names, name) 127 | end 128 | i = i + 1 129 | end 130 | 131 | for hosts in xmldata:gmatch("(.-)") do 132 | table.insert(target_hosts, hosts) 133 | end 134 | 135 | for i, _ in ipairs(target_names) do 136 | res[target_names[i]] = target_hosts[i] 137 | end 138 | 139 | return res 140 | end, 141 | } 142 | 143 | --- Registers OMP2 credentials for a given host 144 | function add_account(host, username, password) 145 | if not nmap.registry[host.ip] then 146 | nmap.registry[host.ip] = {} 147 | end 148 | 149 | if not nmap.registry[host.ip]["omp2accounts"] then 150 | nmap.registry[host.ip]["omp2accounts"] = {} 151 | end 152 | 153 | table.insert(nmap.registry[host.ip]["omp2accounts"], {["username"] = username, ["password"] = password}) 154 | end 155 | 156 | --- Retrieves the list of accounts for a given host 157 | function get_accounts(host) 158 | local accounts = {} 159 | local username, password 160 | 161 | username = nmap.registry.args["omp2.username"] 162 | password = nmap.registry.args["omp2.password"] 163 | 164 | if username and password then 165 | table.insert(accounts, {["username"] = username, ["password"] = password}) 166 | end 167 | 168 | if nmap.registry[host.ip] and nmap.registry[host.ip]["omp2accounts"] then 169 | for _, account in pairs(nmap.registry[host.ip]["omp2accounts"]) do 170 | table.insert(accounts, account) 171 | end 172 | end 173 | 174 | if #accounts > 0 then 175 | return accounts 176 | end 177 | return nil 178 | end 179 | 180 | 181 | return _ENV; 182 | -------------------------------------------------------------------------------- /tests/nmap/ospf.ok.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- A minimalistic OSPF (Open Shortest Path First routing protocol) library, currently supporting IPv4 and the following 3 | -- OSPF message types: HELLO 4 | -- 5 | -- The library consists of an OSPF class that contains code to handle OSPFv2 packets. 6 | -- 7 | -- @author "Patrik Karlsson " 8 | -- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html 9 | 10 | local bin = require "bin" 11 | local bit = require "bit" 12 | local math = require "math" 13 | local stdnse = require "stdnse" 14 | local table = require "table" 15 | local ipOps = require "ipOps" 16 | local packet = require "packet" 17 | _ENV = stdnse.module("ospf", stdnse.seeall) 18 | 19 | -- The OSPF class. 20 | OSPF = { 21 | 22 | -- Message Type constants 23 | Message = { 24 | HELLO = 1, 25 | DB_DESCRIPTION = 2, 26 | LS_UPDATE = 4, 27 | }, 28 | 29 | LSUpdate = { 30 | 31 | }, 32 | 33 | Header = { 34 | size = 24, 35 | new = function(self, type, area_id, router_id, auth_type, auth_data) 36 | local o = { 37 | ver = 2, 38 | type = type, 39 | length = 0, 40 | router_id = router_id or 0, 41 | area_id = area_id or 0, 42 | chksum = 0, 43 | auth_type = auth_type or 0, 44 | auth_data = auth_data or {}, 45 | } 46 | setmetatable(o, self) 47 | self.__index = self 48 | return o 49 | end, 50 | 51 | parse = function(data) 52 | local header = OSPF.Header:new() 53 | local pos 54 | pos, header.ver, header.type, header.length = bin.unpack(">CCS", data) 55 | assert( header.ver == 2, "Invalid OSPF version detected") 56 | 57 | pos, header.router_id, header.area_id, header.chksum, header.auth_type 58 | = bin.unpack("ISS", data, pos) 59 | 60 | -- No authentication 61 | if header.auth_type == 0x00 then 62 | header.auth_data.password = nil 63 | -- Clear text password 64 | elseif header.auth_type == 0x01 then 65 | pos, header.auth_data.password = bin.unpack(">A8", data, pos) 66 | -- MD5 hash authentication 67 | elseif header.auth_type == 0x02 then 68 | local _ 69 | _, header.auth_data.keyid = bin.unpack(">C", data, pos+2) 70 | _, header.auth_data.length = bin.unpack(">C", data, pos+3) 71 | _, header.auth_data.seq = bin.unpack(">C", data, pos+4) 72 | _, header.auth_data.hash = bin.unpack(">H"..header.auth_data.length, data, header.length+1) 73 | else 74 | -- Shouldn't happen 75 | stdnse.debug1("Unknown authentication type " .. header.auth_type) 76 | return nil 77 | end 78 | header.router_id = ipOps.fromdword(header.router_id) 79 | return header 80 | end, 81 | 82 | --- Sets the OSPF Area ID 83 | -- @param areaid Area ID. 84 | setAreaID = function(self, areaid) 85 | self.area_id = (type(areaid) == "number") and areaid or ipOps.todword(areaid) 86 | end, 87 | 88 | --- Sets the OSPF Router ID 89 | -- @param router_id Router ID. 90 | setRouterId = function(self, router_id) 91 | self.router_id = router_id 92 | end, 93 | 94 | --- Sets the OSPF Packet length 95 | -- @param length Packet length. 96 | setLength = function(self, length) 97 | self.length = self.size + length 98 | end, 99 | 100 | __tostring = function(self) 101 | local auth 102 | if self.auth_type == 0x00 then 103 | auth = bin.pack(">L", 0x00) 104 | elseif self.auth_type == 0x01 then 105 | auth = bin.pack(">A8", self.auth_data.password) 106 | elseif self.auth_type == 0x02 then 107 | auth = bin.pack(">A".. self.auth_data.length, self.auth_data.hash) 108 | end 109 | local hdr = bin.pack(">CCS", self.ver, self.type, self.length ) 110 | .. bin.pack(">IISS", ipOps.todword(self.router_id), self.area_id, self.chksum, self.auth_type) 111 | .. auth 112 | return hdr 113 | end, 114 | 115 | }, 116 | 117 | Hello = { 118 | new = function(self) 119 | local o = { 120 | header = OSPF.Header:new(OSPF.Message.HELLO), 121 | options = 0x02, 122 | prio = 0, 123 | interval = 10, 124 | router_dead_interval = 40, 125 | neighbors = {}, 126 | DR = "0.0.0.0", 127 | BDR = "0.0.0.0", 128 | } 129 | setmetatable(o, self) 130 | self.__index = self 131 | return o 132 | end, 133 | 134 | --- Adds a neighbor to the list of neighbors. 135 | -- @param neighbor IP Address of the neighbor. 136 | addNeighbor = function(self, neighbor) 137 | table.insert(self.neighbors, neighbor) 138 | end, 139 | 140 | --- Sets the OSPF netmask. 141 | -- @param netmask Netmask in A.B.C.D 142 | setNetmask = function(self, netmask) 143 | if netmask then 144 | self.netmask = netmask 145 | end 146 | end, 147 | 148 | --- Sets the OSPF designated Router. 149 | -- @param router IP address of the designated router. 150 | setDesignatedRouter = function(self, router) 151 | if router then 152 | self.DR = router 153 | end 154 | end, 155 | 156 | --- Sets the OSPF backup Router. 157 | -- @param router IP Address of the backup router. 158 | setBackupRouter = function(self, router) 159 | if router then 160 | self.BDR = router 161 | end 162 | end, 163 | 164 | __tostring = function(self) 165 | self.neighbors = self.neighbors or {} 166 | local function tostr() 167 | local data = bin.pack(">ISCCIII", ipOps.todword(self.netmask), self.interval, self.options, self.prio, self.router_dead_interval, ipOps.todword(self.DR), ipOps.todword(self.BDR)) 168 | for _, n in ipairs(self.neighbors) do 169 | data = data .. bin.pack(">I", ipOps.todword(n)) 170 | end 171 | self.header:setLength(#data) 172 | return tostring(self.header) .. data 173 | end 174 | local data = tostr() 175 | self.header.chksum = packet.in_cksum(data:sub(1,12) .. data:sub(25)) 176 | return tostr() 177 | end, 178 | 179 | parse = function(data) 180 | local hello = OSPF.Hello:new() 181 | local pos = OSPF.Header.size + 1 182 | hello.header = OSPF.Header.parse(data) 183 | assert( #data >= hello.header.length, "OSPF packet too short") 184 | pos, hello.netmask, hello.interval, hello.options, hello.prio, 185 | hello.router_dead_interval, hello.DR, 186 | hello.BDR = bin.unpack("SCCI", self.mtu, self.options, flags, self.sequence) 256 | self.header:setLength(#data) 257 | return tostring(self.header) .. data 258 | end 259 | local data = tostr() 260 | self.header.chksum = packet.in_cksum(data:sub(1,12) .. data:sub(25)) 261 | return tostr() 262 | end, 263 | 264 | parse = function(data) 265 | local desc = OSPF.DBDescription:new() 266 | local pos = OSPF.Header.size + 1 267 | desc.header = OSPF.Header.parse(data) 268 | assert( #data == desc.header.length, "OSPF packet too short") 269 | 270 | local flags = 0 271 | pos, desc.mtu, desc.options, flags, desc.sequence = bin.unpack(">SCCI", data, pos) 272 | 273 | desc.init = ( bit.band(flags, 4) == 4 ) 274 | desc.more = ( bit.band(flags, 2) == 2 ) 275 | desc.master = ( bit.band(flags, 1) == 1 ) 276 | 277 | if ( desc.init or not(desc.more) ) then 278 | return desc 279 | end 280 | 281 | return desc 282 | end, 283 | 284 | }, 285 | 286 | Response = { 287 | 288 | parse = function(data) 289 | local pos, ver, ospf_type = bin.unpack("CC", data) 290 | if ( ospf_type == OSPF.Message.HELLO ) then 291 | return OSPF.Hello.parse( data ) 292 | elseif( ospf_type == OSPF.Message.DB_DESCRIPTION ) then 293 | return OSPF.DBDescription.parse(data) 294 | end 295 | return 296 | end, 297 | 298 | } 299 | } 300 | 301 | return _ENV; 302 | -------------------------------------------------------------------------------- /tests/nmap/pop3.ok.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- POP3 functions. 3 | -- 4 | -- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html 5 | 6 | local base64 = require "base64" 7 | local comm = require "comm" 8 | local stdnse = require "stdnse" 9 | local string = require "string" 10 | local table = require "table" 11 | _ENV = stdnse.module("pop3", stdnse.seeall) 12 | 13 | local HAVE_SSL, openssl = pcall(require,'openssl') 14 | 15 | 16 | err = { 17 | none = 0, 18 | userError = 1, 19 | pwError = 2, 20 | informationMissing = 3, 21 | OpenSSLMissing = 4, 22 | } 23 | 24 | --- 25 | -- Check a POP3 response for "+OK". 26 | -- @param line First line returned from an POP3 request. 27 | -- @return The string "+OK" if found or nil otherwise. 28 | function stat(line) 29 | return string.match(line, "+OK") 30 | end 31 | 32 | 33 | 34 | --- 35 | -- Try to log in using the USER/PASS commands. 36 | -- @param socket Socket connected to POP3 server. 37 | -- @param user User string. 38 | -- @param pw Password string. 39 | -- @return Status (true or false). 40 | -- @return Error code if status is false. 41 | function login_user(socket, user, pw) 42 | socket:send("USER " .. user .. "\r\n") 43 | local status, line = socket:receive_lines(1) 44 | if not stat(line) then return false, err.user_error end 45 | socket:send("PASS " .. pw .. "\r\n") 46 | 47 | status, line = socket:receive_lines(1) 48 | 49 | if stat(line) then return true, err.none 50 | else return false, err.pwError 51 | end 52 | end 53 | 54 | 55 | --- 56 | -- Try to login using the the AUTH command using SASL/Plain method. 57 | -- @param socket Socket connected to POP3 server. 58 | -- @param user User string. 59 | -- @param pw Password string. 60 | -- @return Status (true or false). 61 | -- @return Error code if status is false. 62 | function login_sasl_plain(socket, user, pw) 63 | 64 | local auth64 = base64.enc(user .. "\0" .. user .. "\0" .. pw) 65 | socket:send("AUTH PLAIN " .. auth64 .. "\r\n") 66 | 67 | local status, line = socket:receive_lines(1) 68 | 69 | if stat(line) then 70 | return true, err.none 71 | else 72 | return false, err.pwError 73 | end 74 | end 75 | 76 | --- 77 | -- Try to login using the AUTH command using SASL/Login method. 78 | -- @param user User string. 79 | -- @param pw Password string. 80 | -- @param pw String containing password to login. 81 | -- @return Status (true or false). 82 | -- @return Error code if status is false. 83 | function login_sasl_login(socket, user, pw) 84 | 85 | local user64 = base64.enc(user) 86 | 87 | local pw64 = base64.enc(pw) 88 | 89 | socket:send("AUTH LOGIN\r\n") 90 | 91 | local status, line = socket:receive_lines(1) 92 | if not base64.dec(string.sub(line, 3)) == "User Name:" then 93 | return false, err.userError 94 | end 95 | 96 | socket:send(user64) 97 | 98 | local status, line = socket:receive_lines(1) 99 | 100 | if not base64.dec(string.sub(line, 3)) == "Password:" then 101 | return false, err.userError 102 | end 103 | 104 | socket:send(pw64) 105 | 106 | local status, line = socket:receive_lines(1) 107 | 108 | if stat(line) then 109 | return true, err.none 110 | else 111 | return false, err.pwError 112 | end 113 | end 114 | 115 | --- 116 | -- Try to login using the APOP command. 117 | -- @param socket Socket connected to POP3 server. 118 | -- @param user User string. 119 | -- @param pw Password string. 120 | -- @param challenge String containing challenge from POP3 server greeting. 121 | -- @return Status (true or false). 122 | -- @return Error code if status is false. 123 | function login_apop(socket, user, pw, challenge) 124 | if type(challenge) ~= "string" then return false, err.informationMissing end 125 | 126 | local apStr = stdnse.tohex(openssl.md5(challenge .. pw)) 127 | socket:send(("APOP %s %s\r\n"):format(user, apStr)) 128 | 129 | local status, line = socket:receive_lines(1) 130 | 131 | if (stat(line)) then 132 | return true, err.none 133 | else 134 | return false, err.pwError 135 | end 136 | end 137 | 138 | --- 139 | -- Asks a POP3 server for capabilities. 140 | -- 141 | -- See RFC 2449. 142 | -- @param host Host to be queried. 143 | -- @param port Port to connect to. 144 | -- @return Table containing capabilities or nil on error. 145 | -- @return nil or String error message. 146 | function capabilities(host, port) 147 | 148 | local socket, line, bopt, first_line = comm.tryssl(host, port, "" , {request_timeout=10000, recv_before=true}) 149 | if not socket then 150 | return nil, "Could Not Connect" 151 | end 152 | if not stat(first_line) then 153 | return nil, "No Response" 154 | end 155 | 156 | local capas = {} 157 | if string.find(first_line, "<[%p%w]+>") then 158 | capas.APOP = {} 159 | end 160 | 161 | local status = socket:send("CAPA\r\n") 162 | if( not(status) ) then 163 | return nil, "Failed to send" 164 | end 165 | 166 | status, line = socket:receive_buf("%.", false) 167 | if( not(status) ) then 168 | return nil, "Failed to receive" 169 | end 170 | socket:close() 171 | 172 | local lines = stdnse.strsplit("\r\n",line) 173 | if not stat(table.remove(lines,1)) then 174 | capas.capa = false 175 | return capas 176 | end 177 | 178 | for _, line in ipairs(lines) do 179 | if ( line and #line>0 ) then 180 | local capability = line:sub(line:find("[%w-]+")) 181 | line = line:sub(#capability + 2) 182 | if ( line ~= "" ) then 183 | capas[capability] = stdnse.strsplit(" ", line) 184 | else 185 | capas[capability] = {} 186 | end 187 | end 188 | end 189 | 190 | return capas 191 | end 192 | 193 | --- 194 | -- Try to login using the AUTH command using SASL/CRAM-MD5 method. 195 | -- @param socket Socket connected to POP3 server. 196 | -- @param user User string. 197 | -- @param pw Password string. 198 | -- @return Status (true or false). 199 | -- @return Error code if status is false. 200 | function login_sasl_crammd5(socket, user, pw) 201 | 202 | socket:send("AUTH CRAM-MD5\r\n") 203 | 204 | local status, line = socket:receive_lines(1) 205 | 206 | local challenge = base64.dec(string.sub(line, 3)) 207 | 208 | local digest = stdnse.tohex(openssl.hmac('md5', pw, challenge)) 209 | local authStr = base64.enc(user .. " " .. digest) 210 | socket:send(authStr .. "\r\n") 211 | 212 | local status, line = socket:receive_lines(1) 213 | 214 | if stat(line) then 215 | return true, err.none 216 | else 217 | return false, err.pwError 218 | end 219 | end 220 | 221 | -- Overwrite functions requiring OpenSSL if we got no OpenSSL. 222 | if not HAVE_SSL then 223 | 224 | local no_ssl = function() 225 | return false, err.OpenSSLMissing 226 | end 227 | 228 | login_apop = no_ssl 229 | login_sasl_crammd5 = no_ssl 230 | end 231 | 232 | 233 | return _ENV; 234 | -------------------------------------------------------------------------------- /tests/nmap/re.ok.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- Regular Expression functions 3 | -- 4 | -- This is the re.lua module included in the LPeg distribution (http://www.inf.puc-rio.br/~roberto/lpeg/re.html) 5 | -- 6 | -- @class module 7 | -- @name re 8 | -- @copyright 2008-2010 Lua.org, PUC-Rio. (https://svn.nmap.org/nmap/docs/licenses/MIT) 9 | 10 | --- Compiles the given string and returns an equivalent LPeg pattern. 11 | -- 12 | -- The given string may define either an expression or a grammar. The optional 13 | -- defs table provides extra Lua values to be used by the pattern. 14 | -- @class function 15 | -- @name compile 16 | -- @param string a regular expression or an LPeg grammar 17 | -- @param defs Optional values to be used by the pattern 18 | -- @return an LPeg pattern 19 | 20 | --- Searches the given pattern in the given subject. 21 | -- 22 | -- If it finds a match, returns the index where this occurrence starts and the 23 | -- index where it ends. Otherwise, returns nil. 24 | -- 25 | -- An optional numeric argument init makes the search starts at that position 26 | -- in the subject string. As usual in Lua libraries, a negative value counts 27 | -- from the end. 28 | -- @class function 29 | -- @name find 30 | -- @param subject The string to search 31 | -- @param pattern A regular expression 32 | -- @param init Optional index into subject to start searching 33 | -- @return index where the occurrence starts or nil 34 | -- @return index where the occurrence ends 35 | 36 | --- Global substitution. 37 | -- 38 | -- Does a global substitution, replacing all occurrences of pattern in the 39 | -- given subject by replacement. 40 | -- @class function 41 | -- @name gsub 42 | -- @param subject The string to search 43 | -- @param pattern The pattern to match 44 | -- @param replacement The replacement for each pattern 45 | -- @return The string with all occurrences replaced 46 | 47 | --- Matches the given pattern against the given subject 48 | -- 49 | -- Matches the given pattern against the given subject, returning all captures. 50 | -- @class function 51 | -- @name match 52 | -- @param subject The string to search 53 | -- @param pattern The pattern to match 54 | -- @param init Optional index into subject to start searching 55 | -- @return pattern captures 56 | 57 | --- Updates the pre-defined character classes to the current locale. 58 | -- 59 | -- @class function 60 | -- @name updatelocale 61 | 62 | -- $Id: re.lua,v 1.44 2013/03/26 20:11:40 roberto Exp $ 63 | 64 | -- imported functions and modules 65 | local tonumber, type, print, error = tonumber, type, print, error 66 | local setmetatable = setmetatable 67 | local m = require"lpeg" 68 | 69 | -- 'm' will be used to parse expressions, and 'mm' will be used to 70 | -- create expressions; that is, 're' runs on 'm', creating patterns 71 | -- on 'mm' 72 | local mm = m 73 | 74 | -- pattern's metatable 75 | local mt = getmetatable(mm.P(0)) 76 | 77 | 78 | 79 | -- No more global accesses after this point 80 | local version = _VERSION 81 | if version == "Lua 5.2" then _ENV = nil end 82 | 83 | 84 | local any = m.P(1) 85 | 86 | 87 | -- Pre-defined names 88 | local Predef = { nl = m.P"\n" } 89 | 90 | 91 | local mem 92 | local fmem 93 | local gmem 94 | 95 | 96 | local function updatelocale () 97 | mm.locale(Predef) 98 | Predef.a = Predef.alpha 99 | Predef.c = Predef.cntrl 100 | Predef.d = Predef.digit 101 | Predef.g = Predef.graph 102 | Predef.l = Predef.lower 103 | Predef.p = Predef.punct 104 | Predef.s = Predef.space 105 | Predef.u = Predef.upper 106 | Predef.w = Predef.alnum 107 | Predef.x = Predef.xdigit 108 | Predef.A = any - Predef.a 109 | Predef.C = any - Predef.c 110 | Predef.D = any - Predef.d 111 | Predef.G = any - Predef.g 112 | Predef.L = any - Predef.l 113 | Predef.P = any - Predef.p 114 | Predef.S = any - Predef.s 115 | Predef.U = any - Predef.u 116 | Predef.W = any - Predef.w 117 | Predef.X = any - Predef.x 118 | mem = {} -- restart memoization 119 | fmem = {} 120 | gmem = {} 121 | local mt = {__mode = "v"} 122 | setmetatable(mem, mt) 123 | setmetatable(fmem, mt) 124 | setmetatable(gmem, mt) 125 | end 126 | 127 | 128 | updatelocale() 129 | 130 | 131 | 132 | local I = m.P(function (s,i) print(i, s:sub(1, i-1)); return i end) 133 | 134 | 135 | local function getdef (id, defs) 136 | local c = defs and defs[id] 137 | if not c then error("undefined name: " .. id) end 138 | return c 139 | end 140 | 141 | 142 | local function patt_error (s, i) 143 | local msg = (#s < i + 20) and s:sub(i) 144 | or s:sub(i,i+20) .. "..." 145 | msg = ("pattern error near '%s'"):format(msg) 146 | error(msg, 2) 147 | end 148 | 149 | local function mult (p, n) 150 | local np = mm.P(true) 151 | while n >= 1 do 152 | if n%2 >= 1 then np = np * p end 153 | p = p * p 154 | n = n/2 155 | end 156 | return np 157 | end 158 | 159 | local function equalcap (s, i, c) 160 | if type(c) ~= "string" then return nil end 161 | local e = #c + i 162 | if s:sub(i, e - 1) == c then return e else return nil end 163 | end 164 | 165 | 166 | local S = (Predef.space + "--" * (any - Predef.nl)^0)^0 167 | 168 | local name = m.R("AZ", "az", "__") * m.R("AZ", "az", "__", "09")^0 169 | 170 | local arrow = S * "<-" 171 | 172 | local seq_follow = m.P"/" + ")" + "}" + ":}" + "~}" + "|}" + (name * arrow) + -1 173 | 174 | name = m.C(name) 175 | 176 | 177 | -- a defined name only have meaning in a given environment 178 | local Def = name * m.Carg(1) 179 | 180 | local num = m.C(m.R"09"^1) * S / tonumber 181 | 182 | local String = "'" * m.C((any - "'")^0) * "'" + 183 | '"' * m.C((any - '"')^0) * '"' 184 | 185 | 186 | local defined = "%" * Def / function (c,Defs) 187 | local cat = Defs and Defs[c] or Predef[c] 188 | if not cat then error ("name '" .. c .. "' undefined") end 189 | return cat 190 | end 191 | 192 | local Range = m.Cs(any * (m.P"-"/"") * (any - "]")) / mm.R 193 | 194 | local item = defined + Range + m.C(any) 195 | 196 | local Class = 197 | "[" 198 | * (m.C(m.P"^"^-1)) -- optional complement symbol 199 | * m.Cf(item * (item - "]")^0, mt.__add) / 200 | function (c, p) return c == "^" and any - p or p end 201 | * "]" 202 | 203 | local function adddef (t, k, exp) 204 | if t[k] then 205 | error("'"..k.."' already defined as a rule") 206 | else 207 | t[k] = exp 208 | end 209 | return t 210 | end 211 | 212 | local function firstdef (n, r) return adddef({n}, n, r) end 213 | 214 | 215 | local function NT (n, b) 216 | if not b then 217 | error("rule '"..n.."' used outside a grammar") 218 | else return mm.V(n) 219 | end 220 | end 221 | 222 | 223 | local exp = m.P{ "Exp", 224 | Exp = S * ( m.V"Grammar" 225 | + m.Cf(m.V"Seq" * ("/" * S * m.V"Seq")^0, mt.__add) ); 226 | Seq = m.Cf(m.Cc(m.P"") * m.V"Prefix"^0 , mt.__mul) 227 | * (#seq_follow + patt_error); 228 | Prefix = "&" * S * m.V"Prefix" / mt.__len 229 | + "!" * S * m.V"Prefix" / mt.__unm 230 | + m.V"Suffix"; 231 | Suffix = m.Cf(m.V"Primary" * S * 232 | ( ( m.P"+" * m.Cc(1, mt.__pow) 233 | + m.P"*" * m.Cc(0, mt.__pow) 234 | + m.P"?" * m.Cc(-1, mt.__pow) 235 | + "^" * ( m.Cg(num * m.Cc(mult)) 236 | + m.Cg(m.C(m.S"+-" * m.R"09"^1) * m.Cc(mt.__pow)) 237 | ) 238 | + "->" * S * ( m.Cg((String + num) * m.Cc(mt.__div)) 239 | + m.P"{}" * m.Cc(nil, m.Ct) 240 | + m.Cg(Def / getdef * m.Cc(mt.__div)) 241 | ) 242 | + "=>" * S * m.Cg(Def / getdef * m.Cc(m.Cmt)) 243 | ) * S 244 | )^0, function (a,b,f) return f(a,b) end ); 245 | Primary = "(" * m.V"Exp" * ")" 246 | + String / mm.P 247 | + Class 248 | + defined 249 | + "{:" * (name * ":" + m.Cc(nil)) * m.V"Exp" * ":}" / 250 | function (n, p) return mm.Cg(p, n) end 251 | + "=" * name / function (n) return mm.Cmt(mm.Cb(n), equalcap) end 252 | + m.P"{}" / mm.Cp 253 | + "{~" * m.V"Exp" * "~}" / mm.Cs 254 | + "{|" * m.V"Exp" * "|}" / mm.Ct 255 | + "{" * m.V"Exp" * "}" / mm.C 256 | + m.P"." * m.Cc(any) 257 | + (name * -arrow + "<" * name * ">") * m.Cb("G") / NT; 258 | Definition = name * arrow * m.V"Exp"; 259 | Grammar = m.Cg(m.Cc(true), "G") * 260 | m.Cf(m.V"Definition" / firstdef * m.Cg(m.V"Definition")^0, 261 | adddef) / mm.P 262 | } 263 | 264 | local pattern = S * m.Cg(m.Cc(false), "G") * exp / mm.P * (-any + patt_error) 265 | 266 | 267 | local function compile (p, defs) 268 | if mm.type(p) == "pattern" then return p end -- already compiled 269 | local cp = pattern:match(p, 1, defs) 270 | if not cp then error("incorrect pattern", 3) end 271 | return cp 272 | end 273 | 274 | local function match (s, p, i) 275 | local cp = mem[p] 276 | if not cp then 277 | cp = compile(p) 278 | mem[p] = cp 279 | end 280 | return cp:match(s, i or 1) 281 | end 282 | 283 | local function find (s, p, i) 284 | local cp = fmem[p] 285 | if not cp then 286 | cp = compile(p) / 0 287 | cp = mm.P{ mm.Cp() * cp * mm.Cp() + 1 * mm.V(1) } 288 | fmem[p] = cp 289 | end 290 | local i, e = cp:match(s, i or 1) 291 | if i then return i, e - 1 292 | else return i 293 | end 294 | end 295 | 296 | local function gsub (s, p, rep) 297 | local g = gmem[p] or {} -- ensure gmem[p] is not collected while here 298 | gmem[p] = g 299 | local cp = g[rep] 300 | if not cp then 301 | cp = compile(p) 302 | cp = mm.Cs((cp / rep + 1)^0) 303 | g[rep] = cp 304 | end 305 | return cp:match(s) 306 | end 307 | 308 | 309 | -- exported names 310 | local re = { 311 | compile = compile, 312 | match = match, 313 | find = find, 314 | gsub = gsub, 315 | updatelocale = updatelocale, 316 | } 317 | 318 | -- NSE uses Lua 5.2 319 | --if version == "Lua 5.1" then _G.re = re end 320 | 321 | return re 322 | -------------------------------------------------------------------------------- /tests/nmap/redis.ok.lua: -------------------------------------------------------------------------------- 1 | --- A minimalistic Redis (in-memory key-value data store) library. 2 | -- 3 | -- @author "Patrik Karlsson " 4 | 5 | local match = require "match" 6 | local nmap = require "nmap" 7 | local stdnse = require "stdnse" 8 | local table = require "table" 9 | _ENV = stdnse.module("redis", stdnse.seeall) 10 | 11 | Request = { 12 | 13 | new = function(self, cmd, ...) 14 | local o = { cmd = cmd, args = {...} } 15 | setmetatable (o,self) 16 | self.__index = self 17 | return o 18 | end, 19 | 20 | __tostring = function(self) 21 | local output = ("*%s\r\n$%d\r\n%s\r\n"):format(#self.args + 1, #self.cmd, self.cmd) 22 | 23 | for _, arg in ipairs(self.args) do 24 | arg = tostring(arg) 25 | output = output .. ("$%s\r\n%s\r\n"):format(#arg, arg) 26 | end 27 | 28 | return output 29 | end 30 | 31 | } 32 | 33 | 34 | Response = { 35 | 36 | Type = { 37 | STATUS = 0, 38 | ERROR = 1, 39 | INTEGER = 2, 40 | BULK = 3, 41 | MULTIBULK = 4, 42 | }, 43 | 44 | new = function(self, socket) 45 | local o = { socket = socket } 46 | setmetatable (o,self) 47 | self.__index = self 48 | return o 49 | end, 50 | 51 | receive = function(self) 52 | local status, data = self.socket:receive_buf("\r\n", false) 53 | if ( not(status) ) then 54 | return false, "Failed to receive data from server" 55 | end 56 | 57 | -- if we have a status, integer or error message 58 | if ( data:match("^[%-%+%:]") ) then 59 | local response = { data = data } 60 | local t = data:match("^([-+:])") 61 | if ( t == "-" ) then 62 | response.type = Response.Type.ERROR 63 | elseif ( t == "+" ) then 64 | response.type = Response.Type.STATUS 65 | elseif ( t == ":" ) then 66 | response.type = Response.Type.INTEGER 67 | end 68 | 69 | return true, response 70 | end 71 | 72 | -- process bulk reply 73 | if ( data:match("^%$") ) then 74 | -- non existing key 75 | if ( data == "$-1" ) then 76 | return true, nil 77 | end 78 | 79 | local len = tonumber(data:match("^%$(%d*)")) 80 | -- we should only have a single line, so we can just peel of the length 81 | status, data = self.socket:receive_buf(match.numbytes(len), false) 82 | if( not(status) ) then 83 | return false, "Failed to receive data from server" 84 | end 85 | 86 | return true, { data = data, type = Response.Type.BULK } 87 | end 88 | 89 | -- process multi-bulk reply 90 | if ( data:match("^%*%d*") ) then 91 | local count = data:match("^%*(%d*)") 92 | local results = {} 93 | 94 | for i=1, count do 95 | -- peel of the length 96 | local status = self.socket:receive_buf("\r\n", false) 97 | if( not(status) ) then 98 | return false, "Failed to receive data from server" 99 | end 100 | 101 | status, data = self.socket:receive_buf("\r\n", false) 102 | if( not(status) ) then 103 | return false, "Failed to receive data from server" 104 | end 105 | table.insert(results, data) 106 | end 107 | return true, { data = results, type = Response.Type.MULTIBULK } 108 | end 109 | 110 | return false, "Unsupported response" 111 | end, 112 | 113 | 114 | 115 | } 116 | 117 | Helper = { 118 | 119 | new = function(self, host, port) 120 | local o = { host = host, port = port } 121 | setmetatable (o,self) 122 | self.__index = self 123 | return o 124 | end, 125 | 126 | connect = function(self) 127 | self.socket = nmap.new_socket() 128 | return self.socket:connect(self.host, self.port) 129 | end, 130 | 131 | reqCmd = function(self, cmd, ...) 132 | local req = Request:new(cmd, ...) 133 | local status, err = self.socket:send(tostring(req)) 134 | if (not(status)) then 135 | return false, "Failed to send command to server" 136 | end 137 | return Response:new(self.socket):receive() 138 | end, 139 | 140 | close = function(self) 141 | return self.socket:close() 142 | end 143 | 144 | } 145 | 146 | return _ENV; 147 | -------------------------------------------------------------------------------- /tests/nmap/rsync.ok.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- A minimalist RSYNC (remote file sync) library 3 | -- 4 | -- @author "Patrik Karlsson " 5 | 6 | local base64 = require "base64" 7 | local bin = require "bin" 8 | local match = require "match" 9 | local nmap = require "nmap" 10 | local stdnse = require "stdnse" 11 | local table = require "table" 12 | local openssl = stdnse.silent_require "openssl" 13 | _ENV = stdnse.module("rsync", stdnse.seeall) 14 | 15 | 16 | -- The Helper class serves as the main interface for script writers 17 | Helper = { 18 | 19 | -- Creates a new instance of the Helper class 20 | -- @param host table as received by the action function 21 | -- @param port table as received by the action function 22 | -- @param options table containing any additional options 23 | -- @return o instance of Helper 24 | new = function(self, host, port, options) 25 | local o = { host = host, port = port, options = options or {} } 26 | assert(o.options.module, "No rsync module was specified, aborting ...") 27 | setmetatable(o, self) 28 | self.__index = self 29 | return o 30 | end, 31 | 32 | -- Handles send and receive of control messages 33 | -- @param data string containing the command to send 34 | -- @return status true on success, false on failure 35 | -- @return data containing the response from the server 36 | -- err string, if status is false 37 | ctrl_exch = function(self, data) 38 | local status, err = self.socket:send(data.."\n") 39 | if ( not(status) ) then 40 | return false, err 41 | end 42 | local status, data = self.socket:receive_buf("\n", false) 43 | if( not(status) ) then 44 | return false, err 45 | end 46 | return true, data 47 | end, 48 | 49 | -- Connects to the rsync server 50 | -- @return status, true on success, false on failure 51 | -- @return err string containing an error message if status is false 52 | connect = function(self) 53 | self.socket = nmap.new_socket() 54 | self.socket:set_timeout(self.options.timeout or 5000) 55 | local status, err = self.socket:connect(self.host, self.port) 56 | if ( not(status) ) then 57 | return false, err 58 | end 59 | 60 | local data 61 | status, data = self:ctrl_exch("@RSYNCD: 29") 62 | if ( not(status) ) then 63 | return false, data 64 | end 65 | if ( not(data:match("^@RSYNCD: [%.%d]+$")) ) then 66 | return false, "Protocol error" 67 | end 68 | return true 69 | end, 70 | 71 | -- Authenticates against the rsync module. If no username is given, assume 72 | -- no authentication is required. 73 | -- @param username [optional] string containing the username 74 | -- @param password [optional] string containing the password 75 | login = function(self, username, password) 76 | password = password or "" 77 | local status, data = self:ctrl_exch(self.options.module) 78 | if (not(status)) then 79 | return false, data 80 | end 81 | 82 | local chall 83 | if ( data:match("@RSYNCD: OK") ) then 84 | return true, "No authentication was required" 85 | else 86 | chall = data:match("^@RSYNCD: AUTHREQD (.*)$") 87 | if ( not(chall) and data:match("^@ERROR: Unknown module") ) then 88 | return false, data:match("^@ERROR: (.*)$") 89 | elseif ( not(chall) ) then 90 | return false, "Failed to retrieve challenge" 91 | end 92 | end 93 | 94 | if ( chall and not(username) ) then 95 | return false, "Authentication required" 96 | end 97 | 98 | local md4 = openssl.md4("\0\0\0\0" .. password .. chall) 99 | local resp = base64.enc(md4):sub(1,-3) 100 | status, data = self:ctrl_exch(username .. " " .. resp) 101 | if (not(status)) then 102 | return false, data 103 | end 104 | 105 | if ( data == "@RSYNCD: OK" ) then 106 | return true, "Authentication successful" 107 | end 108 | return false, "Authentication failed" 109 | end, 110 | 111 | -- Lists accessible modules from the rsync server 112 | -- @return status true on success, false on failure 113 | -- @return modules table containing a list of modules 114 | listModules = function(self) 115 | local status, data = self.socket:send("\n") 116 | if (not(status)) then 117 | return false, data 118 | end 119 | 120 | local modules = {} 121 | while(true) do 122 | status, data = self.socket:receive_buf("\n", false) 123 | if (not(status)) then 124 | return false, data 125 | end 126 | if ( data == "@RSYNCD: EXIT" ) then 127 | break 128 | else 129 | table.insert(modules, data) 130 | end 131 | end 132 | return true, modules 133 | end, 134 | 135 | -- Lists the files available for the directory/module 136 | -- TODO: Add support for parsing results, seemed straight forward at 137 | -- first, but wasn't. 138 | listFiles = function(self) 139 | -- list recursively and enable MD4 checksums 140 | local data = ("--server\n--sender\n-rc\n.\n%s\n\n"):format(self.options.module) 141 | local status, data = self.socket:send(data) 142 | if ( not(status) ) then 143 | return false, data 144 | end 145 | status, data = self.socket:receive_bytes(4) 146 | if ( not(status) ) then 147 | return false, data 148 | end 149 | 150 | status, data = self.socket:send("\0\0\0\0") 151 | if ( not(status) ) then 152 | return false, data 153 | end 154 | 155 | status, data = self.socket:receive_buf(match.numbytes(4), false) 156 | if ( not(status) ) then 157 | return false, data 158 | end 159 | 160 | local pos, len = bin.unpack("t contains value, false otherwise. 18 | local function includes(t, value) 19 | for _, elem in ipairs(t) do 20 | if elem == value then 21 | return true 22 | end 23 | end 24 | return false 25 | end 26 | 27 | --- Check if the port and its protocol are in the exclude directive. 28 | -- 29 | -- @param port A port number. 30 | -- @param proto The protocol to match against, default "tcp". 31 | -- @return True if the port and protocol are 32 | -- in the exclude directive. 33 | port_is_excluded = function(port, proto) 34 | proto = proto or "tcp" 35 | return nmap.port_is_excluded(port, proto) 36 | end 37 | 38 | --- Return a portrule that returns true when given an open port matching a 39 | -- single port number or a list of port numbers. 40 | -- @param ports A single port number or a list of port numbers. 41 | -- @param protos The protocol or list of protocols to match against, default 42 | -- "tcp". 43 | -- @param states A state or list of states to match against, default 44 | -- {"open", "open|filtered"}. 45 | -- @return Function for the portrule. 46 | -- @usage portrule = shortport.portnumber({80, 443}) 47 | portnumber = function(ports, protos, states) 48 | protos = protos or "tcp" 49 | states = states or {"open", "open|filtered"} 50 | 51 | if type(ports) ~= "table" then 52 | ports = {ports} 53 | end 54 | if type(protos) ~= "table" then 55 | protos = {protos} 56 | end 57 | if type(states) ~= "table" then 58 | states = {states} 59 | end 60 | 61 | return function(host, port) 62 | return includes(ports, port.number) 63 | and includes(protos, port.protocol) 64 | and includes(states, port.state) 65 | end 66 | end 67 | 68 | --- Return a portrule that returns true when given an open port with a 69 | -- service name matching a single service name or a list of service 70 | -- names. 71 | -- 72 | -- A service name is something like "http", "https", 73 | -- "smtp", or "ftp". These service names are 74 | -- determined by Nmap's version scan or (if no version scan information is 75 | -- available) the service assigned to the port in nmap-services 76 | -- (e.g. "http" for TCP port 80). 77 | -- @param services Service name or a list of names to run against. 78 | -- @param protos The protocol or list of protocols to match against, default 79 | -- "tcp". 80 | -- @param states A state or list of states to match against, default 81 | -- {"open", "open|filtered"}. 82 | -- @return Function for the portrule. 83 | -- @usage portrule = shortport.service("ftp") 84 | service = function(services, protos, states) 85 | protos = protos or "tcp" 86 | states = states or {"open", "open|filtered"} 87 | 88 | if type(services) ~= "table" then 89 | services = {services} 90 | end 91 | if type(protos) ~= "table" then 92 | protos = {protos} 93 | end 94 | if type(states) ~= "table" then 95 | states = {states} 96 | end 97 | 98 | return function(host, port) 99 | return includes(services, port.service) 100 | and includes(protos, port.protocol) 101 | and includes(states, port.state) 102 | end 103 | end 104 | 105 | --- Return a portrule that returns true when given an open port matching 106 | -- either a port number or service name. 107 | -- 108 | -- This function is a combination of the portnumber and 109 | -- service functions. The port and service may be single values or 110 | -- a list of values as in those functions. This function exists because many 111 | -- scripts explicitly try to run against the well-known ports, but want also to 112 | -- run against any other port which was discovered to run the named service. 113 | -- @usage portrule = shortport.port_or_service(22,"ssh"). 114 | -- @param ports A single port number or a list of port numbers. 115 | -- @param services Service name or a list of names to run against. 116 | -- @param protos The protocol or list of protocols to match against, default 117 | -- "tcp". 118 | -- @param states A state or list of states to match against, default 119 | -- {"open", "open|filtered"}. 120 | -- @return Function for the portrule. 121 | port_or_service = function(ports, services, protos, states) 122 | return function(host, port) 123 | local port_checker = portnumber(ports, protos, states) 124 | local service_checker = service(services, protos, states) 125 | return port_checker(host, port) or service_checker(host, port) 126 | end 127 | end 128 | 129 | --- Return a portrule that returns true when given an open port matching 130 | -- either a port number or service name and has not been listed in the 131 | -- exclude port directive of the nmap-service-probes file. If version 132 | -- intensity is lesser than rarity value, portrule always returns false. 133 | -- 134 | -- This function is a combination of the port_is_excluded 135 | -- and port_or_service functions. The port, service, proto may 136 | -- be single values or a list of values as in those functions. 137 | -- This function can be used by version category scripts to check if a 138 | -- given port and its protocol are in the exclude directive and that version 139 | -- intensity is greater than or equal to the rarity value of the script. 140 | -- @usage portrule = shortport.version_port_or_service(22) 141 | -- @usage portrule = shortport.version_port_or_service(nil, "ssh", "tcp") 142 | -- @usage portrule = shortport.version_port_or_service(nil, nil, "tcp", nil, 8) 143 | -- @param services Service name or a list of names to run against. 144 | -- @param protos The protocol or list of protocols to match against, default 145 | -- "tcp". 146 | -- @param states A state or list of states to match against, default 147 | -- {"open", "open|filtered"}. 148 | -- @param rarity A minimum value of version script intensity, below 149 | -- which the function always returns false, default 7. 150 | -- @return Function for the portrule. 151 | version_port_or_service = function(ports, services, protos, states, rarity) 152 | return function(host, port) 153 | local p_s_check = port_or_service(ports, services, protos, states) 154 | return p_s_check(host, port) 155 | and not(port_is_excluded(port.number, port.protocol)) 156 | and (nmap.version_intensity() >= (rarity or 7)) 157 | end 158 | end 159 | 160 | --[[ 161 | Apache Tomcat HTTP server default ports: 8180 and 8000 162 | Litespeed webserver default ports: 8088 and 7080 163 | --]] 164 | LIKELY_HTTP_PORTS = { 165 | 80, 443, 631, 7080, 8080, 8443, 8088, 5800, 3872, 8180, 8000 166 | } 167 | 168 | LIKELY_HTTP_SERVICES = { 169 | "http", "https", "ipp", "http-alt", "https-alt", "vnc-http", "oem-agent", 170 | "soap", "http-proxy", 171 | } 172 | 173 | --- 174 | -- A portrule that matches likely HTTP services. 175 | -- 176 | -- @name http 177 | -- @class function 178 | -- @param host The host table to match against. 179 | -- @param port The port table to match against. 180 | -- @return true if the port is likely to be HTTP, 181 | -- false otherwise. 182 | -- @usage 183 | -- portrule = shortport.http 184 | 185 | http = port_or_service(LIKELY_HTTP_PORTS, LIKELY_HTTP_SERVICES) 186 | 187 | local LIKELY_SSL_PORTS = { 188 | 443, -- https 189 | 465, -- smtps 190 | 636, -- ldapssl 191 | 989, -- ftps-data 192 | 990, -- ftps-control 193 | 992, -- telnets 194 | 993, -- imaps 195 | 994, -- ircs 196 | 995, -- pop3s 197 | 3269, -- globalcatLDAPssl 198 | 3389, -- ms-wbt-server 199 | 5061, -- sip-tls 200 | 6679, 201 | 6697, 202 | 8443, -- https-alt 203 | 9001, -- tor-orport 204 | } 205 | local LIKELY_SSL_SERVICES = { 206 | "ftps", "ftps-data", "ftps-control", "https", "https-alt", "imaps", "ircs", 207 | "ldapssl", "ms-wbt-server", "pop3s", "sip-tls", "smtps", "telnets", "tor-orport", 208 | } 209 | 210 | --- 211 | -- A portrule that matches likely SSL services. 212 | -- 213 | -- @param host The host table to match against. 214 | -- @param port The port table to match against. 215 | -- @return true if the port is likely to be SSL, 216 | -- false otherwise. 217 | -- @usage 218 | -- portrule = shortport.ssl 219 | function ssl(host, port) 220 | return (port.version and port.version.service_tunnel == "ssl") or 221 | port_or_service(LIKELY_SSL_PORTS, LIKELY_SSL_SERVICES, {"tcp", "sctp"})(host, port) 222 | end 223 | 224 | return _ENV; 225 | -------------------------------------------------------------------------------- /tests/nmap/socks.ok.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- A smallish SOCKS version 5 proxy protocol implementation 3 | -- 4 | -- @author "Patrik Karlsson " 5 | -- 6 | 7 | local bin = require "bin" 8 | local match = require "match" 9 | local nmap = require "nmap" 10 | local stdnse = require "stdnse" 11 | local string = require "string" 12 | _ENV = stdnse.module("socks", stdnse.seeall) 13 | 14 | -- SOCKS Authentication methods 15 | AuthMethod = { 16 | NONE = 0, 17 | GSSAPI = 1, 18 | USERPASS = 2, 19 | } 20 | 21 | Request = { 22 | 23 | -- Class that handles the connection request to the server 24 | Connect = { 25 | 26 | -- Creates a new instance of the class 27 | -- @param auth_method table of requested authentication methods 28 | -- @return o instance on success, nil on failure 29 | new = function(self, auth_method) 30 | local o = { 31 | version = 5, 32 | auth_method = ( "table" ~= type(auth_method) and { auth_method } or auth_method ) 33 | } 34 | setmetatable(o, self) 35 | self.__index = self 36 | return o 37 | end, 38 | 39 | -- Converts the instance to string, so that it can be sent to the 40 | -- server. 41 | -- @return string containing the raw request 42 | __tostring = function(self) 43 | local methods = "" 44 | for _, m in ipairs(self.auth_method) do 45 | methods = methods .. string.char(m) 46 | end 47 | return bin.pack("Cp", self.version, methods) 48 | end, 49 | 50 | }, 51 | 52 | -- Class that handles the authentication request to the server 53 | Authenticate = { 54 | 55 | -- Creates a new instance of the class 56 | -- @param auth_method number with the requested authentication method 57 | -- @param creds method specific table of credentials 58 | -- currently only user and pass authentication is supported 59 | -- this method requires two fields to be present 60 | -- username and password 61 | -- @return o instance on success, nil on failure 62 | new = function(self, auth_method, creds) 63 | local o = { 64 | auth_method = auth_method, 65 | creds = creds 66 | } 67 | setmetatable(o, self) 68 | self.__index = self 69 | if ( auth_method == 2 ) then 70 | return o 71 | end 72 | end, 73 | 74 | -- Converts the instance to string, so that it can be sent to the 75 | -- server. 76 | -- @return string containing the raw request 77 | __tostring = function(self) 78 | -- we really don't support anything but 2, but let's pretend that 79 | -- we actually do 80 | if ( 2 == self.auth_method ) then 81 | local version = 1 82 | local username= self.creds.username or "" 83 | local password= self.creds.password or "" 84 | 85 | username = (username == "") and "\0" or username 86 | password = (password == "") and "\0" or password 87 | 88 | return bin.pack("Cpp", version, username, password) 89 | end 90 | end, 91 | 92 | } 93 | 94 | } 95 | 96 | Response = { 97 | 98 | -- Class that handles the connection response 99 | Connect = { 100 | 101 | -- Creates a new instance of the class 102 | -- @param data string containing the data as received over the socket 103 | -- @return o instance on success, nil on failure 104 | new = function(self, data) 105 | local o = { data = data } 106 | setmetatable(o, self) 107 | self.__index = self 108 | if ( o:parse() ) then 109 | return o 110 | end 111 | end, 112 | 113 | -- Parses the received data and populates member variables 114 | -- @return true on success, false on failure 115 | parse = function(self) 116 | if ( #self.data ~= 2 ) then 117 | return 118 | end 119 | local pos 120 | pos, self.version, self.method = bin.unpack("CC", self.data) 121 | return true 122 | end 123 | 124 | }, 125 | 126 | -- Class that handles the authentication response 127 | Authenticate = { 128 | 129 | Status = { 130 | SUCCESS = 0, 131 | -- could be anything but zero 132 | FAIL = 1, 133 | }, 134 | 135 | -- Creates a new instance of the class 136 | -- @param data string containing the data as received over the socket 137 | -- @return o instance on success, nil on failure 138 | new = function(self, data) 139 | local o = { data = data } 140 | setmetatable(o, self) 141 | self.__index = self 142 | if ( o:parse() ) then 143 | return o 144 | end 145 | end, 146 | 147 | -- Parses the received data and populates member variables 148 | -- @return true on success, false on failure 149 | parse = function(self) 150 | if ( #self.data ~= 2 ) then 151 | return 152 | end 153 | local pos 154 | pos, self.version, self.status = bin.unpack("CC", self.data) 155 | return true 156 | end, 157 | 158 | -- checks if the authentication was successful or not 159 | -- @return true on success, false on failure 160 | isSuccess = function(self) 161 | return ( self.status == self.Status.SUCCESS ) 162 | end, 163 | 164 | } 165 | 166 | } 167 | 168 | -- The main script interface 169 | Helper = { 170 | 171 | -- Create a new instance of the class 172 | -- @param host table containing the host table 173 | -- @param port table containing the port table 174 | -- @param options table containing library options, currently: 175 | -- timeout - socket timeout in ms 176 | -- @return o instance of Helper 177 | new = function(self, host, port, options) 178 | options = options or {} 179 | local o = { host = host, port = port, options = options } 180 | setmetatable(o, self) 181 | self.__index = self 182 | return o 183 | end, 184 | 185 | -- Get the authentication method name by number 186 | -- @param method number containing the authentication method 187 | -- @return string containing the method name or Unknown 188 | authNameByNumber = function(self, method) 189 | local methods = { 190 | [0] = "No authentication", 191 | [1] = "GSSAPI", 192 | [2] = "Username and password", 193 | } 194 | return methods[method] or ("Unknown method (%d)"):format(method) 195 | end, 196 | 197 | -- Connects to the SOCKS server 198 | -- @param auth_method table containing the auth. methods to request 199 | -- @return status true on success, false on failure 200 | -- @return response table containing the response or err string on failure 201 | connect = function(self, auth_method) 202 | self.socket = nmap.new_socket() 203 | self.socket:set_timeout(self.options.timeout or 10000) 204 | local status, err = self.socket:connect(self.host, self.port) 205 | if ( not(status) ) then 206 | return status, err 207 | end 208 | 209 | auth_method = auth_method or {AuthMethod.NONE, AuthMethod.GSSAPI, AuthMethod.USERPASS} 210 | status = self.socket:send( tostring(Request.Connect:new(auth_method)) ) 211 | if ( not(status) ) then 212 | self.socket:close() 213 | return false, "Failed to send connection request to server" 214 | end 215 | 216 | local status, data = self.socket:receive_buf(match.numbytes(2), true) 217 | if ( not(status) ) then 218 | self.socket:close() 219 | return false, "Failed to receive connection response from server" 220 | end 221 | 222 | local response = Response.Connect:new(data) 223 | if ( not(response) ) then 224 | return false, "Failed to parse response from server" 225 | end 226 | 227 | if ( response.version ~= 5 ) then 228 | return false, ("Unsupported SOCKS version (%d)"):format(response.version) 229 | end 230 | if ( response.method == 0xFF ) then 231 | return false, "No acceptable authentication methods" 232 | end 233 | 234 | -- store the method so authenticate knows what to use 235 | self.auth_method = response.method 236 | return true, response 237 | end, 238 | 239 | -- Authenticates to the SOCKS server 240 | -- @param creds table containing authentication method specific fields 241 | -- currently only authentication method 2 (username and pass) is 242 | -- implemented. That method requires the following fields: 243 | -- username - containing the username 244 | -- password - containing the password 245 | -- @return status true on success, false on failure 246 | -- @return err string containing the error message 247 | authenticate = function(self, creds) 248 | if ( self.auth_method ~= 2 ) then 249 | return false, "Authentication method not supported" 250 | end 251 | local req = Request.Authenticate:new(self.auth_method, creds) 252 | if ( not(req) ) then 253 | return false, "Failed to create authentication request" 254 | end 255 | 256 | local status = self.socket:send(tostring(req)) 257 | if ( not(status) ) then 258 | return false, "Failed to send authentication request" 259 | end 260 | 261 | if ( 2 == self.auth_method ) then 262 | local status, data = self.socket:receive_buf(match.numbytes(2), true) 263 | local auth = Response.Authenticate:new(data) 264 | 265 | if ( not(auth) ) then 266 | return false, "Failed to parse authentication response" 267 | end 268 | 269 | if ( auth:isSuccess() ) then 270 | return true, "Authentication was successful" 271 | else 272 | return false, "Authentication failed" 273 | end 274 | 275 | end 276 | return false, "Unsupported authentication method" 277 | end, 278 | 279 | -- closes the connection to the server 280 | close = function(self) 281 | return self.socket:close() 282 | end, 283 | 284 | } 285 | 286 | return _ENV; 287 | -------------------------------------------------------------------------------- /tests/nmap/strbuf.ok.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- String buffer facilities. 3 | -- 4 | -- Lua's string operations are very flexible and offer an easy-to-use way to 5 | -- manipulate strings. Concatenation using the .. operator is such 6 | -- an operation. The drawback of the built-in API however is the way it handles 7 | -- concatenation of many string values. Since strings in Lua are immutable 8 | -- values, each time you concatenate two strings both get copied into the 9 | -- result string. 10 | -- 11 | -- The strbuf module offers a workaround for this problem, while 12 | -- maintaining the nice syntax. This is accomplished by overloading the 13 | -- concatenation operator (..), the equality operator (==) and the tostring 14 | -- operator. A string buffer is created by passing a string to 15 | -- strbuf.new. Afterwards you can append to the string buffer, 16 | -- or compare two string buffers for equality just as you would do with normal 17 | -- strings. 18 | -- 19 | -- When looking at the details there are some more restrictions/oddities: The 20 | -- concatenation operator requires its left-hand value to be a string buffer. 21 | -- Therefore, if you want to prepend a string to a given string buffer you have 22 | -- to create a new string buffer out of the string you want to prepend. The 23 | -- string buffer's tostring operator concatenates the strings 24 | -- inside the buffer using newlines by default, since this appears to be the 25 | -- separator used most often. 26 | -- 27 | -- Example usage: 28 | -- 29 | -- local buf = strbuf.new() 30 | -- local buf2 = strbuf.new('hello') 31 | -- buf = buf .. 'string' 32 | -- buf = buf .. 'data' 33 | -- print(buf) -- default separator is a newline 34 | -- print(strbuf.dump(buf)) -- no separator 35 | -- print(strbuf.dump(buf, ' ')) -- separated by spaces 36 | -- strbuf.clear(buf) 37 | -- 38 | -- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html 39 | 40 | -- DEPENDENCIES -- 41 | 42 | local stdnse = require "stdnse" 43 | local table = require "table" 44 | local getmetatable = getmetatable; 45 | local setmetatable = setmetatable; 46 | local type = type; 47 | local error = error; 48 | local ipairs = ipairs; 49 | local pairs = pairs; 50 | local concat = table.concat; 51 | 52 | _ENV = stdnse.module("strbuf", stdnse.seeall) 53 | 54 | -- String buffer functions. Concatenation is not efficient in 55 | -- lua as strings are immutable. If a large amount of '..' sequential 56 | -- operations are needed a string buffer should be used instead 57 | -- e.g. for i = 1, 10 do s = s..i end 58 | 59 | --- Dumps the string buffer as a string. 60 | -- 61 | -- The second parameter is used as a delimiter between the strings stored inside 62 | -- the string buffer. 63 | -- @name dump 64 | -- @class function 65 | -- @param sbuf String buffer to dump. 66 | -- @param delimiter String to separate the buffer's contents. 67 | -- @return Concatenated string result. 68 | dump = concat; 69 | 70 | --- Appends a string to a string buffer. 71 | -- @param sbuf String buffer. 72 | -- @param s String to append. 73 | -- @return sbuf. 74 | function concatbuf(sbuf, s) 75 | if type(s) == "string" then 76 | sbuf[#sbuf+1] = s; 77 | elseif getmetatable(s) == getmetatable(sbuf) then 78 | for _,v in ipairs(s) do 79 | sbuf[#sbuf+1] = v; 80 | end 81 | else 82 | error("bad #2 operand to strbuf concat operation", 2); 83 | end 84 | return sbuf; 85 | end 86 | 87 | --- Determines if the two string buffers are equal. Two buffers are equal 88 | -- if they are the same or if they have equivalent contents. 89 | -- @param sbuf1 String buffer one. 90 | -- @param sbuf2 String buffer two. 91 | -- @return True if equal, false otherwise. 92 | function eqbuf(sbuf1, sbuf2) 93 | if getmetatable(sbuf1) ~= getmetatable(sbuf2) then 94 | error("one or more operands is not a string buffer", 2); 95 | elseif #sbuf1 ~= #sbuf2 then 96 | return false; 97 | else 98 | for i = 1, #sbuf1 do 99 | if sbuf1[i] ~= sbuf2[i] then 100 | return false; 101 | end 102 | end 103 | return true; 104 | end 105 | end 106 | 107 | --- Clears a string buffer. 108 | -- @param sbuf String buffer. 109 | function clear(sbuf) 110 | for k in pairs(sbuf) do 111 | sbuf[k] = nil; 112 | end 113 | end 114 | 115 | --- Returns the string buffer as a string. The delimiter used is a newline. 116 | -- @param sbuf String buffer. 117 | -- @return String made from concatenating the buffer. 118 | function tostring(sbuf) 119 | return concat(sbuf, "\n"); 120 | end 121 | 122 | local mt = { 123 | __concat = concatbuf, 124 | __tostring = tostring, 125 | __eq = eqbuf, 126 | __index = _M, 127 | }; 128 | 129 | --- Create a new string buffer. 130 | -- 131 | -- The optional arguments are added to the string buffer. The result of adding 132 | -- non-strings is undefined. The equals and tostring 133 | -- operators for string buffers are overloaded to be eqbuf and 134 | -- tostring respectively. 135 | -- @param ... Strings to add to the buffer initially. 136 | -- @return String buffer. 137 | function new(...) 138 | return setmetatable({...}, mt); 139 | end 140 | 141 | return _ENV; 142 | -------------------------------------------------------------------------------- /tests/nmap/strict.ok.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- Strict declared global library. Checks for undeclared global variables 3 | -- during runtime execution. 4 | -- 5 | -- This module places the strict function in the global 6 | -- environment. The strict function allows a script to add runtime checking so 7 | -- that undeclared globals cause an error to be raised. This is useful for 8 | -- finding accidental use of globals when local was intended. 9 | -- 10 | -- A global variable is considered "declared" if the script makes an assignment 11 | -- to the global name (even nil) in the file scope. 12 | -- 13 | -- @class module 14 | -- @name strict 15 | -- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html 16 | 17 | local debug = require "debug" 18 | 19 | local error = error; 20 | local getmetatable = getmetatable; 21 | local rawset = rawset; 22 | local rawget = rawget; 23 | local setmetatable = setmetatable; 24 | local type = type; 25 | 26 | local getinfo = debug.getinfo; 27 | 28 | _ENV = {}; 29 | 30 | local function what () 31 | local d = getinfo(3, "S"); 32 | return d and d.what or "C"; 33 | end 34 | 35 | --- The strict function. 36 | -- 37 | -- This function adds runtime checking to the global environment for use of 38 | -- undeclared globals. A global is 'undeclared' if not assigned in the file 39 | -- (script) scope previously. An error will be raised on use of an undeclared 40 | -- global. 41 | -- 42 | -- This function should be passed last to stdnse.module in order to allow 43 | -- other environment option functions (e.g. stdnse.seeall) to change the 44 | -- environment first. This is important for allowing globals outside the 45 | -- library (in _G) to be indexed. 46 | -- 47 | -- @see stdnse.module 48 | -- @usage 49 | -- _ENV = stdnse.module(name, require "strict"); 50 | -- @param env The environment to modify. 51 | local function strict (env) 52 | local mt = getmetatable(env) or setmetatable(env, {}) and getmetatable(env); 53 | local _newindex, _index = mt.__newindex, mt.__index; 54 | 55 | mt.__declared = {}; 56 | 57 | function mt.__newindex (t, n, v) 58 | if type(_newindex) == "function" then 59 | _newindex(t, n, v); -- hook it 60 | end 61 | if not mt.__declared[n] then 62 | local w = what(); 63 | if w ~= "main" and w ~= "C" then 64 | error("assign to undeclared variable '"..n.."'", 2); 65 | end 66 | mt.__declared[n] = true; 67 | end 68 | rawset(t, n, v); 69 | end 70 | 71 | function mt.__index (t, n) 72 | if type(_index) == "function" then 73 | local v = _index(t, n); -- hook it 74 | if v ~= nil then return v end 75 | elseif _index ~= nil then 76 | local v = _index[n]; 77 | if v ~= nil then return v end 78 | end 79 | if not mt.__declared[n] and what() ~= "C" then 80 | error("variable '"..n.."' is not declared", 2); 81 | end 82 | return rawget(t, n); 83 | end 84 | 85 | return env; 86 | end 87 | 88 | return strict; 89 | -------------------------------------------------------------------------------- /tests/nmap/tab.ok.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- Arrange output into tables. 3 | -- 4 | -- This module provides NSE scripts with a way to output structured tables 5 | -- similar to what NmapOutputTable.cc provides. 6 | -- 7 | -- Example usage: 8 | -- 9 | -- local t = tab.new() 10 | -- tab.add(t, 1, 'A1') 11 | -- tab.add(t, 2, 'A2') 12 | -- tab.nextrow(t) 13 | -- tab.add(t, 1, 'BBBBBBBBB1') 14 | -- tab.add(t, 2, 'BBB2') 15 | -- tab.nextrow(t) 16 | -- tab.addrow(t, 'C1', 'C2') 17 | -- tab.dump(t) 18 | -- 19 | -- 20 | -- tab.add works on the bottom-most row until 21 | -- tab.nextrow is called. Think of tab.nextrow as 22 | -- typing Enter at the end of a line. tab.addrow adds a whole row 23 | -- at a time and calls tab.nextrow automatically. 24 | -- 25 | -- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html 26 | 27 | local stdnse = require "stdnse" 28 | local strbuf = require "strbuf" 29 | local string = require "string" 30 | local table = require "table" 31 | _ENV = stdnse.module("tab", stdnse.seeall) 32 | 33 | --- Create and return a new table. 34 | -- @return A new table. 35 | function new() 36 | local t = {} 37 | 38 | t.current_row = 1 39 | setmetatable(t, {__tostring=dump}) 40 | return t 41 | end 42 | 43 | --- Add a new string item to a table at a given column position. 44 | -- 45 | -- The item will be added to the current row. If nextrow hasn't 46 | -- been called yet that will be row 1. 47 | -- @param t The table. 48 | -- @param v The string to add. 49 | -- @param c The column position at which to add the item. 50 | function add(t, c, v) 51 | assert(t) 52 | assert(type(v) == "string") 53 | 54 | -- add a new row if one doesn't exist 55 | t[t.current_row] = t[t.current_row] or {} 56 | 57 | t[t.current_row][c] = v 58 | return true 59 | end 60 | 61 | --- Add a complete row to the table and move on to the next row. 62 | -- 63 | -- Calls add for each argument starting with the second argument 64 | -- and after that calls nextrow. 65 | -- @param t The table. 66 | -- @param ... The elements to add to the row. 67 | function addrow(t, ...) 68 | for i = 1, select("#", ...) do 69 | add(t, i, tostring((select(i, ...)))) 70 | end 71 | nextrow(t) 72 | end 73 | 74 | --- Move on to the next row in the table. 75 | -- 76 | -- If this is not called then previous column values will be over-written by 77 | -- subsequent values. 78 | -- @param t The table. 79 | function nextrow(t) 80 | assert(t) 81 | assert(t.current_row) 82 | t[t.current_row] = t[t.current_row] or {} 83 | t.current_row = t.current_row + 1 84 | end 85 | 86 | --- Return a formatted string representation of the table. 87 | -- 88 | -- The number of spaces in a column is based on the largest element in the 89 | -- column with an additional two spaces for padding. 90 | -- @param t The table. 91 | function dump(t) 92 | assert(t) 93 | 94 | local column_width = {} 95 | local num_columns = {} 96 | local buf = strbuf.new() 97 | 98 | -- find widest element in each column 99 | for i, row in ipairs(t) do 100 | num_columns[i] = 0 101 | for x, elem in pairs(row) do 102 | local elem_width = #elem 103 | if not column_width[x] or elem_width > column_width[x] then 104 | column_width[x] = elem_width 105 | end 106 | if x > num_columns[i] then 107 | num_columns[i] = x 108 | end 109 | end 110 | end 111 | 112 | -- build buf with padding so all column elements line up 113 | for i, row in ipairs(t) do 114 | local text_row = {} 115 | for x = 1, num_columns[i] do 116 | local elem = row[x] or "" 117 | if x < num_columns[i] then 118 | text_row[#text_row + 1] = elem .. string.rep(" ", column_width[x] - #elem) 119 | else 120 | text_row[#text_row + 1] = elem 121 | end 122 | end 123 | buf = buf .. table.concat(text_row, " ") .. "\n" 124 | end 125 | 126 | return strbuf.dump(buf) 127 | end 128 | 129 | return _ENV; 130 | -------------------------------------------------------------------------------- /tests/nmap/target.ok.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- Utility functions to add new discovered targets to Nmap scan queue. 3 | -- 4 | -- The library lets scripts to add new discovered targets to Nmap scan 5 | -- queue. Only scripts that run in the script pre-scanning phase 6 | -- (prerule) and the script scanning phase (hostrule and portrule) are 7 | -- able to add new targets. Post-scanning scripts (postrule) are not 8 | -- allowed to add new targets. 9 | -- 10 | -- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html 11 | -- 12 | -- @args newtargets If specified, lets NSE scripts add new targets. 13 | -- @args max-newtargets Sets the number of the maximum allowed 14 | -- new targets. If set to 0 or less then there 15 | -- is no limit. The default value is 0. 16 | 17 | local nmap = require "nmap" 18 | local stdnse = require "stdnse" 19 | local table = require "table" 20 | local type = type 21 | local select = select 22 | local tonumber = tonumber 23 | 24 | _ENV = stdnse.module("target", stdnse.seeall) 25 | 26 | 27 | -- This is a special variable and it is a global one, so 28 | -- scripts can check it to see if adding targets is allowed, 29 | -- before calling target.add() function. 30 | -- This variable will be set to true if the script argument 31 | -- 'newtargets' was specified. 32 | ALLOW_NEW_TARGETS = false 33 | 34 | local newtargets, max_newtargets = stdnse.get_script_args("newtargets", 35 | "max-newtargets") 36 | if newtargets then 37 | ALLOW_NEW_TARGETS = true 38 | end 39 | 40 | if max_newtargets then 41 | max_newtargets = tonumber(max_newtargets) 42 | else 43 | max_newtargets = 0 44 | end 45 | 46 | --- Local function to calculate max allowed new targets 47 | local calc_max_targets = function(targets) 48 | if max_newtargets > 0 then 49 | local pushed_targets = nmap.new_targets_num() 50 | if pushed_targets >= max_newtargets then 51 | return 0 52 | elseif (targets + pushed_targets) > max_newtargets then 53 | return (max_newtargets - pushed_targets) 54 | end 55 | end 56 | return targets 57 | end 58 | 59 | --- Adds the passed arguments to the Nmap scan queue. 60 | -- 61 | -- Only prerule, portrule and hostrule scripts can add new targets. 62 | -- 63 | -- @param targets A variable number of targets. Target is a 64 | -- string that represents an IP or a Hostname. If this function 65 | -- is called without target arguments then it will return true 66 | -- and the number of pending targets (waiting to be scanned). 67 | -- @usage 68 | -- local status, err = target.add("192.168.1.1") 69 | -- local status, err = target.add("192.168.1.1","192.168.1.2",...) 70 | -- local status, err = target.add("scanme.nmap.org","192.168.1.1",...) 71 | -- local status, err = target.add(table.unpack(array_of_targets)) 72 | -- local status, pending_targets = target.add() 73 | -- @return True if it has been able to add a minimum one target, or 74 | -- False on failures and if no targets were added. If this 75 | -- function is called without target arguments then it will 76 | -- return true. 77 | -- @return Number of added targets on success, or a string error 78 | -- message in case of failures. If this function is called 79 | -- without target arguments then it will return the number 80 | -- of targets that are in the queue (waiting to be scanned). 81 | add = function (...) 82 | -- Force the check here, but it would be better if scripts 83 | -- check ALLOW_NEW_TARGETS before calling target.add() 84 | if not ALLOW_NEW_TARGETS then 85 | stdnse.debug1( 86 | "ERROR: to add targets run with --script-args 'newtargets'") 87 | return false, "to add targets run with --script-args 'newtargets'" 88 | end 89 | 90 | local new_targets = {count = select("#", ...), ...} 91 | 92 | -- function called without arguments 93 | if new_targets.count == 0 then 94 | return true, nmap.add_targets() 95 | end 96 | 97 | new_targets.count = calc_max_targets(new_targets.count) 98 | 99 | if new_targets.count == 0 then 100 | stdnse.debug3( 101 | "Warning: Maximum new targets reached, no more new targets.") 102 | return false, "Maximum new targets reached, no more new targets." 103 | end 104 | 105 | local hosts, err = nmap.add_targets(table.unpack(new_targets,1,new_targets.count)) 106 | 107 | if hosts == 0 then 108 | stdnse.debug3("%s", err) 109 | return false, err 110 | end 111 | 112 | return true, hosts 113 | end 114 | 115 | return _ENV; 116 | -------------------------------------------------------------------------------- /tests/nmap/versant.ok.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- A tiny library allowing some basic information enumeration from 3 | -- Versant object database software (see 4 | -- http://en.wikipedia.org/wiki/Versant_Corporation). The code is 5 | -- entirely based on packet dumps captured when using the Versant 6 | -- Management Center administration application. 7 | -- 8 | -- @author "Patrik Karlsson " 9 | -- 10 | 11 | local stdnse = require "stdnse" 12 | local bin = require "bin" 13 | local match = require "match" 14 | local nmap = require "nmap" 15 | local string = require "string" 16 | local table = require "table" 17 | _ENV = stdnse.module("versant", stdnse.seeall) 18 | 19 | Versant = { 20 | 21 | -- fallback to these constants when version and user are not given 22 | USER = "nmap", 23 | VERSION = "8.0.2", 24 | 25 | -- Creates an instance of the Versant class 26 | -- @param host table 27 | -- @param port table 28 | -- @return o new instance of Versant 29 | new = function(self, host, port) 30 | local o = { host = host, port = port, socket = nmap.new_socket() } 31 | setmetatable(o, self) 32 | self.__index = self 33 | return o 34 | end, 35 | 36 | -- Connects a socket to the Versant server 37 | -- @return status true on success, false on failure 38 | -- @return err string containing the error message if status is false 39 | connect = function(self) 40 | return self.socket:connect(self.host, self.port) 41 | end, 42 | 43 | -- Closes the socket 44 | -- @return status true on success, false on failure 45 | -- @return err string containing the error message if status is false 46 | close = function(self) 47 | return self.socket:close() 48 | end, 49 | 50 | -- Sends command to the server 51 | -- @param cmd string containing the command to run 52 | -- @param arg string containing any arguments 53 | -- @param user [optional] string containing the user name 54 | -- @param ver [optional] string containing the version number 55 | -- @return status true on success, false on failure 56 | -- @return data opaque string containing the response 57 | sendCommand = function(self, cmd, arg, user, ver) 58 | 59 | user = user or Versant.USER 60 | ver = ver or Versant.VERSION 61 | arg = arg or "" 62 | 63 | local data = bin.pack("Hzzz", 64 | "000100000000000000020002000000010000000000000000000000000000000000010000", 65 | cmd, 66 | user, 67 | ver 68 | ) 69 | -- align to even 4 bytes 70 | data = data .. string.rep("\0", 4 - ((#data % 4) or 0)) 71 | 72 | data = data .. bin.pack("Hzxxxxxxxxxxz", 73 | "0000000b000001000000000000000000", 74 | ("%s:%d"):format(self.host.ip, self.port.number), 75 | arg 76 | ) 77 | 78 | data = data .. string.rep("\0", 2048 - #data) 79 | 80 | local status, err = self.socket:send(data) 81 | if ( not(status) ) then 82 | return false, "Failed to send request to server" 83 | end 84 | 85 | local status, data = self.socket:receive_buf(match.numbytes(2048), true) 86 | if ( not(status) ) then 87 | return false, "Failed to read response from server" 88 | end 89 | 90 | return status, data 91 | end, 92 | 93 | -- Get database node information 94 | -- @return status true on success, false on failure 95 | -- @return result table containing an entry for each database. Each entry 96 | -- contains a table with the following fields: 97 | -- name - the database name 98 | -- owner - the database owner 99 | -- created - the date when the database was created 100 | -- version - the database version 101 | getNodeInfo = function(self) 102 | local status, data = self:sendCommand("o_getnodeinfo", "-nodeinfo") 103 | if ( not(status) ) then 104 | return false, data 105 | end 106 | 107 | status, data = self.socket:receive_buf(match.numbytes(4), true) 108 | if ( not(status) ) then 109 | return false, "Failed to read response from server" 110 | end 111 | 112 | local _, db_count = bin.unpack(">I", data) 113 | if ( db_count == 0 ) then 114 | return false, "Database count was zero" 115 | end 116 | 117 | status, data = self.socket:receive_buf(match.numbytes(4), true) 118 | if ( not(status) ) then 119 | return false, "Failed to read response from server" 120 | end 121 | 122 | local _, buf_size = bin.unpack(">I", data) 123 | local dbs = {} 124 | 125 | for i=1, db_count do 126 | status, data = self.socket:receive_buf(match.numbytes(buf_size), true) 127 | local _, db = nil, {} 128 | 129 | _, db.name = bin.unpack("z", data, 23) 130 | _, db.owner = bin.unpack("z", data, 599) 131 | _, db.created= bin.unpack("z", data, 631) 132 | _, db.version= bin.unpack("z", data, 663) 133 | 134 | -- remove trailing line-feed 135 | db.created = db.created:match("^(.-)\n*$") 136 | 137 | table.insert(dbs, db) 138 | end 139 | return true, dbs 140 | end, 141 | 142 | -- Gets the database OBE port, this port is dynamically allocated once this 143 | -- command completes. 144 | -- 145 | -- @return status true on success, false on failure 146 | -- @return port table containing the OBE port 147 | getObePort = function(self) 148 | 149 | local status, data = self:sendCommand("o_oscp", "-utility") 150 | if ( not(status) ) then 151 | return false, data 152 | end 153 | 154 | status, data = self.socket:receive_buf(match.numbytes(256), true) 155 | if ( not(status) ) then 156 | return false, "Failed to read response from server" 157 | end 158 | 159 | local pos, success = bin.unpack(">I", data) 160 | if ( success ~= 0 ) then 161 | return false, "Response contained invalid data" 162 | end 163 | 164 | local port = { protocol = "tcp" } 165 | pos, port.number = bin.unpack(">S", data, pos) 166 | 167 | return true, port 168 | end, 169 | 170 | 171 | -- Gets the XML license file from the database 172 | -- @return status true on success, false on failure 173 | -- @return data string containing the XML license file 174 | getLicense = function(self) 175 | 176 | local status, data = self:sendCommand("o_licfile", "-license") 177 | if ( not(status) ) then 178 | return false, data 179 | end 180 | 181 | status, data = self.socket:receive_buf(match.numbytes(4), true) 182 | if ( not(status) ) then 183 | return false, "Failed to read response from server" 184 | end 185 | 186 | local _, len = bin.unpack(">I", data) 187 | if ( len == 0 ) then 188 | return false, "Failed to retrieve license file" 189 | end 190 | 191 | status, data = self.socket:receive_buf(match.numbytes(len), true) 192 | if ( not(status) ) then 193 | return false, "Failed to read response from server" 194 | end 195 | 196 | return true, data 197 | end, 198 | 199 | -- Gets the TCP port for a given database 200 | -- @param db string containing the database name 201 | -- @return status true on success, false on failure 202 | -- @return port table containing the database port 203 | getDbPort = function(self, db) 204 | local status, data = self:sendCommand(db, "") 205 | if ( not(status) ) then 206 | return false, data 207 | end 208 | 209 | if ( not(status) ) then 210 | return false, "Failed to connect to database" 211 | end 212 | 213 | local _, port = nil, { protocol = "tcp" } 214 | _, port.number = bin.unpack(">I", data, 27) 215 | if ( port == 0 ) then 216 | return false, "Failed to determine database port" 217 | end 218 | return true, port 219 | end, 220 | } 221 | 222 | Versant.OBE = { 223 | 224 | -- Creates a new versant OBE instance 225 | -- @param host table 226 | -- @param port table 227 | -- @return o new instance of Versant OBE 228 | new = function(self, host, port) 229 | local o = { host = host, port = port, socket = nmap.new_socket() } 230 | setmetatable(o, self) 231 | self.__index = self 232 | return o 233 | end, 234 | 235 | -- Connects a socket to the Versant server 236 | -- @return status true on success, false on failure 237 | -- @return err string containing the error message if status is false 238 | connect = function(self) 239 | return self.socket:connect(self.host, self.port) 240 | end, 241 | 242 | -- Closes the socket 243 | -- @return status true on success, false on failure 244 | -- @return err string containing the error message if status is false 245 | close = function(self) 246 | return self.socket:close() 247 | end, 248 | 249 | -- Get database information including file paths and hostname 250 | -- @return status true on success false on failure 251 | -- @return result table containing the fields: 252 | -- root_path - the database root directory 253 | -- db_path - the database directory 254 | -- lib_path - the library directory 255 | -- hostname - the database host name 256 | getVODInfo = function(self) 257 | local data = bin.pack("Hz", 258 | "1002005d00000000000100000000000d000000000000000000000000", --28 259 | "-noprint -i " --12 + 1 (for null) 260 | ) .. string.rep("\0", 215) -- 256 - (28 + 12 + 1) 261 | 262 | self.socket:send(data) 263 | local status, data = self.socket:receive_buf(match.numbytes(256), true) 264 | if ( not(status) ) then 265 | return false, "Failed to read response from server" 266 | end 267 | 268 | local pos, len = bin.unpack(">I", data, 13) 269 | status, data = self.socket:receive_buf(match.numbytes(len), true) 270 | if ( not(status) ) then 271 | return false, "Failed to read response from server" 272 | end 273 | 274 | local result, pos, offset = {}, 1, 13 275 | pos, result.version = bin.unpack("z", data) 276 | 277 | for _, item in ipairs({"root_path", "db_path", "lib_path", "hostname"}) do 278 | pos, result[item] = bin.unpack("z", data, offset) 279 | offset = offset + 256 280 | end 281 | return true, result 282 | end, 283 | } 284 | 285 | return _ENV; 286 | -------------------------------------------------------------------------------- /tests/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | GREEN="\e[0;32m" 4 | RED="\e[0;31m" 5 | NORM="\e[0m " 6 | 7 | pass() 8 | { 9 | echo -ne "$GREEN" 10 | echo -ne "PASS$NORM" 11 | echo "$@" 12 | } 13 | 14 | fail() 15 | { 16 | echo -ne "$RED" 17 | echo -ne "FAIL$NORM" 18 | echo "$@" 19 | } 20 | 21 | VIM="vim -u NONE -U NONE -i NONE" 22 | LOG="results.diff" 23 | 24 | do_tests() 25 | { 26 | DIRECTORY=$1 27 | REMOVE_INDENT=$2 28 | 29 | for f in $DIRECTORY*.ok.lua; do 30 | basename="${f%.ok.lua}" 31 | INPUT="$basename.in.lua" 32 | OUTPUT="$basename.OUT.lua" 33 | COMP="$basename.ok.lua" 34 | 35 | if [[ $REMOVE_INDENT -eq 0 ]]; then 36 | $VIM -c "write! $INPUT" -c "qa!" "$COMP" 37 | else 38 | $VIM -c "normal ggVG420<<" -c "write! $INPUT" -c "qa!" "$COMP" 39 | fi 40 | if [[ -n $3 ]]; then 41 | $VIM \ 42 | -c "set nocompatible lazyredraw" \ 43 | -c "edit $INPUT" \ 44 | -c "syntax on" \ 45 | -c "source ../after/indent/lua.vim" \ 46 | -c "set sw=$3 sts=$3 ts=$3 expandtab" \ 47 | -c "normal ggVG=" \ 48 | -c "write! $OUTPUT" \ 49 | -c "qa!" 50 | else 51 | $VIM \ 52 | -c "set nocompatible lazyredraw" \ 53 | -c "edit $INPUT" \ 54 | -c "syntax on" \ 55 | -c "source ../after/indent/lua.vim" \ 56 | -c "normal ggVG=" \ 57 | -c "write! $OUTPUT" \ 58 | -c "qa!" 59 | fi 60 | if diff "$COMP" "$OUTPUT" &>/dev/null ; then 61 | pass $basename 62 | else 63 | fail $basename 64 | echo "--------------------------------------------------------------------------------" >> $LOG 65 | echo "$OUTPUT" >> $LOG 66 | echo "$COMP" >> $LOG 67 | diff -rupN $COMP $OUTPUT >> $LOG 68 | if [[ -z $4 ]]; then 69 | exit 1 70 | fi 71 | fi 72 | done 73 | } 74 | 75 | echo "" > $LOG 76 | 77 | do_tests "basic/" 1 78 | do_tests "basic_passthrough/" 0 79 | do_tests "tsukuyomi/" 0 80 | 81 | # problematics ones which are clearly wrong 82 | # do_tests "nmap/stdnse" 0 2 83 | # do_tests "nmap/anyconnect" 0 2 84 | 85 | do_tests "nmap/*" 0 2 1 86 | -------------------------------------------------------------------------------- /tests/tsukuyomi/tsukuyomi_004.OUT.lua: -------------------------------------------------------------------------------- 1 | -- vim: et sw=2 sts=2 ts=2 2 | local tsukuyomi = tsukuyomi 3 | local tsukuyomi_core = tsukuyomi.core 4 | local PushbackReader = tsukuyomi.lang.PushbackReader 5 | local Compiler = tsukuyomi.lang.Namespace.GetNamespaceSpace('tsukuyomi.lang.Compiler') 6 | local PersistentList = tsukuyomi.lang.PersistentList 7 | local Symbol = tsukuyomi.lang.Symbol 8 | 9 | tsukuyomi_core['eval'] = tsukuyomi.lang.Function.new() 10 | tsukuyomi_core['eval'][1] = function (form) 11 | assert(false) 12 | end 13 | 14 | local def_symbol = Symbol.intern('def') 15 | 16 | local function describe(datum) 17 | local info 18 | if type(datum) == 'table' and datum.first then 19 | if datum:first() == def_symbol then 20 | local symbol = datum:rest():first() 21 | symbol = tsukuyomi.core['*ns*']:bind_symbol(symbol) 22 | info = tostring(symbol) 23 | end 24 | end 25 | return info 26 | end 27 | 28 | tsukuyomi_core['load-file'] = tsukuyomi.lang.Function.new() 29 | tsukuyomi_core['load-file'][1] = function (name) 30 | local f = io.open(name) 31 | local text = f:read('*all') 32 | f:close() 33 | local r = PushbackReader.new(text, name) 34 | 35 | local datum = tsukuyomi_core.read[1](r) 36 | while datum do 37 | local lua_code = Compiler.compile(datum) 38 | local chunk, err = loadstring(lua_code, describe(datum)) 39 | if err then 40 | io.stderr:write(err) 41 | io.stderr:write('\n') 42 | assert(false) 43 | else 44 | chunk() 45 | end 46 | 47 | datum = tsukuyomi_core.read[1](r) 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /tests/tsukuyomi/tsukuyomi_004.in.lua: -------------------------------------------------------------------------------- 1 | -- vim: et sw=2 sts=2 ts=2 2 | local tsukuyomi = tsukuyomi 3 | local tsukuyomi_core = tsukuyomi.core 4 | local PushbackReader = tsukuyomi.lang.PushbackReader 5 | local Compiler = tsukuyomi.lang.Namespace.GetNamespaceSpace('tsukuyomi.lang.Compiler') 6 | local PersistentList = tsukuyomi.lang.PersistentList 7 | local Symbol = tsukuyomi.lang.Symbol 8 | 9 | tsukuyomi_core['eval'] = tsukuyomi.lang.Function.new() 10 | tsukuyomi_core['eval'][1] = function (form) 11 | assert(false) 12 | end 13 | 14 | local def_symbol = Symbol.intern('def') 15 | 16 | local function describe(datum) 17 | local info 18 | if type(datum) == 'table' and datum.first then 19 | if datum:first() == def_symbol then 20 | local symbol = datum:rest():first() 21 | symbol = tsukuyomi.core['*ns*']:bind_symbol(symbol) 22 | info = tostring(symbol) 23 | end 24 | end 25 | return info 26 | end 27 | 28 | tsukuyomi_core['load-file'] = tsukuyomi.lang.Function.new() 29 | tsukuyomi_core['load-file'][1] = function (name) 30 | local f = io.open(name) 31 | local text = f:read('*all') 32 | f:close() 33 | local r = PushbackReader.new(text, name) 34 | 35 | local datum = tsukuyomi_core.read[1](r) 36 | while datum do 37 | local lua_code = Compiler.compile(datum) 38 | local chunk, err = loadstring(lua_code, describe(datum)) 39 | if err then 40 | io.stderr:write(err) 41 | io.stderr:write('\n') 42 | assert(false) 43 | else 44 | chunk() 45 | end 46 | 47 | datum = tsukuyomi_core.read[1](r) 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /tests/tsukuyomi/tsukuyomi_004.ok.lua: -------------------------------------------------------------------------------- 1 | -- vim: et sw=2 sts=2 ts=2 2 | local tsukuyomi = tsukuyomi 3 | local tsukuyomi_core = tsukuyomi.core 4 | local PushbackReader = tsukuyomi.lang.PushbackReader 5 | local Compiler = tsukuyomi.lang.Namespace.GetNamespaceSpace('tsukuyomi.lang.Compiler') 6 | local PersistentList = tsukuyomi.lang.PersistentList 7 | local Symbol = tsukuyomi.lang.Symbol 8 | 9 | tsukuyomi_core['eval'] = tsukuyomi.lang.Function.new() 10 | tsukuyomi_core['eval'][1] = function (form) 11 | assert(false) 12 | end 13 | 14 | local def_symbol = Symbol.intern('def') 15 | 16 | local function describe(datum) 17 | local info 18 | if type(datum) == 'table' and datum.first then 19 | if datum:first() == def_symbol then 20 | local symbol = datum:rest():first() 21 | symbol = tsukuyomi.core['*ns*']:bind_symbol(symbol) 22 | info = tostring(symbol) 23 | end 24 | end 25 | return info 26 | end 27 | 28 | tsukuyomi_core['load-file'] = tsukuyomi.lang.Function.new() 29 | tsukuyomi_core['load-file'][1] = function (name) 30 | local f = io.open(name) 31 | local text = f:read('*all') 32 | f:close() 33 | local r = PushbackReader.new(text, name) 34 | 35 | local datum = tsukuyomi_core.read[1](r) 36 | while datum do 37 | local lua_code = Compiler.compile(datum) 38 | local chunk, err = loadstring(lua_code, describe(datum)) 39 | if err then 40 | io.stderr:write(err) 41 | io.stderr:write('\n') 42 | assert(false) 43 | else 44 | chunk() 45 | end 46 | 47 | datum = tsukuyomi_core.read[1](r) 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /tests/tsukuyomi/tsukuyomi_006.OUT.lua: -------------------------------------------------------------------------------- 1 | -- vim: et sw=2 sts=2 ts=2 2 | local tsukuyomi = tsukuyomi 3 | local util = require('tsukuyomi.thirdparty.util') 4 | 5 | local PersistentList = tsukuyomi.lang.PersistentList 6 | local PersistentVector = tsukuyomi.lang.PersistentVector 7 | local PersistentHashMap = tsukuyomi.lang.PersistentHashMap 8 | local ArraySeq = tsukuyomi.lang.ArraySeq 9 | local ConcatSeq = tsukuyomi.lang.ConcatSeq 10 | local Symbol = tsukuyomi.lang.Symbol 11 | local Keyword = tsukuyomi.lang.Keyword 12 | local Var = tsukuyomi.lang.Var 13 | 14 | print('PersistentList: ' .. tostring(PersistentList)) 15 | print('PersistentList.EMPTY: ' .. tostring(PersistentList.EMPTY)) 16 | print('PersistentVector: ' .. tostring(PersistentVector)) 17 | print('PersistentHashMap: ' .. tostring(PersistentHashMap)) 18 | print('ConcatSeq: ' .. tostring(ConcatSeq)) 19 | print('ArraySeq: ' .. tostring(ArraySeq)) 20 | 21 | -- TODO: add indenting 22 | -- TODO: make not vulnerable to a stack overflow when printing cons cells 23 | -- TODO: make not vulnerable to infinite loop due to self referential data structures 24 | function tsukuyomi.print(datum) 25 | if type(datum) == 'boolean' then 26 | return tostring(datum) 27 | elseif type(datum) == 'number' then 28 | return tostring(datum) 29 | elseif type(datum) == 'string' then 30 | return '"' .. datum .. '"' 31 | elseif datum == nil then 32 | return 'nil' 33 | end 34 | 35 | local mt = getmetatable(datum) 36 | 37 | if mt == Symbol or mt == Keyword then 38 | return tostring(datum) 39 | elseif mt == PersistentVector then 40 | local items = {} 41 | for i = 0, datum:count() - 1 do 42 | table.insert(items, tsukuyomi.print(datum:get(i))) 43 | end 44 | return '[' .. table.concat(items, ' ') .. ']' 45 | elseif mt == PersistentHashMap then 46 | local items = {} 47 | local seq = datum:seq() 48 | while seq and seq:first() ~= nil do 49 | local kv = seq:first() 50 | local k = kv:get(0) 51 | local v = kv:get(1) 52 | table.insert(items, tsukuyomi.print(k)) 53 | table.insert(items, tsukuyomi.print(v)) 54 | seq = seq:rest() 55 | end 56 | return '{' .. table.concat(items, ' ') .. '}' 57 | elseif mt == Var then 58 | return tostring(datum) 59 | elseif datum.first ~= nil then 60 | local items = {} 61 | 62 | --[[ 63 | while true do 64 | if datum:count() == 0 then 65 | local check = datum:seq() 66 | if check ~= nil then 67 | print(getmetatable(datum)) 68 | print(util.show(datum)) 69 | assert(false) 70 | end 71 | break 72 | end 73 | 74 | local item = datum:first() 75 | table.insert(items, tsukuyomi.print(item)) 76 | 77 | datum = datum:rest() 78 | end 79 | ]]-- 80 | 81 | while datum:seq() do 82 | local item = datum:first() 83 | table.insert(items, tsukuyomi.print(item)) 84 | datum = datum:rest() 85 | end 86 | return '(' .. table.concat(items, ' ') .. ')' 87 | else 88 | print(util.show(datum)) 89 | assert(false) 90 | end 91 | end 92 | 93 | tsukuyomi.core['pr-str'] = tsukuyomi.lang.Function.new() 94 | tsukuyomi.core['pr-str'][1] = tsukuyomi.print 95 | -------------------------------------------------------------------------------- /tests/tsukuyomi/tsukuyomi_006.in.lua: -------------------------------------------------------------------------------- 1 | -- vim: et sw=2 sts=2 ts=2 2 | local tsukuyomi = tsukuyomi 3 | local util = require('tsukuyomi.thirdparty.util') 4 | 5 | local PersistentList = tsukuyomi.lang.PersistentList 6 | local PersistentVector = tsukuyomi.lang.PersistentVector 7 | local PersistentHashMap = tsukuyomi.lang.PersistentHashMap 8 | local ArraySeq = tsukuyomi.lang.ArraySeq 9 | local ConcatSeq = tsukuyomi.lang.ConcatSeq 10 | local Symbol = tsukuyomi.lang.Symbol 11 | local Keyword = tsukuyomi.lang.Keyword 12 | local Var = tsukuyomi.lang.Var 13 | 14 | print('PersistentList: ' .. tostring(PersistentList)) 15 | print('PersistentList.EMPTY: ' .. tostring(PersistentList.EMPTY)) 16 | print('PersistentVector: ' .. tostring(PersistentVector)) 17 | print('PersistentHashMap: ' .. tostring(PersistentHashMap)) 18 | print('ConcatSeq: ' .. tostring(ConcatSeq)) 19 | print('ArraySeq: ' .. tostring(ArraySeq)) 20 | 21 | -- TODO: add indenting 22 | -- TODO: make not vulnerable to a stack overflow when printing cons cells 23 | -- TODO: make not vulnerable to infinite loop due to self referential data structures 24 | function tsukuyomi.print(datum) 25 | if type(datum) == 'boolean' then 26 | return tostring(datum) 27 | elseif type(datum) == 'number' then 28 | return tostring(datum) 29 | elseif type(datum) == 'string' then 30 | return '"' .. datum .. '"' 31 | elseif datum == nil then 32 | return 'nil' 33 | end 34 | 35 | local mt = getmetatable(datum) 36 | 37 | if mt == Symbol or mt == Keyword then 38 | return tostring(datum) 39 | elseif mt == PersistentVector then 40 | local items = {} 41 | for i = 0, datum:count() - 1 do 42 | table.insert(items, tsukuyomi.print(datum:get(i))) 43 | end 44 | return '[' .. table.concat(items, ' ') .. ']' 45 | elseif mt == PersistentHashMap then 46 | local items = {} 47 | local seq = datum:seq() 48 | while seq and seq:first() ~= nil do 49 | local kv = seq:first() 50 | local k = kv:get(0) 51 | local v = kv:get(1) 52 | table.insert(items, tsukuyomi.print(k)) 53 | table.insert(items, tsukuyomi.print(v)) 54 | seq = seq:rest() 55 | end 56 | return '{' .. table.concat(items, ' ') .. '}' 57 | elseif mt == Var then 58 | return tostring(datum) 59 | elseif datum.first ~= nil then 60 | local items = {} 61 | 62 | --[[ 63 | while true do 64 | if datum:count() == 0 then 65 | local check = datum:seq() 66 | if check ~= nil then 67 | print(getmetatable(datum)) 68 | print(util.show(datum)) 69 | assert(false) 70 | end 71 | break 72 | end 73 | 74 | local item = datum:first() 75 | table.insert(items, tsukuyomi.print(item)) 76 | 77 | datum = datum:rest() 78 | end 79 | ]]-- 80 | 81 | while datum:seq() do 82 | local item = datum:first() 83 | table.insert(items, tsukuyomi.print(item)) 84 | datum = datum:rest() 85 | end 86 | return '(' .. table.concat(items, ' ') .. ')' 87 | else 88 | print(util.show(datum)) 89 | assert(false) 90 | end 91 | end 92 | 93 | tsukuyomi.core['pr-str'] = tsukuyomi.lang.Function.new() 94 | tsukuyomi.core['pr-str'][1] = tsukuyomi.print 95 | -------------------------------------------------------------------------------- /tests/tsukuyomi/tsukuyomi_006.ok.lua: -------------------------------------------------------------------------------- 1 | -- vim: et sw=2 sts=2 ts=2 2 | local tsukuyomi = tsukuyomi 3 | local util = require('tsukuyomi.thirdparty.util') 4 | 5 | local PersistentList = tsukuyomi.lang.PersistentList 6 | local PersistentVector = tsukuyomi.lang.PersistentVector 7 | local PersistentHashMap = tsukuyomi.lang.PersistentHashMap 8 | local ArraySeq = tsukuyomi.lang.ArraySeq 9 | local ConcatSeq = tsukuyomi.lang.ConcatSeq 10 | local Symbol = tsukuyomi.lang.Symbol 11 | local Keyword = tsukuyomi.lang.Keyword 12 | local Var = tsukuyomi.lang.Var 13 | 14 | print('PersistentList: ' .. tostring(PersistentList)) 15 | print('PersistentList.EMPTY: ' .. tostring(PersistentList.EMPTY)) 16 | print('PersistentVector: ' .. tostring(PersistentVector)) 17 | print('PersistentHashMap: ' .. tostring(PersistentHashMap)) 18 | print('ConcatSeq: ' .. tostring(ConcatSeq)) 19 | print('ArraySeq: ' .. tostring(ArraySeq)) 20 | 21 | -- TODO: add indenting 22 | -- TODO: make not vulnerable to a stack overflow when printing cons cells 23 | -- TODO: make not vulnerable to infinite loop due to self referential data structures 24 | function tsukuyomi.print(datum) 25 | if type(datum) == 'boolean' then 26 | return tostring(datum) 27 | elseif type(datum) == 'number' then 28 | return tostring(datum) 29 | elseif type(datum) == 'string' then 30 | return '"' .. datum .. '"' 31 | elseif datum == nil then 32 | return 'nil' 33 | end 34 | 35 | local mt = getmetatable(datum) 36 | 37 | if mt == Symbol or mt == Keyword then 38 | return tostring(datum) 39 | elseif mt == PersistentVector then 40 | local items = {} 41 | for i = 0, datum:count() - 1 do 42 | table.insert(items, tsukuyomi.print(datum:get(i))) 43 | end 44 | return '[' .. table.concat(items, ' ') .. ']' 45 | elseif mt == PersistentHashMap then 46 | local items = {} 47 | local seq = datum:seq() 48 | while seq and seq:first() ~= nil do 49 | local kv = seq:first() 50 | local k = kv:get(0) 51 | local v = kv:get(1) 52 | table.insert(items, tsukuyomi.print(k)) 53 | table.insert(items, tsukuyomi.print(v)) 54 | seq = seq:rest() 55 | end 56 | return '{' .. table.concat(items, ' ') .. '}' 57 | elseif mt == Var then 58 | return tostring(datum) 59 | elseif datum.first ~= nil then 60 | local items = {} 61 | 62 | --[[ 63 | while true do 64 | if datum:count() == 0 then 65 | local check = datum:seq() 66 | if check ~= nil then 67 | print(getmetatable(datum)) 68 | print(util.show(datum)) 69 | assert(false) 70 | end 71 | break 72 | end 73 | 74 | local item = datum:first() 75 | table.insert(items, tsukuyomi.print(item)) 76 | 77 | datum = datum:rest() 78 | end 79 | ]]-- 80 | 81 | while datum:seq() do 82 | local item = datum:first() 83 | table.insert(items, tsukuyomi.print(item)) 84 | datum = datum:rest() 85 | end 86 | return '(' .. table.concat(items, ' ') .. ')' 87 | else 88 | print(util.show(datum)) 89 | assert(false) 90 | end 91 | end 92 | 93 | tsukuyomi.core['pr-str'] = tsukuyomi.lang.Function.new() 94 | tsukuyomi.core['pr-str'][1] = tsukuyomi.print 95 | --------------------------------------------------------------------------------