local creds = require "creds"
local redis = require "redis"
local nmap = require "nmap"
local shortport = require "shortport"
local stdnse = require "stdnse"
local table = require "table"

description = [[
Retrieves address list a Redis key-value store listens on.
]]

---
-- @usage
-- nmap -p 6379 <ip> --script redis-bind
--
-- @output
-- PORT     STATE SERVICE
-- 6379/tcp open  redis
-- | redis-bind: 
-- |   127.0.0.1
-- |   127.0.0.2
-- |   127.0.0.3
-- |_  192.168.100.6
--

author = "Vasily Kulikov"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"discovery", "safe"}
dependencies = {"redis-brute"}


portrule = shortport.port_or_service(6379, "redis")

local function fail(err) return stdnse.format_output(false, err) end

action = function(host, port)

  local helper = redis.Helper:new(host, port)
  local status = helper:connect()
  if( not(status) ) then
    return fail("Failed to connect to server")
  end

  -- do we have a service password
  local c = creds.Credentials:new(creds.ALL_DATA, host, port)
  local cred = c:getCredentials(creds.State.VALID + creds.State.PARAM)()

  if ( cred and cred.pass ) then
    local status, response = helper:reqCmd("AUTH", cred.pass)
    if ( not(status) ) then
      helper:close()
      return fail(response)
    end
  end

  local status, response = helper:reqCmd("CONFIG", "GET", "bind")
  if ( not(status) ) then
    helper:close()
    return fail(response)
  end
  helper:close()

  if ( redis.Response.Type.ERROR == response.type ) then
    if ( "-ERR operation not permitted" == response.data ) or
        ( "-NOAUTH Authentication required." == response.data ) then
      return fail("Authentication required")
    end
    return fail(response.data)
  end
  stdnse.debug2("%s", response.data[2])

  local restab = stdnse.strsplit(" ", response.data[2])
  if ( not(restab) or 0 == #restab ) then
    return fail("Failed to parse response from server")
  end

  local ips = {}
  for _, ip in ipairs(restab) do
    stdnse.debug1("ip=%s", ip)
    if ip == '' then ip = '0.0.0.0' end
    table.insert(ips, ip)
  end

  return stdnse.format_output(true, ips)
end

