local ffi = require "ffi" local bit = require "bit" ffi.cdef[[ int open(const char *path, int flags, ...); int close(int fd); size_t read(int d, void *buf, size_t nbytes); size_t write(int d, void *buf, size_t nbytes); int select(int nfds, uint32_t *readfds, uint32_t *writefds, uint32_t *exceptfds, struct timeval *timeout); typedef int64_t time_t; time_t time(time_t *); ]] local C = ffi.C local O = { RDONLY = 0, WRONLY = 1, RDWR = 2, } local bwquota = 4000000 local bwinterval = 60 local bwused = 0 local starttime = ffi.new("time_t", 0) local bufsize = 2048 local buf = ffi.new("uint8_t[?]", bufsize) local function isset(mask, b) return bit.band(mask, bit.lshift(1, b)) ~= 0 end local fd1 = C.open("/dev/tun0", O.RDWR) local fd2 = C.open("/dev/tun1", O.RDWR) local readmask = bit.bor(bit.lshift(1, fd1), bit.lshift(1, fd2)) readset = ffi.new("uint32_t[1]") readset[0] = readmask local counts = { } for i = 0, 255 do counts[i] = 0 end local function tally(buf, amt) for i = 0, amt do local val = buf[i] counts[val] = counts[val] + 1 end end local function forward(fd, buf, amt) if bwused > bwquota * 3 / 4 then local x = math.random(bwquota) if x < bwused then return end end tally(buf, amt) C.write(fd, buf, amt) bwused = bwused + amt end while true do readset[0] = readmask C.select(fd2 + 1, readset, nil, nil, nil) local now = C.time(nil) if now > starttime + bwinterval then for i = 0, 255 do local label = string.char(i) if string.match(label, "%A") then label = "?" end io.write(string.format("%s %4.4d ", label, counts[i])) if math.fmod(i, 12) == 0 then io.write("\n") end end starttime = now bwused = 0 end if isset(readset[0], fd1) then local amt = C.read(fd1, buf, bufsize) forward(fd2, buf, amt) end if isset(readset[0], fd2) then local amt = C.read(fd2, buf, bufsize) forward(fd1, buf, amt) end end