Skip to content

Commit af22a57

Browse files
committed
net-mgmt/pfSense-pkg-ANDwatch: Add ANDwatch package. Implement #16070.
1 parent aa54860 commit af22a57

File tree

13 files changed

+919
-0
lines changed

13 files changed

+919
-0
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
2+
PORTNAME= pfSense-pkg-ANDwatch
3+
PORTVERSION= 2.1
4+
CATEGORIES= net-mgmt
5+
MASTER_SITES= # empty
6+
DISTFILES= # empty
7+
8+
MAINTAINER= dennypage@me.com
9+
COMMENT= pfSense package ANDwatch
10+
WWW= https://github.com/dennypage/andwatch
11+
12+
LICENSE= APACHE20
13+
14+
RUN_DEPENDS= andwatch>=2.1.0:net-mgmt/andwatch
15+
16+
NO_BUILD= yes
17+
NO_MTREE= yes
18+
19+
SUB_FILES= pkg-install pkg-deinstall
20+
SUB_LIST= PORTNAME=${PORTNAME}
21+
22+
do-extract:
23+
${MKDIR} ${WRKSRC}
24+
25+
do-install:
26+
${MKDIR} ${STAGEDIR}${PREFIX}/pkg
27+
${MKDIR} ${STAGEDIR}/etc/inc/priv
28+
${MKDIR} ${STAGEDIR}${PREFIX}/www/shortcuts
29+
${MKDIR} ${STAGEDIR}${DATADIR}
30+
${INSTALL_DATA} ${FILESDIR}${PREFIX}/pkg/andwatch.xml \
31+
${STAGEDIR}${PREFIX}/pkg
32+
${INSTALL_DATA} ${FILESDIR}${PREFIX}/pkg/andwatch.inc \
33+
${STAGEDIR}${PREFIX}/pkg
34+
${INSTALL_DATA} ${FILESDIR}${PREFIX}/pkg/andwatch-notify.php \
35+
${STAGEDIR}${PREFIX}/pkg
36+
${INSTALL_DATA} ${FILESDIR}/etc/inc/priv/andwatch.priv.inc \
37+
${STAGEDIR}/etc/inc/priv
38+
${INSTALL_DATA} ${FILESDIR}${DATADIR}/info.xml \
39+
${STAGEDIR}${DATADIR}
40+
${INSTALL_DATA} ${FILESDIR}${PREFIX}/www/shortcuts/pkg_andwatch.inc \
41+
${STAGEDIR}${PREFIX}/www/shortcuts
42+
${INSTALL_DATA} ${FILESDIR}${PREFIX}/www/andwatch.php \
43+
${STAGEDIR}${PREFIX}/www
44+
${INSTALL_DATA} ${FILESDIR}${PREFIX}/www/status_andwatch.php \
45+
${STAGEDIR}${PREFIX}/www
46+
${CHMOD} 555 ${STAGEDIR}${PREFIX}/pkg/andwatch-notify.php
47+
48+
@${REINPLACE_CMD} -i '' -e "s|%%PKGVERSION%%|${PKGVERSION}|" \
49+
${STAGEDIR}${DATADIR}/info.xml
50+
51+
.include <bsd.port.mk>
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
/*
3+
* andwatch.priv.inc
4+
*
5+
* part of pfSense (https://www.pfsense.org)
6+
* Copyright (c) 2025 Denny Page
7+
* All rights reserved.
8+
*
9+
* Licensed under the Apache License, Version 2.0 (the "License");
10+
* you may not use this file except in compliance with the License.
11+
* You may obtain a copy of the License at
12+
*
13+
* http://www.apache.org/licenses/LICENSE-2.0
14+
*
15+
* Unless required by applicable law or agreed to in writing, software
16+
* distributed under the License is distributed on an "AS IS" BASIS,
17+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18+
* See the License for the specific language governing permissions and
19+
* limitations under the License.
20+
*/
21+
22+
global $priv_list;
23+
24+
$priv_list['page-services-andwatch'] = array();
25+
$priv_list['page-services-andwatch']['name'] = "WebCfg - Services: ANDwatch";
26+
$priv_list['page-services-andwatch']['descr'] = "Access the ANDwatch package configuration";
27+
$priv_list['page-services-andwatch']['match'] = array();
28+
$priv_list['page-services-andwatch']['match'][] = "andwatch.php";
29+
30+
$priv_list['page-status-andwatch'] = array();
31+
$priv_list['page-status-andwatch']['name'] = "WebCfg - Status: ANDwatch Database";
32+
$priv_list['page-status-andwatch']['descr'] = "Access the ANDwatch package database";
33+
$priv_list['page-status-andwatch']['match'] = array();
34+
$priv_list['page-status-andwatch']['match'][] = "status_andwatch.php*";
35+
36+
?>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/bin/sh
2+
3+
/usr/local/bin/php -f /etc/rc.packages %%PORTNAME%% ${2}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/bin/sh
2+
3+
if [ "${2}" != "POST-INSTALL" ]; then
4+
exit 0
5+
fi
6+
7+
${PKG_ROOTDIR}/usr/local/bin/php -f ${PKG_ROOTDIR}/etc/rc.packages %%PORTNAME%% ${2}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#!/usr/bin/env php
2+
<?php
3+
require_once("notices.inc");
4+
5+
$timestamp=$argv[1];
6+
$ifname=convert_real_interface_to_friendly_descr($argv[2]);
7+
$hostname=$argv[3];
8+
$ipaddr=$argv[4];
9+
$new_hwaddr=$argv[5];
10+
$new_hwaddr_org=$argv[6];
11+
$old_hwaddr=$argv[7];
12+
$old_hwaddr_org=$argv[8];
13+
14+
$msg = "\nANDwatch notificaton\n\n";
15+
$msg .= sprintf("%22s: %s\n", "timestamp", $timestamp);
16+
$msg .= sprintf("%22s: %s\n", "interface", $ifname);
17+
$msg .= sprintf("%22s: %s\n", "hostname", $hostname);
18+
$msg .= sprintf("%22s: %s\n", "ip address", $ipaddr);
19+
$msg .= sprintf("%22s: %s\n", "new ethernet address", $new_hwaddr);
20+
$msg .= sprintf("%22s: %s\n", "new ethernet org", $new_hwaddr_org);
21+
$msg .= sprintf("%22s: %s\n", "old ethernet address", $old_hwaddr);
22+
$msg .= sprintf("%22s: %s\n", "old ethernet org", $old_hwaddr_org);
23+
24+
notify_all_remote($msg);
25+
?>
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
<?php
2+
/*
3+
* andwatch.inc
4+
*
5+
* part of pfSense (https://www.pfsense.org)
6+
* Copyright (c) 2025 Denny Page
7+
* All rights reserved.
8+
*
9+
* Licensed under the Apache License, Version 2.0 (the "License");
10+
* you may not use this file except in compliance with the License.
11+
* You may obtain a copy of the License at
12+
*
13+
* http://www.apache.org/licenses/LICENSE-2.0
14+
*
15+
* Unless required by applicable law or agreed to in writing, software
16+
* distributed under the License is distributed on an "AS IS" BASIS,
17+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18+
* See the License for the specific language governing permissions and
19+
* limitations under the License.
20+
*/
21+
22+
require_once("config.inc");
23+
require_once("functions.inc");
24+
require_once("util.inc");
25+
require_once("service-utils.inc");
26+
27+
const ANDWATCH_SVC_NAME = 'andwatchd';
28+
const ANDWATCH_RC_FILE = '/usr/local/etc/rc.d/andwatch.sh';
29+
const ANDWATCHD_CMD = '/usr/local/bin/andwatchd';
30+
const ANDWATCHD_NOTIFY_CMD = '/usr/local/pkg/andwatch-notify.php';
31+
const ANDWATCHD_PID_PREFIX = '/var/run/andwatch-';
32+
const ANDWATCH_MA_DB_FILE = '/var/db/andwatch/ma_db.sqlite';
33+
const ANDWATCH_UPDATE_MA_CMD = '/usr/local/bin/andwatch-update-ma';
34+
const ANDWATCH_QUERY_CMD = '/usr/local/bin/andwatch-query';
35+
36+
$shortcut_section = 'andwatch';
37+
38+
// Is ANDwatch enabled?
39+
function andwatch_enabled() {
40+
return (config_get_path('installedpackages/andwatch/enable', false));
41+
}
42+
43+
44+
// Write the rc file
45+
function andwatch_write_rcfile() {
46+
// Get the current configuration
47+
$current_config = config_get_path('installedpackages/andwatch');
48+
49+
// Get the real interface names
50+
$interfaces = array();
51+
foreach (array_filter(explode(',', array_get_path($current_config, 'active_interfaces', ''))) as $interface) {
52+
$interface_name = get_real_interface($interface);
53+
if (!isset($interface_name)) {
54+
continue;
55+
}
56+
$interfaces[$interface] = $interface_name;
57+
}
58+
59+
// Ensure the assignments database exists
60+
$start = "if [ \! -f " . ANDWATCH_MA_DB_FILE . " ]\n";
61+
$start .= "\tthen\n";
62+
$start .= "\t\techo Updating MAC Assignments database\n";
63+
$start .= "\t\t" . ANDWATCH_UPDATE_MA_CMD . "\n";
64+
$start .= "\tfi\n\n";
65+
66+
// Individual daemons
67+
$start .= "\techo Starting ANDwatch daemons";
68+
foreach ($interfaces as $interface => $real_interface) {
69+
// Basic configuration with syslog and pid file
70+
$cmd = ANDWATCHD_CMD . " -s -p " . ANDWATCHD_PID_PREFIX . "{$real_interface}.pid";
71+
72+
// Notifications
73+
if (array_get_path($current_config, "interfaces/{$interface}/notifications", false)) {
74+
$cmd .= " -n " . ANDWATCHD_NOTIFY_CMD;
75+
}
76+
77+
// Expiration (andwatchd default is 30)
78+
$expiration = array_get_path($current_config, "interfaces/{$interface}/expiration", '30');
79+
if (is_numericint($expiration) && ($expiration != '30')) {
80+
$cmd .= " -O {$expiration}";
81+
}
82+
83+
// PCAP filter
84+
$filter = null;
85+
switch (array_get_path($current_config, "interfaces/{$interface}/pcap_filter", 'none')) {
86+
case 'link-local':
87+
$filter = "'not net 169.254.0.0/16 and not net fe80::0/10'";
88+
break;
89+
case 'link-local-unique':
90+
$filter = "'not net 169.254.0.0/16 and not net fe80::0/10 and not net fc00::0/7'";
91+
break;
92+
case 'custom':
93+
$filter = escapeshellarg(trim(array_get_path($current_config, "interfaces/{$interface}/custom_filter")));
94+
break;
95+
}
96+
if (!empty($filter)) {
97+
$cmd .= " -F " . $filter;
98+
}
99+
100+
$cmd .= " {$real_interface}";
101+
$start .= "\n\t{$cmd}";
102+
}
103+
104+
// Write the rc file
105+
$stop = '/usr/bin/killall ' . ANDWATCH_SVC_NAME;
106+
write_rcfile(array(
107+
"file" => "andwatch.sh",
108+
"start" => $start,
109+
"stop" => $stop
110+
)
111+
);
112+
}
113+
114+
115+
// Sync the config
116+
function andwatch_sync_config() {
117+
// Stop the service if it is currently running
118+
if (is_service_running(ANDWATCH_SVC_NAME)) {
119+
log_error("Stopping service ANDwatch");
120+
stop_service(ANDWATCH_SVC_NAME);
121+
}
122+
123+
// If the service is now disabled, remove the cron job and rc file
124+
if (!andwatch_enabled()) {
125+
install_cron_job(ANDWATCH_UPDATE_MA_CMD, false);
126+
unlink_if_exists(ANDWATCH_RC_FILE);
127+
return;
128+
}
129+
130+
// Set a cron job to update the MAC registration database
131+
$cron_already_installed = false;
132+
foreach (config_get_path('cron/item', []) as $item) {
133+
if ($item['command'] == ANDWATCH_UPDATE_MA_CMD) {
134+
$cron_already_installed = true;
135+
break;
136+
}
137+
}
138+
if ($cron_already_installed == false) {
139+
install_cron_job(ANDWATCH_UPDATE_MA_CMD, true, rand(0,59), rand(0,23), '1,15', '*', '*', 'root', true);
140+
}
141+
142+
// Write the rc file
143+
andwatch_write_rcfile();
144+
145+
// Take no further action during platform boot
146+
if (is_platform_booting()) {
147+
return;
148+
}
149+
150+
// Start the service
151+
log_error("Starting service ANDwatch");
152+
start_service(ANDWATCH_SVC_NAME);
153+
}
154+
155+
156+
// Clean up on deinstall
157+
function andwatch_deinstall_command() {
158+
if (is_service_running(ANDWATCH_SVC_NAME)) {
159+
log_error("Stopping service ANDwatch");
160+
stop_service(ANDWATCH_SVC_NAME);
161+
}
162+
163+
install_cron_job(ANDWATCH_UPDATE_MA_CMD, false);
164+
unlink_if_exists(ANDWATCH_RC_FILE);
165+
}
166+
167+
168+
// Run a query
169+
function andwatch_query_interface($ifname, $all = false)
170+
{
171+
$entries = array();
172+
173+
// Build the query command
174+
$cmd = ANDWATCH_QUERY_CMD;
175+
if ($all) {
176+
$cmd .= ' -a';
177+
}
178+
$cmd .= ' ' . get_real_interface($ifname);
179+
180+
// Run the query
181+
$pipe = popen($cmd, 'r');
182+
if ($pipe) {
183+
while ($line = fgets($pipe)) {
184+
list($date, $time, $age, $hostname, $ipaddr, $hwaddr, $org) = sscanf(trim($line), '%s %s %s %s %s %s %[^$]s');
185+
$entry = [
186+
'datetime' => "$date $time",
187+
'age' => $age,
188+
'hostname' => $hostname,
189+
'ipaddr' => $ipaddr,
190+
'hwaddr' => $hwaddr,
191+
'org' => $org
192+
];
193+
$entries[] = $entry;
194+
}
195+
pclose($pipe);
196+
}
197+
198+
return $entries;
199+
}
200+
201+
?>
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<!DOCTYPE packagegui SYSTEM "../schema/packages.dtd">
3+
<?xml-stylesheet type="text/xsl" href="../xsl/package.xsl"?>
4+
<packagegui>
5+
<copyright>
6+
<![CDATA[
7+
/*
8+
* andwatch.xml
9+
*
10+
* part of pfSense (https://www.pfsense.org)
11+
* Copyright (c) 2025 Denny Page
12+
* All rights reserved.
13+
*
14+
* Licensed under the Apache License, Version 2.0 (the "License");
15+
* you may not use this file except in compliance with the License.
16+
* You may obtain a copy of the License at
17+
*
18+
* http://www.apache.org/licenses/LICENSE-2.0
19+
*
20+
* Unless required by applicable law or agreed to in writing, software
21+
* distributed under the License is distributed on an "AS IS" BASIS,
22+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23+
* See the License for the specific language governing permissions and
24+
* limitations under the License.
25+
*/
26+
]]>
27+
</copyright>
28+
<name>andwatch</name>
29+
<title>Services: ANDwatch</title>
30+
<include_file>/usr/local/pkg/andwatch.inc</include_file>
31+
<menu>
32+
<name>ANDwatch</name>
33+
<tooltiptext>ANDwatch Settings</tooltiptext>
34+
<section>Services</section>
35+
<url>/andwatch.php</url>
36+
</menu>
37+
<menu>
38+
<name>ANDwatch Database</name>
39+
<tooltiptext>ANDwatch Database</tooltiptext>
40+
<section>Status</section>
41+
<url>/status_andwatch.php</url>
42+
</menu>
43+
<service>
44+
<name>andwatchd</name>
45+
<rcfile>andwatch.sh</rcfile>
46+
<executable>andwatchd</executable>
47+
<description>ANDwatch Daemon</description>
48+
<starts_on_sync></starts_on_sync>
49+
</service>
50+
<custom_php_resync_config_command>
51+
andwatch_sync_config();
52+
</custom_php_resync_config_command>
53+
<custom_php_pre_deinstall_command>
54+
andwatch_deinstall_command();
55+
</custom_php_pre_deinstall_command>
56+
</packagegui>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0"?>
2+
<pfsensepkgs>
3+
<package>
4+
<name>ANDwatch</name>
5+
<website>https://github.com/dennypage/andwatch/</website>
6+
<descr><![CDATA[ANDwatch monitors ARP and Neighbor Discovery activity, maintains a database of IP to Ethernet address mappings, and sends notifications when a mapping changes.]]></descr>
7+
<version>%%PKGVERSION%%</version>
8+
<configurationfile>andwatch.xml</configurationfile>
9+
</package>
10+
</pfsensepkgs>

0 commit comments

Comments
 (0)