push partial docs

This commit is contained in:
Domingo Dirutigliano
2025-03-05 10:02:15 +01:00
parent 22b90376b3
commit e31796b249
9 changed files with 239 additions and 1 deletions

View File

@@ -0,0 +1,39 @@
import { ActionIcon, Box, Modal, ScrollArea, Title, Tooltip } from "@mantine/core";
import { useState } from "react";
import { FaBookBookmark } from "react-icons/fa6";
import { NFRegexDocs } from "./NFRegex/NFRegexDocs";
import { NFProxyDocs } from "./NFProxy/NFProxyDocs";
import { PortHijackDocs } from "./PortHijack/PortHijackDocs";
import { EnumToPrimitiveUnion } from "../js/utils";
export enum DocType{
NFREGEX = "nfregex",
NFPROXY = "nfproxy",
PORTHIJACK = "porthijack",
}
export const DocsButton = ({ doc }: { doc: EnumToPrimitiveUnion<DocType> }) => {
const [open, setOpen] = useState(false);
return <Box>
<Tooltip label="Add a new service" color="pink">
<ActionIcon color="pink" onClick={()=>setOpen(true)} size="lg" radius="md" variant="filled"><FaBookBookmark size="20px" /></ActionIcon>
</Tooltip>
<Modal opened={open} onClose={() => setOpen(false)} fullScreen title={
<Title order={2}>Firegex Docs 📕</Title>
} scrollAreaComponent={ScrollArea.Autosize}>
{
doc == DocType.NFREGEX ?
<NFRegexDocs />:
doc == DocType.NFPROXY ?
<NFProxyDocs />:
doc == DocType.PORTHIJACK ?
<PortHijackDocs />:
<Title order={3}>Docs not found</Title>
}
</Modal>
</Box>
}

View File

@@ -0,0 +1,105 @@
import { CodeHighlight } from "@mantine/code-highlight";
import { Container, Title, Text, List, Code, Space } from "@mantine/core";
const IMPORT_CODE_EXAMPLE = `from firegex.nfproxy import pyfilter, ACCEPT, REJECT`
const FOO_FILTER_CODE = `from firegex.nfproxy import pyfilter, ACCEPT, REJECT
# This is NOT a filter
def useless_function() -> int:
print("This is a useless function")
return 42
@pyfilter
def none_filter(): # This is a filter that does nothing
useless_function()
return ACCEPT
`
export const NFProxyDocs = () => {
return (
<Container size="xl">
<Title order={1}>🌐 Netfilter Proxy Documentation</Title>
<Title order={2} mt="xl" mb="sm">📖 Overview</Title>
<Text size="lg">
Netfilter Proxy is a simulated proxy that leverages <a href="https://netfilter.org/projects/libnetfilter_queue/">nfqueue</a> to intercept network packets.
It follows a similar workflow to NFRegex but introduces Python-based filtering capabilities,
providing users with the flexibility to upload custom filters.
</Text>
<Title order={2} mt="lg" mb="sm"> How to Use Netfilter Proxy</Title>
<Text size="lg">
To use Netfilter Proxy, simply create and upload a Python filter. The filter is passed to the C++ binary,
which then processes packets using the provided logic. This allows you to tailor the filtering behavior
to your needs.
</Text>
<Title order={2} mt="lg" mb="sm">🚀 How It Works</Title>
<Text mb="sm" size="lg">
The proxy is built on a multi-threaded architecture and integrates Python for dynamic filtering:
</Text>
<List>
<List.Item>
<Text size="lg">
<strong>Packet Interception: </strong>
The <a href="https://netfilter.org/projects/libnetfilter_queue/">nfqueue</a> kernel module intercepts network packets(a <a href="https://netfilter.org/">netfilter</a> module) 🔍<br />
The rules for attach the nfqueue on the network traffic is done by the nftables lib with json APIs by the python manager.
</Text>
</List.Item>
<List.Item>
<Text size="lg">
<strong>Packet Reading: </strong>
A dedicated thread reads packets from <a href="https://netfilter.org/projects/libnetfilter_queue/">nfqueue</a>. 🧵
</Text>
</List.Item>
<List.Item>
<Text size="lg">
<strong>Multi-threaded Analysis: </strong>
The C++ binary launches multiple threads, each starting its own Python interpreter.
Thanks to Python 3.12s support for <a href="https://peps.python.org/pep-0684/">a per-interpeter GIL</a>, real multithreading is achieved.
Traffic is distributed among threads based on IP addresses and port hashing, ensuring that
packets belonging to the same flow are processed by the same thread.
</Text>
</List.Item>
<List.Item>
<Text size="lg">
<strong>Python Filter Integration: </strong>
Users can upload custom Python filters which are then executed by the interpreter,
allowing for dynamic and flexible packet handling. 🐍
</Text>
</List.Item>
<List.Item>
<Text size="lg">
<strong>HTTP Parsing: </strong>
<a href="https://github.com/domysh/pyllhttp">A Python wrapper for llhttp</a> (forked and adapted for working with multi-interpeters) is used to parse HTTP connections, making it easier to handle
and analyze HTTP traffic. 📡
</Text>
</List.Item>
</List>
<Title order={2} mt="lg" mb="sm">💡 How to write pyfilters?</Title>
<Text size="lg">
First of all install the firegex lib and update it running <Code>pip install -U fgex</Code>.
After that you can use <Code>firegex</Code> module.
<CodeHighlight code={IMPORT_CODE_EXAMPLE} language="python" my="sm"/>
With this code we imported the <Code>pyfilter</Code> decorator and the <Code>ACCEPT</Code> and <Code>REJECT</Code> constants.<br />
Let's create a first (useless) filter to see the syntax:
<CodeHighlight code={FOO_FILTER_CODE} language="python" my="sm"/>
You see that the filter must be decorated with the <Code>pyfilter</Code> decorator and must return a statement about how to manage that packet.
<br/><Space h="sm" />
You can save every data about the current flow in the global variables, the code you write will be executed only once for flow. The globals are isolated between flows.
For each packet the filter functions will be called with the required paramethers and the same globals as before.
<br/><Space h="sm" />
<strong>Saving data in globals of other modules is not recommended, because that memory is shared by the flows managed by the same thread and lead to unexpected behaviors.</strong>
<br/><Space h="sm" />
<strong>Global variables that starts with __firegex_ are reserved for internal use, don't use them.</strong>
</Text>
</Container>
);
};

