-- Her birini kapsayan minimum boyutlu IP adresi bloklarını hesaplayın -- Değişken olarak IPv4 veya IPv6 adresleri girilir. local bit32 = require('bit32') local Collection -- a table to hold items Collection = { add = function (self, item) if item ~= nil then self.n = self.n + 1 self[self.n] = item end end, join = function (self, sep) return table.concat(self, sep) end, remove = function (self, pos) if self.n > 0 and (pos == nil or (0 < pos and pos <= self.n)) then self.n = self.n - 1 return table.remove(self, pos) end end, sort = function (self, comp) table.sort(self, comp) end, new = function () return setmetatable({n = 0}, Collection) end } Collection.__index = Collection local function empty(text) -- Return true if text is nil or empty (assuming a string). return text == nil or text == '' end local timestamps = {} -- cache local function start_date(code, months) -- Return a timestamp string for a URL to list user contributions -- on and after the returned date. -- The code specifies the wanted format. -- For this module, only recent contributions are wanted, so the -- timestamp is today's date less the given number of months (1 to 12). local key = code .. months if not timestamps[key] then local date = os.date('!*t') -- today's UTC date local y, m, d = date.year, date.month, date.day -- full year, month (1-12), day (1-31) m = m - months if m <= 0 then m = m + 12 y = y - 1 end local limit = m == 2 and 28 or 30 if d > limit then d = limit -- good enough to ensure date is valid end timestamps['y-m-d' .. months] = string.format('%d-%02d-%02d', y, m, d) timestamps['ymdHMS' .. months] = string.format('%d%02d%02d000000', y, m, d) end return timestamps[key] or '' end local note_text = { range = '*Links for ranges show the contributions in the previous %s.', gadget = [=[ *<span id="need-gadget"></span>Contributions links for IPv6 ranges need the "<span style="color:green;">Allow /16, /24 and /27 – /32 CIDR ranges on Special:Contributions forms</span>" gadget enabled in [[Special:Preferences#mw-prefsection-gadgets|Special:Preferences]], and scripting enabled in the browser.]=], } local function make_note(strings, key) -- Record the fact that a particular note is needed, and return -- wikitext for a link to the note or '' if no link needed. if not strings.nonote then strings.notes = strings.notes or {} if not strings.notes[key] then if key == 'gadget' then strings.notes[key] = note_text[key] elseif key == 'range' then local when = 'month' if strings.months > 1 then when = strings.months .. ' months' end strings.notes[key] = string.format(note_text.range, when) else error('make_note: unexpected key') end end if key == 'gadget' then return ' [[#need-gadget|<sup>[note]</sup>]]' end end return '' end local function describe_total(total, isalloc) -- Return text describing given number of addresses or /64 allocations. if total <= 9999 then -- Can have fractions if total is the number of /64 allocations. if total < 9 then return (string.format('%.1f', total):gsub('%.0$', '')) end return string.format('%.0f', total) end if not isalloc then local alloc = 2^64 if total >= alloc then return describe_total(total / alloc, true) .. ' /64' end end total = total/1024 local suffix = 'K' if total >= 1024 then total = total/1024 suffix = 'M' if total >= 1024 then total = total/1024 suffix = 'G' if total > 64 then return '>64G' end end end return string.format('%.0f', total) .. suffix end local function describe_size(ipsize, size) -- Return text describing how many IPs are in a range with size = prefix length. local function numtext(n) if n <= 16 then return tostring(2^n) end if n <= 19 then return tostring(2^(n - 10)) .. 'K' end if n <= 29 then return tostring(2^(n - 20)) .. 'M' end if n <= 36 then return tostring(2^(n - 30)) .. 'G' end return '>64G' end local host = ipsize - size if host <= 32 then -- IPv4 or IPv6. return numtext(host) end -- Must be IPv6. if host <= 64 then local s = ({ [64] = '1', [63] = '50%', [62] = '25%', [61] = '12%', [60] = '6%', [59] = '3%', [58] = '2%' })[host] or '<1%' return s .. ' /64' end -- IPv6 with size < 64. return numtext(host - 64) .. ' /64' end local function ipv6_string(ip) -- Return a string equivalent to the given IPv6 address. local z1, z2 -- indices of run of zeros to be displayed as "::" local zstart, zcount for i = 1, 9 do -- Find left-most occurrence of longest run of two or more zeros. if i < 9 and ip[i] == 0 then if zstart then zcount = zcount + 1 else zstart = i zcount = 1 end else if zcount and zcount > 1 then if not z1 or zcount > z2 - z1 + 1 then z1 = zstart z2 = zstart + zcount - 1 end end zstart = nil zcount = nil end end local parts = Collection.new() for i = 1, 8 do if z1 and z1 <= i and i <= z2 then if i == z1 then if z1 == 1 or z2 == 8 then if z1 == 1 and z2 == 8 then return '::' end parts:add(':') else parts:add('') end end else parts:add(string.format('%x', ip[i])) end end return parts:join(':') end local function ip_string(ip) -- Return a string equivalent to given IP address (IPv4 or IPv6). if ip.n == 2 then -- IPv4. local parts = {} for i = 1, 2 do local w = ip[i] local q = i == 1 and 1 or 3 parts[q] = math.floor(w / 256) parts[q+1] = w % 256 end return table.concat(parts, '.') end return ipv6_string(ip) end -- Metatable for some operations on IP addresses. local ipmt = { __eq = function (lhs, rhs) -- Return true if values in numbered tables match. if lhs.n == rhs.n then for i = 1, lhs.n do if lhs[i] ~= rhs[i] then return false end end return true end return false end, __lt = function (lhs, rhs) -- Return true if lhs < rhs; for sort. if lhs.n == rhs.n then for i = 1, lhs.n do if lhs[i] ~= rhs[i] then return lhs[i] < rhs[i] end end return false end return lhs.n < rhs.n -- sort IPv4 before IPv6, although not needed end, } local function ipv4_address(ip_str) -- Return a collection of two 16-bit words (numbers) equivalent -- to the IPv4 address given as a quad-dotted string, or -- return nil if invalid. -- This representation is for compatibility with IPv6 addresses. local parts = Collection.new() local s = ip_str:match('^%s*(.-)%s*$') .. '.' for item in s:gmatch('(.-)%.') do parts:add(item) end if parts.n == 4 then for i, s in ipairs(parts) do if s:match('^%d+$') then local num = tonumber(s) if 0 <= num and num <= 255 then if num > 0 and s:match('^0') then -- A redundant leading zero is an error because it is for an IP in octal. return nil end parts[i] = num else return nil end else return nil end end local result = Collection.new() for i = 1, 3, 2 do result:add(parts[i] * 256 + parts[i+1]) end return setmetatable(result, ipmt) end return nil end local function ipv6_address(ip_str) -- Return a collection of eight 16-bit words (numbers) equivalent -- to the IPv6 address given as a colon-delimited string, or -- return nil if invalid. local _, n = ip_str:gsub(':', ':') if n < 7 then ip_str, n = ip_str:gsub('::', string.rep(':', 9 - n)) end local parts = Collection.new() for item in (ip_str .. ':'):gmatch('(.-):') do parts:add(item) end if parts.n == 8 then for i, s in ipairs(parts) do if s == '' then parts[i] = 0 else local num = tonumber('0x' .. s) if num and 0 <= num and num <= 65535 then parts[i] = num else return nil end end end return setmetatable(parts, ipmt) end return nil end local function common_length(num1, num2, nr_bits) -- Return number of prefix bits that two integers have in common. -- Number of bits in each number is nr_bits = 16, 8, 4, 2 or 1. if nr_bits <= 1 then return num1 == num2 and 1 or 0 end local half = nr_bits / 2 local splitter = 2^half local upper1, lower1 = math.modf(num1 / splitter) local upper2, lower2 = math.modf(num2 / splitter) if upper1 == upper2 then lower1 = math.floor(lower1 * splitter + 0.5) lower2 = math.floor(lower2 * splitter + 0.5) return half + common_length(lower1, lower2, half) end return common_length(upper1, upper2, half) end local function common_prefix_length(ip1, ip2) -- Return number of prefix bits that two IPs have in common. -- Caller ensures that both IPs are IPv4 or both are IPv6. local size = 0 for i = 1, ip1.n do local w1, w2 = ip1[i], ip2[i] if w1 == w2 then size = size + 16 else return size + common_length(w1, w2, 16) end end return size end local function ip_prefix(ip, length) -- Return a copy of ip masked to contain only the prefix of given length. local result = { n = ip.n } for i = 1, ip.n do if length > 0 then if length >= 16 then result[i] = ip[i] length = length - 16 else result[i] = bit32.band(ip[i], bit32.arshift(0xffff8000, length - 1)) length = 0 end else result[i] = 0 end end return setmetatable(result, ipmt) end local function ip_incremented(ip) -- Return a new IP equal to ip + 1. -- Will wraparound (255.255.255.255 + 1 = 0.0.0.0)! local result = { n = ip.n } local carry = 1 for i = ip.n, 1, -1 do local sum = ip[i] + carry if sum >= 0x10000 then carry = 1 sum = sum - 0x10000 else carry = 0 end result[i] = sum end return setmetatable(result, ipmt) end local function is_next_ip(ip1, ip2) -- Return true if ip2 is the next IP after ip1 (ip2 == ip1 + 1). -- IPs are sorted and unique so ip1 < ip2 and can ignore wrapping to zero. -- This is lower overhead than making a new incremented IP then comparing. if ip1 and ip2 then local carry = 1 for i = ip1.n, 1, -1 do local sum = ip1[i] + carry if sum >= 0x10000 then carry = 1 sum = sum - 0x10000 else carry = 0 end if sum ~= ip2[i] then return false end end return true end end -- Each IP in a range except for the last IP has a 'common' field which is -- a number specifying how many bits are common between the prefixes of this -- IP and the next IP (0 if this IP starts with 0 and the next starts with 1). -- Each non-empty range has exactly one "minimum common", that is, its value -- of common is smaller than all others. That there is only one minimum common -- follows from the fact that the IPs are unique and sorted. local function make_range(iplist, ifirst, ilast) -- Return a table for the range of IPs from iplist[ifirst] to iplist[ilast] inclusive. local imin, vmin, done if ifirst < ilast then for i = ifirst, ilast - 1 do -- Find the (unique) minimum of common lengths. local common = iplist[i].common if vmin then if vmin > common then vmin = common imin = i end else vmin = common imin = i end end else vmin = iplist.ipsize imin = ifirst done = true end if vmin > iplist.allocation then -- For IPv6, the default allocation is /64 and there is no point having -- more precise ranges as they add unnecessary complexity. -- However, using results=all sets allocation = 128 so vmin is not changed. vmin = iplist.allocation end return { ifirst = ifirst, -- index of first IP ilast = ilast, -- index of last IP imin = imin, -- index of IP with minimum common size = vmin, -- number of common bits in prefix (the minimum) prefix = ip_prefix(iplist[imin], vmin), -- IP table of the base IP done = done, -- true if know that this range cannot be improved } end local function split_range(iplist, range, depth) -- Return a table of two or more ranges that more precisely target -- the IPs in range, or return nothing if unable to improve range. depth = depth and depth + 1 or 0 if depth <= 20 and -- 20 examines 1M contiguous addresses down to individual IPs not range.done and range.size < iplist.allocation and range.ifirst < range.ilast then local imin = range.imin assert(imin and range.ifirst <= imin and imin < range.ilast) local r1 = make_range(iplist, range.ifirst, range.imin) local r2 = make_range(iplist, range.imin + 1, range.ilast) local pointless = range.size + 1 if r1.size > pointless or r2.size > pointless then return { r1, r2 } end local result = Collection.new() local function store_split(range) local split = split_range(iplist, range, depth) if split then for _, r in ipairs(split) do result:add(r) end return true else result:add(range) end end local improved1 = store_split(r1) local improved2 = store_split(r2) if improved1 or improved2 then return result end end range.done = true end local function better_summary(iplist, summary) -- Return a better summary that more precisely targets the specified IPs, -- or return nil if unable to improve the summary. local better = Collection.new() local improved for _, range in ipairs(summary) do local split = split_range(iplist, range) if split then improved = true for _, r in ipairs(split) do better:add(r) end else better:add(range) end end return improved and better end local function make_summaries(iplist) -- Return a collection where each item is a summary. -- A summary is a table of one or more ranges. -- A summary covers all the given IPs and probably more. -- A range is a table representing a CIDR block such as 1.2.248.0/21. -- The first summary found is a single range; each subsequent summary -- (if any) uses more ranges to better target the given IPs. -- The result omits any summary with a range size that is too small (too many IPs). local function good_size(summary) for _, range in ipairs(summary) do if range.size < iplist.minsize then return false end end return true end local summaries = Collection.new() if iplist.n > 0 then for i = 1, iplist.n - 1 do -- Set length of prefixes common between each pair of IPs. iplist[i].common = common_prefix_length(iplist[i], iplist[i+1]) end local summary = { make_range(iplist, 1, iplist.n) } while summary and summaries.n < iplist.maxresults do if good_size(summary) then summaries:add(summary) end summary = better_summary(iplist, summary) end end return summaries end local function extract_ipv4(result, omitted, line) -- Extract any IPv4 addresses from given line or throw error. -- Accept CIDR /n to specify a range (only accept 16 to 32). -- Addresses must be delimited with whitespace to reduce false positives. local function store(hit) local n = 32 local lhs, rhs = hit:match('^(.-)/(%d+)$') if lhs then hit = lhs n = tonumber(rhs) if not (n and 16 <= n and n <= 32) then error('CIDR /n only accepts n = 16 to 32, invalid: ' .. lhs .. '/' .. rhs, 0) end end local ip = ipv4_address(hit) if ip then if n == 32 then result:add(ip) else if ip ~= ip_prefix(ip, n) then error('Invalid base address (host bits should be zero): ' .. hit, 0) end for _ = 1, 2^(32 - n) do result:add(ip) ip = ip_incremented(ip) end end else omitted:add(hit) end end line = line:gsub(':', ' ') -- so wikitext indents or other colons don't obscure an IVp4 address for hit in line:gmatch('%S+') do if hit:match('^%d+%.%d+[%.%d/]+$') then local _, n = hit:gsub('%.', '.') if n >= 3 then store(hit) end end end end local function extract_ipv6(result, omitted, line) -- Extract any IPv6 addresses from given line or throw error. -- Addresses must be delimited with whitespace to reduce false positives. -- Want to accept all valid IPv6 despite the fact that contributors will -- not have an address starting with ':'. -- Also want to be able to parse arbitrary wikitext which might use colons -- for indenting. To achieve that, if an address at the start of a line -- is valid, use it; otherwise strip any leading colons and try again. for pos, hit in line:gmatch('()(%S+)') do local ipstr, length = hit:match('^([:%x]+)(/?%d*)$') if ipstr then local _, n = ipstr:gsub(':', ':') if n >= 2 then local ip = ipv6_address(ipstr) if not ip and pos == 1 then ipstr, n = ipstr:gsub('^:+', '') if n > 0 then ip = ipv6_address(ipstr) end end if ip then if length and #length > 0 then error('CIDR /n not accepted for IPv6: ' .. hit, 0) end result:add(ip) else omitted:add(hit) end end end end end local function contribs(address, strings, ipbase, size) -- Return a URL or wikilink to list the contributions for an IP or IP range, -- or return an empty string if cannot do anything useful. -- The given address is a string of either a single IP or a CIDR range. -- If using old system: -- For IPv6 CIDR, return a Special:Contributions link using an asterisk -- wildcard which should work if the user has enabled the gadget -- "Allow /16, /24 and /27 – /32 CIDR ranges on Special:Contributions". local encoded, count = address:gsub('/', '%%2F') if strings.want_old and count > 0 then make_note(strings, 'range') if address:find(':', 1, true) then if ipbase and size then local digits = math.floor(size / 4) if digits < 3 then digits = 3 end local wildcard = digits % 4 == 0 and ':*' or '*' local parts = {} for i = 1, 8 do local hex = string.format('%X', ipbase[i]) -- must be uppercase if digits >= 4 then parts[i] = hex digits = digits - 4 if digits <= 0 then break end else local nz -- number of leading zeros in this group of four digits if hex == '0' then nz = 4 else nz = 4 - #hex end if digits <= nz then -- Cannot properly handle this case; have to omit group -- because "0" never occurs as the first digit. wildcard = ':*' else hex = string.rep('0', nz) .. hex -- four digits parts[i] = hex:sub(1, digits) end break end end address = table.concat(parts, ':') .. wildcard local url = '[https://en.wikipedia.org/wiki/Special:Contributions/%s?ucstart=%s c]' -- %s = IPv6 prefix address in uppercase with '*' wildcard at end -- %s = Start date formatted 'yyyymmdd000000' return string.format(url, address, start_date('ymdHMS', strings.months)) .. make_note(strings, 'gadget') end return '' -- no contributions link available end local url = '[https://tools.wmflabs.org/xtools/rangecontribs/?project=en.wikipedia.org&namespace=all&limit=50&text=%s&begin=%s c]' -- %s = IPv4 CIDR range with '/' changed to '%2F' -- %s = Start date formatted 'yyyy-mm-dd' return string.format(url, encoded, start_date('y-m-d', strings.months)) end return '[[Special:Contributions/' .. address .. '|c]]' end -- Strings for results using plain text. -- The pre tags used are html which do not provide "nowiki", -- but that is not required by the text used. local plaintext = { header = [=[ <pre> Total Affected Given Range]=], footer = '</pre>', sumfirst = [=[ ---------------------------------------------------------- %s%-12s %-12s %-11d %s%s]=], -- %s = empty string (dummy for compatibility) -- %s = total affected -- %s = affected -- %d = given (number of addresses given in input covered by this range) -- %s = IP address range -- %s = empty string sumnext = [=[ %-12s %-11d %s%s]=], -- %s = affected -- %d = given -- %s = IP address range -- %s = empty string } -- Strings for results using a table in wikitext. local wikitable = { header = [=[ {| class="wikitable" ! Total<br />affected !! Affected<br />addresses !! Given<br />addresses !! Range !! Contribs]=], footer = '|}', sumfirst = [=[ |- style="background: darkgray; height: 6px;" |colspan="5" | |- style="vertical-align: top;" |rowspan="%s" |%s ||%s ||%d ||%s ||%s]=], -- %s = string of number of ranges in summary (number of rows) -- %s = total affected -- %s = affected -- %d = given -- %s = IP address range -- %s = contributions link sumnext = [=[ |- |%s ||%d ||%s ||%s]=], -- %s = affected -- %d = given -- %s = IP address range -- %s = contributions link } local function show_summary(lines, strings, iplist, summary) -- Show the summary by adding table wikitext or plain text to lines. local want_plain = iplist.want_plain local total = 0 for _, range in ipairs(summary) do -- A number is a double which easily handles 2^128 = 3.4e38. total = total + 2^(iplist.ipsize - range.size) end for i, range in ipairs(summary) do local prefix = ip_string(range.prefix) local size = range.size local affected = describe_size(iplist.ipsize, size) local given = range.ilast - range.ifirst + 1 local address local link = '' if size == iplist.ipsize then address = prefix if not want_plain then link = contribs(address, strings) end else address = prefix .. '/' .. size if not want_plain then link = contribs(address, strings, range.prefix, size) end end local s if i == 1 then s = string.format(strings.sumfirst, want_plain and '' or tostring(#summary), describe_total(total), affected, given, address, link) else s = string.format(strings.sumnext, affected, given, address, link) end -- Pre tags returned by a module are html tags, not like wikitext <pre>...</pre>. lines:add(want_plain and mw.text.nowiki(s) or s) end end local function process_ips(lines, iplist, omitted) -- Process a list of IP addresses, adding text of results to lines. -- The list should contain either all IPv4 addresses, or all IPv6 (not a mixture). local seq1, seq2, seqmany local function show_sequence() if seq1 and seq2 then local text = ip_string(seq1) if seqmany then seqmany = false text = text .. ' – ' .. ip_string(seq2) end seq1 = nil seq2 = nil local markup = text:sub(1, 1) == ':' and ':<nowiki/>' or ':' lines:add(markup .. text) end end local function show_ip(ip) -- Show IP or record it to be included in a "from to" sequence of IPs. if is_next_ip(seq2, ip) then seq2 = ip seqmany = true else show_sequence() seq1 = ip seq2 = ip seqmany = false end end if iplist.n < 1 then return end if lines.n > 0 then lines:add('') end if omitted.n > 0 then lines:add('Warning, omitted as invalid: ' .. omitted:join(' ')) lines:add('') end local heading_line if not iplist.nolist then lines:add('') -- this blank line is replaced with a heading heading_line = lines.n end local duplicates = Collection.new() local previous iplist:sort() -- Check for duplicates which can interfere with method to get ranges. for i, ip in ipairs(iplist) do if previous == ip then duplicates:add(i) -- index to omit duplicate later elseif not iplist.nolist then show_ip(ip) end previous = ip end show_sequence() local duplicate_text = '' if duplicates.n > 0 then duplicate_text = ' (after omitting some duplicates)' for i = duplicates.n, 1, -1 do iplist:remove(duplicates[i]) end end local heading_text = string.format('Sorted %d %s address%s', iplist.n, iplist.ipname, iplist.n == 1 and '' or 'es' ) if heading_line then lines[heading_line] = heading_text .. duplicate_text .. ':' end local strings = iplist.want_plain and plaintext or wikitable strings.notes = nil -- needed when module is kept loaded for multiple tests strings.want_old = iplist.want_old strings.nonote = iplist.nonote strings.months = iplist.months lines:add(strings.header) local upto = lines.n for _, summary in ipairs(make_summaries(iplist)) do show_summary(lines, strings, iplist, summary) end lines:add(strings.footer) if upto + 1 == lines.n then -- Show message in the very unlikely event that no results are found. lines:add('----') lines:add('No suitable ranges found; use <code>|results=all</code> to see all ranges.') end if strings.notes then lines:add('') lines:add("'''Notes'''") for _, key in ipairs({'range', 'gadget'}) do if strings.notes[key] then lines:add(strings.notes[key]) end end end end local function make_options(args) -- Return table of options from validated args or throw error. local options = {} if not empty(args.comment) then options.comment = args.comment end -- Parameter 'months' is only used if 'old' is also used. local months = math.floor(tonumber(args.months) or tonumber(args.month) or 1) if months < 1 then months = 1 elseif months > 12 then months = 12 end options.months = months -- silently ignore invalid input local allocation if not empty(args.allocation) then allocation = tonumber(args.allocation) if not (allocation and 48 <= allocation and allocation <= 128) then error('Invalid allocation "' .. args.allocation .. '" (should be 48 to 128; default is 64)', 0) end end local maxresults if not empty(args.results) then if args.results == 'all' then options.all = true allocation = allocation or 128 maxresults = 1000 else maxresults = tonumber(args.results) if not (maxresults and 1 <= maxresults and maxresults <= 100) then error('Invalid results "' .. args.results .. '" (should be 1 to 100)', 0) end end end options.allocation = allocation or 64 options.maxresults = maxresults or 10 local keywords = { -- Table of k, v strings. -- If an argument matches k, an option named v is set to true. ok = 'noannounce', old = 'want_old', nolist = 'nolist', nonote = 'nonote', text = 'text', } local want_old for i, arg in ipairs(args) do local flag = keywords[arg:match('^%s*(%w+)%s*$')] if flag then options[i] = 'skip' options[flag] = true if flag == 'want_old' then want_old = true end end end if not want_old then options.nonote = true end return options end local function _IPblock(args) -- Process given args; can be called from another module. -- Throw an error if need to report a problem. local options = make_options(args) local v4list, v4omitted = Collection.new(), Collection.new() local v6list, v6omitted = Collection.new(), Collection.new() v4list.ipsize = 32 v4list.ipname = 'IPv4' v6list.ipsize = 128 v6list.ipname = 'IPv6' v4list.allocation = 32 v6list.allocation = options.allocation if options.all then v4list.minsize = 0 v6list.minsize = 0 else v4list.minsize = 16 -- cannot block more IPs than /16 for IPv4 v6list.minsize = 19 -- or /19 for IPv6 ($wgBlockCIDRLimit) end for _, k in ipairs({'maxresults', 'months', 'want_old', 'nolist', 'nonote'}) do v4list[k] = options[k] v6list[k] = options[k] end if options.text then v4list.want_plain = true v6list.want_plain = true end for i, arg in ipairs(args) do if options[i] ~= 'skip' then for line in string.gmatch(arg .. '\n', '[\t ]*(.-)[\t\r ]*\n') do -- Skip line if is empty or a comment. if line ~= '' then local comment = options.comment if not (comment and line:sub(1, #comment) == comment) then line = line :gsub('Special:Contributions/', ' ') -- so input "Special:Contributions/1.2.3.4" works :gsub('Special:Contribs/', ' ') :gsub('[!"#&\'()+,%-;<=>?[%]_{|}]', ' ') -- replace accepted delimiters with a space :gsub('\226\128\142', ' ') -- replace LTR marks (U+200E) extract_ipv4(v4list, v4omitted, line) extract_ipv6(v6list, v6omitted, line) end end end end end if v4list.n < 1 and v6list.n < 1 then error('No valid IPv4 or IPv6 address in arguments', 0) end local lines = Collection.new() if not options.noannounce then -- 1: Commented out April 2016 as expired. -- 1: lines:add("'''Please see [[Template talk:Blockcalc#Version February 2016|this announcement]].'''") -- 2: Commented out December 2017 as expired. -- 2: lines:add("'''By default, links now use [[Special:Contributions]] per [[Template talk:IP range calculator#Version November 2017|this announcement]].'''") end process_ips(lines, v4list, v4omitted) process_ips(lines, v6list, v6omitted) return lines:join('\n') end local function IPblock(frame) -- Return wikitext to display the smallest IPv4 or IPv6 CIDR range that -- covers each address given in the arguments, or return error text. -- Input can have any mixture of IPs; IPv4 and IPv6 are processed separately. local ok, msg = pcall(_IPblock, frame:getParent().args) if ok then return msg end return '<strong class="error">Error: ' .. msg .. '</strong>' end local function sha1(frame) -- Return SHA-1 hash of first parameter. -- This is for use at [[User:Johnuniq/Security]] to generate hash of a password. local text = (frame.args[1] or ''):match("^%s*(.-)%s*$") if text ~= '' then return 'SHA-1 hash after removing any leading or trailing whitespace is <code>' .. mw.hash.hashValue('sha1', text) .. '</code>' end return 'Usage: <code>{{#invoke:IPblock|sha1|text}}</code> to display the SHA-1 hash of <code>text</code>.' end return { IPblock = IPblock, _IPblock = _IPblock, sha1 = sha1, }
wikipedia, wiki, viki, vikipedia, oku, kitap, kütüphane, kütübhane, ara, ara bul, bul, herşey, ne arasanız burada,hikayeler, makale, kitaplar, öğren, wiki, bilgi, tarih, yukle, izle, telefon için, turk, türk, türkçe, turkce, nasıl yapılır, ne demek, nasıl, yapmak, yapılır, indir, ücretsiz, ücretsiz indir, bedava, bedava indir, mp3, video, mp4, 3gp, jpg, jpeg, gif, png, resim, müzik, şarkı, film, film, oyun, oyunlar, mobil, cep telefonu, telefon, android, ios, apple, samsung, iphone, xiomi, xiaomi, redmi, honor, oppo, nokia, sonya, mi, pc, web, computer, bilgisayar
Modul belgelemesi olustur Bu Scribunto modulu icin bir belgeleme sayfasi olusturmak isteyebilirsiniz Kullanicilar denemelerini bu sablonun deneme tahtasi olustur yansitma ve test senaryosu olustur sayfalarinda yapabilirler Lutfen kategorileri alt sayfasina ekleyin Bu modul ile ilgili alt sayfalar icin buraya tiklayiniz Her birini kapsayan minimum boyutlu IP adresi bloklarini hesaplayin Degisken olarak IPv4 veya IPv6 adresleri girilir local bit32 require bit32 local Collection a table to hold items Collection add function self item if item nil then self n self n 1 self self n item end end join function self sep return table concat self sep end remove function self pos if self n gt 0 and pos nil or 0 lt pos and pos lt self n then self n self n 1 return table remove self pos end end sort function self comp table sort self comp end new function return setmetatable n 0 Collection end Collection index Collection local function empty text Return true if text is nil or empty assuming a string return text nil or text end local timestamps cache local function start date code months Return a timestamp string for a URL to list user contributions on and after the returned date The code specifies the wanted format For this module only recent contributions are wanted so the timestamp is today s date less the given number of months 1 to 12 local key code months if not timestamps key then local date os date t today s UTC date local y m d date year date month date day full year month 1 12 day 1 31 m m months if m lt 0 then m m 12 y y 1 end local limit m 2 and 28 or 30 if d gt limit then d limit good enough to ensure date is valid end timestamps y m d months string format d 02d 02d y m d timestamps ymdHMS months string format d 02d 02d000000 y m d end return timestamps key or end local note text range Links for ranges show the contributions in the previous s gadget lt span id need gadget gt lt span gt Contributions links for IPv6 ranges need the lt span style color green gt Allow 16 24 and 27 32 CIDR ranges on Special Contributions forms lt span gt gadget enabled in Special Preferences mw prefsection gadgets Special Preferences and scripting enabled in the browser local function make note strings key Record the fact that a particular note is needed and return wikitext for a link to the note or if no link needed if not strings nonote then strings notes strings notes or if not strings notes key then if key gadget then strings notes key note text key elseif key range then local when month if strings months gt 1 then when strings months months end strings notes key string format note text range when else error make note unexpected key end end if key gadget then return need gadget lt sup gt note lt sup gt end end return end local function describe total total isalloc Return text describing given number of addresses or 64 allocations if total lt 9999 then Can have fractions if total is the number of 64 allocations if total lt 9 then return string format 1f total gsub 0 end return string format 0f total end if not isalloc then local alloc 2 64 if total gt alloc then return describe total total alloc true 64 end end total total 1024 local suffix K if total gt 1024 then total total 1024 suffix M if total gt 1024 then total total 1024 suffix G if total gt 64 then return gt 64G end end end return string format 0f total suffix end local function describe size ipsize size Return text describing how many IPs are in a range with size prefix length local function numtext n if n lt 16 then return tostring 2 n end if n lt 19 then return tostring 2 n 10 K end if n lt 29 then return tostring 2 n 20 M end if n lt 36 then return tostring 2 n 30 G end return gt 64G end local host ipsize size if host lt 32 then IPv4 or IPv6 return numtext host end Must be IPv6 if host lt 64 then local s 64 1 63 50 62 25 61 12 60 6 59 3 58 2 host or lt 1 return s 64 end IPv6 with size lt 64 return numtext host 64 64 end local function ipv6 string ip Return a string equivalent to the given IPv6 address local z1 z2 indices of run of zeros to be displayed as local zstart zcount for i 1 9 do Find left most occurrence of longest run of two or more zeros if i lt 9 and ip i 0 then if zstart then zcount zcount 1 else zstart i zcount 1 end else if zcount and zcount gt 1 then if not z1 or zcount gt z2 z1 1 then z1 zstart z2 zstart zcount 1 end end zstart nil zcount nil end end local parts Collection new for i 1 8 do if z1 and z1 lt i and i lt z2 then if i z1 then if z1 1 or z2 8 then if z1 1 and z2 8 then return end parts add else parts add end end else parts add string format x ip i end end return parts join end local function ip string ip Return a string equivalent to given IP address IPv4 or IPv6 if ip n 2 then IPv4 local parts for i 1 2 do local w ip i local q i 1 and 1 or 3 parts q math floor w 256 parts q 1 w 256 end return table concat parts end return ipv6 string ip end Metatable for some operations on IP addresses local ipmt eq function lhs rhs Return true if values in numbered tables match if lhs n rhs n then for i 1 lhs n do if lhs i rhs i then return false end end return true end return false end lt function lhs rhs Return true if lhs lt rhs for sort if lhs n rhs n then for i 1 lhs n do if lhs i rhs i then return lhs i lt rhs i end end return false end return lhs n lt rhs n sort IPv4 before IPv6 although not needed end local function ipv4 address ip str Return a collection of two 16 bit words numbers equivalent to the IPv4 address given as a quad dotted string or return nil if invalid This representation is for compatibility with IPv6 addresses local parts Collection new local s ip str match s s for item in s gmatch do parts add item end if parts n 4 then for i s in ipairs parts do if s match d then local num tonumber s if 0 lt num and num lt 255 then if num gt 0 and s match 0 then A redundant leading zero is an error because it is for an IP in octal return nil end parts i num else return nil end else return nil end end local result Collection new for i 1 3 2 do result add parts i 256 parts i 1 end return setmetatable result ipmt end return nil end local function ipv6 address ip str Return a collection of eight 16 bit words numbers equivalent to the IPv6 address given as a colon delimited string or return nil if invalid local n ip str gsub if n lt 7 then ip str n ip str gsub string rep 9 n end local parts Collection new for item in ip str gmatch do parts add item end if parts n 8 then for i s in ipairs parts do if s then parts i 0 else local num tonumber 0x s if num and 0 lt num and num lt 65535 then parts i num else return nil end end end return setmetatable parts ipmt end return nil end local function common length num1 num2 nr bits Return number of prefix bits that two integers have in common Number of bits in each number is nr bits 16 8 4 2 or 1 if nr bits lt 1 then return num1 num2 and 1 or 0 end local half nr bits 2 local splitter 2 half local upper1 lower1 math modf num1 splitter local upper2 lower2 math modf num2 splitter if upper1 upper2 then lower1 math floor lower1 splitter 0 5 lower2 math floor lower2 splitter 0 5 return half common length lower1 lower2 half end return common length upper1 upper2 half end local function common prefix length ip1 ip2 Return number of prefix bits that two IPs have in common Caller ensures that both IPs are IPv4 or both are IPv6 local size 0 for i 1 ip1 n do local w1 w2 ip1 i ip2 i if w1 w2 then size size 16 else return size common length w1 w2 16 end end return size end local function ip prefix ip length Return a copy of ip masked to contain only the prefix of given length local result n ip n for i 1 ip n do if length gt 0 then if length gt 16 then result i ip i length length 16 else result i bit32 band ip i bit32 arshift 0xffff8000 length 1 length 0 end else result i 0 end end return setmetatable result ipmt end local function ip incremented ip Return a new IP equal to ip 1 Will wraparound 255 255 255 255 1 0 0 0 0 local result n ip n local carry 1 for i ip n 1 1 do local sum ip i carry if sum gt 0x10000 then carry 1 sum sum 0x10000 else carry 0 end result i sum end return setmetatable result ipmt end local function is next ip ip1 ip2 Return true if ip2 is the next IP after ip1 ip2 ip1 1 IPs are sorted and unique so ip1 lt ip2 and can ignore wrapping to zero This is lower overhead than making a new incremented IP then comparing if ip1 and ip2 then local carry 1 for i ip1 n 1 1 do local sum ip1 i carry if sum gt 0x10000 then carry 1 sum sum 0x10000 else carry 0 end if sum ip2 i then return false end end return true end end Each IP in a range except for the last IP has a common field which is a number specifying how many bits are common between the prefixes of this IP and the next IP 0 if this IP starts with 0 and the next starts with 1 Each non empty range has exactly one minimum common that is its value of common is smaller than all others That there is only one minimum common follows from the fact that the IPs are unique and sorted local function make range iplist ifirst ilast Return a table for the range of IPs from iplist ifirst to iplist ilast inclusive local imin vmin done if ifirst lt ilast then for i ifirst ilast 1 do Find the unique minimum of common lengths local common iplist i common if vmin then if vmin gt common then vmin common imin i end else vmin common imin i end end else vmin iplist ipsize imin ifirst done true end if vmin gt iplist allocation then For IPv6 the default allocation is 64 and there is no point having more precise ranges as they add unnecessary complexity However using results all sets allocation 128 so vmin is not changed vmin iplist allocation end return ifirst ifirst index of first IP ilast ilast index of last IP imin imin index of IP with minimum common size vmin number of common bits in prefix the minimum prefix ip prefix iplist imin vmin IP table of the base IP done done true if know that this range cannot be improved end local function split range iplist range depth Return a table of two or more ranges that more precisely target the IPs in range or return nothing if unable to improve range depth depth and depth 1 or 0 if depth lt 20 and 20 examines 1M contiguous addresses down to individual IPs not range done and range size lt iplist allocation and range ifirst lt range ilast then local imin range imin assert imin and range ifirst lt imin and imin lt range ilast local r1 make range iplist range ifirst range imin local r2 make range iplist range imin 1 range ilast local pointless range size 1 if r1 size gt pointless or r2 size gt pointless then return r1 r2 end local result Collection new local function store split range local split split range iplist range depth if split then for r in ipairs split do result add r end return true else result add range end end local improved1 store split r1 local improved2 store split r2 if improved1 or improved2 then return result end end range done true end local function better summary iplist summary Return a better summary that more precisely targets the specified IPs or return nil if unable to improve the summary local better Collection new local improved for range in ipairs summary do local split split range iplist range if split then improved true for r in ipairs split do better add r end else better add range end end return improved and better end local function make summaries iplist Return a collection where each item is a summary A summary is a table of one or more ranges A summary covers all the given IPs and probably more A range is a table representing a CIDR block such as 1 2 248 0 21 The first summary found is a single range each subsequent summary if any uses more ranges to better target the given IPs The result omits any summary with a range size that is too small too many IPs local function good size summary for range in ipairs summary do if range size lt iplist minsize then return false end end return true end local summaries Collection new if iplist n gt 0 then for i 1 iplist n 1 do Set length of prefixes common between each pair of IPs iplist i common common prefix length iplist i iplist i 1 end local summary make range iplist 1 iplist n while summary and summaries n lt iplist maxresults do if good size summary then summaries add summary end summary better summary iplist summary end end return summaries end local function extract ipv4 result omitted line Extract any IPv4 addresses from given line or throw error Accept CIDR n to specify a range only accept 16 to 32 Addresses must be delimited with whitespace to reduce false positives local function store hit local n 32 local lhs rhs hit match d if lhs then hit lhs n tonumber rhs if not n and 16 lt n and n lt 32 then error CIDR n only accepts n 16 to 32 invalid lhs rhs 0 end end local ip ipv4 address hit if ip then if n 32 then result add ip else if ip ip prefix ip n then error Invalid base address host bits should be zero hit 0 end for 1 2 32 n do result add ip ip ip incremented ip end end else omitted add hit end end line line gsub so wikitext indents or other colons don t obscure an IVp4 address for hit in line gmatch S do if hit match d d d then local n hit gsub if n gt 3 then store hit end end end end local function extract ipv6 result omitted line Extract any IPv6 addresses from given line or throw error Addresses must be delimited with whitespace to reduce false positives Want to accept all valid IPv6 despite the fact that contributors will not have an address starting with Also want to be able to parse arbitrary wikitext which might use colons for indenting To achieve that if an address at the start of a line is valid use it otherwise strip any leading colons and try again for pos hit in line gmatch S do local ipstr length hit match x d if ipstr then local n ipstr gsub if n gt 2 then local ip ipv6 address ipstr if not ip and pos 1 then ipstr n ipstr gsub if n gt 0 then ip ipv6 address ipstr end end if ip then if length and length gt 0 then error CIDR n not accepted for IPv6 hit 0 end result add ip else omitted add hit end end end end end local function contribs address strings ipbase size Return a URL or wikilink to list the contributions for an IP or IP range or return an empty string if cannot do anything useful The given address is a string of either a single IP or a CIDR range If using old system For IPv6 CIDR return a Special Contributions link using an asterisk wildcard which should work if the user has enabled the gadget Allow 16 24 and 27 32 CIDR ranges on Special Contributions local encoded count address gsub 2F if strings want old and count gt 0 then make note strings range if address find 1 true then if ipbase and size then local digits math floor size 4 if digits lt 3 then digits 3 end local wildcard digits 4 0 and or local parts for i 1 8 do local hex string format X ipbase i must be uppercase if digits gt 4 then parts i hex digits digits 4 if digits lt 0 then break end else local nz number of leading zeros in this group of four digits if hex 0 then nz 4 else nz 4 hex end if digits lt nz then Cannot properly handle this case have to omit group because 0 never occurs as the first digit wildcard else hex string rep 0 nz hex four digits parts i hex sub 1 digits end break end end address table concat parts wildcard local url https en wikipedia org wiki Special Contributions s ucstart s c s IPv6 prefix address in uppercase with wildcard at end s Start date formatted yyyymmdd000000 return string format url address start date ymdHMS strings months make note strings gadget end return no contributions link available end local url https tools wmflabs org xtools rangecontribs project en wikipedia org amp namespace all amp limit 50 amp text s amp begin s c s IPv4 CIDR range with changed to 2F s Start date formatted yyyy mm dd return string format url encoded start date y m d strings months end return Special Contributions address c end Strings for results using plain text The pre tags used are html which do not provide nowiki but that is not required by the text used local plaintext header lt pre gt Total Affected Given Range footer lt pre gt sumfirst s 12s 12s 11d s s s empty string dummy for compatibility s total affected s affected d given number of addresses given in input covered by this range s IP address range s empty string sumnext 12s 11d s s s affected d given s IP address range s empty string Strings for results using a table in wikitext local wikitable header class wikitable Total lt br gt affected Affected lt br gt addresses Given lt br gt addresses Range Contribs footer sumfirst style background darkgray height 6px colspan 5 style vertical align top rowspan s s s d s s s string of number of ranges in summary number of rows s total affected s affected d given s IP address range s contributions link sumnext s d s s s affected d given s IP address range s contributions link local function show summary lines strings iplist summary Show the summary by adding table wikitext or plain text to lines local want plain iplist want plain local total 0 for range in ipairs summary do A number is a double which easily handles 2 128 3 4e38 total total 2 iplist ipsize range size end for i range in ipairs summary do local prefix ip string range prefix local size range size local affected describe size iplist ipsize size local given range ilast range ifirst 1 local address local link if size iplist ipsize then address prefix if not want plain then link contribs address strings end else address prefix size if not want plain then link contribs address strings range prefix size end end local s if i 1 then s string format strings sumfirst want plain and or tostring summary describe total total affected given address link else s string format strings sumnext affected given address link end Pre tags returned by a module are html tags not like wikitext lt pre gt lt pre gt lines add want plain and mw text nowiki s or s end end local function process ips lines iplist omitted Process a list of IP addresses adding text of results to lines The list should contain either all IPv4 addresses or all IPv6 not a mixture local seq1 seq2 seqmany local function show sequence if seq1 and seq2 then local text ip string seq1 if seqmany then seqmany false text text ip string seq2 end seq1 nil seq2 nil local markup text sub 1 1 and lt nowiki gt or lines add markup text end end local function show ip ip Show IP or record it to be included in a from to sequence of IPs if is next ip seq2 ip then seq2 ip seqmany true else show sequence seq1 ip seq2 ip seqmany false end end if iplist n lt 1 then return end if lines n gt 0 then lines add end if omitted n gt 0 then lines add Warning omitted as invalid omitted join lines add end local heading line if not iplist nolist then lines add this blank line is replaced with a heading heading line lines n end local duplicates Collection new local previous iplist sort Check for duplicates which can interfere with method to get ranges for i ip in ipairs iplist do if previous ip then duplicates add i index to omit duplicate later elseif not iplist nolist then show ip ip end previous ip end show sequence local duplicate text if duplicates n gt 0 then duplicate text after omitting some duplicates for i duplicates n 1 1 do iplist remove duplicates i end end local heading text string format Sorted d s address s iplist n iplist ipname iplist n 1 and or es if heading line then lines heading line heading text duplicate text end local strings iplist want plain and plaintext or wikitable strings notes nil needed when module is kept loaded for multiple tests strings want old iplist want old strings nonote iplist nonote strings months iplist months lines add strings header local upto lines n for summary in ipairs make summaries iplist do show summary lines strings iplist summary end lines add strings footer if upto 1 lines n then Show message in the very unlikely event that no results are found lines add lines add No suitable ranges found use lt code gt results all lt code gt to see all ranges end if strings notes then lines add lines add Notes for key in ipairs range gadget do if strings notes key then lines add strings notes key end end end end local function make options args Return table of options from validated args or throw error local options if not empty args comment then options comment args comment end Parameter months is only used if old is also used local months math floor tonumber args months or tonumber args month or 1 if months lt 1 then months 1 elseif months gt 12 then months 12 end options months months silently ignore invalid input local allocation if not empty args allocation then allocation tonumber args allocation if not allocation and 48 lt allocation and allocation lt 128 then error Invalid allocation args allocation should be 48 to 128 default is 64 0 end end local maxresults if not empty args results then if args results all then options all true allocation allocation or 128 maxresults 1000 else maxresults tonumber args results if not maxresults and 1 lt maxresults and maxresults lt 100 then error Invalid results args results should be 1 to 100 0 end end end options allocation allocation or 64 options maxresults maxresults or 10 local keywords Table of k v strings If an argument matches k an option named v is set to true ok noannounce old want old nolist nolist nonote nonote text text local want old for i arg in ipairs args do local flag keywords arg match s w s if flag then options i skip options flag true if flag want old then want old true end end end if not want old then options nonote true end return options end local function IPblock args Process given args can be called from another module Throw an error if need to report a problem local options make options args local v4list v4omitted Collection new Collection new local v6list v6omitted Collection new Collection new v4list ipsize 32 v4list ipname IPv4 v6list ipsize 128 v6list ipname IPv6 v4list allocation 32 v6list allocation options allocation if options all then v4list minsize 0 v6list minsize 0 else v4list minsize 16 cannot block more IPs than 16 for IPv4 v6list minsize 19 or 19 for IPv6 wgBlockCIDRLimit end for k in ipairs maxresults months want old nolist nonote do v4list k options k v6list k options k end if options text then v4list want plain true v6list want plain true end for i arg in ipairs args do if options i skip then for line in string gmatch arg n t t r n do Skip line if is empty or a comment if line then local comment options comment if not comment and line sub 1 comment comment then line line gsub Special Contributions so input Special Contributions 1 2 3 4 works gsub Special Contribs gsub amp lt gt replace accepted delimiters with a space gsub 226 128 142 replace LTR marks U 200E extract ipv4 v4list v4omitted line extract ipv6 v6list v6omitted line end end end end end if v4list n lt 1 and v6list n lt 1 then error No valid IPv4 or IPv6 address in arguments 0 end local lines Collection new if not options noannounce then 1 Commented out April 2016 as expired 1 lines add Please see Template talk Blockcalc Version February 2016 this announcement 2 Commented out December 2017 as expired 2 lines add By default links now use Special Contributions per Template talk IP range calculator Version November 2017 this announcement end process ips lines v4list v4omitted process ips lines v6list v6omitted return lines join n end local function IPblock frame Return wikitext to display the smallest IPv4 or IPv6 CIDR range that covers each address given in the arguments or return error text Input can have any mixture of IPs IPv4 and IPv6 are processed separately local ok msg pcall IPblock frame getParent args if ok then return msg end return lt strong class error gt Error msg lt strong gt end local function sha1 frame Return SHA 1 hash of first parameter This is for use at User Johnuniq Security to generate hash of a password local text frame args 1 or match s s if text then return SHA 1 hash after removing any leading or trailing whitespace is lt code gt mw hash hashValue sha1 text lt code gt end return Usage lt code gt amp 123 invoke IPblock sha1 text amp 125 lt code gt to display the SHA 1 hash of lt code gt text lt code gt end return IPblock IPblock IPblock IPblock sha1 sha1