Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lua function check if ipv4 or ipv6 or string

I'd like to have a function that I can pass a whitespace trimmed string to and it will return
0 for error (not a string) 1 for ipv4 2 for ipv6 3 for a string thats not an ip.

Ipv6 has these rules:

Ipv6 is represented by 8 groups of 16-bit hexadecimal values separated by colons (:)
The hexadecimal digits are case-insensitive
Abbreviation rules:
1: Omit leading zeroes in a 16-bit value
2: Replace one or more groups of consecutive zeroes by a double colon

wiki example showing 3 ways that are all the same ipv6:

fe80:0000:0000:0000:0202:b3ff:fe1e:8329
fe80:0:0:0:202:b3ff:fe1e:8329
fe80::202:b3ff:fe1e:8329 

I'm reasonably sure for ipv4 you just check for three . then check the string is all
numbers and the .'s are counted as numbers and the last check for just a string
would be at the end of an if statement so if its not ipv4/6 and its a string then
it returns 3

like image 858
Col_Blimp Avatar asked Jun 11 '12 07:06

Col_Blimp


People also ask

How to check if a value is a string in Lua?

there is a function in lua called type, you can use it like type (value) == "number" and this will only be true if value is a number. if this solved your problem you should not be asking "how to check wether a value is a string" as you obviously wanted to know wether a string contains a digit. if that solved your problem.

How do you check if a string is an IPv4 address?

If the given string S is a valid IPv4, then print “IPv4”, if the string S is a valid IPv6, then print “IPv4”. Otherwise, print “-1”. A valid IPv4 address is an IP in the form “x 1.x 2.x 3.x 4 ” where 0 ≤ x i ≤ 255 and x i cannot contain leading zeros.

What is if statement in Lua programming language?

If statement in Lua is just like other programming languages including C, C++, Python. If a statement is very important while programming as it leverages the option of creating a condition where the coder can derive two outputs for the true and false results respectively. In this article, if the statement is explained in detail with examples.

What is a valid IPv6 address for a string?

A valid IPv6 address is an IP in the form “x 1 : x 2 : x 3 : x 4 : x 5 : x 6 : x 7 : x 8 ” where: x i is a hexadecimal string which may contain digits, lower-case English letter (‘a’ to ‘f’) and upper-case English letters (‘A’ to ‘F’).


1 Answers

Mike's solution is good, but it can be improved on in several ways. In its current form it doesn't get to ipv6 address check, but it's easy to fix. The ipv6 check fails on things like "1050!0!0+0-5@600$300c#326b" and "1050:0:0:0:5:600:300c:326babcdef" (recognizing both as valid addresses) and "1050:::600:5:1000::" (recognizing it as string).

Here is the improved version (IPv4 are assumed to be decimal numbers and IPv6 are assumed to be hexadecimal numbers):

function GetIPType(ip)
  local R = {ERROR = 0, IPV4 = 1, IPV6 = 2, STRING = 3}
  if type(ip) ~= "string" then return R.ERROR end

  -- check for format 1.11.111.111 for ipv4
  local chunks = {ip:match("^(%d+)%.(%d+)%.(%d+)%.(%d+)$")}
  if #chunks == 4 then
    for _,v in pairs(chunks) do
      if tonumber(v) > 255 then return R.STRING end
    end
    return R.IPV4
  end

  -- check for ipv6 format, should be 8 'chunks' of numbers/letters
  -- without leading/trailing chars
  -- or fewer than 8 chunks, but with only one `::` group
  local chunks = {ip:match("^"..(("([a-fA-F0-9]*):"):rep(8):gsub(":$","$")))}
  if #chunks == 8
  or #chunks < 8 and ip:match('::') and not ip:gsub("::","",1):match('::') then
    for _,v in pairs(chunks) do
      if #v > 0 and tonumber(v, 16) > 65535 then return R.STRING end
    end
    return R.IPV6
  end

  return R.STRING
end

The script to check:

local IPType = {[0] = "Error", "IPv4", "IPv6", "string"}
local ips = {
    "128.1.0.1", -- ipv4
    "223.255.254.254", -- ipv4
    "999.12345.0.0001", -- invalid ipv4
    "1050:0:0:0:5:600:300c:326b", -- ipv6
    "1050!0!0+0-5@600$300c#326b", -- string
    "1050:0:0:0:5:600:300c:326babcdef", -- string
    "1050:0000:0000:0000:0005:0600:300c:326b", -- ipv6
    "fe80:0000:0000:0000:0202:b3ff:fe1e:8329", -- ipv6
    "fe80:0:0:0:202:b3ff:fe1e:8329", -- ipv6
    "fe80::202:b3ff:fe1e:8329", -- ipv6
    "1050:::600:5:1000::", -- contracted ipv6
    "::", -- ipv6
    "::1", -- ipv6
    "::1::", -- string
    "129.garbage.9.1", -- string
    "xxx127.0.0.0", -- error
    "xxx1050:0000:0000:0000:0005:0600:300c:326b", -- string
    129.10 -- error
}
for k,v in pairs(ips) do
    print(v, IPType[GetIPType(v)])
end

And the output:

128.1.0.1   IPv4
223.255.254.254 IPv4
999.12345.0.0001    string
1050:0:0:0:5:600:300c:326b  IPv6
1050!0!0+0-5@600$300c#326b  string
1050:0:0:0:5:600:300c:326babcdef    string
1050:0000:0000:0000:0005:0600:300c:326b IPv6
fe80:0000:0000:0000:0202:b3ff:fe1e:8329 IPv6
fe80:0:0:0:202:b3ff:fe1e:8329   IPv6
fe80::202:b3ff:fe1e:8329    IPv6
1050:::600:5:1000:: IPv6
::  IPv6
::1 IPv6
::1::   string
129.garbage.9.1 string
xxx127.0.0.0    string
xxx1050:0000:0000:0000:0005:0600:300c:326b  string
129.1   Error

Updated on 9/6/2018 to add handling of garbage before/after addresses and checking for contracted ipv6, which allows for fewer than 8 groups with one empty group of two consecutive colons.

like image 63
Paul Kulchenko Avatar answered Jan 04 '23 04:01

Paul Kulchenko