View File

@@ -0,0 +1,69 @@
import { Container, Title, Text, List } from "@mantine/core";
export const NFRegexDocs = () => {
return (
<Container size="xl">
<Title order={1}>📡 Netfilter Regex Documentation</Title>
<Title order={2} mt="xl" mb="sm">📖 Overview</Title>
<Text size="lg">
Netfilter Regex is a powerful feature that enables filtering of network packets using regular expressions. This capability is especially useful when you need to inspect packet content and match specific strings or patterns.
</Text>
<Title order={2} mt="lg" mb="sm"> How to Use Netfilter Regex</Title>
<Text size="lg">
To get started, create a service and attach a regular expression to it. Once the service is configured, apply it to a network interface to dynamically filter packets based on the defined regex.
</Text>
<Title order={2} mt="lg" mb="sm">🚀 How It Works</Title>
<Text mb="sm" size="lg">
The packet filtering process is implemented in C++ and involves several key steps:
</Text>
<List>
<List.Item>
<Text size="lg">
<strong>Packet Interception: </strong>
The <a href="https://netfilter.org/projects/libnetfilter_queue/">nfqueue</a> kernel module intercepts network packets (a <a href="https://netfilter.org/">netfilter</a> module) 🔍<br />
The rules for attach the nfqueue on the network traffic is done by the nftables lib with json APIs by the python manager.
</Text>
</List.Item>
<List.Item>
<Text size="lg">
<strong>Packet Reading: </strong>
A dedicated thread reads packets from <a href="https://netfilter.org/projects/libnetfilter_queue/">nfqueue</a>. 🧵
</Text>
</List.Item>
<List.Item>
<Text size="lg">
<strong>Packet Parsing: </strong>
Intercepted packets are parsed by <a href="https://libtins.github.io/">libtins</a>, a C++ library that extracts the payload from each packet. 📄
</Text>
</List.Item>
<List.Item>
<Text size="lg">
<strong>Multi-threaded Analysis: </strong>
Multiple threads analyze packets concurrently.
While the <a href="https://netfilter.org/projects/libnetfilter_queue/">nfqueue</a> module balances network
load based solely on IP addressesresulting in a single thread handling traffic in NAT environments
like CTF networks, firegex manage this threads user-level in a different way.
The traffic is routed in the threads based on IP addresses combined with port hashing,
ensuring a more balanced workload and that flows will be analyzed by the same thread.
</Text>
</List.Item>
<List.Item>
<Text size="lg">
<strong>TCP Handling: </strong>
For TCP connections, <a href="https://libtins.github.io/">libtins</a> employs a TCP follower to order packets received from the kernel. 📈
</Text>
</List.Item>
<List.Item>
<Text size="lg">
<strong>Regex Matching: </strong>
The extracted payload is processed using <a href="https://github.com/VectorCamp/vectorscan">vectorscan</a> a fork of <a href="https://github.com/intel/hyperscan">hyperscan</a> that runs also on arm64.
For UDP packets, matching occurs on a per-packet basis while saving only the match context rather than the full payload. 🎯
</Text>
</List.Item>
</List>
</Container>
);
};

