Lunatik هو إطار لبرمجة Kernel Linux مع Lua. يتكون من مترجم LUA المعدل لتشغيله في النواة ؛ برنامج تشغيل الجهاز (مكتوب في LUA =)) وأداة سطر الأوامر لتحميل وتشغيل البرامج النصية وإدارة بيئات وقت التشغيل من مساحة المستخدم ؛ A C API لتحميل وتشغيل البرامج النصية وإدارة بيئات وقت التشغيل من kernel ؛ و LUA APIs لمرافق kernel ملزمة لنصوص LUA.
فيما يلي مثال على برنامج تشغيل جهاز حرف مكتوب في لوا باستخدام Lunatik لإنشاء أحرف 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 بمجرد الانتهاء ، يمكن نسخ debian_kernel_postinst_lunatik.sh من الأدوات/قد يتم نسخه في /etc/kernel/postinst.d/ : هذا يضمن lunatik (وأيضًا libs xdp ) مُرشح على ترقية kernel.
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 : تحميل وحدات kernel lunatikunload : تفريغ وحدات kernel lunatikreload : تحديث وحدات kernel lunatikstatus : أظهر وحدات kernel Lunatik التي يتم تحميلها حاليًاlist : إظهار بيئات وقت التشغيل تعمل حاليًاrun : إنشاء بيئة وقت تشغيل جديدة لتشغيل البرنامج النصي /lib/modules/lua/<script>.lua lua/<script>.spawn : قم بإنشاء بيئة وقت تشغيل جديدة وتفرخ مؤشر ترابط لتشغيل البرنامج النصي /lib/modules/lua/<script>.lua lua/<script>.stop : أوقف بيئة وقت التشغيل التي تم إنشاؤها لتشغيل البرنامج النصي <script>default : ابدأ عملية استبدال (اقرأ - حلقة طباعة val -eval) يعتمد Lunatik 3.4 على LUA 5.4 تم تكييفه لتشغيله في النواة.
لا يدعم Lunatik الحساب العائم ، وبالتالي فهو لا يدعم __div ولا __pow والرقم النوع له فقط عدد صحيح من النوع الفرعي.
لا يدعم Lunatik مكتبات IO و OS ، ومعرفات معينة من المكتبات التالية:
Lunatik يعدل المعرفات التالية:
"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 جديدة ثم يقوم بتحميل وتشغيل البرنامج النصي /lib/modules/lua/<script>.lua lua/<script>. 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 () Mutex لقفل بيئة 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 () بتعيين العنوان الذي أشار إليه pruntime و Lua الإضافي مع مؤشر لبيئة runtime الجديدة التي تم إنشاؤها ، وتعين العداد المرجعي إلى 1 ثم إرجاع 0 . 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 مرور ولاية لوا المرتبطة كأول وسيطة تليها الوسائط المتنوعة. 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 () ينشئ بيئة وقت تشغيل جديدة ثم يقوم بتحميل وتشغيل البرنامج النصي /lib/modules/lua/<script>.lua lua/<script>. 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. The driver must be defined as a table containing the following field:
name : string defining the device name; it is used for creating the device file (eg, /dev/<name> ). The driver table might optionally contain the following fields:
read : callback function to handle the read operation on the device file. It receives the driver table as the first argument followed by two integers, the length to be read and the file offset . It should return a string and, optionally, the updated offset . If the length of the returned string is greater than the requested length , the string will be corrected to that length . If the updated offset is not returned, the offset will be updated with offset + length .write : callback function to handle the write operation on the device file. It receives the driver table as the first argument followed by the string to be written and an integer as the file offset . It might return optionally the written length followed by the updated offset . If the returned length is greater than the requested length , the returned length will be corrected. If the updated offset is not returned, the offset will be updated with offset + length .open : وظيفة رد الاتصال للتعامل مع العملية المفتوحة على ملف الجهاز. It receives the driver table and it is expected to return nothing.release : callback function to handle the release operation on the device file. يستقبل جدول driver ومن المتوقع أن يعيد أي شيء.mode : عدد صحيح يحدد وضع ملف الجهاز. إذا لم يتم تعريف رد اتصال العملية ، فإن device يعيد -ENXIO إلى VFS عند وصوله.
device.stop(dev) ، dev:stop() Device.stop () يزيل driver جهاز محدد بواسطة كائن dev من النظام.
توفر مكتبة linux الدعم لبعض مرافق Kernel Linux.
linux.random([m [, n]])Linux.Random () يحاكي سلوك Math.Random ، ولكن الربط <Linux/Random.h> s get_random_u32 () و get_random_u64 () واجهات برمجة التطبيقات.
عند استدعاء بدون حجج ، ينتج عددًا صحيحًا مع جميع البتات العشوائية (pseudo). عندما يتم استدعاؤها مع اثنين من الأعداد الصحيحة m و n ، تقوم Linux.random () بإرجاع عدد صحيح من العشبية الزائفة مع توزيع موحد في النطاق [m, n] . المكالمة math.random(n) ، من أجل n إيجابي ، تعادل math.random(1, n) .
linux.statLinux.Stat هو جدول يصدر <Linux/Stat.h> Integer Flags to Lua.
"IRWXUGO" : إذن للقراءة والكتابة والتنفيذ للمستخدم والمجموعة وغيرها ."IRUGO" : إذن فقط للقراءة للمستخدم والمجموعة وغيرها ."IWUGO" : إذن فقط للكتابة للمستخدم والمجموعة وغيرها ."IXUGO" : إذن فقط للتنفيذ للمستخدم والمجموعة وغيرها . linux.schedule([timeout [, state]]) Linux.Schedule () يضع state المهمة الحالية ويجعلها تنام حتى تنقضي timeout ثانية. إذا تم حذف timeout ، فإنه يستخدم MAX_SCHEDULE_TIMEOUT . إذا تم حذف state ، فإنها تستخدم task.INTERRUPTIBLE .
linux.taskLinux.task هو جدول يصدر أعلام حالة المهمة إلى لوا.
"RUNNING" : المهمة تنفذ على وحدة المعالجة المركزية أو في انتظار تنفيذها."INTERRUPTIBLE" : المهمة تنتظر إشارة أو مورد (نوم)."UNINTERRUPTIBLE" : يتصرف مثل "مقاطع" باستثناء أن الإشارة لن تستيقظ المهمة."KILLABLE" : يتصرف مثل "غير متقطع" باستثناء أن الإشارات المميتة ستستيقظ المهمة."IDLE" : يتصرف مثل "غير متوقعة" باستثناء أنه يتجنب محاسبة Loadavg. linux.time()Linux.Time () إرجاع الوقت الحالي في النانو ثانية منذ فترة.
linux.errnoLinux.Errno هو جدول يصرخ <uapi/asm-generic/errno-base.h> أعلام لوا.
"PERM" : العملية غير مسموح بها."NOENT" : لا يوجد مثل هذا الملف أو الدليل."SRCH" : لا توجد عملية."INTR" : استدعاء النظام المقطع."IO" : خطأ I/O."NXIO" : لا يوجد مثل هذا الجهاز أو العنوان."2BIG" : ، قائمة الوسيطة طويلة جدًا."NOEXEC" : EXEC Exect Error."BADF" : رقم الملف السيئ."CHILD" : لا توجد عمليات طفل."AGAIN" : حاول مرة أخرى."NOMEM" : من الذاكرة."ACCES" : تم رفض الإذن."FAULT" : العنوان السيئ."NOTBLK" : حظر الجهاز المطلوب."BUSY" : جهاز أو مورد مشغول."EXIST" : ملف موجود."XDEV" : رابط الجهاز."NODEV" : لا مثل هذا الجهاز."NOTDIR" : ليس دليلًا."ISDIR" : هو دليل."INVAL" : وسيطة غير صالحة."NFILE" : File Table Overflow."MFILE" : الكثير من الملفات المفتوحة."NOTTY" : ليس آلة كاتبة."TXTBSY" : ملف نصي مشغول."FBIG" : ملف كبير جدا."NOSPC" : لا توجد مساحة على الجهاز."SPIPE" : سعي غير قانوني."ROFS" : نظام الملفات للقراءة فقط."MLINK" : الكثير من الروابط."PIPE" : أنبوب مكسور."DOM" : حجة الرياضيات خارج مجال Func."RANGE" : نتائج الرياضيات غير ممثلة. linux.hton16(num)يقوم Linux.hton16 () بتحويل طلب بايت المضيف إلى شبكة بايت الشبكة لمكانة 16 بت.
linux.hton32(num)يقوم Linux.hton32 () بتحويل طلب بايت المضيف إلى شبكة بايت الشبكة لمكانة 32 بت.
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.
The notifier library provides support for the kernel notifier chains.
notifier.keyboard(callback) notifier.keyboard() returns a new keyboard notifier object and installs it in the system. The callback function is called whenever a console keyboard event happens (eg, a key has been pressed or released). This callback receives the following arguments:
event : the available events are defined by the notifier.kbd table.down : true , if the key is pressed; false , if it is released.shift : true , if the shift key is held; false , otherwise.key : keycode or keysym depending on event . The callback function might return the values defined by the notifier.notify table.
notifier.kbdnotifier.kbd is a table that exports KBD flags to Lua.
"KEYCODE" : keyboard keycode , called before any other."UNBOUND_KEYCODE" : keyboard keycode which is not bound to any other."UNICODE" : keyboard unicode."KEYSYM" : keyboard keysym ."POST_KEYSYM" : called after keyboard keysym interpretation. notifier.netdevice(callback) notifier.netdevice() returns a new netdevice notifier object and installs it in the system. The callback function is called whenever a console netdevice event happens (eg, a network interface has been connected or disconnected). This callback receives the following arguments:
event : the available events are defined by the notifier.netdev table.name : the device name. The callback function might return the values defined by the notifier.notify table.
notifier.netdevnotifier.netdev is a table that exports NETDEV flags to Lua.
notifier.notifynotifier.notify is a table that exports NOTIFY flags to Lua.
"DONE" : don't care."OK" : suits me."BAD" : bad/veto action."STOP" : clean way to return from the notifier and stop further calls. notfr:delete() notfr:delete() removes a notifier specified by the notfr object from the system.
The socket library provides support for the kernel networking handling. This library was inspired by Chengzhi Tan's GSoC project.
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" : مخصص لمشروع X.25."INET6" : IP الإصدار 6."ROSE" : راديو الهواة X.25 PLP."DEC" : مخصص لمشروع DECNET."NETBEUI" : محجوز لمشروع 802.2LLC."SECURITY" : رد الاتصال الأمنية الزائفة AF."KEY" : PF_KEY MANAGEMENT API."NETLINK" : NetLink."ROUTE" : الاسم المستعار لمحاكاة 4.4bsd."PACKET" : عائلة الحزمة."ASH" : الرماد."ECONET" : Acorn Econet."ATMSVC" : ATM SVCs."RDS" : مآخذ RDS."SNA" : Linux SNA Project (Nutters!)."IRDA" : Irda Sockets."PPPOX" : مآخذ PPPOX."WANPIPE" : مآخذ Wanpipe API."LLC" : Linux LLC."IB" : عنوان Infiniband الأصلي."MPLS" : MPLS."CAN" : شبكة منطقة التحكم."TIPC" : Tipc Sockets."BLUETOOTH" : مآخذ بلوتوث."IUCV" : مآخذ IUCV."RXRPC" : مآخذ RXRPC."ISDN" : مآخذ MISDN."PHONET" : مآخذ صوتي."IEEE802154" : IEEE802154 Sockets."CAIF" : CAIF Sockets."ALG" : مآخذ الخوارزمية."NFC" : مآخذ NFC."VSOCK" : vsockets."KCM" : kernel connection multiplexor."QIPCRTR" : Qualcomm IPC Router."SMC" : رقم احتياطي لعائلة بروتوكول PF_SMC التي تعيد استخدام عائلة AF_INET."XDP" : Sockets XDP."MCTP" : بروتوكول نقل مكونات الإدارة."MAX" : الحد الأقصى. socket.sockSocket.sock هو جدول يصدر أنواع المقبس (جورب):
"STREAM" : مقبس دفق (اتصال)."DGRAM" : Datagram (conn.less) socket."RAW" : المقبس الخام."RDM" : رسالة موثوق بها."SEQPACKET" : Sequential Packet Socket."DCCP" : مقبس بروتوكول التحكم في مزارع DATAGRAM."PACKET" : Linux طريقة محددة للحصول على الحزم على مستوى DEV.والأعلام (جورب):
"CLOEXEC" : n/a."NONBLOCK" : n/a. socket.ipprotoSocket.ipproto هو جدول يصدر بروتوكولات IP (ipproto) إلى لوا.
"IP" : بروتوكول دمية لـ TCP."ICMP" : بروتوكول رسالة التحكم في الإنترنت."IGMP" : بروتوكول إدارة مجموعة الإنترنت."IPIP" : أنفاق IPIP (تستخدم أنفاق KA9Q الأقدم 94)."TCP" : بروتوكول التحكم في النقل."EGP" : بروتوكول البوابة الخارجية."PUP" : بروتوكول الجرو."UDP" : بروتوكول بيانات المستخدم."IDP" : بروتوكول XNS IDP."TP" : لذا فئة بروتوكول النقل 4."DCCP" : بروتوكول التحكم في احتقان Datagram."IPV6" : IPv6-in-IPv4 tunnelling."RSVP" : بروتوكول RSVP."GRE" : Cisco GRE tunnels (rfc 1701,1702)."ESP" : Encapsulation Security Payload protocol."AH" : Authentication Header protocol."MTP" : Multicast Transport Protocol."BEETPH" : IP option pseudo header for BEET."ENCAP" : Encapsulation Header."PIM" : Protocol Independent Multicast."COMP" : Compression Header Protocol."SCTP" : Stream Control Transport Protocol."UDPLITE" : UDP-Lite (RFC 3828)."MPLS" : MPLS in IP (RFC 4023)."ETHERNET" : Ethernet-within-IPv6 Encapsulation."RAW" : Raw IP packets."MPTCP" : Multipath TCP connection. sock:close() sock:close() removes sock object from the system.
sock:send(message, [addr [, port]]) sock:send() sends a string message through the socket sock . 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. 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 (): قم بحظر حتى 1+ حزم."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]) جورب: Connect () يربط sock المقبس بعنوان addr . إذا كانت عائلة عنوان sock هي af.INET ، فإنها تتوقع الحجج التالية:
addr : integer يصف عنوان IPv4 الوجهة.port : integer يصف منفذ IPv4 الوجهة.خلاف ذلك:
addr : سلسلة معبأة تصف عنوان الوجهة.الأعلام المتاحة موجودة على جدول Socket.sock.
بالنسبة لمآخذ بيانات DataGram ، فإن addr هو العنوان الذي يتم إرسال بيانات بياناته افتراضيًا ، والعنوان الوحيد الذي يتم استلام مخططات البيانات منه. لمآخذ الدفق ، محاولات الاتصال بـ addr .
sock:getsockname() جورب: GetSockName () احصل على العنوان الذي يرتبط به sock المقبس. إذا كانت عائلة عنوان sock af.INET ، فإنها تُرجع ما يلي:
addr : integer يصف عنوان IPv4 المحدد.port : integer يصف منفذ IPv4 المحدود.خلاف ذلك:
addr : سلسلة معبأة تصف العنوان المحدد. sock:getpeername() جورب: getPeerName () احصل على العنوان الذي يتم توصيل sock المقبس. إذا كانت عائلة عنوان sock af.INET ، فإنها تُرجع ما يلي:
addr : integer يصف عنوان IPv4 من النظير.port : integer يصف منفذ IPv4 من النظير.خلاف ذلك:
addr : سلسلة معبأة تصف عنوان النظير. توفر مكتبة socket.inet الدعم لمآخذ IPv4 عالية المستوى.
inet.tcp() يقوم Inet.TCP () بإنشاء socket جديد باستخدام عائلة AF.Inet للعنوان ، Sock.stream type وبروتوكول ipproto.tcp. يتجاوز طرق socket لاستخدام العناوين كترميز أرقام ونقاط (على سبيل المثال ، "127.0.0.1" ) ، بدلاً من الأعداد الصحيحة.
inet.udp() Inet.udp () ينشئ socket جديدة باستخدام عائلة AF.Inet للعنوان ، Sock.dgram type وبروتوكول ipproto.udp. يتجاوز طرق socket لاستخدام العناوين كترميز أرقام ونقاط (على سبيل المثال ، "127.0.0.1" ) ، بدلاً من الأعداد الصحيحة.
udp:receivefrom(length [, flags]) UDP: RESECTFROM () هو مجرد اسم مستعار sock:receive(length, flags, true) .
توفر مكتبة rcu الدعم لآلية مزامنة تحديث Kernel للقراءة (RCU). كانت هذه المكتبة مستوحاة من مشروع GSOC Caio Messias.
rcu.table([size]) RCU.Table () ينشئ كائن rcu.table جديد يربط جدول التجزئة العام kernel. تستقبل هذه الوظيفة كوسيطة ، عدد الدلاء المستديرة حتى الطاقة التالية من 2. الحجم الافتراضي هو 1024 . يجب أن يكون المفتاح سلسلة ويجب أن تكون القيمة كائن Lunatik أو لا شيء.
توفر مكتبة thread الدعم لبراميل مؤشر ترابط kernel.
thread.run(runtime, name) Thread.run () ينشئ كائن thread جديد ويستيقظه. هذه الوظيفة تتلقى الوسائط التالية:
runtime : بيئة وقت التشغيل لتشغيل مهمة في مؤشر ترابط kernel الذي تم إنشاؤه. يجب تحديد المهمة من خلال إرجاع وظيفة على البرنامج النصي الذي تم تحميله في بيئة runtime .name : سلسلة تمثل اسم الموضوع (على سبيل المثال ، كما هو موضح في ps ). thread.shouldstop() thread.shouldstop () إرجاع true إذا تم استدعاء thread.stop () ؛ خلاف ذلك ، فإنه يعود false .
thread.current() Thread.Current () إرجاع كائن thread يمثل المهمة الحالية.
thrd:stop() THRD: STOP () تعيين THEARD.SHOULDSTOP () على THERD thrd لإرجاع TRUE ، ويستيقظ thrd ، وينتظر الخروج.
thrd:task() Thrd: Task () إرجاع جدول يحتوي على معلومات مهمة هذا thread (على سبيل المثال ، "CPU" ، "Command" ، "PID" و "TGID").
توفر مكتبة fib الدعم لقاعدة معلومات إعادة توجيه kernel.
fib.newrule(table, priority)fib.newrule () يربط kernel fib_nl_newrule api ؛ إنه ينشئ قاعدة FIB جديدة تتوافق مع جدول التوجيه المحدد مع المبتدئ المحدد. تشبه هذه الوظيفة قاعدة IP لأمر المستخدم المستخدم إضافة بواسطة iProute2.
fib.delrule(table, priority)fib.delrule () يربط kernel fib_nl_delrule api ؛ إنه يزيل قاعدة FIB التي تطابق جدول التوجيه المحدد مع المبتدئ المحدد. تشبه هذه الوظيفة قاعدة IP لأمر المستخدم المستخدم DEL المقدمة من IPROUTE2.
توفر مكتبة data الدعم لربط ذاكرة النظام بـ LUA.
data.new(size) Data.new () ينشئ كائن data جديد يخصص بايت size .
d:getnumber(offset) D: GetNumber () يستخرج LUA_INTEGER من الذاكرة المشار إليها بواسطة كائن data offset بايت ، بدءًا من الصفر.
d:setnumber(offset, number) D: SetNumber () أدخل number LUA_INTEGER في الذاكرة المشار إليها بواسطة كائن data offset بايت ، بدءًا من الصفر.
d:getbyte(offset) D: GetByte () يستخرج بايت من الذاكرة المشار إليها بواسطة كائن data offset بايت ، بدءًا من الصفر.
d:setbyte(offset, byte) D: Setbyte () أدخل بايت في الذاكرة المشار إليها بواسطة كائن data offset بايت ، بدءًا من الصفر.
d:getstring(offset[, length]) D: GetString () يستخلص سلسلة مع بايت length من الذاكرة المشار إليها بواسطة كائن data offset بايت ، بدءًا من الصفر. إذا تم حذف length ، فإنه يستخرج جميع البايتات من offset إلى نهاية data .
d:setstring(offset, s) D: SetString () أدخل السلسلة s في الذاكرة المشار إليها بواسطة كائن data offset بايت ، بدءًا من الصفر.
d:getint8(offset) D: GetInt8 (D ، Offset) يستخلص عدد صحيح موقّع 8 بت من الذاكرة المشار إليها بواسطة كائن data offset بايت ، بدءًا من الصفر.
d:setint8(offset, number) D: SetInt8 () إدراج رقم 8 بت موقّع في الذاكرة المشار إليها بواسطة كائن data offset بايت ، بدءًا من الصفر.
d:getuint8(offset) D: GetUint8 () يستخلص عدد صحيح 8 بت غير موقّع من الذاكرة المشار إليها بواسطة كائن data offset بايت ، بدءًا من الصفر.
d:setuint8(offset, number) D: Setuint8 () إدراج رقم 8 بت غير موقّع في الذاكرة المشار إليها بواسطة كائن data offset بايت ، بدءًا من الصفر.
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 () إرجاع كائن probe جديد لمراقبة symbol kernel (سلسلة) أو address (Light userData) ويقوم بتثبيت 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 : ربط لإرفاق الامتداد ، قيمة واحدة من أي من جدول السنانير - netfilter.inet_hooks ، netfilter.bridge_hooks و netfilter.arp_hooks (ملاحظة: netfilter.netdev_hooks غير متوفر للإرث x_tables). (Eg - 1 << inet_hooks.LOCAL_OUT ).match : function to be called for matching packets. It receives the following arguments:skb (readonly): a data object representing the socket buffer.par : a table containing hotdrop , thoff (transport header offset) and fragoff (fragment offset) fields.userargs : a lua string passed from the userspace xtable module.true if the packet matches the extension; otherwise, it must return false .checkentry : function to be called for checking the entry. This function receives userargs as its argument.destroy : function to be called for destroying the xtable extension. This function receives userargs as its argument. xtable.target(opts)xtable.target() returns a new xtable object for target extension. 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 : ربط لإرفاق الامتداد ، قيمة واحدة من أي من جدول السنانير - netfilter.inet_hooks ، netfilter.bridge_hooks و netfilter.arp_hooks (ملاحظة: netfilter.netdev_hooks غير متوفر للإرث x_tables). (Eg - 1 << inet_hooks.LOCAL_OUT ).target : function to be called for targeting packets. It receives the following arguments:skb : a data object representing the socket buffer.par (readonly): a table containing hotdrop , thoff (transport header offset) and fragoff (fragment offset) fields.userargs : a lua string passed from the userspace xtable module.checkentry : function to be called for checking the entry. This function receives userargs as its argument.destroy : function to be called for destroying the xtable extension. This function receives userargs as its argument. The netfilter library provides support for the new netfilter hook system.
netfilter.register(ops) netfilter.register() registers a new netfilter hook with the given ops table. This function receives the following arguments:
ops : a table containing the following fields:pf : protocol family, one of netfilter.familyhooknum : ربط لإرفاق المرشح ، قيمة واحدة من أي من جدول الخطافات - 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.