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

Remove target IP address from debug messages in whois-ip.nse

stdnse.debug writes the IP to messages so scripts don't have to.
A couple of functions no longer needed the target IP passed to them: their
signature and nsedoc were updated accordingly, along with any calls to them.
Also fix some white space.
This commit is contained in:
jah
2015-02-20 03:34:57 +00:00
parent 6146593e11
commit 836c6e25bc

View File

@@ -101,7 +101,7 @@ hostrule = function( host )
local is_private, err = ipOps.isPrivate( host.ip )
if is_private == nil then
stdnse.debug1("Error in Hostrule: %s.", err )
stdnse.debug1("Error in Hostrule: %s.", err)
return false
end
@@ -196,7 +196,7 @@ action = function( host )
status, retval = pcall( get_next_action, tracking, host.ip )
if not status then
stdnse.debug1("%s pcall caught an exception in get_next_action: %s.", host.ip, retval )
stdnse.debug1("pcall caught an exception in get_next_action: %s.", retval)
else tracking = retval end
if tracking.this_db then
@@ -207,13 +207,13 @@ action = function( host )
-- analyse data
status, retval = pcall( analyse_response, tracking, host.ip, response, data )
if not status then
stdnse.debug1("%s pcall caught an exception in analyse_response: %s.", host.ip, retval )
stdnse.debug1("pcall caught an exception in analyse_response: %s.", retval)
else data = retval end
-- get next action
status, retval = pcall( get_next_action, tracking, host.ip )
if not status then
stdnse.debug1("%s pcall caught an exception in get_next_action: %s.", host.ip, retval )
stdnse.debug1("pcall caught an exception in get_next_action: %s.", retval)
if not tracking.last_db then tracking.last_db, tracking.this_db = tracking.this_db or tracking.next_db, nil end
else tracking = retval end
end
@@ -346,7 +346,7 @@ function check_response_cache( ip )
-- record found in cache
return true, nil
else
stdnse.debug1("%s Error in check_response_cache: Empty Cache Entry was found.", ip )
stdnse.debug1("Error in check_response_cache: Empty Cache Entry was found.")
end
return false, nil
@@ -467,7 +467,7 @@ function get_db_from_assignments( ip )
end
if not nmap.registry.whois.local_assignments_data or not nmap.registry.whois.local_assignments_data[af] then
stdnse.debug1("Error in get_db_from_assignments: Missing assignments data in registry." )
stdnse.debug1("Error in get_db_from_assignments: Missing assignments data in registry.")
return nil
end
@@ -494,14 +494,14 @@ end
function do_query(db, ip)
if type( db ) ~= "string" or not nmap.registry.whois.whoisdb[db] then
stdnse.debug1("%s Error in do_query: %s is not a defined Whois service.", ip, db)
stdnse.debug1("Error in do_query: %s is not a defined Whois service.", db)
return nil
end
local service = nmap.registry.whois.whoisdb[db]
if type( service.hostname ) ~= "string" or service.hostname == "" then
stdnse.debug1("%s Error in do_query: Invalid hostname for %s.", ip, db)
stdnse.debug1("Error in do_query: Invalid hostname for %s.", db)
return nil
end
@@ -517,7 +517,7 @@ function do_query(db, ip)
local socket = nmap.new_socket()
local catch = function()
stdnse.debug1("%s Connection to %s failed or was aborted! No Output for this Target.", ip, db )
stdnse.debug1("Connection to %s failed or was aborted! No Output for this Target.", db)
nmap.registry.whois.mutex[db] "done"
socket:close()
end
@@ -540,7 +540,7 @@ function do_query(db, ip)
socket:close()
stdnse.debug3("%s Ended Query at %s.", ip, db)
stdnse.debug3("Ended Query at %s.", db)
if #result == 0 then
return nil
@@ -593,13 +593,13 @@ function analyse_response( tracking, ip, response, data )
if type( meta ) == "table" and type( meta.fieldreq ) == "table" and type( meta.fieldreq.ob_exist ) == "string" then
have_objects = response:match( meta.fieldreq.ob_exist )
else
stdnse.debug2("%s Could not check for objects, problem with meta data.", ip )
stdnse.debug2("Could not check for objects, problem with meta data.")
have_objects = false
end
-- if we do not recognize objects check for an known error/non-object message
if not have_objects then
stdnse.debug4("%s %s has not responded with the expected objects.", ip, this_db )
stdnse.debug4("%s has not responded with the expected objects.", this_db)
local tmp, msg
-- may have found our record saying something similar to "No Record Found"
for _, pattern in ipairs( nmap.registry.whois.m_none ) do
@@ -607,7 +607,7 @@ function analyse_response( tracking, ip, response, data )
local pattern_u = pattern:gsub( "$addr", ip:upper() )
msg = response:match( pattern_l ) or response:match( pattern_u )
if msg then
stdnse.debug4("%s %s responded with a message which is assumed to be authoritative (but may not be).", ip, this_db )
stdnse.debug4("%s responded with a message which is assumed to be authoritative (but may not be).", this_db)
break
end
end
@@ -616,7 +616,7 @@ function analyse_response( tracking, ip, response, data )
for _, pattern in ipairs( nmap.registry.whois.m_err ) do
msg = response:match( pattern )
if msg then
stdnse.debug4("%s %s responded with an ERROR message.", ip, this_db )
stdnse.debug4("%s responded with an ERROR message.", this_db)
break
end
end
@@ -635,7 +635,7 @@ function analyse_response( tracking, ip, response, data )
for setname, set in pairs( nmap.registry.whois.fields_meta ) do
if set ~= nmap.registry.whois.whoisdb[this_db].fieldreq and response:match(set.ob_exist) then
foreign_obj = setname
stdnse.debug4("%s %s seems to have responded using the set of objects named: %s.", ip, this_db, foreign_obj )
stdnse.debug4("%s seems to have responded using the set of objects named: %s.", this_db, foreign_obj)
break
end
end
@@ -644,7 +644,7 @@ function analyse_response( tracking, ip, response, data )
meta = nmap.registry.whois.whoisdb.ripe
meta.redirects = nil
have_objects = true
stdnse.debug4("%s %s will use the display properties of ripe.", ip, this_db )
stdnse.debug4("%s will use the display properties of ripe.", this_db)
elseif foreign_obj then
-- find a display to match the objects.
for some_db, db_props in pairs( nmap.registry.whois.whoisdb ) do
@@ -653,7 +653,7 @@ function analyse_response( tracking, ip, response, data )
meta = nmap.registry.whois.whoisdb[some_db]
meta.redirects = nil
have_objects = true
stdnse.debug4("%s %s will use the display properties of %s.", ip, this_db, some_db )
stdnse.debug4("%s will use the display properties of %s.", this_db, some_db)
break
end
end
@@ -662,23 +662,23 @@ function analyse_response( tracking, ip, response, data )
-- extract fields from the entire response for record/redirect discovery
if have_objects then
stdnse.debug4("%s Parsing Query response from %s.", ip, this_db )
data[this_db] = extract_objects_from_response( response, this_db, ip, meta )
stdnse.debug4("Parsing Query response from %s.", this_db)
data[this_db] = extract_objects_from_response( response, this_db, meta )
end
local response_chunk, found, nextdb
-- do record/redirect discovery, cache found redirect
if not nmap.registry.whois.nofollow and have_objects and meta.redirects then
stdnse.debug4("%s Testing response for redirection.", ip )
found, nextdb, data.iana = redirection_rules( this_db, ip, data, meta )
stdnse.debug4("Testing response for redirection.")
found, nextdb, data.iana = redirection_rules( this_db, data, meta )
end
-- get most specific assignment and handle arin's organisation-focused record layout and then
-- modify the data table depending on whether we're redirecting or quitting
if have_objects then
stdnse.debug5("%s Extracting Fields from response.", ip )
stdnse.debug5("Extracting Fields from response.")
-- optionally constrain response to a more focused area
-- discarding previous extraction
@@ -686,18 +686,18 @@ function analyse_response( tracking, ip, response, data )
local offset, ptr, strbgn, strend
response_chunk, offset = constrain_response( response, this_db, ip, meta )
if offset > 0 then
data[this_db] = extract_objects_from_response( response_chunk, this_db, ip, meta )
data[this_db] = extract_objects_from_response( response_chunk, this_db, meta )
end
if offset > 1 and meta.unordered then
-- fetch an object immediately in front of inetnum
stdnse.debug5("%s %s Searching for an object group immediately before this range.", ip, this_db )
stdnse.debug5("%s Searching for an object group immediately before this range.", this_db)
-- split objects from the record, up to offset. Last object should be the one we want.
local obj_sel = stdnse.strsplit( "\r?\n\r?\n", response:sub( 1, offset ) )
response_chunk = "\n" .. obj_sel[#obj_sel] .. "\n"
-- check if any of the objects we like match this single object in response chunk
for ob, t in pairs( meta.fieldreq ) do
if ob ~= "ob_exist" and type( t.ob_start ) == "string" and response_chunk:match( t.ob_start ) then
data[this_db][ob] = extract_objects_from_response( response_chunk, this_db, ip, meta, ob )
data[this_db][ob] = extract_objects_from_response( response_chunk, this_db, meta, ob )
end
end
@@ -722,10 +722,10 @@ function analyse_response( tracking, ip, response, data )
end
-- DEBUG
stdnse.debug5("%s %s Fields captured :", ip, this_db )
stdnse.debug5("%s Fields captured :", this_db)
for ob, t in pairs( data[this_db] ) do
for fieldname, fieldvalue in pairs( t ) do
stdnse.debug5("%s %s %s.%s %s.", ip, this_db, ob, fieldname, fieldvalue )
stdnse.debug5("%s %s.%s %s.", this_db, ob, fieldname, fieldvalue)
end
end
@@ -804,12 +804,11 @@ end
-- If a fifth parameter specific_object is not supplied, all objects defined in fields_meta will be captured if they are present in the response.
-- @param response_string String obtained from a service in response to our query.
-- @param db String id of the whois service queried.
-- @param ip String representing the Target's IP address.
-- @param meta Table, nmap.registry.whois.whoisdb[db] where db is either the service queried or a mirrored service.
-- @param specific_object Optional string index of a single object defined in fields_meta (e.g. "inetnum").
-- @return Table indexed by object name containing the fields captured for each object found.
function extract_objects_from_response( response_string, db, ip, meta, specific_object )
function extract_objects_from_response( response_string, db, meta, specific_object )
local objects_to_extract = {}
local extracted_objects = {}
@@ -820,15 +819,15 @@ function extract_objects_from_response( response_string, db, ip, meta, specific_
-- we either receive a table for one object or for all objects
if type( specific_object ) == "string" and meta.fieldreq[specific_object] then
objects_to_extract[specific_object] = meta.fieldreq[specific_object]
stdnse.debug5("%s Extracting a single object: %s.", ip, specific_object )
stdnse.debug5("Extracting a single object: %s.", specific_object)
else
stdnse.debug5("%s Extracting all objects.", ip )
stdnse.debug5("Extracting all objects.")
objects_to_extract = meta.fieldreq
end
for object_name, object in pairs( objects_to_extract ) do
if object_name and object_name ~= "ob_exist" then
stdnse.debug5("%s Seeking object group: %s.", ip, object_name)
stdnse.debug5("Seeking object group: %s.", object_name)
extracted_objects[object_name] = {}
extracted_objects[object_name].for_compare = {} -- this will allow us to compare two tables
-- get a substr of response_string that corresponds to a single object
@@ -837,7 +836,7 @@ function extract_objects_from_response( response_string, db, ip, meta, specific_
-- if we could not find the end, make the end EOF
ob_end = ob_end or -1
if ob_start and ob_end then
stdnse.debug5("%s Capturing: %s with indices %s and %s.", ip, object_name, ob_start, ob_end )
stdnse.debug5("Capturing: %s with indices %s and %s.", object_name, ob_start, ob_end)
local obj_string = response_string:sub( ob_start, ob_end )
for fieldname, pattern in pairs( object ) do
if fieldname ~= "ob_start" and fieldname ~= "ob_end" then
@@ -864,7 +863,6 @@ end -- function
---
-- Checks for referrals in fields extracted from the whois query response.
-- @param db String id of the whois service queried.
-- @param ip String representing the Target's IP address.
-- @param data Table, indexed by whois service id, of extracted fields.
-- @param meta Table, nmap.registry.whois.whoisdb[db] where db is either the service queried or a mirrored service.
-- @return Boolean "found". True if a referral is not found (i.e. No Referral means the desired record has been "found"), otherwise False.
@@ -872,9 +870,9 @@ end -- function
-- @return Number "iana_count". This is the total number of referral to IANA for this Target (for all queries) and is stored in data.iana.
-- @see redirection_validation
function redirection_rules( db, ip, data, meta )
function redirection_rules( db, data, meta )
if type( db ) ~= "string" or db == "" or type( ip ) ~= "string" or ip == "" or type( data ) ~= "table" or not next( data ) then
if type( db ) ~= "string" or db == "" or type( data ) ~= "table" or not next( data ) then
return false, nil, nil
end
@@ -910,19 +908,19 @@ function redirection_rules( db, ip, data, meta )
-- arin record points to iana so we won't follow and we assume we have our record
if directed_to == iana and directed_from == arin then
stdnse.debug4("%s %s Accept arin record (matched IANA).", ip, directed_from )
stdnse.debug4("%s Accept arin record (matched IANA).", directed_from)
return true, nil, ( icnt+1 )
end
-- non-arin record points to iana so we query arin next
if directed_to == iana then
stdnse.debug4("%s Redirecting to arin (matched IANA).", ip )
stdnse.debug4("Redirecting to arin (matched IANA).")
return false, arin, ( icnt+1 )
end
-- a redirect, but not to iana or to self, so we follow it.
if directed_to ~= nmap.registry.whois.whoisdb[directed_from].id then
stdnse.debug4("%s %s redirects us to %s.", ip, directed_from, directed_to )
stdnse.debug4("%s redirects us to %s.", directed_from, directed_to)
return false, directed_to, icnt
end
@@ -938,14 +936,14 @@ function redirection_rules( db, ip, data, meta )
-- if a field has been captured for the given redirect info
if data[db][obj] and data[db][obj][fld] then
stdnse.debug5("%s Seek redirect in object: %s.%s for %s.", ip, obj, fld, pattern )
stdnse.debug5("Seek redirect in object: %s.%s for %s.", obj, fld, pattern)
-- iterate over nmap.registry.whois.whoisdb to find pattern (from each service) in the designated field
for member, mem_properties in pairs( nmap.registry.whois.whoisdb ) do
-- if pattern if found in the field, we have a redirect to member
if type( mem_properties[pattern] ) == "string" and string.lower( data[db][obj][fld] ):match( mem_properties[pattern] ) then
stdnse.debug5("%s Matched %s in %s.%s.", ip, pattern, obj, fld )
stdnse.debug5("Matched %s in %s.%s.", pattern, obj, fld)
return redirection_validation( nmap.registry.whois.whoisdb[member].id, db, iana_count )
elseif type( mem_properties[pattern] ) == "table" then
@@ -953,7 +951,7 @@ function redirection_rules( db, ip, data, meta )
-- pattern is an array of patterns
for _, pattn in ipairs( mem_properties[pattern] ) do
if type( pattn ) == "string" and string.lower( data[db][obj][fld] ):match( pattn ) then
stdnse.debug5("%s Matched %s in %s.%s.", ip, pattern, obj, fld )
stdnse.debug5("Matched %s in %s.%s.", pattern, obj, fld)
return redirection_validation( nmap.registry.whois.whoisdb[member].id, db, iana_count )
end
end
@@ -1007,7 +1005,7 @@ function constrain_response( response, db, ip, meta )
if # mptr > 1 then
-- find the closest one to host.ip and constrain the response to it
stdnse.debug5("%s %s Focusing on the smallest of %s address ranges.", ip, db, #mptr )
stdnse.debug5("%s Focusing on the smallest of %s address ranges.", db, #mptr)
-- sort the table mptr into nets ascending
table.sort( mptr, smallest_range )
-- select the first net that includes host.ip
@@ -1025,15 +1023,14 @@ function constrain_response( response, db, ip, meta )
if mptr[index+1] and ( mptr[index+1].pointer > mptr[index].pointer ) then
bound = mptr[index+1].pointer
end
stdnse.debug5("%s %s Smallest range containing target IP addr. is %s.", ip, db, trim( str_net ) )
local dbg = "%s %s %s smallest range is offset from %s to %s."
stdnse.debug5("%s Smallest range containing target IP addr. is %s.", db, trim( str_net ))
-- isolate inetnum and associated objects
if bound then
stdnse.debug5(dbg, SCRIPT_NAME, ip, db, ptr, bound)
stdnse.debug5("%s smallest range is offset from %s to %s.", db, ptr, bound)
-- get from pointer to bound
return response:sub(ptr,bound), ptr
else
stdnse.debug5(dbg, SCRIPT_NAME, ip, db, ptr, "the end")
stdnse.debug5("%s smallest range is offset from %s to %s.", db, ptr, "the end")
-- or get the whole thing from the pointer onwards
return response:sub(ptr), ptr
end
@@ -1075,7 +1072,7 @@ function not_short_prefix( ip, range, redirect )
first, last, err[#err+1] = ipOps.get_ips_from_range( range )
if #err > 0 then
stdnse.debug1("Error in not_short_prefix: s%.", table.concat( err, " " ) )
stdnse.debug1("Error in not_short_prefix: s%.", table.concat( err, " " ))
return nil
end
@@ -1119,7 +1116,7 @@ function add_to_cache( ip, range, redirect, data )
-- we need to cache some range so we'll cache the small assignment that includes ip.
if type( range ) ~= "string" or type( get_prefix_length( range ) ) ~= "number" then
range = get_assignment( ip, longest_prefix )
stdnse.debug5("%s Caching an assumed Range: %s", ip, range)
stdnse.debug5("Caching an assumed Range: %s", range)
end
nmap.registry.whois.cache[ip] = {} -- destroy any previous cache entry for this target.
@@ -1212,13 +1209,13 @@ function output( ip, services_queried )
end
if type( services_queried ) ~= "table" then
stdnse.debug1("%s Error in output(): No data found.", ip )
stdnse.debug1("Error in output(): No data found.")
return nil
elseif #services_queried == 0 then
stdnse.debug1("%s Error in output(): No data found, no queries were completed.", ip )
stdnse.debug1("Error in output(): No data found, no queries were completed.")
return nil
elseif #services_queried > 0 then
stdnse.debug1("%s Error in output(): No data found - could not understand query responses.", ip )
stdnse.debug1("Error in output(): No data found - could not understand query responses.")
return nil
end
@@ -1239,7 +1236,7 @@ function get_output_from_cache( ip )
local ip_key = get_cache_key( ip )
if not ip_key then
stdnse.debug1("%s Error in get_output_from_cache().", ip )
stdnse.debug1("Error in get_output_from_cache().")
return nil
end
@@ -1711,7 +1708,7 @@ function get_args()
nmap.registry.whois.using_cache = false
elseif ( db == "nofile" ) then
nmap.registry.whois.using_local_assignments_file = false
stdnse.debug2("Not using local assignments data." )
stdnse.debug2("Not using local assignments data.")
end
elseif not ( string.match( table.concat( t, " " ), db ) ) then
-- we have a unique valid whois db
@@ -1728,12 +1725,12 @@ function get_args()
if ( #t > 1 ) and nmap.registry.whois.nofollow then
-- using nofollow, we do not follow redirects and can only accept what we find as a record therefore we only accept the first db supplied
t = {t[1]}
stdnse.debug1("Too many args supplied with 'nofollow', only using %s.", t[1] )
stdnse.debug1("Too many args supplied with 'nofollow', only using %s.", t[1])
end
if ( #t > 0 ) then
nmap.registry.whois.whoisdb_default_order = t
stdnse.debug2("whoisdb_default_order: %s.", table.concat( t, " " ) )
stdnse.debug2("whoisdb_default_order: %s.", table.concat( t, " " ))
end
end
@@ -1762,7 +1759,7 @@ function get_local_assignments_data()
local fetchfile = "nmap-services"
local directory_path, err = get_parentpath( fetchfile )
if err then
stdnse.debug1("Nmap.fetchfile() failed to get a path to %s: %s.", fetchfile, err )
stdnse.debug1("Nmap.fetchfile() failed to get a path to %s: %s.", fetchfile, err)
return nil, err
end
@@ -1778,10 +1775,10 @@ function get_local_assignments_data()
local file, exists = directory_path .. assignment_data_spec.local_resource
exists, err = file_exists( file )
if not exists and err then
stdnse.debug1("Error accessing %s: %s.", file, err )
stdnse.debug1("Error accessing %s: %s.", file, err)
elseif not exists then
update_required = true
stdnse.debug2("%s does not exist or is empty. Fetching it now...", file )
stdnse.debug2("%s does not exist or is empty. Fetching it now...", file)
elseif exists then
update_required, modified_date, entity_tag = requires_updating( file )
end
@@ -1790,7 +1787,7 @@ function get_local_assignments_data()
-- read an existing and up-to-date file into file_content.
if exists and not update_required then
stdnse.debug2("%s was cached less than %s ago. Reading...", file, nmap.registry.whois.local_assignments_file_expiry )
stdnse.debug2("%s was cached less than %s ago. Reading...", file, nmap.registry.whois.local_assignments_file_expiry)
file_content = read_from_file( file )
end
@@ -1799,10 +1796,10 @@ function get_local_assignments_data()
if update_required then
http_response = ( conditional_download( assignment_data_spec.remote_resource, modified_date, entity_tag ) )
if not http_response or type( http_response.status ) ~= "number" then
stdnse.debug1("Failed whilst requesting %s.", assignment_data_spec.remote_resource )
stdnse.debug1("Failed whilst requesting %s.", assignment_data_spec.remote_resource)
elseif http_response.status == 200 then
-- prepend our file header
stdnse.debug2("Retrieved %s.", assignment_data_spec.remote_resource )
stdnse.debug2("Retrieved %s.", assignment_data_spec.remote_resource)
file_content = stdnse.strsplit( "\r?\n", http_response.body )
table.insert( file_content, 1, "** Do Not Alter This Line or The Following Line **" )
local hline = {}
@@ -1814,19 +1811,19 @@ function get_local_assignments_data()
table.insert( file_content, 2, table.concat( hline ) )
write_success, err = write_to_file( file, file_content )
if err then
stdnse.debug1("Error writing %s to %s: %s.", assignment_data_spec.remote_resource, file, err )
stdnse.debug1("Error writing %s to %s: %s.", assignment_data_spec.remote_resource, file, err)
end
elseif http_response.status == 304 then
-- update our file header with a new timestamp
stdnse.debug1("%s is up-to-date.", file )
stdnse.debug1("%s is up-to-date.", file)
file_content = read_from_file( file )
file_content[2] = file_content[2]:gsub("^<[-+]?%d+>(.*)$", "<" .. os.time() .. ">%1")
write_success, err = write_to_file( file, file_content )
if err then
stdnse.debug1("Error writing to %s: %s.", file, err )
stdnse.debug1("Error writing to %s: %s.", file, err)
end
else
stdnse.debug1("HTTP %s whilst requesting %s.", http_response.status, assignment_data_spec.remote_resource )
stdnse.debug1("HTTP %s whilst requesting %s.", http_response.status, assignment_data_spec.remote_resource)
end
end
@@ -1840,7 +1837,7 @@ function get_local_assignments_data()
if #t == 0 or err then
-- good header, but bad file? Kill the file!
write_to_file( file, "" )
stdnse.debug1("Problem with the data in %s.", file )
stdnse.debug1("Problem with the data in %s.", file)
else
for i, v in pairs( t ) do
ret[address_family][#ret[address_family]+1] = v
@@ -1859,7 +1856,7 @@ function get_local_assignments_data()
for af, t in pairs( ret ) do
if #t == 0 then
ret[af] = nil
stdnse.debug1("Cannot use local assignments file for address family %s.", af )
stdnse.debug1("Cannot use local assignments file for address family %s.", af)
end
end
@@ -1983,7 +1980,7 @@ function read_from_file( file )
local f, err, _ = io.open( file, "r" )
if not f then
stdnse.debug1("Error opening %s for reading: %s", file, err )
stdnse.debug1("Error opening %s for reading: %s", file, err)
return nil, err
end
@@ -2043,7 +2040,7 @@ function conditional_download( url, mod_date, e_tag )
and ( tostring( request_response.status ):match( "30%d" )
and type( request_response.header.location ) == "string"
and request_response.header.location ~= "" ) then
stdnse.debug2("HTTP Status:%d New Location: %s.", request_response.status, request_response.header.location )
stdnse.debug2("HTTP Status:%d New Location: %s.", request_response.status, request_response.header.location)
request_response = http.get_url( request_response.header.location, request_options )
end
@@ -2072,7 +2069,7 @@ function write_to_file( file, content )
local f, err, _ = io.open( file, "w" )
if not f then
stdnse.debug1("Error opening %s for writing: %s.", file, err )
stdnse.debug1("Error opening %s for writing: %s.", file, err)
return nil, err
end