1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-09 22:21:29 +00:00
Files
nmap/scripts/nfs-statfs.nse

209 lines
5.5 KiB
Lua

description = [[
Retrieves disk space statistics and information from the remote NFS
share. This script will try to emulate the behaviour of the "df" tool.
The script will provide pathconf information of the remote NFS if
the version used is NFSv3.
]]
---
-- @output
-- PORT STATE SERVICE
-- | nfs-statfs:
-- |
-- | Filesystem 1K-blocks Used Available Use% Blocksize
-- | /mnt/nfs/files 5542276 2732012 2528728 52% 4096
-- |_ /mnt/nfs/opensource 5534416 620640 4632644 12% 4096
--
-- @args nfs-statfs.human If set to '1' or 'true' shows the filesystem
-- size in the human readable format.
--
-- Version 0.3
-- Created 01/25/2010 - v0.1 - created by Patrik Karlsson <patrik@cqure.net>
-- Revised 02/22/2010 - v0.2 - adapted to support new RPC library
-- Revised 03/13/2010 - v0.3 - converted host to port rule
-- Revised 06/28/2010 - v0.4 - added NFSv3 support and doc
author = "Patrik Karlsson, Djalal Harouni"
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"discovery", "safe"}
require("shortport")
require("rpc")
require("tab")
portrule = shortport.port_or_service(111, "rpcbind", {"tcp", "udp"} )
local function table_fsstat(nfs, mount, stats)
local fs, err = rpc.Util.calc_fsstat_table(stats, nfs.version, nfs.human)
if fs == nil then
return false, err
end
fs.filesystem = string.format("%s", mount)
return true, fs
end
local function table_fsinfo(nfs, fsinfo)
local ret = {}
local fs, err = rpc.Util.calc_fsinfo_table(fsinfo, nfs.version, nfs.human)
if fs == nil then
return false, err
end
ret.maxfilesize = fs.maxfilesize
return true, ret
end
local function table_pathconf(nfs, pconf)
local ret = {}
local fs, err = rpc.Util.calc_pathconf_table(pconf, nfs.version)
if fs == nil then
return false, err
end
ret.linkmax = fs.linkmax
return true, ret
end
local function report(nfs, tables)
local outtab, tab_size, tab_avail
local tab_filesys, tab_used, tab_use,
tab_bs, tab_maxfs, tab_linkmax = " Filesystem",
"Used", "Use%", "Blocksize", "Maxfilesize", "Maxlink"
if nfs.human then
tab_size = "Size"
tab_avail = "Avail"
else
tab_size = "1K-blocks"
tab_avail = "Available"
end
if nfs.version == 2 then
outtab = tab.new(6)
tab.nextrow(outtab)
tab.addrow(outtab, tab_filesys, tab_size, tab_used,
tab_avail, tab_use, tab_bs)
for _, t in ipairs(tables) do
tab.nextrow(outtab)
tab.addrow(outtab, (" %s"):format(t.filesystem), t.size,
t.used, t.available, t.use, t.bsize)
end
elseif nfs.version == 3 then
outtab = tab.new(7)
tab.nextrow(outtab)
tab.addrow(outtab, tab_filesys, tab_size, tab_used,
tab_avail, tab_use, tab_maxfs, tab_linkmax)
for _, t in ipairs(tables) do
tab.nextrow(outtab)
tab.addrow(outtab, (" %s"):format(t.filesystem), t.size,
t.used, t.available, t.use, t.maxfilesize,
t.linkmax)
end
end
return tab.dump(outtab)
end
local function nfs_filesystem_info(nfs, mount, filesystem)
local results, res, status = {}, {}
local nfsobj = rpc.NFS:new()
local mnt_comm, nfs_comm, fhandle
mnt_comm, fhandle = rpc.Helper.MountPath(nfs.host, nfs.port, mount)
if mnt_comm == nil then
return false, fhandle
end
local nfs_comm, status = rpc.Helper.NfsOpen(nfs.host, nfs.port)
if nfs_comm == nil then
rpc.Helper.UnmountPath(mnt_comm, mount)
return false, status
end
nfs.version = nfs_comm.version
-- use simple check since NFSv1 is not used anymore.
if (mnt_comm.version ~= nfs_comm.version) then
rpc.Helper.UnmountPath(mnt_comm, mount)
return false, string.format("versions mismatch, nfs v%d - mount v%d",
nfs_comm.version, mnt_comm.version)
end
if nfs_comm.version < 3 then
status, res = nfsobj:StatFs(nfs_comm, fhandle)
elseif nfs_comm.version == 3 then
status, res = nfsobj:FsStat(nfs_comm, fhandle)
end
if status then
status, res = table_fsstat(nfs, mount, res)
if status then
for k, v in pairs(res) do
results[k] = v
end
end
if nfs_comm.version == 3 then
status, res = nfsobj:FsInfo(nfs_comm, fhandle)
if status then
status, res = table_fsinfo(nfs, res)
if status then
for k, v in pairs(res) do
results[k] = v
end
end
end
status, res = nfsobj:PathConf(nfs_comm, fhandle)
if status then
status, res = table_pathconf(nfs, res)
if status then
for k, v in pairs(res) do
results[k] = v
end
end
end
end
end
rpc.Helper.NfsClose(nfs_comm)
rpc.Helper.UnmountPath(mnt_comm, mount)
if (not(status)) then
return status, res
end
table.insert(filesystem, results)
return true, nil
end
action = function(host, port)
local o, fs_info, mounts, status = {}, {}, {}, {}
local nfs_info =
{
host = host,
port = port,
human = nmap.registry.args['nfs-statfs.human'] or nil,
}
status, mounts = rpc.Helper.ShowMounts( host, port )
if (not(status)) then
return stdnse.format_output(false, mounts)
end
for _, v in ipairs(mounts) do
local err
status, err = nfs_filesystem_info(nfs_info, v.name, fs_info)
if (not(status)) then
return stdnse.format_output(false, err)
end
end
table.insert(o, report(nfs_info, fs_info))
return stdnse.format_output(true, o)
end