test packet rewrite dns example
This commit is contained in:
@@ -0,0 +1,2 @@
|
|||||||
|
netfilterqueue
|
||||||
|
scapy
|
||||||
67
backend/example_scripts/dns_rewrite_example_to_pwned.py
Normal file
67
backend/example_scripts/dns_rewrite_example_to_pwned.py
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Minimal NFQUEUE example: rewrite DNS queries from example.com to pwned.com."""
|
||||||
|
|
||||||
|
import signal
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from netfilterqueue import NetfilterQueue
|
||||||
|
from scapy.all import DNS, DNSQR, IP, UDP
|
||||||
|
|
||||||
|
SOURCE_QNAME = b"example.com."
|
||||||
|
TARGET_QNAME = b"pwned.com."
|
||||||
|
|
||||||
|
nfq = NetfilterQueue()
|
||||||
|
|
||||||
|
|
||||||
|
def _handle_packet(packet) -> None:
|
||||||
|
try:
|
||||||
|
ip = IP(packet.get_payload())
|
||||||
|
if ip.haslayer(UDP) and ip.haslayer(DNS) and ip.haslayer(DNSQR):
|
||||||
|
dns = ip[DNS]
|
||||||
|
query = ip[DNSQR]
|
||||||
|
|
||||||
|
# Only touch DNS requests for exactly example.com.
|
||||||
|
if dns.qr == 0 and query.qname == SOURCE_QNAME:
|
||||||
|
query.qname = TARGET_QNAME
|
||||||
|
del ip.len
|
||||||
|
del ip.chksum
|
||||||
|
del ip[UDP].len
|
||||||
|
del ip[UDP].chksum
|
||||||
|
packet.set_payload(bytes(ip))
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
packet.accept()
|
||||||
|
|
||||||
|
|
||||||
|
def _stop(_sig, _frame) -> None:
|
||||||
|
raise SystemExit(0)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
if len(sys.argv) != 2:
|
||||||
|
print("Usage: dns_rewrite_example_to_pwned.py <qnum>", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
try:
|
||||||
|
qnum = int(sys.argv[1])
|
||||||
|
except ValueError:
|
||||||
|
print("qnum must be an integer", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
signal.signal(signal.SIGINT, _stop)
|
||||||
|
signal.signal(signal.SIGTERM, _stop)
|
||||||
|
|
||||||
|
nfq.bind(qnum, _handle_packet)
|
||||||
|
try:
|
||||||
|
nfq.run()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
nfq.unbind()
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
@@ -2,6 +2,7 @@ import {
|
|||||||
DeleteOutlined,
|
DeleteOutlined,
|
||||||
DownloadOutlined,
|
DownloadOutlined,
|
||||||
EditOutlined,
|
EditOutlined,
|
||||||
|
EyeOutlined,
|
||||||
FileAddOutlined,
|
FileAddOutlined,
|
||||||
PauseCircleOutlined,
|
PauseCircleOutlined,
|
||||||
PlayCircleOutlined,
|
PlayCircleOutlined,
|
||||||
@@ -72,6 +73,7 @@ export default function ScriptsManager({ onOpenInEditor }: { onOpenInEditor?: (c
|
|||||||
const [editorModalVisible, setEditorModalVisible] = useState(false);
|
const [editorModalVisible, setEditorModalVisible] = useState(false);
|
||||||
const [editorValue, setEditorValue] = useState<string>('');
|
const [editorValue, setEditorValue] = useState<string>('');
|
||||||
const [currentEditingName, setCurrentEditingName] = useState<string | null>(null);
|
const [currentEditingName, setCurrentEditingName] = useState<string | null>(null);
|
||||||
|
const [editorReadOnly, setEditorReadOnly] = useState(false);
|
||||||
|
|
||||||
const [useInlineReqEditor, setUseInlineReqEditor] = useState(false);
|
const [useInlineReqEditor, setUseInlineReqEditor] = useState(false);
|
||||||
const [inlineReqValue, setInlineReqValue] = useState<string>('');
|
const [inlineReqValue, setInlineReqValue] = useState<string>('');
|
||||||
@@ -383,6 +385,7 @@ export default function ScriptsManager({ onOpenInEditor }: { onOpenInEditor?: (c
|
|||||||
const blob = await downloadScript(name);
|
const blob = await downloadScript(name);
|
||||||
const text = await blob.text();
|
const text = await blob.text();
|
||||||
setEditorValue(text);
|
setEditorValue(text);
|
||||||
|
setEditorReadOnly(false);
|
||||||
setEditorModalVisible(true);
|
setEditorModalVisible(true);
|
||||||
setCurrentEditingName(name);
|
setCurrentEditingName(name);
|
||||||
if (onOpenInEditor) onOpenInEditor(text);
|
if (onOpenInEditor) onOpenInEditor(text);
|
||||||
@@ -393,6 +396,19 @@ export default function ScriptsManager({ onOpenInEditor }: { onOpenInEditor?: (c
|
|||||||
[onOpenInEditor],
|
[onOpenInEditor],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const openReadOnlyViewerFromServer = useCallback(async (name: string) => {
|
||||||
|
try {
|
||||||
|
const blob = await downloadScript(name);
|
||||||
|
const text = await blob.text();
|
||||||
|
setEditorValue(text);
|
||||||
|
setEditorReadOnly(true);
|
||||||
|
setEditorModalVisible(true);
|
||||||
|
setCurrentEditingName(name);
|
||||||
|
} catch (err: any) {
|
||||||
|
notification.error({ message: 'Failed to open', description: err?.message ?? String(err) });
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
const handleSaveFromEditorAs = useCallback(
|
const handleSaveFromEditorAs = useCallback(
|
||||||
async (name: string) => {
|
async (name: string) => {
|
||||||
try {
|
try {
|
||||||
@@ -608,6 +624,13 @@ export default function ScriptsManager({ onOpenInEditor }: { onOpenInEditor?: (c
|
|||||||
onClick={() => handleDownload(record.name)}
|
onClick={() => handleDownload(record.name)}
|
||||||
icon={<DownloadOutlined />}
|
icon={<DownloadOutlined />}
|
||||||
/>
|
/>
|
||||||
|
{record.is_protected_example ? (
|
||||||
|
<IconButtonTooltip
|
||||||
|
title="View script"
|
||||||
|
onClick={() => openReadOnlyViewerFromServer(record.name)}
|
||||||
|
icon={<EyeOutlined />}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
{!record.is_protected_example ? (
|
{!record.is_protected_example ? (
|
||||||
<IconButtonTooltip
|
<IconButtonTooltip
|
||||||
title="Open in editor"
|
title="Open in editor"
|
||||||
@@ -642,6 +665,7 @@ export default function ScriptsManager({ onOpenInEditor }: { onOpenInEditor?: (c
|
|||||||
handleEditRequirements,
|
handleEditRequirements,
|
||||||
isScriptActive,
|
isScriptActive,
|
||||||
openAddRequirements,
|
openAddRequirements,
|
||||||
|
openReadOnlyViewerFromServer,
|
||||||
openInEditorFromServer,
|
openInEditorFromServer,
|
||||||
renderStatus,
|
renderStatus,
|
||||||
],
|
],
|
||||||
@@ -819,59 +843,86 @@ export default function ScriptsManager({ onOpenInEditor }: { onOpenInEditor?: (c
|
|||||||
|
|
||||||
<Modal
|
<Modal
|
||||||
open={editorModalVisible}
|
open={editorModalVisible}
|
||||||
title={currentEditingName ? `Editing — ${currentEditingName}` : 'Editor'}
|
title={
|
||||||
onCancel={() => setEditorModalVisible(false)}
|
currentEditingName
|
||||||
|
? `${editorReadOnly ? 'Viewing' : 'Editing'} — ${currentEditingName}`
|
||||||
|
: editorReadOnly
|
||||||
|
? 'Viewer'
|
||||||
|
: 'Editor'
|
||||||
|
}
|
||||||
|
onCancel={() => {
|
||||||
|
setEditorModalVisible(false);
|
||||||
|
setEditorReadOnly(false);
|
||||||
|
}}
|
||||||
width={900}
|
width={900}
|
||||||
footer={
|
footer={
|
||||||
<Space>
|
editorReadOnly ? (
|
||||||
<Button onClick={() => setEditorModalVisible(false)}>Close</Button>
|
|
||||||
<Button
|
<Button
|
||||||
type="default"
|
|
||||||
onClick={() =>
|
|
||||||
Modal.confirm({
|
|
||||||
title: 'Save as',
|
|
||||||
content: (
|
|
||||||
<Form
|
|
||||||
layout="vertical"
|
|
||||||
onFinish={(values) => {
|
|
||||||
handleSaveFromEditorAs(values.name);
|
|
||||||
Modal.destroyAll();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Form.Item name="name" label="Name" rules={[{ required: true }]}>
|
|
||||||
<Input placeholder="new_name.py" />
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item>
|
|
||||||
<Button htmlType="submit" type="primary">
|
|
||||||
Save
|
|
||||||
</Button>
|
|
||||||
</Form.Item>
|
|
||||||
</Form>
|
|
||||||
),
|
|
||||||
icon: null,
|
|
||||||
okButtonProps: { style: { display: 'none' } },
|
|
||||||
cancelButtonProps: { style: { display: 'none' } },
|
|
||||||
})
|
|
||||||
}
|
|
||||||
>
|
|
||||||
Save as...
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (!currentEditingName) {
|
setEditorModalVisible(false);
|
||||||
notification.warning({ message: 'No filename to overwrite' });
|
setEditorReadOnly(false);
|
||||||
return;
|
|
||||||
}
|
|
||||||
handleSaveFromEditorAs(currentEditingName);
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Save
|
Close
|
||||||
</Button>
|
</Button>
|
||||||
</Space>
|
) : (
|
||||||
|
<Space>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
setEditorModalVisible(false);
|
||||||
|
setEditorReadOnly(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Close
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
type="default"
|
||||||
|
onClick={() =>
|
||||||
|
Modal.confirm({
|
||||||
|
title: 'Save as',
|
||||||
|
content: (
|
||||||
|
<Form
|
||||||
|
layout="vertical"
|
||||||
|
onFinish={(values) => {
|
||||||
|
handleSaveFromEditorAs(values.name);
|
||||||
|
Modal.destroyAll();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Form.Item name="name" label="Name" rules={[{ required: true }]}>
|
||||||
|
<Input placeholder="new_name.py" />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item>
|
||||||
|
<Button htmlType="submit" type="primary">
|
||||||
|
Save
|
||||||
|
</Button>
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
),
|
||||||
|
icon: null,
|
||||||
|
okButtonProps: { style: { display: 'none' } },
|
||||||
|
cancelButtonProps: { style: { display: 'none' } },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Save as...
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
onClick={() => {
|
||||||
|
if (!currentEditingName) {
|
||||||
|
notification.warning({ message: 'No filename to overwrite' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
handleSaveFromEditorAs(currentEditingName);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Save
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<PythonEditor value={editorValue} onChange={setEditorValue} height={520} />
|
<PythonEditor value={editorValue} onChange={setEditorValue} height={520} readOnly={editorReadOnly} />
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
<Modal
|
<Modal
|
||||||
|
|||||||
Reference in New Issue
Block a user