View File

@@ -0,0 +1,9 @@
import { Box } from "@mantine/core"
export const PortHijackDocs = () => {
return <Box>
PORT
{/* TODO write me pls */}
</Box>
}

View File

@@ -20,6 +20,13 @@ export const DEV_IP_BACKEND = "127.0.0.1:4444"
export const WARNING_NFPROXY_TIME_LIMIT = 1000*60*10 // 10 minutes export const WARNING_NFPROXY_TIME_LIMIT = 1000*60*10 // 10 minutes
export type EnumToPrimitiveUnion<T> = `${T & string}` | ParseNumber<`${T & number}`>;
type ParseNumber<T> = T extends `${infer U extends number}` ? U : never;
export function typeCastEnum<E>(value: EnumToPrimitiveUnion<E>): E {
return value as E;
}
export const socketio = import.meta.env.DEV? export const socketio = import.meta.env.DEV?
io("ws://"+DEV_IP_BACKEND, { io("ws://"+DEV_IP_BACKEND, {
path:"/sock/socket.io", path:"/sock/socket.io",

View File

@@ -13,6 +13,7 @@ import { MdUploadFile } from "react-icons/md";
import { notifications } from '@mantine/notifications'; import { notifications } from '@mantine/notifications';
import { useFileDialog } from '@mantine/hooks'; import { useFileDialog } from '@mantine/hooks';
import { CodeHighlight } from '@mantine/code-highlight'; import { CodeHighlight } from '@mantine/code-highlight';
import { DocsButton } from '../../components/DocsButton';
export default function NFProxy({ children }: { children: any }) { export default function NFProxy({ children }: { children: any }) {
@@ -131,6 +132,8 @@ export default function NFProxy({ children }: { children: any }) {
<TbReload size={18} /> <TbReload size={18} />
</ActionIcon> </ActionIcon>
</Tooltip> </Tooltip>
<Space w="xs" />
<DocsButton doc="nfproxy" />
</Box> </Box>
</Box> </Box>
<Space h="md" /> <Space h="md" />

View File

@@ -12,6 +12,7 @@ import { TbReload } from 'react-icons/tb';
import { FaFilter } from 'react-icons/fa'; import { FaFilter } from 'react-icons/fa';
import { FaServer } from "react-icons/fa6"; import { FaServer } from "react-icons/fa6";
import { VscRegex } from "react-icons/vsc"; import { VscRegex } from "react-icons/vsc";
import { DocsButton } from '../../components/DocsButton';
function NFRegex({ children }: { children: any }) { function NFRegex({ children }: { children: any }) {
@@ -59,6 +60,8 @@ function NFRegex({ children }: { children: any }) {
<ActionIcon color="indigo" onClick={()=>queryClient.invalidateQueries(["nfregex"])} size="lg" radius="md" variant="filled" <ActionIcon color="indigo" onClick={()=>queryClient.invalidateQueries(["nfregex"])} size="lg" radius="md" variant="filled"
loading={services.isFetching}><TbReload size={18} /></ActionIcon> loading={services.isFetching}><TbReload size={18} /></ActionIcon>
</Tooltip> </Tooltip>
<Space w="xs" />
<DocsButton doc="nfregex" />
</Box> </Box>
</Box> </Box>
<Space h="md" /> <Space h="md" />

View File

@@ -9,6 +9,7 @@ import { useQueryClient } from '@tanstack/react-query';
import { TbReload } from 'react-icons/tb'; import { TbReload } from 'react-icons/tb';
import { FaServer } from 'react-icons/fa'; import { FaServer } from 'react-icons/fa';
import { GrDirections } from 'react-icons/gr'; import { GrDirections } from 'react-icons/gr';
import { DocsButton } from '../../components/DocsButton';
function PortHijack() { function PortHijack() {
@@ -42,6 +43,8 @@ function PortHijack() {
<ActionIcon color="indigo" onClick={()=>queryClient.invalidateQueries(["porthijack"])} size="lg" radius="md" variant="filled" <ActionIcon color="indigo" onClick={()=>queryClient.invalidateQueries(["porthijack"])} size="lg" radius="md" variant="filled"
loading={services.isFetching}><TbReload size={18} /></ActionIcon> loading={services.isFetching}><TbReload size={18} /></ActionIcon>
</Tooltip> </Tooltip>
<Space w="xs" />
<DocsButton doc="porthijack" />
</Box> </Box>
</Box> </Box>
<Space h="md" /> <Space h="md" />