Lunatikは、Luaを使用してLinuxカーネルをスクリプト化するためのフレームワークです。これは、カーネルで動作するように変更されたLUAインタープリターによって構成されています。デバイスドライバー(LUA =)で記述)と、ユーザースペースからスクリプトをロードおよび実行し、ランタイム環境を管理するコマンドラインツール。スクリプトをロードおよび実行し、カーネルからランタイム環境を管理するC API。カーネル施設をLUAスクリプトに結合するためのLUA API。
Lunatikを使用してLuaで書かれた文字デバイスドライバーの例を示し、ランダムASCIIの印刷可能な文字を生成します。
-- /lib/modules/lua/passwd.lua
--
-- implements /dev/passwd for generate passwords
-- usage: $ sudo lunatik run passwd
-- $ head -c <width> /dev/passwd
local device = require ( " device " )
local linux = require ( " linux " )
local function nop () end -- do nothing
local s = linux . stat
local driver = { name = " passwd " , open = nop , release = nop , mode = s . IRUGO }
function driver : read () -- read(2) callback
-- generate random ASCII printable characters
return string.char ( linux . random ( 32 , 126 ))
end
-- creates a new character device
device . new ( driver )依存関係をインストールします(ここでは、Debian/Ubuntuのために、分布に適応します):
sudo apt install git build-essential lua5.4 dwarves clang llvm libelf-dev linux-headers- $( uname -r ) linux-tools-common linux-tools- $( uname -r ) pkg-config libpcap-dev m4 lunatikをコンパイルしてインストールします:
LUNATIK_DIR= ~ /lunatik # to be adapted
mkdir " ${LUNATIK_DIR} " ; cd " ${LUNATIK_DIR} "
git clone --depth 1 --recurse-submodules https://github.com/luainkernel/lunatik.git
cd lunatik
make
sudo make install完了したら、Tools// /etc/kernel/postinst.d/ postinst.d/にコピーされる可能性があるdebian_kernel_postinst_lunatik.shスクリプトは、 lunatik (およびxdp必要なLIBS)がカーネルのアップグレードでコンパイルされることを保証します。
sudo lunatik # execute Lunatik REPL
Lunatik 3.5 Copyright (C) 2023-2024 ring-0 Ltda.
> return 42 -- execute this line in the kernel
42
usage: lunatik [load | unload | reload | status | list] [run | spawn | stop < script > ]load :Lunatikカーネルモジュールをロードしますunload :Lunatikカーネルモジュールをアンロードしますreload :Lunatikカーネルモジュールをリロードしますstatus : show which Lunatik kernel modules are currently loadedlist : show which runtime environments are currently runningrun : create a new runtime environment to run the script /lib/modules/lua/<script>.luaspawn : create a new runtime environment and spawn a thread to run the script /lib/modules/lua/<script>.luastop : stop the runtime environment created to run the script <script>default : start a REPL (Read–Eval–Print Loop) Lunatik 3.4 is based on Lua 5.4 adapted to run in the kernel.
Lunatikは浮動小数点の算術をサポートしていないため、 __divも__powメタトッドもサポートせず、タイプ数にはサブタイプの整数のみがあります。
Lunatik does not support both io and os libraries, and the given identifiers from the following libraries:
Lunatik modifies the following identifiers:
"Lua 5.4-kernel" ."/lib/modules/lua/?.lua;/lib/modules/lua/?/init.lua" .Lunatik does not support luaL_Stream, luaL_execresult, luaL_fileresult, luaopen_io and luaopen_os.
Lunatik modifies luaL_openlibs to remove luaopen_io and luaopen_os.
#include <lunatik.h> int lunatik_runtime ( lunatik_object_t * * pruntime , const char * script , bool sleep ); lunatik_runtime()新しいruntime環境を作成し、この環境のエントリポイントとして、Script /lib/modules/lua/<script>.lua lua/<script> .luaをロードして実行します。 It must only be called from process context . The runtime environment is a Lunatik object that holds a Lua state. Lunatik objects are special Lua userdata which also hold a lock type and a reference counter. sleepが本当なら、 lunatik_runtime()は、 runtime環境とgfp_kernelフラグをロックするためにミューテックスを使用して、後でlunatik_run()呼び出しで新しいメモリを割り当てるために新しいメモリを割り当てます。 Otherwise, it will use a spinlock and GFP_ATOMIC. lunatik_runtime() opens the Lua standard libraries present on Lunatik.成功した場合、 lunatik_runtime()は、 1 pruntime Luaの追加スペース0指し示したアドレスを設定しますruntime Otherwise, it returns -ENOMEM , if insufficient memory is available; or -EINVAL , if it fails to load or run the script .
-- /lib/modules/lua/mydevice.lua
function myread ( len , off )
return " 42 "
end static lunatik_object_t * runtime ;
static int __init mydevice_init ( void )
{
return lunatik_runtime ( & runtime , "mydevice" , true);
} int lunatik_stop ( lunatik_object_t * runtime ); lunatik_stop() closes the Lua state created for this runtime environment and decrements the reference counter. Once the reference counter is decremented to zero, the lock type and the memory allocated for the runtime environment are released. If the runtime environment has been released, it returns 1 ; otherwise, it returns 0 .
void lunatik_run ( lunatik_object_t * runtime , < inttype > ( * handler )(...), < inttype > & ret , ...); lunatik_run()は、 runtime環境をロックし、 handlerを呼び出して、関連するLua状態を最初の議論に続くVariadicの議論として通過します。 If the Lua state has been closed, ret is set with -ENXIO ; otherwise, ret is set with the result of handler(L, ...) call. Then, it restores the Lua stack and unlocks the runtime environment. It is defined as a macro.
static int l_read ( lua_State * L , char * buf , size_t len , loff_t * off )
{
size_t llen ;
const char * lbuf ;
lua_getglobal ( L , "myread" );
lua_pushinteger ( L , len );
lua_pushinteger ( L , * off );
if ( lua_pcall ( L , 2 , 2 , 0 ) != LUA_OK ) { /* calls myread(len, off) */
pr_err ( "%sn" , lua_tostring ( L , -1 ));
return - ECANCELED ;
}
lbuf = lua_tolstring ( L , -2 , & llen );
llen = min ( len , llen );
if ( copy_to_user ( buf , lbuf , llen ) != 0 )
return - EFAULT ;
* off = ( loff_t ) luaL_optinteger ( L , -1 , * off + llen );
return ( ssize_t ) llen ;
}
static ssize_t mydevice_read ( struct file * f , char * buf , size_t len , loff_t * off )
{
ssize_t ret ;
lunatik_object_t * runtime = ( lunatik_object_t * ) f -> private_data ;
lunatik_run ( runtime , l_read , ret , buf , len , off );
return ret ;
} void lunatik_getobject ( lunatik_object_t * object ); lunatik_getobject() increments the reference counter of this object (eg, runtime environment).
int lunatik_putobject ( lunatik_object_t * object ); lunatik_putobject() decrements the reference counter of this object (eg, runtime environment). If the object has been released, it returns 1 ; otherwise, it returns 0 .
lunatik_object_t * lunatik_toruntime ( lua_State * L ); lunatik_toruntime() returns the runtime environment referenced by the L 's extra space.
The lunatik library provides support to load and run scripts and manage runtime environments from Lua.
lunatik.runtime(script [, sleep]) lunatik.runtime()新しいランタイム環境を作成し、この環境のエントリポイントとして、cript /lib/modules/lua/<script>.lua lua/<script> .luaをロードして実行します。 It returns a Lunatik object representing the runtime environment. If sleep is true or omitted, it will use a mutex and GFP_KERNEL; otherwise, it will use a spinlock and GFP_ATOMIC. lunatik.runtime() opens the Lua standard libraries present on Lunatik.
runtime:stop() runtime:stop() stops the runtime environment and clear its reference from the runtime object.
runtime:resume([obj1, ...]) runtime:resume() resumes the execution of a runtime . The values obj1, ... are passed as the arguments to the function returned on the runtime creation. If the runtime has yielded, resume() restarts it; the values obj1, ... are passed as the results from the yield.
The device library provides support for writting character device drivers in Lua.
device.new(driver) device.new() returns a new device object and installs its driver in the system. driver 、次のフィールドを含むテーブルとして定義する必要があります。
name :文字列デバイス名を定義します。デバイスファイル( /dev/<name>など)の作成に使用されます。 driverテーブルには、オプションで次のフィールドが含まれている場合があります。
read :デバイスファイルの読み取り操作を処理するコールバック関数。最初の引数としてdriverテーブルを受信し、その後に2つの整数、読み取りのlengthとファイルoffset続きます。文字列を返し、オプションでupdated offset返します。返された文字列の長さが要求されたlengthよりも大きい場合、文字列はそのlengthに修正されます。 updated offsetが返されない場合、 offset offset + lengthで更新されます。write :デバイスファイルの書き込み操作を処理するコールバック関数。最初の引数としてdriverテーブルを受信し、その後に文字列が書かれた文字列とファイルoffsetとして整数が続きます。書面によるlengthオプションで返す可能性があります。その後、 updated offsetが続きます。返された長さが要求されたlengthよりも大きい場合、返された長さは修正されます。 updated offsetが返されない場合、 offset offset + lengthで更新されます。open :デバイスファイルのオープン操作を処理するコールバック関数。 driverテーブルを受け取り、何も返さないと予想されます。release :デバイスファイルのリリース操作を処理するコールバック関数。 driverテーブルを受け取り、何も返さないと予想されます。mode :デバイスファイルモードを指定する整数。操作コールバックが定義されていない場合、 deviceアクセス時に-ENXIO VFSに返します。
device.stop(dev) 、 dev:stop() device.stop()システムからdevオブジェクトによって指定されたデバイスdriverを削除します。
linuxライブラリは、一部のLinuxカーネル設備をサポートしています。
linux.random([m [, n]])Linux.random()は、Math.randomの動作を模倣しますが、 <Linux/Random.h>のget_random_u32()およびget_random_u64()apisをバインディングします。
引数なしで呼び出されると、すべてのビット(擬似)ランダムを持つ整数が生成されます。 2つの整数mとnで呼び出されると、 linux.random()は、範囲の均一な分布で擬似ランダム整数を返します[m, n] 。ポジティブnの呼び出しmath.random(n)は、 math.random(1, n)と同等です。
linux.statLinux.statは、<linux/stat.h>整数フラグをluaにエクスポートするテーブルです。
"IRWXUGO" :ユーザー、グループ、その他の読み取り、書き込み、実行の許可。"IRUGO" :ユーザー、グループ、その他の読み取りのみを許可します。"IWUGO" :ユーザー、グループ、その他のために書くためだけの許可。"IXUGO" :ユーザー、グループ、その他の実行のみを許可します。 linux.schedule([timeout [, state]]) linux.schedule() sets the current task state and makes the it sleep until timeout milliseconds have elapsed. If timeout is omitted, it uses MAX_SCHEDULE_TIMEOUT . If state is omitted, it uses task.INTERRUPTIBLE .
linux.tasklinux.task is a table that exports task state flags to Lua.
"RUNNING" : task is executing on a CPU or waiting to be executed."INTERRUPTIBLE" : task is waiting for a signal or a resource (sleeping)."UNINTERRUPTIBLE" : behaves like "INTERRUPTIBLE" with the exception that signal will not wake up the task."KILLABLE" : behaves like "UNINTERRUPTIBLE" with the exception that fatal signals will wake up the task."IDLE" : behaves like "UNINTERRUPTIBLE" with the exception that it avoids the loadavg accounting. linux.time()linux.time() returns the current time in nanoseconds since epoch.
linux.errnolinux.errno is a table that exports <uapi/asm-generic/errno-base.h> flags to Lua.
"PERM" : Operation not permitted."NOENT" : No such file or directory."SRCH" : No such process."INTR" : Interrupted system call."IO" : I/O error."NXIO" :No such device or address."2BIG" :, Argument list too long."NOEXEC" : Exec format error."BADF" : Bad file number."CHILD" : No child processes."AGAIN" : Try again."NOMEM" : Out of memory."ACCES" : Permission denied."FAULT" : Bad address."NOTBLK" : Block device required."BUSY" : Device or resource busy."EXIST" : File exists."XDEV" : Cross-device link."NODEV" : No such device."NOTDIR" : Not a directory."ISDIR" : Is a directory."INVAL" : Invalid argument."NFILE" : File table overflow."MFILE" : Too many open files."NOTTY" : Not a typewriter."TXTBSY" : Text file busy."FBIG" : File too large."NOSPC" : No space left on device."SPIPE" : Illegal seek."ROFS" : Read-only file system."MLINK" : Too many links."PIPE" : Broken pipe."DOM" : Math argument out of domain of func."RANGE" : Math result not representable. linux.hton16(num)linux.hton16() converts the host byte order to network byte order for a 16-bit integer.
linux.hton32(num)linux.hton32() converts the host byte order to network byte order for a 32-bit integer.
linux.hton64(num)linux.hton64() converts the host byte order to network byte order for a 64-bit integer.
linux.ntoh16(num)linux.ntoh16() converts the network byte order to host byte order for a 16-bit integer.
linux.ntoh32(num)linux.ntoh32() converts the network byte order to host byte order for a 32-bit integer.
linux.ntoh64(num)linux.ntoh64() converts the network byte order to host byte order for a 64-bit integer.
linux.htobe16(num)linux.htobe16() converts the host byte order to big-endian byte order for a 16-bit integer.
linux.htobe32(num)linux.htobe32() converts the host byte order to big-endian byte order for a 32-bit integer.
linux.htobe64(num)linux.htobe64() converts the host byte order to big-endian byte order for a 64-bit integer.
linux.be16toh(num)linux.be16toh() converts the big-endian byte order to host byte order for a 16-bit integer.
linux.be32toh(num)linux.be32toh() converts the big-endian byte order to host byte order for a 32-bit integer.
linux.be64toh(num)linux.be64toh() converts the big-endian byte order to host byte order for a 64-bit integer.
linux.htole16(num)linux.htole16() converts the host byte order to little-endian byte order for a 16-bit integer.
linux.htole32(num)linux.htole32() converts the host byte order to little-endian byte order for a 32-bit integer.
linux.htole64(num)linux.htole64() converts the host byte order to little-endian byte order for a 64-bit integer.
linux.le16toh(num)linux.le16toh() converts the little-endian byte order to host byte order for a 16-bit integer.
linux.le32toh(num)linux.le32toh() converts the little-endian byte order to host byte order for a 32-bit integer.
linux.le64toh(num)linux.le64toh() converts the little-endian byte order to host byte order for a 64-bit integer.
notifier Libraryは、カーネルNotifier Chainsのサポートを提供します。
notifier.keyboard(callback) Notifier.keyboard()新しいキーボードnotifierオブジェクトを返し、システムにインストールします。 callback関数は、コンソールキーボードイベントが発生するたびに呼び出されます(たとえば、キーが押されたりリリースされたりしました)。このcallback 、次の引数を受け取ります。
event :利用可能なイベントは、notifier.kbdテーブルで定義されます。down : true 、キーが押されている場合。 false 、それがリリースされている場合。shift : true 、シフトキーが保持されている場合。 false 、それ以外の場合。key : eventに応じてKeyCodeまたはKeysym 。 callback関数は、notifier.notifyテーブルによって定義された値を返す場合があります。
notifier.kbdNotifier.kbdは、KBDフラグをLUAにエクスポートするテーブルです。
"KEYCODE" :キーボードキーコード、その他の前に呼び出されます。"UNBOUND_KEYCODE" :他の任意のキーボードキーコード。"UNICODE" :キーボードUnicode。"KEYSYM" :キーボードKeysym 。"POST_KEYSYM" :キーボードキーイム解釈の後に呼び出されます。 notifier.netdevice(callback) Notifier.NetDevice()新しいNetDevice notifierオブジェクトを返し、システムにインストールします。 callback関数は、コンソールNetDeviceイベントが発生するたびに呼び出されます(たとえば、ネットワークインターフェイスが接続または切断されています)。このcallback 、次の引数を受け取ります。
event :利用可能なイベントは、notifier.netdevテーブルによって定義されます。name :デバイス名。 callback関数は、notifier.notifyテーブルによって定義された値を返す場合があります。
notifier.netdevNotifier.netdevは、NetDevフラグをLUAにエクスポートするテーブルです。
notifier.notifyNotifier.Notifyは、LUAにフラグを通知することをエクスポートするテーブルです。
"DONE" :気にしないでください。"OK" :私に合っています。"BAD" :悪い/拒否権。"STOP" :通知者から戻ってさらに電話をかける方法をきれいにします。 notfr:delete() notfr:delete()は、システムからnotfrオブジェクトによって指定されたnotifierを削除します。
socketライブラリは、カーネルネットワーキングの取り扱いをサポートします。このライブラリは、Thengzhi TanのGSOCプロジェクトに触発されました。
socket.new(family, type, protocol) socket.new() creates a new socket object. This function receives the following arguments:
family : the available address families are defined by the socket.af table.sock : the available types are present on the socket.sock table.protocol : the available protocols are defined by the socket.ipproto table. socket.afsocket.af is a table that exports address families (AF) to Lua.
"UNSPEC" : Unspecified."UNIX" : Unix domain sockets."LOCAL" : POSIX name for AF_UNIX."INET" : Internet IP Protocol."AX25" : Amateur Radio AX.25."IPX" : Novell IPX."APPLETALK" : AppleTalk DDP."NETROM" : Amateur Radio NET/ROM."BRIDGE" : Multiprotocol bridge."ATMPVC" : ATM PVCs."X25" : Reserved for X.25 project."INET6" : IP version 6."ROSE" : Amateur Radio X.25 PLP."DEC" : Reserved for DECnet project."NETBEUI" : Reserved for 802.2LLC project."SECURITY" : Security callback pseudo AF."KEY" : PF_KEY key management API."NETLINK" : Netlink."ROUTE" : Alias to emulate 4.4BSD."PACKET" : Packet family."ASH" : Ash."ECONET" : Acorn Econet."ATMSVC" : ATM SVCs."RDS" : RDS sockets."SNA" : Linux SNA Project (nutters!)."IRDA" : IRDA sockets."PPPOX" : PPPoX sockets."WANPIPE" : Wanpipe API Sockets."LLC" : Linux LLC."IB" : Native InfiniBand address."MPLS" : MPLS."CAN" : Controller Area Network."TIPC" : TIPC sockets."BLUETOOTH" : Bluetooth sockets."IUCV" : IUCV sockets."RXRPC" : RxRPC sockets."ISDN" : mISDN sockets."PHONET" : Phonet sockets."IEEE802154" : IEEE802154 sockets."CAIF" : CAIF sockets."ALG" : Algorithm sockets."NFC" : NFC sockets."VSOCK" : vSockets."KCM" : Kernel Connection Multiplexor."QIPCRTR" : Qualcomm IPC Router."SMC" : reserve number for PF_SMC protocol family that reuses AF_INET address family."XDP" : XDP sockets."MCTP" : Management component transport protocol."MAX" : Maximum. socket.socksocket.sock is a table that exports socket types (SOCK):
"STREAM" : stream (connection) socket."DGRAM" : datagram (conn.less) socket."RAW" : raw socket."RDM" : reliably-delivered message."SEQPACKET" : sequential packet socket."DCCP" : Datagram Congestion Control Protocol socket."PACKET" : linux specific way of getting packets at the dev level.とフラグ(靴下):
"CLOEXEC" :n/a。"NONBLOCK" : n/a. socket.ipprotoSocket.Ipprotoは、IPプロトコル(IPPROTO)をLUAにエクスポートするテーブルです。
"IP" :TCPのダミープロトコル。"ICMP" :インターネット制御メッセージプロトコル。"IGMP" :インターネットグループ管理プロトコル。"IPIP" :IPIPトンネル(古いKA9Qトンネルは94を使用)。"TCP" :伝送制御プロトコル。"EGP" :エクステリアゲートウェイプロトコル。"PUP" :pupプロトコル。"UDP" :ユーザーデータグラムプロトコル。"IDP" :XNS IDPプロトコル。"TP" :輸送プロトコルクラス4。"DCCP" :データグラムの混雑制御プロトコル。"IPV6" :IPv6-in-IPV4トンネル。"RSVP" :RSVPプロトコル。"GRE" :Cisco Gre Tunnels(RFC 1701,1702)。"ESP" :カプセル化セキュリティペイロードプロトコル。"AH" : Authentication Header protocol."MTP" :マルチキャストトランスポートプロトコル。"BEETPH" :BeetのIPオプション擬似ヘッダー。"ENCAP" :カプセル化ヘッダー。"PIM" :Protocol Independent Multicast。"COMP" : Compression Header Protocol."SCTP" :ストリーム制御輸送プロトコル。"UDPLITE" :UDP-lite(RFC 3828)。"MPLS" :IPのMPL(RFC 4023)。"ETHERNET" :イーサネット-IPV6カプセル化。"RAW" :RAW IPパケット。"MPTCP" :MultiPath TCP接続。 sock:close()靴下:close()は、システムからsockオブジェクトを削除します。
sock:send(message, [addr [, port]])靴下:send()は、ソケットsockを介して文字列messageを送信します。 sock住所ファミリがaf.INETある場合、次の議論が期待されます。
addr :宛先IPv4アドレスを説明するinteger 。port : integer describing the destination IPv4 port.さもないと:
addr : packed string describing the destination address. sock:receive(length, [flags [, from]]) sock:receive() receives a string with up to length bytes through the socket sock . The available message flags are defined by the socket.msg table. If from is true , it returns the received message followed by the peer's address. Otherwise, it returns only the received message.
socket.msgsocket.msg is a table that exports message flags to Lua.
"OOB" : n/a."PEEK" : n/a."DONTROUTE" : n/a."TRYHARD" : Synonym for "DONTROUTE" for DECnet."CTRUNC" : n/a."PROBE" : Do not send. Only probe path fe for MTU."TRUNC" : n/a."DONTWAIT" : Nonblocking io."EOR" : End of record."WAITALL" : Wait for a full request."FIN" : n/a."SYN" : n/a."CONFIRM" : Confirm path validity."RST" : n/a."ERRQUEUE" : Fetch message from error queue."NOSIGNAL" : Do not generate SIGPIPE."MORE" : Sender will send more."WAITFORONE" : recvmmsg(): block until 1+ packets avail."SENDPAGE_NOPOLICY" : sendpage() internal: do no apply policy."SENDPAGE_NOTLAST" : sendpage() internal: not the last page."BATCH" : sendmmsg(): more messages coming."EOF" : n/a."NO_SHARED_FRAGS" : sendpage() internal: page frags are not shared."SENDPAGE_DECRYPTED" : sendpage() internal: page may carry plain text and require encryption."ZEROCOPY" : Use user data in kernel path."FASTOPEN" : Send data in TCP SYN."CMSG_CLOEXEC" : Set close_on_exec for file descriptor received through SCM_RIGHTS. sock:bind(addr [, port]) sock:bind() binds the socket sock to a given address. If the sock address family is af.INET , then it expects the following arguments:
addr : integer describing host IPv4 address.port : integer describing host IPv4 port.さもないと:
addr : packed string describing host address. sock:listen([backlog]) sock:listen() moves the socket sock to listening state.
backlog : pending connections queue size. If omitted, it uses SOMAXCONN as default. sock:accept([flags]) sock:accept() accepts a connection on socket sock . It returns a new socket object. The available flags are present on the socket.sock table.
sock:connect(addr [, port] [, flags]) sock:connect() connects the socket sock to the address addr . If the sock address family is af.INET , then it expects the following arguments:
addr : integer describing the destination IPv4 address.port : integer describing the destination IPv4 port.さもないと:
addr : packed string describing the destination address.The available flags are present on the socket.sock table.
For datagram sockets, addr is the address to which datagrams are sent by default, and the only address from which datagrams are received. For stream sockets, attempts to connect to addr .
sock:getsockname() sock:getsockname() get the address which the socket sock is bound. If the sock address family is af.INET , then it returns the following:
addr : integer describing the bounded IPv4 address.port : integer describing the bounded IPv4 port.さもないと:
addr : packed string describing the bounded address. sock:getpeername() sock:getpeername() get the address which the socket sock is connected. If the sock address family is af.INET , then it returns the following:
addr :ピアのIPv4アドレスを説明するinteger 。port :ピアのIPv4ポートを説明するinteger 。さもないと:
addr :ピアのアドレスを説明するパック文字列。 socket.inetライブラリは、高レベルのIPv4ソケットをサポートしています。
inet.tcp() inet.tcp() af.inetアドレスファミリ、sock.streamタイプ、ipproto.tcpプロトコルを使用して新しいsocketを作成します。 socketメソッドをオーバーライドして、整数の代わりに、アドレスを数字とドットの表記( "127.0.0.1"など)として使用します。
inet.udp() inet.udp() af.inetアドレスファミリ、sock.dgramタイプ、ipproto.udpプロトコルを使用して新しいsocketを作成します。 socketメソッドをオーバーライドして、整数の代わりに、アドレスを数字とドットの表記( "127.0.0.1"など)として使用します。
udp:receivefrom(length [, flags]) udp:receivefrom()は、 sock:receive(length, flags, true)のエイリアスです。
rcuライブラリは、カーネル読み取りコピーアップデート(RCU)同期メカニズムのサポートを提供します。このライブラリは、Caio MessiasのGSOCプロジェクトに触発されました。
rcu.table([size]) rcu.table()カーネルジェネリックハッシュテーブルをバインドする新しいrcu.tableオブジェクトを作成します。この関数は、次のパワー2のバケツの数を引数として受信します。デフォルトサイズは1024です。キーは文字列でなければならず、値はlunatikオブジェクトまたはnilでなければなりません。
threadライブラリは、カーネルスレッドプリミティブのサポートを提供します。
thread.run(runtime, name) thread.run() creates a new thread object and wakes it up.この関数は、次の引数を受け取ります。
runtime :作成されたカーネルスレッドでタスクを実行するためのランタイム環境。タスクは、 runtime環境にロードされたスクリプトの関数を返すことで指定する必要があります。name :スレッドの名前を表す文字列(例えば、 psに示されているように)。 thread.shouldstop() thread.shouldStop()は、thread.stop()が呼び出された場合にtrueを返します。それ以外の場合、それはfalseを返します。
thread.current() thread.current()現在のタスクを表すthreadオブジェクトを返します。
thrd:stop() thrd:stop() setswers.shouldStop()をスレッドthrdに設定して、trueを返し、 thrdを目覚めさせ、終了するのを待ちます。
thrd:task() thrd:task()このthreadのタスク情報を含むテーブル( "cpu"、 "command"、 "pid"、 "tgid")を返します。
fibライブラリは、カーネル転送情報ベースのサポートを提供します。
fib.newrule(table, priority)fib.newrule()は、kernel fib_nl_newrule apiをバインドします。指定されたルーティングテーブルと指定された先駆者に一致する新しいFIBルールを作成します。この関数は、iproute2が提供するユーザー空間コマンドIPルールの追加に似ています。
fib.delrule(table, priority)fib.delrule()は、kernel fib_nl_delrule apiにバインドします。指定されたルーティングテーブルと指定された先駆者に一致するFIBルールを削除します。 This function is similar to the user-space command ip rule del provided by iproute2.
The data library provides support for binding the system memory to Lua.
data.new(size) data.new() creates a new data object which allocates size bytes.
d:getnumber(offset) d:getnumber() extracts a lua_Integer from the memory referenced by a data object and a byte offset , starting from zero.
d:setnumber(offset, number) d:setnumber() insert a lua_Integer number into the memory referenced by a data object and a byte offset , starting from zero.
d:getbyte(offset) d:getbyte() extracts a byte from the memory referenced by a data object and a byte offset , starting from zero.
d:setbyte(offset, byte) d:setbyte() insert a byte into the memory referenced by a data object and a byte offset , starting from zero.
d:getstring(offset[, length]) d:getstring() extracts a string with length bytes from the memory referenced by a data object and a byte offset , starting from zero. If length is omitted, it extracts all bytes from offset to the end of the data .
d:setstring(offset, s) d:setstring() insert the string s into the memory referenced by a data object and a byte offset , starting from zero.
d:getint8(offset) d:getint8(d, offset) extracts a signed 8-bit integer from the memory referenced by a data object and a byte offset , starting from zero.
d:setint8(offset, number) d:setint8() inserts a signed 8-bit number into the memory referenced by a data object and a byte offset , starting from zero.
d:getuint8(offset) d:getuint8() extracts an unsigned 8-bit integer from the memory referenced by a data object and a byte offset , starting from zero.
d:setuint8(offset, number) d:setuint8() inserts an unsigned 8-bit number into the memory referenced by a data object and a byte offset , starting from zero.
d:getint16(offset) d:getint16() extracts a signed 16-bit integer from the memory referenced by a data object and a byte offset , starting from zero.
d:setint16(offset, number) d:setint16() inserts a signed 16-bit number into the memory referenced by a data object and a byte offset , starting from zero.
d:getuint16(offset) d:getuint16() extracts an unsigned 16-bit integer from the memory referenced by a data object and a byte offset , starting from zero.
d:setuint16(offset, number) d:setuint16() inserts an unsigned 16-bit number into the memory referenced by a data object and a byte offset , starting from zero.
d:getint32(offset) d:getint32() extracts a signed 32-bit integer from the memory referenced by a data object and a byte offset , starting from zero.
d:setint32(offset, number) d:setint32() inserts a signed 32-bit number into the memory referenced by a data object and a byte offset , starting from zero.
d:getuint32(offset) d:getuint32() extracts an unsigned 32-bit integer from the memory referenced by a data object and a byte offset , starting from zero.
d:setuint32(offset, number) d:setuint32() inserts an unsigned 32-bit number into the memory referenced by a data object and a byte offset , starting from zero.
d:getint64(offset) d:getint64() extracts a signed 64-bit integer from the memory referenced by a data object and a byte offset , starting from zero.
d:setint64(offset, number) d:setint64() inserts a signed 64-bit number into the memory referenced by a data object and a byte offset , starting from zero.
The probe library provides support for kernel probes.
probe.new(symbol|address, handlers) probe.new()カーネルsymbol (文字列)またはaddress (ライトユーザーData)を監視するための新しいprobeオブジェクトを返し、システムにhandlersをインストールします。 The handler must be defined as a table containing the following field:
pre : function to be called before the probed instruction. It receives the symbol or address , followed by a closure that may be called to show the CPU registers and stack in the system log.post : function to be called after the probed instruction. It receives the symbol or address , followed by a closure that may be called to show the CPU registers and stack in the system log. p:stop() p:stop() removes the probe handlers from the system.
p:enable(bool) p:enable() enables or disables the probe handlers, accordingly to bool .
The syscall library provides support for system call addresses and numbers.
syscall.address(number) syscall.address() returns the system call address (light userdata) referenced by the given number .
syscall.number(name) syscall.number() returns the system call number referenced by the given name .
The syscall.table library provides support for translating system call names to addresses (light userdata).
The xdp library provides support for the kernel eXpress Data Path (XDP) subsystem. This library was inspired by Victor Nogueira's GSoC project.
xdp.attach(callback) xdp.attach() registers a callback function to the current runtime to be called from an XDP/eBPF program whenever it calls bpf_luaxdp_run kfunc. This callback receives the following arguments:
buffer : a data object representing the network buffer.argument : a data object containing the argument passed by the XDP/eBPF program. The callback function might return the values defined by the xdp.action table.
xdp.detach() xdp.detach() unregisters the callback associated with the current runtime , if any.
xdp.actionxdp.action is a table that exports xdp_action flags to Lua.
"ABORTED" : Indicates that the XDP program aborted, typically due to an error."DROP" : Specifies that the packet should be dropped, discarding it entirely."PASS" : Allows the packet to pass through to the Linux network stack."TX" : Transmits the packet back out on the same interface it was received."REDIRECT" : Redirects the packet to another interface or processing context. The xtable library provides support for developing netfilter xtable extensions.
xtable.match(opts)xtable.match() returns a new xtable object for match extensions. This function receives the following arguments:
opts : a table containing the following fields:name : string representing the xtable extension name.revision : integer representing the xtable extension revision.family : address family, one of netfilter.family.proto : protocol number, one of socket.ipproto.hooks :拡張機能を添付するためのフック、フックテーブルのいずれかの1つの値-netfilter.inet_hooks、netfilter.bridge_hooks、netfilter.arp_hooks(注:netfilter.netdev_hooksはレガシーx_tablesで使用できません)。 (Eg - 1 << inet_hooks.LOCAL_OUT ).match :一致するパケットのために呼び出される機能。次の引数を受け取ります。skb (Readonly):ソケットバッファを表すdataオブジェクト。par : hotdrop 、 thoff (トランスポートヘッダーオフセット)、 fragoff (Fragment Offset)フィールドを含むテーブル。userargs :userspace xtableモジュールから渡されたLUA文字列。trueを返す必要があります。それ以外の場合は、 falseを返す必要があります。checkentry :エントリをチェックするために呼び出される機能。この関数は、その引数としてuserargsを受信します。destroy :XTABLE拡張機能を破壊するために呼び出される機能。この関数は、その引数としてuserargsを受信します。 xtable.target(opts)Xtable.target()は、ターゲット拡張機能の新しいXTableオブジェクトを返します。この関数は、次の引数を受け取ります。
opts :次のフィールドを含むテーブル:name :Xtable拡張機能名を表す文字列。revision :XTABLE拡張機能を表す整数。family :netfilter.familyの1人、家族を住所します。proto :Socket.Ipprotoの1つ、プロトコル番号。hooks :拡張機能を添付するためのフック、フックテーブルのいずれかの1つの値-netfilter.inet_hooks、netfilter.bridge_hooks、netfilter.arp_hooks(注:netfilter.netdev_hooksはレガシーx_tablesで使用できません)。 (例1 << inet_hooks.LOCAL_OUT )。target :ターゲットパケットのために呼び出される機能。次の引数を受け取ります。skb :ソケットバッファを表すdataオブジェクト。par (Readonly): hotdrop 、 thoff (Transport Header Offset)、 fragoff (Fragment Offset)フィールドを含むテーブル。userargs :userspace xtableモジュールから渡されたLUA文字列。checkentry :エントリをチェックするために呼び出される機能。この関数は、その引数としてuserargsを受信します。destroy :XTABLE拡張機能を破壊するために呼び出される機能。この関数は、その引数としてuserargsを受信します。 netfilterライブラリは、新しいNetFilterフックシステムをサポートしています。
netfilter.register(ops) netfilter.register()は、指定されたopsテーブルで新しいNetFilterフックを登録します。 This function receives the following arguments:
ops : a table containing the following fields:pf : protocol family, one of netfilter.familyhooknum :フックをフックフィルターに接続します。フックテーブルのいずれかから1つの値-netfilter.inet_hooks、netfilter.bridge_hooks、netfilter.arp_hooks、netfilter.netdev_hooks。 (Eg - inet_hooks.LOCAL_OUT + 11 ).priority : priority of the hook. One of the values from the netfilter.ip_priority or netfilter.bridge_priority tables.hook : function to be called for the hook. It receives the following arguments:skb : a data object representing the socket buffer.netfilter.familynetfilter.family is a table that exports address families to Lua.
"UNSPEC" : Unspecified."INET" : Internet Protocol version 4."IPV4" : Internet Protocol version 4."IPV6" : Internet Protocol version 6."ARP" : Address Resolution Protocol."NETDEV" : Device ingress and egress path"BRIDGE" : Ethernet Bridge. netfilter.actionnetfilter.action is a table that exports netfilter actions to Lua.
"DROP" : NF_DROP . The packet is dropped. It is not forwarded, processed, or seen by any other network layer."ACCEPT" : NF_ACCEPT . The packet is accepted and passed to the next step in the network processing chain."STOLEN" : NF_STOLEN . The packet is taken by the handler, and processing stops."QUEUE" : NF_QUEUE . The packet is queued for user-space processing."REPEAT" : NF_REPEAT . The packet is sent through the hook chain again."STOP" : NF_STOP . Processing of the packet stops."CONTINUE" : XT_CONTINUE . Return the packet should continue traversing the rules within the same table."RETURN" : XT_RETURN . Return the packet to the previous chain. netfilter.inet_hooksnetfilter.inet_hooks is a table that exports inet netfilter hooks to Lua.
"PRE_ROUTING" : NF_INET_PRE_ROUTING . The packet is received by the network stack."LOCAL_IN" : NF_INET_LOCAL_IN . The packet is destined for the local system."FORWARD" : NF_INET_FORWARD . The packet is to be forwarded to another host."LOCAL_OUT" : NF_INET_LOCAL_OUT . The packet is generated by the local system."POST_ROUTING" : NF_INET_POST_ROUTING . The packet is about to be sent out. netfilter.bridge_hooksnetfilter.bridge_hooks is a table that exports bridge netfilter hooks to Lua.
"PRE_ROUTING" : NF_BR_PRE_ROUTING . First hook invoked, runs before forward database is consulted."LOCAL_IN" : NF_BR_LOCAL_IN . Invoked for packets destined for the machine where the bridge was configured on."FORWARD" : NF_BR_FORWARD . Called for frames that are bridged to a different port of the same logical bridge device."LOCAL_OUT" : NF_BR_LOCAL_OUT . Called for locally originating packets that will be transmitted via the bridge."POST_ROUTING" : NF_BR_POST_ROUTING . Called for all locally generated packets and all bridged packets netfilter.arp_hooksnetfilter.arp_hooks is a table that exports arp netfilter hooks to Lua.
"IN" : NF_ARP_IN . The packet is received by the network stack."OUT" : NF_ARP_OUT . The packet is generated by the local system."FORWARD" : NF_ARP_FORWARD . The packet is to be forwarded to another host. netfilter.netdev_hooksnetfilter.netdev_hooks is a table that exports netdev netfilter hooks to Lua.
"INGRESS" : NF_NETDEV_INGRESS . The packet is received by the network stack."EGRESS" : NF_NETDEV_EGRESS . The packet is generated by the local system. netfilter.ip_prioritynetfilter.ip_priority is a table that exports netfilter IPv4/IPv6 priority levels to Lua.
"FIRST" : NF_IP_PRI_FIRST"RAW_BEFORE_DEFRAG" : NF_IP_PRI_RAW_BEFORE_DEFRAG"CONNTRACK_DEFRAG" : NF_IP_PRI_CONNTRACK_DEFRAG"RAW" : NF_IP_PRI_RAW"SELINUX_FIRST" : NF_IP_PRI_SELINUX_FIRST"CONNTRACK" : NF_IP_PRI_CONNTRACK"MANGLE" : NF_IP_PRI_MANGLE"NAT_DST" : NF_IP_PRI_NAT_DST"FILTER" : NF_IP_PRI_FILTER"SECURITY" : NF_IP_PRI_SECURITY"NAT_SRC" : NF_IP_PRI_NAT_SRC"SELINUX_LAST" : NF_IP_PRI_SELINUX_LAST"CONNTRACK_HELPER" : NF_IP_PRI_CONNTRACK_HELPER"LAST" : NF_IP_PRI_LAST netfilter.bridge_prioritynetfilter.bridge_priority is a table that exports netfilter bridge priority levels to Lua.
"FIRST" : NF_BR_PRI_FIRST"NAT_DST_BRIDGED" : NF_BR_PRI_NAT_DST_BRIDGED"FILTER_BRIDGED" : NF_BR_PRI_FILTER_BRIDGED"BRNF" : NF_BR_PRI_BRNF"NAT_DST_OTHER" : NF_BR_PRI_NAT_DST_OTHER"FILTER_OTHER" : NF_BR_PRI_FILTER_OTHER"NAT_SRC" : NF_BR_PRI_NAT_SRC"LAST" : NF_BR_PRI_LAST The luaxt userspace library provides support for generating userspace code for xtable extensions.
To build the library, the following steps are required:
usr/lib/xtable and create a libxt_<ext_name>.lua file.luaxt ) in the created file.LUAXTABLE_MODULE=<ext_name> make to build the extension and LUAXTABLE_MODULE=<ext_name> make install (as root) to install the userspace plugin to the system. Now load the extension normally using iptables .
luaxt.match(opts)luaxt.match() returns a new luaxt object for match extensions. This function receives the following arguments:
opts : a table containing the following fields:revision : integer representing the xtable extension revision ( must be same as used in corresponding kernel extension).family : address family, one of luaxt.familyhelp : function to be called for displaying help message for the extension.init : function to be called for initializing the extension. This function receives an par table that can be used to set userargs . ( par.userargs = "mydata" )print : function to be called for printing the arguments. This function recevies userargs set by the init or parse function.save : function to be called for saving the arguments. This function recevies userargs set by the init or parse function.parse : function to be called for parsing the command line arguments. This function receives an par table that can be used to set userargs and flags . ( par.userargs = "mydata" )final_check : function to be called for final checking of the arguments. This function receives flags set by the parse function. luaxt.target(opts)luaxt.target() returns a new luaxt object for target extensions. This function receives the following arguments:
opts : a table containing the following fields:revision : integer representing the xtable extension revision ( must be same as used in corresponding kernel extension).family : address family, one of luaxt.familyhelp : function to be called for displaying help message for the extension.init : function to be called for initializing the extension. This function receives an par table that can be used to set userargs . ( par.userargs = "mydata" )print : function to be called for printing the arguments. This function recevies userargs set by the init or parse function.save : function to be called for saving the arguments. This function recevies userargs set by the init or parse function.parse : function to be called for parsing the command line arguments. This function receives an par table that can be used to set userargs and flags . ( par.userargs = "mydata" )final_check : function to be called for final checking of the arguments. This function receives flags set by the parse function. luaxt.familyluaxt.family is a table that exports address families to Lua.
"UNSPEC" : Unspecified."INET" : Internet Protocol version 4."IPV4" : Internet Protocol version 4."IPV6" : Internet Protocol version 6."ARP" : Address Resolution Protocol."NETDEV" : Device ingress and egress path"BRIDGE" : Ethernet Bridge.completion The completion library provides support for the kernel completion primitives.
Task completion is a synchronization mechanism used to coordinate the execution of multiple threads, similar to pthread_barrier , it allows threads to wait for a specific event to occur before proceeding, ensuring certain tasks are complete in a race-free manner.
completion.new() completion.new() creates a new completion object.
c:complete()c:complete() signals a single thread waiting on this completion.
c:wait([timeout]) c:wait() waits for completion of a task until the specified timeout expires. The timeout is specified in milliseconds. If the timeout parameter is omitted, it waits indefinitely. Passing a timeout value less than zero results in undefined behavior. Threads waiting for events can be interrupted by signals, for example, such as when thread.stop is invoked. Therefore, this function can return in three ways:
truenil, "timeout"nil, "interrupt" spyglass is a kernel script that implements a keylogger inspired by the spy kernel module. This kernel script logs the keysym of the pressed keys in a device ( /dev/spyglass ). If the keysym is a printable character, spyglass logs the keysym itself; otherwise, it logs a mnemonic of the ASCII code, (eg, <del> stands for 127 ).
sudo make examples_install # installs examples
sudo lunatik run examples/spyglass # runs spyglass
sudo tail -f /dev/spyglass # prints the key log
sudo sh -c "echo 'enable=false' > /dev/spyglass" # disable the key logging
sudo sh -c "echo 'enable=true' > /dev/spyglass" # enable the key logging
sudo sh -c "echo 'net=127.0.0.1:1337' > /dev/spyglass" # enable network support
nc -lu 127.0.0.1 1337 & # listen to UDP 127.0.0.1:1337
sudo tail -f /dev/spyglass # sends the key log through the network
keylocker is a kernel script that implements Konami Code for locking and unlocking the console keyboard. When the user types ↑ ↑ ↓ ↓ ← → ← → LCTRL LALT , the keyboard will be locked ; that is, the system will stop processing any key pressed until the user types the same key sequence again.
sudo make examples_install # installs examples
sudo lunatik run examples/keylocker # runs keylocker
<↑> <↑> <↓> <↓> <←> <→> <←> <→> <LCTRL> <LALT> # locks keyboard
<↑> <↑> <↓> <↓> <←> <→> <←> <→> <LCTRL> <LALT> # unlocks keyboard
tap is a kernel script that implements a sniffer using AF_PACKET socket. It prints destination and source MAC addresses followed by Ethernet type and the frame size.
sudo make examples_install # installs examples
sudo lunatik run examples/tap # runs tap
cat /dev/tap
shared is a kernel script that implements an in-memory key-value store using rcu, data, socket and thread.
sudo make examples_install # installs examples
sudo lunatik spawn examples/shared # spawns shared
nc 127.0.0.1 90 # connects to shared
foo=bar # assigns "bar" to foo
foo # retrieves foo
bar
^C # finishes the connection
echod is an echo server implemented as kernel scripts.
sudo make examples_install # installs examples
sudo lunatik spawn examples/echod/daemon # runs echod
nc 127.0.0.1 1337
hello kernel!
hello kernel!
systrack is a kernel script that implements a device driver to monitor system calls. It prints the amount of times each system call was called since the driver has been installed.
sudo make examples_install # installs examples
sudo lunatik run examples/systrack # runs systracker
cat /dev/systrack
writev: 0
close: 1927
write: 1085
openat: 2036
read: 4131
readv: 0
filter is a kernel extension composed by a XDP/eBPF program to filter HTTPS sessions and a Lua kernel script to filter SNI TLS extension. This kernel extension drops any HTTPS request destinated to a blacklisted server.
Compile and install libbpf , libxdp and xdp-loader :
mkdir -p " ${LUNATIK_DIR} " ; cd " ${LUNATIK_DIR} " # LUNATIK_DIR must be set to the same value as above (Setup section)
git clone --depth 1 --recurse-submodules https://github.com/xdp-project/xdp-tools.git
cd xdp-tools/lib/libbpf/src
make
sudo DESTDIR=/ make install
cd ../../../
make libxdp
cd xdp-loader
make
sudo make installCome back to this repository, install and load the filter:
cd ${LUNATIK_DIR} /lunatik # cf. above
sudo make btf_install # needed to export the 'bpf_luaxdp_run' kfunc
sudo make examples_install # installs examples
make ebpf # builds the XDP/eBPF program
sudo make ebpf_install # installs the XDP/eBPF program
sudo lunatik run examples/filter/sni false # runs the Lua kernel script
sudo xdp-loader load -m skb < ifname > https.o # loads the XDP/eBPF programFor example, testing is easy thanks to docker. Assuming docker is installed and running:
sudo xdp-loader load -m skb docker0 https.o
sudo journalctl -ft kerneldocker run --rm -it alpine/curl https://ebpf.io The system logs (in the first terminal) should display filter_sni: ebpf.io DROP , and the docker run… should return curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to ebpf.io:443 .
This other sni filter uses netfilter api.
dnsblock is a kernel script that uses the lunatik xtable library to filter DNS packets. This script drops any outbound DNS packet with question matching the blacklist provided by the user.
sudo make examples_install # installs examples
cd examples/dnsblock
make # builds the userspace extension for netfilter
sudo make install # installs the extension to Xtables directory
sudo lunatik run examples/dnsblock/dnsblock false # runs the Lua kernel script
sudo iptables -A OUTPUT -m dnsblock -j DROP # this initiates the netfilter framework to load our extension
sudo make examples_install # installs examples
sudo lunatik run examples/dnsblock/nf_dnsblock false # runs the Lua kernel script
dnsdoctor is a kernel script that uses the lunatik xtable library to change the DNS response from Public IP to a Private IP if the destination IP matches the one provided by the user. For example, if the user wants to change the DNS response from 192.168.10.1 to 10.1.2.3 for the domain lunatik.com if the query is being sent to 10.1.1.2 (a private client), this script can be used.
sudo make examples_install # installs examples
cd examples/dnsdoctor
setup.sh # sets up the environment
# test the setup, a response with IP 192.168.10.1 should be returned
dig lunatik.com
# run the Lua kernel script
sudo lunatik run examples/dnsdoctor/dnsdoctor false
# build and install the userspace extension for netfilter
make
sudo make install
# add rule to the mangle table
sudo iptables -t mangle -A PREROUTING -p udp --sport 53 -j dnsdoctor
# test the setup, a response with IP 10.1.2.3 should be returned
dig lunatik.com
# cleanup
sudo iptables -t mangle -D PREROUTING -p udp --sport 53 -j dnsdoctor # remove the rule
sudo lunatik unload
cleanup.sh
sudo make examples_install # installs examples
examples/dnsdoctor/setup.sh # sets up the environment
# test the setup, a response with IP 192.168.10.1 should be returned
dig lunatik.com
# run the Lua kernel script
sudo lunatik run examples/dnsdoctor/nf_dnsdoctor false
# test the setup, a response with IP 10.1.2.3 should be returned
dig lunatik.com
# cleanup
sudo lunatik unload
examples/dnsdoctor/cleanup.sh
Lunatik is dual-licensed under MIT or GPL-2.0-only.
Lua submodule is licensed under MIT. For more details, see its Copyright Notice.
Klibc submodule is dual-licensed under BSD 3-Clause or GPL-2.0-only. For more details, see its LICENCE file.