-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathn8n-workflow.json
More file actions
131 lines (131 loc) · 8.72 KB
/
Copy pathn8n-workflow.json
File metadata and controls
131 lines (131 loc) · 8.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
{
"name": "Technitium DNS -> UniFi Log Insights DNS v0.1.3",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "technitium-dns-log-export",
"responseMode": "responseNode",
"options": {}
},
"type": "n8n-nodes-base.webhook",
"typeVersion": 2.1,
"position": [-1424, -352],
"id": "92c183f1-3018-41d4-a600-1dadfa8e7ebd",
"name": "Webhook"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "5d6769e1-0808-43ed-92da-022acbb4d9fb",
"leftValue": "={{$json.headers['x-log-exporter-token']}}",
"rightValue": "CHANGE_ME_SHARED_TOKEN",
"operator": {
"type": "string",
"operation": "equals",
"name": "filter.operator.equals"
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.3,
"position": [-1200, -352],
"id": "32dc90c4-0891-45d9-9ebf-73297e5b9f27",
"name": "If"
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={\"ok\":true}",
"options": {
"responseCode": 200
}
},
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.5,
"position": [-528, -448],
"id": "05473b99-1c82-4b15-9da9-e6b3a97ebdc7",
"name": "Respond to Webhook 'true'"
},
{
"parameters": {
"respondWith": "text",
"responseBody": "{{ JSON.stringify($json) }}",
"options": {
"responseCode": 403
}
},
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.5,
"position": [-976, -256],
"id": "c515fd27-ea49-49c8-8d24-740c03752a3a",
"name": "Respond to Webhook 'forbidden'"
},
{
"parameters": {
"command": "={{ \"sh -lc 'printf \\\"%s\\\\n\\\" \" + JSON.stringify($json.syslogLine) + \" | nc -u -w1 unifi-log-insight 514'\" }}"
},
"type": "n8n-nodes-base.executeCommand",
"typeVersion": 1,
"position": [-752, -448],
"id": "d522ddd8-3ae5-4ca9-9b20-4b9d4cd90c88",
"name": "Execute Command"
},
{
"parameters": {
"jsCode": "const inputItem = $input.first();\nconst payload = inputItem.json?.body ?? [];\nconst entries = Array.isArray(payload) ? payload : [payload];\n\nconst blockedTypes = new Set([\"SOA\", \"IXFR\"]);\nconst blockedClientIps = new Set([\n \"172.22.16.1\",\n \"172.21.16.1\",\n]);\n\nfunction formatRfc3164Utc(ts) {\n const hasExplicitTimestamp =\n ts !== null &&\n ts !== undefined &&\n String(ts).trim() !== \"\";\n\n const date = hasExplicitTimestamp ? new Date(ts) : new Date();\n\n if (Number.isNaN(date.getTime())) {\n return null;\n }\n\n const months = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\",\n \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"];\n\n const mon = months[date.getUTCMonth()];\n const day = date.getUTCDate();\n const dd = day < 10 ? ` ${day}` : `${day}`;\n const hh = String(date.getUTCHours()).padStart(2, \"0\");\n const mm = String(date.getUTCMinutes()).padStart(2, \"0\");\n const ss = String(date.getUTCSeconds()).padStart(2, \"0\");\n\n return `${mon} ${dd} ${hh}:${mm}:${ss}`;\n}\n\nfunction tryParseJsonString(value) {\n if (typeof value !== \"string\" || !value.trim()) return null;\n try {\n return JSON.parse(value);\n } catch {\n return null;\n }\n}\n\nfunction normalizeClientIp(value) {\n const raw = String(value ?? \"\").trim();\n if (!raw) return \"\";\n\n const bracketedIpv6 = raw.match(/^\\[([0-9a-fA-F:.]+)\\](?::\\d+)?$/);\n if (bracketedIpv6) return bracketedIpv6[1];\n\n const ipv4WithPort = raw.match(/^((?:\\d{1,3}\\.){3}\\d{1,3})(?::\\d+)?$/);\n if (ipv4WithPort) return ipv4WithPort[1];\n\n return raw;\n}\n\nconst out = [];\n\nfor (const entry of entries) {\n const parsed =\n tryParseJsonString(entry?.RenderedMessage) ??\n tryParseJsonString(entry?.MessageTemplate) ??\n (entry && typeof entry === \"object\" ? entry : null);\n\n if (!parsed || typeof parsed !== \"object\") {\n out.push({\n json: {\n ok: true,\n forwarded: false,\n skipReason: \"unparsable_log_entry\",\n original: entry,\n },\n });\n continue;\n }\n\n const timestampRaw =\n parsed.timestamp ??\n parsed.Timestamp ??\n entry?.Timestamp ??\n null;\n\n const clientIpRaw =\n parsed.clientIp ??\n parsed.clientIPAddress ??\n parsed.client ??\n parsed.remoteAddress ??\n null;\n\n const question = parsed.question ?? {};\n const questionName =\n question.questionName ??\n question.name ??\n parsed.questionName ??\n parsed.domain ??\n null;\n\n const questionType =\n question.questionType ??\n question.type ??\n parsed.questionType ??\n parsed.type ??\n null;\n\n const protocolRaw = String(parsed.protocol ?? \"\").trim();\n const responseCodeRaw = String(parsed.responseCode ?? \"\").trim();\n const responseTypeRaw = String(parsed.responseType ?? \"\").trim();\n\n const normalizedType = String(questionType ?? \"\").trim().toUpperCase();\n const normalizedName = String(questionName ?? \"\").trim();\n const normalizedClientIp = normalizeClientIp(clientIpRaw);\n\n let skipReason = null;\n\n if (!normalizedType) {\n skipReason = \"missing_question_type\";\n } else if (!normalizedName) {\n skipReason = \"missing_question_name\";\n } else if (!normalizedClientIp) {\n skipReason = \"missing_client_ip\";\n } else if (blockedTypes.has(normalizedType)) {\n skipReason = `filtered_type_${normalizedType}`;\n } else if (blockedClientIps.has(normalizedClientIp)) {\n skipReason = `filtered_client_${normalizedClientIp}`;\n }\n\n if (skipReason) {\n out.push({\n json: {\n ok: true,\n forwarded: false,\n skipReason,\n original: parsed,\n originalEntry: entry,\n },\n });\n continue;\n }\n\n const rfc3164Timestamp = formatRfc3164Utc(timestampRaw);\n\n if (!rfc3164Timestamp) {\n out.push({\n json: {\n ok: true,\n forwarded: false,\n skipReason: \"invalid_timestamp\",\n parsed: {\n timestampRaw,\n clientIp: normalizedClientIp,\n questionName: normalizedName,\n questionType: normalizedType,\n protocol: protocolRaw || null,\n responseCode: responseCodeRaw || null,\n responseType: responseTypeRaw || null,\n },\n original: parsed,\n originalEntry: entry,\n },\n });\n continue;\n }\n\n const extras = [\n protocolRaw ? `proto=${protocolRaw}` : null,\n responseCodeRaw ? `rcode=${responseCodeRaw}` : null,\n responseTypeRaw ? `rtype=${responseTypeRaw}` : null,\n ].filter(Boolean).join(\" \");\n\n const syslogLine =\n `<14>${rfc3164Timestamp} technitium-dns dnsmasq[1]: ` +\n `query[${normalizedType}] ${normalizedName} from ${normalizedClientIp}` +\n (extras ? ` ${extras}` : \"\");\n\n out.push({\n json: {\n ok: true,\n forwarded: true,\n skipReason: null,\n syslogLine,\n parsed: {\n timestampRaw,\n clientIp: normalizedClientIp,\n questionName: normalizedName,\n questionType: normalizedType,\n protocol: protocolRaw || null,\n responseCode: responseCodeRaw || null,\n responseType: responseTypeRaw || null,\n },\n original: parsed,\n originalEntry: entry,\n },\n });\n}\n\nreturn out;"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [-976, -448],
"id": "97cd12c2-45af-4d53-9565-9e73de57d5f2",
"name": "Transform -> RFC"
}
],
"pinData": {},
"connections": {
"Webhook": {
"main": [[{ "node": "If", "type": "main", "index": 0 }]]
},
"If": {
"main": [
[{ "node": "Transform -> RFC", "type": "main", "index": 0 }],
[{ "node": "Respond to Webhook 'forbidden'", "type": "main", "index": 0 }]
]
},
"Respond to Webhook 'forbidden'": {
"main": [[]]
},
"Execute Command": {
"main": [
[{ "node": "Respond to Webhook 'true'", "type": "main", "index": 0 }]
]
},
"Transform -> RFC": {
"main": [
[{ "node": "Execute Command", "type": "main", "index": 0 }]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1",
"binaryMode": "separate",
"timeSavedMode": "fixed",
"callerPolicy": "workflowsFromSameOwner",
"availableInMCP": false
},
"id": "Tg9HDazIJTo8ycJs"
}