В повседневной работе я пользуюсь десятками включённых VPN клиентов. Эти клиенты соединяются с разными серверами, а серверы имеют разные настройки. Так например у меня возникала ситуация когда нужный мне роут пробрасывался через TUN интерфейс который PUSH-ился с сервера. Если бы сервер использовал только я стоило бы перенастроить только сервер чтобы это исправить. Однако сервером пользуются и другие люди и там этот PUSH необходим. Сначала я руками переписывал роут и забывал до следующего переподключения. Но последнее время часто приходилось переподключаться и вечное переписывание роута стало раздражать. В документации к OpenVPN написано что в настройках с недавнего времени появился ключ который поможет клиенту отвергнуть то что ему предлагает сервер.
Continue reading OpenVPN как не принять предложение сервера о настройке интерфейсов
Category: Scripts
Почему копипастить команды с web сразу в терминал это глупость?
Потому что bash/sh терминал выполнит команду если в ней будет перевод строки.
Во-первых когда команда набирается руками происходит запоминание, сначала вы внимательно читаете команду, затем вводите ту часть которую запомнили, затем дальше читаете и снова вводите. Работают глаза, голова и руки. Запоминается эффективнее.
Во-вторых вместе с командой можно скопипастить чужой зловредный код. Не верите?
Выделите код который приведён ниже скопируйте и затем вставьте в тектовый редактор. После этого вы всегда будете копипастить код через редактор, а короткие команды будете набирать руками.
Continue reading Почему копипастить команды с web сразу в терминал это глупость?
Однострочный скрипт вывода smart информации по нескольким дискам в виде таблицы
Буквы дисков нужно задать в операторе for in a b (ниже будет скрипт который сам выберет все диски)
# for idx in a b ; do smartctl -A /dev/sd$idx | sed -n '/^ID#/,/^$/p' | sed -e '/^ID#/d;s/^./'"$idx "'&/g'; done | sed -e '/^[ \t]*$/d' | awk '{disks[$1]=$1;keys[$3]=$2$3;valuelen=length($11);keylen=length($3);if(valuelen>maxvaluelen){maxvaluelen=valuelen}if(keylen>maxkeylen){maxkeylen=keylen};VALUES[$1,$3]=$11}END{printf("\n%-"maxkeylen"s","NAME");for(disk in disks){printf(" %"maxvaluelen"s",toupper("SD"disk))};for(key in keys){printf("\n%-"maxkeylen"s",key); for(disk in disks){printf(" %"maxvaluelen"s", VALUES[disk,key])}};printf("\n")}' NAME SDA SDB Spin_Retry_Count 0 0 Seek_Error_Rate 0 0 Start_Stop_Count 101 21 Multi_Zone_Error_Rate 0 0 Offline_Uncorrectable 0 0 Spin_Up_Time 9216 10183 Power_Cycle_Count 95 12 Calibration_Retry_Count 0 0 Load_Cycle_Count 199966 111455 Reallocated_Sector_Ct 0 0 Raw_Read_Error_Rate 3 0 Current_Pending_Sector 0 0 Reallocated_Event_Count 0 0 Power_On_Hours 9259 11992 Temperature_Celsius 27 23 UDMA_CRC_Error_Count 0 0 Power-Off_Retract_Count 33 7
Одним движением руки этот скрипт преобразуется в вывод информации, например по 8-ми дискам в RAID контроллере 3ware.
for idx in `seq 0 7` ; do smartctl -A /dev/twa0 -d 3ware,$idx | sed -n '/^ID#/,/^$/p' | sed -e '/^ID#/d;s/^./'"$idx "'&/g'; done | sed -e '/^[ \t]*$/d' | awk '{disks[$1]=$1;keys[$3]=$2$3;valuelen=length($11);keylen=length($3);if(valuelen>maxvaluelen){maxvaluelen=valuelen}if(keylen>maxkeylen){maxkeylen=keylen};VALUES[$1,$3]=$11}END{printf("\n%-"maxkeylen"s","NAME");for(disk in disks){printf(" %"maxvaluelen"s",toupper("p:"disk))};for(key in keys){printf("\n%-"maxkeylen"s",key); for(disk in disks){printf(" %"maxvaluelen"s", VALUES[disk,key])}};printf("\n")}'
А такой скрипт сам выберет все диски с помощью lsblk и выведет состояние smart
while read NAME ; do smartctl -A "${NAME}" | sed -n '/^ID#/,/^$/p' | sed -e '/^ID#/d' -e 's|^.|'"${NAME} "'&|g'; done < <(lsblk -d --noheadings --output name,type | awk '$2=="disk"{print "/dev/"$1}' | sort) | sed -e '/^[ \t]*$/d' | awk '{disks[$1]=$1;keys[$3]=$2$3;valuelen=length($11);keylen=length($3);if(valuelen>maxvaluelen){maxvaluelen=valuelen};if(keylen>maxkeylen){maxkeylen=keylen};VALUES[$1,$3]=$11}END{printf("\n%-"maxkeylen"s","NAME");for(disk in disks){valuelen=length(disk);if(valuelen>maxvaluelen){maxvaluelen=valuelen}};for(disk in disks){printf(" %"maxvaluelen"s",disk)};for(key in keys){printf("\n%-"maxkeylen"s",key); for(disk in disks){printf(" %"maxvaluelen"s", VALUES[disk,key])}};printf("\n")}'
Обновление базы дисков smartctl на CentOS 6.7
Чтобы обновить базу дисков smartctl на CentOS release 6.7 (Final) нужно использовать новый скрипт, так как старый, который идёт в дистрибутиве не работает.
update-smart-drivedb -v ./aa.txt Download from branches/RELEASE_5_43_DRIVEDB % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 109 329 109 329 0 0 1108 0 --:--:-- --:--:-- --:--:-- 2611 ./aa.txt.error: rejected by /usr/sbin/smartctl, probably no longer compatible
С момента моего предыдущего обновления снова изменилась структура smartmontools линков для получения свежей базы. Поэтому я написал скрипт который загружает скрипт обновления и настраивает его так чтобы он стянул свежую базу дисков.
Continue reading Обновление базы дисков smartctl на CentOS 6.7
Мониториг почтовой очереди
Скрипт получает состояние почтовой очереди и подсчитывает количество заданий их общий размер и выводил даты самого молодого и старого задания в очереди.
mailq | sed -e 's/[\t]\+/ /g' | sed -e '/^ \+/d;/^ *$/d' | awk '{if(NR==1){qtimestr=gensub(/^.+ (-+Q-Time-+) .+$/,"\\1","g",$0);start=index($0,qtimestr);len=length(qtimestr);}else{printf("%d;%"len"s\n", $2, substr($0,start,len));}}' | while IFS=';' read size date ; do echo -e "`date -d\"${date}\" '+%F %T'`;${size}"; done | sort | awk -F';' '{count++;size=size+$2;if(NR==1){printf("oldest:%s\n", $1)}}END{if(count>0){printf("youngest:%s\ncount:%d\nsize:%dMB\n", $1, count, size/1024/1024)}}' oldest:2015-10-31 04:21:00 youngest:2015-11-04 11:25:00 count:10 size:25MB
Теперь немного доработав скрипт можно его использовать в системах мониторинга, чтобы оповестить администратора о неадекватном росте количества заданий в очереди. Например, если через взломанный эккаунт сервер используется для рассылки спама.
Значительно более быстро контролировать количество заданий в очереди можно контролировать если очередь заданий разместить на отдельной файловой системе.
df -iP /var/spool/mqueue Filesystem Inodes IUsed IFree IUse% Mounted on /dev/mapper/VG_MAIN-MQUEUE 10485760 120 10485640 1% /var/spool/mqueue В данном случае интересует количество использованных inodes.
df -iP /var/spool/mqueue | awk '{if($3 ~ /^[0-9]+$/){print $2, $3, $4}}' 10485760 120 10485640
Здесь нужно мониторить второе поле которое показывает количество занятых inode. Их резкий рост и удержание на высоком уровне будет сигнализировать о вероятной спамерской активности с вашего сервера. А так как в отличии от первого (с mailq) такой скрипт работает очень быстро то мониторить можно ежесекундно.
Повторюсь, этот способ не подойдёт если каталог с почтовыми очередями находится в одной файловой системе с другими каталогами, например на корневой FS. Здесь начнут влиять inode временных файлов и всяких других создаваемых пользователями, программами и демонами. Впрочем вынести почтовые очереди на отдельную FS не такая уж и сложная задача. А для сервера полезная.
Запись терминальной сессии
Для записи терминальной сессии можно использовать обычный подход, записывать видео. Однако в этом есть два неудобства: во-первых видео занимает много места, во-вторых из видео нельзя сделать copy&paste текстовой информации.
Оба эти недостатка отсутствуют в программе asciinema. Её файлы маленькие и поддерживается copy&paste.
Галерею работ можно посмотреть на https://asciinema.org/.
И сразу можно сделать копию для себя так как исходный код прилагается.
Исходный код плеера
Исходный код для сайта
А с помощью другой утилиты можно устроить живую демонстрацию своей консоли.
Трансляция окна своей консоли как WEB приложения
GoTTY позволяет устроить демонстрацию окна своей консоли как web приложения.
Для эмуляции терминала на JavaScript в интернет браузерах Gotty использует hterm. Gotty имеет свой websocket сервер перебрасывает PTY веб-клиентам и принимает ввод от клиентов и перебрасывает его на PTY. Идея hterm + websocket была навеяна Wetty.
Для каждого клиента подсоединяющегося к websocket GoTTY порождает новый процесс и это значит, что напрямую нельзя расшаривать терминал многим клиентам. Однако можно использовать мультиплексор терминала tmux. Но в этом случае клиенты будут находиться в режиме viewonly без передачи нажатий клавиатуры в терминал, а тот кто будет подключён локально сможет управлять терминалом.
Распространяется под лицензией MIT.
Исходники на https://github.com/yudai/gotty
Также имеется и утилита которая позволяет сделать легковесные файлы с записью работы в терминальной сессии и воспроизводить их в браузере.
Получение списка NS серверов для домена
Однострочный скрипт для получения списка ns сероверов домена.
DOMAIN="youngblog.hoster-ok.com"; TLD="${DOMAIN##*.}"; FLD="${DOMAIN%.*}"; FLD="${FLD##*.}"; echo -e "TLD:${TLD}\nFLD:${FLD}"; ROOTNS=`dig +short NS ${TLD}. | head -n 1 | sed -e 's/\.$//g'`; dig +authority +noadditional +nocomments +nostats +nocmd ${FLD}.${TLD}. @${ROOTNS} | sed -e 's/[;#%].*//g;s/^[ \t]*//g;s/[ \t]*$//g;/^$/d' TLD:com FLD:hoster-ok hoster-ok.com. 172800 IN NS ns1.vds-ok.com. hoster-ok.com. 172800 IN NS ns2.vds-ok.com. hoster-ok.com. 172800 IN NS ns1.hoster-ok.com.
Принцип следующий:
Первая команда dig +short NS ${TLD}. (обратите внимание на точку на конце) получает корневые NS сервера которые обслуживают конкретный TLD (Top Level Domain) например .com .net .org .ru и т.д., а вторая команда dig +authority +noadditional +nocomments +nostats +nocmd ${FLD}.${TLD}. @${ROOTNS} получает из определённого NS @${ROOTNS} информацию по домену ${FLD}.${TLD}. (снова обратите внимание на точку на конце) информация, которую нужно включить или подавить, перечислена ключами.
Обновление виртуальных квот Pure-FTP
Случается скопировать файлы в папку ftp пользователя или удалить в обход ftp сервера. Тоесть прямо с диска сервера, а не через FTP соединение. После этого наблюдается несоответствие суммарного размера файлов на диске в каталоге ftp с теми размерами которые вычисляет pureftp. В корне каждого ftp каталога при включённых виртуальных квотах размещаются файлы .ftpquota. Эти файлы содержат два числа: количество файлов и их суммарный размер. При каждом добавлении обновлении или удалении файла через FTP демон pure-ftpd вносит измненение в этот файл. И если каталоги FTP изменять (добавлять удалять файлы) в обход pure-ftpd изменения остаются неучтёнными в этом файле. Для того чтобы восстановить соответствие сожержимого папок ftp сервера и файла .ftpquota предназначается команда pure-quotacheck. Работает она только для одного выбранного пользователя. А если необходимо пробежаться по всем пользователям то можно воспользоваться таким скриптом:
#!/bin/bash PUREPW="/usr/bin/pure-pw" PUREQUOTACHECK="/usr/sbin/pure-quotacheck" AWK="/bin/awk" SED="/bin/sed" XARGS="/usr/bin/xargs" # update all virtual quotas with no messages # "${PUREPW}" list | "${AWK}" '{print $2}' | "${SED}" -e 's|/\./$||g' | "${XARGS}" -I{} "${PUREQUOTACHECK}" -u pureftp -d "{}" # update all virtual quotas with progress info "${PUREPW}" list | "${AWK}" '{print gensub(/\.\/$/,"","g",$2)}' | while read FTPHOME ; do [ -e "${FTPHOME}" ] && ( echo -en "${FTPHOME}:"; [ -e "${FTPHOME}.ftpquota" ] && BEFORE=`cat "${FTPHOME}.ftpquota"` || BEFORE=""; "${PUREQUOTACHECK}" -u pureftp -d "${FTPHOME}"; AFTER=`cat "${FTPHOME}.ftpquota"`; [ "${BEFORE}" == "${AFTER}" ] && (echo -en " no changes ") || ( echo -en " changed\n" echo -e "1 ${BEFORE}\n2 ${AFTER}" | "${AWK}" '{printf("files:%10d size:%14d", $2, $3); if($1==1){printf("\n");}}' ) echo " [Done]" ); done
pureftp – это локальный пользователь для демона pure-ftpd
Этот скрипт отчитается о изменении файлов .ftpquota для каждого пользователя ftp и выведет информацию из этого файла перед и после обновления, так что будет ясно где была разница. Внутри также есть закоментарованный “однострочник” которые обновить файлы .ftpquota без вывода каких либо сообщений.
В документации по PureFTP рекомендуется регулярно обновлять виртуальные квоты. Поэтому скрипт можно добавить в крон и в зависимости от количества и объёма всех FTP файлов запускать его один раз в сутки или в неделю.
А этот скрипт выводит текущие квоты всех пользователей.
pure-pw list | awk '{print gensub(/\.\/$/,".ftpquota","g",$2)}' | while read FN ; do [ -e "${FN}" ] && (echo -en "${FN}:"; cat "${FN}" | tr -d '\n'; echo ) ; done
Получить список соответствия LV = dm-N
При мониторинге производительности дисковой подсистемы возникает необходимость воспользоваться командой iostat. Она выводит результат по утилизации дисков с использованием символических имёт из ядра вида vd[a-z]N sd[a-z]N и dm-N. Когда речь касается физических дисков например /dev/sdaN тут всё понятно. А вот когда используется LVM то чтобы узнать какоe имя dm-N соответствует какому логическому тому нужно посмотреть какие lv_kernel_major и lv_kernel_minor соответствуют данному dm устройству в ядре. Следующая команда делает это автоматически.
lvs -o lv_name,lv_kernel_major,lv_kernel_minor | while read LVNAME LVKMAJOR LVKMINOR ; do grep '^[ \t]*'${LVKMAJOR}'[ \t]\+'${LVKMINOR}'[ \t]\+' /proc/partitions | awk -v name="${LVNAME}" '{print $4" "name}'; done dm-7 lv_log dm-0 lv_root dm-1 lv_swap dm-5 empty dm-6 lv_server_fm-disk0 dm-8 lv_server_fm-disk1 dm-2 lv_vm1_disk0 dm-3 lv_vm2_disk0 dm-4 lv_vm3_disk0
Если нужно получить полные имена то нужно использовать опцию lv_path
# lvs -o lv_path,lv_kernel_major,lv_kernel_minor | while read LVNAME LVKMAJOR LVKMINOR ; do grep '^[ \t]*'${LVKMAJOR}'[ \t]\+'${LVKMINOR}'[ \t]\+' /proc/partitions | awk -v name="${LVNAME}" '{print $4" "name}'; done dm-7 /dev/vg_v03t/lv_log dm-0 /dev/vg_v03t/lv_root dm-1 /dev/vg_v03t/lv_swap dm-5 /dev/vg_vm/empty dm-6 /dev/vg_vm/lv_server_fm-disk0 dm-8 /dev/vg_vm/lv_server_fm-disk1 dm-2 /dev/vg_vm/lv_vm1_disk0 dm-3 /dev/vg_vm/lv_vm2_disk0 dm-4 /dev/vg_vm/lv_vm3_disk0
А если полные имена через /dev/mapper то опцию lv_dm_path
# lvs -o lv_dm_path,lv_kernel_major,lv_kernel_minor | while read LVNAME LVKMAJOR LVKMINOR ; do grep '^[ \t]*'${LVKMAJOR}'[ \t]\+'${LVKMINOR}'[ \t]\+' /proc/partitions | awk -v name="${LVNAME}" '{print $4" "name}'; done dm-7 /dev/mapper/vg_v03t-lv_log dm-0 /dev/mapper/vg_v03t-lv_root dm-1 /dev/mapper/vg_v03t-lv_swap dm-5 /dev/mapper/vg_vm-empty dm-6 /dev/mapper/vg_vm-lv_server_fm--disk0 dm-8 /dev/mapper/vg_vm-lv_server_fm--disk1 dm-2 /dev/mapper/vg_vm-lv_vm1_disk0 dm-3 /dev/mapper/vg_vm-lv_vm2_disk0 dm-4 /dev/mapper/vg_vm-lv_vm3_disk0