Beim Ändern von ignore-Regelsätzen für logcheck unterlaufen mir ganz gern Tippfehler in komplexeren Ausdrücken. Dumm nur, wenn ich das erst beim nächsten Cron-Run merke, in Form einer solchen Meldung:
egrep: Unmatched ) or \)
Toll: weder Regelsatz noch Zeilennummer werden genannt, also manuell suchen. Da es sich aber meist um umfangreiche Regelsätze handelt und ich (selbst bei gefundenem Satz) keine Möglichkeit gefunden habe, egrep die Zeilennummer des ungültigen Ausdrucks zu entlocken, entstand auf die Schnelle folgendes simples Script:
#!/bin/bash
if [ $# -ne 1 ]; then
echo "usage: $0 RULES_FILE"
exit 1
fi
if ! [ -r "$1" ]; then
echo "unable to read $1"
exit 1
fi
LINES=$(wc -l "$1" | cut -d ' ' -f 1)
for I in $(seq $LINES); do
echo "line $I..."
echo "foo" | egrep "$(cat "$1" | head -n $I | tail -n 1)"
done
exit 0
Es gibt bestimmt auch irgendeine elegantere Lösung, aber vielleicht erspart es ja jemandem die nervige Sucherei
Ja, das vom Paket iptables mitgebrachte init-script leistet wunderbare Dienste. Nein, es besteht kein akuter Grund, eine Alternative zu schreiben…
Einen Nachteil hat es schon: die Konfiguration wird in einem nicht kommentierbaren Format hinterlegt, was bei mir in letzter Zeit ständig zur Frage “WTF hat doch gleich dieser Port da verloren? Was lässt die rule da nochmal durch?” geführt hat.
<bash-addicted>Yep, eindeutige Notwenigkeit für ein selbst gehämmertes, kommentierbares Script!</bash-addicted> Wie in guten alten Debian-Zeiten übernimmt jetzt also bei mir ein einfaches, aber für den Job völlig ausreichendes init-script den Job. Wer es verwenden mag:
#!/bin/bash
#
# easy-to-edit iptables init script for Arch
# 2010 by Alexander Koch
#
# TCP services: ssh
SERVICES_TCP=( 22 )
# UDP services:
SERVICES_UDP=( )
. /etc/rc.conf
. /etc/rc.d/functions
if [ -e "/etc/conf.d/iptables" ]; then
. /etc/conf.d/iptables
fi
if [ -z "$IPTABLES" ]; then
IPTABLES="/usr/sbin/iptables"
fi
if ! [ -x "$IPTABLES" ]; then
echo "unable to execute iptables binary: $IPTABLES"
exit 1
fi
function reset_tables() {
ERR=0
$IPTABLES -F || ERR=1
$IPTABLES -X || ERR=1
$IPTABLES -P INPUT ACCEPT || ERR=1
$IPTABLES -P OUTPUT ACCEPT || ERR=1
if [ $IPTABLES_FORWARD -eq 1 ]; then
$IPTABLES -P FORWARD ACCEPT || ERR=1
echo 1 >/proc/sys/net/ipv4/ip_forward || ERR=1
else
$IPTABLES -P FORWARD DROP || ERR=1
echo 0 >/proc/sys/net/ipv4/ip_forward || ERR=1
fi
return $ERR
}
function setup_tables() {
ERR=0
# setup prevention chain against common attacks
$IPTABLES -N preventions || ERR=1
$IPTABLES -A preventions -f -j DROP || ERR=1 # frags
$IPTABLES -A preventions -p tcp --tcp-flags ALL ALL -j DROP || ERR=1 # XMAS
$IPTABLES -A preventions -p tcp --tcp-flags ALL NONE -j DROP || ERR=1 # null
# setup services chain
$IPTABLES -N services || ERR=1
for PORT in ${SERVICES_TCP[@]}; do
$IPTABLES -A services -p tcp --dport $PORT -j ACCEPT || ERR=1
done
for PORT in ${SERVICES_UDP[@]}; do
$IPTABLES -A services -p udp --dport $PORT -j ACCEPT || ERR=1
done
# allow incoming ping requests
iptables -A services -p icmp --icmp-type echo-request -j ACCEPT || ERR=1
# setup main chains
$IPTABLES -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT || ERR=1
$IPTABLES -A INPUT -i lo -j ACCEPT || ERR=1
$IPTABLES -A INPUT -j preventions || ERR=1
$IPTABLES -A INPUT -m state --state NEW -j services || ERR=1
$IPTABLES -A INPUT -p tcp -j REJECT --reject-with tcp-reset || ERR=1
$IPTABLES -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable || ERR=1
$IPTABLES -P INPUT DROP || ERR=1
return $ERR
}
case "$1" in
start)
stat_busy "Loading IP Tables"
reset_tables
if ! setup_tables; then
stat_fail
exit 1
else
add_daemon miptables
stat_done
fi
;;
stop)
stat_busy "Flushing IP Tables"
if reset_tables; then
rm_daemon miptables
stat_done
else
stat_fail
exit 1
fi
;;
restart)
if ! ck_daemon miptables; then
rm_daemon miptables
fi
$0 start
exit $?
;;
*)
echo "usage: $0 {start|stop|restart}"
;;
esac
exit 0
Gefiltert werden nur eingehende Pakete; related und established Pakete werden ebenfalls ohne weitere Beachtung durchgelassen, ebenso alles über loopback. Für neue Pakete werden zuerst ein paar Vulnerability-Checks durchgeführt. Nach Außen wird ein Verhalten wie ohne iptables emuliert (z.B. REJECTs mit tcp-reset).
Bugreports wie immer willkommen, und Benutzung auf eigene Gefahr!
Update 31.07.10: Bugfixed
Im Arch Bootscript /etc/rc.sysinit werden u.A. die per /etc/crypttab definierten verschlüsselten Volumes geöffnet und gemountet – sequentiell. Da ein luksOpen-Aufruf generell schon recht lange dauert, kommen bei mehreren solcher Volumes schnell einige Sekunden zusammen.
Auf einer Kiste mit fünf LUKS-Volumes kam mir die Idee, die entsprechende Funktion mal per “&” zu forken und das Ganze so ein wenig zu parallelisieren.
In wie fern das jetzt tatsächlich im messbaren Bereich liegt, sei mal dahingestellt. Ich bilde mir jedenfalls erfolgreich einen Geschwindigkeits-zuwachs ein, und da der Patch meines Erachtens recht unkritisch ist, bleibe ich dabei
Wer es ausprobieren mag:
--- /etc/rc.sysinit.backup 2010-01-24 15:35:12.000000000 +0100
+++ /etc/rc.sysinit 2010-05-04 18:57:53.380890577 +0200
@@ -149,7 +149,7 @@
cpass="$3"
shift 3
copts="$*"
- stat_append "${cname}.."
+ #stat_append "${cname}.."
# For some fun reason, the parameter ordering varies for
# LUKS and non-LUKS devices. Joy.
if [ "${cpass}" = "SWAP" ]; then
@@ -188,15 +188,16 @@
fi
if [ $? -ne 0 ]; then
csfailed=1
- stat_append "failed "
+ stat_append "${cname} failed "
else
- stat_append "ok "
+ stat_append "${cname} ok "
fi
fi
}
while read line; do
- eval do_crypt "$line"
+ eval do_crypt "$line" &
done </etc/crypttab
+ wait
if [ $csfailed -eq 0 ]; then
stat_done
else
In meinem Arch Ramdisk-Script <1.4 hatte sich ein dämlicher Bug eingeschlichen: bei sämtlichen rsync-Aufrufen fehlte das --delete.
Das bewirkt z.B. bei Verwendung mit Firefox, dass der Cache nie geleert wird und (streng) monoton wächst – unschön.
Hier die gefixte Version
#!/bin/sh
#
# Manages outsourcing of specified directories into memory on bootup and
# takes care of synchronization/backup on system shutdown.
#
# Version 1.4, 2010-04-26, by Alexander Koch
#
# includes
. /etc/rc.conf
. /etc/rc.d/functions
# configuration (syntax is: [persist. storage]:[mountpoint]:[mount options])
DISKS=('/home/alex/.ramdisks/_mozilla:/home/alex/.mozilla:size=100M,uid=1000,gid=100' \
'empty:/home/alex/.adobe:size=10M,uid=1000,gid=100' \
'empty:/home/alex/.macromedia:size=10M,uid=1000,gid=100')
# helper functions
function activate_rd() {
[ -d "$1" ] || [ "$1" = "empty" ] || return 1
[ -d "$2" ] || return 1
mount | grep "$2" &>/dev/null && return 1
MNT="mount -t tmpfs"
[ -z "$3" ] || MNT="$MNT -o $3"
$MNT none "$2"
[ $? -gt 0 ] && return 1
if [ "$1" != "empty" ]; then
for D in $1/.* $1/*; do
[ "$(basename "$D")" == "." ] && continue
[ "$(basename "$D")" == ".." ] && continue
rsync -axq "$D" "$2" &>/dev/null
if [ $? -gt 0 ]; then
umount "$2"
return 1
fi
done
fi
return 0
}
function backup_rd() {
mount | grep "$1" &>/dev/null || return 0
if [ "$2" != "empty" ]; then
for D in $1/.* $1/*; do
[ "$(basename "$D")" == "." ] && continue
[ "$(basename "$D")" == ".." ] && continue
rsync -axq --delete "$D" "$2" &>/dev/null
if [ $? -gt 0 ]; then
tar -cf "/root/$(basename "$2")-failed.tar" "$1"
return 1
fi
done
fi
umount "$1" || return 1
return 0
}
# main logic
case $1 in
start)
stat_busy "Mounting ramdisks"
error=0
for M in ${DISKS[@]}; do
FROM="$(echo "$M" | cut -d ':' -f 1)"
TO="$(echo "$M" | cut -d ':' -f 2)"
OPTS="$(echo "$M" | cut -d ':' -f 3)"
activate_rd "$FROM" "$TO" "$OPTS" || error=1
done
if [ $error -eq 0 ]; then
add_daemon ramdisks
stat_done
else
stat_fail
exit 1
fi
;;
stop)
stat_busy "Saving ramdisks"
error=0
for M in ${DISKS[@]}; do
FROM="$(echo "$M" | cut -d ':' -f 2)"
TO="$(echo "$M" | cut -d ':' -f 1)"
backup_rd "$FROM" "$TO" || error=1
done
if [ $error -eq 0 ]; then
rm_daemon ramdisks
stat_done
else
stat_fail
echo -n "WARNING: failed to save ramdisk(s), tried to make "
echo "backup(s) under /root."
echo "Hit enter to proceed shutdown."
read DUMMY
exit 1
fi
;;
restart)
if ! ck_daemon ramdisks; then
"$0" stop && sleep 3
fi
"$0" start
;;
*)
echo "usage: $0 {start|stop|restart}"
;;
esac
exit 0
Mein Arch ramdisk-script hat ein weiteres Update erfahren, die Konfiguration ist nun mehr nach KISS und dot-Ordner werden korrekt behandelt.
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
| #!/bin/sh
#
# Manages outsourcing of specified directories into memory on bootup and
# takes care of synchronization/backup on system shutdown.
#
# Version 1.3, 2010-03-15, by Alexander Koch
#
# includes
. /etc/rc.conf
. /etc/rc.d/functions
# configuration (syntax is: [persist. storage]:[mountpoint]:[mount options])
DISKS=('/home/alex/.ramdisks/_mozilla:/home/alex/.mozilla:size=100M,uid=1000,gid=100' \
'empty:/home/alex/.adobe:size=10M,uid=1000,gid=100' \
'empty:/home/alex/.macromedia:size=10M,uid=1000,gid=100')
# helper functions
function activate_rd() {
[ -d "$1" ] || [ "$1" = "empty" ] || return 1
[ -d "$2" ] || return 1
mount | grep "$2" &>/dev/null && return 1
MNT="mount -t tmpfs"
[ -z "$3" ] || MNT="$MNT -o $3"
$MNT none "$2"
[ $? -gt 0 ] && return 1
if [ "$1" != "empty" ]; then
for D in $1/.* $1/*; do
[ "$(basename "$D")" == "." ] && continue
[ "$(basename "$D")" == ".." ] && continue
rsync -axq "$D" "$2" &>/dev/null
if [ $? -gt 0 ]; then
umount "$2"
return 1
fi
done
fi
return 0
}
function backup_rd() {
mount | grep "$1" &>/dev/null || return 0
if [ "$2" != "empty" ]; then
for D in $1/.* $1/*; do
[ "$(basename "$D")" == "." ] && continue
[ "$(basename "$D")" == ".." ] && continue
rsync -axq "$D" "$2" &>/dev/null
if [ $? -gt 0 ]; then
tar -cf "/root/$(basename "$2")-failed.tar" "$1"
return 1
fi
done
fi
umount "$1" || return 1
return 0
}
# main logic
case $1 in
start)
stat_busy "Mounting ramdisks"
error=0
for M in ${DISKS[@]}; do
FROM="$(echo "$M" | cut -d ':' -f 1)"
TO="$(echo "$M" | cut -d ':' -f 2)"
OPTS="$(echo "$M" | cut -d ':' -f 3)"
activate_rd "$FROM" "$TO" "$OPTS" || error=1
done
if [ $error -eq 0 ]; then
add_daemon ramdisks
stat_done
else
stat_fail
exit 1
fi
;;
stop)
stat_busy "Saving ramdisks"
error=0
for M in ${DISKS[@]}; do
FROM="$(echo "$M" | cut -d ':' -f 2)"
TO="$(echo "$M" | cut -d ':' -f 1)"
backup_rd "$FROM" "$TO" || error=1
done
if [ $error -eq 0 ]; then
rm_daemon ramdisks
stat_done
else
stat_fail
echo -n "WARNING: failed to save ramdisk(s), tried to make "
echo "backup(s) under /root."
echo "Hit enter to proceed shutdown."
read DUMMY
exit 1
fi
;;
restart)
if ! ck_daemon ramdisks; then
"$0" stop && sleep 3
fi
"$0" start
;;
*)
echo "usage: $0 {start|stop|restart}"
;;
esac
exit 0 |
Aus meiner Gentoo-Zeit habe ich oft etc-update vermisst, was sich um das Aktualisieren von Configs kümmert. Als Arch-Pendant hier mal mein Ansatz in Form eines Bash-Scripts. Es findet aktualisierende und verwaiste .pacnew, sowie überholte .pacsave und arbeitet sie interaktiv sequentiell ab.
#!/bin/sh
DIR="/etc"
if [ $(id -u) -gt 0 ]; then
sudo $0
exit $?
fi
function work()
{
ANS="z"
while echo "$ANS" | egrep -v '^[0-3]$' &>/dev/null; do
echo "$1:"
echo " [0] colordiff (old->new)"
echo " [1] upgrade (overwrite)"
echo " [2] keep (delete .pacnew)"
echo " [3] skip"
echo -n "choice: "
read ANS
done
case $ANS in
0)
colordiff "$1" "$2"
work "$1" "$2"
;;
1)
mv "$2" "$1" || exit 1
;;
2)
rm "$2" || exit 1
;;
3)
true
;;
*)
work "$1" "$2"
;;
esac
}
PACNEW="$(find $DIR -iname '*.pacnew' 2>/dev/null)"
PACSAV="$(find $DIR -iname '*.pacsave' 2>/dev/null)"
for FILE in $PACNEW; do
CONF="${FILE%.pacnew}"
if [ -e "$CONF" ]; then
work "$CONF" "$FILE"
else
echo -n "$FILE orphaned, delete? [Y/n] "
read ANS
if [ "$ANS" == "Y" -o "$ANS" == "y" -o "$ANS" == "" ]; then
rm "$FILE" || exit 1
fi
fi
done
for FILE in $PACSAV; do
CONF="${FILE%.pacsave}"
if [ -e "$CONF" ]; then
echo -n "$CONF obsolete ($(basename $CONF) present), delete? [Y/n] "
else
echo -n "$FILE remaining, delete? [Y/n] "
fi
read ANS
if [ "$ANS" == "Y" -o "$ANS" == "y" -o "$ANS" == "" ]; then
rm "$FILE" || exit 1
fi
done
exit 0
Wie immer der Hinweis: Benutztung auf eigene Gefahr!
Update: Ja, ich kenne yaourt und weiß um yaourt -C Bescheid *grml*, aber warum yaourt benutzen, wenn man auch ein Bashscript schreiben kann?
Wer über Nacht große Downloads auf der Xorg-losen Box laufen lassen will, braucht einen wget-tauglichen Link. Oft wird gerade dieser jedoch von der anbietenden Seite auf Biegen und Brechen zu verschleiern versucht. Es gibt zwar für jede Taktik auch eine geeignete Gegenmaßnahme (sonst würde der Download per Browser ja auch nicht funktionieren), wer sich aber das Suchen und Basteln sparen möchte und auch gern mal viele Links ohne großen Aufwand zusammenklicken will, kann folgende Methode nutzen:
Über das Firefox-Addon FlashGot lässt sich ein benutzerdefinierter Downloadmanager einrichten, an den FlashGot dann die URL und wahlweise diverse andere Informationen wie Header, etc. weiter gibt.
Als so ein Downloadmanager dient beispielsweise folgendes kleines Bash-script, welches alle ihm übergebenen Links eines bekannten 1-Click-Hosters (
) unter ~/links.txt ablegt:
#!/bin/sh
echo "$1" | sed -e 's/\/.*\.rapid/\/\/rapid/' >> ~/links.txt
exit 0
Konnte mich endlich aufraffen, einen schon lange vorhandenen Schönheitsfehler bei Verwendung von laptop-mode unter Arch zu beseitigen: die Dienste. Unter /etc/laptop-mode/batt-stop verlinkte Dienste werden von laptop-mode beim Wechsel auf Batterieversorgung beendet und beim Wechsel zurück auf Netzteil wieder gestartet – soweit so gut. Startet man die Kiste allerdings schon auf Batterie, werden die Dienste zuerst per init gestartet und dann direkt wieder gestoppt – unschön.
Folgender Hack (Zeile 11-17) für die rc.multi entfernt alle unter /etc/laptop-mode/batt-stop verlinkten Dienste aus $DAEMONS, sodass diese erst garnicht gestartet werden (natürlich nur bei Batteriebetrieb).
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
| #
# /etc/rc.multi
#
. /etc/rc.conf
. /etc/rc.d/functions
# Load sysctl variables if sysctl.conf is present
[ -r /etc/sysctl.conf ] && /sbin/sysctl -q -p &>/dev/null
# Check for battery state, filter DAEMONS
[ -r /proc/acpi/ac_adapter/ACAD/state ] && grep on-line /proc/acpi/ac_adapter/ACAD/state &>/dev/null
if [ $? -gt 0 ]; then
for n in $(seq 0 $((${#DAEMONS[@]} - 1))); do
[ -e /etc/laptop-mode/batt-stop/${DAEMONS[$n]} ] && unset DAEMONS[$n]
done
fi
# Start daemons
for daemon in "${DAEMONS[@]}"; do
if [ "$daemon" = "${daemon#!}" ]; then
if [ "$daemon" = "${daemon#@}" ]; then
start_daemon $daemon
else
start_daemon_bkgd ${daemon:1}
fi
fi
done
if [ -x /etc/rc.local ]; then
/etc/rc.local
fi
# vim: set ts=2 noet: |
Natürlich kann man sowas auch manuell immer wieder neu machen, aber bei vier aufeinanderfolgenden Installationen (allesamt auf Arch) ohne direkte Verbindung hat sich dann doch ein kleines (bash)Script angeboten.
Vielleicht kann es ja noch jemandem praktische Dienste leisten
BENUTZUNG AUF EIGENE GEFAHR!
#!/bin/sh
# check requirements
if [ -x /usr/sbin/iptables ]; then
echo "iptables binary not found."
exit 1
fi
# clear chains
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT
iptables -F
iptables -X
# create new chains and link them
iptables -N open # services will be opened here
iptables -N interfaces # completely open interfaces here
iptables -A INPUT -j open
iptables -A INPUT -j interfaces
# deny forwarding
iptables -P FORWARD DROP
# allow all outgoing traffic
iptables -P OUTPUT ACCEPT
# allow all traffic on loopback
iptables -A interfaces -i lo -j ACCEPT
# allow related connections (-> stateful)
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
# allowed services
iptables -A INPUT -p icmp -j ACCEPT # ping
iptables -A open -p tcp --dport 22 -j ACCEPT # ssh
# deny all other incoming traffic
iptables -A INPUT -p tcp -j REJECT --reject-with tcp-reset # imitate default linux behaviour
iptables -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable # "
iptables -P INPUT DROP
# protection against common attacks
iptables -A INPUT -p tcp ! --syn -m state --state NEW -j DROP # SYN for new packets
iptables -A INPUT -f -j DROP # fragmentation check
iptables -A INPUT -p tcp --tcp-flags ALL ALL -j DROP # XMAS-packets
iptables -A INPUT -p tcp --tcp-flags ALL NONE -j DROP # null packets
iptables -I INPUT -p icmp --icmp-type redirect -j DROP # ICMP type match blocking
iptables -I INPUT -p icmp --icmp-type router-advertisement -j DROP # "
iptables -I INPUT -p icmp --icmp-type router-solicitation -j DROP # "
iptables -I INPUT -p icmp --icmp-type address-mask-request -j DROP # "
iptables -I INPUT -p icmp --icmp-type address-mask-reply -j DROP # "
echo "net.ipv4.conf.all.rp_filter = 1" >> /etc/sysctl.conf # enable source address verification
echo "net.ipv4.tcp_timestamps = 0" >> /etc/sysctl.conf # nmap uptime detection
echo "net.ipv4.conf.all.accept_source_route=0" >> /etc/sysctl.conf # we are not a router
echo "net.ipv4.icmp_echo_ignore_broadcasts=1" >> /etc/sysctl.conf # "
echo "net.ipv4.icmp_ignore_bogus_error_messages=1" >> /etc/sysctl.conf # "
# disable ip forwarding
if [ -e /etc/conf.d/iptables ]; then
cat /etc/conf.d/iptables | egrep -v '^IPTABLES_FORWARD' > /tmp/iptables.conf
echo "IPTABLES_FORWARD=0" >> /tmp/iptables.conf
cat /tmp/iptables.conf > /etc/conf.d/iptables
rm /tmp/iptables.conf
fi
# and finally save our work
/etc/rc.d/iptables save
(zum Ausklappen Pfeil benutzen)
Das Script erstellt ein Basis-Regelwerk und lässt nur Ping (ICMP) und SSH (auf allen interfaces) eingehend zu. Alle anderen eingehenden Verbindungen werden geblockt; ausgehende Verbindungen vollständig erlaubt. Desweiteren implementiert es Schutzmaßnahmen gegen die üblichsten Attacken.