1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-19 05:59:01 +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) FsStat = function(self, comm, file_handle)
local status, packet local status, packet
local pos, data = 1, "" local pos, data = 1, ""
local reponse = {} local header, response = {}, {}
if (comm.version < 3) then if (comm.version < 3) then
return false, string.format("NFS version: %d does not support FSSTAT", return false, string.format("NFS version: %d does not support FSSTAT",
@@ -1867,7 +1867,7 @@ NFS = {
pos, fsinfo.rtmax, fsinfo.rtpref, fsinfo.rtmult, pos, fsinfo.rtmax, fsinfo.rtpref, fsinfo.rtmult,
fsinfo.wtmax, fsinfo.wtpref, fsinfo.wtmult, fsinfo.wtmax, fsinfo.wtpref, fsinfo.wtmult,
fsinfo.dtpref = Util.unmarshall_uint32(data, pos, 7) 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.time_delta = Util.unmarshall_nfstime(data, pos)
pos, fsinfo.properties = Util.unmarshall_uint32(data, pos) pos, fsinfo.properties = Util.unmarshall_uint32(data, pos)
@@ -1877,7 +1877,7 @@ NFS = {
FsInfo = function(self, comm, file_handle) FsInfo = function(self, comm, file_handle)
local status, packet local status, packet
local pos, data = 1, "" local pos, data = 1, ""
local reponse = {} local header, response = {}
if (comm.version < 3) then if (comm.version < 3) then
return false, string.format("NFS version: %d does not support FSINFO", return false, string.format("NFS version: %d does not support FSINFO",
@@ -1913,7 +1913,7 @@ NFS = {
return true, response return true, response
end, end,
PathConfDecode = function(self, comm, file_handle) PathConfDecode = function(self, comm, data, pos)
local pconf, status, value_follows = {} local pconf, status, value_follows = {}
status, data = comm:GetAdditionalBytes(data, pos, 4) status, data = comm:GetAdditionalBytes(data, pos, 4)
@@ -1956,7 +1956,7 @@ NFS = {
PathConf = function(self, comm, file_handle) PathConf = function(self, comm, file_handle)
local status, packet local status, packet
local pos, data = 1, "" local pos, data = 1, ""
local reponse = {} local header, response = {}
if (comm.version < 3) then if (comm.version < 3) then
return false, string.format("NFS version: %d does not support PATHCONF", return false, string.format("NFS version: %d does not support PATHCONF",
@@ -3071,12 +3071,12 @@ Util =
-- readable format -- readable format
SizeToHuman = function(size, blocksize) SizeToHuman = function(size, blocksize)
local bs, idx = 1024, 1 local bs, idx = 1024, 1
local unit = { "B", "K", "M", "G" } local unit = { "B", "K", "M", "G" , "T"}
if blocksize and blocksize == 1000 then if blocksize and blocksize == 1000 then
bs = blocksize bs = blocksize
end end
for i=1, #unit do for i=1, #unit do
if (size > bs) then if (size > bs and idx < #unit) then
size = size / bs size = size / bs
idx = idx + 1 idx = idx + 1
end end
@@ -3126,6 +3126,111 @@ Util =
return ret return ret
end, 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 --- Converts a RPC program name to it's equivalent number
-- --
-- @param prog_name string containing the name of the RPC program -- @param prog_name string containing the name of the RPC program

View File

@@ -1,21 +1,22 @@
description = [[ 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 -- @output
-- PORT STATE SERVICE -- PORT STATE SERVICE
-- | nfs-statfs: -- | nfs-statfs:
-- | /home/storage/backup -- |
-- | Block size: 512 -- | Filesystem 1K-blocks Used Available Use% Blocksize
-- | Total blocks: 1901338728 -- | /mnt/nfs/files 5542276 2732012 2528728 52% 4096
-- | Free blocks: 729769328 -- |_ /mnt/nfs/opensource 5534416 620640 4632644 12% 4096
-- | Available blocks: 633186880 --
-- | /home -- @args nfs-statfs.human If set to '1' or 'true' shows the filesystem
-- | Block size: 512 -- size in the human readable format.
-- | Total blocks: 1901338728
-- | Free blocks: 729769328
-- |_ Available blocks: 633186880
-- --
-- Version 0.3 -- 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> -- 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 02/22/2010 - v0.2 - adapted to support new RPC library
-- Revised 03/13/2010 - v0.3 - converted host to port rule -- 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" license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
categories = {"discovery", "safe"} categories = {"discovery", "safe"}
require("shortport") require("shortport")
require("rpc") require("rpc")
require("tab")
portrule = shortport.port_or_service(111, "rpcbind", {"tcp", "udp"} ) portrule = shortport.port_or_service(111, "rpcbind", {"tcp", "udp"} )
action = function(host, port) local function table_fsstat(nfs, mount, stats)
local fs, err = rpc.Util.calc_fsstat_table(stats, nfs.version, nfs.human)
local result, entry = {}, {} if fs == nil then
local status, mounts = rpc.Helper.ShowMounts( host, port ) return false, err
end
if ( not(status) ) then fs.filesystem = string.format("%s", mount)
return stdnse.format_output(false, mounts) return true, fs
end end
for _, v in ipairs( mounts ) do local function table_fsinfo(nfs, fsinfo)
local entry = {} local ret = {}
local status, stats = rpc.Helper.ExportStats(host, port, v.name) local fs, err = rpc.Util.calc_fsinfo_table(fsinfo, nfs.version, nfs.human)
if fs == nil then
entry.name = v.name return false, err
end
if (not(status)) then
table.insert(entry, string.format("ERROR: %s", stats)) ret.maxfilesize = fs.maxfilesize
else return true, ret
table.insert( entry, string.format("Block size: %d", stats.block_size) ) end
table.insert( entry, string.format("Total blocks: %d", stats.total_blocks) )
table.insert( entry, string.format("Free blocks: %d", stats.free_blocks) ) local function table_pathconf(nfs, pconf)
table.insert( entry, string.format("Available blocks: %d", stats.available_blocks) ) local ret = {}
end local fs, err = rpc.Util.calc_pathconf_table(pconf, nfs.version)
table.insert( result, entry ) if fs == nil then
end return false, err
end
return stdnse.format_output( true, result )
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 end