# This script is intended as main script for packnl embedding, it
# dispatches to the command of the first argument.
+(context 'MAIN:SITE)
+
+(define (set-int K V) (set K (int V 0 10)))
+
+(define (set-ints K V)
+ (map (curry set-int K) (clean empty? (parse V "\\s*,?\\s*" 0))))
+
+(define (set-list K V)
+ (map (curry set K) (clean empty? (parse V "\\s*,?\\s*" 0))))
+
+(constant
+ 'FILE "hourglass.conf"
+ 'KEYS '(
+ ("libc" set)
+ ("listener.ports" set-ints)
+ ("listener.ip" set)
+ ("listener.activity.dir" set)
+ ("control.action" set)
+ ("control.dat" set)
+ ("control.net" set)
+ ("control.extra.dat" set)
+ ("control.usage.dat" set)
+ ("control.usage.tmp" set)
+
+ ("wui.port" set-int)
+ ("wui.roles" set)
+ ("wui.passwd" set)
+ )
+ )
+
+(define (setting LINE)
+ (when (regex "^\\s([^;#][^=]*)=(.*)" LINE 0)
+ (let ((KV (map trim (list $1 $2))))
+ (if (lookup (KV 0) KEYS) (apply $it (list (sym (KV 0)) (KV 1)))))))
+
+(map setting (parse (or (read-file FILE) "") "\n"))
+
+####################
+(context MAIN)
+
(if (exists file? (list (main-args 1)
(string (main-args 1) ".lsp")))
(load $it)
(write-line 2 (join (map string args)))
(exit 1))
-(constant 'NOW (date-value))
+(constant
+ 'NOW (date-value)
+ 'ACTDIR SITE:listener.activity.dir
+ 'CONTROL.DAT SITE:control.dat
+ 'EXTRA.DAT SITE:control.extra.dat
+ 'USAGE.DAT SITE:usage.dat
+ 'USAGE.TMP SITE:usage.tmp
+ )
# Set current time variables in local timezone
(map set '(YEAR MONTH DATE HOUR MINUTE SECOND DOY DOW)
DAY (list YEAR MONTH DATE)
HM (list HOUR MINUTE)
TOTAL '()
- CONTROL.DAT "control.dat"
- EXTRA.DAT "control-extra.dat"
- USAGE.DAT "usage.dat"
- USAGE.TMP ".usage.dat"
)
# Load CONTROL.DAT
(setf
GAP (or (lookup 'gap CONTROL) 15)
CLIP (or (lookup 'clip CONTROL) 1000)
- NET (or (lookup 'net CONTROL) "10.0.0.0/8")
)
# Load the configured control mechanism
;;==== Utilities for activity data
# Activity is lines of timestamps. Collect TOTAL as list of unique
# time values (H M) within the start-end time span.
+
(define (log-name-fmt t)
(format "%d%02d%02d-.*\\.dat" (0 3 (date-list t))))
(define (log-lines f)
- (find-all "([0-9]+( \\S+)?).*" (read-file (string "activity/" f)) $1 0))
+ (find-all "([0-9]+( \\S+)?).*" (read-file (format "%s/%s" ACTDIR f)) $1 0))
# Collect all timestamps of the UTC date of the given time stamp
(define (logs t)
- (flat (map log-lines (directory "activity" (log-name-fmt t)))))
+ (flat (map log-lines (directory ACTDIR (log-name-fmt t)))))
# Translate timestamp into its local time (hour minute), if it's
# within the applicable day, null otherwise.
; Updated at Sun Aug 8 22:53:01 2021
-((control "ipset-control.lsp")
- (net "192.168.104.0/24")
+((net "192.168.104.0/24")
(gap 10)
(clip 1000)
(1 timed (5 30) (2 0) (20 0))
--- /dev/null
+; Hourglass site configuration
+libc = /lib/x86_64-linux-gnu/libc.so.6
+
+listener.net = 192.168.255
+listener.ports = 80 443
+listener.activity.dir = activity
+listener.tap = hourglass
+listener.tundev = /dev/net/tun
+
+control.action = ipset-control.lsp
+control.dat = control.dat
+control.net = 10.0.0.0/8
+control.extra.dat = control-extra.dat
+control.usage.dat = usage.dat
+control.usage.tmp = .usage.dat
+
+ipset.bin = /sbin/ipset
+ipset.table = TIMO
+
+wui.port = 1070
+wui.passwd = .htpassswd
override setting, in file +control-extra.dat+, whilst also showing
current usage measure from file +usage.dat+.
+The server +hourglass-web+ is first installed with
+----
+$ ./hourglass-web install
+----
+That installation sets up a small +www+ sub directory with "CGI"
+scripting to provide the Hourglass User Interface on port 1070.
+
Hourglass Network Traffic Capture
---------------------------------
# Should load from "ipset.cfg"
-(constant 'IPSET "/sbin/ipset" 'TABLE "TIMO" )
+(constant 'IPSET SITE:ipset.bin 'TABLE SITE:ipset.table NET SITE:control.net)
;; Return current low-leve "close" or "open" status
(define (current-status)
- (if (exec (format "%s list %s | grep %s" IPSET TABLE NET)) "close" "open"))
+ (if (member NET (exec (format "%s list %s" IPSET TABLE))) "close" "open"))
;; Ensure low-level setting is "close" or "open" as given
(define (control cmd reason)
(signal 2 (fn (x) (exit 0)))
# The following is for Devuan GNU+Linux
-(constant 'LIBC (exists file? '("/lib/x86_64-linux-gnu/libc.so.6"
- "/lib/i386-linux-gnu/libc.so.6"
- )))
+(constant 'LIBC SITE:libc)
(import LIBC "ioctl" "int" "int" "long" "void*" )
(import LIBC "perror" "void" "char*" )
(import LIBC "ntohl" "int" "int" )
(if (null? a) v (nil? v) true (null? (1 a)) v (a 1))))
# Set logging mode.
-(constant 'listener-log-ip (mainarg "-l" nil))
-
# Open the tap named by "-t tapX" on the command line, or "tap0" byt
# default. Then make a TUNSETIFF call to initialize it (as
# IFF_TAP|IFF_NO_PI).
-(constant 'IFNAME (mainarg "-t" "tap0") 'IFD (open "/dev/net/tun" "u") )
+(constant
+ 'listener-log-ip SITE:listener.ip
+ 'IFNAME SITE:listener.tap
+ 'PORTS SITE:listener.ports
+ 'IFD (open SITE:listener.tundev "u")
+ 'ACTNAMEFMT "%d%02d%02d-network.dat"
+ 'ACTDIR SITE:listener.activity.dir
+ 'ACTFILEFMT (format "%s/%s" ACTDIR ACTNAMEFMT )
+)
(unless (number? IFD) (die "open"))
(unless (zero? (ioctl IFD 0x400454ca (pack "s16 u s22" IFNAME 0x1002 "")))
(die (string "set " IFNAME)))
# The TCP ports of interest
-(constant 'PORTS '(80 443))
# Set up for optional tracking of IP addresses
(define counter:counter nil)
# This funcion collates all given ips, and it extends the log line
# with the list of ips used during the minute.
(setf next-mark 0 packet-count 0)
+
(define (mark-active t) ; buffer
(when listener-log-ip (track-data))
(inc packet-count)
;(write-line 2 (string (list t packet-count ports (counter))))
(when (>= t next-mark)
- (let ((d (format "activity/%d%02d%02d-network.dat" (0 3 (date-list t))))
+ (let ((d (format ACTFILEFMT (0 3 (date-list t))))
(c (map string (counter))))
(append-file d (string t " " packet-count " " (join c " ") "\n"))
(setf next-mark (+ t 60) packet-count 0)
(write-line 1 (read-file "tmpl/unauthorized.http"))
(exit 0))
-(define (role-script ROLE)
+;; Determine actual script name respecting given role, if any.
+(define (role-script (ROLE "."))
(let ((CMD (and (regex "([^/]*).cgi$" (main-args 0) 0) $1)))
- (if (= "." ROLE) (string CMD ".lsp")
- (format "%s/%s.lsp" ROLE CMD))))
+ (if (= "." ROLE) (string CMD ".lsp") (format "%s/%s.lsp" ROLE CMD))))
(setf
- ROLES (map (fn (x) (parse x ":")) (parse (read-file "roles.txt") "\n"))
REMOTE_USER (and (regex "([^:]+):" (base64-dec (6 AUTH)) 0) $1)
- ROLE (or (lookup REMOTE_USER ROLES) "child")
- SCRIPT (role-script ROLE)
+ SCRIPT (role-script)
)
(env "REMOTE_USER" REMOTE_USER)
(env "ROLE" ROLE)
#!/usr/bin/newlisp
#
-# Install the Hourglass service to new directory www
+# Install the Hourglass web tree to a new "www" subdirectory
(when (directory? "www")
(write-line 2 "** directory www exists. aborting")
</select>
networks packets in a minute, to count as activity.
</div>
- <div id="net_field" class="extra">
- <input type="textfield" name="net" value="<?newlisp NET ?>">
- controlled network.
- </div>
</div>
<div id="form_submit" class="extra" >
<?newlisp UPDATE?>
exit 1
}
-SERVICE=manager/hourglass-web
+SERVICE=hourglass-web
[ -f "$SERVICE" ] || die "** missing $SERVICE ** aborting"
# This is a control script to start and stop the network activity
# listening.
-CMD=${1-start}
-NET=192.168.249
-TAP=hourglass0
-SET=TIMO
+CONF="hourglass.conf"
+function getcfg() {
+ grep -E "\\s*[^;#]$1]\\s*=" $CONF | sed 's/.*=\s*(.*)/\1/;s/\s*$//'
+}
+
+NET="$(getcfg listener.ip)"
+TAP="$(getcfg listener.tap)"
+SET="$(getcfg ipset.table)"
cd $(dirname $0)