home *** CD-ROM | disk | FTP | other *** search
/ Hackers Magazine 57 / CdHackersMagazineNr57.iso / Software / Networking / nmap-5.00-setup.exe / nselib / ipOps.lua < prev    next >
Text File  |  2009-07-06  |  16KB  |  531 lines

  1. --- Utility functions for manipulating and comparing IP addresses.
  2. -- @copyright Same as Nmap--See http://nmap.org/book/man-legal.html
  3.  
  4. local type     = type
  5. local table    = table
  6. local string   = string
  7. local ipairs   = ipairs
  8. local tonumber = tonumber
  9.  
  10. local stdnse   = require "stdnse"
  11.  
  12. module ( "ipOps" )
  13.  
  14.  
  15.  
  16. ---
  17. -- Checks to see if the supplied IP address is part of a non-routable
  18. -- address space.
  19. --
  20. -- The non-Internet-routable address spaces known to this function are
  21. -- * IPv4 Loopback (RFC3330)
  22. -- * IPv4 Private Use (RFC1918)
  23. -- * IPv4 Link Local (RFC3330)
  24. -- * IPv6 Unspecified and Loopback (RFC3513)
  25. -- * IPv6 Unique Local Unicast (RFC4193)
  26. -- * IPv6 Link Local Unicast (RFC4291)
  27. -- @param ip  String representing an IPv4 or IPv6 address.  Shortened notation
  28. -- is permitted.
  29. -- @usage
  30. -- local is_private = ipOps.isPrivate( "192.168.1.1" )
  31. -- @return True or false (or <code>nil</code> in case of an error).
  32. -- @return String error message in case of an error.
  33. isPrivate = function( ip )
  34.  
  35.   ip, err = expand_ip( ip )
  36.   if err then return nil, err end
  37.  
  38.   local ipv4_private = { "10/8", "127/8", "169.254/16", "172.15/12", "192.168/16" }
  39.   local ipv6_private = { "::/127", "FC00::/7", "FE80::/10" }
  40.   local t, is_private = {}
  41.   if ip:match( ":" ) then
  42.     t = ipv6_private
  43.   else
  44.     t = ipv4_private
  45.   end
  46.  
  47.   for _, range in ipairs( t ) do
  48.     is_private, err = ip_in_range( ip, range )
  49.     -- return as soon as is_private is true or err
  50.     if is_private then return true end
  51.     if err then return nil, err end
  52.   end
  53.   return false
  54.  
  55. end
  56.  
  57.  
  58.  
  59. ---
  60. -- Converts the supplied IPv4 address into a DWORD value.
  61. --
  62. -- For example, the address a.b.c.d becomes (((a*256+b)*256+c)*256+d).
  63. --
  64. -- Note: IPv6 addresses are not supported. Currently, numbers in NSE are
  65. -- limited to 10^14, and consequently not all IPv6 addresses can be
  66. -- represented.
  67. -- @param ip  String representing an IPv4 address.  Shortened notation is
  68. -- permitted.
  69. -- @usage
  70. -- local dword = ipOps.todword( "73.150.2.210" )
  71. -- @return Number corresponding to the supplied IP address (or <code>nil</code>
  72. -- in case of an error).
  73. -- @return String error message in case of an error.
  74. todword = function( ip )
  75.  
  76.   if type( ip ) ~= "string" or ip:match( ":" ) then
  77.     return nil, "Error in ipOps.todword: Expected IPv4 address."
  78.   end
  79.  
  80.   local n, ret = {}
  81.   n, err = get_parts_as_number( ip )
  82.   if err then return nil, err end
  83.  
  84.   ret = (((n[1]*256+n[2]))*256+n[3])*256+n[4]
  85.  
  86.   return ret
  87.  
  88. end
  89.  
  90.  
  91.  
  92. ---
  93. -- Separates the supplied IP address into its constituent parts and
  94. -- returns them as a table of numbers.
  95. --
  96. -- For example, the address 139.104.32.123 becomes { 139, 104, 32, 123 }.
  97. -- @usage
  98. -- local a, b, c, d;
  99. -- local t, err = ipOps.get_parts_as_number( "139.104.32.123" )
  100. -- if t then a, b, c, d = unpack( t ) end
  101. -- @param ip  String representing an IPv4 or IPv6 address.  Shortened notation
  102. -- is permitted.
  103. -- @return   Array of numbers for each part of the supplied IP address (or
  104. -- <code>nil</code> in case of an error).
  105. -- @return String error message in case of an error.
  106. get_parts_as_number = function( ip )
  107.  
  108.   ip, err = expand_ip( ip )
  109.   if err then return nil, err end
  110.  
  111.   local pattern, base
  112.   if ip:match( ":" ) then
  113.     pattern = "%x+"
  114.     base = 16
  115.   else
  116.     pattern = "%d+"
  117.     base = 10
  118.   end
  119.   local t = {}
  120.   for part in string.gmatch(ip, pattern) do
  121.     t[#t+1] = tonumber( part, base )
  122.   end
  123.  
  124.   return t
  125.  
  126. end
  127.  
  128.  
  129.  
  130. ---
  131. -- Compares two IP addresses (from the same address family).
  132. -- @param left   String representing an IPv4 or IPv6 address.  Shortened
  133. -- notation is permitted.
  134. -- @param op     A comparison operator which may be one of the following
  135. -- strings: <code>"eq"</code>, <code>"ge"</code>, <code>"le"</code>,
  136. -- <code>"gt"</code> or <code>"lt"</code> (respectively ==, >=, <=, >, <).
  137. -- @param right  String representing an IPv4 or IPv6 address.  Shortened
  138. -- notation is permitted.
  139. -- @usage
  140. -- if ipOps.compare_ip( "2001::DEAD:0:0:0", "eq", "2001:0:0:0:DEAD::" ) then
  141. --   ...
  142. -- end
  143. -- @return True or false (or <code>nil</code> in case of an error).
  144. -- @return String error message in case of an error.
  145. compare_ip = function( left, op, right )
  146.  
  147.   if type( left ) ~= "string" or type( right ) ~= "string" then
  148.     return nil, "Error in ipOps.compare_ip: Expected IP address as a string."
  149.   end
  150.  
  151.   if ( left:match( ":" ) and not right:match( ":" ) ) or ( not left:match( ":" ) and right:match( ":" ) ) then
  152.     return nil, "Error in ipOps.compare_ip: IP addresses must be from the same address family."
  153.   end
  154.  
  155.   if op == "lt" or op == "le" then
  156.     left, right = right, left
  157.   elseif op ~= "eq" and op ~= "ge" and op ~= "gt" then
  158.     return nil, "Error in ipOps.compare_ip: Invalid Operator."
  159.   end
  160.  
  161.   local err ={}
  162.   left, err[#err+1] = ip_to_bin( left )
  163.   right, err[#err+1] = ip_to_bin( right )
  164.   if #err > 0 then
  165.     return nil, table.concat( err, " " )
  166.   end
  167.  
  168.   if string.len( left ) ~= string.len( right ) then
  169.       -- shouldn't happen...
  170.       return nil, "Error in ipOps.compare_ip: Binary IP addresses were of different lengths."
  171.   end
  172.  
  173.   -- equal?
  174.   if ( op == "eq" or op == "le" or op == "ge" ) and left == right then
  175.     return true
  176.   elseif op == "eq" then
  177.     return false
  178.   end
  179.  
  180.   -- starting from the leftmost bit, subtract the bit in right from the bit in left
  181.   local compare
  182.   for i = 1, string.len( left ), 1 do
  183.     compare = tonumber( string.sub( left, i, i ) ) - tonumber( string.sub( right, i, i ) )
  184.     if compare == 1 then
  185.       return true
  186.     elseif compare == -1 then
  187.       return false
  188.     end
  189.   end
  190.   return false
  191.  
  192. end
  193.  
  194.  
  195.  
  196. ---
  197. -- Checks whether the supplied IP address is within the supplied range of IP
  198. -- addresses.
  199. --
  200. -- The address and the range must both belong to the same address family.
  201. -- @param ip     String representing an IPv4 or IPv6 address.  Shortened
  202. -- notation is permitted.
  203. -- @param range  String representing a range of IPv4 or IPv6 addresses in
  204. -- first-last or CIDR notation (e.g.
  205. -- <code>"192.168.1.1 - 192.168.255.255"</code> or
  206. -- <code>"2001:0A00::/23"</code>).
  207. -- @usage
  208. -- if ipOps.ip_in_range( "192.168.1.1", "192/8" ) then ... end
  209. -- @return True or false (or <code>nil</code> in case of an error).
  210. -- @return String error message in case of an error.
  211. ip_in_range = function( ip, range )
  212.  
  213.   local first, last, err = get_ips_from_range( range )
  214.   if err then return nil, err end
  215.   ip, err = expand_ip( ip )
  216.   if err then return nil, err end
  217.   if ( ip:match( ":" ) and not first:match( ":" ) ) or ( not ip:match( ":" ) and first:match( ":" ) ) then
  218.     return nil, "Error in ipOps.ip_in_range: IP address is of a different address family to Range."
  219.   end
  220.  
  221.   err = {}
  222.   local ip_ge_first, ip_le_last
  223.   ip_ge_first, err[#err+1] = compare_ip( ip, "ge", first )
  224.   ip_le_last, err[#err+1] = compare_ip( ip, "le", last )
  225.   if #err > 0 then
  226.     return nil, table.concat( err, " " )
  227.   end
  228.  
  229.   if ip_ge_first and ip_le_last then
  230.     return true
  231.   else
  232.     return false
  233.   end
  234.  
  235. end
  236.  
  237.  
  238.  
  239. ---
  240. -- Expands an IP address supplied in shortened notation.
  241. -- Serves also to check the well-formedness of an IP address.
  242. --
  243. -- Note: IPv4in6 notated addresses will be returned in pure IPv6 notation unless
  244. -- the IPv4 portion is shortened and does not contain a dot, in which case the
  245. -- address will be treated as IPv6.
  246. -- @param ip  String representing an IPv4 or IPv6 address in shortened or full notation.
  247. -- @usage
  248. -- local ip = ipOps.expand_ip( "2001::" )
  249. -- @return    String representing a fully expanded IPv4 or IPv6 address (or
  250. -- <code>nil</code> in case of an error).
  251. -- @return String error message in case of an error.
  252. expand_ip = function( ip )
  253.  
  254.   if type( ip ) ~= "string" or ip == "" then
  255.     return nil, "Error in ipOps.expand_ip: Expected IP address as a string."
  256.   end
  257.  
  258.   local err4 = "Error in ipOps.expand_ip: An address assumed to be IPv4 was malformed."
  259.  
  260.   if not ip:match( ":" ) then
  261.     -- ipv4: missing octets should be "0" appended
  262.     if ip:match( "[^\.0-9]" ) then
  263.       return nil, err4
  264.     end
  265.     local octets = {}
  266.     for octet in string.gmatch( ip, "%d+" ) do
  267.       if tonumber( octet, 10 ) > 255 then return nil, err4 end
  268.       octets[#octets+1] = octet
  269.     end
  270.     if #octets > 4 then return nil, err4 end
  271.     while #octets < 4 do
  272.       octets[#octets+1] = "0"
  273.     end
  274.     return ( table.concat( octets, "." ) )
  275.   end
  276.  
  277.   if ip:match( "[^\.:%x]" ) then
  278.     return nil, ( err4:gsub( "IPv4", "IPv6" ) )
  279.   end
  280.  
  281.   -- preserve ::
  282.   ip = string.gsub(ip, "::", ":z:")
  283.  
  284.   -- get a table of each hexadectet
  285.   local hexadectets = {}
  286.   for hdt in string.gmatch( ip, "[\.z%x]+" ) do
  287.     hexadectets[#hexadectets+1] = hdt
  288.   end
  289.  
  290.   -- deal with IPv4in6 (last hexadectet only)
  291.   local t = {}
  292.   if hexadectets[#hexadectets]:match( "[\.]+" ) then
  293.     hexadectets[#hexadectets], err = expand_ip( hexadectets[#hexadectets] )
  294.     if err then return nil, ( err:gsub( "IPv4", "IPv4in6" ) ) end
  295.     t = stdnse.strsplit( "[\.]+", hexadectets[#hexadectets] )
  296.     for i, v in ipairs( t ) do
  297.       t[i] = tonumber( v, 10 )
  298.     end
  299.     hexadectets[#hexadectets] = stdnse.tohex( 256*t[1]+t[2] )
  300.     hexadectets[#hexadectets+1] = stdnse.tohex( 256*t[3]+t[4] )
  301.   end
  302.  
  303.   -- deal with :: and check for invalid address
  304.   local z_done = false
  305.   for index, value in ipairs( hexadectets ) do
  306.     if value:match( "[\.]+" ) then
  307.       -- shouldn't have dots at this point
  308.       return nil, ( err4:gsub( "IPv4", "IPv6" ) )
  309.     elseif value == "z" and z_done then
  310.       -- can't have more than one ::
  311.       return nil, ( err4:gsub( "IPv4", "IPv6" ) )
  312.     elseif value == "z" and not z_done then
  313.       z_done = true
  314.       hexadectets[index] = "0"
  315.       local bound = 8 - #hexadectets
  316.       for i = 1, bound, 1 do
  317.         table.insert( hexadectets, index+i, "0" )
  318.       end
  319.     elseif tonumber( value, 16 ) > 65535 then
  320.       -- more than FFFF!
  321.       return nil, ( err4:gsub( "IPv4", "IPv6" ) )
  322.     end
  323.   end
  324.  
  325.   -- make sure we have exactly 8 hexadectets
  326.   if #hexadectets > 8 then return nil, ( err4:gsub( "IPv4", "IPv6" ) ) end
  327.   while #hexadectets < 8 do
  328.     hexadectets[#hexadectets+1] = "0"
  329.   end
  330.  
  331.   return ( table.concat( hexadectets, ":" ) )
  332.  
  333. end
  334.  
  335.  
  336.  
  337. ---
  338. -- Returns the first and last IP addresses in the supplied range of addresses.
  339. -- @param range  String representing a range of IPv4 or IPv6 addresses in either
  340. -- CIDR or first-last notation.
  341. -- @usage
  342. -- first, last = ipOps.get_ips_from_range( "192.168.0.0/16" )
  343. -- @return       String representing the first address in the supplied range (or
  344. -- <code>nil</code> in case of an error).
  345. -- @return       String representing the last address in the supplied range (or
  346. -- <code>nil</code> in case of an error).
  347. -- @return       String error message in case of an error.
  348. get_ips_from_range = function( range )
  349.  
  350.   if type( range ) ~= "string" then
  351.     return nil, nil, "Error in ipOps.get_ips_from_range: Expected a range as a string."
  352.   end
  353.  
  354.   local first, last, prefix
  355.   if range:match( "/" ) then
  356.     first, prefix = range:match( "([%x%d:\.]+)/(%d+)" )
  357.   elseif range:match( "-" ) then
  358.     first, last = range:match( "([%x%d:\.]+)%s*\-%s*([%x%d:\.]+)" )
  359.   end
  360.  
  361.   local err = {}
  362.   if first and ( last or prefix ) then
  363.     first, err[#err+1] = expand_ip( first )
  364.   else
  365.     return nil, nil, "Error in ipOps.get_ips_from_range: The range supplied could not be interpreted."
  366.   end
  367.   if last then
  368.     last, err[#err+1] = expand_ip( last )
  369.   elseif first and prefix then
  370.     last, err[#err+1] = get_last_ip( first, prefix )
  371.   end
  372.  
  373.   if first and last then
  374.     if ( first:match( ":" ) and not last:match( ":" ) ) or ( not first:match( ":" ) and last:match( ":" ) ) then
  375.       return nil, nil, "Error in ipOps.get_ips_from_range: First IP address is of a different address family to last IP address."
  376.     end
  377.     return first, last
  378.   else
  379.     return nil, nil, table.concat( err, " " )
  380.   end
  381.  
  382. end
  383.  
  384.  
  385.  
  386. ---
  387. -- Calculates the last IP address of a range of addresses given an IP address in
  388. -- the range and prefix length for that range.
  389. -- @param ip      String representing an IPv4 or IPv6 address.  Shortened
  390. -- notation is permitted.
  391. -- @param prefix  Number or a string representing a decimal number corresponding
  392. -- to a prefix length.
  393. -- @usage
  394. -- last = ipOps.get_last_ip( "192.0.0.0", 26 )
  395. -- @return        String representing the last IP address of the range denoted
  396. -- by the supplied parameters (or <code>nil</code> in case of an error).
  397. -- @return String error message in case of an error.
  398. get_last_ip = function( ip, prefix )
  399.  
  400.   local first, err = ip_to_bin( ip )
  401.   if err then return nil, err end
  402.  
  403.   prefix = tonumber( prefix )
  404.   if not prefix or ( prefix < 0 ) or ( prefix > string.len( first ) ) then
  405.     return nil, "Error in ipOps.get_last_ip: Invalid prefix length."
  406.   end
  407.  
  408.   local hostbits = string.sub( first, prefix + 1 )
  409.   hostbits = string.gsub( hostbits, "0", "1" )
  410.   local last = string.sub( first, 1, prefix ) .. hostbits
  411.   last, err = bin_to_ip( last )
  412.   if err then return nil, err end
  413.   return last
  414.  
  415. end
  416.  
  417.  
  418.  
  419. ---
  420. -- Converts an IP address into a string representing the address as binary
  421. -- digits.
  422. -- @param ip  String representing an IPv4 or IPv6 address.  Shortened notation
  423. -- is permitted.
  424. -- @usage
  425. -- bit_string = ipOps.ip_to_bin( "2001::" )
  426. -- @return    String representing the supplied IP address as 32 or 128 binary
  427. -- digits (or <code>nil</code> in case of an error).
  428. -- @return    String error message in case of an error.
  429. ip_to_bin = function( ip )
  430.  
  431.   ip, err = expand_ip( ip )
  432.   if err then return nil, err end
  433.  
  434.   local t, mask = {}
  435.  
  436.   if not ip:match( ":" ) then
  437.     -- ipv4 string
  438.     for octet in string.gmatch( ip, "%d+" ) do
  439.       t[#t+1] = stdnse.tohex( tonumber(octet) )
  440.     end
  441.     mask = "00"
  442.   else
  443.     -- ipv6 string
  444.     for hdt in string.gmatch( ip, "%x+" ) do
  445.       t[#t+1] = hdt
  446.     end
  447.     mask = "0000"
  448.   end
  449.  
  450.   -- padding
  451.   for i, v in ipairs( t ) do
  452.     t[i] = mask:sub( 1, string.len( mask ) - string.len( v ) ) .. v
  453.   end
  454.  
  455.   return hex_to_bin( table.concat( t ) )
  456.  
  457. end
  458.  
  459.  
  460.  
  461. ---
  462. -- Converts a string of binary digits into an IP address.
  463. -- @param binstring  String representing an IP address as 32 or 128 binary
  464. -- digits.
  465. -- @usage
  466. -- ip = ipOps.bin_to_ip( "01111111000000000000000000000001" )
  467. -- @return           String representing an IP address (or <code>nil</code> in
  468. -- case of an error).
  469. -- @return           String error message in case of an error.
  470. bin_to_ip = function( binstring )
  471.  
  472.   if type( binstring ) ~= "string" or binstring:match( "[^01]+" ) then
  473.     return nil, "Error in ipOps.bin_to_ip: Expected string of binary digits."
  474.   end
  475.  
  476.   if string.len( binstring ) == 32 then
  477.     af = 4
  478.   elseif string.len( binstring ) == 128 then
  479.     af = 6
  480.   else
  481.     return nil, "Error in ipOps.bin_to_ip: Expected exactly 32 or 128 binary digits."
  482.   end
  483.  
  484.   t = {}
  485.   if af == 6 then
  486.     local pattern = string.rep( "[01]", 16 )
  487.     for chunk in string.gmatch( binstring, pattern ) do
  488.       t[#t+1] = stdnse.tohex( tonumber( chunk, 2 ) )
  489.     end
  490.     return table.concat( t, ":" )
  491.   end
  492.  
  493.   if af == 4 then
  494.     local pattern = string.rep( "[01]", 8 )
  495.     for chunk in string.gmatch( binstring, pattern ) do
  496.       t[#t+1] = tonumber( chunk, 2 ) .. ""
  497.     end
  498.     return table.concat( t, "." )
  499.   end
  500.  
  501. end
  502.  
  503.  
  504.  
  505. ---
  506. -- Converts a string of hexadecimal digits into the corresponding string of
  507. -- binary digits.
  508. --
  509. -- Each hex digit results in four bits. This function is really just a wrapper
  510. -- around <code>stdnse.tobinary</code>.
  511. -- @param hex  String representing a hexadecimal number.
  512. -- @usage
  513. -- bin_string = ipOps.hex_to_bin( "F00D" )
  514. -- @return     String representing the supplied number in binary digits (or
  515. -- <code>nil</code> in case of an error).
  516. -- @return     String error message in case of an error.
  517. hex_to_bin = function( hex )
  518.  
  519.   if type( hex ) ~= "string" or hex == "" or hex:match( "[^%x]+" ) then
  520.     return nil, "Error in ipOps.hex_to_bin: Expected string representing a hexadecimal number."
  521.   end
  522.  
  523.   local t, mask, binchar = {}, "0000"
  524.   for hexchar in string.gmatch( hex, "%x" ) do
  525.       binchar = stdnse.tobinary( tonumber( hexchar, 16 ) )
  526.       t[#t+1] = mask:sub( 1, string.len( mask ) - string.len( binchar ) ) .. binchar
  527.   end
  528.   return table.concat( t )
  529.  
  530. end
  531.