-
-
Save creationix/b7f949c3e360773bece2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local ffi = require 'ffi' | |
local uv = require 'uv' | |
local os = require('os') | |
local AF_INET = 2 | |
local AF_INET6 = jit.os == "OSX" and 30 or | |
jit.os == "Linux" and 10 or error("Unknown OS") | |
local SOCK_RAW = 3 | |
local IPPROTO_ICMP = 1 | |
local IPPROTO_ICMP6 = 58 | |
ffi.cdef[[ | |
int socket(int socket_family, int socket_type, int protocol); | |
]] | |
local band = bit.band | |
local bor = bit.bor | |
local bnot = bit.bnot | |
local lshift = bit.lshift | |
local rshift = bit.rshift | |
local byte = string.byte | |
local char = string.char | |
local time = os.time | |
-- Calculate 16-bit one's complement of the one's complement sum | |
local function checksum(buffer) | |
local sum = 0 | |
for i = 1, #buffer, 2 do | |
local word = bor(lshift(byte(buffer, i), 8), byte(buffer, i + 1)) | |
sum = sum + word | |
if sum > 0xffff then | |
sum = sum - 0xffff -- remove carry bit and add 1 | |
end | |
end | |
-- Take complement | |
sum = band(bnot(sum), 0xffff) | |
-- Return as 2-byte string in network byte order | |
return char(rshift(sum, 8), band(sum, 0xff)) | |
end | |
local function sock4(ip) | |
local sockfd = ffi.C.socket(AF_INET, SOCK_RAW, IPPROTO_ICMP) | |
assert(sockfd >= 0, "Failed to create socket") | |
local raw = uv.new_udp() | |
assert(raw:open(sockfd)) | |
return raw | |
end | |
local function sock6(ip) | |
local sockfd = ffi.C.socket(AF_INET6, SOCK_RAW, IPPROTO_ICMP6) | |
assert(sockfd >= 0, "Failed to create socket") | |
local raw = uv.new_udp() | |
assert(raw:open(sockfd)) | |
return raw | |
end | |
local id = math.random(0x10000) % 0x10000 | |
local seq = 0 | |
local function ping(ip, payload) | |
local now = time() | |
local top, sock | |
if ip:match("^%d+%.%d+%.%d+%.%d+$") then | |
top = "\x08\x00" | |
sock = sock4(ip) | |
else | |
top = "\x80\x00" | |
sock = sock6(ip) | |
end | |
local bottom = char( | |
band(rshift(id, 8), 0xff), band(id, 0xff), -- id | |
band(rshift(seq, 8), 0xff), band(seq, 0xff), -- seq | |
-- timestamp | |
band(rshift(now, 24), 0xff), band(rshift(now, 16), 0xff), | |
band(rshift(now, 8), 0xff), band(now, 0xff) | |
) .. payload | |
seq = (seq + 1) % 256 | |
sock:send(top .. checksum(top .. "\x00\x00" .. bottom) .. bottom, ip, 0) | |
sock:recv_start(function (err, message, address) | |
assert(not err, err) | |
p { message = message, address = address } | |
sock:recv_stop() | |
end) | |
end | |
local e4payload = "\x00\x02\x7b\x14\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" .. | |
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" .. | |
"\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" .. | |
"\x30\x31\x32\x33\x34\x35\x36\x37" | |
local e6payload = "\x56\x03\x01\xc9\x00\x01\xa3\x7d" | |
uv.new_timer():start(0, 1000, function () | |
ping("127.0.0.1", e4payload) | |
ping("::1", e6payload) | |
ping("23.253.227.83", e4payload) | |
ping("2001:4800:7817:103:be76:4eff:fe05:3fa8", e6payload) | |
end) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment