-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Jianhui Zhao <[email protected]>
- Loading branch information
Showing
1 changed file
with
96 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
#!/usr/bin/env eco | ||
|
||
--[[ | ||
to allow root to use icmp6 sockets, run: | ||
sysctl -w net.ipv4.ping_group_range="0 0" | ||
--]] | ||
|
||
local socket = require 'eco.socket' | ||
local time = require 'eco.time' | ||
|
||
local ICMP6_HEADER_LEN = 8 | ||
local ICMP6_ECHO = 128 | ||
local ICMP6_ECHOREPLY = 129 | ||
|
||
local dest_ip = '::1' | ||
local local_id = math.random(0, 65535) | ||
local local_seq = 1 | ||
local local_data = 'hello' | ||
|
||
local function build_icmp_req() | ||
local data = { | ||
string.char(ICMP6_ECHO), -- type | ||
'\0', -- code | ||
'\0\0', -- checksum | ||
'\0\0', -- id: the kernel will assign it with local port | ||
string.char(local_seq >> 8, local_seq & 0xff), -- sequence | ||
local_data | ||
} | ||
|
||
local_seq = local_seq + 1 | ||
|
||
return table.concat(data) | ||
end | ||
|
||
local function parse_icmp_resp(data) | ||
if #data < ICMP6_HEADER_LEN then | ||
return nil, 'invalid icmp resp' | ||
end | ||
|
||
local icmp_type = data:byte(1) | ||
local id_hi = data:byte(5) | ||
local id_lo = data:byte(6) | ||
local id = (id_hi << 8) + id_lo | ||
|
||
local seq_hi = data:byte(7) | ||
local seq_lo = data:byte(8) | ||
local seq = (seq_hi << 8) + seq_lo | ||
|
||
return icmp_type, id, seq, #data - ICMP6_HEADER_LEN | ||
end | ||
|
||
local s, err = socket.icmp6() | ||
if not s then | ||
print(err) | ||
return | ||
end | ||
|
||
-- s:setoption('bindtodevice', 'eth0') | ||
|
||
s:bind(nil, local_id) | ||
|
||
print(string.format('PING %s, %d bytes of data.', dest_ip, #local_data)) | ||
|
||
while true do | ||
_, err = s:sendto(build_icmp_req(), dest_ip, 0) | ||
if err then | ||
print('send fail:', err) | ||
break | ||
end | ||
|
||
local start = time.now() | ||
|
||
local resp, peer = s:recvfrom(1024, 5.0) | ||
if not resp then | ||
print('recv fail:', peer) | ||
break | ||
end | ||
|
||
local elapsed = time.now() - start | ||
|
||
local icmp_type, id, seq, n = parse_icmp_resp(resp) | ||
|
||
if icmp_type then | ||
if icmp_type == ICMP6_ECHOREPLY then | ||
if id == local_id then | ||
print(string.format('%d bytes from %s: icmp_seq=%d time=%.3f ms', n, dest_ip, seq, elapsed * 1000)) | ||
end | ||
else | ||
print('Got ICMP packet with type ' .. icmp_type) | ||
end | ||
else | ||
print(id) | ||
end | ||
|
||
time.sleep(1.0) | ||
end |