UQMI - как извлечь разом все SMS
uqmi --list-messages -d /dev/cdc-wdm0 -s / | jq '.[]' | while read ID; do ( uqmi --get-message $ID -d /dev/cdc-wdm0 -s 2>/dev/null | jq --arg ID $ID '.+{"id":$ID}'); done | jq --slurp . -c
Просто так блог.
uqmi --list-messages -d /dev/cdc-wdm0 -s / | jq '.[]' | while read ID; do ( uqmi --get-message $ID -d /dev/cdc-wdm0 -s 2>/dev/null | jq --arg ID $ID '.+{"id":$ID}'); done | jq --slurp . -c
Или как скрестить ежа (маршрутизацию на основании адресов) и ужа (встроенный механизм политик интернет-подключений).
Достаточно очевидным решением представляется подсесть на существующий механизм (работающий за счет xmarks/connmarks), помечая нужным нам соединения так, чтоб их уже встроенный механизм маршрутизации отправлял в нужную сторону с учетом приоритетов, балансировки и прочих сетевых кунштюков.
Для определения адреса в нужный ipset будем использовать AdGuard Home.
Конфигурация будет простым шелл-скриптом с набором переменных, который будем в нужном месте включать в рабочие скрипты.
Правила будут иметь вид:
назначение источник протокол порты имя_политики
Если перед каким-то ключом стоит "!" - значит, в итоговых правилах будет отрицание этого условия ("все, кроме Х"). Значение ключа "-" означает, что по этому ключу в правиле выбор осуществляться не будет ("все"). Порядок применения - в порядке перечисления в конфигурации, сработает последнее примененное правило.
# cat /opt/etc/config/pbr
BASE_URL="http://192.168.1.100/config/" # здесь у нас хранилище конфигураций
FILTER_DIR="/tmp/filter.lists/"
TIMEOUT=4200
DST_IPSETS="vpn1 vpn1.list
vpn2 vpn2.list
vpn vpn.list
isp isp.list
tor tor.list"
DST_FIXED_IPSETS="blocked"
SRC_MACSETS="trusted trusted.list
devices devices.list"
RULES="vpn trusted tcp 21,22,25,80,81,443,587,993,995,5222,5269 ANY_VPN
vpn1 trusted tcp 21,22,25,80,81,443,587,993,995,5222,5269 VPN1
vpn1 devices tcp 80,443 VPN1
vpn2 trusted tcp 21,22,25,80,81,443,587,993,995,5222,5269 VPN2
vpn2 !trusted tcp 80,443 VPN2
blocked trusted - - ANY_VPN
blocked devices tcp 80,443 ANY_VPN
tor trusted - - TOR
tor devices tcp 80,443 TOR
isp - - - ISP"
Скрипт для создания ipsets и файла настроек для AdGuard:
# cat /opt/etc/init.d/S84ipset
#!/bin/sh
. /opt/etc/config/pbr
get_dst_set() {
SET_N=$1
LIST_N=$2
curl $BASE_URL/$LIST_N 2>/dev/null | grep . | grep -v '^#' | cut -f 1 | sort | uniq > $FILTER_DIR/${LIST_N}.new
if ! diff -q $FILTER_DIR/${LIST_N}.new $FILTER_DIR/$LIST_N; then
cp $FILTER_DIR/${LIST_N}.new $FILTER_DIR/$LIST_N
cat $FILTER_DIR/${LIST_N} | while read DOMAIN; do
echo "$DOMAIN/$SET_N,${SET_N}6"
done > $FILTER_DIR/${SET_N}.ipset
fi
rm $FILTER_DIR/${LIST_N}.new
}
get_src_set() {
SET_N=$1
LIST_N=$2
curl $BASE_URL/$LIST_N 2>/dev/null | grep . | grep -v '^#' | cut -f 1 | sort | uniq > $FILTER_DIR/${SET_N}.mac
}
fill_src_ipsets() {
curl http://127.0.0.1:79/rci/show/ip/neighbour 2>/dev/null | jq -c -r '.[]' | while read NEIGHBOUR; do
MAC_ADDR=$(echo $NEIGHBOUR | jq '.mac' | tr -d '"')
echo "$SRC_MACSETS" | while read SET_NAME FILE_NAME; do
if grep -q $MAC_ADDR $FILTER_DIR/${SET_NAME}.mac; then
FAMILY=$(echo $NEIGHBOUR | jq -c '."address-family"' | tr -d '"')
if [ "$FAMILY" == "ipv6" ]; then
ADDR_LIST=$(echo $NEIGHBOUR | jq -c '.addresses.address')
echo $ADDR_LIST | jq -c -r '.[]' | jq -c '.address' |tr -d '"' | while read ADDRESS; do
ipset -q add ${SET_NAME}6 $ADDRESS
done
else
ADDRESS=$(echo $NEIGHBOUR | jq -c '.address' | tr -d '"')
ipset -q add $SET_NAME $ADDRESS
fi
fi
done
done
}
fill_ipset_files() {
mkdir -p $FILTER_DIR
touch $FILTER_DIR/adguard.ipsets
echo "$DST_IPSETS" | while read SET_NAME FILE_NAME; do
get_dst_set $SET_NAME $FILE_NAME
done
cat $FILTER_DIR/*.ipset > $FILTER_DIR/adguard.ipsets
echo "$SRC_MACSETS" | while read SET_NAME FILE_NAME; do
get_src_set $SET_NAME $FILE_NAME
done
fill_src_ipsets
}
start() {
echo "$DST_IPSETS" | while read SET_NAME FILE_NAME; do
ipset -q create $SET_NAME hash:net timeout $TIMEOUT
ipset -q create ${SET_NAME}6 hash:net timeout $TIMEOUT family ipv6
done
echo "$DST_FIXED_IPSETS" | while read SET_NAME; do
ipset -q create $SET_NAME hash:net timeout 0
ipset -q create ${SET_NAME}6 hash:net timeout 0 family ipv6
done
echo "$SRC_MACSETS" | while read SET_NAME FILE_NAME; do
ipset -q create $SET_NAME hash:ip timeout 0
ipset -q create ${SET_NAME}6 hash:ip timeout 0 family ipv6
done
fill_ipset_files
}
reload() {
fill_ipset_files
/opt/etc/init.d/S99adguardhome restart
}
case "$1" in
start)
start
;;
restart)
start
;;
reload)
reload
;;
esac
Не забываем в конфигурации AdGuard сослаться на ipset-file: /tmp/filter.lists/adguard.ipsets
Хук для обработки сообщений о появлении нового устройства в сети, проверки его принадлежности к одному из наборов mac-адресов и добавления адреса в ipset.
# cat /opt/etc/ndm/neighbour.d/macset
#!/bin/sh
. /opt/etc/config/pbr
MAC=$(curl http://127.0.0.1:79/rci/show/ip/neighbour 2>/dev/null | jq --arg num "$id" '.[$num].mac' | tr -d '"')
echo "${SRC_MACSETS}" | while read SET_NAME FILE_NAME; do
if grep -q $MAC $FILTER_DIR/${SET_NAME}.mac; then
ADDR=$(curl http://127.0.0.1:79/rci/show/ip/neighbour 2>/dev/null | jq -c --arg num "$id" '.[$num]')
FAMILY=$(echo $ADDR | jq -c '."address-family"' | tr -d '"')
if [ "$FAMILY" == "ipv6" ]; then
ADDR_LIST=$(echo $ADDR | jq -c '.addresses.address')
echo $ADDR_LIST | jq -c -r '.[]' | jq -c '.address' |tr -d '"' | while read ADDRESS; do
if [ "$ACTION" == "del" ]; then
ipset -q del ${SET_NAME}6 $ADDRESS
else
ipset -q add ${SET_NAME}6 $ADDRESS
fi
done
fi
if [ "$FAMILY" == "ipv4" ]; then
ADDRESS=$(echo $ADDR | jq -c '.address' | tr -d '"')
if [ "$ACTION" == "del" ]; then
ipset -q del $SET_NAME $ADDRESS
else
ipset -q add $SET_NAME $ADDRESS
fi
fi
fi
done
exit 0
Ну и главный хук - для подвешивания меток на соединения.
# cat /opt/etc/ndm/netfilter.d/050-pbr.sh
#!/bin/sh
[ "$table" != "mangle" ] && exit;
[ ! -z "$(ipset --quiet list vpn)" ] || exit 0
. /opt/etc/config/pbr
# HACK!!!!
insmod /lib/modules/4.9-ndm-5/xt_multiport.ko
check_bang() {
VAR=$1
PREFIX1=$2
PREFIX2=$3
POSTFIX=$4
SETPOSTFIX=$5
if [ "$VAR" != "-" ]; then
if [ "${VAR:0:1}" != "!" ]; then
echo $PREFIX1 $PREFIX2 $VAR$SETPOSTFIX $POSTFIX
else
echo $PREFIX1 ! $PREFIX2 ${VAR:1}$SETPOSTFIX $POSTFIX
fi
else
echo ""
fi
}
process_rule() {
DSTSET=$1
SRCSET=$2
PROTO=$3
PORTS=$4
POLICY=$5
CONNMARK=$(curl http://127.0.0.1:79/rci/show/ip/policy 2>/dev/null | jq '.[] | select( .description == "'$POLICY'") | .mark' | tr -d '"')
RULE=""
if [ "$type" != "ip6tables" ]; then
DSTSET=$(check_bang $DSTSET "-m set" "--match-set" "dst" "")
SRCSET=$(check_bang $SRCSET "-m set" "--match-set" "src" "")
else
DSTSET=$(check_bang $DSTSET "-m set" "--match-set" "dst" "6")
SRCSET=$(check_bang $SRCSET "-m set" "--match-set" "src" "6")
fi
PROTO=$(check_bang $PROTO "" "-p" "" "")
PORTS=$(check_bang $PORTS "-m multiport" "--dports" "" "")
if [ "$type" != "ip6tables" ]; then
iptables -w -t mangle -A PBRP -m conntrack --ctstate NEW $PROTO $PORTS $DSTSET $SRCSET -j CONNMARK --set-mark 0x$CONNMARK
iptables -w -t mangle -A PBRO -m conntrack --ctstate NEW $PROTO $PORTS $DSTSET -j CONNMARK --set-mark 0x$CONNMARK
else
ip6tables -w -t mangle -A PBRP -m conntrack --ctstate NEW $PROTO $PORTS $DSTSET $SRCSET -j CONNMARK --set-mark 0x$CONNMARK
ip6tables -w -t mangle -A PBRO -m conntrack --ctstate NEW $PROTO $PORTS $DSTSET -j CONNMARK --set-mark 0x$CONNMARK
fi
}
process_rules() {
if [ "$type" != "ip6tables" ]; then
iptables -w -t mangle -N PBRP 2>/dev/null
iptables -w -t mangle -N PBRO 2>/dev/null
iptables -w -t mangle -F PBRP
iptables -w -t mangle -F PBRO
echo "$RULES" | while read -r RULE; do
process_rule $RULE
done
iptables -w -t mangle -A PBRP -j CONNMARK --restore-mark
iptables -w -t mangle -A PBRO -j CONNMARK --restore-mark
iptables -w -t mangle -A PBRP -j RETURN
iptables -w -t mangle -A PBRO -j RETURN
iptables -w -t mangle -D PREROUTING -j PBRP 2>/dev/null
iptables -w -t mangle -A PREROUTING -j PBRP
iptables -w -t mangle -D OUTPUT -j PBRO 2>/dev/null
iptables -w -t mangle -A OUTPUT -j PBRO
else
ip6tables -w -t mangle -N PBRP 2>/dev/null
ip6tables -w -t mangle -N PBRO 2>/dev/null
ip6tables -w -t mangle -F PBRP
ip6tables -w -t mangle -F PBRO
echo "$RULES" | while read -r RULE; do
process_rule $RULE
done
ip6tables -w -t mangle -A PBRP -j CONNMARK --restore-mark
ip6tables -w -t mangle -A PBRO -j CONNMARK --restore-mark
ip6tables -w -t mangle -A PBRP -j RETURN
ip6tables -w -t mangle -A PBRO -j RETURN
ip6tables -w -t mangle -D PREROUTING -j PBRP 2>/dev/null
ip6tables -w -t mangle -A PREROUTING -j PBRP
ip6tables -w -t mangle -D OUTPUT -j PBRO 2>/dev/null
ip6tables -w -t mangle -A OUTPUT -j PBRO
fi
}
process_rules
exit 0
SERVER_MAC="b4:2e:99:ce:7f:44"
mac_to_ipv6 () {
mac=$1
prefix=$2
IFS=':'; set $prefix; unset IFS
prefix=$1:$2:$3:$4
IFS=':'; set $mac; unset IFS
ipv6="$prefix:$(printf %02x $((0x$1 ^ 2)))$2:${3}ff:fe$4:$5$6"
ipv6="${ipv6//::::/::}"
ipv6="${ipv6//:::/::}"
echo $ipv6
}
local_v6=$(mac_to_ipv6 $SERVER_MAC fe80)
Это будет локальный адрес на интерфейсе, если нужен глобальный - вместо fe80 нужен префикс подсети.
С префиксами ситуация так и не изменилась - адрес и префикс, выдаваемые пользователю, меняются в случайный момент, так что рецепт с одновременным туннелем со стабильным адресом для соединений входящих остается актуальным, за некоторыми незначительными дополнениями.
Роутинг в момент смены состояния интерфейса, с автоматическим прописыванием маршрута для подсети. Отрабатывается ситуация, когда туннелей больше одного (для резервирования - работать они могут и одновременно, но вот если они не стоят приоритетным интерфейсом, маршруты и префикс Кинетик анонсировать в локальную сеть не будет, нужно это из какого-то другого места делать, или с другого хоста, или запускать еще один экземпляр radvd из EntWare).
/opt/etc/ndm/ifstatechanged.d/ipv6:
#!/bin/sh
if [[ "$id" == "TunnelSixInFour"* ]]; then
SUBNET=$(ndmc -c "show ipv6 prefixes" | awk '
/prefix:/ {prefix=$2}
/interface:/ {iface=$2}
prefix && iface {print iface ">" prefix; prefix=""; iface=""}
' | grep "^$id" | cut -d '>' -f 2)
echo SUBNET=$SUBNET
ADDR=$(ndmc -c show interface $id | awk '
/address:/ {addr=$2}
/proto:/ {proto=$2}
proto=="STATIC" {print addr; exit}
'
)
echo ADDR=$ADDR
TABLE=20"${id: -1}"
echo TABLE=$TABLE
if [ "$change" == "connected" ] && [ "$connected" == "yes" ]; then
echo Setting ipv6 routes for $id
/opt/sbin/ip -6 route del default dev $system_name table $TABLE 2>/dev/null
/opt/sbin/ip -6 route add default dev $system_name table $TABLE
/opt/sbin/ip -6 rule del from $SUBNET table $TABLE 2>/dev/null
/opt/sbin/ip -6 rule add from $SUBNET table $TABLE
fi
if [ "$change" == "link" ] && [ "$connected" == "no" ]; then
echo Cleaning ipv6 routes for $id
/opt/sbin/ip -6 route del default dev $system_name table $TABLE 2>/dev/null
/opt/sbin/ip -6 rule del from $SUBNET table $TABLE 2>/dev/null
fi
fi
exit 0
Однострочник для отлова установленных вручную пакетов в OpenWRT:
BT=$(opkg status busybox | grep Installed-Time | cut -d ' ' -f 2); opkg list-installed | cut -d ' ' -f 1 | while read PKG; do ( opkg status $PKG | grep -q "Installed-Time: $BT" || ( opkg status $PKG | grep -q "Status: install user installed" && echo $PKG ) ) ; done
1) Смотрим время пакета busybox, все, поставленное вместе с системой будет иметь то же время установки.
2) Смотрим список установленных пакетов.
3) Для каждого пакета проверяем время установки и статус, если статус "установлено пользователем" и время отличается от базового времени системы - значит, ставилось руками.
Имеется роутер Keenetic на свежей прошивке (4.0), имеется на нем (наконец-то) нативный IPv6 от Ростелекома, но с хаотически меняющимся при каждом соединении адресом/сетью, и имеется тоннель от HE со стабильным адресом.
Хочется выход через РТ, но сервер с адресом на HE.
Плюс по умолчанию еще весь IPv6 извне зарезан к чертовой матери, и штатных средств отключить это в интерфейсе и в CLI нет как класса.
Ну что ж, зря что ли Entware ставили? Чтоб выдернуть настройки - воспользуемся командой ndmc, вывод там не самый удобный, многострочный, но awk нам поможет.
Разрешаем трафик извне на сервер.
/opt/etc/ndm/netfilter.d/ipv6:
#!/opt/bin/sh
SERVER=100
SUBNET=$(ndmc -c "show ipv6 prefixes" | awk '
/prefix:/ {prefix=$2}
/interface:/ {iface=$2}
prefix && iface {print iface ">" prefix; prefix=""; iface=""}
' | grep TunnelSixInFour0 | cut -d '>' -f 2)
PREFIX=$(echo $SUBNET | cut -d '/' -f 1)
/opt/sbin/ip6tables -D FORWARD -d $PREFIX$SERVER -j ACCEPT 2>/dev/null
/opt/sbin/ip6tables -I FORWARD -d $PREFIX$SERVER -j ACCEPT
Настраиваем маршрутизацию приходящего из HE-подсети в соответствующий интерфейс.
/opt/etc/ndm/wan.d/ipv6:
#!/opt/bin/sh
SERVER=100
SUBNET=$(ndmc -c "show ipv6 prefixes" | awk '
/prefix:/ {prefix=$2}
/interface:/ {iface=$2}
prefix && iface {print iface ">" prefix; prefix=""; iface=""}
' | grep TunnelSixInFour0 | cut -d '>' -f 2)
PREFIX=$(echo $SUBNET | cut -d '/' -f 1)
ADDR=$(ndmc -c show interface TunnelSixInFour0 | awk '
/address:/ {addr=$2}
/proto:/ {proto=$2}
proto=="STATIC" {print addr; exit}
'
)
GATE=$(echo $ADDR | rev | cut -d ":" -f 2- | rev):1
/opt/sbin/ip6tables -D FORWARD -d $PREFIX$SERVER -j ACCEPT 2>/dev/null
/opt/sbin/ip6tables -I FORWARD -d $PREFIX$SERVER -j ACCEPT
/opt/sbin/ip -6 route del $ADDR/126 dev tun6in4_0 2>/dev/null
/opt/sbin/ip -6 route del default via $GATE dev tun6in4_0 table 200 2>/dev/null
/opt/sbin/ip -6 route add $ADDR/126 dev tun6in4_0
/opt/sbin/ip -6 route add default via $GATE dev tun6in4_0 table 200
/opt/sbin/ip -6 rule del from $SUBNET table 200 2>/dev/null
/opt/sbin/ip -6 rule add from $SUBNET table 200
Простая, с необходимым, но достаточным базовым набором функций, прошивка для интернет-часов на ESP8266 с светодиодными панелями на MAX7219.
Поддерживает:
Лицензия - WTFPL, делайте с кодом что хотите, зарабатывать на этом я не собираюсь все равно.
https://git.rvb.name/esp-clock.git https://github.com/rvbglas/esp_clock
Универсальный вариант, работающий и с gdm, и с lightdm - запускаем отдельный скрипт, который сам найдет, какая виртуальная консоль активна, кто в ней сидит, и какие параметры вызова необходимы. Причем запускаем только тогда, когда будет обращение на порт. В норме - задраенный отовсюду, кроме локального адреса, соединение поверх ssh.
Вспомогательный скрипт, который будет отключать локальную консоль при подключении извне и включать ее обратно после отсоединения:
/usr/local/bin/switch_console
#!/bin/sh
case $1 in
1|on)
desired=1
;;
0|off)
desired=0
;;
*)
echo "USAGE: $0 0|1|on|off"
exit 1
;;
esac
export DISPLAY=:0
export XAUTHORITY=/var/run/lightdm/root/:0
keyboards=`xinput | grep -v "XTEST" | grep "slave keyboard" | sed -re 's/^.*\sid=([0-9]+)\s.*$/\1/'`
mouses=`xinput | grep -v "XTEST" | grep "slave pointer" | sed -re 's/^.*\sid=([0-9]+)\s.*$/\1/'`
monitors=`xrandr | grep " connected" | sed -re 's/^(.+) connected.*$/\1/'`
for device in $mouses
do
xinput --set-prop $device "Device Enabled" $desired
done
for device in $keyboards
do
xinput --set-prop $device "Device Enabled" $desired
done
for device in $monitors
do
xrandr --output $device --brightness $desired
done
Юнит-файлы для запуска скрипта при обращении к порту:
/etc/systemd/system/xvnc.socket
[Unit]
Description=XVNC Server
[Socket]
ListenStream=127.0.0.1:5900
Accept=yes
[Install]
WantedBy=sockets.target
/etc/systemd/system/xvnc@.service
[Unit]
Description=XVNC Per-Connection Daemon
[Service]
ExecStart=/usr/local/bin/startx11vnc
ExecStartPost=/usr/local/bin/switch_console 0
StandardInput=socket
StandardError=syslog
И основной скрипт:
/usr/local/bin/startx11vnc
#!/bin/sh
pidtree() {
echo -n $1 " "
for _child in $(ps -o pid --no-headers --ppid $1); do
echo -n $_child `pidtree $_child` " "
done
}
CONSOLE=`fgconsole`
for SESSION in `loginctl list-sessions | awk '$4 ~ /seat/ {$1=$1; print $1;}'`
do
SESSCON=`loginctl show-session $SESSION | grep VTNr= | cut -d "=" -f 2`
STATE=`loginctl show-session $SESSION | grep State= | cut -d "=" -f 2`
if [ "$CONSOLE" -eq "$SESSCON" ] && [ "$STATE" = "active" ]; then
break
fi
done
PS=`loginctl show-session $SESSION | grep Leader= | cut -d "=" -f 2`
AUTH=""
for SPS in `pidtree $PS | sort | uniq`
do
AUTH=`strings /proc/$SPS/environ | grep XAUTHORITY= | cut -d "=" -f 2`
DISPLAY=`strings /proc/$SPS/environ | grep DISPLAY= | cut -d "=" -f 2`
if [ "$AUTH" != "" ]; then
break
fi
done
/usr/bin/x11vnc -inetd -xkb -skip_keycodes 187,188 -display $DISPLAY -auth $AUTH -noxrecord -noxfixes -noxdamage -unixpw -o /var/log/x11vnc.log -enc none
sleep 2
for i in `loginctl list-sessions | awk '$4 ~ /seat/ { print $1; }'`; do loginctl lock-session $i; done
/usr/local/bin/switch_console 1
Разрешаем выполнение скрипта и запуск процесса.
$ sudo chmod a+x /usr/local/bin/startx11vnc
$ sudo chmod a+x /usr/local/bin/switch_console
$ sudo systemctl daemon-reload
$ sudo systemctl enable xvnc.socket
$ sudo systemctl start xvnc.socket
Вариант с IMPOSM3.
Сначала грузим файлы в кеш, для каждого вызывая:
imposm import -mapping $mapping -read $filename -cachedir $cache -appendcache
При этом в режиме -appendcache данные там копятся.
После того как все файлы залили - переливаем их в БД:
imposm import -mapping $mapping -connection $connstr -cachedir $cache -write
И весь кеш улетает внутрь PGSQL/PostGIS.
Работа а-ля винда с RDP: подключились со стороны - локальная консоль блокируется, по выходу - сессия заблокирована паролем.
Скрипт для блокировки-разблокировки устройств ввода и отключения-включения экрана (через настройки системной яркости), потянут с Хабра, чуть допилен напильником, чтобы корректно работал от демона, а не только из терминальной сессии пользователя:
/usr/local/bin/switch_console:
#!/bin/sh
case $1 in
1|on)
desired=1
;;
0|off)
desired=0
;;
*)
echo "USAGE: $0 0|1|on|off"
exit 1
;;
esac
export DISPLAY=:0
export XAUTHORITY=/var/run/lightdm/root/:0
keyboards=$(xinput | grep -v "XTEST" | grep "slave keyboard" | sed -re 's/^.*\sid=([0-9]+)\s.*$/\1/')
mouses=$(xinput | grep -v "XTEST" | grep "slave pointer" | sed -re 's/^.*\sid=([0-9]+)\s.*$/\1/')
monitors=$(xrandr | grep " connected" | sed -re 's/^(.+) connected.*$/\1/')
for device in $mouses
do
xinput --set-prop $device "Device Enabled" $desired
done
for device in $keyboards
do
xinput --set-prop $device "Device Enabled" $desired
done
for device in $monitors
do
xrandr --output $device --brightness $desired
done
На случай подключения новых устройств в процессе работы - сажаем этот скрипт в цикле:
/usr/local/bin/disable_console:
#!/bin/sh
while [ $(pgrep x11vnc | wc -l) -ne "0" ]
do
/usr/local/bin/switch_console 0
sleep 1
done
x11vnc будем запускать через сокет systemd:
/etc/systemd/system/xvnc.socket:
[Unit]
Description=XVNC Server
[Socket]
ListenStream=5900
Accept=yes
[Install]
WantedBy=sockets.target
/etc/systemd/system/xvnc@.service:
[Unit]
Description=XVNC Per-Connection Daemon
[Service]
ExecStart=/usr/local/bin/startx11vnc
ExecStartPost=/sbin/start-stop-daemon --start -b --exec /usr/local/bin/disable_console
StandardInput=socket
StandardError=syslog
Собственно скрипт для запуска x11vnc и разблокировки локальной консоли по завершении работы:
/usr/local/bin/startx11vnc:
#!/bin/sh
/usr/bin/x11vnc -inetd -xkb -skip_keycodes 187,188 -auth /var/run/lightdm/root/:0 -noxrecord -noxfixes -noxdamage -unixpw -o /var/log/x11vnc.log -enc none
sleep 4
for i in $(loginctl list-sessions | grep seat | awk '{ print $1; }'); do loginctl lock-session $i; done
/usr/local/bin/switch_console 1
logger -t startx11vnc local console enabled
Скриптам разрешаем выполнение (chmod a+x), конфигурацию systemd перечитываем (systemctl daemon-reload; systemctl enable xvnc.socket; systemctl start xvnc.socket), подключаемся, наслаждаемся.