code push
This commit is contained in:
@@ -10,8 +10,8 @@ export const ModalLog = (
|
||||
}
|
||||
) => {
|
||||
return <Modal size="90%" title={title} opened={opened} onClose={close} centered>
|
||||
<ScrollArea h={500} style={{ minWidth: "100%",whiteSpace: "pre-wrap"}}>
|
||||
<Code block mih={500}>{data}</Code>
|
||||
<ScrollArea h={500} style={{ maxWidth: "100%",whiteSpace: "break-spaces"}} scrollbars="y">
|
||||
<Code block mih={500} style={{ maxWidth: "100%",whiteSpace: "break-spaces"}}>{data}</Code>
|
||||
</ScrollArea>
|
||||
</Modal>
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import { IoIosWarning } from "react-icons/io"
|
||||
import { socketio, WARNING_NFPROXY_TIME_LIMIT } from "../../js/utils"
|
||||
import { Tooltip } from "@mantine/core"
|
||||
import { useEffect, useState } from "react"
|
||||
import { round } from "@mantine/core/lib/components/ColorPicker/converters/parsers"
|
||||
|
||||
|
||||
export const ExceptionWarning = ({ service_id }: { service_id: string }) => {
|
||||
@@ -17,9 +18,25 @@ export const ExceptionWarning = ({ service_id }: { service_id: string }) => {
|
||||
}
|
||||
}, [])
|
||||
|
||||
const [_time, setTime] = useState(new Date());
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
setTime(new Date());
|
||||
}, 1000);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
|
||||
const deltaTime = new Date().getTime()-lastExceptionTimestamp
|
||||
const minutes = Math.floor(deltaTime/(1000*60))
|
||||
const seconds = Math.floor(deltaTime/1000)%60
|
||||
|
||||
const deltaStringTime = `${minutes.toString().length>1?minutes:"0"+minutes}:${seconds.toString().length>1?seconds:"0"+seconds}`
|
||||
|
||||
return <>
|
||||
{(new Date().getTime()-lastExceptionTimestamp <= WARNING_NFPROXY_TIME_LIMIT)?
|
||||
<Tooltip label={`There was an exception less than ${WARNING_NFPROXY_TIME_LIMIT/(1000*60)} minutes ago: check the logs`} color="yellow">
|
||||
<Tooltip label={`There was an exception less than ${deltaStringTime} minutes ago: check the logs`} color="yellow">
|
||||
<IoIosWarning size={30} style={{ color: "yellow" }} />
|
||||
</Tooltip>
|
||||
:null}
|
||||
|
||||
@@ -96,3 +96,77 @@ export const nfproxy = {
|
||||
return status === "ok"?undefined:status
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const EXAMPLE_PYFILTER = `# This in an example of a filter file with http protocol
|
||||
|
||||
# From here we can import the DataTypes that we want to use:
|
||||
# The data type must be specified in the filter functions
|
||||
# And will also interally be used to decide when call some filters and how aggregate data
|
||||
from firegex.nfproxy.params import RawPacket
|
||||
|
||||
# global context in this execution is dedicated to a single TCP stream
|
||||
# - This code will be executed once at the TCP stream start
|
||||
# - The filter will be called for each packet in the stream
|
||||
# - You can store in global context some data you need, but exceeding with data stored could be dangerous
|
||||
# - At the end of the stream the global context will be destroyed
|
||||
|
||||
from firegex.nfproxy import pyfilter
|
||||
# pyfilter is a decorator, this will make the function become an effective filter and must have parameters with a specified type
|
||||
|
||||
from firegex.nfproxy import REJECT, ACCEPT, UNSTABLE_MANGLE, DROP
|
||||
# - The filter must return one of the following values:
|
||||
# - ACCEPT: The packet will be accepted
|
||||
# - REJECT: The packet will be rejected (will be activated a mechanism to send a FIN packet and drop all data in the stream)
|
||||
# - UNSTABLE_MANGLE: The packet will be mangled and accepted
|
||||
# - DROP: All the packets in this stream will be easly dropped
|
||||
|
||||
# If you want, you can use print to debug your filters, but this could slow down the filter
|
||||
|
||||
# Filter names must be unique and are specified by the name of the function wrapped by the decorator
|
||||
@pyfilter
|
||||
# This function will handle only a RawPacket object, this is the lowest level of the packet abstraction
|
||||
def strange_filter(packet:RawPacket):
|
||||
# Mangling packets can be dangerous, due to instability of the internal TCP state mangling done by the filter below
|
||||
# Also is not garanteed that l4_data is the same of the packet data:
|
||||
# packet data is the assembled TCP stream, l4_data is the TCP payload of the packet in the nfqueue
|
||||
# Unorder packets in TCP are accepted by default, and python is not called in this case
|
||||
# For this reason mangling will be only available RawPacket: higher level data abstraction will be read-only
|
||||
if b"TEST_MANGLING" in packet.l4_data:
|
||||
# It's possible to change teh raw_packet and l4_data values for mangling the packet, data is immutable instead
|
||||
packet.l4_data = packet.l4_data.replace(b"TEST", b"UNSTABLE")
|
||||
return UNSTABLE_MANGLE
|
||||
# Drops the traffic
|
||||
if b"BAD DATA 1" in packet.data:
|
||||
return DROP
|
||||
# Rejects the traffic
|
||||
if b"BAD DATA 2" in packet.data:
|
||||
return REJECT
|
||||
# Accepts the traffic (default if None is returned)
|
||||
return ACCEPT
|
||||
|
||||
# Example with a higher level of abstraction
|
||||
@pyfilter
|
||||
def http_filter(http:HTTPRequest):
|
||||
if http.method == "GET" and "test" in http.url:
|
||||
return REJECT
|
||||
|
||||
# ADVANCED OPTIONS
|
||||
# You can specify some additional options on the streaming managment
|
||||
# pyproxy will automatically store all the packets (already ordered by the c++ binary):
|
||||
#
|
||||
# If the stream is too big, you can specify what actions to take:
|
||||
# This can be done defining some variables in the global context
|
||||
# - FGEX_STREAM_MAX_SIZE: The maximum size of the stream in bytes (default 1MB)
|
||||
# NOTE: the stream size is calculated by the sum of the dimension of the packets in the stream (both directions)
|
||||
# - FGEX_FULL_STREAM_ACTION: The action to do when the stream is full
|
||||
# - FLUSH: Flush the stream and continue to acquire new packets (default)
|
||||
# - DROP: Drop the next stream packets - like a DROP action by filter
|
||||
# - REJECT: Reject the stream and close the connection - like a REJECT action by filter
|
||||
# - ACCEPT: Stops to call pyfilters and accept the traffic
|
||||
|
||||
# Example of a global context
|
||||
FGEX_STREAM_MAX_SIZE = 4096
|
||||
FGEX_FULL_STREAM_ACTION = REJECT
|
||||
# This could be an ideal configuration if we expect to normally have streams with a maximum size of 4KB of traffic
|
||||
`
|
||||
|
||||
@@ -37,9 +37,14 @@ export default function NavBar() {
|
||||
<Divider my="xs" />
|
||||
<Box style={{flexGrow: 1}} component={ScrollArea} px="xs" mt="xs">
|
||||
<NavBarButton navigate="nfregex" closeNav={closeNav} name="Netfilter Regex" color="grape" icon={<BsRegex size={19} />} />
|
||||
<NavBarButton navigate="nfproxy" closeNav={closeNav} name="Netfilter Proxy" color="lime" icon={<TbPlugConnected size={19} />} />
|
||||
<NavBarButton navigate="firewall" closeNav={closeNav} name="Firewall Rules" color="red" icon={<PiWallLight size={19} />} />
|
||||
<NavBarButton navigate="porthijack" closeNav={closeNav} name="Hijack Port to Proxy" color="blue" icon={<GrDirections size={19} />} />
|
||||
<Box px="xs" mt="lg">
|
||||
<Title order={5}>Experimental Features 🧪</Title>
|
||||
</Box>
|
||||
<Text></Text>
|
||||
<Divider my="xs" />
|
||||
<NavBarButton navigate="nfproxy" closeNav={closeNav} name="Netfilter Proxy" color="lime" icon={<TbPlugConnected size={19} />} />
|
||||
</Box>
|
||||
|
||||
</AppShell.Navbar>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Navigate, useNavigate, useParams } from 'react-router-dom';
|
||||
import { Badge, Divider, Menu } from '@mantine/core';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { FaFilter, FaPencilAlt, FaPlay, FaStop } from 'react-icons/fa';
|
||||
import { nfproxy, nfproxyServiceFilterCodeQuery, nfproxyServicePyfiltersQuery, nfproxyServiceQuery, serviceQueryKey } from '../../components/NFProxy/utils';
|
||||
import { EXAMPLE_PYFILTER, nfproxy, nfproxyServiceFilterCodeQuery, nfproxyServicePyfiltersQuery, nfproxyServiceQuery, serviceQueryKey } from '../../components/NFProxy/utils';
|
||||
import { MdDoubleArrow } from "react-icons/md"
|
||||
import YesNoModal from '../../components/YesNoModal';
|
||||
import { errorNotify, isMediumScreen, okNotify, regex_ipv4, socketio } from '../../js/utils';
|
||||
@@ -45,17 +45,20 @@ export default function ServiceDetailsNFProxy() {
|
||||
useEffect(()=>{
|
||||
if (srv){
|
||||
if (openLogModal){
|
||||
logDataSetters.setState([])
|
||||
socketio.emit("nfproxy-outstream-join", { service: srv });
|
||||
socketio.on(`nfproxy-outstream-${srv}`, (data) => {
|
||||
logDataSetters.append(data)
|
||||
});
|
||||
}else{
|
||||
logDataSetters.setState([])
|
||||
socketio.emit("nfproxy-outstream-leave", { service: srv });
|
||||
socketio.off(`nfproxy-outstream-${srv}`);
|
||||
logDataSetters.setState([])
|
||||
}
|
||||
return () => {
|
||||
logDataSetters.setState([])
|
||||
socketio.emit("nfproxy-outstream-leave", { service: srv });
|
||||
socketio.off(`nfproxy-outstream-${srv}`);
|
||||
logDataSetters.setState([])
|
||||
}
|
||||
}
|
||||
}, [openLogModal, srv])
|
||||
@@ -199,11 +202,13 @@ export default function ServiceDetailsNFProxy() {
|
||||
|
||||
{(!filtersList.data || filtersList.data.length == 0)?<>
|
||||
<Space h="xl" />
|
||||
<Title className='center-flex' style={{textAlign:"center"}} order={3}>No filters found! Edit the proxy file</Title>
|
||||
<Title className='center-flex' style={{textAlign:"center"}} order={3}>No filters found! Edit the proxy file, install the firegex client:<Space w="xs" /><Code mb={-4} >pip install fgex</Code></Title>
|
||||
<Space h="xs" />
|
||||
<Title className='center-flex' style={{textAlign:"center"}} order={3}>Install the firegex client:<Space w="xs" /><Code mb={-4} >pip install fgex</Code></Title>
|
||||
<Title className='center-flex' style={{textAlign:"center"}} order={3}>Then create a new filter file with the following syntax and upload it here (using the button above)</Title>
|
||||
<Space h="xs" />
|
||||
<Title className='center-flex' style={{textAlign:"center"}} order={3}>Then run the command:<Space w="xs" /><Code mb={-4} >fgex nfproxy</Code></Title>
|
||||
<Title className='center-flex' style={{textAlign:"center"}} order={3}>Before upload the filter you can test it using the fgex command installed by the python lib</Title>
|
||||
<Space h="lg" />
|
||||
<CodeHighlight code={EXAMPLE_PYFILTER} language="python" />
|
||||
</>:<>{filtersList.data?.map( (filterInfo) => <PyFilterView filterInfo={filterInfo} key={filterInfo.name}/>)}</>
|
||||
}
|
||||
<YesNoModal
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ActionIcon, Badge, Box, FileButton, LoadingOverlay, Space, ThemeIcon, Title, Tooltip } from '@mantine/core';
|
||||
import { ActionIcon, Badge, Box, Code, LoadingOverlay, Space, ThemeIcon, Title, Tooltip } from '@mantine/core';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { BsPlusLg } from "react-icons/bs";
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
@@ -7,11 +7,12 @@ import { errorNotify, getErrorMessage, isMediumScreen } from '../../js/utils';
|
||||
import AddEditService from '../../components/NFProxy/AddEditService';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { TbPlugConnected, TbReload } from 'react-icons/tb';
|
||||
import { nfproxy, nfproxyServiceQuery } from '../../components/NFProxy/utils';
|
||||
import { EXAMPLE_PYFILTER, nfproxy, nfproxyServiceQuery } from '../../components/NFProxy/utils';
|
||||
import { FaFilter, FaPencilAlt, FaServer } from 'react-icons/fa';
|
||||
import { MdUploadFile } from "react-icons/md";
|
||||
import { notifications } from '@mantine/notifications';
|
||||
import { useFileDialog } from '@mantine/hooks';
|
||||
import { CodeHighlight } from '@mantine/code-highlight';
|
||||
|
||||
|
||||
export default function NFProxy({ children }: { children: any }) {
|
||||
@@ -138,13 +139,27 @@ export default function NFProxy({ children }: { children: any }) {
|
||||
<LoadingOverlay visible={services.isLoading} />
|
||||
{(services.data && services.data?.length > 0)?services.data.map( srv => <ServiceRow service={srv} key={srv.service_id} onClick={()=>{
|
||||
navigator("/nfproxy/"+srv.service_id)
|
||||
}} />):<><Space h="xl"/> <Title className='center-flex' style={{textAlign:"center"}} order={3}>No services found! Add one clicking the "+" buttons</Title>
|
||||
<Box className='center-flex'>
|
||||
}} />):<>
|
||||
<Box className='center-flex-row'>
|
||||
<Space h="xl" />
|
||||
<Title className='center-flex' style={{textAlign:"center"}} order={3}>Netfilter proxy is a simulated proxy written using python with a c++ core</Title>
|
||||
<Space h="xs" />
|
||||
<Title className='center-flex' style={{textAlign:"center"}} order={5}>Filters are created using a simple python syntax, infact the first you need to do is to install the firegex lib:<Space w="xs" /><Code mb={-4} >pip install firegex</Code></Title>
|
||||
<Space h="xs" />
|
||||
<Title className='center-flex' style={{textAlign:"center"}} order={5}>Then you can create a new service and write custom filters for the service</Title>
|
||||
<Space h="xs" />
|
||||
<Title className='center-flex' style={{textAlign:"center"}} order={5}>Below there is a description and example about how a pyfilter has to be composed (this example is replicated in every empty service)</Title>
|
||||
<Space h="lg" />
|
||||
<CodeHighlight code={EXAMPLE_PYFILTER} language="python" />
|
||||
<Space h="lg" />
|
||||
<Title className='center-flex' style={{textAlign:"center"}} order={3}>Add your first service</Title>
|
||||
<Space h="lg" />
|
||||
<Tooltip label="Add a new service" color="blue">
|
||||
<ActionIcon color="blue" onClick={()=>setOpen(true)} size="xl" radius="md" variant="filled">
|
||||
<BsPlusLg size="20px" />
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
|
||||
</Box>
|
||||
</>}
|
||||
</>}
|
||||
|
||||
Reference in New Issue
Block a user