1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-16 04:39:03 +00:00

Merge r18534:r18591 from nmap-exp/djalal/nse-nfs/

This commit is contained in:
djalal
2010-07-06 00:29:54 +00:00
parent 0347e05487
commit 53b2b629dc
2 changed files with 296 additions and 48 deletions

View File

@@ -1795,7 +1795,7 @@ NFS = {
FsStat = function(self, comm, file_handle)
local status, packet
local pos, data = 1, ""
local reponse = {}
local header, response = {}, {}
if (comm.version < 3) then
return false, string.format("NFS version: %d does not support FSSTAT",
@@ -1867,7 +1867,7 @@ NFS = {
pos, fsinfo.rtmax, fsinfo.rtpref, fsinfo.rtmult,
fsinfo.wtmax, fsinfo.wtpref, fsinfo.wtmult,
fsinfo.dtpref = Util.unmarshall_uint32(data, pos, 7)
pos, fsinfo.maxfilesize = Util.unmarshall_size3(data, pos)
pos, fsinfo.maxfilesize = Util.unmarshall_nfssize3(data, pos)
pos, fsinfo.time_delta = Util.unmarshall_nfstime(data, pos)
pos, fsinfo.properties = Util.unmarshall_uint32(data, pos)
@@ -1877,7 +1877,7 @@ NFS = {
FsInfo = function(self, comm, file_handle)
local status, packet
local pos, data = 1, ""
local reponse = {}
local header, response = {}
if (comm.version < 3) then
return false, string.format("NFS version: %d does not support FSINFO",
@@ -1913,7 +1913,7 @@ NFS = {
return true, response
end,
PathConfDecode = function(self, comm, file_handle)
PathConfDecode = function(self, comm, data, pos)
local pconf, status, value_follows = {}
status, data = comm:GetAdditionalBytes(data, pos, 4)
@@ -1956,7 +1956,7 @@ NFS = {
PathConf = function(self, comm, file_handle)
local status, packet
local pos, data = 1, ""
local reponse = {}
local header, response = {}
if (comm.version < 3) then
return false, string.format("NFS version: %d does not support PATHCONF",
@@ -3071,12 +3071,12 @@ Util =
-- readable format
SizeToHuman = function(size, blocksize)
local bs, idx = 1024, 1
local unit = { "B", "K", "M", "G" }
local unit = { "B", "K", "M", "G" , "T"}
if blocksize and blocksize == 1000 then
bs = blocksize
end
for i=1, #unit do
if (size > bs) then
if (size > bs and idx < #unit) then
size = size / bs
idx = idx + 1
end
@@ -3126,6 +3126,111 @@ Util =
return ret
end,
--- Return the pathconf filesystem table
--
-- @param pconf table returned by the NFSv3 PATHCONF call
-- @param nfsversion the version of the remote NFS server
-- @return fs table that contains the remote filesystem
-- pathconf information.
calc_pathconf_table = function(pconf, nfsversion)
local fs = {}
if nfsversion ~= 3 then
return nil, "ERROR: unsupported NFS version."
end
fs.linkmax = pconf.linkmax
fs.name_max = pconf.name_max
if pconf.chown_restricted then
fs.chown_restricted = "True"
else
fs.chown_restricted = "False"
end
return fs, nil
end,
--- Calculate and return the fsinfo filesystem table
--
-- @param fsinfo table returned by the NFSv3 FSINFO call
-- @param nfsversion the version of the remote NFS server
-- @param human if set show the size in the human
-- readable format.
-- @return fs table that contains the remote filesystem
-- information.
calc_fsinfo_table = function(fsinfo, nfsversion, human)
local fs = {}
local nfsobj = NFS:new()
if nfsversion ~= 3 then
return nil, "ERROR: unsupported NFS version."
end
fs.maxfilesize = Util.SizeToHuman(fsinfo.maxfilesize)
if nfsobj:FSinfoLink(fsinfo.properties, nfsversion) ~= 0 then
fs.link = "True"
else
fs.link = "False"
end
if nfsobj:FSinfoSymlink(fsinfo.properties, nfsversion) ~= 0 then
fs.symlink = "True"
else
fs.symlink = "False"
end
return fs, nil
end,
--- Calculate and return the fsstat filesystem table
--
-- @param stats table returned by the NFSv3 FSSTAT or
-- NFSv2 STATFS calls
-- @param nfsversion the version of the remote NFS server
-- @param human if set show the size in the human
-- readable format.
-- @return df table that contains the remote filesystem
-- attributes.
calc_fsstat_table = function(stats, nfsversion, human)
local df, base = {}, 1024
local size, free, total, avail, used, use
if (nfsversion == 3) then
free = stats.fbytes
size = stats.tbytes
avail = stats.abytes
elseif (nfsversion == 2) then
df.bsize = stats.block_size
free = stats.free_blocks * df.bsize
size = stats.total_blocks * df.bsize
avail = stats.available_blocks * df.bsize
else
return nil, "ERROR: unsupported NFS version."
end
if (human) then
if (df.bsize) then
df.bsize = Util.SizeToHuman(df.bsize)
end
df.size = Util.SizeToHuman(size)
df.available = Util.SizeToHuman(avail)
used = size - free
avail = avail
df.used = Util.SizeToHuman(used)
total = used + avail
else
free = free / base
df.size = size / base
df.available = avail / base
used = df.size - free
df.used = used
total = df.used + df.available
end
use = math.ceil(used * 100 / total)
df.use = string.format("%.0f%%", use)
return df, nil
end,
--- Converts a RPC program name to it's equivalent number
--
-- @param prog_name string containing the name of the RPC program

View File

@@ -1,21 +1,22 @@
description = [[
Retrieves disk space statistics from the remote NFS share
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:
-- | /home/storage/backup
-- | Block size: 512
-- | Total blocks: 1901338728
-- | Free blocks: 729769328
-- | Available blocks: 633186880
-- | /home
-- | Block size: 512
-- | Total blocks: 1901338728
-- | Free blocks: 729769328
-- |_ Available blocks: 633186880
-- |
-- | 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
@@ -23,43 +24,185 @@ Retrieves disk space statistics from the remote NFS share
-- 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"
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"} )
action = function(host, port)
local result, entry = {}, {}
local 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 entry = {}
local status, stats = rpc.Helper.ExportStats(host, port, v.name)
entry.name = v.name
if (not(status)) then
table.insert(entry, string.format("ERROR: %s", stats))
else
table.insert( entry, string.format("Block size: %d", stats.block_size) )
table.insert( entry, string.format("Total blocks: %d", stats.total_blocks) )
table.insert( entry, string.format("Free blocks: %d", stats.free_blocks) )
table.insert( entry, string.format("Available blocks: %d", stats.available_blocks) )
end
table.insert( result, entry )
end
return stdnse.format_output( true, result )
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