Showing preview only (531K chars total). Download the full file or copy to clipboard to get everything.
Repository: luainkernel/lunatik
Branch: master
Commit: 8dbbf0188e5f
Files: 165
Total size: 492.1 KB
Directory structure:
gitextract_tvyvzgq9/
├── .editorconfig
├── .github/
│ └── workflows/
│ ├── build.yaml
│ └── doc.yml
├── .gitignore
├── .gitmodules
├── Kbuild
├── Kconfig
├── LICENSE-GPL
├── LICENSE-MIT
├── Makefile
├── README.md
├── autogen/
│ ├── linux/
│ │ └── .gitignore
│ └── lunatik/
│ └── .gitignore
├── bin/
│ └── lunatik
├── config.ld
├── configure.lua
├── doc/
│ └── capi.md
├── driver.lua
├── examples/
│ ├── cpuexporter.lua
│ ├── dnsblock/
│ │ ├── common.lua
│ │ └── nf_dnsblock.lua
│ ├── dnsdoctor/
│ │ ├── cleanup.sh
│ │ ├── common.lua
│ │ ├── nf_dnsdoctor.lua
│ │ └── setup.sh
│ ├── echod/
│ │ ├── daemon.lua
│ │ └── worker.lua
│ ├── filter/
│ │ ├── Makefile
│ │ ├── https.c
│ │ └── sni.lua
│ ├── gesture.lua
│ ├── keylocker.lua
│ ├── lldpd.lua
│ ├── shared.lua
│ ├── spyglass.lua
│ ├── systrack.lua
│ ├── tap.lua
│ ├── tcpreject/
│ │ ├── cleanup.sh
│ │ ├── nf_tcpreject.lua
│ │ └── setup.sh
│ └── xiaomi.lua
├── gensymbols.sh
├── include/
│ ├── assert.h
│ ├── ctype.h
│ ├── errno.h
│ ├── float.h
│ ├── klibc/
│ │ └── diverr.h
│ ├── limits.h
│ ├── locale.h
│ ├── math.h
│ ├── setjmp.h
│ ├── stdarg.h
│ ├── stddef.h
│ ├── stdint.h
│ ├── stdio.h
│ ├── stdlib.h
│ ├── string.h
│ └── time.h
├── lib/
│ ├── Kbuild
│ ├── crypto/
│ │ └── hkdf.lua
│ ├── lighten.lua
│ ├── luabyteorder.c
│ ├── luacompletion.c
│ ├── luacpu.c
│ ├── luacrypto.h
│ ├── luacrypto_aead.c
│ ├── luacrypto_comp.c
│ ├── luacrypto_core.c
│ ├── luacrypto_rng.c
│ ├── luacrypto_shash.c
│ ├── luacrypto_skcipher.c
│ ├── luadarken.c
│ ├── luadata.c
│ ├── luadata.h
│ ├── luadevice.c
│ ├── luafib.c
│ ├── luafifo.c
│ ├── luahid.c
│ ├── lualinux.c
│ ├── luanetfilter.c
│ ├── luanetfilter.h
│ ├── luanotifier.c
│ ├── luaprobe.c
│ ├── luarcu.c
│ ├── luarcu.h
│ ├── luasignal.c
│ ├── luaskb.c
│ ├── luaskb.h
│ ├── luaskel.c
│ ├── luasocket.c
│ ├── luasyscall.c
│ ├── luathread.c
│ ├── luaxdp.c
│ ├── lunatik/
│ │ └── runner.lua
│ ├── mailbox.lua
│ ├── net.lua
│ ├── socket/
│ │ ├── inet.lua
│ │ ├── raw.lua
│ │ └── unix.lua
│ ├── syscall/
│ │ └── table.lua
│ └── util.lua
├── lunatik.h
├── lunatik_aux.c
├── lunatik_conf.h
├── lunatik_core.c
├── lunatik_obj.c
├── lunatik_run.c
├── lunatik_val.c
├── lunatik_val.h
├── tests/
│ ├── README.md
│ ├── crypto/
│ │ ├── aead.lua
│ │ ├── comp.lua
│ │ ├── hkdf.lua
│ │ ├── rng.lua
│ │ ├── run.sh
│ │ ├── shash.lua
│ │ └── skcipher.lua
│ ├── io/
│ │ ├── softirq.lua
│ │ ├── test.lua
│ │ └── test.sh
│ ├── lib.sh
│ ├── monitor/
│ │ ├── gc.lua
│ │ ├── gc.sh
│ │ └── run.sh
│ ├── rcu/
│ │ ├── map_sync.lua
│ │ ├── map_sync.sh
│ │ ├── map_sync_clean.lua
│ │ ├── map_values.lua
│ │ └── run.sh
│ ├── run.sh
│ ├── runtime/
│ │ ├── opt_guards.lua
│ │ ├── opt_guards.sh
│ │ ├── opt_guards_recv.lua
│ │ ├── opt_skb_single.lua
│ │ ├── opt_skb_single.sh
│ │ ├── rcu_shared.lua
│ │ ├── rcu_shared.sh
│ │ ├── rcu_shared_recv.lua
│ │ ├── refcnt_leak.lua
│ │ ├── refcnt_leak.sh
│ │ ├── resume_mailbox.lua
│ │ ├── resume_mailbox.sh
│ │ ├── resume_mailbox_send.lua
│ │ ├── resume_shared.lua
│ │ ├── resume_shared.sh
│ │ ├── resume_shared_recv.lua
│ │ └── run.sh
│ ├── socket/
│ │ ├── run.sh
│ │ └── unix/
│ │ ├── dgram.sh
│ │ ├── dgram_client.lua
│ │ ├── dgram_server.lua
│ │ ├── run.sh
│ │ ├── stream.sh
│ │ ├── stream_client.lua
│ │ └── stream_server.lua
│ └── thread/
│ ├── dummy.lua
│ ├── run.sh
│ ├── run_during_load.lua
│ ├── run_during_load.sh
│ ├── shouldstop.lua
│ ├── shouldstop.sh
│ └── shouldstop_run.lua
└── tools/
├── Readme.md
├── debian_kernel_postinst_lunatik.sh
└── shade.sh
================================================
FILE CONTENTS
================================================
================================================
FILE: .editorconfig
================================================
root = true
[*]
indent_style = tab
indent_size = tab
trim_trailing_whitespace = true
insert_final_newline = true
================================================
FILE: .github/workflows/build.yaml
================================================
# Based on https://gist.github.com/domenic/ec8b0fc8ab45f39403dd
name: Build Modules
on:
pull_request:
branches:
- master
push:
branches:
- master
jobs:
build:
name: Build ${{ matrix.kernel-version }}
strategy:
matrix:
kernel-version: [5.15, 6.11]
fail-fast: false
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install dependencies
run: |
sudo apt-get update -qq
sudo apt-get install -yq build-essential bc bison flex libssl-dev dwarves libelf-dev libncurses-dev clang llvm pkg-config libpcap-dev lua5.4 lua5.4-dev m4
- name: Setup kernel ${{ matrix.kernel-version }}
run: |
KERNEL_VERSION="${{ matrix.kernel-version }}"
MAJOR=$(echo $KERNEL_VERSION | cut -d. -f1)
wget -q "https://cdn.kernel.org/pub/linux/kernel/v${MAJOR}.x/linux-${KERNEL_VERSION}.tar.xz"
tar xf linux-${KERNEL_VERSION}.tar.xz
cd linux-${KERNEL_VERSION}
make mrproper
make defconfig
echo "CONFIG_STACK_VALIDATION=n" >> .config
echo "CONFIG_WERROR=n" >> .config
if [[ "$KERNEL_VERSION" == "5."* ]]; then
sed -i 's/-Werror//g' tools/objtool/Makefile
sed -i 's/-Werror//g' tools/lib/subcmd/Makefile
export HOSTCFLAGS="-Wno-error=deprecated-declarations -Wno-error=use-after-free"
fi
make modules_prepare -j$(nproc)
echo "KERNEL_DIR=$(pwd)" >> $GITHUB_ENV
- name: Build Lunatik
run: |
make clean MODULES_BUILD_PATH="${{ env.KERNEL_DIR }}" || true
make -j$(nproc) MODULES_BUILD_PATH="${{ env.KERNEL_DIR }}" KBUILD_MODPOST_WARN=1
- name: Verify modules built
run: |
test -f lunatik.ko || { echo "Build failed" ; exit 1; }
echo "Lunatik built successfully for kernel ${{ matrix.kernel-version }}"
================================================
FILE: .github/workflows/doc.yml
================================================
# Based on https://gist.github.com/domenic/ec8b0fc8ab45f39403dd
name: Build Docs
on:
pull_request:
branches:
- master
push:
branches:
- master
jobs:
build:
name: Build docs
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Lua
uses: leafo/gh-actions-lua@v8
with:
luaVersion: 5.4
- name: Setup Lua Rocks
uses: leafo/gh-actions-luarocks@v4
- name: Setup dependencies
run: luarocks install ldoc
- name: Build docs
run: make doc-site
- name: Deploy
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: doc
================================================
FILE: .gitignore
================================================
*.[aod]
*.cmd
*.ko
*.mod
*.mod.*
*.so
Module.symvers
modules.builtin
modules.order
build/
lunatik_sym.h
moontastik*
dnstest
doc/*
!doc/capi.md
================================================
FILE: .gitmodules
================================================
[submodule "lua"]
path = lua
url = https://github.com/luainkernel/lua.git
[submodule "klibc"]
path = klibc
url = https://github.com/luainkernel/klibc.git
================================================
FILE: Kbuild
================================================
# SPDX-FileCopyrightText: (c) 2023-2026 Ring Zero Desenvolvimento de Software LTDA
# SPDX-License-Identifier: MIT OR GPL-2.0-only
ifeq ($(ARCH), x86)
ifdef CONFIG_X86_32
KLIBC_ARCH := i386
asflags-y += -D_REGPARM
else
KLIBC_ARCH := x86_64
endif
else
KLIBC_ARCH := $(ARCH)
endif
KLIBC_USR := klibc/usr
KLIBC_INC := $(KLIBC_USR)/include/arch/$(KLIBC_ARCH)
KLIBC_LIBGCC := $(KLIBC_USR)/klibc/libgcc
LUNATIK_FLAGS := -D_LUNATIK -D_KERNEL -I${PWD}/$(KLIBC_INC)
asflags-y += $(LUNATIK_FLAGS)
ccflags-y += $(LUNATIK_FLAGS) -DLUNATIK_RUNTIME=$(CONFIG_LUNATIK_RUNTIME) \
-Wimplicit-fallthrough=0 -I$(src) -I${PWD} -I${PWD}/include -I${PWD}/lua
subdir-ccflags-y += $(ccflags-y)
obj-$(CONFIG_LUNATIK) += lunatik.o
lunatik-objs += lua/lapi.o lua/lcode.o lua/lctype.o lua/ldebug.o lua/ldo.o \
lua/ldump.o lua/lfunc.o lua/lgc.o lua/llex.o lua/lmem.o \
lua/lobject.o lua/lopcodes.o lua/lparser.o lua/lstate.o \
lua/lstring.o lua/ltable.o lua/ltm.o \
lua/lundump.o lua/lvm.o lua/lzio.o lua/lauxlib.o lua/lbaselib.o \
lua/lcorolib.o lua/ldblib.o lua/lstrlib.o \
lua/ltablib.o lua/lutf8lib.o lua/lmathlib.o lua/liolib.o lua/linit.o \
lua/loadlib.o $(KLIBC_USR)/klibc/arch/$(KLIBC_ARCH)/setjmp.o \
lunatik_aux.o lunatik_obj.o lunatik_val.o lunatik_core.o
ifeq ($(CONFIG_64BIT),)
lunatik-objs += $(KLIBC_LIBGCC)/__udivmoddi4.o \
$(KLIBC_LIBGCC)/__divdi3.o $(KLIBC_LIBGCC)/__udivdi3.o \
$(KLIBC_LIBGCC)/__moddi3.o $(KLIBC_LIBGCC)/__umoddi3.o
endif
obj-$(CONFIG_LUNATIK_RUN) += lunatik_run.o
obj-y += lib/
================================================
FILE: Kconfig
================================================
# SPDX-FileCopyrightText: (c) 2026 Tanmay Deobhankar <emailtotanmay@gmail.com>
# SPDX-License-Identifier: MIT OR GPL-2.0-only
menuconfig LUNATIK
tristate "Lunatik Lua Interpreter"
default m
help
Lunatik is a framework for scripting the Linux kernel with Lua.
It allows you to write kernel drivers and extensions using Lua scripts.
if LUNATIK
config LUNATIK_RUNTIME
bool
default y
select LUNATIK_DEVICE
select LUNATIK_RCU
help
Enables the core Lunatik runtime environment, allowing creation of
isolated Lua states within the kernel. This requires both device
and RCU support.
config LUNATIK_RUN
tristate "Lunatik Run (Execution Support)"
default y
help
Support for running Lua scripts in the kernel. This is required
for basic script execution functionality.
config LUNATIK_DEVICE
tristate "Lunatik Device Support"
default m
help
Allows creating character devices using Lua.
config LUNATIK_LINUX
tristate "Lunatik Linux API Bindings"
default m
help
Provides Lua bindings for common Linux kernel functions (random, stat, etc.).
config LUNATIK_NOTIFIER
tristate "Lunatik Notifier Support"
default m
help
Support for kernel notifiers in Lua.
config LUNATIK_SOCKET
tristate "Lunatik Socket Support"
default m
help
Networking socket support for Lua scripts.
config LUNATIK_RCU
tristate "Lunatik RCU Support"
default m
help
Read-Copy-Update (RCU) synchronization support.
config LUNATIK_THREAD
tristate "Lunatik Thread Support"
default m
help
Kernel thread management from Lua.
config LUNATIK_FIB
tristate "Lunatik FIB (Forwarding Information Base) Support"
default m
help
Access to the kernel FIB (routing capability).
config LUNATIK_DATA
tristate "Lunatik Data Support"
default m
help
Shared data structures support.
config LUNATIK_SKB
tristate "Lunatik SKB (Socket Buffer) Support"
default m
depends on LUNATIK_DATA
help
Socket buffer (skb) access support for Lua scripts.
Requires Lunatik Data support.
config LUNATIK_PROBE
tristate "Lunatik Probe (Kprobe/Kretprobe) Support"
default m
help
Dynamic tracing support using kprobes.
config LUNATIK_SYSCALL
tristate "Lunatik Syscall Support"
default m
help
System call tracking and manipulation.
config LUNATIK_XDP
tristate "Lunatik XDP Support"
default m
help
Express Data Path (XDP) support for high-performance packet processing.
config LUNATIK_FIFO
tristate "Lunatik FIFO Support"
default m
help
First-In-First-Out queue support.
config LUNATIK_NETFILTER
tristate "Lunatik Netfilter bindings"
default m
depends on LUNATIK_SKB
help
New Netfilter API bindings.
Requires Lunatik SKB support.
config LUNATIK_COMPLETION
tristate "Lunatik Completion Support"
default m
help
Kernel completion synchronization primitives.
config LUNATIK_CRYPTO
tristate "Lunatik Crypto Support"
default m
help
Linux Crypto API support (hash, cipher, AEAD, RNG, compression).
config LUNATIK_DARKEN
tristate "Lunatik Darken (Encrypted Script) Support"
depends on LUNATIK_CRYPTO
default m
help
AES-256-CTR encrypted Lua script support.
config LUNATIK_CPU
tristate "Lunatik CPU Support"
default m
help
CPU management and information.
config LUNATIK_HID
tristate "Lunatik HID (Human Interface Device) Support"
default m
help
HID driver support in Lua.
config LUNATIK_SIGNAL
tristate "Lunatik Signal Support"
default m
help
Signal handling support.
config LUNATIK_BYTEORDER
tristate "Lunatik Byteorder Support"
default m
help
Byte order swapping functions.
endif
================================================
FILE: LICENSE-GPL
================================================
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
================================================
FILE: LICENSE-MIT
================================================
MIT License
Copyright (c) 2023-2025 Ring Zero Desenvolvimento de Software LTDA
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: Makefile
================================================
# SPDX-FileCopyrightText: (c) 2023-2026 Ring Zero Desenvolvimento de Software LTDA
# SPDX-License-Identifier: MIT OR GPL-2.0-only
KERNEL_RELEASE ?= ${shell uname -r}
MODULES_PATH := /lib/modules
MODULES_RELEASE_PATH := ${MODULES_PATH}/${KERNEL_RELEASE}
# needed when zfs module is installed
MODULES_ORDER_LIST := kernel/zfs/zfs.ko kernel/zfs/zlua.ko updates/dkms/zfs.ko updates/dkms/zlua.ko
MODULES_ORDER_FILE := ${MODULES_RELEASE_PATH}/modules.order
BTF_INSTALL_PATH = ${MODULES_RELEASE_PATH}/build
MODULES_BUILD_PATH ?= ${BTF_INSTALL_PATH}
MODULES_INSTALL_PATH := ${MODULES_RELEASE_PATH}/kernel
SCRIPTS_INSTALL_PATH := ${MODULES_PATH}/lua
INCLUDE_PATH := ${MODULES_BUILD_PATH}/include
LUA ?= lua5.4
LUA_PATH ?= $(shell $(LUA) -e 'print(package.path:match("([^;]*)/%?%.lua;"))')
LUNATIK_INSTALL_PATH = /usr/local/sbin
LUNATIK_EBPF_INSTALL_PATH = /usr/local/lib/bpf/lunatik
LUNATIK_TESTS_INSTALL_PATH = /usr/local/share/lunatik/tests
MOONTASTIK_RELEASE ?= v0.1c
LUA_API = lua/lua.h lua/lauxlib.h lua/lualib.h
RM = rm -f
MKDIR = mkdir -p -m 0755
LN = ln -sf
INSTALL = install -o root -g root
CONFIG_LUNATIK ?= m
CONFIG_LUNATIK_RUNTIME ?= y
CONFIG_LUNATIK_RUN ?= m
# Order matters: modules are loaded left-to-right and unloaded right-to-left (rmmod).
# A module must appear AFTER all modules it depends on (e.g. SKB before NETFILTER).
LUNATIK_MODULES := DEVICE LINUX NOTIFIER SOCKET RCU THREAD FIB DATA PROBE SYSCALL XDP FIFO SKB NETFILTER \
COMPLETION CRYPTO CPU HID SIGNAL BYTEORDER DARKEN
$(foreach c,$(LUNATIK_MODULES),\
$(eval CONFIG_LUNATIK_$(c) ?= m))
# disable modules here, e.g.:
# CONFIG_LUNATIK_SYSCALL := n
LUNATIK_CONFIG_MODULES := \
$(foreach c,$(LUNATIK_MODULES),CONFIG_LUNATIK_$(c)=$(CONFIG_LUNATIK_$(c)))
LUNATIK_CONFIG_FLAGS := CONFIG_LUNATIK=$(CONFIG_LUNATIK) CONFIG_LUNATIK_RUNTIME=$(CONFIG_LUNATIK_RUNTIME) \
CONFIG_LUNATIK_RUN=$(CONFIG_LUNATIK_RUN) $(LUNATIK_CONFIG_MODULES)
LUNATIK_MODULES := \
$(foreach c,$(LUNATIK_MODULES),\
$(if $(filter y m,$(CONFIG_LUNATIK_$(c))),$(c)))
all: lunatik_sym.h configure
${MAKE} -C ${MODULES_BUILD_PATH} M=${PWD} $(LUNATIK_CONFIG_FLAGS)
clean:
${MAKE} -C ${MODULES_BUILD_PATH} M=${PWD} clean
${MAKE} -C examples/filter clean
${RM} lunatik_sym.h
${RM} autogen/lunatik/*.lua
${RM} autogen/linux/*.lua
scripts_install:
${MKDIR} ${SCRIPTS_INSTALL_PATH}
${MKDIR} ${SCRIPTS_INSTALL_PATH}/lunatik
${MKDIR} ${SCRIPTS_INSTALL_PATH}/socket
${MKDIR} ${SCRIPTS_INSTALL_PATH}/syscall
${MKDIR} ${SCRIPTS_INSTALL_PATH}/crypto
${MKDIR} ${SCRIPTS_INSTALL_PATH}/linux
${MKDIR} ${LUA_PATH}/lunatik
${INSTALL} -m 0644 driver.lua ${SCRIPTS_INSTALL_PATH}/
${INSTALL} -m 0644 lib/mailbox.lua ${SCRIPTS_INSTALL_PATH}/
${INSTALL} -m 0644 lib/net.lua ${SCRIPTS_INSTALL_PATH}/
${INSTALL} -m 0644 lib/util.lua ${SCRIPTS_INSTALL_PATH}/
${INSTALL} -m 0644 lib/lighten.lua ${SCRIPTS_INSTALL_PATH}/
${INSTALL} -m 0644 lib/lunatik/*.lua ${SCRIPTS_INSTALL_PATH}/lunatik
${INSTALL} -m 0644 lib/socket/*.lua ${SCRIPTS_INSTALL_PATH}/socket
${INSTALL} -m 0644 lib/syscall/*.lua ${SCRIPTS_INSTALL_PATH}/syscall
${INSTALL} -m 0644 lib/crypto/*.lua ${SCRIPTS_INSTALL_PATH}/crypto
${INSTALL} -m 0644 autogen/linux/*.lua ${SCRIPTS_INSTALL_PATH}/linux
${INSTALL} -m 0644 autogen/lunatik/*.lua ${SCRIPTS_INSTALL_PATH}/lunatik
${LN} ${SCRIPTS_INSTALL_PATH}/lunatik/config.lua ${LUA_PATH}/lunatik/config.lua
${INSTALL} -D -m 0755 bin/lunatik ${LUNATIK_INSTALL_PATH}/lunatik
scripts_uninstall:
${RM} ${SCRIPTS_INSTALL_PATH}/driver.lua
${RM} ${SCRIPTS_INSTALL_PATH}/runner.lua
${RM} ${SCRIPTS_INSTALL_PATH}/mailbox.lua
${RM} ${SCRIPTS_INSTALL_PATH}/net.lua
${RM} -r ${SCRIPTS_INSTALL_PATH}/lunatik
${RM} -r ${SCRIPTS_INSTALL_PATH}/socket
${RM} -r ${SCRIPTS_INSTALL_PATH}/syscall
${RM} -r ${SCRIPTS_INSTALL_PATH}/crypto
${RM} -r ${SCRIPTS_INSTALL_PATH}/linux
${RM} ${LUNATIK_INSTALL_PATH}/lunatik
${RM} -r ${LUA_PATH}/lunatik
.PHONY: ebpf defines
ebpf:
${MAKE} -C examples/filter
ebpf_install:
${MKDIR} ${LUNATIK_EBPF_INSTALL_PATH}
${INSTALL} -m 0644 examples/filter/https.o ${LUNATIK_EBPF_INSTALL_PATH}/
ebpf_uninstall:
${RM} -r ${LUNATIK_EBPF_INSTALL_PATH}
examples_install:
${MKDIR} ${SCRIPTS_INSTALL_PATH}/examples
${INSTALL} -m 0644 examples/*.lua ${SCRIPTS_INSTALL_PATH}/examples
${MKDIR} ${SCRIPTS_INSTALL_PATH}/examples/echod
${INSTALL} -m 0644 examples/echod/*.lua ${SCRIPTS_INSTALL_PATH}/examples/echod
${MKDIR} ${SCRIPTS_INSTALL_PATH}/examples/filter
${INSTALL} -m 0644 examples/filter/*.lua ${SCRIPTS_INSTALL_PATH}/examples/filter
${MKDIR} ${SCRIPTS_INSTALL_PATH}/examples/dnsblock
${INSTALL} -m 0644 examples/dnsblock/*.lua ${SCRIPTS_INSTALL_PATH}/examples/dnsblock
${MKDIR} ${SCRIPTS_INSTALL_PATH}/examples/dnsdoctor
${INSTALL} -m 0644 examples/dnsdoctor/*.lua ${SCRIPTS_INSTALL_PATH}/examples/dnsdoctor
${MKDIR} ${SCRIPTS_INSTALL_PATH}/examples/tcpreject
${INSTALL} -m 0644 examples/tcpreject/*.lua ${SCRIPTS_INSTALL_PATH}/examples/tcpreject
examples_uninstall:
${RM} -r ${SCRIPTS_INSTALL_PATH}/examples
tests_install:
${MKDIR} ${LUNATIK_TESTS_INSTALL_PATH}
${INSTALL} -m 0755 tests/run.sh ${LUNATIK_TESTS_INSTALL_PATH}
${INSTALL} -m 0644 tests/lib.sh ${LUNATIK_TESTS_INSTALL_PATH}
${MKDIR} ${LUNATIK_TESTS_INSTALL_PATH}/rcu
${INSTALL} -m 0755 tests/rcu/run.sh tests/rcu/map_sync.sh ${LUNATIK_TESTS_INSTALL_PATH}/rcu
${MKDIR} ${SCRIPTS_INSTALL_PATH}/tests/rcu
${INSTALL} -m 0644 tests/rcu/*.lua ${SCRIPTS_INSTALL_PATH}/tests/rcu
${MKDIR} ${SCRIPTS_INSTALL_PATH}/tests/crypto
${INSTALL} -m 0644 tests/crypto/*.lua ${SCRIPTS_INSTALL_PATH}/tests/crypto
${MKDIR} ${LUNATIK_TESTS_INSTALL_PATH}/crypto
${INSTALL} -m 0755 tests/crypto/run.sh ${LUNATIK_TESTS_INSTALL_PATH}/crypto
${MKDIR} ${LUNATIK_TESTS_INSTALL_PATH}/monitor
${INSTALL} -m 0755 tests/monitor/*.sh ${LUNATIK_TESTS_INSTALL_PATH}/monitor
${INSTALL} -m 0644 tests/monitor/*.lua ${SCRIPTS_INSTALL_PATH}/tests/monitor
${MKDIR} ${LUNATIK_TESTS_INSTALL_PATH}/thread
${INSTALL} -m 0755 tests/thread/*.sh ${LUNATIK_TESTS_INSTALL_PATH}/thread
${INSTALL} -m 0644 tests/thread/*.lua ${SCRIPTS_INSTALL_PATH}/tests/thread
${MKDIR} ${LUNATIK_TESTS_INSTALL_PATH}/runtime
${INSTALL} -m 0755 tests/runtime/*.sh ${LUNATIK_TESTS_INSTALL_PATH}/runtime
${INSTALL} -m 0644 tests/runtime/*.lua ${SCRIPTS_INSTALL_PATH}/tests/runtime
${MKDIR} ${LUNATIK_TESTS_INSTALL_PATH}/socket/unix
${INSTALL} -m 0755 tests/socket/run.sh ${LUNATIK_TESTS_INSTALL_PATH}/socket
${INSTALL} -m 0755 tests/socket/unix/*.sh ${LUNATIK_TESTS_INSTALL_PATH}/socket/unix
${MKDIR} ${SCRIPTS_INSTALL_PATH}/tests/socket/unix
${INSTALL} -m 0644 tests/socket/unix/*.lua ${SCRIPTS_INSTALL_PATH}/tests/socket/unix
${MKDIR} ${LUNATIK_TESTS_INSTALL_PATH}/io
${INSTALL} -m 0755 tests/io/*.sh ${LUNATIK_TESTS_INSTALL_PATH}/io
${MKDIR} ${SCRIPTS_INSTALL_PATH}/tests/io
${INSTALL} -m 0644 tests/io/*.lua ${SCRIPTS_INSTALL_PATH}/tests/io
tests_uninstall:
${RM} -r ${SCRIPTS_INSTALL_PATH}/tests
${RM} -r ${LUNATIK_TESTS_INSTALL_PATH}
modules_install:
${MKDIR} ${MODULES_INSTALL_PATH}/lunatik
${INSTALL} -m 0644 *.ko lib/*.ko ${MODULES_INSTALL_PATH}/lunatik
btf_install:
cp /sys/kernel/btf/vmlinux ${BTF_INSTALL_PATH}
modules_uninstall:
${RM} -r ${MODULES_INSTALL_PATH}/lunatik
install: scripts_install modules_install
for mod in $(MODULES_ORDER_LIST); do \
sed -i "\|^$$mod$$|d" $(MODULES_ORDER_FILE); \
echo "$$mod" >> $(MODULES_ORDER_FILE); \
done
depmod -a
uninstall: scripts_uninstall modules_uninstall
for mod in $(MODULES_ORDER_LIST); do \
sed -i "\|^$$mod$$|d" $(MODULES_ORDER_FILE); \
done
depmod -a
lunatik_sym.h: $(LUA_API) gensymbols.sh
${shell CC='$(CC)' ./gensymbols.sh $(LUA_API) > lunatik_sym.h}
configure:
CC='$(CC)' "$(LUA)" configure.lua "$(KERNEL_RELEASE)" "$(INCLUDE_PATH)" "$(LUNATIK_MODULES)"
moontastik_install_%:
[ $* ] || (echo "usage: make moontastik_install_TARGET" ; exit 1)
wget https://github.com/luainkernel/moontastik/releases/download/${MOONTASTIK_RELEASE}/moontastik_lua.zip -O moontastik_lua.zip
[ -d moontastik_lua ] && ${RM} -r moontastik_lua || true
unzip moontastik_lua.zip
cd moontastik_lua/"$*" && ./install.sh ; cd -
moontastik_uninstall_%:
[ $* ] || (echo "usage: make moontastik_uninstall_TARGET" ; exit 1)
${RM} -r ${SCRIPTS_INSTALL_PATH}/$*
doc-site:
ldoc .
================================================
FILE: README.md
================================================
# Lunatik
Lunatik is a framework for scripting the Linux kernel with [Lua](https://www.lua.org/).
It is composed by the Lua interpreter modified to run in the kernel;
a [device driver](driver.lua) (written in Lua =)) and a [command line tool](bin/lunatik)
to load and run scripts and manage runtime environments from the user space;
a [C API](doc/capi.md) to load and run scripts and manage runtime environments from the kernel;
and [Lua APIs](#lunatik-lua-apis) for binding kernel facilities to Lua scripts.
> Note: Lunatik supports Linux Kernel versions 5.15 and later
Feel free to join us on [Matrix](https://matrix.to/#/#lunatik:matrix.org).
Here is an example of a character device driver written in Lua using Lunatik
to generate random ASCII printable characters:
```Lua
-- /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 s = linux.stat
local driver = {name = "passwd", 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)
```
## Setup
Install dependencies (here for Debian/Ubuntu, to be adapted to one's distribution):
```sh
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
```
Install dependencies (here for Arch Linux):
```sh
sudo pacman -S git lua clang llvm m4 libpcap pkg-config build2 linux-tools linux-headers
```
The `lua-readline` package is optional. When installed, the REPL gains line editing and command history:
```sh
sudo apt install lua-readline # Debian/Ubuntu
```
Compile and install `lunatik`:
```sh
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
```
Once done, the `debian_kernel_postinst_lunatik.sh` script from tools/ may be copied into
`/etc/kernel/postinst.d/`: this ensures `lunatik` (and also the `xdp` needed libs) will get
compiled on kernel upgrade.
### OpenWRT
Install Lunatik from our [package feed](https://github.com/luainkernel/openwrt_feed/tree/openwrt-23.05).
## Usage
```
sudo lunatik # execute Lunatik REPL
Lunatik 4.2 Copyright (C) 2023-2026 Ring Zero Desenvolvimento de Software LTDA.
> return 42 -- execute this line in the kernel
42
```
### lunatik
```Shell
usage: lunatik [load|unload|reload|status|test|list] [run|spawn|stop <script>]
```
* `load`: load Lunatik kernel modules
* `unload`: unload Lunatik kernel modules
* `reload`: reload Lunatik kernel modules
* `status`: show which Lunatik kernel modules are currently loaded
* `test [suite]`: run installed test suites (see [Testing](#testing))
* `list`: show which runtime environments are currently running
* `run [softirq]`: create a new runtime environment to run the script `/lib/modules/lua/<script>.lua`; pass `softirq` for hooks that fire in atomic context (netfilter, XDP)
* `spawn`: create a new runtime environment and spawn a thread to run the script `/lib/modules/lua/<script>.lua`
* `stop`: stop the runtime environment created to run the script `<script>`
* `default`: start a _REPL (Read–Eval–Print Loop)_
### Testing
Install and run the test suites:
```sh
sudo make tests_install
sudo lunatik test # run all suites
sudo lunatik test thread # run a specific suite (monitor, thread, runtime)
```
## Lua Version
Lunatik 4.2 is based on
[Lua 5.5 adapted](https://github.com/luainkernel/lua)
to run in the kernel.
### Floating-point numbers
Lunatik **does not** support floating-point arithmetic,
thus it **does not** support `__div` nor `__pow`
[metamethods](https://www.lua.org/manual/5.5/manual.html#2.4)
and the type _number_ has only the subtype _integer_.
### Lua API
Lunatik **does not** support the [os](https://www.lua.org/manual/5.5/manual.html#6.9) library,
floating-point arithmetic (`__div`, `__pow`), or `debug.debug`.
The `math` library is present but all floating-point functions are absent —
only integer operations are supported.
The [io](https://www.lua.org/manual/5.5/manual.html#6.8) library is supported with the
following limitations: there are no default streams (`io.stdin`, `io.stdout`, `io.stderr`),
no default input/output (`io.read`, `io.write`, `io.input`, `io.output`), no process pipes
(`io.popen`), no temporary files (`io.tmpfile`), and no buffering control (`file:setvbuf`).
The available functions are `io.open`, `io.lines`, `io.type`, and the file handle methods
`read`, `write`, `lines`, `flush`, `seek`, and `close`.
On failure, error messages always read `"I/O error"` regardless of the underlying errno.
Lunatik **modifies** the following identifiers:
* [\_VERSION](https://www.lua.org/manual/5.5/manual.html#pdf-_VERSION): is defined as `"Lua 5.5-kernel"`.
* [collectgarbage("count")](https://www.lua.org/manual/5.5/manual.html#pdf-collectgarbage): returns the total memory in use by Lua in **bytes**, instead of _Kbytes_.
* [package.path](https://www.lua.org/manual/5.5/manual.html#pdf-package.path): is defined as `"/lib/modules/lua/?.lua;/lib/modules/lua/?/init.lua"`.
* [require](https://www.lua.org/manual/5.5/manual.html#pdf-require): only supports built-in or already linked C modules, that is, Lunatik **cannot** load kernel modules dynamically.
## Lunatik Lua APIs
Lua APIs are documented with [LDoc](https://stevedonovan.github.io/ldoc/) and can be browsed at
[luainkernel.github.io/lunatik](https://luainkernel.github.io/lunatik/).
The table below lists the available kernel Lua modules:
| Module | Description |
|--------|-------------|
| `linux` | Kernel utilities: `schedule`, `time`, `random`, `stat` flags |
| `thread` | Kernel threads: spawn, stop, `shouldstop` |
| `socket` | Kernel sockets: TCP, UDP, AF\_PACKET, AF\_UNIX |
| `data` | Raw memory buffer for binary data read/write |
| `device` | Character device drivers |
| `rcu` | RCU-protected shared hash table |
| `netfilter` | Netfilter hooks: register packet processing callbacks |
| `skb` | Socket buffer (`sk_buff`): inspect and modify packets |
| `xdp` | XDP (eXpress Data Path) hooks |
| `crypto` | Kernel crypto API: hash, cipher, AEAD, RNG, compression |
| `hid` | HID device drivers |
| `probe` | Kernel probes (kprobe / tracepoint) |
| `fib` | FIB routing table lookup |
| `fifo` | Kernel FIFO queues |
| `signal` | POSIX signal management |
| `byteorder` | Network byte order conversions |
| `darken` | AES-256-CTR encrypted script execution |
| `lighten` | Lua interface for running encrypted scripts via `darken` |
| `notifier` | Kernel notifier chain registration |
| `lunatik.runner` | Run, spawn, and stop scripts from within Lua |
| `net` | Networking helpers |
| `mailbox` | Asynchronous inter-runtime messaging |
## Lunatik C API
The [C API](doc/capi.md) allows kernel modules to create and manage Lunatik runtime
environments, define new object classes, and expose kernel facilities to Lua scripts.
See [doc/capi.md](doc/capi.md) for the full reference.
# Examples
### spyglass
[spyglass](examples/spyglass.lua)
is a kernel script that implements a _keylogger_ inspired by the
[spy](https://github.com/jarun/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, (e.g., `<del>` stands for `127`).
#### Usage
```
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
[keylocker](examples/keylocker.lua)
is a kernel script that implements
[Konami Code](https://en.wikipedia.org/wiki/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.
#### Usage
```
sudo make examples_install # installs examples
sudo lunatik run examples/keylocker # runs keylocker
<↑> <↑> <↓> <↓> <←> <→> <←> <→> <LCTRL> <LALT> # locks keyboard
<↑> <↑> <↓> <↓> <←> <→> <←> <→> <LCTRL> <LALT> # unlocks keyboard
```
### tap
[tap](examples/tap.lua)
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.
#### Usage
```
sudo make examples_install # installs examples
sudo lunatik run examples/tap # runs tap
cat /dev/tap
```
### shared
[shared](examples/shared.lua)
is a kernel script that implements an in-memory key-value store using
[rcu](https://github.com/luainkernel/lunatik#rcu),
[data](https://github.com/luainkernel/lunatik#data),
[socket](https://github.com/luainkernel/lunatik#socket) and
[thread](https://github.com/luainkernel/lunatik#thread).
#### Usage
```
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
[echod](examples/echod)
is an echo server implemented as kernel scripts.
#### Usage
```
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
[systrack](examples/systrack.lua)
is a kernel script that implements a device driver to monitor system calls.
It prints the amount of times each [system call](examples/systrack.lua#L29)
was called since the driver has been installed.
#### Usage
```
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
[filter](examples/filter) is a kernel extension composed by
a XDP/eBPF program to filter HTTPS sessions and
a Lua kernel script to filter [SNI](https://datatracker.ietf.org/doc/html/rfc3546#section-3.1) TLS extension.
This kernel extension drops any HTTPS request destinated to a
[blacklisted](examples/filter/sni.lua#L35) server.
#### Usage
Compile and install `libbpf`, `libxdp` and `xdp-loader`:
```sh
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 install
```
Come back to this repository, install and load the filter:
```sh
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 softirq # runs the Lua kernel script
sudo xdp-loader load -m skb <ifname> https.o # loads the XDP/eBPF program
```
For example, testing is easy thanks to [docker](https://www.docker.com).
Assuming docker is installed and running:
- in a terminal:
```sh
sudo xdp-loader load -m skb docker0 https.o
sudo journalctl -ft kernel
```
- in another one:
```sh
docker 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`.
### filter in MoonScript
[This other sni filter](https://github.com/luainkernel/snihook) uses netfilter api.
### dnsblock
[dnsblock](examples/dnsblock) is a kernel script that uses the netfilter framework ([luanetfilter](https://github.com/luainkernel/lunatik#netfilter)) to filter DNS packets.
This script drops any outbound DNS packet with question matching the blacklist provided by the user. By default, it will block DNS resolutions for the domains `github.com` and `gitlab.com`.
#### Usage
```
sudo make examples_install # installs examples
sudo lunatik run examples/dnsblock/nf_dnsblock softirq # runs the Lua kernel script
```
### dnsdoctor
[dnsdoctor](examples/dnsdoctor) is a kernel script that uses the netfilter framework ([luanetfilter](https://github.com/luainkernel/lunatik#netfilter)) 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.
#### Usage
```
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 softirq
# 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
```
### tcpreject
[tcpreject](examples/tcpreject) is a kernel script that uses the
netfilter framework ([luanetfilter](https://github.com/luainkernel/lunatik#netfilter))
and the socket buffer API ([luaskb](https://github.com/luainkernel/lunatik#skb))
to inject a TCP RST toward the origin of forwarded packets.
It intercepts packets marked by an `nft` rule, builds a RST+ACK by
copying the original packet, inverting IP, MAC, and port addresses,
trimming the payload, and recomputing the checksums.
It supports both IPv4 and IPv6.
By default, it rejects forwarded HTTPS (TCP/443) connections to `8.8.8.8` (IPv4)
and `2001:4860:4860::8888` (IPv6).
#### Usage
```
sudo make examples_install # installs examples
sudo examples/tcpreject/setup.sh # sets up namespace, nft mark rule, and loads the hook
# connection is reset immediately (IPv4)
ip netns exec tcpreject curl --connect-timeout 2 https://8.8.8.8
# connection is reset immediately (IPv6)
ip netns exec tcpreject curl --connect-timeout 2 https://[2001:4860:4860::8888]
# cleanup
sudo examples/tcpreject/cleanup.sh
```
### gesture
[gesture](examples/gesture.lua)
is a kernel script that implements a HID driver for QEMU USB Mouse (0627:0001).
It supports gestures: swiping right locks the mouse, and swiping left unlocks it.
#### Usage
1. You need to change the display protocal into `VNC` and enable USB mouse device in QEMU, the following configuration can help you disable PS2 mouse & enable USB mouse:
```
<features>
<!-- ... -->
<ps2 state="off"/>
<!-- ... -->
</features>
```
2. run the gesture script:
```
sudo make examples_install # installs examples
sudo lunatik run examples/gesture softirq # runs gesture
# In QEMU window:
# Drag right to lock the mouse
# Drag left to unlock the mouse
```
### xiaomi
[xiaomi](examples/xiaomi.lua)
is a kernel script that ports the Xiaomi Silent Mouse driver to Lua using `luahid`.
It fixes the report descriptor for the device (`0x2717`:`0x5014`).
#### Usage
```
sudo make examples_install # installs examples
sudo lunatik run examples/xiaomi softirq # runs xiaomi driver
```
Then insert the Xiaomi Silent Mouse with bluetooth mode on and it should work properly.
### lldpd
[lldpd](examples/lldpd.lua) shows how to implement a simple LLDP transmitter in kernel space using Lunatik.
It periodically emits LLDP frames on a given interface using an AF_PACKET socket.
#### Usage
```
sudo make examples_install # installs examples
# the LLDP daemon sends frames on a single Ethernet interface
# you may use an existing interface, or create a virtual one for testing
# create a veth pair (the example uses veth0 by default)
ip link add veth0 type veth peer name veth1
ip link set veth0 up
ip link set veth1 up
sudo lunatik spawn examples/lldpd # runs lldpd
# verify LLDP frames are being transmitted
sudo tcpdump -i veth0 -e ether proto 0x88cc -vv
```
### cpuexporter
[cpuexporter](examples/cpuexporter.lua) will gather CPU usage statistics and expose using [OpenMetrics text format](https://github.com/prometheus/OpenMetrics/blob/main/specification/OpenMetrics.md#text-format) at a UNIX socket file.
#### Usage
```shell
sudo make examples_install # installs examples
sudo lunatik spawn examples/cpuexporter # runs cpuexporter
sudo socat - UNIX-CONNECT:/tmp/cpuexporter.sock <<<""
# TYPE cpu_usage_system gauge
cpu_usage_system{cpu="cpu1"} 0.0000000000000000 1764094519529162
cpu_usage_system{cpu="cpu0"} 0.0000000000000000 1764094519529162
# TYPE cpu_usage_idle gauge
cpu_usage_idle{cpu="cpu1"} 100.0000000000000000 1764094519529162
cpu_usage_idle{cpu="cpu0"} 100.0000000000000000 1764094519529162
...
```
## References
### Talks and Papers
* [Scripting the Linux Routing Table with Lua](https://netdevconf.info/0x17/sessions/talk/scripting-the-linux-routing-table-with-lua.html) — Netdev 0x17 (2023)
* [Linux Network Scripting with Lua](https://legacy.netdevconf.info/0x14/session.html?talk-linux-network-scripting-with-lua) — Netdev 0x14 (2020)
* [Lua no Núcleo](https://www.youtube.com/watch?v=-ufBgy044HI) — Lua Workshop 2023, PUC-Rio (Portuguese)
* [Scriptable Operating Systems with Lua](https://www.netbsd.org/~lneto/dls14.pdf) — DLS 2014
* [Lua in Kernel](https://events.canonical.com/event/89/contributions/506/attachments/265/393/Lua%20in%20Kernel%20-%20OOSC%202024%20(2).pdf) — Opportunity Open Source Conference 2024
### Articles
* [From the Kernel to the Moon: A Journey into Lunatik Bindings](https://medium.com/@lourival.neto/from-the-kernel-to-the-moon-a-journey-into-lunatik-bindings-c2cac8816f9e) — Medium (2025)
* [Is eBPF driving you crazy? Let it run Lunatik instead!](https://medium.com/@lourival.neto/is-ebpf-driving-you-crazy-let-it-run-lunatik-instead-4aca7d63e6fd) — Medium (2024)
* [Lua in the kernel?](https://lwn.net/Articles/830154/) — LWN.net (2020)
### GSoC Projects
* [LuaHID](https://github.com/qrsikno2/GSoC2025) — LabLua (2025), Jieming Zhou
* [Lunatik binding for Netfilter](https://summerofcode.withgoogle.com/archive/2024/projects/BIJAPZjf) — LabLua (2024), Mohammad Shehar Yaar Tausif
* [Lua hook on kTLS](https://luainkernel.github.io/ktls/) — LabLua (2020), Xinzhe Wang
* [Lunatik States Management](https://github.com/luainkernel/lunatik/pull/20) — LabLua (2020), Matheus Rodrigues
* [XDP Lua](https://victornogueirario.github.io/xdplua/) — LabLua (2019), Victor Nogueira
* [RCU binding for Lunatik](https://github.com/cmessias/lunatik) — LabLua (2018), Caio Messias
* [Lunatik Socket Library](https://github.com/luainkernel/lunatik/pull/4) — LabLua (2018), Chengzhi Tan
* [Port Lua Test Suite to the NetBSD Kernel](https://www.google-melange.com/archive/gsoc/2015/orgs/lablua/projects/gmesalazar.html) — LabLua (2015), Guilherme Salazar
* [Lua scripting in the NetBSD kernel](http://netbsd-soc.sourceforge.net/projects/luakern/) — The NetBSD Foundation (2010), Lourival Vieira Neto
## License
Lunatik is dual-licensed under [MIT](LICENSE-MIT) or [GPL-2.0-only](LICENSE-GPL).
[Lua](https://github.com/luainkernel/lua) submodule is licensed under MIT.
For more details, see its [Copyright Notice](https://github.com/luainkernel/lua/blob/lunatik/lua.h#L530-L556).
[Klibc](https://github.com/luainkernel/klibc) submodule is dual-licensed under BSD 3-Clause or GPL-2.0-only.
For more details, see its [LICENCE](https://github.com/luainkernel/klibc/blob/lunatik/usr/klibc/LICENSE) file.
================================================
FILE: autogen/linux/.gitignore
================================================
# Ignore everything in this directory
*
# Except this file
!.gitignore
================================================
FILE: autogen/lunatik/.gitignore
================================================
# Ignore everything in this directory
*
# Except this file
!.gitignore
================================================
FILE: bin/lunatik
================================================
#!/usr/bin/lua5.4
--
-- SPDX-FileCopyrightText: (c) 2023-2026 Ring Zero Desenvolvimento de Software LTDA
-- SPDX-License-Identifier: MIT OR GPL-2.0-only
--
local config = require("lunatik.config")
local device = "/dev/lunatik"
local copyright = "Copyright (C) 2023-2026 Ring Zero Desenvolvimento de Software LTDA."
local modules = config.modules
local function probe()
return os.execute("[ -e " .. device .. " ]")
end
local function dostring(chunk)
do
local loader <close> = assert(io.open(device, "r+"))
loader:write(chunk)
end
local reader <close> = assert(io.open(device, "r"))
return reader:read("a")
end
local function sh(command, module, loaded)
local op = loaded and "&&" or "||"
os.execute(string.format("MODULE=%s;grep -wq $MODULE /proc/modules %s%s", module, op, command))
end
local function load_modules()
for _, m in ipairs(modules) do
sh("modprobe $MODULE", m)
end
if not probe() then
error("couldn't create " .. device)
end
local result = dostring[[
lunatik = require("lunatik")
lunatik.runner = require("lunatik.runner")
lunatik.runner.startup()
]]
if result ~= "" then error(result) end
end
local function unload_modules()
if probe() then
dostring("lunatik.runner.shutdown()")
end
for i = #modules, 1, -1 do
sh("rmmod $MODULE", modules[i], true)
end
end
local function reload_modules()
unload_modules()
load_modules()
end
local function status_modules()
for _, m in ipairs(modules) do
sh("echo $MODULE is loaded || echo $MODULE is not loaded", m, true)
end
end
local function ensure_loaded()
if not probe() then load_modules() end
local result = dostring[[
lunatik = lunatik or require("lunatik")
lunatik.runner = lunatik.runner or require("lunatik.runner")
lunatik.runner.startup()
]]
if result ~= "" then error(result) end
end
local tests_path = "/usr/local/share/lunatik/tests"
local function test_modules()
ensure_loaded()
local suite = arg[2]
local target = suite and (tests_path .. "/" .. suite .. "/run.sh")
or (tests_path .. "/run.sh")
if not os.execute("[ -f " .. target .. " ]") then
error("tests not installed; run: sudo make tests_install")
end
os.execute("bash " .. target)
end
local commands = {
load = load_modules,
unload = unload_modules,
reload = reload_modules,
status = status_modules,
test = test_modules,
}
local function readline_reader()
local rl = require("readline")
rl.set_readline_name("lunatik")
local function read_line(prompt)
local line = rl.readline(prompt)
if line and line ~= "" then rl.add_history(line) end
return line
end
return read_line
end
local function fallback_reader(prompt)
io.write(prompt)
io.flush()
return io.read("l")
end
local function try_as_expr(chunk)
return load("return " .. chunk .. ";") ~= nil
end
local function is_incomplete(chunk)
local _, err = load(chunk)
return err ~= nil and err:sub(-5) == "<eof>"
end
local function repl(read_line)
local line = read_line("> ")
while line ~= nil do
local chunk = line
while is_incomplete(chunk) do
local more = read_line(">> ")
if more == nil then break end
chunk = chunk .. "\n" .. more
end
local send = try_as_expr(chunk) and ("return " .. chunk) or chunk
local res = dostring(send)
if res ~= "" then print(res) end
line = read_line("> ")
end
end
local function start_repl()
ensure_loaded()
local version = dostring("return _LUNATIK_VERSION")
print(version .. " " .. copyright)
local ok, read_line = pcall(readline_reader)
if not ok then read_line = fallback_reader end
repl(read_line)
end
local cmd = commands[arg[1]]
if cmd then
cmd()
os.exit()
end
if #arg >= 1 then
local token = arg[1]
local script = arg[2]
local tokens = {run = true, spawn = true, stop = true, list = true}
local needs_script = {run = true, spawn = true, stop = true}
if not tokens[token] or (needs_script[token] and not script) then
print("usage: lunatik [load|unload|reload|status|test|list] [run|spawn|stop <script>]")
os.exit(false)
end
ensure_loaded()
local parm = arg[3] and (', "' .. arg[3] .. '"') or ""
local ret = token == "list" and "return" or ""
local chunk = string.format("%s lunatik.runner.%s('%s'%s)", ret, token, script, parm)
print(dostring(chunk))
os.exit()
end
start_repl()
================================================
FILE: config.ld
================================================
-- LDoc configuration file for the Lunatik project
-- Place this file at the root of your project and run 'ldoc .'
-- The name of your project
project = 'Lunatik'
description = 'Lunatik is a framework for scripting the Linux kernel with Lua.'
-- The title for the generated documentation
title = 'Lunatik API Documentation'
-- Source files to document.
-- LDoc will recursively scan directories.
-- By manually specifying order, we ensure menu order.
file = {
'./lib/luabyteorder.c',
'./lib/luacompletion.c',
'./lib/luacpu.c',
'./lib/crypto/hkdf.lua',
'./lib/luacrypto_aead.c',
'./lib/luacrypto_comp.c',
'./lib/luacrypto_core.c',
'./lib/luacrypto_rng.c',
'./lib/luacrypto_shash.c',
'./lib/luacrypto_skcipher.c',
'./lib/luadarken.c',
'./lib/luadata.c',
'./lib/luadevice.c',
'./lib/luafib.c',
'./lib/luafifo.c',
'./lib/luahid.c',
'./lib/lighten.lua',
'./lunatik_core.c',
'./lib/lunatik/runner.lua',
'./lib/lualinux.c',
'./lib/mailbox.lua',
'./lib/net.lua',
'./lib/luanetfilter.h',
'./lib/luanetfilter.c',
'./lib/luaskb.c',
'./lib/luanotifier.c',
'./lib/luaprobe.c',
'./lib/luarcu.c',
'./lib/luasignal.c',
'./lib/luasocket.c',
'./lib/socket/inet.lua',
'./lib/socket/raw.lua',
'./lib/socket/unix.lua',
'./lib/luasyscall.c',
'./lib/syscall/table.lua',
'./lib/luathread.c',
'./lib/luaxdp.c',
}
-- examples = "./examples"
-- The directory where LDoc will output the generated documentation.
dir = 'doc'
-- The output format. Common options: 'markdown', 'html'.
-- 'markdown' is good for GitHub pages or further processing.
-- 'html' generates a browsable website.
format = 'markdown'
-- For HTML output, you can specify a style.
-- style = '!fixed' -- A common built-in style
-- style = '!menu' -- Another built-in style with a navigation menu
-- new_style = true -- Use with '!menu' for a more modern look
-- If you have a README.md file you'd like to use as the main page content:
readme = 'README.md'
boilerplate = true
-- Merge documentation for modules that might be split across multiple files
-- or have parts in C and Lua.
merge = true
-- Sort modules and functions alphabetically in the output.
sort = true
-- By default, LDoc only documents exported functions and tables.
-- Set to true to document everything, including local functions (usually not for API docs).
-- all = false -- This is the default
-- For more LDoc options, see: https://github.com/lunarmodules/LDoc
================================================
FILE: configure.lua
================================================
--
-- SPDX-FileCopyrightText: (c) 2026 Ashwani Kumar Kamal <ashwanikamal.im421@gmail.com>
-- SPDX-License-Identifier: MIT OR GPL-2.0-only
--
local OUTPUT_DIR = "autogen"
local SCRIPT = arg[0]
local KERNEL = arg[1]
local INCLUDE = arg[2]
local MODULES = arg[3]
local specs = {
{
header = "uapi/linux/if_ether.h",
prefix = "ETH_P_",
module_name = "eth",
},
{
header = "uapi/linux/stat.h",
prefix = "S_",
module_name = "stat",
},
{
header = "uapi/linux/signal.h",
prefix = "SIG",
module_name = "signal",
}
}
local function exit(msg)
io.stderr:write(string.format("%s: %s\n", SCRIPT, msg))
os.exit(1)
end
if not KERNEL or not INCLUDE or not MODULES then
exit("usage: lua5.4 " .. SCRIPT .. " <KERNEL> <INCLUDE> <MODULES>")
end
local CC = os.getenv("CC") or "cc"
local CPP = string.format("%s -E -dM -I%s", CC, INCLUDE)
local function preprocess(header_path)
local cmd = string.format("%s %s/%s", CPP, INCLUDE, header_path)
local pipe <close> = io.popen(cmd)
if not pipe then
exit("failed to run preprocessor on " .. header_path)
end
return pipe:read("*a")
end
local function collect_constants(cpp_output, prefix)
local constants = {}
local macro_names = {}
for macro, literal in cpp_output:gmatch("#define%s+(" .. prefix .. "%w+)%s+(%S+)") do
constants[macro] = literal
table.insert(macro_names, macro)
end
table.sort(macro_names)
return constants, macro_names
end
local function resolve_value(value, constants, prefix, module_name, seen)
if tonumber(value) then return value end
if not constants[value] then return nil end
seen = seen or {}
-- recursion check: avoid cyclic defines
if seen[value] then return nil end
seen[value] = true
if value:find("^" .. prefix) then
local stripped = value:gsub("^" .. prefix, "")
return string.format('%s["%s"]', module_name, stripped)
end
return resolve_value(constants[value], constants, prefix, module_name, seen)
end
local function write_constants(file, module, spec, constants, macro_names)
for _, macro in ipairs(macro_names) do
local field_name = macro:gsub("^" .. spec.prefix, "")
local resolved_value = resolve_value(constants[macro], constants, spec.prefix, spec.module_name)
if resolved_value then
file:write(string.format('%s["%s"]\t= %s\n', spec.module_name, field_name, resolved_value))
end
end
end
local function write_module(dir, module, writer, ...)
local filepath = string.format("%s/%s/%s.lua", OUTPUT_DIR, dir, module)
local file <close>, err = io.open(filepath, "w")
if not file then
exit("cannot open " .. filepath .. ": " .. err)
end
file:write("-- auto-generated, do not edit\n")
file:write("-- kernel: " .. KERNEL .. "\n\n")
file:write("local " .. module .. " = {}\n\n")
writer(file, module, ...)
file:write("\nreturn " .. module .. "\n\n")
end
local function write_config(file, module)
file:write(string.format('%s.kernel_version = "%s"\n', module, KERNEL))
file:write(string.format('%s.modules = {\n\t"lunatik",\n', module))
for m in MODULES:gmatch("%S+") do
file:write(string.format('\t"lua%s",\n', m:lower()))
end
file:write('\t"lunatik_run"\n}\n')
end
for _, spec in ipairs(specs) do
local cpp_output = preprocess(spec.header)
local constants, macro_names = collect_constants(cpp_output, spec.prefix)
write_module("linux", spec.module_name, write_constants, spec, constants, macro_names)
end
write_module("lunatik", "config", write_config)
================================================
FILE: doc/capi.md
================================================
# Lunatik C API
```C
#include <lunatik.h>
```
## Types
### lunatik\_class\_t
```C
typedef struct lunatik_class_s {
const char *name;
const luaL_Reg *methods;
void (*release)(void *);
lunatik_opt_t opt;
} lunatik_class_t;
```
Describes a Lunatik object class.
- `name`: class name; used as the argument to `require` and to identify the class.
- `methods`: `NULL`-terminated array of Lua methods registered in the metatable.
- `release`: called when the object's reference counter reaches zero; may be `NULL`.
- `opt`: bitmask of `LUNATIK_OPT_*` flags controlling class behaviour. Flags are inherited by
every instance via `object->opt = opt | class->opt` (see `lunatik_newobject`). Flags differ
in whether they act as **constraints** or **capabilities**:
- `LUNATIK_OPT_SOFTIRQ` *(constraint)*: all instances use a spinlock and `GFP_ATOMIC`; absence
means mutex and `GFP_KERNEL`. Because this flag is always inherited, a SOFTIRQ class can never
produce a non-SOFTIRQ instance.
- `LUNATIK_OPT_MONITOR` *(capability)*: the class supports a monitored metatable that wraps Lua
method calls with the object lock, enabling safe concurrent access from multiple runtimes.
Inherited by default but cancelled when an instance is created with `LUNATIK_OPT_SINGLE`.
- `LUNATIK_OPT_SINGLE` *(constraint)*: all instances are private and non-shareable by default.
Like `SOFTIRQ`, this is always inherited and cannot be overridden per instance.
- `LUNATIK_OPT_EXTERNAL` *(constraint)*: `object->private` holds an external pointer — Lunatik
will not free it on release.
### lunatik\_reg\_t
```C
typedef struct lunatik_reg_s {
const char *name;
lua_Integer value;
} lunatik_reg_t;
```
A name–integer-value pair used to export constants to Lua. Arrays must be terminated by `{NULL, 0}`.
### lunatik\_namespace\_t
```C
typedef struct lunatik_namespace_s {
const char *name;
const lunatik_reg_t *reg;
} lunatik_namespace_t;
```
A named table of `lunatik_reg_t` constants. Passed to `LUNATIK_NEWLIB` to create sub-tables
in the module table (e.g., `netfilter.action`, `netfilter.family`). Terminated by `{NULL, NULL}`.
---
## Runtime
### lunatik\_runtime
```C
int lunatik_runtime(lunatik_object_t **pruntime, const char *script, bool sleep);
```
_lunatik\_runtime()_ creates a new `runtime` environment then loads and runs the script
`/lib/modules/lua/<script>.lua` as the entry point for this environment.
It _must_ only be called from _process context_.
The `runtime` environment is a Lunatik object that holds
a [Lua state](https://www.lua.org/manual/5.5/manual.html#lua_State).
Lunatik objects are special
Lua [userdata](https://www.lua.org/manual/5.5/manual.html#2.1)
which also hold
a [lock type](https://docs.kernel.org/locking/locktypes.html) and
a [reference counter](https://www.kernel.org/doc/Documentation/kref.txt).
If `sleep` is _true_, _lunatik\_runtime()_ will use a
[mutex](https://docs.kernel.org/locking/mutex-design.html)
for locking the `runtime` environment and the
[GFP\_KERNEL](https://www.kernel.org/doc/html/latest/core-api/memory-allocation.html)
flag for allocating new memory later on
[lunatik\_run()](#lunatik_run) calls.
Otherwise, it will use a [spinlock](https://docs.kernel.org/locking/locktypes.html#raw-spinlock-t-and-spinlock-t) and [GFP\_ATOMIC](https://www.kernel.org/doc/html/latest/core-api/memory-allocation.html).
_lunatik\_runtime()_ opens the Lua standard libraries
[present on Lunatik](https://github.com/luainkernel/lunatik#c-api).
If successful, _lunatik\_runtime()_ sets the address pointed by `pruntime` and
[Lua's extra space](https://www.lua.org/manual/5.5/manual.html#lua_getextraspace)
with a pointer for the new created `runtime` environment,
sets the _reference counter_ to `1` and then returns `0`.
Otherwise, it returns `-ENOMEM`, if insufficient memory is available;
or `-EINVAL`, if it fails to load or run the `script`.
#### Example
```Lua
-- /lib/modules/lua/mydevice.lua
function myread(len, off)
return "42"
end
```
```C
static lunatik_object_t *runtime;
static int __init mydevice_init(void)
{
return lunatik_runtime(&runtime, "mydevice", true);
}
```
### lunatik\_stop
```C
int lunatik_stop(lunatik_object_t *runtime);
```
_lunatik\_stop()_
[closes](https://www.lua.org/manual/5.5/manual.html#lua_close)
the
[Lua state](https://www.lua.org/manual/5.5/manual.html#lua_State)
created for this `runtime` environment and decrements the
[reference counter](https://www.kernel.org/doc/Documentation/kref.txt).
Once the reference counter is decremented to zero, the
[lock type](https://docs.kernel.org/locking/locktypes.html)
and the memory allocated for the `runtime` environment are released.
If the `runtime` environment has been released, it returns `1`;
otherwise, it returns `0`.
### lunatik\_run
```C
void lunatik_run(lunatik_object_t *runtime, <inttype> (*handler)(...), <inttype> &ret, ...);
```
_lunatik\_run()_ locks the `runtime` environment and calls the `handler`
passing the associated Lua state as the first argument followed by the variadic arguments.
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.
#### Example
```C
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("%s\n", 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;
}
```
### lunatik\_handle
```C
void lunatik_handle(lunatik_object_t *runtime, <inttype> (*handler)(...), <inttype> &ret, ...);
```
Like `lunatik_run`, but without acquiring the runtime lock. Use this when the lock is
already held, or when calling from within a `lunatik_run` handler. Defined as a macro.
### lunatik\_toruntime
```C
lunatik_object_t *lunatik_toruntime(lua_State *L);
```
Returns the `runtime` environment referenced by `L`'s
[extra space](https://www.lua.org/manual/5.5/manual.html#lua_getextraspace).
Defined as a macro.
### lunatik\_isready
```C
bool lunatik_isready(lua_State *L);
```
Returns `true` if the script associated with `L` has finished loading (i.e., the top-level
chunk has returned). Use this to guard operations that must not run during module
initialization — for example, spawning a kernel thread from a `runner.spawn` callback.
---
## Object Lifecycle
### lunatik\_newobject
```C
lunatik_object_t *lunatik_newobject(lua_State *L, const lunatik_class_t *class, size_t size, lunatik_opt_t opt);
```
_lunatik\_newobject()_ allocates a new Lunatik object and pushes a userdata
containing a pointer to the object onto the Lua stack.
`object->opt` is computed as `opt | class->opt`: all class flags are inherited by the instance.
`opt` may add flags on top (e.g. `LUNATIK_OPT_SOFTIRQ` for a non-sleepable runtime instance).
- Pass `LUNATIK_OPT_MONITOR` to wrap method calls with the object lock, enabling safe concurrent
access from multiple runtimes.
- Pass `LUNATIK_OPT_SINGLE` for a private, non-shareable instance. The object cannot be cloned or
passed to another runtime via `_ENV` or `resume`. `SINGLE` cancels `MONITOR` inheritance: a
`SINGLE` instance of a `MONITOR` class does **not** get monitor wrappers, since non-shared
objects do not need them.
- Pass `LUNATIK_OPT_NONE` (`0`) to inherit only the class flags.
It allocates `size` bytes for the object's private data, unless `LUNATIK_OPT_EXTERNAL` is set in
`class->opt`, in which case `object->private` is expected to be set by the caller.
### lunatik\_createobject
```C
lunatik_object_t *lunatik_createobject(const lunatik_class_t *class, size_t size, lunatik_opt_t opt);
```
_lunatik\_createobject()_ creates a Lunatik object independently of any Lua
state. This is intended for objects created in C that will be shared
with Lua runtimes later via `lunatik_cloneobject`.
Like `lunatik_newobject`, `object->opt` is computed as `opt | class->opt`.
Sleep mode is determined by `LUNATIK_OPT_SOFTIRQ` in `object->opt`.
Returns a pointer to the `lunatik_object_t` on success, or `NULL` if memory allocation fails.
### lunatik\_cloneobject
```C
void lunatik_cloneobject(lua_State *L, lunatik_object_t *object);
```
_lunatik\_cloneobject()_ pushes `object` onto the Lua stack as a userdata with the correct
metatable. It calls `lunatik_require(L, class->name)` internally to ensure the class
metatable is registered even if the script never called `require` itself.
The object must not have `LUNATIK_OPT_SINGLE` set; otherwise a Lua error is raised.
Use together with `lunatik_createobject` for C-owned objects that must be passed to Lua:
```C
obj = lunatik_createobject(&luafoo_class, sizeof(foo_t), LUNATIK_OPT_MONITOR);
lunatik_run(runtime, my_handler, ret, obj);
/* inside my_handler: */
lunatik_cloneobject(L, obj); /* pushes userdata, increments refcount */
lunatik_getobject(obj);
```
### lunatik\_getobject
```C
void lunatik_getobject(lunatik_object_t *object);
```
Increments the [reference counter](https://www.kernel.org/doc/Documentation/kref.txt) of `object`.
### lunatik\_putobject
```C
int lunatik_putobject(lunatik_object_t *object);
```
Decrements the [reference counter](https://www.kernel.org/doc/Documentation/kref.txt) of `object`.
If the object has been released, returns `1`; otherwise returns `0`.
---
## Object Access
### lunatik\_checkobject
```C
lunatik_object_t *lunatik_checkobject(lua_State *L, int i);
```
Returns the Lunatik object at stack position `i`. Raises a Lua error if the value is not a
Lunatik object. Defined as a macro.
### lunatik\_toobject
```C
lunatik_object_t *lunatik_toobject(lua_State *L, int i);
```
Returns the Lunatik object at stack position `i` without type checking. Returns `NULL` if
the value is not a userdata. Defined as a macro.
### LUNATIK\_OBJECTCHECKER
```C
#define LUNATIK_OBJECTCHECKER(checker, T)
```
Generates a `static inline` function `T checker(lua_State *L, int ix)` that returns
`object->private` cast to `T`. Performs a full object check; raises a Lua error if the
value at `ix` is not a valid Lunatik object.
### LUNATIK\_PRIVATECHECKER
```C
#define LUNATIK_PRIVATECHECKER(checker, T, ...)
```
Like `LUNATIK_OBJECTCHECKER`, but also guards against use-after-free by checking that
`private != NULL` before returning. The optional `...` may include additional validation
statements (e.g., checking a secondary field) that are executed before `return private`.
---
## Registry and Attach/Detach
The registry pattern keeps pre-allocated objects alive across `lunatik_run` calls without
exposing them to the GC:
```
// Registration (once, at hook setup):
lunatik_attach(L, obj, field, luafoo_new) // creates object, stores in registry, sets obj->field
// Use (on each callback):
lunatik_getregistry(L, obj->field) // pushes userdata
lunatik_object_t *o = lunatik_toobject(L, -1);
luafoo_reset(o, ...); // update the wrapped pointer
// Teardown (on unregister):
lunatik_detach(runtime, obj, field) // unregisters and nulls obj->field
```
### lunatik\_registerobject
```C
void lunatik_registerobject(lua_State *L, int ix, lunatik_object_t *object);
```
Pins `object` and its `private` pointer in `LUA_REGISTRYINDEX`, preventing garbage
collection. `ix` is typically the index of the opts table passed to the registration function.
### lunatik\_unregisterobject
```C
void lunatik_unregisterobject(lua_State *L, lunatik_object_t *object);
```
Removes `object` and its `private` pointer from the registry, allowing GC to collect them.
### lunatik\_getregistry
```C
int lunatik_getregistry(lua_State *L, void *key);
```
Pushes the value stored in `LUA_REGISTRYINDEX` at `key` onto the Lua stack and returns
its type. Defined as a macro wrapping `lua_rawgetp`.
### lunatik\_attach
```C
void lunatik_attach(lua_State *L, obj, field, new_fn, ...);
```
Creates a new object by calling `new_fn(L, ...)`, stores it in `LUA_REGISTRYINDEX` keyed by
the returned pointer, sets `obj->field` to the result, and pops the userdata from the stack.
Defined as a macro.
### lunatik\_detach
```C
void lunatik_detach(lunatik_object_t *runtime, obj, field);
```
Unregisters `obj->field` from the registry and sets `obj->field = NULL`. Safe to call when
the Lua state may already be closed (e.g., from `release` after `lunatik_stop`). Defined as a macro.
---
## Error Handling
### lunatik\_throw
```C
void lunatik_throw(lua_State *L, int ret);
```
Pushes the POSIX error name for `-ret` (e.g., `"ENOMEM"`) as a string and calls `lua_error`.
Used to convert negative kernel error codes into Lua errors.
### lunatik\_try
```C
void lunatik_try(lua_State *L, op, ...);
```
Calls `op(...)`. If the return value is negative, calls `lunatik_throw`. Defined as a macro.
### lunatik\_tryret
```C
void lunatik_tryret(lua_State *L, ret, op, ...);
```
Like `lunatik_try`, but stores the return value in `ret` before checking. Defined as a macro.
---
## Table Fields
These macros read fields from a Lua table at stack index `idx` into a C struct.
### lunatik\_setinteger
```C
void lunatik_setinteger(lua_State *L, int idx, hook, field);
```
Reads a required integer field named `field` from the table at `idx` into `hook->field`.
Raises a Lua error if the field is missing or not a number.
### lunatik\_optinteger
```C
void lunatik_optinteger(lua_State *L, int idx, priv, field, opt);
```
Reads an optional integer field named `field` from the table at `idx` into `priv->field`.
Falls back to `opt` if the field is absent or nil.
### lunatik\_setstring
```C
void lunatik_setstring(lua_State *L, int idx, hook, field, maxlen);
```
Reads a required string field named `field` from the table at `idx` into `hook->field`,
truncated to `maxlen` bytes. Raises a Lua error if the field is missing or not a string.
---
## Module Definition
### LUNATIK\_CLASSES
```C
#define LUNATIK_CLASSES(name, ...)
```
Declares a NULL-terminated `const lunatik_class_t *` array named `lua<name>_classes`,
to be passed as the `classes` argument of `LUNATIK_NEWLIB`.
- `name`: module name suffix (same token used in `LUNATIK_NEWLIB`).
- `...`: one or more `lunatik_class_t *` pointers.
### LUNATIK\_NEWLIB
```C
#define LUNATIK_NEWLIB(libname, funcs, classes, namespaces)
```
Defines and exports the `luaopen_<libname>` entry point using `EXPORT_SYMBOL_GPL`.
- `funcs`: `luaL_Reg[]` of Lua-callable functions (the module table).
- `classes`: NULL-terminated `const lunatik_class_t **` array declared with
`LUNATIK_CLASSES`, or `NULL` if the module defines no object type.
- `namespaces`: `lunatik_namespace_t[]` of constant sub-tables, or `NULL`.
When `classes != NULL`, `LUNATIK_NEWLIB` registers the metatable(s) for every
class in the array. When `namespaces != NULL`, it creates constant sub-tables
inside the module table.
#### Example — single class
```C
static const luaL_Reg luafoo_lib[] = {
{"new", luafoo_new},
{NULL, NULL},
};
LUNATIK_CLASSES(foo, &luafoo_class);
LUNATIK_NEWLIB(foo, luafoo_lib, luafoo_classes, NULL);
```
#### Example — multiple classes
```C
LUNATIK_CLASSES(foo, &luafoo_class, &luafoo_bar_class);
LUNATIK_NEWLIB(foo, luafoo_lib, luafoo_classes, NULL);
```
---
## Memory
### lunatik\_malloc
```C
void *lunatik_malloc(lua_State *L, size_t size);
```
Allocates `size` bytes using the Lua allocator. Returns `NULL` on failure.
### lunatik\_realloc
```C
void *lunatik_realloc(lua_State *L, void *ptr, size_t size);
```
Reallocates `ptr` to `size` bytes using the Lua allocator.
### lunatik\_free
```C
void lunatik_free(void *ptr);
```
Frees memory allocated by `lunatik_malloc` or `lunatik_realloc`. Equivalent to `kfree`.
================================================
FILE: driver.lua
================================================
--
-- SPDX-FileCopyrightText: (c) 2023-2026 Ring Zero Desenvolvimento de Software LTDA
-- SPDX-License-Identifier: MIT OR GPL-2.0-only
--
local device = require("device")
local driver = {name = "lunatik"}
function driver:read()
local result = self.result
self.result = nil
return result
end
local function result(_, ...)
local n = select('#', ...)
local t = {}
for i = 1, n do
t[i] = tostring(select(i, ...))
end
return table.concat(t, '\t')
end
function driver:write(buf)
local ok, err = load(buf)
if ok then
err = result(pcall(ok))
end
self.result = err
end
device.new(driver)
================================================
FILE: examples/cpuexporter.lua
================================================
--
-- SPDX-FileCopyrightText: (c) 2025-2026 Enderson Maia <endersonmaia@gmail.com>
-- SPDX-License-Identifier: MIT OR GPL-2.0-only
--
local lunatik = require("lunatik")
local thread = require("thread")
local unix = require("socket.unix")
local linux = require("linux")
local cpu = require("cpu")
local socket = require("socket")
local shouldstop = thread.shouldstop
local NONBLOCK = socket.sock.NONBLOCK
local server = unix.stream("/tmp/cpuexporter.sock")
server:bind()
server:listen()
local last_stats = {}
local last_total_stats = {}
-- Scale integer to decimal with high precision
-- Converts a ratio (metric/total) to percentage format with 16 decimal places
local function format_percentage(metric, total)
if total == 0 then
return "0.0000000000000000"
end
local int_part = (metric * 100) // total
local remainder = (metric * 100) % total
local frac_high = (remainder * 100000000) // total
local remainder2 = (remainder * 100000000) % total
local frac_low = (remainder2 * 100000000) // total
return string.format("%d.%08d%08d", int_part, frac_high, frac_low)
end
-- Helper function to sum all stats values in a table
-- Note: guest and guest_nice are already included in user and nice respectively
-- according to the Linux kernel documentation, so we must exclude them from the total
local function sum_stats(stats)
local sum = 0
stats["guest"] = 0
stats["guest_nice"] = 0
for key, value in pairs(stats) do
sum = sum + value
end
return sum
end
-- returns per cpu stats, total_stats tables
local function cpu_stats()
--TODO: add cpu-total with accumulated values for all cpus
local stats = {}
local total_stats = {}
cpu.foreach_online(function(id)
stats[id] = {}
stats[id] = cpu.stats(id)
total_stats[id] = sum_stats(stats[id])
end)
return stats, total_stats
end
-- returns cpu_usage (%) table
local function cpu_usage()
local usage = {}
local current_stats, current_total_stats = cpu_stats()
for cpu_id, _ in pairs(current_stats) do
local total_delta = current_total_stats[cpu_id] - (last_total_stats[cpu_id] or 0)
local guest_delta = current_stats[cpu_id].guest - (last_stats[cpu_id].guest or 0)
local guest_nice_delta = current_stats[cpu_id].guest_nice - (last_stats[cpu_id].guest_nice or 0)
usage[cpu_id] = {}
for metric, value in pairs(current_stats[cpu_id]) do
local metric_delta = value - (last_stats[cpu_id][metric] or 0)
if metric == "user" then
metric_delta = metric_delta - guest_delta
elseif metric == "nice" then
metric_delta = metric_delta - guest_nice_delta
end
usage[cpu_id][metric] = format_percentage(metric_delta, total_delta)
end
end
last_stats = current_stats
last_total_stats = current_total_stats
return usage
end
local function cpu_metrics()
local metrics = ""
local ts_ms = linux.time() // 1000 -- convert nanoseconds to milliseconds
local usage_data = cpu_usage() -- Call once and store the result
-- Collect all unique metric names from the first available CPU
local cpu_metric_names = {}
for _, cpu_metrics in pairs(usage_data) do
for key, _ in pairs(cpu_metrics) do
cpu_metric_names[key] = true
end
break -- Only need one CPU to get all metric names
end
-- Output grouped by metric name
for metric, _ in pairs(cpu_metric_names) do
metrics = metrics .. string.format('# TYPE cpu_usage_%s gauge\n', metric)
for cpu_id, cpu_metrics in pairs(usage_data) do
local value = cpu_metrics[metric] or "0"
metrics = metrics .. string.format('cpu_usage_%s{cpu="cpu%d"} %s %d\n',
metric, cpu_id, value, ts_ms)
end
end
return metrics
end
local function handle_client(session)
-- Read the request
local request, err = session:receive(1024)
if not request then
error(err)
end
-- Check if this is an HTTP request
local method, path, http_version = string.match(request, "^(%w+)%s+([^%s]+)%s+(HTTP/%d%.%d)")
if http_version then
-- This is an HTTP request, validate it
if method ~= "GET" then
session:send("HTTP/1.1 405 Method Not Allowed\r\n\r\n")
error("Method not allowed: " .. tostring(method))
end
if path ~= "/metrics" then
session:send("HTTP/1.1 404 Not Found\r\n\r\n")
error("Path not found: " .. tostring(path))
end
-- Send HTTP response headers
session:send("HTTP/1.1 200 OK\r\n")
session:send("Content-Type: text/plain; version=0.0.4\r\n")
session:send("\r\n")
end
-- Send metrics (works for both HTTP and plain connections like socat)
session:send(cpu_metrics())
end
-- Initial sample
last_stats = cpu_stats()
local function daemon()
print("cpud [daemon]: started")
while (not shouldstop()) do
local ok, session = pcall(server.accept, server, NONBLOCK)
if ok then
local ok, err = pcall(handle_client, session)
if not ok then
print("cpud [daemon]: error handling client: " .. tostring(err))
end
session:close()
elseif session == "EAGAIN" then
linux.schedule(100)
end
end
print("cpud [daemon]: stopped")
end
return daemon
================================================
FILE: examples/dnsblock/common.lua
================================================
--
-- SPDX-FileCopyrightText: (c) 2024 Mohammad Shehar Yaar Tausif <sheharyaar48@gmail.com>
-- SPDX-License-Identifier: MIT OR GPL-2.0-only
--
-- Common code for new netfilter framework and legacy iptables dnsblock example
local linux = require("linux")
local byteorder = require("byteorder")
local string = require("string")
local common = {}
local udp = 0x11
local dns = 0x35
local blacklist = {
"github.com",
"gitlab.com",
}
local function get_domain(skb, off)
local _, _, name = skb:getstring(off):find("([^\0]*)")
return name
end
local function check_blacklist(name)
for _, v in ipairs(blacklist) do
if string.find(name, v) ~= nil then
return true
end
end
return false
end
function common.hook(skb, thoff, proto)
if proto == udp then
local dstport = byteorder.ntoh16(skb:getuint16(thoff + 2))
if dstport == dns then
local qoff = thoff + 20
local name = get_domain(skb, qoff)
if check_blacklist(name) then
print("DNS query for " .. name .. " blocked\n")
return true
end
end
end
return false
end
return common
================================================
FILE: examples/dnsblock/nf_dnsblock.lua
================================================
--
-- SPDX-FileCopyrightText: (c) 2024-2026 Mohammad Shehar Yaar Tausif <sheharyaar48@gmail.com>
-- SPDX-License-Identifier: MIT OR GPL-2.0-only
--
-- Filter DNS packets based on a blocklist using new netfilter hooks
local nf = require("netfilter")
local common = require("examples.dnsblock.common")
local family = nf.family
local action = nf.action
local hooks = nf.inet_hooks
local priority = nf.ip_priority
local function dnsblock_hook(skb)
local pkt = skb:data("net")
local proto = pkt:getuint8(9)
local ihl = (pkt:getuint8(0) & 0x0F)
local thoff = ihl * 4
return common.hook(pkt, thoff, proto) and action.DROP or action.ACCEPT
end
nf.register{
hook = dnsblock_hook,
pf = family.INET,
hooknum = hooks.LOCAL_OUT,
priority = priority.FILTER,
}
================================================
FILE: examples/dnsdoctor/cleanup.sh
================================================
# SPDX-FileCopyrightText: (c) 2024 Mohammad Shehar Yaar Tausif <sheharyaar48@gmail.com>
# SPDX-License-Identifier: MIT OR GPL-2.0-only
#!/bin/bash
set -eux
rm dnstest -rf
# backup resolv config
if [[ -f /etc/resolv.conf.lunatik ]]; then
echo "Restoring dns config from resolv.conf.lunatik"
sudo rm /etc/resolv.conf
sudo cp /etc/resolv.conf.lunatik /etc/resolv.conf
sudo rm /etc/resolv.conf.lunatik
fi
# down the interfaces
sudo ip -n ns1 link set veth1 down
sudo ip -n ns2 link set veth3 down
sudo ip link set veth2 down
sudo ip link set veth4 down
sudo ip addr delete 10.1.1.2/24 dev veth2
sudo ip -n ns1 addr delete 10.1.1.3/24 dev veth1
sudo ip addr delete 10.1.2.2/24 dev veth4
sudo ip -n ns2 addr delete 10.1.2.3/24 dev veth3
# delete link between host and the namespaces
sudo ip -n ns1 link delete veth1
sudo ip -n ns2 link delete veth3
# delete namespaces ns1 for dns server ns2 for server
sudo ip netns delete ns1
sudo ip netns delete ns2
================================================
FILE: examples/dnsdoctor/common.lua
================================================
--
-- SPDX-FileCopyrightText: (c) 2024 Mohammad Shehar Yaar Tausif <sheharyaar48@gmail.com>
-- SPDX-License-Identifier: MIT OR GPL-2.0-only
--
-- Common code for new netfilter framework and legacy iptables dns doctoring example
local nf = require("netfilter")
local linux = require("linux")
local byteorder = require("byteorder")
local action = nf.action
local dns = 0x35
local common = {}
local function get_domain(skb, off)
local _, nameoff, name = skb:getstring(off):find("([^\0]*)")
return name, nameoff + 1
end
function common.hook(skb, thoff, target_dns, target_ip, dst_ip, packet_dst)
if packet_dst ~= byteorder.hton32(dst_ip) then
return action.ACCEPT
end
local srcport = byteorder.ntoh16(skb:getuint16(thoff))
if srcport == dns then
local dnsoff = thoff + 8
local nanswers = byteorder.ntoh16(skb:getuint16(dnsoff + 6))
-- check the domain name
dnsoff = dnsoff + 12
local domainname, nameoff = get_domain(skb, dnsoff)
if domainname == target_dns then
dnsoff = dnsoff + nameoff + 4 -- skip over type, label fields
-- iterate over answers
for i = 1, nanswers do
local atype = byteorder.hton16(skb:getuint16(dnsoff + 2))
if atype == 1 then
skb:setuint32(dnsoff + 12, byteorder.hton32(target_ip))
end
dnsoff = dnsoff + 16
end
end
end
return action.ACCEPT
end
return common
================================================
FILE: examples/dnsdoctor/nf_dnsdoctor.lua
================================================
--
-- SPDX-FileCopyrightText: (c) 2024-2026 Mohammad Shehar Yaar Tausif <sheharyaar48@gmail.com>
-- SPDX-License-Identifier: MIT OR GPL-2.0-only
--
-- DNS Doctoring using new netfilter API
local nf = require("netfilter")
local string = require("string")
local common = require("examples.dnsdoctor.common")
local action = nf.action
local family = nf.family
local hooks = nf.inet_hooks
local pri = nf.ip_priority
local udp = 0x11
local function dnsdoctor_hook(skb)
local pkt = skb:data("mac")
local ihl = pkt:getuint8(0) & 0x0F
local thoff = ihl * 4
local proto = pkt:getuint8(9)
local packet_dst = pkt:getuint32(16)
if proto ~= udp then
return action.ACCEPT
end
local target_dns = string.pack("s1s1", "lunatik", "com")
local dns_ip = "10.1.2.3"
local target_ip = 0
dns_ip:gsub("%d+", function(s) target_ip = target_ip * 256 + tonumber(s) end)
local dst = "10.1.1.2"
local dst_ip = 0
dst:gsub("%d+", function(s) dst_ip = dst_ip * 256 + tonumber(s) end)
return common.hook(pkt, thoff, target_dns, target_ip, dst_ip, packet_dst)
end
nf.register{
hook = dnsdoctor_hook,
pf = family.INET,
hooknum = hooks.PRE_ROUTING,
priority = pri.MANGLE + 1,
}
================================================
FILE: examples/dnsdoctor/setup.sh
================================================
# SPDX-FileCopyrightText: (c) 2024 Mohammad Shehar Yaar Tausif <sheharyaar48@gmail.com>
# SPDX-License-Identifier: MIT OR GPL-2.0-only
#!/bin/bash
set -eux
# add namespaces ns1 for dns server ns2 for server
sudo ip netns add ns1
sudo ip netns add ns2
# add link between host and the namespaces
sudo ip link add veth1 netns ns1 type veth peer name veth2
sudo ip link add veth3 netns ns2 type veth peer name veth4
# add ip address to the links
# DNS IP : 10.1.1.3
# Server IP : 10.1.2.3
sudo ip addr add 10.1.1.2/24 dev veth2
sudo ip -n ns1 addr add 10.1.1.3/24 dev veth1
sudo ip addr add 10.1.2.2/24 dev veth4
sudo ip -n ns2 addr add 10.1.2.3/24 dev veth3
# up the interfaces
sudo ip -n ns1 link set veth1 up
sudo ip -n ns2 link set veth3 up
sudo ip link set veth2 up
sudo ip link set veth4 up
# make a directory to setup dns server
mkdir dnstest
cd dnstest
python -m venv .venv
source .venv/bin/activate
pip install dnserver
# backup resolv config
echo "Backing up resolver config to /etc/resolver.conf.lunatik"
sudo cp -f /etc/resolv.conf /etc/resolv.conf.lunatik && \
sudo sed -i 's/nameserver/#nameserver/g' /etc/resolv.conf && \
echo "nameserver 10.1.1.3" | sudo tee -a /etc/resolv.conf && \
# add zone info and run dns server in ns1
echo """
[[zones]]
host = 'lunatik.com'
type = 'A'
answer = '192.168.10.1'
[[zones]]
host = 'lunatik.com'
type = 'NS'
answer = 'ns1.lunatik.com.'
[[zones]]
host = 'lunatik.com'
type = 'NS'
answer = 'ns2.lunatik.com.'
""" > zones.toml
sudo ip netns exec ns1 .venv/bin/dnserver --no-upstream zones.toml
================================================
FILE: examples/echod/daemon.lua
================================================
--
-- SPDX-FileCopyrightText: (c) 2023-2024 Ring Zero Desenvolvimento de Software LTDA
-- SPDX-License-Identifier: MIT OR GPL-2.0-only
--
local lunatik = require("lunatik")
local thread = require("thread")
local socket = require("socket")
local inet = require("socket.inet")
local linux = require("linux")
local data = require("data")
local shouldstop = thread.shouldstop
local task = linux.task
local sock = socket.sock
local control = data.new(2)
control:setbyte(1, 1) -- alive
local server = inet.tcp()
server:bind(inet.localhost, 1337)
server:listen()
local n = 1
local worker = "echod/worker"
local function daemon()
print("echod [daemon]: started")
while (not shouldstop()) do
local ok, session = pcall(server.accept, server, sock.NONBLOCK)
if ok then
control:setbyte(0, n) -- #workers
local runtime = lunatik.runtime("examples/" .. worker)
runtime:resume(control, session)
thread.run(runtime, worker .. n)
n = n + 1
elseif session == "EAGAIN" then
linux.schedule(100)
end
end
control:setbyte(1, 0) -- dead
print("echod [daemon]: stopped")
end
return daemon
================================================
FILE: examples/echod/worker.lua
================================================
--
-- SPDX-FileCopyrightText: (c) 2023-2026 Ring Zero Desenvolvimento de Software LTDA
-- SPDX-License-Identifier: MIT OR GPL-2.0-only
--
local thread = require("thread")
local shouldstop = thread.shouldstop
local function info(id, message)
local prefix = "echod [worker #" .. id .. "]"
print(string.format("%s: %s", prefix, message))
end
local function alive(control)
return control:getbyte(1) ~= 0
end
local function echo(session)
local message = session:receive(1024)
session:send(message)
return message == ""
end
local function worker(control, session)
return function ()
local id = control:getbyte(0)
info(id, "started")
repeat
local ok, err = pcall(echo, session)
if not ok then
return info(id, "aborted")
end
until (not alive(control) or err or shouldstop())
info(id, "stopped")
end
end
return worker
================================================
FILE: examples/filter/Makefile
================================================
# SPDX-FileCopyrightText: (c) 2023-2024 Ring Zero Desenvolvimento de Software LTDA
# SPDX-License-Identifier: MIT OR GPL-2.0-only
all: vmlinux https.o
vmlinux:
bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h
https.o: https.c
clang -target bpf -Wall -O2 -c -g $<
clean:
rm -f vmlinux.h https.o
================================================
FILE: examples/filter/https.c
================================================
/*
* SPDX-FileCopyrightText: (c) 2024 Ring Zero Desenvolvimento de Software LTDA
* SPDX-License-Identifier: MIT OR GPL-2.0-only
*/
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_endian.h>
extern int bpf_luaxdp_run(char *key, size_t key__sz, struct xdp_md *xdp_ctx, void *arg, size_t arg__sz) __ksym;
static char runtime[] = "examples/filter/sni";
struct bpf_luaxdp_arg {
__u16 offset;
} __attribute__((packed));
SEC("xdp")
int filter_https(struct xdp_md *ctx)
{
struct bpf_luaxdp_arg arg;
void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data;
struct iphdr *ip = data + sizeof(struct ethhdr);
if (ip + 1 > (struct iphdr *)data_end)
goto pass;
if (ip->protocol != IPPROTO_TCP)
goto pass;
struct tcphdr *tcp = (void *)ip + (ip->ihl * 4);
if (tcp + 1 > (struct tcphdr *)data_end)
goto pass;
if (bpf_ntohs(tcp->dest) != 443 || !tcp->psh)
goto pass;
void *payload = (void *)tcp + (tcp->doff * 4);
if (payload > data_end)
goto pass;
arg.offset = bpf_htons((__u16)(payload - data));
int action = bpf_luaxdp_run(runtime, sizeof(runtime), ctx, &arg, sizeof(arg));
return action < 0 ? XDP_PASS : action;
pass:
return XDP_PASS;
}
char _license[] SEC("license") = "Dual MIT/GPL";
================================================
FILE: examples/filter/sni.lua
================================================
--
-- SPDX-FileCopyrightText: (c) 2024 Ring Zero Desenvolvimento de Software LTDA
-- SPDX-License-Identifier: MIT OR GPL-2.0-only
--
local xdp = require("xdp")
local action = xdp.action
local function set(t)
local s = {}
for _, key in ipairs(t) do s[key] = true end
return s
end
local blacklist = set{
"ebpf.io",
}
local function log(sni, verdict)
print(string.format("filter_sni: %s %s", sni, verdict))
end
local function unpacker(packet, base)
local byte = function (offset)
return packet:getbyte(base + offset)
end
local short = function (offset)
local offset = base + offset
return packet:getbyte(offset) << 8 | packet:getbyte(offset + 1)
end
local str = function (offset, length)
return packet:getstring(base + offset, length)
end
return byte, short, str
end
local function offset(argument)
return select(2, unpacker(argument, 0))(0)
end
local client_hello = 0x01
local handshake = 0x16
local server_name = 0x00
local session = 43
local max_extensions = 17
local function filter_sni(packet, argument)
local byte, short, str = unpacker(packet, offset(argument))
if byte(0) ~= handshake or byte(5) ~= client_hello then
return action.PASS
end
local cipher = (session + 1) + byte(session)
local compression = cipher + 2 + short(cipher)
local extension = compression + 3 + byte(compression)
for i = 1, max_extensions do
local data = extension + 4
if short(extension) == server_name then
local length = short(data + 3)
local sni = str(data + 5, length)
verdict = blacklist[sni] and "DROP" or "PASS"
log(sni, verdict)
return action[verdict]
end
extension = data + short(extension + 2)
end
return action.PASS
end
xdp.attach(filter_sni)
================================================
FILE: examples/gesture.lua
================================================
--
-- SPDX-FileCopyrightText: (c) 2025-2026 Jieming Zhou <qrsikno@gmail.com>
-- SPDX-License-Identifier: MIT OR GPL-2.0-only
--
-- Driver for QEMU's USB mouse with gesture (dragging),
-- swiping right to lock the mouse and swiping left to unlock it.
local hid = require("hid")
local driver = {name = "gesture", id_table = {{vendor = 0x0627, product = 0x0001}}}
local threshold = 2
local function debug(fmt, ...)
print(string.format(fmt, ...))
end
function driver:probe(id)
self.state = {x = 0, count = 0, lock = false}
end
local function forward(x0, x1)
return (x0 >= 32767 and x1 <= 0) or (x1 > x0)
end
local function count(state, direction)
if direction ~= "neutral" then
if state.direction == direction then
state.count = state.count + 1
else
state.count = 0
state.direction = direction
end
end
return state.count
end
function driver:raw_event(hdev, report, raw)
local state = self.state
local button = raw:getbyte(0)
local left_down = (button & 1) == 1
if left_down then
local x0 = state.x
local x1 = raw:getint16(1)
local direction = x0 == x1 and "neutral" or
forward(x0, x1) and "right" or "left"
debug("%s\t%d %d", direction, x0, x1)
if count(state, direction) > threshold then
if direction == "right" then
state.lock = true
elseif direction == "left" then
state.lock = false
end
end
state.x = x1
end
if state.lock then
local last = #raw - 1
for i = 0, last do
raw:setbyte(i, 0)
end
end
end
hid.register(driver)
================================================
FILE: examples/keylocker.lua
================================================
--
-- SPDX-FileCopyrightText: (c) 2023-2024 Ring Zero Desenvolvimento de Software LTDA
-- SPDX-License-Identifier: MIT OR GPL-2.0-only
--
local notifier = require("notifier")
-- <UP> <UP> <DOWN> <DOWN> <LEFT> <RIGHT> <LEFT> <RIGHT> <LCTRL> <LALT>
local konami = {code = {103, 103, 108, 108, 105, 106, 105, 106, 29, 56}, ix = 1}
function konami:completion(key)
self.ix = key == self.code[self.ix] and (self.ix + 1) or 1
return self.ix == (#self.code + 1)
end
local notify = notifier.notify
local kbd = notifier.kbd
local enable = true
local function locker(event, down, shift, key)
if not down and event == kbd.KEYCODE and konami:completion(key) then
enable = not enable
end
return enable and notify.OK or notify.STOP
end
notifier.keyboard(locker)
================================================
FILE: examples/lldpd.lua
================================================
--
-- SPDX-FileCopyrightText: (c) 2025-2026 Ashwani Kumar Kamal <ashwanikamal.im421@gmail.com>
-- SPDX-License-Identifier: MIT OR GPL-2.0-only
--
-- Daemon to send LLDP frames on given interface
local raw = require("socket.raw")
local linux = require("linux")
local thread = require("thread")
local eth = require("linux.eth")
local shouldstop = thread.shouldstop
-- LLDP multicast destination
local ETH_DST_MAC = string.char(0x01,0x80,0xc2,0x00,0x00,0x0e)
-- System Capabilities: station only
local LLDP_CAP_STATION_ONLY = 0x0080
local config = {
interface = "veth0",
port_description = "ethernet interface",
-- default transmission interval used in lldpd implementation (30s)
-- https://lldpd.github.io/usage.html
tx_interval_ms = 30000,
system = {
name = "lunatik-lldpd",
description = "LLDP daemon implemented in Lunatik",
ttl = 120,
capabilities = LLDP_CAP_STATION_ONLY,
capabilities_enabled = LLDP_CAP_STATION_ONLY,
},
}
local ethertype = string.pack(">I2", eth.LLDP)
local function tlv(t, payload, subtype)
if subtype then
payload = string.char(subtype) .. payload
end
return string.pack(">I2", (t << 9) | #payload) .. payload
end
local function build_lldp_frame(chassis_id)
local port_id = config.interface
local ttl = string.pack(">I2", config.system.ttl)
local capabilities = string.pack(">I2I2", config.system.capabilities, config.system.capabilities_enabled)
local pdu = {
-- Ethernet header
ETH_DST_MAC,
chassis_id,
ethertype,
-- LLDP TLVs
tlv(1, chassis_id, 4),
tlv(2, port_id, 5),
tlv(3, ttl),
tlv(4, config.port_description),
tlv(5, config.system.name),
tlv(6, config.system.description),
tlv(7, capabilities),
-- End of LLDPDU
tlv(0, ""),
}
return table.concat(pdu)
end
local ifindex = linux.ifindex(config.interface)
local src_mac = linux.ifaddr(ifindex)
local lldp_frame = build_lldp_frame(src_mac)
local function worker()
local tx <close> = raw.bind(eth.LLDP, ifindex)
while (not shouldstop()) do
tx:send(lldp_frame)
print(string.format("[lldpd] frame sent on ifindex=%d (%d bytes)", ifindex, #lldp_frame))
linux.schedule(config.tx_interval_ms)
end
print("[lldpd] worker stopped")
end
return worker
================================================
FILE: examples/shared.lua
================================================
--
-- Copyright (c) 2023-2024 ring-0 Ltda.
--
-- Permission is hereby granted, free of charge, to any person obtaining
-- a copy of this software and associated documentation files (the
-- "Software"), to deal in the Software without restriction, including
-- without limitation the rights to use, copy, modify, merge, publish,
-- distribute, sublicense, and/or sell copies of the Software, and to
-- permit persons to whom the Software is furnished to do so, subject to
-- the following conditions:
--
-- The above copyright notice and this permission notice shall be
-- included in all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--
local thread = require("thread")
local socket = require("socket")
local inet = require("socket.inet")
local rcu = require("rcu")
local data = require("data")
local linux = require("linux")
local shared = rcu.table()
local server = inet.tcp()
server:bind(inet.localhost, 90)
server:listen()
local shouldstop = thread.shouldstop
local task = linux.task
local sock = socket.sock
local size = 1024
local function handle(session)
repeat
local request = session:receive(size)
local key, assign, value = string.match(request, "(%w+)(=*)(%w*)\n")
if key then
if assign ~= "" then
local slot
if value ~= "" then
slot = shared[key] or data.new(size)
slot:setstring(0, value)
end
shared[key] = slot
else
local value = shared[key]:getstring(0, size)
session:send(value .. "\n")
end
end
until (not key or shouldstop())
end
local function daemon()
print("starting shared...")
while (not shouldstop()) do
local ok, session = pcall(server.accept, server, sock.NONBLOCK)
if ok then
handle(session)
elseif session == "EAGAIN" then
linux.schedule(100)
end
end
print("stopping shared...")
end
return daemon
================================================
FILE: examples/spyglass.lua
================================================
--
-- SPDX-FileCopyrightText: (c) 2023-2024 Ring Zero Desenvolvimento de Software LTDA
-- SPDX-License-Identifier: MIT OR GPL-2.0-only
--
local notifier = require("notifier")
local device = require("device")
local inet = require("socket.inet")
local function info(...)
print("spyglass: " .. string.format(...))
end
local control = {
[0] = "nul", [1] = "soh", [2] = "stx", [3] = "etx", [4] = "eot", [5] = "enq",
[6] = "ack", [7] = "bel", [8] = "bs", [9] = "ht", [10] = "nl", [11] = "vt",
[12] = "np", [13] = "cr", [14] = "so", [15] = "si", [16] = "dle", [17] = "dc1",
[18] = "dc2", [19] = "dc3", [20] = "dc4", [21] = "nak", [22] = "syn", [23] = "etb",
[24] = "can", [25] = "em", [26] = "sub", [27] = "esc", [28] = "fs", [29] = "gs",
[30] = "rs", [31] = "us", [127] = "del"
}
local function printable(keysym)
return keysym >= 32 and keysym <= 126
end
local spyglass = {name = "spyglass", log = ""}
function spyglass:read()
local log = self.log
self.log = ""
local socket = self.socket
if socket and #log > 0 then
pcall(socket.send, socket, log, ip, port)
return ""
end
return log
end
local settings = {
['enable'] = function (self, enable)
local enable = enable ~= "false"
if enable and not self.notifier then
self.notifier = notifier.keyboard(self.callback)
elseif not enable and self.notifier then
self.notifier:delete()
self.notifier = nil
end
end,
['net'] = function (self, net)
local ip, port = string.match(net, "(%g+):(%d+)")
if ip then
info("enabling network support %s:%d", ip, port)
self.socket = inet.udp()
self.socket:connect(ip, port)
elseif self.socket then
info("disabling network support")
self.socket:close()
self.socket = nil
end
end
}
function spyglass:write(buf)
for k, v in string.gmatch(buf, "(%w+)=(%g+)") do
local setter = settings[k]
if setter then
setter(self, v)
end
end
end
local notify = notifier.notify
local kbd = notifier.kbd
function spyglass.callback(event, down, shift, key)
if not down and event == kbd.KEYSYM then
local keysym = key & 0xFF
local log = printable(keysym) and string.char(keysym) or
string.format("<%s>", control[keysym])
spyglass.log = spyglass.log .. log
end
return notify.OK
end
spyglass.notifier = notifier.keyboard(spyglass.callback)
spyglass.device = device.new(spyglass)
================================================
FILE: examples/systrack.lua
================================================
--
-- SPDX-FileCopyrightText: (c) 2023-2024 Ring Zero Desenvolvimento de Software LTDA
-- SPDX-License-Identifier: MIT OR GPL-2.0-only
--
local linux = require("linux")
local probe = require("probe")
local device = require("device")
local systab = require("syscall.table")
local syscalls = {"openat", "read", "write", "readv", "writev", "close"}
local s = linux.stat
local driver = {name = "systrack", mode = s.IRUGO}
local track = {}
local toggle = true
function driver:read()
local log = ""
if toggle then
for symbol, counter in pairs(track) do
log = log .. string.format("%s: %d\n", symbol, counter)
end
end
toggle = not toggle
return log
end
for _, symbol in ipairs(syscalls) do
local address = systab[symbol]
track[symbol] = 0
local function handler()
track[symbol] = track[symbol] + 1
end
probe.new(address, {pre = handler})
end
device.new(driver)
================================================
FILE: examples/tap.lua
================================================
--
-- SPDX-FileCopyrightText: (c) 2023-2024 Ring Zero Desenvolvimento de Software LTDA
-- SPDX-License-Identifier: MIT OR GPL-2.0-only
--
local device = require("device")
local raw = require("socket.raw")
local linux = require("linux")
local MTU = 1500
local s = linux.stat
local tap = {name = "tap", mode = s.IRUGO}
local socket = raw.bind()
function tap:read()
local frame = socket:receive(MTU)
local dst, src, ethtype = string.unpack(">I6I6I2", frame)
return string.format("%X\t%X\t%X\t%d\n", dst, src, ethtype, #frame)
end
device.new(tap)
================================================
FILE: examples/tcpreject/cleanup.sh
================================================
#!/bin/bash
# SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA
# SPDX-License-Identifier: MIT OR GPL-2.0-only
set -eux
lunatik stop examples/tcpreject/nf_tcpreject
nft delete table ip tcpreject
nft delete table ip6 tcpreject
ip link del veth-tcpreject
ip netns del tcpreject
echo 0 > /proc/sys/net/ipv4/ip_forward
echo 0 > /proc/sys/net/ipv6/conf/all/forwarding
================================================
FILE: examples/tcpreject/nf_tcpreject.lua
================================================
--
-- SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA
-- SPDX-License-Identifier: MIT OR GPL-2.0-only
--
-- Inject a TCP RST toward the origin for forwarded packets matching a mark.
-- Use nft to mark packets before this hook runs (priority mangle < filter).
local netfilter = require("netfilter")
local byteorder = require("byteorder")
local family = netfilter.family
local action = netfilter.action
local hooks = netfilter.inet_hooks
local priority = netfilter.ip_priority
local IP_TOTLEN = 2
local IP_SADDR = 12
local IP_DADDR = 16
local IP6_PAYLEN = 4
local IP6_SADDR = 8
local IP6_DADDR = 24
local IP6_HDRLEN = 40
local TCP_SPORT = 0
local TCP_DPORT = 2
local TCP_SEQ = 4
local TCP_ACK = 8
local TCP_DOFF = 12
local TCP_FLAGS = 13
local TCP_URGENT = 18
local TCP_HDRLEN = 20
local RST = 0x04
local ACK = 0x10
local DOFF5 = 0x50 -- data offset = 5 (20 bytes, no options)
local function swap_addrs(npkt, nframe, ihl)
local ver = npkt:getuint8(0) >> 4
if ver == 4 then
local saddr = npkt:getuint32(IP_SADDR)
local daddr = npkt:getuint32(IP_DADDR)
npkt:setuint32(IP_SADDR, daddr)
npkt:setuint32(IP_DADDR, saddr)
else
for i = 0, 3 do
local s = npkt:getuint32(IP6_SADDR + i * 4)
local d = npkt:getuint32(IP6_DADDR + i * 4)
npkt:setuint32(IP6_SADDR + i * 4, d)
npkt:setuint32(IP6_DADDR + i * 4, s)
end
end
local sport = npkt:getuint16(ihl + TCP_SPORT)
local dportn = npkt:getuint16(ihl + TCP_DPORT)
npkt:setuint16(ihl + TCP_SPORT, dportn)
npkt:setuint16(ihl + TCP_DPORT, sport)
local dst_hi = nframe:getuint32(0)
local dst_lo = nframe:getuint16(4)
local src_hi = nframe:getuint32(6)
local src_lo = nframe:getuint16(10)
nframe:setuint32(0, src_hi)
nframe:setuint16(4, src_lo)
nframe:setuint32(6, dst_hi)
nframe:setuint16(10, dst_lo)
end
local function set_rst(npkt, ihl)
local seq = byteorder.ntoh32(npkt:getuint32(ihl + TCP_SEQ))
local ackn = npkt:getuint32(ihl + TCP_ACK)
npkt:setuint32(ihl + TCP_SEQ, ackn)
npkt:setuint32(ihl + TCP_ACK, byteorder.hton32(seq + 1))
npkt:setuint8(ihl + TCP_DOFF, DOFF5)
npkt:setuint8(ihl + TCP_FLAGS, RST | ACK)
npkt:setuint16(ihl + TCP_URGENT, 0)
end
local function tcpreject(skb)
local pkt = skb:data("net")
local ver = pkt:getuint8(0) >> 4
local ihl = ver == 4 and (pkt:getuint8(0) & 0x0F) * 4 or IP6_HDRLEN
local nskb = skb:copy()
local nframe = nskb:data("mac")
local npkt = nskb:data("net")
swap_addrs(npkt, nframe, ihl)
set_rst(npkt, ihl)
local rst_len = ihl + TCP_HDRLEN
nskb:resize(rst_len)
if ver == 4 then
npkt:setuint16(IP_TOTLEN, byteorder.hton16(rst_len))
else
npkt:setuint16(IP6_PAYLEN, byteorder.hton16(TCP_HDRLEN))
end
nskb:checksum()
nskb:forward()
return action.DROP
end
netfilter.register{
hook = tcpreject,
pf = family.INET,
hooknum = hooks.FORWARD,
priority = priority.FILTER,
mark = 0x403,
}
netfilter.register{
hook = tcpreject,
pf = family.IPV6,
hooknum = hooks.FORWARD,
priority = priority.FILTER,
mark = 0x403,
}
================================================
FILE: examples/tcpreject/setup.sh
================================================
#!/bin/bash
# SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA
# SPDX-License-Identifier: MIT OR GPL-2.0-only
set -eux
NETNS=tcpreject
VETH_HOST=veth-tcpreject
VETH_NS=veth-ns
HOST_ADDR=10.99.0.1
NS_ADDR=10.99.0.2
PREFIX=10.99.0.0/24
HOST_ADDR6=fd99::1
NS_ADDR6=fd99::2
PREFIX6=fd99::/64
DNS4=8.8.8.8
DNS6=2001:4860:4860::8888
MARK=0x403
# namespace + veth pair
ip netns add $NETNS
ip link add $VETH_HOST type veth peer name $VETH_NS
ip link set $VETH_NS netns $NETNS
ip addr add $HOST_ADDR/24 dev $VETH_HOST
ip -6 addr add $HOST_ADDR6/64 dev $VETH_HOST
ip link set $VETH_HOST up
ip -n $NETNS addr add $NS_ADDR/24 dev $VETH_NS
ip -n $NETNS -6 addr add $NS_ADDR6/64 dev $VETH_NS
ip -n $NETNS link set $VETH_NS up
ip -n $NETNS link set lo up
ip -n $NETNS route add default via $HOST_ADDR
ip -n $NETNS -6 route add default via $HOST_ADDR6
# forwarding + masquerade so the namespace can reach the internet
echo 1 > /proc/sys/net/ipv4/ip_forward
echo 1 > /proc/sys/net/ipv6/conf/all/forwarding
nft add table ip tcpreject
nft add chain ip tcpreject postrouting \
{ type nat hook postrouting priority srcnat \; }
nft add rule ip tcpreject postrouting \
ip saddr $PREFIX masquerade
# mark TCP/443 at mangle priority (before the Lua FILTER hook)
nft add chain ip tcpreject forward \
{ type filter hook forward priority mangle \; }
nft add rule ip tcpreject forward \
ip daddr $DNS4 tcp dport 443 mark set $MARK
nft add table ip6 tcpreject
nft add chain ip6 tcpreject forward \
{ type filter hook forward priority mangle \; }
nft add rule ip6 tcpreject forward \
ip6 daddr $DNS6 tcp dport 443 mark set $MARK
# load the Lua hook
lunatik run examples/tcpreject/nf_tcpreject softirq
echo "setup done"
echo "test IPv4: ip netns exec $NETNS curl --connect-timeout 2 https://$DNS4"
echo "test IPv6: ip netns exec $NETNS curl --connect-timeout 2 https://[$DNS6]"
================================================
FILE: examples/xiaomi.lua
================================================
--
-- SPDX-FileCopyrightText: (c) 2025-2026 Jieming Zhou <qrsikno@gmail.com>
-- SPDX-License-Identifier: MIT OR GPL-2.0-only
--
-- Porting Xiaomi Silent Mouse's Kernel driver to work with luahid.
-- Link: https://elixir.bootlin.com/linux/v6.16.3/source/drivers/hid/hid-xiaomi.c
local hid = require("hid")
local driver = {name = "luahid_xiaomi", id_table = {{bus = 0x05, vendor = 0x2717, product = 0x5014}}}
local mi_silent_mouse_orig_rdesc_length = 87
local mi_silent_mouse_rdesc_fixed = {
0x05, 0x01, -- Usage Page (Desktop),
0x09, 0x02, -- Usage (Mouse),
0xA1, 0x01, -- Collection (Application),
0x85, 0x03, -- Report ID (3),
0x09, 0x01, -- Usage (Pointer),
0xA1, 0x00, -- Collection (Physical),
0x05, 0x09, -- Usage Page (Button),
0x19, 0x01, -- Usage Minimum (01h),
0x29, 0x05, -- X -- Usage Maximum (05h),
0x15, 0x00, -- Logical Minimum (0),
0x25, 0x01, -- Logical Maximum (1),
0x75, 0x01, -- Report Size (1),
0x95, 0x05, -- Report Count (5),
0x81, 0x02, -- Input (Variable),
0x75, 0x03, -- Report Size (3),
0x95, 0x01, -- Report Count (1),
0x81, 0x01, -- Input (Constant),
0x05, 0x01, -- Usage Page (Desktop),
0x09, 0x30, -- Usage (X),
0x09, 0x31, -- Usage (Y),
0x15, 0x81, -- Logical Minimum (-127),
0x25, 0x7F, -- Logical Maximum (127),
0x75, 0x08, -- Report Size (8),
0x95, 0x02, -- Report Count (2),
0x81, 0x06, -- Input (Variable, Relative),
0x09, 0x38, -- Usage (Wheel),
0x15, 0x81, -- Logical Minimum (-127),
0x25, 0x7F, -- Logical Maximum (127),
0x75, 0x08, -- Report Size (8),
0x95, 0x01, -- Report Count (1),
0x81, 0x06, -- Input (Variable, Relative),
0xC0, -- End Collection,
0xC0, -- End Collection,
0x06, 0x01, 0xFF, -- Usage Page (FF01h),
0x09, 0x01, -- Usage (01h),
0xA1, 0x01, -- Collection (Application),
0x85, 0x05, -- Report ID (5),
0x09, 0x05, -- Usage (05h),
0x15, 0x00, -- Logical Minimum (0),
0x26, 0xFF, 0x00, -- Logical Maximum (255),
0x75, 0x08, -- Report Size (8),
0x95, 0x04, -- Report Count (4),
0xB1, 0x02, -- Feature (Variable),
0xC0 -- End Collection
}
function driver:report_fixup(hdev, report, data)
if hdev.product == 0x5014 and #report == mi_silent_mouse_orig_rdesc_length then
print("Fixing Xiaomi Silent Mouse report descriptor")
for i = 1, #mi_silent_mouse_rdesc_fixed do
report:setbyte(i - 1, mi_silent_mouse_rdesc_fixed[i])
end
end
end
hid.register(driver)
================================================
FILE: gensymbols.sh
================================================
#!/bin/sh
# SPDX-FileCopyrightText: (c) 2023-2026 Ring Zero Desenvolvimento de Software LTDA
# SPDX-License-Identifier: MIT OR GPL-2.0-only
sed "s/.*luaconf.h.*//g" "$@" | \
${CC} -Ilua/ -D_KERNEL -DLUNATIK_GENSYMBOLS -E - | \
grep API | sed "s/.*(\(\w*\))\s*(.*/EXPORT_SYMBOL(\1);/g"
================================================
FILE: include/assert.h
================================================
/*
* SPDX-FileCopyrightText: (c) 2023-2024 Ring Zero Desenvolvimento de Software LTDA
* SPDX-License-Identifier: MIT OR GPL-2.0-only
*/
#ifndef lunatik_assert_h
#define lunatik_assert_h
/* placeholder */
#endif
================================================
FILE: include/ctype.h
================================================
/*
* SPDX-FileCopyrightText: (c) 2023-2024 Ring Zero Desenvolvimento de Software LTDA
* SPDX-License-Identifier: MIT OR GPL-2.0-only
*/
#ifndef lunatik_ctype_h
#define lunatik_ctype_h
#include <linux/ctype.h>
#endif
================================================
FILE: include/errno.h
================================================
/*
* SPDX-FileCopyrightText: (c) 2023-2026 Ring Zero Desenvolvimento de Software LTDA
* SPDX-License-Identifier: MIT OR GPL-2.0-only
*/
#ifndef lunatik_errno_h
#define lunatik_errno_h
static __maybe_unused int errno;
#endif
================================================
FILE: include/float.h
================================================
/*
* SPDX-FileCopyrightText: (c) 2023-2024 Ring Zero Desenvolvimento de Software LTDA
* SPDX-License-Identifier: MIT OR GPL-2.0-only
*/
#ifndef lunatik_float_h
#define lunatik_float_h
/* placeholder */
#endif
================================================
FILE: include/klibc/diverr.h
================================================
/*
* SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA
* SPDX-License-Identifier: MIT OR GPL-2.0-only
*/
#ifndef lunatik_klibc_diverr_h
#define lunatik_klibc_diverr_h
#include <linux/types.h>
static __inline__ void __divide_error(void) {}
#endif
================================================
FILE: include/limits.h
================================================
/*
* SPDX-FileCopyrightText: (c) 2023-2026 Ring Zero Desenvolvimento de Software LTDA
* SPDX-License-Identifier: MIT OR GPL-2.0-only
*/
#ifndef lunatik_limits_h
#define lunatik_limits_h
#include <linux/limits.h>
#define UCHAR_MAX (255)
#define CHAR_BIT (8)
/**
* vdso/limits.h defines INT_MAX as ((int)(~0U >> 1)) which breaks
* "#if MAX_CNST/(MAXARG_vC + 1) > MAXARG_Ax" on lparser.c
* see https://gcc.gnu.org/onlinedocs/cpp/If.html
**/
#undef INT_MAX
#define INT_MAX (2147483647)
#endif
================================================
FILE: include/locale.h
================================================
/*
* SPDX-FileCopyrightText: (c) 2023-2024 Ring Zero Desenvolvimento de Software LTDA
* SPDX-License-Identifier: MIT OR GPL-2.0-only
*/
#ifndef lunatik_locale_h
#define lunatik_locale_h
/* placeholder */
#endif
================================================
FILE: include/math.h
================================================
/*
* SPDX-FileCopyrightText: (c) 2023-2024 Ring Zero Desenvolvimento de Software LTDA
* SPDX-License-Identifier: MIT OR GPL-2.0-only
*/
#ifndef lunatik_math_h
#define lunatik_math_h
/* placeholder */
#endif
================================================
FILE: include/setjmp.h
================================================
/*
* SPDX-FileCopyrightText: (c) 2023-2024 Ring Zero Desenvolvimento de Software LTDA
* SPDX-License-Identifier: MIT OR GPL-2.0-only
*/
#ifndef lunatik_setjmp_h
#define lunatik_setjmp_h
#include <linux/types.h>
#include <klibc/archconfig.h>
#include <klibc/archsetjmp.h>
extern int setjmp(jmp_buf);
extern void __attribute__((noreturn)) longjmp(jmp_buf, int);
#endif
================================================
FILE: include/stdarg.h
================================================
/*
* SPDX-FileCopyrightText: (c) 2023-2024 Ring Zero Desenvolvimento de Software LTDA
* SPDX-License-Identifier: MIT OR GPL-2.0-only
*/
#ifndef lunatik_stdarg_h
#define lunatik_stdarg_h
#include <linux/stdarg.h>
#endif
================================================
FILE: include/stddef.h
================================================
/*
* SPDX-FileCopyrightText: (c) 2023-2024 Ring Zero Desenvolvimento de Software LTDA
* SPDX-License-Identifier: MIT OR GPL-2.0-only
*/
#ifndef lunatik_stddef_h
#define lunatik_stddef_h
#include <linux/stddef.h>
#endif
================================================
FILE: include/stdint.h
================================================
/*
* SPDX-FileCopyrightText: (c) 2023-2026 Ring Zero Desenvolvimento de Software LTDA
* SPDX-License-Identifier: MIT OR GPL-2.0-only
*/
#ifndef lunatik_stdint_h
#define lunatik_stdint_h
#include <linux/types.h>
#if BITS_PER_LONG == 32
uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t *rem);
int64_t __divdi3(int64_t num, int64_t den);
uint64_t __udivdi3(uint64_t num, uint64_t den);
int64_t __moddi3(int64_t num, int64_t den);
uint64_t __umoddi3(uint64_t num, uint64_t den);
#endif /* BITS_PER_LONG = 32 */
#endif
================================================
FILE: include/stdio.h
================================================
/*
* SPDX-FileCopyrightText: (c) 2023-2026 Ring Zero Desenvolvimento de Software LTDA
* SPDX-License-Identifier: MIT OR GPL-2.0-only
*/
/* Kernel-space FILE implementation for lua/liolib.c, backed by VFS */
#ifndef lunatik_stdio_h
#define lunatik_stdio_h
#include <errno.h>
#include <linux/printk.h>
#include <linux/fs.h>
#include <linux/slab.h>
#define BUFSIZE (512)
#define EOF (-1)
#define feof(f) ((f)->eof)
#define ferror(f) ((f)->err)
#define clearerr(f) ((f)->eof = 0, (f)->err = 0)
#define fflush(f) (0)
#define bufempty(f) ((f)->bufpos >= (f)->buflen && unlikely(fill(f) == 0))
#define l_getc(f) getc(f)
#define l_lockfile(f) ((void)(f))
#define l_unlockfile(f) ((void)(f))
#define l_fseek(f, o, w) seek((f), (o), (w))
#define l_ftell(f) ((f)->pos)
#define l_seeknum loff_t
typedef struct {
struct file *filp;
loff_t pos;
int bufpos;
int buflen;
int err;
int eof;
int unget; /* -1 = empty, 0-255 = pushed-back char */
char buf[BUFSIZE];
} FILE;
static inline FILE *fopen(const char *path, const char *mode)
{
if (unlikely(!mode))
return NULL;
int flags;
switch (mode[0]) {
case 'r':
flags = (mode[1] == '+') ? O_RDWR : O_RDONLY;
break;
case 'w':
flags = (mode[1] == '+') ? O_RDWR | O_CREAT | O_TRUNC
: O_WRONLY | O_CREAT | O_TRUNC;
break;
case 'a':
flags = (mode[1] == '+') ? O_RDWR | O_CREAT | O_APPEND
: O_WRONLY | O_CREAT | O_APPEND;
break;
default:
return NULL;
}
FILE *f = kzalloc(sizeof(FILE), GFP_KERNEL);
if (unlikely(!f))
return NULL;
f->filp = filp_open(path, flags, 0666);
if (unlikely(IS_ERR(f->filp))) {
kfree(f);
return NULL;
}
f->unget = -1;
return f;
}
static inline int fclose(FILE *f)
{
int ret = filp_close(f->filp, NULL);
kfree(f);
return ret ? EOF : 0;
}
static inline int fill(FILE *f)
{
ssize_t n = kernel_read(f->filp, f->buf, BUFSIZE, &f->pos);
f->bufpos = 0;
if (unlikely(n <= 0)) {
f->eof = (n == 0);
f->err = (n < 0);
f->buflen = 0;
return 0;
}
f->buflen = (int)n;
return (int)n;
}
static inline int getc(FILE *f)
{
if (unlikely(f->unget >= 0)) {
int c = f->unget;
f->unget = -1;
return c;
}
return bufempty(f) ? EOF : (unsigned char)f->buf[f->bufpos++];
}
static inline int ungetc(int c, FILE *f)
{
if (unlikely(c == EOF))
return EOF;
f->eof = 0;
f->unget = c;
return c;
}
static inline size_t fread(void *ptr, size_t sz, size_t nmemb, FILE *f)
{
size_t total;
if (unlikely(sz == 0 || (total = sz * nmemb) == 0))
return 0;
size_t done = 0;
char *dst = (char *)ptr;
if (unlikely(f->unget >= 0)) {
dst[done++] = (char)f->unget;
f->unget = -1;
}
while (done < total) {
int avail = f->buflen - f->bufpos;
if (unlikely(!(avail || (avail = fill(f)))))
break;
int n = (int)min_t(size_t, avail, total - done);
memcpy(dst + done, f->buf + f->bufpos, n);
f->bufpos += n;
done += n;
}
return done / sz;
}
static inline size_t fwrite(const void *ptr, size_t sz, size_t nmemb, FILE *f)
{
size_t total;
if (unlikely(sz == 0 || (total = sz * nmemb) == 0))
return 0;
ssize_t n = kernel_write(f->filp, ptr, total, &f->pos);
if (unlikely(n < 0)) {
f->err = 1;
return 0;
}
return (size_t)n / sz;
}
static inline int seek(FILE *f, loff_t off, int whence)
{
loff_t ret = vfs_llseek(f->filp, off, whence);
if (unlikely(ret < 0)) {
f->err = 1;
return -1;
}
f->pos = ret;
f->bufpos = 0;
f->buflen = 0;
f->unget = -1;
return 0;
}
#endif
================================================
FILE: include/stdlib.h
================================================
/*
* SPDX-FileCopyrightText: (c) 2023-2026 Ring Zero Desenvolvimento de Software LTDA
* SPDX-License-Identifier: MIT OR GPL-2.0-only
*/
#ifndef lunatik_stdlib_h
#define lunatik_stdlib_h
#include <linux/slab.h>
#define abort() BUG()
#define free(a) kfree((a))
#define realloc(a,b) krealloc((a),(b),GFP_KERNEL)
static inline char *getenv(const char *name)
{
(void)name;
return NULL;
}
#endif
================================================
FILE: include/string.h
================================================
/*
* SPDX-FileCopyrightText: (c) 2023-2026 Ring Zero Desenvolvimento de Software LTDA
* SPDX-License-Identifier: MIT OR GPL-2.0-only
*/
#ifndef lunatik_string_h
#define lunatik_string_h
#include <linux/string.h>
#define strcoll(l,r) strcmp((l),(r))
#define strerror(n) "I/O error"
#if defined(CONFIG_FORTIFY_SOURCE) && !defined(unsafe_memcpy)
#define unsafe_memcpy(dst, src, bytes, justification) __builtin_memcpy(dst, src, bytes)
#endif
#endif
================================================
FILE: include/time.h
================================================
/*
* SPDX-FileCopyrightText: (c) 2023-2024 Ring Zero Desenvolvimento de Software LTDA
* SPDX-License-Identifier: MIT OR GPL-2.0-only
*/
#ifndef lunatik_time_h
#define lunatik_time_h
/* placeholder */
#endif
================================================
FILE: lib/Kbuild
================================================
# SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA
# SPDX-License-Identifier: MIT OR GPL-2.0-only
obj-$(CONFIG_LUNATIK_DEVICE) += luadevice.o
obj-$(CONFIG_LUNATIK_LINUX) += lualinux.o
obj-$(CONFIG_LUNATIK_NOTIFIER) += luanotifier.o
obj-$(CONFIG_LUNATIK_SOCKET) += luasocket.o
obj-$(CONFIG_LUNATIK_RCU) += luarcu.o
obj-$(CONFIG_LUNATIK_THREAD) += luathread.o
obj-$(CONFIG_LUNATIK_FIB) += luafib.o
obj-$(CONFIG_LUNATIK_DATA) += luadata.o
obj-$(CONFIG_LUNATIK_PROBE) += luaprobe.o
obj-$(CONFIG_LUNATIK_SYSCALL) += luasyscall.o
obj-$(CONFIG_LUNATIK_XDP) += luaxdp.o
obj-$(CONFIG_LUNATIK_FIFO) += luafifo.o
obj-$(CONFIG_LUNATIK_NETFILTER) += luanetfilter.o
obj-$(CONFIG_LUNATIK_COMPLETION) += luacompletion.o
obj-$(CONFIG_LUNATIK_CRYPTO) += luacrypto.o
luacrypto-objs := luacrypto_shash.o luacrypto_skcipher.o luacrypto_aead.o \
luacrypto_rng.o luacrypto_comp.o luacrypto_core.o
obj-$(CONFIG_LUNATIK_CPU) += luacpu.o
obj-$(CONFIG_LUNATIK_HID) += luahid.o
obj-$(CONFIG_LUNATIK_SIGNAL) += luasignal.o
obj-$(CONFIG_LUNATIK_BYTEORDER) += luabyteorder.o
obj-$(CONFIG_LUNATIK_DARKEN) += luadarken.o
obj-$(CONFIG_LUNATIK_SKB) += luaskb.o
================================================
FILE: lib/crypto/hkdf.lua
================================================
--
-- SPDX-FileCopyrightText: (c) 2025-2026 jperon <cataclop@hotmail.com>
-- SPDX-License-Identifier: MIT OR GPL-2.0-only
--
--- HMAC-based Extract-and-Expand Key Derivation Function (HKDF) based on RFC 5869.
-- This module provides functions to perform HKDF operations, utilizing the
-- underlying `crypto` C module for HMAC calculations.
-- @classmod crypto.hkdf
local shash = require("crypto").shash
local char, rep, sub = string.char, string.rep, string.sub
--- HKDF operations.
-- This table provides the `new` method to create HKDF instances and also
-- serves as the prototype for these instances.
local HKDF = {}
--- Closes the HKDF instance and releases the underlying HMAC transform.
-- This method is also called by the garbage collector.
-- @function HKDF:close
function HKDF:close()
self.tfm:__close()
end
HKDF.__close = HKDF.close
HKDF.__index = HKDF
function HKDF.__len(self)
return self.tfm:digestsize()
end
--- Creates a new HKDF instance for a given hash algorithm.
-- @function HKDF.new
-- @tparam string alg base hash algorithm name (e.g., "sha256", "sha512").
-- The "hmac(" prefix will be added automatically.
-- @treturn HKDF An HKDF instance table with methods for key derivation.
-- @usage local hkdf_sha256 = require("crypto.hkdf").new("sha256")
function HKDF.new(alg)
local hmac = setmetatable({}, HKDF)
hmac.tfm = shash("hmac(" .. alg .. ")")
hmac.salt = rep("\0", #hmac)
return hmac
end
--- Performs an HMAC calculation using the instance's algorithm.
-- @tparam string key HMAC key.
-- @tparam string data data to hash.
-- @treturn string HMAC digest.
function HKDF:hmac(key, data)
self.tfm:setkey(key)
return self.tfm:digest(data)
end
--- Performs the HKDF Extract step.
-- @function HKDF:extract
-- @tparam[opt] string salt Optional salt value. If nil or not provided, a salt of `hash_len` zeros is used.
-- @tparam string ikm Input Keying Material.
-- @treturn string Pseudorandom Key (PRK).
function HKDF:extract(salt, ikm)
return self:hmac((salt or self.salt), ikm)
end
--- Performs the HKDF Expand step.
-- @function HKDF:expand
-- @tparam string prk Pseudorandom Key.
-- @tparam[opt] string info Optional context and application-specific information. Defaults to an empty string if nil.
-- @tparam number length desired length in bytes for the Output Keying Material (OKM).
-- @treturn string Output Keying Material of the specified `length`.
function HKDF:expand(prk, info, length)
info = info or ""
local hash_len = #self
local n = length / hash_len
n = (n * hash_len == length) and n or n + 1
local okm, t = "", ""
for i = 1, n do
t = self:hmac(prk, t .. info .. char(i))
okm = okm .. t
end
return sub(okm, 1, length)
end
--- Performs the full HKDF (Extract and Expand) operation.
-- @function HKDF:hkdf
-- @tparam[opt] string salt Optional salt value.
-- @tparam string ikm Input Keying Material.
-- @tparam[opt] string info Optional context and application-specific information.
-- @tparam number length desired length in bytes for the Output Keying Material.
-- @treturn string Output Keying Material.
function HKDF:hkdf(salt, ikm, info, length)
return self:expand(self:extract(salt, ikm), info, length)
end
return HKDF
================================================
FILE: lib/lighten.lua
================================================
--
-- SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA
-- SPDX-License-Identifier: MIT OR GPL-2.0-only
--
--- Encrypted Lua script support (AES-256-CTR).
-- This module provides functions to run encrypted Lua scripts
-- using the `darken` C module.
-- @module lighten
local light = require("light")
local darken = require("darken")
local hex2bin = require("util").hex2bin
local lighten = {}
--- Decrypts and executes an encrypted Lua script.
-- @tparam string ct Hex-encoded ciphertext.
-- @tparam string iv Hex-encoded 16-byte IV.
-- @return The return values of the decrypted script.
function lighten.run(ct, iv)
return darken.run(hex2bin(ct), hex2bin(iv), hex2bin(light))
end
return lighten
================================================
FILE: lib/luabyteorder.c
================================================
/*
* SPDX-FileCopyrightText: (c) 2024-2026 Mohammad Shehar Yaar Tausif <sheharyaar48@gmail.com>
* SPDX-License-Identifier: MIT OR GPL-2.0-only
*/
#include <linux/module.h>
#include <linux/byteorder/generic.h>
#include <lunatik.h>
/***
* Byte Order Conversion
* @module byteorder
*/
#define LUABYTEORDER_BYTESWAPPER(swapper, T) \
static int luabyteorder_##swapper(lua_State *L) \
{ \
T x = (T)luaL_checkinteger(L, 1); \
lua_pushinteger(L, (lua_Integer)swapper(x)); \
return 1; \
}
/***
* Converts a 16-bit integer from host byte order to big-endian byte order.
* @function htobe16
* @tparam integer num16-bit integer in host byte order.
* @treturn integer value in big-endian byte order.
*/
LUABYTEORDER_BYTESWAPPER(cpu_to_be16, u16);
/***
* Converts a 32-bit integer from host byte order to big-endian byte order.
* @function htobe32
* @tparam integer num32-bit integer in host byte order.
* @treturn integer value in big-endian byte order.
*/
LUABYTEORDER_BYTESWAPPER(cpu_to_be32, u32);
/***
* Converts a 16-bit integer from host byte order to little-endian byte order.
* @function htole16
* @tparam integer num16-bit integer in host byte order.
* @treturn integer value in little-endian byte order.
*/
LUABYTEORDER_BYTESWAPPER(cpu_to_le16, u16);
/***
* Converts a 32-bit integer from host byte order to little-endian byte order.
* @function htole32
* @tparam integer num32-bit integer in host byte order.
* @treturn integer value in little-endian byte order.
*/
LUABYTEORDER_BYTESWAPPER(cpu_to_le32, u32);
/***
* Converts a 16-bit integer from big-endian byte order to host byte order.
* @function be16toh
* @tparam integer num16-bit integer in big-endian byte order.
* @treturn integer value in host byte order.
*/
LUABYTEORDER_BYTESWAPPER(be16_to_cpu, u16);
/***
* Converts a 32-bit integer from big-endian byte order to host byte order.
* @function be32toh
* @tparam integer num32-bit integer in big-endian byte order.
* @treturn integer value in host byte order.
*/
LUABYTEORDER_BYTESWAPPER(be32_to_cpu, u32);
/***
* Converts a 16-bit integer from little-endian byte order to host byte order.
* @function le16toh
* @tparam integer num16-bit integer in little-endian byte order.
* @treturn integer value in host byte order.
*/
LUABYTEORDER_BYTESWAPPER(le16_to_cpu, u16);
/***
* Converts a 32-bit integer from little-endian byte order to host byte order.
* @function le32toh
* @tparam integer num32-bit integer in little-endian byte order.
* @treturn integer value in host byte order.
*/
LUABYTEORDER_BYTESWAPPER(le32_to_cpu, u32);
/***
* Converts a 64-bit integer from host byte order to big-endian byte order.
* @function htobe64
* @tparam integer num64-bit integer in host byte order.
* @treturn integer value in big-endian byte order.
*/
LUABYTEORDER_BYTESWAPPER(cpu_to_be64, u64);
/***
* Converts a 64-bit integer from host byte order to little-endian byte order.
* @function htole64
* @tparam integer num64-bit integer in host byte order.
* @treturn integer value in little-endian byte order.
*/
LUABYTEORDER_BYTESWAPPER(cpu_to_le64, u64);
/***
* Converts a 64-bit integer from big-endian byte order to host byte order.
* @function be64toh
* @tparam integer num64-bit integer in big-endian byte order.
* @treturn integer value in host byte order.
*/
LUABYTEORDER_BYTESWAPPER(be64_to_cpu, u64);
/***
* Converts a 64-bit integer from little-endian byte order to host byte order.
* @function le64toh
* @tparam integer num64-bit integer in little-endian byte order.
* @treturn integer value in host byte order.
*/
LUABYTEORDER_BYTESWAPPER(le64_to_cpu, u64);
static const luaL_Reg luabyteorder_lib[] = {
/***
* Converts a 16-bit integer from network (big-endian) byte order to host byte order.
* @function ntoh16
* @tparam integer num16-bit integer in network byte order.
* @treturn integer value in host byte order.
*/
{"ntoh16", luabyteorder_be16_to_cpu},
/***
* Converts a 32-bit integer from network (big-endian) byte order to host byte order.
* @function ntoh32
* @tparam integer num32-bit integer in network byte order.
* @treturn integer value in host byte order.
*/
{"ntoh32", luabyteorder_be32_to_cpu},
/***
* Converts a 16-bit integer from host byte order to network (big-endian) byte order.
* @function hton16
* @tparam integer num16-bit integer in host byte order.
* @treturn integer value in network byte order.
*/
{"hton16", luabyteorder_cpu_to_be16},
/***
* Converts a 32-bit integer from host byte order to network (big-endian) byte order.
* @function hton32
* @tparam integer num32-bit integer in host byte order.
* @treturn integer value in network byte order.
*/
{"hton32", luabyteorder_cpu_to_be32},
{"htobe16", luabyteorder_cpu_to_be16},
{"htobe32", luabyteorder_cpu_to_be32},
{"htole16", luabyteorder_cpu_to_le16},
{"htole32", luabyteorder_cpu_to_le32},
{"be16toh", luabyteorder_be16_to_cpu},
{"be32toh", luabyteorder_be32_to_cpu},
{"le16toh", luabyteorder_le16_to_cpu},
{"le32toh", luabyteorder_le32_to_cpu},
/***
* Converts a 64-bit integer from network (big-endian) byte order to host byte order.
* @function ntoh64
* @tparam integer num64-bit integer in network byte order.
* @treturn integer value in host byte order.
*/
{"ntoh64", luabyteorder_be64_to_cpu},
/***
* Converts a 64-bit integer from host byte order to network (big-endian) byte order.
* @function hton64
* @tparam integer num64-bit integer in host byte order.
* @treturn integer value in network byte order.
*/
{"hton64", luabyteorder_cpu_to_be64},
{"htobe64", luabyteorder_cpu_to_be64},
{"htole64", luabyteorder_cpu_to_le64},
{"be64toh", luabyteorder_be64_to_cpu},
{"le64toh", luabyteorder_le64_to_cpu},
{NULL, NULL}
};
LUNATIK_NEWLIB(byteorder, luabyteorder_lib, NULL, NULL);
static int __init luabyteorder_init(void)
{
return 0;
}
static void __exit luabyteorder_exit(void)
{
}
module_init(luabyteorder_init);
module_exit(luabyteorder_exit);
MODULE_LICENSE("Dual MIT/GPL");
MODULE_AUTHOR("Mohammad Shehar Yaar Tausif <sheharyaar48@gmail.com>");
================================================
FILE: lib/luacompletion.c
================================================
/*
* SPDX-FileCopyrightText: (c) 2023-2025 Ring Zero Desenvolvimento de Software LTDA
* SPDX-License-Identifier: MIT OR GPL-2.0-only
*/
/***
* Lua bindings for kernel completion mechanisms.
* This library allows Lua scripts to create, signal, and wait on
* kernel completion objects.
*
* Task completion is a synchronization mechanism used to coordinate the
* execution of multiple threads. It allows threads to wait for a specific
* event to occur before proceeding, ensuring certain tasks are complete.
*
* @module completion
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/completion.h>
#include <linux/sched.h>
#include <lunatik.h>
LUNATIK_OBJECTCHECKER(luacompletion_check, struct completion *);
/***
* Signals a completion.
* This wakes up one task waiting on this completion object.
* Corresponds to the kernel's `complete()` function.
* @function complete
* @treturn nil
* @usage
* -- Assuming 'c' is a completion object returned by completion.new()
* c:complete()
* @see completion.new
*/
static int luacompletion_complete(lua_State *L)
{
struct completion *completion = luacompletion_check(L, 1);
complete(completion);
return 0;
}
/***
* Waits for a completion to be signaled.
* This function will block the current Lua runtime until the completion
* is signaled, an optional timeout occurs, or the wait is interrupted.
* The Lunatik runtime invoking this method must be sleepable.
* Corresponds to the kernel's `wait_for_completion_interruptible_timeout()`.
*
* @function wait
* @tparam[opt] integer timeout Optional timeout in milliseconds. If omitted or set to `MAX_SCHEDULE_TIMEOUT` (a large kernel-defined constant), waits indefinitely.
* @treturn boolean `true` if the completion was signaled successfully before timeout or interruption.
* @treturn nil,string `nil` and an error message if the wait did not complete successfully. The message will be one of:
* - `"timeout"`: The specified timeout elapsed.
* - `"interrupt"`: The waiting task was interrupted by a signal (e.g., `thread.stop()`).
* If the wait fails for other kernel internal reasons, the C code might push `"unknown"`, though typical documented returns are for timeout and interrupt.
* - `"unknown"`: An unexpected error occurred during the wait.
* @usage
* -- Assuming 'c' is a completion object
* local success, err_msg = c:wait(1000) -- Wait for up to 1 second
* if success then
* print("Completion received!")
* else
* print("Wait failed: " .. err_msg)
* end
* @see completion.new
*/
static int luacompletion_wait(lua_State *L)
{
struct completion *completion = luacompletion_check(L, 1);
lua_Integer timeout = luaL_optinteger(L, 2, MAX_SCHEDULE_TIMEOUT);
unsigned long timeout_jiffies = msecs_to_jiffies((unsigned long)timeout);
long ret;
lunatik_checkruntime(L, LUNATIK_OPT_NONE);
ret = wait_for_completion_interruptible_timeout(completion, timeout_jiffies);
if (ret > 0) {
lua_pushboolean(L, true);
return 1;
}
lua_pushnil(L);
switch (ret) {
case 0:
lua_pushliteral(L, "timeout");
break;
case -ERESTARTSYS:
lua_pushliteral(L, "interrupt");
break;
default:
lua_pushliteral(L, "unknown");
break;
}
return 2;
}
static int luacompletion_new(lua_State *L);
static const luaL_Reg luacompletion_lib[] = {
{"new", luacompletion_new},
{NULL, NULL}
};
static const luaL_Reg luacompletion_mt[] = {
{"__gc", lunatik_deleteobject},
{"complete", luacompletion_complete},
{"wait", luacompletion_wait},
{NULL, NULL}
};
static const lunatik_class_t luacompletion_class = {
.name = "completion",
.methods = luacompletion_mt,
.opt = LUNATIK_OPT_SOFTIRQ,
};
/***
* Creates a new kernel completion object.
* Initializes a `struct completion` and returns it wrapped as a Lua userdata
* object of type `completion`.
* @function new
* @treturn completion A new completion object.
* @usage
* local c = completion.new()
* @within completion
*/
static int luacompletion_new(lua_State *L)
{
lunatik_object_t *object = lunatik_newobject(L, &luacompletion_class, sizeof(struct completion), LUNATIK_OPT_NONE);
struct completion *completion = (struct completion *)object->private;
init_completion(completion);
return 1;
}
LUNATIK_CLASSES(completion, &luacompletion_class);
LUNATIK_NEWLIB(completion, luacompletion_lib, luacompletion_classes, NULL);
static int __init luacompletion_init(void)
{
return 0;
}
static void __exit luacompletion_exit(void)
{
}
module_init(luacompletion_init);
module_exit(luacompletion_exit);
MODULE_LICENSE("Dual MIT/GPL");
MODULE_AUTHOR("Savio Sena <savio.sena@gmail.com>");
================================================
FILE: lib/luacpu.c
================================================
/*
* SPDX-FileCopyrightText: (c) 2025 Enderson Maia <endersonmaia@gmail.com
* SPDX-License-Identifier: MIT OR GPL-2.0-only
*/
/***
* Lua interface to Linux CPU abstractions.
* @module cpu
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/cpumask.h>
#include <linux/kernel_stat.h>
#include <lunatik.h>
#define LUACPU_NUM(name) \
static int luacpu_num_##name(lua_State *L) \
{ \
lua_pushinteger(L, (lua_Integer)num_##name##_cpus()); \
return 1; \
}
/***
* @function num_possible
* @treturn integer number of possible CPUs
*/
LUACPU_NUM(possible)
/***
* @function num_present
* @treturn integer number of present CPUs
*/
LUACPU_NUM(present)
/***
* @function num_online
* @treturn integer number of online CPUs
*/
LUACPU_NUM(online)
#define luacpu_setstat(L, idx, kcs, name, NAME) \
do { \
lua_pushinteger(L, (lua_Integer)kcs.cpustat[CPUTIME_##NAME]); \
lua_setfield(L, idx - 1, #name); \
} while (0)
/***
* Returns CPU time statistics for a given CPU.
* @function stats
* @tparam integer cpu CPU number (0-based)
* @treturn table fields: `user`, `nice`, `system`, `idle`, `iowait`, `irq`,
* `softirq`, `steal`, `guest`, `guest_nice`, `forceidle` (if CONFIG_SCHED_CORE)
* @raise if CPU is offline
*/
static int luacpu_stats(lua_State *L)
{
unsigned int cpu = luaL_checkinteger(L, 1);
struct kernel_cpustat kcs;
luaL_argcheck(L, cpu_online(cpu), 1, "CPU is offline");
kcpustat_cpu_fetch(&kcs, cpu);
lua_createtable(L, 0, NR_STATS);
luacpu_setstat(L, -1, kcs, user, USER);
luacpu_setstat(L, -1, kcs, nice, NICE);
luacpu_setstat(L, -1, kcs, system, SYSTEM);
luacpu_setstat(L, -1, kcs, idle, IDLE);
luacpu_setstat(L, -1, kcs, iowait, IOWAIT);
luacpu_setstat(L, -1, kcs, irq, IRQ);
luacpu_setstat(L, -1, kcs, softirq, SOFTIRQ);
luacpu_setstat(L, -1, kcs, steal, STEAL);
luacpu_setstat(L, -1, kcs, guest, GUEST);
luacpu_setstat(L, -1, kcs, guest_nice, GUEST_NICE);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) && defined(CONFIG_SCHED_CORE)
luacpu_setstat(L, -1, kcs, forceidle, FORCEIDLE);
#endif
return 1;
}
#define LUACPU_FOREACH(name) \
static int luacpu_foreach_##name(lua_State *L) \
{ \
unsigned int cpu; \
luaL_checktype(L, 1, LUA_TFUNCTION); \
for_each_##name##_cpu(cpu) { \
lua_pushvalue(L, 1); \
lua_pushinteger(L, cpu); \
lua_call(L, 1, 0); \
} \
return 0; \
}
/***
* Calls a function for each possible CPU.
* @function foreach_possible
* @tparam function callback called with the CPU number
*/
LUACPU_FOREACH(possible)
/***
* Calls a function for each present CPU.
* @function foreach_present
* @tparam function callback called with the CPU number
*/
LUACPU_FOREACH(present)
/***
* Calls a function for each online CPU.
* @function foreach_online
* @tparam function callback called with the CPU number
*/
LUACPU_FOREACH(online)
static const luaL_Reg luacpu_lib[] = {
{"num_possible", luacpu_num_possible},
{"num_present", luacpu_num_present},
{"num_online", luacpu_num_online},
{"stats", luacpu_stats},
{"foreach_possible", luacpu_foreach_possible},
{"foreach_present", luacpu_foreach_present},
{"foreach_online", luacpu_foreach_online},
{NULL, NULL}
};
LUNATIK_NEWLIB(cpu, luacpu_lib, NULL, NULL);
static int __init luacpu_init(void)
{
return 0;
}
static void __exit luacpu_exit(void)
{
}
module_init(luacpu_init);
module_exit(luacpu_exit);
MODULE_LICENSE("Dual MIT/GPL");
MODULE_AUTHOR("Enderson Maia <endersonmaia@gmail.com>");
MODULE_DESCRIPTION("Lunatik interface to Linux's CPU abstractions.");
================================================
FILE: lib/luacrypto.h
================================================
/*
* SPDX-FileCopyrightText: (c) 2025-2026 jperon <cataclop@hotmail.com>
* SPDX-License-Identifier: MIT OR GPL-2.0-only
*/
#ifndef _LUACRYPTO_H
#define _LUACRYPTO_H
#include <linux/err.h>
#include <linux/version.h>
#include <lunatik.h>
#define LUACRYPTO_NEW(name, T, alloc, class) \
int luacrypto_##name##_new(lua_State *L) \
{ \
const char *algname = luaL_checkstring(L, 1); \
T *tfm = alloc(algname, 0, 0); \
if (IS_ERR(tfm)) \
lunatik_throw(L, PTR_ERR(tfm)); \
lunatik_object_t *object = lunatik_newobject(L, &class, 0, LUNATIK_OPT_NONE); \
object->private = tfm; \
return 1; \
}
#define LUACRYPTO_RELEASER(name, T, obj_free) \
static void luacrypto_##name##_release(void *private) \
{ \
T *obj = (T *)private; \
if (obj) \
obj_free(obj); \
}
extern const lunatik_class_t luacrypto_shash_class;
extern const lunatik_class_t luacrypto_skcipher_class;
extern const lunatik_class_t luacrypto_aead_class;
extern const lunatik_class_t luacrypto_rng_class;
int luacrypto_shash_new(lua_State *L);
int luacrypto_skcipher_new(lua_State *L);
int luacrypto_aead_new(lua_State *L);
int luacrypto_rng_new(lua_State *L);
#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 15, 0))
extern const lunatik_class_t luacrypto_comp_class;
int luacrypto_comp_new(lua_State *L);
#endif
#endif /* _LUACRYPTO_H */
================================================
FILE: lib/luacrypto_aead.c
================================================
/*
* SPDX-FileCopyrightText: (c) 2025-2026 jperon <cataclop@hotmail.com>
* SPDX-License-Identifier: MIT OR GPL-2.0-only
*/
/***
* Lua interface to AEAD (Authenticated Encryption with Associated Data) ciphers.
* @classmod crypto_aead
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <crypto/aead.h>
#include <linux/err.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include "luacrypto.h"
LUNATIK_PRIVATECHECKER(luacrypto_aead_check, struct crypto_aead *);
LUACRYPTO_RELEASER(aead, struct crypto_aead, crypto_free_aead);
/***
* Sets the cipher key.
* @function setkey
* @tparam string key
* @raise on invalid key length or algorithm error
*/
static int luacrypto_aead_setkey(lua_State *L)
{
struct crypto_aead *tfm = luacrypto_aead_check(L, 1);
size_t keylen;
const char *key = luaL_checklstring(L, 2, &keylen);
lunatik_try(L, crypto_aead_setkey, tfm, key, keylen);
return 0;
}
/***
* Sets the authentication tag size.
* @function setauthsize
* @tparam integer tagsize tag size in bytes
* @raise on unsupported size
*/
static int luacrypto_aead_setauthsize(lua_State *L)
{
struct crypto_aead *tfm = luacrypto_aead_check(L, 1);
unsigned int tagsize = (unsigned int)lunatik_checkinteger(L, 2, 1, UINT_MAX);
lunatik_try(L, crypto_aead_setauthsize, tfm, tagsize);
return 0;
}
/***
* Returns the required IV size in bytes.
* @function ivsize
* @treturn integer
*/
static int luacrypto_aead_ivsize(lua_State *L)
{
struct crypto_aead *tfm = luacrypto_aead_check(L, 1);
lua_pushinteger(L, crypto_aead_ivsize(tfm));
return 1;
}
/***
* Returns the authentication tag size in bytes.
* @function authsize
* @treturn integer
*/
static int luacrypto_aead_authsize(lua_State *L)
{
struct crypto_aead *tfm = luacrypto_aead_check(L, 1);
lua_pushinteger(L, crypto_aead_authsize(tfm));
return 1;
}
typedef struct luacrypto_aead_request_s {
struct scatterlist sg;
struct aead_request *aead;
const char *data;
const char *aad;
u8 *iv;
size_t aad_len;
size_t crypt_len;
size_t authsize;
} luacrypto_aead_request_t;
static inline void luacrypto_aead_newrequest(lua_State *L, luacrypto_aead_request_t *request)
{
memset(request, 0, sizeof(luacrypto_aead_request_t));
struct crypto_aead *tfm = luacrypto_aead_check(L, 1);
size_t iv_len;
const char *iv = luaL_checklstring(L, 2, &iv_len);
if (iv_len != crypto_aead_ivsize(tfm))
lunatik_throw(L, -EINVAL);
request->data = luaL_checklstring(L, 3, &request->crypt_len);
request->aad = luaL_optlstring(L, 4, "", &request->aad_len);
request->authsize = (size_t)crypto_aead_authsize(tfm);
request->iv = (u8 *)lunatik_checkalloc(L, iv_len);
memcpy(request->iv, iv, iv_len);
gfp_t gfp = lunatik_gfp(lunatik_toruntime(L));
request->aead = aead_request_alloc(tfm, gfp);
if (request->aead == NULL) {
lunatik_free(request->iv);
lunatik_enomem(L);
}
}
static inline void luacrypto_aead_setrequest(luacrypto_aead_request_t *request, char *buffer, size_t buffer_len)
{
struct aead_request *aead = request->aead;
struct scatterlist *sg = &request->sg;
/* Build combined = aad || data in buffer */
memcpy(buffer, request->aad, request->aad_len);
memcpy(buffer + request->aad_len, request->data, request->crypt_len);
sg_init_one(sg, buffer, buffer_len);
aead_request_set_ad(aead, request->aad_len);
aead_request_set_crypt(aead, sg, sg, request->crypt_len, request->iv);
aead_request_set_callback(aead, 0, NULL, NULL);
}
static inline void luacrypto_aead_request_free(luacrypto_aead_request_t *request)
{
aead_request_free(request->aead);
lunatik_free(request->iv);
}
static inline char *luacrypto_aead_prepare(lua_State *L, luacrypto_aead_request_t *request, size_t buffer_len)
{
char *buffer = (char *)lunatik_malloc(L, buffer_len);
if (buffer == NULL) {
luacrypto_aead_request_free(request);
lunatik_enomem(L);
}
luacrypto_aead_setrequest(request, buffer, buffer_len);
return buffer;
}
static inline int luacrypto_aead_finish(lua_State *L, luacrypto_aead_request_t *request,
char *buffer, int ret, size_t output_len)
{
luacrypto_aead_request_free(request);
if (ret < 0) {
lunatik_free(buffer);
lunatik_throw(L, ret);
}
lua_pushlstring(L, buffer + request->aad_len, output_len);
lunatik_free(buffer);
return 1;
}
/***
* Encrypts plaintext with authentication.
* IV length must match `ivsize()`.
* @function encrypt
* @tparam string iv initialization vector
* @tparam string plaintext data to encrypt
* @tparam[opt] string aad additional authenticated data (default: empty string)
* @treturn string ciphertext concatenated with authentication tag
* @raise on encryption failure or incorrect IV length
*/
static int luacrypto_aead_encrypt(lua_State *L)
{
luacrypto_aead_request_t request;
luacrypto_aead_newrequest(L, &request);
size_t buffer_len = request.aad_len + request.crypt_len + request.authsize;
char *buffer = luacrypto_aead_prepare(L, &request, buffer_len);
int ret = crypto_aead_encrypt(request.aead);
return luacrypto_aead_finish(L, &request, buffer, ret, request.crypt_len + request.authsize);
}
/***
* Decrypts and authenticates ciphertext.
* IV length must match `ivsize()`. Raises EBADMSG on authentication failure.
* @function decrypt
* @tparam string iv initialization vector
* @tparam string ciphertext_with_tag ciphertext concatenated with authentication tag
* @tparam[opt] string aad additional authenticated data (default: empty string)
* @treturn string decrypted plaintext
* @raise on authentication failure (EBADMSG), incorrect IV length, or input too short
*/
static int luacrypto_aead_decrypt(lua_State *L)
{
luacrypto_aead_request_t request;
luacrypto_aead_newrequest(L, &request);
if (request.crypt_len < request.authsize) {
luacrypto_aead_request_free(&request);
lunatik_throw(L, -EBADMSG);
}
size_t buffer_len = request.aad_len + request.crypt_len;
char *buffer = luacrypto_aead_prepare(L, &request, buffer_len);
int ret = crypto_aead_decrypt(request.aead);
return luacrypto_aead_finish(L, &request, buffer, ret, request.crypt_len - request.authsize);
}
static int luacrypto_aead_algname(lua_State *L)
{
struct crypto_aead *tfm = luacrypto_aead_check(L, 1);
lua_pushstring(L, crypto_tfm_alg_name(crypto_aead_tfm(tfm)));
return 1;
}
static const luaL_Reg luacrypto_aead_mt[] = {
{"algname", luacrypto_aead_algname},
{"setkey", luacrypto_aead_setkey},
{"setauthsize", luacrypto_aead_setauthsize},
{"ivsize", luacrypto_aead_ivsize},
{"authsize", luacrypto_aead_authsize},
{"encrypt", luacrypto_aead_encrypt},
{"decrypt", luacrypto_aead_decrypt},
{"__gc", lunatik_deleteobject},
{"__close", lunatik_closeobject},
{NULL, NULL}
};
const lunatik_class_t luacrypto_aead_class = {
.name = "crypto_aead",
.methods = luacrypto_aead_mt,
.release = luacrypto_aead_release,
.opt = LUNATIK_OPT_MONITOR | LUNATIK_OPT_EXTERNAL,
};
/***
* Creates a new AEAD transform object.
* @function new
* @tparam string algname algorithm name (e.g., "gcm(aes)", "ccm(aes)")
* @treturn crypto_aead
* @raise on allocation failure
* @usage
* local aead = require("crypto").aead
* local cipher = aead("gcm(aes)")
*/
LUACRYPTO_NEW(aead, struct crypto_aead, crypto_alloc_aead, luacrypto_aead_class);
================================================
FILE: lib/luacrypto_comp.c
================================================
/*
* SPDX-FileCopyrightText: (c) 2025-2026 jperon <cataclop@hotmail.com>
* SPDX-License-Identifier: MIT OR GPL-2.0-only
*/
/***
* Lua interface to synchronous compression algorithms.
* @classmod crypto_comp
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/crypto.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/limits.h>
#include "luacrypto.h"
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 15, 0))
#warning "crypto_comp API was removed in Linux 6.15, skip COMP module"
#else
LUNATIK_PRIVATECHECKER(luacrypto_comp_check, struct crypto_comp *);
LUACRYPTO_RELEASER(comp, struct crypto_comp, crypto_free_comp);
#define LUACRYPTO_COMP_OPERATION(name) \
static int luacrypto_comp_##name(lua_State *L) \
{ \
struct crypto_comp *tfm = luacrypto_comp_check(L, 1); \
size_t datalen; \
const u8 *data = (const u8 *)luaL_checklstring(L, 2, &datalen); \
lunatik_checkbounds(L, 2, datalen, 1, UINT_MAX); \
unsigned int max_len = (unsigned int)lunatik_checkinteger(L, 3, 1, UINT_MAX); \
\
luaL_Buffer B; \
u8 *output_buf = luaL_buffinitsize(L, &B, max_len); \
\
lunatik_try(L, crypto_comp_##name, tfm, data, (unsigned int)datalen, output_buf, &max_len); \
luaL_pushresultsize(&B, max_len); \
return 1; \
}
/***
* Compresses data.
* @function compress
* @tparam string data input data
* @tparam integer max_len maximum size of compressed output
* @treturn string compressed data
* @raise on compression failure
*/
LUACRYPTO_COMP_OPERATION(compress);
/***
* Decompresses data.
* @function decompress
* @tparam string data compressed input
* @tparam integer max_len maximum size of decompressed output
* @treturn string decompressed data
* @raise on decompression failure
*/
LUACRYPTO_COMP_OPERATION(decompress);
static const luaL_Reg luacrypto_comp_mt[] = {
{"compress", luacrypto_comp_compress},
{"decompress", luacrypto_comp_decompress},
{"__gc", lunatik_deleteobject},
{"__close", lunatik_closeobject},
{NULL, NULL}
};
const lunatik_class_t luacrypto_comp_class = {
.name = "crypto_comp",
.methods = luacrypto_comp_mt,
.release = luacrypto_comp_release,
.opt = LUNATIK_OPT_MONITOR | LUNATIK_OPT_EXTERNAL,
};
/***
* Creates a new COMP transform object.
* @function new
* @tparam string algname algorithm name (e.g., "lz4", "deflate")
* @treturn crypto_comp
* @raise on allocation failure
* @usage
* local comp = require("crypto").comp
* local c = comp("lz4")
*/
LUACRYPTO_NEW(comp, struct crypto_comp, crypto_alloc_comp, luacrypto_comp_class);
#endif
================================================
FILE: lib/luacrypto_core.c
================================================
/*
* SPDX-FileCopyrightText: (c) 2025-2026 jperon <cataclop@hotmail.com>
* SPDX-License-Identifier: MIT OR GPL-2.0-only
*/
/***
* Lua interface to the Linux Crypto API.
* @module crypto
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include "luacrypto.h"
static const luaL_Reg luacrypto_lib[] = {
{"shash", luacrypto_shash_new},
{"skcipher", luacrypto_skcipher_new},
{"aead", luacrypto_aead_new},
{"rng", luacrypto_rng_new},
#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 15, 0))
{"comp", luacrypto_comp_new},
#endif
{NULL, NULL}
};
static const lunatik_class_t *luacrypto_classes[] = {
&luacrypto_shash_class,
&luacrypto_skcipher_class,
&luacrypto_aead_class,
&luacrypto_rng_class,
#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 15, 0))
&luacrypto_comp_class,
#endif
NULL
};
LUNATIK_NEWLIB(crypto, luacrypto_lib, luacrypto_classes, NULL);
static int __init luacrypto_init(void)
{
return 0;
}
static void __exit luacrypto_exit(void)
{
}
module_init(luacrypto_init);
module_exit(luacrypto_exit);
MODULE_LICENSE("Dual MIT/GPL");
MODULE_AUTHOR("jperon <cataclop@hotmail.com>");
MODULE_DESCRIPTION("Lunatik Linux Crypto API interface");
================================================
FILE: lib/luacrypto_rng.c
================================================
/*
* SPDX-FileCopyrightText: (c) 2025-2026 jperon <cataclop@hotmail.com>
* SPDX-License-Identifier: MIT OR GPL-2.0-only
*/
/***
* Lua interface to synchronous Random Number Generators (RNG).
* @classmod crypto_rng
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <crypto/rng.h>
#include <linux/err.h>
#include <linux/limits.h>
#include <linux/slab.h>
#include "luacrypto.h"
LUNATIK_PRIVATECHECKER(luacrypto_rng_check, struct crypto_rng *);
LUACRYPTO_RELEASER(rng, struct crypto_rng, crypto_free_rng);
/***
* Generates random bytes, optionally reseeding first.
* @function generate
* @tparam integer n number of bytes to generate
* @tparam[opt] string seed optional seed data
* @treturn string random bytes
* @raise on generation failure
*/
static int luacrypto_rng_generate(lua_State *L)
{
struct crypto_rng *tfm = luacrypto_rng_check(L, 1);
unsigned int num_bytes = (unsigned int)lunatik_checkinteger(L, 2, 1, UINT_MAX);
size_t seed_len = 0;
const char *seed_data = lua_tolstring(L, 3, &seed_len);
luaL_Buffer B;
char *buffer = luaL_buffinitsize(L, &B, num_bytes);
lunatik_try(L, crypto_rng_generate, tfm, seed_data, (unsigned int)seed_len, (u8 *)buffer, num_bytes);
luaL_pushresultsize(&B, num_bytes);
return 1;
}
/***
* Reseeds the RNG.
* @function reset
* @tparam string seed
* @raise on reseed failure
*/
static int luacrypto_rng_reset(lua_State *L)
{
struct crypto_rng *tfm = luacrypto_rng_check(L, 1);
size_t seed_len = 0;
const char *seed_data = lua_tolstring(L, 2, &seed_len);
lunatik_try(L, crypto_rng_reset, tfm, (const u8 *)seed_data, (unsigned int)seed_len);
return 0;
}
/***
* Generates random bytes without reseeding.
* @function getbytes
* @tparam integer n number of bytes to generate
* @treturn string random bytes
* @raise on generation failure
*/
static int luacrypto_rng_getbytes(lua_State *L)
{
struct crypto_rng *tfm = luacrypto_rng_check(L, 1);
unsigned int num_bytes = (unsigned int)lunatik_checkinteger(L, 2, 1, UINT_MAX);
luaL_Buffer B;
u8 *buffer = (u8 *)luaL_buffinitsize(L, &B, num_bytes);
lunatik_try(L, crypto_rng_get_bytes, tfm, (u8 *)buffer, num_bytes);
luaL_pushresultsize(&B, num_bytes);
return 1;
}
/***
* Returns algorithm information.
* @function info
* @treturn table with fields `driver_name` (string) and `seedsize` (integer)
*/
static int luacrypto_rng_info(lua_State *L)
{
struct crypto_rng *tfm = luacrypto_rng_check(L, 1);
const struct rng_alg *alg = crypto_rng_alg(tfm);
lua_createtable(L, 0, 2);
lua_pushstring(L, alg->base.cra_driver_name);
lua_setfield(L, -2, "driver_name");
lua_pushinteger(L, alg->seedsize);
lua_setfield(L, -2, "seedsize");
return 1;
}
static int luacrypto_rng_algname(lua_State *L)
{
struct crypto_rng *tfm = luacrypto_rng_check(L, 1);
lua_pushstring(L, crypto_tfm_alg_name(crypto_rng_tfm(tfm)));
return 1;
}
static const luaL_Reg luacrypto_rng_mt[] = {
{"algname", luacrypto_rng_algname},
{"generate", luacrypto_rng_generate},
{"reset", luacrypto_rng_reset},
{"getbytes", luacrypto_rng_getbytes},
{"info", luacrypto_rng_info},
{"__gc", lunatik_deleteobject},
{"__close", lunatik_closeobject},
{NULL, NULL}
};
const lunatik_class_t luacrypto_rng_class = {
.name = "crypto_rng",
.methods = luacrypto_rng_mt,
.release = luacrypto_rng_release,
.opt = LUNATIK_OPT_MONITOR | LUNATIK_OPT_EXTERNAL,
};
/***
* Creates a new RNG object.
* @function new
* @tparam[opt] string algname algorithm name; defaults to "stdrng"
* @treturn crypto_rng
* @raise on allocation or initialization failure
* @usage
* local rng = require("crypto").rng
* local r = rng() -- uses "stdrng"
*/
int luacrypto_rng_new(lua_State *L)
{
const char *algname = luaL_optstring(L, 1, "stdrng");
lunatik_object_t *object = lunatik_newobject(L, &luacrypto_rng_class, 0, LUNATIK_OPT_NONE);
struct crypto_rng *tfm = crypto_alloc_rng(algname, 0, 0);
if (IS_ERR(tfm))
lunatik_throw(L, PTR_ERR(tfm));
object->private = tfm;
lunatik_try(L, crypto_rng_reset, tfm, NULL, 0);
return 1;
}
================================================
FILE: lib/luacrypto_shash.c
================================================
/*
* SPDX-FileCopyrightText: (c) 2025-2026 jperon <cataclop@hotmail.com>
* SPDX-License-Identifier: MIT OR GPL-2.0-only
*/
/***
* Lua interface to synchronous message digest (hash) algorithms, including HMAC.
* @classmod crypto_shash
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <crypto/hash.h>
#include <linux/err.h>
#include <linux/slab.h>
#include "luacrypto.h"
LUNATIK_PRIVATECHECKER(luacrypto_shash_check, struct shash_desc *);
static void luacrypto_shash_release(void *private)
{
struct shash_desc *obj = (struct shash_desc *)private;
if (obj) {
if (obj->tfm)
crypto_free_shash(obj->tfm);
lunatik_free(obj);
}
}
/***
* Returns the digest size in bytes.
* @function digestsize
* @treturn integer
*/
static int luacrypto_shash_digestsize(lua_State *L)
{
struct shash_desc *sdesc = luacrypto_shash_check(L, 1);
lua_pushinteger(L, crypto_shash_digestsize(sdesc->tfm));
return 1;
}
/***
* Sets the key (required for HMAC algorithms).
* @function setkey
* @tparam string key
* @raise on invalid key or algorithm error
*/
static int luacrypto_shash_setkey(lua_State *L)
{
struct shash_desc *sdesc = luacrypto_shash_check(L, 1);
size_t keylen;
const char *key = luaL_checklstring(L, 2, &keylen);
lunatik_try(L, crypto_shash_setkey, sdesc->tfm, key, keylen);
return 0;
}
/***
* Computes the digest of data in a single call.
* @function digest
* @tparam string data
* @treturn string digest bytes
* @raise on hash failure
*/
static int luacrypto_shash_digest(lua_State *L)
{
struct shash_desc *sdesc = luacrypto_shash_check(L, 1);
size_t datalen;
const char *data = luaL_checklstring(L, 2, &datalen);
unsigned int digestsize = crypto_shash_digestsize(sdesc->tfm);
luaL_Buffer B;
u8 *digest_buf = luaL_buffinitsize(L, &B, digestsize);
lunatik_try(L, crypto_shash_digest, sdesc, data, datalen, digest_buf);
luaL_pushresultsize(&B, digestsize);
return 1;
}
/***
* Initializes the hash state for incremental hashing.
* @function init
* @raise on initialization failure
*/
static int luacrypto_shash_init_mt(lua_State *L)
{
struct shash_desc *sdesc = luacrypto_shash_check(L, 1);
lunatik_try(L, crypto_shash_init, sdesc);
return 0;
}
/***
* Feeds data into the running hash.
* @function update
* @tparam string data
* @raise on hash failure
*/
static int luacrypto_shash_update(lua_State *L)
{
struct shash_desc *sdesc = luacrypto_shash_check(L, 1);
size_t datalen;
const char *data = luaL_checklstring(L, 2, &datalen);
lunatik_try(L, crypto_shash_update, sdesc, data, datalen);
return 0;
}
/***
* Finalizes and returns the digest.
* @function final
* @treturn string digest bytes
* @raise on hash failure
*/
static int luacrypto_shash_final(lua_State *L)
{
struct shash_desc *sdesc = luacrypto_shash_check(L, 1);
unsigned int digestsize = crypto_shash_digestsize(sdesc->tfm);
luaL_Buffer B;
u8 *digest_buf = luaL_buffinitsize(L, &B, digestsize);
lunatik_try(L, crypto_shash_final, sdesc, digest_buf);
luaL_pushresultsize(&B, digestsize);
return 1;
}
/***
* Feeds final data and returns the digest (update + final in one call).
* @function finup
* @tparam string data
* @treturn string digest bytes
* @raise on hash failure
*/
static int luacrypto_shash_finup(lua_State *L)
{
struct shash_desc *sdesc = luacrypto_shash_check(L, 1);
size_t datalen;
const char *data = luaL_checklstring(L, 2, &datalen);
unsigned int digestsize = crypto_shash_digestsize(sdesc->tfm);
luaL_Buffer B;
u8 *digest_buf = luaL_buffinitsize(L, &B, digestsize);
lunatik_try(L, crypto_shash_finup, sdesc, data, datalen, digest_buf);
luaL_pushresultsize(&B, digestsize);
return 1;
}
/***
* Exports the current internal hash state.
* @function export
* @treturn string opaque state blob
*/
static int luacrypto_shash_export(lua_State *L)
{
struct shash_desc *sdesc = luacrypto_shash_check(L, 1);
unsigned int statesize = crypto_shash_statesize(sdesc->tfm);
luaL_Buffer B;
void *state_buf = luaL_buffinitsize(L, &B, statesize);
crypto_shash_export(sdesc, state_buf);
luaL_pushresultsize(&B, statesize);
return 1;
}
/***
* Restores a previously exported hash state.
* @function import
* @tparam string state blob returned by `export()`
* @raise on length mismatch
*/
static int luacrypto_shash_import(lua_State *L)
{
struct shash_desc *sdesc = luacrypto_shash_check(L, 1);
size_t statelen;
const char *state = luaL_checklstring(L, 2, &statelen);
unsigned int expected_statesize = crypto_shash_statesize(sdesc->tfm);
if (statelen != expected_statesize)
lunatik_throw(L, -EINVAL);
lunatik_try(L, crypto_shash_import, sdesc, state);
return 0;
}
static int luacrypto_shash_algname(lua_State *L)
{
struct shash_desc *sdesc = luacrypto_shash_check(L, 1);
lua_pushstring(L, crypto_tfm_alg_name(crypto_shash_tfm(sdesc->tfm)));
return 1;
}
static const luaL_Reg luacrypto_shash_mt[] = {
{"algname", luacrypto_shash_algname},
{"digestsize", luacrypto_shash_digestsize},
{"setkey", luacrypto_shash_setkey},
{"digest", luacrypto_shash_digest},
{"init", luacrypto_shash_init_mt},
{"update", luacrypto_shash_update},
{"final", luacrypto_shash_final},
{"finup", luacrypto_shash_finup},
{"export", luacrypto_shash_export},
{"import", luacrypto_shash_import},
{"__gc", lunatik_deleteobject},
{"__close", lunatik_closeobject},
{NULL, NULL}
};
const lunatik_class_t luacrypto_shash_class = {
.name = "crypto_shash",
.methods = luacrypto_shash_mt,
.release = luacrypto_shash_release,
.opt = LUNATIK_OPT_MONITOR | LUNATIK_OPT_EXTERNAL,
};
/***
* Creates a new SHASH object.
* @function new
* @tparam string algname algorithm name (e.g., "sha256", "hmac(sha256)")
* @treturn crypto_shash
* @raise on allocation failure
* @usage
* local shash = require("crypto").shash
* local h = shash("sha256")
*/
int luacrypto_shash_new(lua_State *L)
{
const char *algname = luaL_checkstring(L, 1);
struct crypto_shash *tfm = crypto_alloc_shash(algname, 0, 0);
size_t desc_size;
struct shash_desc *sdesc;
lunatik_object_t *object;
if (IS_ERR(tfm))
lunatik_throw(L, PTR_ERR(tfm));
desc_size = sizeof(struct shash_desc) + crypto_shash_descsize(tfm);
sdesc = lunatik_malloc(L, desc_size);
if (!sdesc) {
crypto_free_shash(tfm);
lunatik_enomem(L);
}
sdesc->tfm = tfm;
object = lunatik_newobject(L, &luacrypto_shash_class, 0, LUNATIK_OPT_NONE);
object->private = sdesc;
return 1;
}
================================================
FILE: lib/luacrypto_skcipher.c
================================================
/*
* SPDX-FileCopyrightText: (c) 2025-2026 jperon <cataclop@hotmail.com>
* SPDX-License-Identifier: MIT OR GPL-2.0-only
*/
/***
* Lua interface to symmetric-key ciphers (SKCIPHER).
* @classmod crypto_skcipher
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <crypto/skcipher.h>
#include <linux/err.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include "luacrypto.h"
LUNATIK_PRIVATECHECKER(luacrypto_skcipher_check, struct crypto_skcipher *);
LUACRYPTO_RELEASER(skcipher, struct crypto_skcipher, crypto_free_skcipher);
/***
* Sets the cipher key.
* @function setkey
* @tparam string key
* @raise on invalid key length or algorithm error
*/
static int luacrypto_skcipher_setkey(lua_State *L)
{
struct crypto_skcipher *tfm = luacrypto_skcipher_check(L, 1);
size_t keylen;
const char *key = luaL_checklstring(L, 2, &keylen);
lunatik_try(L, crypto_skcipher_setkey, tfm, key, keylen);
return 0;
}
/***
* Returns the required IV size in bytes.
* @function ivsize
* @treturn integer
*/
static int luacrypto_skcipher_ivsize(lua_State *L)
{
struct crypto_skcipher *tfm = luacrypto_skcipher_check(L, 1);
lua_pushinteger(L, crypto_skcipher_ivsize(tfm));
return 1;
}
/***
* Returns the cipher block size in bytes.
* @function blocksize
* @treturn integer
*/
static int luacrypto_skcipher_blocksize(lua_State *L)
{
struct crypto_skcipher *tfm = luacrypto_skcipher_check(L, 1);
lua_pushinteger(L, crypto_skcipher_blocksize(tfm));
return 1;
}
typedef struct luacrypto_skcipher_request_s {
struct scatterlist sg;
struct skcipher_request *skcipher;
const char *data;
size_t data_len;
u8 *iv;
} luacrypto_skcipher_request_t;
static inline void luacrypto_skcipher_newrequest(lua_State *L, luacrypto_skcipher_request_t *request)
{
memset(request, 0, sizeof(luacrypto_skcipher_request_t));
struct crypto_skcipher *tfm = luacrypto_skcipher_check(L, 1);
size_t iv_len;
const char *iv = luaL_checklstring(L, 2, &iv_len);
if (iv_len != crypto_skcipher_ivsize(tfm))
lunatik_throw(L, -EINVAL);
request->data = luaL_checklstring(L, 3, &request->data_len);
request->iv = (u8 *)lunatik_checkalloc(L, iv_len);
memcpy(request->iv, iv, iv_len);
gfp_t gfp = lunatik_gfp(lunatik_toruntime(L));
request->skcipher = skcipher_request_alloc(tfm, gfp);
if (request->skcipher == NULL) {
lunatik_free(request->iv);
lunatik_enomem(L);
}
}
static inline void luacrypto_skcipher_setrequest(luacrypto_skcipher_request_t *request, char *buffer)
{
struct skcipher_request *skcipher = request->skcipher;
struct scatterlist *sg = &request->sg;
size_t data_len = request->data_len;
memcpy(buffer, request->data, data_len);
sg_init_one(sg, buffer, data_len);
skcipher_request_set_crypt(skcipher, sg, sg, data_len, request->iv);
skcipher_request_set_callback(skcipher, 0, NULL, NULL);
}
static int luacrypto_skcipher_crypt(lua_State *L, int (*crypt)(struct skcipher_request *))
{
luacrypto_skcipher_request_t request;
luacrypto_skcipher_newrequest(L, &request);
char *buffer = (char *)lunatik_malloc(L, request.data_len);
if (buffer == NULL) {
skcipher_request_free(request.skcipher);
lunatik_free(request.iv);
lunatik_enomem(L);
}
luacrypto_skcipher_setrequest(&request, buffer);
int ret = crypt(request.skcipher);
skcipher_request_free(request.skcipher);
lunatik_free(request.iv);
if (ret < 0) {
lunatik_free(buffer);
lunatik_throw(L, ret);
}
lunatik_pushstring(L, buffer, request.data_len);
return 1;
}
/***
* Encrypts data. IV length must match `ivsize()`.
* @function encrypt
* @tparam string iv initialization vector
* @tparam string data plaintext
* @treturn string ciphertext (same length as input)
* @raise on encryption failure or incorrect IV length
*/
static int luacrypto_skcipher_encrypt(lua_State *L)
{
return luacrypto_skcipher_crypt(L, crypto_skcipher_encrypt);
}
/***
* Decrypts data. IV length must match `ivsize()`.
* @function decrypt
* @tparam string iv initialization vector
* @tparam string data ciphertext
* @treturn string plaintext (same length as input)
* @raise on decryption failure or incorrect IV length
*/
static int luacrypto_skcipher_decrypt(lua_State *L)
{
return luacrypto_skcipher_crypt(L, crypto_skcipher_decrypt);
}
static int luacrypto_skcipher_algname(lua_State *L)
{
struct crypto_skcipher *tfm = luacrypto_skcipher_check(L, 1);
lua_pushstring(L, crypto_tfm_alg_name(crypto_skcipher_tfm(tfm)));
return 1;
}
static const luaL_Reg luacrypto_skcipher_mt[] = {
{"algname", luacrypto_skcipher_algname},
{"setkey", luacrypto_skcipher_setkey},
{"ivsize", luacrypto_skcipher_ivsize},
{"blocksize", luacrypto_skcipher_blocksize},
{"encrypt", luacrypto_skcipher_encrypt},
{"decrypt", luacrypto_skcipher_decrypt},
{"__gc", lunatik_deleteobject},
{"__close", lunatik_closeobject},
{NULL, NULL}
};
const lunatik_class_t luacrypto_skcipher_class = {
.name = "crypto_skcipher",
.methods = luacrypto_skcipher_mt,
.release = luacrypto_skcipher_release,
.opt = LUNATIK_OPT_MONITOR | LUNATIK_OPT_EXTERNAL,
};
/***
* Creates a new SKCIPHER transform object.
* @function new
* @tparam string algname algorithm name (e.g., "cbc(aes)", "ctr(aes)")
* @treturn crypto_skcipher
* @raise on allocation failure
* @usage
* local skcipher = require("crypto").skcipher
* local cipher = skcipher("cbc(aes)")
*/
LUACRYPTO_NEW(skcipher, struct crypto_skcipher, crypto_alloc_skcipher, luacrypto_skcipher_class);
================================================
FILE: lib/luadarken.c
================================================
/*
* SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA
* SPDX-License-Identifier: MIT OR GPL-2.0-only
*/
/***
* Encrypted Lua script execution using AES-256-CTR.
*
* This module provides functionality to decrypt and execute Lua scripts
* encrypted with AES-256 in CTR mode. Scripts are decrypted in-kernel
* and executed immediately, with the decrypted plaintext never written
* to persistent storage.
*
* @module darken
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <crypto/skcipher.h>
#include <linux/scatterlist.h>
#include <lunatik.h>
#define LUADARKEN_KEYLEN 32
#define LUADARKEN_IVLEN 16
#define LUADARKEN_ALG "ctr(aes)"
typedef struct luadarken_request_s {
struct crypto_skcipher *tfm;
struct skcipher_request *req;
u8 *iv;
} luadarken_request_t;
static void luadarken_freerequest(luadarken_request_t *r)
{
kfree(r->iv);
if (r->req)
skcipher_request_free(r->req);
if (r->tfm)
crypto_free_skcipher(r->tfm);
}
static struct crypto_skcipher *luadarken_setkey(lua_State *L, const char *key)
{
struct crypto_skcipher *tfm = crypto_alloc_skcipher(LUADARKEN_ALG, 0, 0);
if (IS_ERR(tfm))
lunatik_throw(L, PTR_ERR(tfm));
int ret = crypto_skcipher_setkey(tfm, key, LUADARKEN_KEYLEN);
if (ret < 0) {
crypto_free_skcipher(tfm);
lunatik_throw(L, ret);
}
return tfm;
}
static char *luadarken_setrequest(lua_State *L, luadarken_request_t *r,
const char *ct, size_t ct_len, const char *iv, const char *key)
{
r->tfm = luadarken_setkey(L, key);
gfp_t gfp = lunatik_gfp(lunatik_toruntime(L));
r->req = skcipher_request_alloc(r->tfm, gfp);
if (r->req == NULL)
goto err;
r->iv = kmemdup(iv, LUADARKEN_IVLEN, gfp);
if (r->iv == NULL)
goto err;
char *buf = kmemdup(ct, ct_len, gfp);
if (buf == NULL)
goto err;
struct scatterlist sg;
sg_init_one(&sg, buf, ct_len);
skcipher_request_set_crypt(r->req, &sg, &sg, ct_len, r->iv);
skcipher_request_set_callback(r->req, 0, NULL, NULL);
return buf;
err:
luadarken_freerequest(r);
lunatik_enomem(L);
return NULL; /* unreachable */
}
static void luadarken_decrypt(lua_State *L, luadarken_request_t *r)
{
int ret = crypto_skcipher_decrypt(r->req);
luadarken_freerequest(r);
if (ret < 0)
lunatik_throw(L, ret);
}
/***
* Decrypts and executes an encrypted Lua script.
* @function run
* @tparam string ciphertext encrypted Lua script (binary).
* @tparam string iv 16-byte initialization vector (binary).
* @tparam string key 32-byte AES-256 key (binary).
* @return The return values from the executed script.
* @raise Error if decryption fails or IV/key length is invalid.
*/
static int luadarken_run(lua_State *L)
{
size_t ct_len, iv_len, key_len;
const char *ct = luaL_checklstring(L, 1, &ct_len);
const char *iv = luaL_checklstring(L, 2, &iv_len);
const char *key = luaL_checklstring(L, 3, &key_len);
luaL_argcheck(L, iv_len == LUADARKEN_IVLEN, 2, "IV must be 16 bytes");
luaL_argcheck(L, key_len == LUADARKEN_KEYLEN, 3, "key must be 32 bytes");
luadarken_request_t r = {0};
char *buf = luadarken_setrequest(L, &r, ct, ct_len, iv, key);
luadarken_decrypt(L, &r);
int ret = luaL_loadbufferx(L, buf, ct_len, "=darken", "t");
kfree(buf);
if (ret != LUA_OK)
lua_error(L);
int base = lua_gettop(L);
lua_call(L, 0, LUA_MULTRET);
return lua_gettop(L) - base + 1;
}
static const luaL_Reg luadarken_lib[] = {
{"run", luadarken_run},
{NULL, NULL}
};
LUNATIK_NEWLIB(darken, luadarken_lib, NULL, NULL);
static int __init luadarken_init(void)
{
return 0;
}
static void __exit luadarken_exit(void)
{
}
module_init(luadarken_init);
module_exit(luadarken_exit);
MODULE_LICENSE("Dual MIT/GPL");
MODULE_AUTHOR("Lourival Vieira Neto <lourival.neto@ringzero.com.br>");
MODULE_DESCRIPTION("Lunatik darken — AES-256-CTR script decryption");
================================================
FILE: lib/luadata.c
================================================
/*
* SPDX-FileCopyrightText: (c) 2023-2026 Ring Zero Desenvolvimento de Software LTDA
* SPDX-License-Identifier: MIT OR GPL-2.0-only
*/
/***
* Direct memory access and manipulation.
* @module data
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/bitops.h>
#include <net/checksum.h>
#include <lunatik.h>
#include "luadata.h"
typedef struct luadata_s {
void *ptr;
size_t size;
uint8_t opt;
} luadata_t;
#define LUADATA_NUMBER_SZ (sizeof(lua_Integer))
static int luadata_lnew(lua_State *L);
LUNATIK_PRIVATECHECKER(luadata_check, luadata_t *);
static inline void *luadata_checkbounds(lua_State *L, int ix, luadata_t *data, lua_Integer offset, lua_Integer length)
{
int bounds = offset >= 0 && length > 0 && offset + length <= data->size;
luaL_argcheck(L, bounds, ix, "out of bounds");
return (data->ptr + offset);
}
#define luadata_checkwritable(L, data) luaL_argcheck((L), !((data)->opt & LUADATA_OPT_READONLY), 1, "read only")
#define LUADATA_NEWINT_GETTER(T) \
static int luadata_get##T(lua_State *L) \
{ \
luadata_t *data = luadata_check(L, 1); \
lua_Integer offset = luaL_checkinteger(L, 2); \
T##_t value = *(T##_t *)luadata_checkbounds(L, 2, data, offset, sizeof(T##_t)); \
lua_pushinteger(L, (lua_Integer)value); \
return 1; \
}
#define LUADATA_NEWINT_SETTER(T) \
static int luadata_set##T(lua_State *L) \
{ \
luadata_t *data = luadata_check(L, 1); \
lua_Integer offset = luaL_checkinteger(L, 2); \
T##_t *ptr = luadata_checkbounds(L, 2, data, offset, sizeof(T##_t)); \
luadata_checkwritable(L, data); \
*ptr = (T##_t)luaL_checkinteger(L, 3); \
return 0; \
}
#define LUADATA_NEWINT(T) \
LUADATA_NEWINT_GETTER(T); \
LUADATA_NEWINT_SETTER(T);
LUADATA_NEWINT(int8);
LUADATA_NEWINT(uint8);
LUADATA_NEWINT(int16);
LUADATA_NEWINT(uint16);
LUADATA_NEWINT(int32);
LUADATA_NEWINT(uint32);
LUADATA_NEWINT(int64);
/***
* @function getstring
* @tparam integer offset
* @tparam[opt] integer length number of bytes; default: from offset to end
* @treturn string
* @raise if out of bounds
*/
static int luadata_getstring(lua_State *L)
{
luadata_t *data = luadata_check(L, 1);
lua_Integer offset = luaL_checkinteger(L, 2);
lua_Integer length = luaL_optinteger(L, 3, data->size - offset);
char *str = (char *)luadata_checkbounds(L, 2, data, offset, length);
lua_pushlstring(L, str, length);
return 1;
}
/***
* @function setstring
* @tparam integer offset
* @tparam string s
* @raise if out of bounds or read-only
*/
static int luadata_setstring(lua_State *L)
{
size_t length;
luadata_t *data = luadata_check(L, 1);
lua_Integer offset = luaL_checkinteger(L, 2);
const char *str = luaL_checklstring(L, 3, &length);
void *ptr = luadata_checkbounds(L, 2, data, offset, length);
luadata_checkwritable(L, data);
memcpy(ptr, str, length);
return 0;
}
/***
* @function checksum
* @tparam[opt] integer offset
* @tparam[opt] integer length
* @treturn integer
* @raise if out of bounds
*/
static int luadata_checksum(lua_State *L)
{
luadata_t *data = luadata_check(L, 1);
lua_Integer offset = luaL_optinteger(L, 2, 0);
lua_Integer length = luaL_optinteger(L, 3, data->size - offset);
void *value = (void*)luadata_checkbounds(L, 2, data, offset, length);
__wsum sum = csum_partial(value, length, 0);
lua_pushinteger(L, csum_fold(sum));
return 1;
}
/***
* @function resize
* @tparam integer new_size
* @raise if read-only or not owned
*/
static int luadata_resize(lua_State *L)
{
luadata_t *data = luadata_check(L, 1);
size_t new_size = (size_t)luaL_checkinteger(L, 2);
luadata_checkwritable(L, data);
if (data->opt & LUADATA_OPT_FREE)
data->ptr = lunatik_checknull(L, lunatik_realloc(L, data->ptr, new_size));
else
luaL_error(L, "cannot resize external memory");
data->size = new_size;
return 0;
}
/***
* @function __len
* @treturn integer data size in bytes
*/
static int luadata_length(lua_State *L)
{
luadata_t *data = luadata_check(L, 1);
lua_pushinteger(L, (lua_Integer)data->size);
return 1;
}
/***
* @function __tostring
* @treturn string
*/
static int luadata_tostring(lua_State *L)
{
luadata_t *data = luadata_check(L, 1);
lua_pushlstring(L, (char *)data->ptr, data->size);
return 1;
}
static void luadata_release(void *private)
{
luadata_t *data = (luadata_t *)private;
if (data->opt & LUADATA_OPT_FREE)
lunatik_free(data->ptr);
}
/***
* @function new
* @tparam integer size
* @treturn data
* @raise if allocation fails
*/
static const luaL_Reg luadata_lib[] = {
{"new", luadata_lnew},
{NULL, NULL}
};
static const luaL_Reg luadata_mt[] = {
{"__gc", lunatik_deleteobject},
{"__len", luadata_length},
{"__tostring", luadata_tostring},
/***
* @function getbyte
* @tparam integer offset
* @treturn integer
* @raise if out of bounds
*/
{"getbyte", luadata_getuint8},
/***
* @function setbyte
* @tparam integer offset
* @tparam integer value
* @raise if out of bounds or read-only
*/
{"setbyte", luadata_setuint8},
/***
* @function getint8
* @tparam integer offset
* @treturn integer
* @raise if out of bounds
*/
{"getint8", luadata_getint8},
/***
* @function setint8
* @tparam integer offset
* @tparam integer value
* @raise if out of bounds or read-only
*/
{"setint8", luadata_setint8},
/***
* @function getuint8
* @tparam integer offset
* @treturn integer
* @raise if out of bounds
*/
{"getuint8", luadata_getuint8},
/***
* @function setuint8
* @tparam integer offset
* @tparam integer value
* @raise if out of bounds or read-only
*/
{"setuint8", luadata_setuint8},
/***
* @function getint16
* @tparam integer offset
* @treturn integer
* @raise if out of bounds
*/
{"getint16", luadata_getint16},
/***
* @function setint16
* @tparam integer offset
* @tparam integer value
* @raise if out of bounds or read-only
*/
{"setint16", luadata_setint16},
/***
* @function getuint16
* @tparam integer offset
* @treturn integer
* @raise if out of bounds
*/
{"getuint16", luadata_getuint16},
/***
* @function setuint16
* @tparam integer offset
* @tparam integer value
* @raise if out of bounds or read-only
*/
{"setuint16", luadata_setuint16},
/***
* @function getint32
* @tparam integer offset
* @treturn integer
* @raise if out of bounds
*/
{"getint32", luadata_getint32},
/***
* @function setint32
* @tparam integer offset
* @tparam integer value
* @raise if out of bounds or read-only
*/
{"setint32", luadata_setint32},
/***
* @function getuint32
* @tparam integer offset
* @treturn integer
* @raise if out of bounds
*/
{"getuint32", luadata_getuint32},
/***
* @function setuint32
* @tparam integer offset
* @tparam integer value
* @raise if out of bounds or read-only
*/
{"setuint32", luadata_setuint32},
/***
* @function getint64
* @tparam integer offset
* @treturn integer
* @raise if out of bounds
*/
{"getint64", luadata_getint64},
/***
* @function setint64
* @tparam integer offset
* @tparam integer value
* @raise if out of bounds or read-only
*/
{"setint64", luadata_setint64},
/***
* @function getnumber
* @tparam integer offset
* @treturn integer
* @raise if out of bounds
*/
{"getnumber", luadata_getint64},
/***
* @function setnumber
* @tparam integer offset
* @tparam integer value
* @raise if out of bounds or read-only
*/
{"setnumber", luadata_setint64},
{"getstring", luadata_getstring},
{"setstring", luadata_setstring},
{"resize", luadata_resize},
{"checksum", luadata_checksum},
{NULL, NULL}
};
static const lunatik_class_t luadata_class = {
.name = "data",
.methods = luadata_mt,
.release = luadata_release,
.opt = LUNATIK_OPT_SOFTIRQ | LUNATIK_OPT_MONITOR,
};
static inline void luadata_set(luadata_t *data, void *ptr, size_t size, uint8_t opt)
{
data->ptr = ptr;
data->size = size;
data->opt = opt;
}
static int luadata_lnew(lua_State *L)
{
size_t size = (size_t)luaL_checkinteger(L, 1);
static const char *const modes[] = {"shared", "single", NULL};
int mode = luaL_checkoption(L, 2, "shared", modes);
lunatik_opt_t opt = mode == 1 ? LUNATIK_OPT_SINGLE : LUNATIK_OPT_MONITOR;
lunatik_object_t *object = lunatik_newobject(L, &luadata_class, sizeof(luadata_t), opt);
luadata_t *data = (luadata_t *)object->private;
luadata_set(data, lunatik_checkalloc(L, size), size, LUADATA_OPT_FREE);
return 1; /* object */
}
LUNATIK_CLASSES(data, &luadata_class);
LUNATIK_NEWLIB(data, luadata_lib, luadata_classes, NULL);
lunatik_object_t *luadata_new(lua_State *L, lunatik_opt_t opt)
{
lunatik_require(L, "data");
lunatik_object_t *object = lunatik_newobject(L, &luadata_class, sizeof(luadata_t), opt);
return object;
}
EXPORT_SYMBOL(luadata_new);
int luadata_reset(lunatik_object_t *object, void *ptr, size_t size, uint8_t opt)
{
luadata_t *data;
lunatik_lock(object);
data = (luadata_t *)object->private;
if (data->opt & LUADATA_OPT_FREE) {
lunatik_unlock(object);
return -1;
}
opt = opt & LUADATA_OPT_KEEP ? data->opt : opt;
luadata_set(data, ptr, size, opt);
lunatik_unlock(object);
return 0;
}
EXPORT_SYMBOL(luadata_reset);
static int __init luadata_init(void)
{
return 0;
}
static void __exit luadata_exit(void)
{
}
module_init(luadata_init);
module_exit(luadata_exit);
MODULE_LICENSE("Dual MIT/GPL");
MODULE_AUTHOR("Lourival Vieira Neto <lourival.neto@ringzero.com.br>");
================================================
FILE: lib/luadata.h
================================================
/*
* SPDX-FileCopyrightText: (c) 2024-2026 Ring Zero Desenvolvimento de Software LTDA
* SPDX-License-Identifier: MIT OR GPL-2.0-only
*/
#ifndef luadata_h
#define luadata_h
#include <lunatik.h>
#define LUADATA_OPT_NONE 0x00
#define LUADATA_OPT_READONLY 0x01
#define LUADATA_OPT_FREE 0x02
#define LUADATA_OPT_KEEP 0x80
#define luadata_clear(o) (luadata_reset((o), NULL, 0, LUADATA_OPT_KEEP))
lunatik_object_t *luadata_new(lua_State *L, lunatik_opt_t opt);
int luadata_reset(lunatik_object_t *object, void *ptr, size_t size, uint8_t opt);
static inline void luadata_close(lunatik_object_t *object)
{
luadata_clear(object);
lunatik_putobject(object);
}
#define luadata_attach(L, obj, field, opt) lunatik_attach(L, obj, field, luadata_new, opt)
#endif
================================================
FILE: lib/luadevice.c
================================================
/*
* SPDX-FileCopyrightText: (c) 2023-2025 Ring Zero Desenvolvimento de Software LTDA
* SPDX-License-Identifier: MIT OR GPL-2.0-only
*/
/***
* Low-level Lua interface for creating Linux character device drivers.
*
* This module allows Lua scripts to implement character device drivers
* by providing callback functions for standard file operations like
* `open`, `read`, `write`, and `release`.
*
* @module device
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/fs.h>
#include <linux/printk.h>
#include <linux/string.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/kref.h>
#include <lunatik.h>
static struct class *luadevice_devclass;
/***
* Represents a character device implemented in Lua.
* This is a userdata object returned by `device.new()`. It encapsulates
* the necessary kernel structures (`struct cdev`, `dev_t`) to manage a
* character device, linking file operations to Lua callback functions.
* @type device
*/
typedef struct luadevice_s {
struct list_head entry;
lunatik_object_t *runtime;
struct cdev *cdev;
dev_t devt;
} luadevice_t;
static DEFINE_MUTEX(luadevice_mutex);
static LIST_HEAD(luadevice_list);
#define luadevice_lock() mutex_lock(&luadevice_mutex)
#define luadevice_unlock() mutex_unlock(&luadevice_mutex)
#define luadevice_foreach(luadev) list_for_each_entry((luadev), &luadevice_list, entry)
static inline void luadevice_listadd(luadevice_t *luadev)
{
luadevice_lock();
list_add_tail(&luadev->entry, &luadevice_list);
luadevice_unlock();
}
static inline void luadevice_listdel(luadevice_t *luadev)
{
luadevice_lock();
list_del(&luadev->entry);
luadevice_unlock();
}
static inline luadevice_t *luadevice_find(dev_t devt)
{
luadevice_t *luadev = NULL;
luadevice_lock();
luadevice_foreach(luadev) {
if (luadev->devt == devt)
break;
}
luadevice_unlock();
return luadev;
}
static int luadevice_new(lua_State *L);
static int luadevice_fop(lua_State *L, luadevice_t *luadev, const char *fop, int nargs, int nresults)
{
int base = lua_gettop(L) - nargs;
int ret = -ENXIO;
if (lunatik_getregistry(L, luadev) != LUA_TTABLE) {
pr_err("%s: couldn't find driver\n", fop);
goto err;
}
lunatik_optcfunction(L, -1, fop, lunatik_nop);
lua_insert(L,
gitextract_tvyvzgq9/
├── .editorconfig
├── .github/
│ └── workflows/
│ ├── build.yaml
│ └── doc.yml
├── .gitignore
├── .gitmodules
├── Kbuild
├── Kconfig
├── LICENSE-GPL
├── LICENSE-MIT
├── Makefile
├── README.md
├── autogen/
│ ├── linux/
│ │ └── .gitignore
│ └── lunatik/
│ └── .gitignore
├── bin/
│ └── lunatik
├── config.ld
├── configure.lua
├── doc/
│ └── capi.md
├── driver.lua
├── examples/
│ ├── cpuexporter.lua
│ ├── dnsblock/
│ │ ├── common.lua
│ │ └── nf_dnsblock.lua
│ ├── dnsdoctor/
│ │ ├── cleanup.sh
│ │ ├── common.lua
│ │ ├── nf_dnsdoctor.lua
│ │ └── setup.sh
│ ├── echod/
│ │ ├── daemon.lua
│ │ └── worker.lua
│ ├── filter/
│ │ ├── Makefile
│ │ ├── https.c
│ │ └── sni.lua
│ ├── gesture.lua
│ ├── keylocker.lua
│ ├── lldpd.lua
│ ├── shared.lua
│ ├── spyglass.lua
│ ├── systrack.lua
│ ├── tap.lua
│ ├── tcpreject/
│ │ ├── cleanup.sh
│ │ ├── nf_tcpreject.lua
│ │ └── setup.sh
│ └── xiaomi.lua
├── gensymbols.sh
├── include/
│ ├── assert.h
│ ├── ctype.h
│ ├── errno.h
│ ├── float.h
│ ├── klibc/
│ │ └── diverr.h
│ ├── limits.h
│ ├── locale.h
│ ├── math.h
│ ├── setjmp.h
│ ├── stdarg.h
│ ├── stddef.h
│ ├── stdint.h
│ ├── stdio.h
│ ├── stdlib.h
│ ├── string.h
│ └── time.h
├── lib/
│ ├── Kbuild
│ ├── crypto/
│ │ └── hkdf.lua
│ ├── lighten.lua
│ ├── luabyteorder.c
│ ├── luacompletion.c
│ ├── luacpu.c
│ ├── luacrypto.h
│ ├── luacrypto_aead.c
│ ├── luacrypto_comp.c
│ ├── luacrypto_core.c
│ ├── luacrypto_rng.c
│ ├── luacrypto_shash.c
│ ├── luacrypto_skcipher.c
│ ├── luadarken.c
│ ├── luadata.c
│ ├── luadata.h
│ ├── luadevice.c
│ ├── luafib.c
│ ├── luafifo.c
│ ├── luahid.c
│ ├── lualinux.c
│ ├── luanetfilter.c
│ ├── luanetfilter.h
│ ├── luanotifier.c
│ ├── luaprobe.c
│ ├── luarcu.c
│ ├── luarcu.h
│ ├── luasignal.c
│ ├── luaskb.c
│ ├── luaskb.h
│ ├── luaskel.c
│ ├── luasocket.c
│ ├── luasyscall.c
│ ├── luathread.c
│ ├── luaxdp.c
│ ├── lunatik/
│ │ └── runner.lua
│ ├── mailbox.lua
│ ├── net.lua
│ ├── socket/
│ │ ├── inet.lua
│ │ ├── raw.lua
│ │ └── unix.lua
│ ├── syscall/
│ │ └── table.lua
│ └── util.lua
├── lunatik.h
├── lunatik_aux.c
├── lunatik_conf.h
├── lunatik_core.c
├── lunatik_obj.c
├── lunatik_run.c
├── lunatik_val.c
├── lunatik_val.h
├── tests/
│ ├── README.md
│ ├── crypto/
│ │ ├── aead.lua
│ │ ├── comp.lua
│ │ ├── hkdf.lua
│ │ ├── rng.lua
│ │ ├── run.sh
│ │ ├── shash.lua
│ │ └── skcipher.lua
│ ├── io/
│ │ ├── softirq.lua
│ │ ├── test.lua
│ │ └── test.sh
│ ├── lib.sh
│ ├── monitor/
│ │ ├── gc.lua
│ │ ├── gc.sh
│ │ └── run.sh
│ ├── rcu/
│ │ ├── map_sync.lua
│ │ ├── map_sync.sh
│ │ ├── map_sync_clean.lua
│ │ ├── map_values.lua
│ │ └── run.sh
│ ├── run.sh
│ ├── runtime/
│ │ ├── opt_guards.lua
│ │ ├── opt_guards.sh
│ │ ├── opt_guards_recv.lua
│ │ ├── opt_skb_single.lua
│ │ ├── opt_skb_single.sh
│ │ ├── rcu_shared.lua
│ │ ├── rcu_shared.sh
│ │ ├── rcu_shared_recv.lua
│ │ ├── refcnt_leak.lua
│ │ ├── refcnt_leak.sh
│ │ ├── resume_mailbox.lua
│ │ ├── resume_mailbox.sh
│ │ ├── resume_mailbox_send.lua
│ │ ├── resume_shared.lua
│ │ ├── resume_shared.sh
│ │ ├── resume_shared_recv.lua
│ │ └── run.sh
│ ├── socket/
│ │ ├── run.sh
│ │ └── unix/
│ │ ├── dgram.sh
│ │ ├── dgram_client.lua
│ │ ├── dgram_server.lua
│ │ ├── run.sh
│ │ ├── stream.sh
│ │ ├── stream_client.lua
│ │ └── stream_server.lua
│ └── thread/
│ ├── dummy.lua
│ ├── run.sh
│ ├── run_during_load.lua
│ ├── run_during_load.sh
│ ├── shouldstop.lua
│ ├── shouldstop.sh
│ └── shouldstop_run.lua
└── tools/
├── Readme.md
├── debian_kernel_postinst_lunatik.sh
└── shade.sh
SYMBOL INDEX (345 symbols across 40 files)
FILE: examples/filter/https.c
type xdp_md (line 10) | struct xdp_md
type bpf_luaxdp_arg (line 14) | struct bpf_luaxdp_arg {
function filter_https (line 19) | int filter_https(struct xdp_md *ctx)
FILE: include/klibc/diverr.h
function __divide_error (line 11) | static __inline__ void __divide_error(void) {}
FILE: include/stdio.h
type FILE (line 32) | typedef struct {
function FILE (line 43) | static inline FILE *fopen(const char *path, const char *mode)
function fclose (line 78) | static inline int fclose(FILE *f)
function fill (line 85) | static inline int fill(FILE *f)
function getc (line 101) | static inline int getc(FILE *f)
function ungetc (line 112) | static inline int ungetc(int c, FILE *f)
function fread (line 121) | static inline size_t fread(void *ptr, size_t sz, size_t nmemb, FILE *f)
function fwrite (line 147) | static inline size_t fwrite(const void *ptr, size_t sz, size_t nmemb, FI...
function seek (line 162) | static inline int seek(FILE *f, loff_t off, int whence)
FILE: lib/luabyteorder.c
function luabyteorder_init (line 179) | static int __init luabyteorder_init(void)
function luabyteorder_exit (line 184) | static void __exit luabyteorder_exit(void)
FILE: lib/luacompletion.c
function luacompletion_complete (line 37) | static int luacompletion_complete(lua_State *L)
function luacompletion_wait (line 70) | static int luacompletion_wait(lua_State *L)
function luacompletion_new (line 129) | static int luacompletion_new(lua_State *L)
function luacompletion_init (line 141) | static int __init luacompletion_init(void)
function luacompletion_exit (line 146) | static void __exit luacompletion_exit(void)
FILE: lib/luacpu.c
function luacpu_stats (line 56) | static int luacpu_stats(lua_State *L)
function luacpu_init (line 130) | static int __init luacpu_init(void)
function luacpu_exit (line 135) | static void __exit luacpu_exit(void)
FILE: lib/luacrypto_aead.c
function luacrypto_aead_setkey (line 30) | static int luacrypto_aead_setkey(lua_State *L)
function luacrypto_aead_setauthsize (line 45) | static int luacrypto_aead_setauthsize(lua_State *L)
function luacrypto_aead_ivsize (line 58) | static int luacrypto_aead_ivsize(lua_State *L)
function luacrypto_aead_authsize (line 70) | static int luacrypto_aead_authsize(lua_State *L)
type luacrypto_aead_request_t (line 77) | typedef struct luacrypto_aead_request_s {
function luacrypto_aead_newrequest (line 88) | static inline void luacrypto_aead_newrequest(lua_State *L, luacrypto_aea...
function luacrypto_aead_setrequest (line 113) | static inline void luacrypto_aead_setrequest(luacrypto_aead_request_t *r...
function luacrypto_aead_request_free (line 129) | static inline void luacrypto_aead_request_free(luacrypto_aead_request_t ...
function luacrypto_aead_finish (line 146) | static inline int luacrypto_aead_finish(lua_State *L, luacrypto_aead_req...
function luacrypto_aead_encrypt (line 169) | static int luacrypto_aead_encrypt(lua_State *L)
function luacrypto_aead_decrypt (line 189) | static int luacrypto_aead_decrypt(lua_State *L)
function luacrypto_aead_algname (line 203) | static int luacrypto_aead_algname(lua_State *L)
FILE: lib/luacrypto_core.c
function luacrypto_init (line 39) | static int __init luacrypto_init(void)
function luacrypto_exit (line 44) | static void __exit luacrypto_exit(void)
FILE: lib/luacrypto_rng.c
function luacrypto_rng_generate (line 32) | static int luacrypto_rng_generate(lua_State *L)
function luacrypto_rng_reset (line 54) | static int luacrypto_rng_reset(lua_State *L)
function luacrypto_rng_getbytes (line 70) | static int luacrypto_rng_getbytes(lua_State *L)
function luacrypto_rng_info (line 88) | static int luacrypto_rng_info(lua_State *L)
function luacrypto_rng_algname (line 103) | static int luacrypto_rng_algname(lua_State *L)
function luacrypto_rng_new (line 138) | int luacrypto_rng_new(lua_State *L)
FILE: lib/luacrypto_shash.c
function luacrypto_shash_release (line 21) | static void luacrypto_shash_release(void *private)
function luacrypto_shash_digestsize (line 36) | static int luacrypto_shash_digestsize(lua_State *L)
function luacrypto_shash_setkey (line 49) | static int luacrypto_shash_setkey(lua_State *L)
function luacrypto_shash_digest (line 65) | static int luacrypto_shash_digest(lua_State *L)
function luacrypto_shash_init_mt (line 84) | static int luacrypto_shash_init_mt(lua_State *L)
function luacrypto_shash_update (line 98) | static int luacrypto_shash_update(lua_State *L)
function luacrypto_shash_final (line 114) | static int luacrypto_shash_final(lua_State *L)
function luacrypto_shash_finup (line 133) | static int luacrypto_shash_finup(lua_State *L)
function luacrypto_shash_export (line 152) | static int luacrypto_shash_export(lua_State *L)
function luacrypto_shash_import (line 169) | static int luacrypto_shash_import(lua_State *L)
function luacrypto_shash_algname (line 181) | static int luacrypto_shash_algname(lua_State *L)
function luacrypto_shash_new (line 221) | int luacrypto_shash_new(lua_State *L)
FILE: lib/luacrypto_skcipher.c
function luacrypto_skcipher_setkey (line 30) | static int luacrypto_skcipher_setkey(lua_State *L)
function luacrypto_skcipher_ivsize (line 44) | static int luacrypto_skcipher_ivsize(lua_State *L)
function luacrypto_skcipher_blocksize (line 56) | static int luacrypto_skcipher_blocksize(lua_State *L)
type luacrypto_skcipher_request_t (line 63) | typedef struct luacrypto_skcipher_request_s {
function luacrypto_skcipher_newrequest (line 71) | static inline void luacrypto_skcipher_newrequest(lua_State *L, luacrypto...
function luacrypto_skcipher_setrequest (line 94) | static inline void luacrypto_skcipher_setrequest(luacrypto_skcipher_requ...
function luacrypto_skcipher_crypt (line 108) | static int luacrypto_skcipher_crypt(lua_State *L, int (*crypt)(struct sk...
function luacrypto_skcipher_encrypt (line 141) | static int luacrypto_skcipher_encrypt(lua_State *L)
function luacrypto_skcipher_decrypt (line 154) | static int luacrypto_skcipher_decrypt(lua_State *L)
function luacrypto_skcipher_algname (line 159) | static int luacrypto_skcipher_algname(lua_State *L)
FILE: lib/luadarken.c
type luadarken_request_t (line 28) | typedef struct luadarken_request_s {
function luadarken_freerequest (line 34) | static void luadarken_freerequest(luadarken_request_t *r)
type crypto_skcipher (line 43) | struct crypto_skcipher
type crypto_skcipher (line 45) | struct crypto_skcipher
type scatterlist (line 76) | struct scatterlist
function luadarken_decrypt (line 88) | static void luadarken_decrypt(lua_State *L, luadarken_request_t *r)
function luadarken_run (line 106) | static int luadarken_run(lua_State *L)
function luadarken_init (line 138) | static int __init luadarken_init(void)
function luadarken_exit (line 143) | static void __exit luadarken_exit(void)
FILE: lib/luadata.c
type luadata_t (line 20) | typedef struct luadata_s {
function luadata_getstring (line 81) | static int luadata_getstring(lua_State *L)
function luadata_setstring (line 98) | static int luadata_setstring(lua_State *L)
function luadata_checksum (line 118) | static int luadata_checksum(lua_State *L)
function luadata_resize (line 135) | static int luadata_resize(lua_State *L)
function luadata_length (line 155) | static int luadata_length(lua_State *L)
function luadata_tostring (line 166) | static int luadata_tostring(lua_State *L)
function luadata_release (line 173) | static void luadata_release(void *private)
function luadata_set (line 335) | static inline void luadata_set(luadata_t *data, void *ptr, size_t size, ...
function luadata_lnew (line 342) | static int luadata_lnew(lua_State *L)
function lunatik_object_t (line 358) | lunatik_object_t *luadata_new(lua_State *L, lunatik_opt_t opt)
function luadata_reset (line 366) | int luadata_reset(lunatik_object_t *object, void *ptr, size_t size, uint...
function luadata_init (line 386) | static int __init luadata_init(void)
function luadata_exit (line 391) | static void __exit luadata_exit(void)
FILE: lib/luadata.h
function luadata_close (line 21) | static inline void luadata_close(lunatik_object_t *object)
FILE: lib/luadevice.c
type class (line 29) | struct class
type luadevice_t (line 38) | typedef struct luadevice_s {
function luadevice_listadd (line 54) | static inline void luadevice_listadd(luadevice_t *luadev)
function luadevice_listdel (line 61) | static inline void luadevice_listdel(luadevice_t *luadev)
function luadevice_t (line 68) | static inline luadevice_t *luadevice_find(dev_t devt)
function luadevice_fop (line 82) | static int luadevice_fop(lua_State *L, luadevice_t *luadev, const char *...
function luadevice_doopen (line 108) | static int luadevice_doopen(lua_State *L, luadevice_t *luadev)
function luadevice_doread (line 113) | static ssize_t luadevice_doread(lua_State *L, luadevice_t *luadev, char ...
function luadevice_dowrite (line 133) | static ssize_t luadevice_dowrite(lua_State *L, luadevice_t *luadev, cons...
function luadevice_dorelease (line 158) | static int luadevice_dorelease(lua_State *L, luadevice_t *luadev)
function luadevice_fop_open (line 168) | static int luadevice_fop_open(struct inode *inode, struct file *f)
function luadevice_fop_read (line 182) | static ssize_t luadevice_fop_read(struct file *f, char *buf, size_t len,...
function luadevice_fop_write (line 189) | static ssize_t luadevice_fop_write(struct file *f, const char *buf, size...
function luadevice_fop_release (line 196) | static int luadevice_fop_release(struct inode *inode, struct file *f)
type file_operations (line 204) | struct file_operations
function luadevice_delete (line 213) | static void luadevice_delete(luadevice_t *luadev)
function luadevice_release (line 228) | static void luadevice_release(void *private)
function luadevice_stop (line 257) | static int luadevice_stop(lua_State *L)
function luadevice_new (line 345) | static int luadevice_new(lua_State *L)
type device (line 392) | struct device
type device (line 394) | struct device
function luadevice_init (line 417) | static int __init luadevice_init(void)
function luadevice_exit (line 432) | static void __exit luadevice_exit(void)
FILE: lib/luafib.c
type luafib_rule_t (line 26) | typedef struct luafib_rule_s {
function luafib_nl_rule (line 37) | static int luafib_nl_rule(luafib_rule_t *rule)
function luafib_init (line 144) | static int __init luafib_init(void)
function luafib_exit (line 149) | static void __exit luafib_exit(void)
FILE: lib/luafifo.c
function luafifo_push (line 33) | static int luafifo_push(lua_State *L)
function luafifo_pop (line 59) | static int luafifo_pop(lua_State *L)
function luafifo_release (line 72) | static void luafifo_release(void *private)
function luafifo_new (line 128) | static int luafifo_new(lua_State *L)
function luafifo_init (line 143) | static int __init luafifo_init(void)
function luafifo_exit (line 148) | static void __exit luafifo_exit(void)
FILE: lib/luahid.c
type luahid_t (line 24) | typedef struct luahid_s {
type luahid_ctx_t (line 31) | typedef struct luahid_ctx_s {
function luahid_release (line 42) | static void luahid_release(void *private)
type hid_device_id (line 78) | struct hid_device_id
type hid_device_id (line 81) | struct hid_device_id
type hid_device_id (line 81) | struct hid_device_id
type hid_device_id (line 83) | struct hid_device_id
type hid_device_id (line 102) | struct hid_device_id
function luahid_pcall (line 114) | static inline int luahid_pcall(lua_State *L, lua_CFunction op, luahid_ct...
function luahid_pushhdev (line 141) | static inline void luahid_pushhdev(lua_State *L, const struct hid_device...
function luahid_pushreport (line 148) | static inline void luahid_pushreport(lua_State *L, const struct hid_repo...
function luahid_t (line 158) | static luahid_t *luahid_gethid(struct hid_device *hdev)
function lunatik_object_t (line 166) | static inline lunatik_object_t *luahid_pushdata(lua_State *L, luahid_ctx...
function luahid_op (line 180) | static void luahid_op(lua_State *L, luahid_ctx_t *ctx, int nargs)
function luahid_doprobe (line 202) | static int luahid_doprobe(lua_State *L)
function luahid_probe (line 211) | static int luahid_probe(struct hid_device *hdev, const struct hid_device...
function luahid_doreport_fixup (line 225) | static int luahid_doreport_fixup(lua_State *L)
type __u8 (line 238) | typedef const __u8 * luahid_rdesc_t;
type __u8 (line 240) | typedef __u8 * luahid_rdesc_t;
function luahid_rdesc_t (line 243) | static luahid_rdesc_t luahid_report_fixup(struct hid_device *hdev, __u8 ...
function luahid_doraw_event (line 253) | static int luahid_doraw_event(lua_State *L)
function luahid_raw_event (line 266) | static int luahid_raw_event(struct hid_device *hdev, struct hid_report *...
function luahid_register (line 284) | static int luahid_register(lua_State *L)
function luahid_init (line 318) | static int __init luahid_init(void)
function luahid_exit (line 323) | static void __exit luahid_exit(void)
FILE: lib/lualinux.c
function lualinux_random (line 43) | static int lualinux_random(lua_State *L)
function lualinux_schedule (line 93) | static int lualinux_schedule(lua_State *L)
function lualinux_tracing (line 123) | static int lualinux_tracing(lua_State *L)
function lualinux_time (line 143) | static int lualinux_time(lua_State *L)
function lualinux_difftime (line 157) | static int lualinux_difftime(lua_State *L)
function lualinux_lookup (line 177) | static int lualinux_lookup(lua_State *L)
function lualinux_ifindex (line 196) | static int lualinux_ifindex(lua_State *L)
function lualinux_ifaddr (line 218) | static int lualinux_ifaddr(lua_State *L)
function lualinux_errname (line 296) | static int lualinux_errname(lua_State *L)
function lualinux_init (line 324) | static int __init lualinux_init(void)
function lualinux_exit (line 329) | static void __exit lualinux_exit(void)
FILE: lib/luanetfilter.c
type luanetfilter_t (line 23) | typedef struct luanetfilter_s {
function luanetfilter_pushcb (line 32) | static inline bool luanetfilter_pushcb(lua_State *L, luanetfilter_t *luanf)
function lunatik_object_t (line 46) | static inline lunatik_object_t *luanetfilter_pushskb(lua_State *L, luane...
function luanetfilter_hook_cb (line 63) | static int luanetfilter_hook_cb(lua_State *L, luanetfilter_t *luanf, str...
function luanetfilter_docall (line 86) | static inline unsigned int luanetfilter_docall(luanetfilter_t *luanf, st...
function luanetfilter_hook (line 105) | static unsigned int luanetfilter_hook(void *priv, struct sk_buff *skb, c...
function luanetfilter_register (line 130) | static int luanetfilter_register(lua_State *L)
function luanetfilter_release (line 164) | static void luanetfilter_release(void *private)
function luanetfilter_init (line 180) | static int __init luanetfilter_init(void)
function luanetfilter_exit (line 185) | static void __exit luanetfilter_exit(void)
FILE: lib/luanotifier.c
type notifier_block (line 23) | struct notifier_block
type luanotifier_t (line 34) | typedef struct luanotifier_s {
function luanotifier_keyboard_handler (line 42) | static int luanotifier_keyboard_handler(lua_State *L, void *data)
function luanotifier_netdevice_handler (line 52) | static int luanotifier_netdevice_handler(lua_State *L, void *data)
function luanotifier_vt_handler (line 60) | static int luanotifier_vt_handler (lua_State* L, void* data)
function luanotifier_handler (line 69) | static int luanotifier_handler(lua_State *L, luanotifier_t *notifier, un...
function luanotifier_call (line 93) | static int luanotifier_call(struct notifier_block *nb, unsigned long eve...
function luanotifier_release (line 176) | static void luanotifier_release(void *private)
function luanotifier_checkrunning (line 189) | static inline void luanotifier_checkrunning(lua_State *L, luanotifier_t ...
function luanotifier_stop (line 204) | static int luanotifier_stop(lua_State *L)
function luanotifier_delete (line 223) | static int luanotifier_delete(lua_State *L)
function luanotifier_new (line 403) | static int luanotifier_new(lua_State *L, luanotifier_register_t register...
function luanotifier_init (line 436) | static int __init luanotifier_init(void)
function luanotifier_exit (line 441) | static void __exit luanotifier_exit(void)
FILE: lib/luaprobe.c
type luaprobe_t (line 29) | typedef struct luaprobe_s {
type pt_regs (line 34) | struct pt_regs
function luaprobe_dump (line 36) | static int luaprobe_dump(lua_State *L)
function luaprobe_handler (line 46) | static int luaprobe_handler(lua_State *L, luaprobe_t *probe, const char ...
function luaprobe_pre_handler (line 77) | static int __kprobes luaprobe_pre_handler(struct kprobe *kp, struct pt_r...
function luaprobe_post_handler (line 86) | static void __kprobes luaprobe_post_handler(struct kprobe *kp, struct pt...
function luaprobe_delete (line 96) | static void luaprobe_delete(luaprobe_t *probe)
function luaprobe_release (line 114) | static void luaprobe_release(void *private)
function luaprobe_stop (line 132) | static int luaprobe_stop(lua_State *L)
function luaprobe_enable (line 156) | static int luaprobe_enable(lua_State *L)
function luaprobe_new (line 237) | static int luaprobe_new(lua_State *L)
function luaprobe_init (line 276) | static int __init luaprobe_init(void)
function luaprobe_exit (line 283) | static void __exit luaprobe_exit(void)
FILE: lib/luarcu.c
type luarcu_entry_t (line 27) | typedef struct luarcu_entry_s {
type luarcu_table_t (line 47) | typedef struct luarcu_table_s {
function luarcu_entry_t (line 69) | static inline luarcu_entry_t *luarcu_lookup(luarcu_table_t *table, unsig...
function luarcu_entry_t (line 80) | static luarcu_entry_t *luarcu_newentry(const char *key, size_t keylen, l...
function luarcu_free (line 95) | static inline void luarcu_free(luarcu_entry_t *entry)
function luarcu_getvalue (line 104) | void luarcu_getvalue(lunatik_object_t *table, const char *key, size_t ke...
function luarcu_setvalue (line 122) | int luarcu_setvalue(lunatik_object_t *table, const char *key, size_t key...
function luarcu_index (line 163) | static int luarcu_index(lua_State *L)
function luarcu_newindex (line 183) | static int luarcu_newindex(lua_State *L)
function luarcu_release (line 196) | static void luarcu_release(void *private)
function luarcu_inittable (line 208) | static inline void luarcu_inittable(luarcu_table_t *table, size_t size)
function luarcu_map_handle (line 215) | static int luarcu_map_handle(lua_State *L)
function luarcu_map_call (line 231) | static inline int luarcu_map_call(lua_State *L, int cb, const char *key,...
function luarcu_map (line 248) | static int luarcu_map(lua_State *L)
type luaL_Reg (line 277) | struct luaL_Reg
type luaL_Reg (line 283) | struct luaL_Reg
function lunatik_object_t (line 297) | lunatik_object_t *luarcu_newtable(size_t size, lunatik_opt_t opt)
function luarcu_table (line 318) | static int luarcu_table(lua_State *L)
function luarcu_init (line 330) | static int __init luarcu_init(void)
function luarcu_exit (line 335) | static void __exit luarcu_exit(void)
FILE: lib/luarcu.h
function lunatik_object_t (line 15) | static inline lunatik_object_t *luarcu_getobject(lunatik_object_t *table...
function luarcu_setobject (line 22) | static inline int luarcu_setobject(lunatik_object_t *table, const char *...
FILE: lib/luasignal.c
function luasignal_sigmask (line 27) | static int luasignal_sigmask(lua_State *L)
function luasignal_sigpending (line 47) | static int luasignal_sigpending(lua_State *L)
function luasignal_sigstate (line 64) | static int luasignal_sigstate(lua_State *L)
function luasignal_kill (line 106) | static int luasignal_kill(lua_State *L)
function luasignal_init (line 181) | static int __init luasignal_init(void)
function luasignal_exit (line 186) | static void __exit luasignal_exit(void)
FILE: lib/luaskb.c
function luaskb_len (line 55) | static int luaskb_len(lua_State *L)
function luaskb_ifindex (line 66) | static int luaskb_ifindex(lua_State *L)
function luaskb_vlan (line 78) | static int luaskb_vlan(lua_State *L)
function luaskb_data (line 95) | static int luaskb_data(lua_State *L)
function luaskb_resize (line 128) | static int luaskb_resize(lua_State *L)
function luaskb_csum (line 145) | static inline void luaskb_csum(struct sk_buff *skb, u8 proto, __sum16 csum)
function luaskb_checksum (line 157) | static int luaskb_checksum(lua_State *L)
function luaskb_forward (line 182) | static int luaskb_forward(lua_State *L)
function luaskb_release (line 200) | static void luaskb_release(void *private)
function luaskb_copy (line 241) | static int luaskb_copy(lua_State *L)
function lunatik_object_t (line 253) | lunatik_object_t *luaskb_new(lua_State *L)
function luaskb_init (line 269) | static int __init luaskb_init(void)
function luaskb_exit (line 274) | static void __exit luaskb_exit(void)
FILE: lib/luaskb.h
type luaskb_t (line 12) | typedef struct {
function luaskb_clear (line 19) | static inline void luaskb_clear(lunatik_object_t *object)
FILE: lib/luaskel.c
type luaskel_t (line 10) | typedef struct luaskel_s {
function luaskel_nop (line 16) | static int luaskel_nop(lua_State *L)
function luaskel_release (line 23) | static void luaskel_release(void *private)
function luaskel_new (line 49) | static int luaskel_new(lua_State *L)
function luaskel_init (line 60) | static int __init luaskel_init(void)
function luaskel_exit (line 65) | static void __exit luaskel_exit(void)
FILE: lib/luasocket.c
function luasocket_checkaddr (line 49) | static size_t luasocket_checkaddr(lua_State *L, struct socket *socket, s...
function luasocket_pushaddr (line 84) | static int luasocket_pushaddr(lua_State *L, struct sockaddr_storage *addr)
function luasocket_send (line 137) | static int luasocket_send(lua_State *L)
function luasocket_receive (line 188) | static int luasocket_receive(lua_State *L)
function luasocket_bind (line 245) | static int luasocket_bind(lua_State *L)
function luasocket_listen (line 271) | static int luasocket_listen(lua_State *L)
function luasocket_connect (line 300) | static int luasocket_connect(lua_State *L)
function luasocket_release (line 370) | static void luasocket_release(void *private)
function luasocket_accept (line 711) | static int luasocket_accept(lua_State *L)
function luasocket_new (line 741) | static int luasocket_new(lua_State *L)
function luasocket_init (line 755) | static int __init luasocket_init(void)
function luasocket_exit (line 760) | static void __exit luasocket_exit(void)
FILE: lib/luasyscall.c
function luasyscall_address (line 34) | static int luasyscall_address(lua_State *L)
function luasyscall_init (line 856) | static int __init luasyscall_init(void)
function luasyscall_exit (line 863) | static void __exit luasyscall_exit(void)
FILE: lib/luathread.c
type luathread_t (line 21) | typedef struct luathread_s {
function luathread_resume (line 29) | static int luathread_resume(lua_State *L, luathread_t *thread)
function luathread_func (line 42) | static int luathread_func(void *data)
function luathread_shouldstop (line 74) | static int luathread_shouldstop(lua_State *L)
function luathread_stop (line 89) | static int luathread_stop(lua_State *L)
function luathread_task (line 123) | static int luathread_task(lua_State *L)
function luathread_run (line 181) | static int luathread_run(lua_State *L)
function luathread_current (line 210) | static int luathread_current(lua_State *L)
function luathread_init (line 223) | static int __init luathread_init(void)
function luathread_exit (line 228) | static void __exit luathread_exit(void)
FILE: lib/luaxdp.c
function lunatik_object_t (line 42) | static inline lunatik_object_t *luaxdp_pushdata(lua_State *L, int upvalu...
function luaxdp_callback (line 52) | static int luaxdp_callback(lua_State *L)
function luaxdp_handler (line 74) | static int luaxdp_handler(lua_State *L, struct xdp_buff *ctx, void *arg,...
function luaxdp_checkruntimes (line 97) | static inline int luaxdp_checkruntimes(void)
function __bpf_kfunc (line 106) | __bpf_kfunc int bpf_luaxdp_run(char *key, size_t key__sz, struct xdp_md ...
function BTF_ID_FLAGS (line 137) | BTF_KFUNCS_START(bpf_luaxdp_set)
function luaxdp_attach (line 212) | static int luaxdp_attach(lua_State *L)
function luaxdp_init (line 264) | static int __init luaxdp_init(void)
function luaxdp_exit (line 273) | static void __exit luaxdp_exit(void)
FILE: lunatik.h
type u8 (line 20) | typedef u8 __bitwise lunatik_opt_t;
function lunatik_isready (line 50) | static inline bool lunatik_isready(lua_State *L)
type lunatik_reg_t (line 77) | typedef struct lunatik_reg_s {
type lunatik_namespace_t (line 82) | typedef struct lunatik_namespace_s {
type lunatik_class_t (line 87) | typedef struct lunatik_class_s {
type lunatik_object_t (line 94) | typedef struct lunatik_object_s {
function lunatik_trylock (line 108) | static inline int lunatik_trylock(lunatik_object_t *object)
function lunatik_nop (line 117) | static inline int lunatik_nop(lua_State *L)
function lunatik_throw (line 154) | static inline void lunatik_throw(lua_State *L, int ret)
function lunatik_checkfield (line 172) | static inline void lunatik_checkfield(lua_State *L, int idx, const char ...
function lunatik_object_t (line 186) | static inline lunatik_object_t *lunatik_checkruntime(lua_State *L, lunat...
function lunatik_checkclass (line 197) | static inline void lunatik_checkclass(lua_State *L, const lunatik_class_...
function lunatik_setclass (line 203) | static inline void lunatik_setclass(lua_State *L, const lunatik_class_t ...
function lunatik_setobject (line 213) | static inline void lunatik_setobject(lunatik_object_t *object, const lun...
type kref (line 227) | struct kref
function lunatik_require (line 239) | static inline void lunatik_require(lua_State *L, const char *libname)
function lunatik_pushobject (line 246) | static inline void lunatik_pushobject(lua_State *L, lunatik_object_t *ob...
function lunatik_hasindex (line 252) | static inline bool lunatik_hasindex(lua_State *L, int index)
function lunatik_newclass (line 259) | static inline void lunatik_newclass(lua_State *L, const lunatik_class_t ...
function lunatik_class_t (line 273) | static inline lunatik_class_t *lunatik_getclass(lua_State *L, int ix)
function lunatik_isobject (line 283) | static inline bool lunatik_isobject(lua_State *L, int ix, lunatik_object...
function lunatik_object_t (line 289) | static inline lunatik_object_t **lunatik_testobject(lua_State *L, int ix)
function lunatik_object_t (line 295) | static inline lunatik_object_t **lunatik_checkpobject(lua_State *L, int ix)
function lunatik_newnamespaces (line 302) | static inline void lunatik_newnamespaces(lua_State *L, const lunatik_nam...
function lunatik_newclasses (line 318) | static inline void lunatik_newclasses(lua_State *L, const lunatik_class_...
function lunatik_optcfunction (line 388) | static inline void lunatik_optcfunction(lua_State *L, int idx, const cha...
function lua_Integer (line 399) | static inline lua_Integer lunatik_checkinteger(lua_State *L, int idx, lu...
function lunatik_register (line 406) | static inline void lunatik_register(lua_State *L, int ix, void *key)
function lunatik_unregister (line 412) | static inline void lunatik_unregister(lua_State *L, void *key)
function lunatik_registerobject (line 418) | static inline void lunatik_registerobject(lua_State *L, int ix, lunatik_...
function lunatik_unregisterobject (line 424) | static inline void lunatik_unregisterobject(lua_State *L, lunatik_object...
FILE: lunatik_aux.c
type lunatik_file (line 18) | typedef struct lunatik_file {
function lunatik_loadfile (line 36) | int lunatik_loadfile(lua_State *L, const char *filename, const char *mode)
function lunatik_pusherrname (line 70) | void lunatik_pusherrname(lua_State *L, int err)
type kprobe (line 95) | struct kprobe
FILE: lunatik_conf.h
type lua_State (line 51) | typedef struct lua_State lua_State;
FILE: lunatik_core.c
function lunatik_setversion (line 33) | static inline void lunatik_setversion(lua_State *L)
function lunatik_runerror (line 69) | static inline void lunatik_runerror(lua_State *L, const char *errmsg)
function lunatik_releaseruntime (line 77) | static void lunatik_releaseruntime(void *private)
function lunatik_stop (line 83) | int lunatik_stop(lunatik_object_t *runtime)
function lunatik_lcopyobjects (line 101) | static int lunatik_lcopyobjects(lua_State *L)
function lunatik_copyobjects (line 117) | static inline int lunatik_copyobjects(lua_State *Lto, lua_State *Lfrom, ...
function lunatik_resume (line 127) | static inline int lunatik_resume(lua_State *Lto, lua_State *Lfrom, int n...
function lunatik_lresume (line 141) | static int lunatik_lresume(lua_State *L)
function lunatik_setready (line 192) | static inline void lunatik_setready(lua_State *L)
function lunatik_runscript (line 198) | static int lunatik_runscript(lua_State *L)
function lunatik_newruntime (line 229) | static int lunatik_newruntime(lunatik_object_t **pruntime, lua_State *Lf...
function lunatik_runtime (line 271) | int lunatik_runtime(lunatik_object_t **pruntime, const char *script, lun...
function lunatik_lruntime (line 288) | static int lunatik_lruntime(lua_State *L)
function lunatik_init (line 308) | static int __init lunatik_init(void)
function lunatik_exit (line 313) | static void __exit lunatik_exit(void)
FILE: lunatik_obj.c
function lunatik_object_t (line 19) | lunatik_object_t *lunatik_newobject(lua_State *L, const lunatik_class_t ...
function lunatik_object_t (line 37) | lunatik_object_t *lunatik_createobject(const lunatik_class_t *class, siz...
function lunatik_cloneobject (line 55) | void lunatik_cloneobject(lua_State *L, lunatik_object_t *object)
function lunatik_releaseprivate (line 71) | static inline void lunatik_releaseprivate(const lunatik_class_t *class, ...
function lunatik_closeobject (line 81) | int lunatik_closeobject(lua_State *L)
function lunatik_releaseobject (line 97) | void lunatik_releaseobject(struct kref *kref)
function lunatik_deleteobject (line 110) | int lunatik_deleteobject(lua_State *L)
function lunatik_fixerror (line 122) | inline static void lunatik_fixerror(lua_State *L, const char *method)
function lunatik_monitor (line 133) | static int lunatik_monitor(lua_State *L)
function lunatik_monitorobject (line 154) | void lunatik_monitorobject(lua_State *L, const lunatik_class_t *class)
FILE: lunatik_run.c
function lunatik_run_init (line 17) | static int __init lunatik_run_init(void)
function lunatik_run_exit (line 32) | static void __exit lunatik_run_exit(void)
FILE: lunatik_val.c
function lunatik_checkvalue (line 8) | void lunatik_checkvalue(lua_State *L, int ix, lunatik_value_t *value)
function lunatik_doclone (line 32) | static int lunatik_doclone(lua_State *L)
function lunatik_pushvalue (line 39) | void lunatik_pushvalue(lua_State *L, lunatik_value_t *value)
FILE: lunatik_val.h
type lunatik_value_t (line 9) | typedef struct lunatik_value_s {
Condensed preview — 165 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (542K chars).
[
{
"path": ".editorconfig",
"chars": 114,
"preview": "root = true\n\n[*]\nindent_style = tab\nindent_size = tab\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n"
},
{
"path": ".github/workflows/build.yaml",
"chars": 1926,
"preview": "# Based on https://gist.github.com/domenic/ec8b0fc8ab45f39403dd\nname: Build Modules\non:\n pull_request:\n branches:\n "
},
{
"path": ".github/workflows/doc.yml",
"chars": 796,
"preview": "# Based on https://gist.github.com/domenic/ec8b0fc8ab45f39403dd\nname: Build Docs\non:\n pull_request:\n branches:\n -"
},
{
"path": ".gitignore",
"chars": 144,
"preview": "*.[aod]\n*.cmd\n*.ko\n*.mod\n*.mod.*\n*.so\nModule.symvers\nmodules.builtin\nmodules.order\nbuild/\nlunatik_sym.h\nmoontastik*\ndnst"
},
{
"path": ".gitmodules",
"chars": 158,
"preview": "[submodule \"lua\"]\n\tpath = lua\n\turl = https://github.com/luainkernel/lua.git\n[submodule \"klibc\"]\n\tpath = klibc\n\turl = htt"
},
{
"path": "Kbuild",
"chars": 1514,
"preview": "# SPDX-FileCopyrightText: (c) 2023-2026 Ring Zero Desenvolvimento de Software LTDA\n# SPDX-License-Identifier: MIT OR GPL"
},
{
"path": "Kconfig",
"chars": 3574,
"preview": "# SPDX-FileCopyrightText: (c) 2026 Tanmay Deobhankar <emailtotanmay@gmail.com>\n# SPDX-License-Identifier: MIT OR GPL-2.0"
},
{
"path": "LICENSE-GPL",
"chars": 18092,
"preview": " GNU GENERAL PUBLIC LICENSE\n Version 2, June 1991\n\n Copyright (C) 1989, 1991 Fr"
},
{
"path": "LICENSE-MIT",
"chars": 1104,
"preview": "MIT License\n\nCopyright (c) 2023-2025 Ring Zero Desenvolvimento de Software LTDA\n\nPermission is hereby granted, free of c"
},
{
"path": "Makefile",
"chars": 8267,
"preview": "# SPDX-FileCopyrightText: (c) 2023-2026 Ring Zero Desenvolvimento de Software LTDA\n# SPDX-License-Identifier: MIT OR GPL"
},
{
"path": "README.md",
"chars": 20537,
"preview": "# Lunatik\n\nLunatik is a framework for scripting the Linux kernel with [Lua](https://www.lua.org/).\nIt is composed by the"
},
{
"path": "autogen/linux/.gitignore",
"chars": 72,
"preview": "# Ignore everything in this directory\n*\n# Except this file\n!.gitignore\n\n"
},
{
"path": "autogen/lunatik/.gitignore",
"chars": 72,
"preview": "# Ignore everything in this directory\n*\n# Except this file\n!.gitignore\n\n"
},
{
"path": "bin/lunatik",
"chars": 4279,
"preview": "#!/usr/bin/lua5.4\n--\n-- SPDX-FileCopyrightText: (c) 2023-2026 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License"
},
{
"path": "config.ld",
"chars": 2427,
"preview": "-- LDoc configuration file for the Lunatik project\n-- Place this file at the root of your project and run 'ldoc .'\n\n-- T"
},
{
"path": "configure.lua",
"chars": 3416,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2026 Ashwani Kumar Kamal <ashwanikamal.im421@gmail.com>\n-- SPDX-License-Identifier: MI"
},
{
"path": "doc/capi.md",
"chars": 16241,
"preview": "# Lunatik C API\n\n```C\n#include <lunatik.h>\n```\n\n## Types\n\n### lunatik\\_class\\_t\n```C\ntypedef struct lunatik_class_s {\n\tc"
},
{
"path": "driver.lua",
"chars": 602,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2023-2026 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT O"
},
{
"path": "examples/cpuexporter.lua",
"chars": 4972,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2025-2026 Enderson Maia <endersonmaia@gmail.com>\n-- SPDX-License-Identifier: MIT OR GP"
},
{
"path": "examples/dnsblock/common.lua",
"chars": 1067,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2024 Mohammad Shehar Yaar Tausif <sheharyaar48@gmail.com>\n-- SPDX-License-Identifier: "
},
{
"path": "examples/dnsblock/nf_dnsblock.lua",
"chars": 761,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2024-2026 Mohammad Shehar Yaar Tausif <sheharyaar48@gmail.com>\n-- SPDX-License-Identif"
},
{
"path": "examples/dnsdoctor/cleanup.sh",
"chars": 960,
"preview": "# SPDX-FileCopyrightText: (c) 2024 Mohammad Shehar Yaar Tausif <sheharyaar48@gmail.com>\n# SPDX-License-Identifier: MIT O"
},
{
"path": "examples/dnsdoctor/common.lua",
"chars": 1343,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2024 Mohammad Shehar Yaar Tausif <sheharyaar48@gmail.com>\n-- SPDX-License-Identifier: "
},
{
"path": "examples/dnsdoctor/nf_dnsdoctor.lua",
"chars": 1172,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2024-2026 Mohammad Shehar Yaar Tausif <sheharyaar48@gmail.com>\n-- SPDX-License-Identif"
},
{
"path": "examples/dnsdoctor/setup.sh",
"chars": 1551,
"preview": "# SPDX-FileCopyrightText: (c) 2024 Mohammad Shehar Yaar Tausif <sheharyaar48@gmail.com>\n# SPDX-License-Identifier: MIT O"
},
{
"path": "examples/echod/daemon.lua",
"chars": 1113,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2023-2024 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT O"
},
{
"path": "examples/echod/worker.lua",
"chars": 850,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2023-2026 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT O"
},
{
"path": "examples/filter/Makefile",
"chars": 320,
"preview": "# SPDX-FileCopyrightText: (c) 2023-2024 Ring Zero Desenvolvimento de Software LTDA\n# SPDX-License-Identifier: MIT OR GPL"
},
{
"path": "examples/filter/https.c",
"chars": 1258,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2024 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR GPL-2"
},
{
"path": "examples/filter/sni.lua",
"chars": 1713,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2024 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT OR GPL"
},
{
"path": "examples/gesture.lua",
"chars": 1505,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2025-2026 Jieming Zhou <qrsikno@gmail.com>\n-- SPDX-License-Identifier: MIT OR GPL-2.0-"
},
{
"path": "examples/keylocker.lua",
"chars": 762,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2023-2024 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT O"
},
{
"path": "examples/lldpd.lua",
"chars": 2206,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2025-2026 Ashwani Kumar Kamal <ashwanikamal.im421@gmail.com>\n-- SPDX-License-Identifie"
},
{
"path": "examples/shared.lua",
"chars": 2300,
"preview": "--\n-- Copyright (c) 2023-2024 ring-0 Ltda.\n--\n-- Permission is hereby granted, free of charge, to any person obtaining\n-"
},
{
"path": "examples/spyglass.lua",
"chars": 2349,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2023-2024 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT O"
},
{
"path": "examples/systrack.lua",
"chars": 884,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2023-2024 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT O"
},
{
"path": "examples/tap.lua",
"chars": 563,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2023-2024 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT O"
},
{
"path": "examples/tcpreject/cleanup.sh",
"chars": 392,
"preview": "#!/bin/bash\n# SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n# SPDX-License-Identifier: MIT"
},
{
"path": "examples/tcpreject/nf_tcpreject.lua",
"chars": 3064,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT OR GPL"
},
{
"path": "examples/tcpreject/setup.sh",
"chars": 1888,
"preview": "#!/bin/bash\n# SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n# SPDX-License-Identifier: MIT"
},
{
"path": "examples/xiaomi.lua",
"chars": 2665,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2025-2026 Jieming Zhou <qrsikno@gmail.com>\n-- SPDX-License-Identifier: MIT OR GPL-2.0-"
},
{
"path": "gensymbols.sh",
"chars": 296,
"preview": "#!/bin/sh\n# SPDX-FileCopyrightText: (c) 2023-2026 Ring Zero Desenvolvimento de Software LTDA\n# SPDX-License-Identifier: "
},
{
"path": "include/assert.h",
"chars": 215,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2023-2024 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR "
},
{
"path": "include/ctype.h",
"chars": 220,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2023-2024 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR "
},
{
"path": "include/errno.h",
"chars": 228,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2023-2026 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR "
},
{
"path": "include/float.h",
"chars": 213,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2023-2024 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR "
},
{
"path": "include/klibc/diverr.h",
"chars": 277,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR GPL-2"
},
{
"path": "include/limits.h",
"chars": 499,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2023-2026 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR "
},
{
"path": "include/locale.h",
"chars": 215,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2023-2024 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR "
},
{
"path": "include/math.h",
"chars": 211,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2023-2024 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR "
},
{
"path": "include/setjmp.h",
"chars": 373,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2023-2024 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR "
},
{
"path": "include/stdarg.h",
"chars": 223,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2023-2024 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR "
},
{
"path": "include/stddef.h",
"chars": 223,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2023-2024 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR "
},
{
"path": "include/stdint.h",
"chars": 528,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2023-2026 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR "
},
{
"path": "include/stdio.h",
"chars": 3436,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2023-2026 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR "
},
{
"path": "include/stdlib.h",
"chars": 398,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2023-2026 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR "
},
{
"path": "include/string.h",
"chars": 450,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2023-2026 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR "
},
{
"path": "include/time.h",
"chars": 211,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2023-2024 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR "
},
{
"path": "lib/Kbuild",
"chars": 1173,
"preview": "# SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n# SPDX-License-Identifier: MIT OR GPL-2.0-"
},
{
"path": "lib/crypto/hkdf.lua",
"chars": 3200,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2025-2026 jperon <cataclop@hotmail.com>\n-- SPDX-License-Identifier: MIT OR GPL-2.0-onl"
},
{
"path": "lib/lighten.lua",
"chars": 728,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT OR GPL"
},
{
"path": "lib/luabyteorder.c",
"chars": 6001,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2024-2026 Mohammad Shehar Yaar Tausif <sheharyaar48@gmail.com>\n* SPDX-License-Identifie"
},
{
"path": "lib/luacompletion.c",
"chars": 4576,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2023-2025 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR "
},
{
"path": "lib/luacpu.c",
"chars": 3551,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2025 Enderson Maia <endersonmaia@gmail.com\n* SPDX-License-Identifier: MIT OR GPL-2.0-on"
},
{
"path": "lib/luacrypto.h",
"chars": 1398,
"preview": "/*\n * SPDX-FileCopyrightText: (c) 2025-2026 jperon <cataclop@hotmail.com>\n * SPDX-License-Identifier: MIT OR GPL-2.0-onl"
},
{
"path": "lib/luacrypto_aead.c",
"chars": 7162,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2025-2026 jperon <cataclop@hotmail.com>\n* SPDX-License-Identifier: MIT OR GPL-2.0-only\n"
},
{
"path": "lib/luacrypto_comp.c",
"chars": 2612,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2025-2026 jperon <cataclop@hotmail.com>\n* SPDX-License-Identifier: MIT OR GPL-2.0-only\n"
},
{
"path": "lib/luacrypto_core.c",
"chars": 1151,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2025-2026 jperon <cataclop@hotmail.com>\n* SPDX-License-Identifier: MIT OR GPL-2.0-only\n"
},
{
"path": "lib/luacrypto_rng.c",
"chars": 4000,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2025-2026 jperon <cataclop@hotmail.com>\n* SPDX-License-Identifier: MIT OR GPL-2.0-only\n"
},
{
"path": "lib/luacrypto_shash.c",
"chars": 6349,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2025-2026 jperon <cataclop@hotmail.com>\n* SPDX-License-Identifier: MIT OR GPL-2.0-only\n"
},
{
"path": "lib/luacrypto_skcipher.c",
"chars": 5402,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2025-2026 jperon <cataclop@hotmail.com>\n* SPDX-License-Identifier: MIT OR GPL-2.0-only\n"
},
{
"path": "lib/luadarken.c",
"chars": 3781,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR GPL-2"
},
{
"path": "lib/luadata.c",
"chars": 9231,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2023-2026 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR "
},
{
"path": "lib/luadata.h",
"chars": 760,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2024-2026 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR "
},
{
"path": "lib/luadevice.c",
"chars": 12953,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2023-2025 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR "
},
{
"path": "lib/luafib.c",
"chars": 4491,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2023-2025 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR "
},
{
"path": "lib/luafifo.c",
"chars": 4283,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2024 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR GPL-2"
},
{
"path": "lib/luahid.c",
"chars": 8573,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2025-2026 Jieming Zhou <qrsikno@gmail.com>\n* SPDX-License-Identifier: MIT OR GPL-2.0-on"
},
{
"path": "lib/lualinux.c",
"chars": 10146,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2023-2026 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR "
},
{
"path": "lib/luanetfilter.c",
"chars": 4821,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2024-2026 Mohammad Shehar Yaar Tausif <sheharyaar48@gmail.com>\n* SPDX-License-Identifie"
},
{
"path": "lib/luanetfilter.h",
"chars": 8832,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2024-2025 Mohammad Shehar Yaar Tausif <sheharyaar48@gmail.com>\n* SPDX-License-Identifie"
},
{
"path": "lib/luanotifier.c",
"chars": 15518,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2023-2025 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR "
},
{
"path": "lib/luaprobe.c",
"chars": 8577,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2023-2025 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR "
},
{
"path": "lib/luarcu.c",
"chars": 8966,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2023-2025 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR "
},
{
"path": "lib/luarcu.h",
"chars": 960,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2024 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR GPL-2"
},
{
"path": "lib/luasignal.c",
"chars": 4118,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2025-2026 L Venkata Subramanyam <202301280@dau.ac.in>\n* SPDX-License-Identifier: MIT OR"
},
{
"path": "lib/luaskb.c",
"chars": 7755,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR GPL-2"
},
{
"path": "lib/luaskb.h",
"chars": 659,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR GPL-2"
},
{
"path": "lib/luaskel.c",
"chars": 1525,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2023-2026 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR "
},
{
"path": "lib/luasocket.c",
"chars": 27296,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2023-2026 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR "
},
{
"path": "lib/luasyscall.c",
"chars": 41632,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2024-2025 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR "
},
{
"path": "lib/luathread.c",
"chars": 5989,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2023-2026 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR "
},
{
"path": "lib/luaxdp.c",
"chars": 8572,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2024-2026 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR "
},
{
"path": "lib/lunatik/runner.lua",
"chars": 4143,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2023-2026 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT O"
},
{
"path": "lib/mailbox.lua",
"chars": 4346,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2024 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT OR GPL"
},
{
"path": "lib/net.lua",
"chars": 1362,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2023-2025 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT O"
},
{
"path": "lib/socket/inet.lua",
"chars": 7081,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2023-2025 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT O"
},
{
"path": "lib/socket/raw.lua",
"chars": 1111,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2026 Ashwani Kumar Kamal <ashwanikamal.im421@gmail.com>\n-- SPDX-License-Identifier: MI"
},
{
"path": "lib/socket/unix.lua",
"chars": 5280,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2025-2026 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT O"
},
{
"path": "lib/syscall/table.lua",
"chars": 954,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2024 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT OR GPL"
},
{
"path": "lib/util.lua",
"chars": 1668,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2025 jperon <cataclop@hotmail.com>\n-- SPDX-License-Identifier: MIT OR GPL-2.0-only\n--\n"
},
{
"path": "lunatik.h",
"chars": 14007,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2023-2026 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR "
},
{
"path": "lunatik_aux.c",
"chars": 2886,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2023-2026 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR "
},
{
"path": "lunatik_conf.h",
"chars": 2621,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2023-2026 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR "
},
{
"path": "lunatik_core.c",
"chars": 8337,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2023-2026 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR "
},
{
"path": "lunatik_obj.c",
"chars": 4344,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2023-2026 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR "
},
{
"path": "lunatik_run.c",
"chars": 904,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2023-2024 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR "
},
{
"path": "lunatik_val.c",
"chars": 1391,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR GPL-2"
},
{
"path": "lunatik_val.h",
"chars": 522,
"preview": "/*\n* SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n* SPDX-License-Identifier: MIT OR GPL-2"
},
{
"path": "tests/README.md",
"chars": 3036,
"preview": "# Lunatik Tests\n\nIntegration tests for lunatik kernel modules. Output follows\n[KTAP](https://docs.kernel.org/dev-tools/k"
},
{
"path": "tests/crypto/aead.lua",
"chars": 4081,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2025-2026 jperon <cataclop@hotmail.com>\n-- SPDX-License-Identifier: MIT OR GPL-2.0-onl"
},
{
"path": "tests/crypto/comp.lua",
"chars": 2692,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2025 jperon <cataclop@hotmail.com>\n-- SPDX-License-Identifier: MIT OR GPL-2.0-only\n--\n"
},
{
"path": "tests/crypto/hkdf.lua",
"chars": 2938,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2025 jperon <cataclop@hotmail.com>\n-- SPDX-License-Identifier: MIT OR GPL-2.0-only\n--\n"
},
{
"path": "tests/crypto/rng.lua",
"chars": 2549,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2025 jperon <cataclop@hotmail.com>\n-- SPDX-License-Identifier: MIT OR GPL-2.0-only\n--\n"
},
{
"path": "tests/crypto/run.sh",
"chars": 844,
"preview": "#!/bin/bash\n#\n# SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n# SPDX-License-Identifier: M"
},
{
"path": "tests/crypto/shash.lua",
"chars": 3862,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2025 jperon <cataclop@hotmail.com>\n-- SPDX-License-Identifier: MIT OR GPL-2.0-only\n--\n"
},
{
"path": "tests/crypto/skcipher.lua",
"chars": 3435,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2025-2026 jperon <cataclop@hotmail.com>\n-- SPDX-License-Identifier: MIT OR GPL-2.0-onl"
},
{
"path": "tests/io/softirq.lua",
"chars": 297,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT OR GPL"
},
{
"path": "tests/io/test.lua",
"chars": 3743,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT OR GPL"
},
{
"path": "tests/io/test.sh",
"chars": 772,
"preview": "#!/bin/bash\n#\n# SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n# SPDX-License-Identifier: M"
},
{
"path": "tests/lib.sh",
"chars": 1326,
"preview": "#!/bin/bash\n#\n# SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n# SPDX-License-Identifier: M"
},
{
"path": "tests/monitor/gc.lua",
"chars": 698,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT OR GPL"
},
{
"path": "tests/monitor/gc.sh",
"chars": 1336,
"preview": "#!/bin/bash\n#\n# SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n# SPDX-License-Identifier: M"
},
{
"path": "tests/monitor/run.sh",
"chars": 435,
"preview": "#!/bin/bash\n#\n# SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n# SPDX-License-Identifier: M"
},
{
"path": "tests/rcu/map_sync.lua",
"chars": 1129,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2025-2026 jperon <cataclop@hotmail.com>\n-- SPDX-License-Identifier: MIT OR GPL-2.0-onl"
},
{
"path": "tests/rcu/map_sync.sh",
"chars": 890,
"preview": "#!/bin/bash\n#\n# SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n# SPDX-License-Identifier: M"
},
{
"path": "tests/rcu/map_sync_clean.lua",
"chars": 742,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2025 jperon <cataclop@hotmail.com>\n-- SPDX-License-Identifier: MIT OR GPL-2.0-only\n--\n"
},
{
"path": "tests/rcu/map_values.lua",
"chars": 1808,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT OR GPL"
},
{
"path": "tests/rcu/run.sh",
"chars": 857,
"preview": "#!/bin/bash\n#\n# SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n# SPDX-License-Identifier: M"
},
{
"path": "tests/run.sh",
"chars": 1036,
"preview": "#!/bin/bash\n#\n# SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n# SPDX-License-Identifier: M"
},
{
"path": "tests/runtime/opt_guards.lua",
"chars": 2012,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT OR GPL"
},
{
"path": "tests/runtime/opt_guards.sh",
"chars": 693,
"preview": "#!/bin/bash\n#\n# SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n# SPDX-License-Identifier: M"
},
{
"path": "tests/runtime/opt_guards_recv.lua",
"chars": 386,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT OR GPL"
},
{
"path": "tests/runtime/opt_skb_single.lua",
"chars": 1127,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT OR GPL"
},
{
"path": "tests/runtime/opt_skb_single.sh",
"chars": 979,
"preview": "#!/bin/bash\n#\n# SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n# SPDX-License-Identifier: M"
},
{
"path": "tests/runtime/rcu_shared.lua",
"chars": 464,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT OR GPL"
},
{
"path": "tests/runtime/rcu_shared.sh",
"chars": 799,
"preview": "#!/bin/bash\n#\n# SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n# SPDX-License-Identifier: M"
},
{
"path": "tests/runtime/rcu_shared_recv.lua",
"chars": 454,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT OR GPL"
},
{
"path": "tests/runtime/refcnt_leak.lua",
"chars": 649,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT OR GPL"
},
{
"path": "tests/runtime/refcnt_leak.sh",
"chars": 1434,
"preview": "#!/bin/bash\n#\n# SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n# SPDX-License-Identifier: M"
},
{
"path": "tests/runtime/resume_mailbox.lua",
"chars": 638,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT OR GPL"
},
{
"path": "tests/runtime/resume_mailbox.sh",
"chars": 912,
"preview": "#!/bin/bash\n#\n# SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n# SPDX-License-Identifier: M"
},
{
"path": "tests/runtime/resume_mailbox_send.lua",
"chars": 419,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT OR GPL"
},
{
"path": "tests/runtime/resume_shared.lua",
"chars": 471,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT OR GPL"
},
{
"path": "tests/runtime/resume_shared.sh",
"chars": 884,
"preview": "#!/bin/bash\n#\n# SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n# SPDX-License-Identifier: M"
},
{
"path": "tests/runtime/resume_shared_recv.lua",
"chars": 355,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT OR GPL"
},
{
"path": "tests/runtime/run.sh",
"chars": 560,
"preview": "#!/bin/bash\n#\n# SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n# SPDX-License-Identifier: M"
},
{
"path": "tests/socket/run.sh",
"chars": 427,
"preview": "#!/bin/bash\n#\n# SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n# SPDX-License-Identifier: M"
},
{
"path": "tests/socket/unix/dgram.sh",
"chars": 1437,
"preview": "#!/bin/bash\n#\n# SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n# SPDX-License-Identifier: M"
},
{
"path": "tests/socket/unix/dgram_client.lua",
"chars": 603,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT OR GPL"
},
{
"path": "tests/socket/unix/dgram_server.lua",
"chars": 1037,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT OR GPL"
},
{
"path": "tests/socket/unix/run.sh",
"chars": 463,
"preview": "#!/bin/bash\n#\n# SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n# SPDX-License-Identifier: M"
},
{
"path": "tests/socket/unix/stream.sh",
"chars": 1529,
"preview": "#!/bin/bash\n#\n# SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n# SPDX-License-Identifier: M"
},
{
"path": "tests/socket/unix/stream_client.lua",
"chars": 657,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT OR GPL"
},
{
"path": "tests/socket/unix/stream_server.lua",
"chars": 1144,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT OR GPL"
},
{
"path": "tests/thread/dummy.lua",
"chars": 342,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT OR GPL"
},
{
"path": "tests/thread/run.sh",
"chars": 467,
"preview": "#!/bin/bash\n#\n# SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n# SPDX-License-Identifier: M"
},
{
"path": "tests/thread/run_during_load.lua",
"chars": 312,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT OR GPL"
},
{
"path": "tests/thread/run_during_load.sh",
"chars": 1170,
"preview": "#!/bin/bash\n#\n# SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n# SPDX-License-Identifier: M"
},
{
"path": "tests/thread/shouldstop.lua",
"chars": 400,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT OR GPL"
},
{
"path": "tests/thread/shouldstop.sh",
"chars": 1408,
"preview": "#!/bin/bash\n#\n# SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n# SPDX-License-Identifier: M"
},
{
"path": "tests/thread/shouldstop_run.lua",
"chars": 290,
"preview": "--\n-- SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n-- SPDX-License-Identifier: MIT OR GPL"
},
{
"path": "tools/Readme.md",
"chars": 388,
"preview": "# Additional tools\n\n## debian_kernel_postinst_lunatik.sh\n\nUnder Debian, copy this script into /etc/kernel/postinst.d/\nto"
},
{
"path": "tools/debian_kernel_postinst_lunatik.sh",
"chars": 2875,
"preview": "#!/usr/bin/env bash\n\nLUNATIK_DIR=\"/opt/lunatik\"\nXDP_DIR=\"/opt/xdp-tools\"\nKERNEL_RELEASE=\"$1\"\n# This ugly hack is needed "
},
{
"path": "tools/shade.sh",
"chars": 2312,
"preview": "#!/bin/bash\n# SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA\n# SPDX-License-Identifier: MIT"
}
]
About this extraction
This page contains the full source code of the luainkernel/lunatik GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 165 files (492.1 KB), approximately 149.6k tokens, and a symbol index with 345 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.