Категории

вторник, 5 ноября 2013 г.

Hex to string cmd, bat "function"

@ECHO OFF

:: Включение расширенной обработки команд.
SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION

:: Строка в hex - в данном случае dlink.
SET "x16=646c696e6b"
CALL :Hex_To_String "%x16%" str
ECHO.%str%

PAUSE
EXIT

:Hex_To_String
:: Вызывать так: CALL :Hex_To_String %hex_x16_string% value_name
:: Где %hex_x16_string% - строка в 16-ричном hex формате
:: value_name - имя переменной, в которую вернуть значение вычисленной строки.
  SETLOCAL & SET "x16=%~1"
  SET n=45
  FOR %%A IN (- . / 0 1 2 3 4 5 6 7 8 9) DO SET "s.!n!=%%A" & SET /A n+=1
  SET n=65
  FOR %%A IN (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) DO SET "s.!n!=%%A" & SET /A n+=1
  SET n=97
  FOR %%A IN (a b c d e f g h i j k l m n o p q r s t u v w x y z) DO SET "s.!n!=%%A" & SET /A n+=1
  SET "xs="
  FOR /L %%C IN (0,2,8184) DO (
    IF "!x16:~%%C,1!"=="" GOTO _ex_Hex str
    SET /A x10=0x!x16:~%%C,2!
    CALL SET xs=!xs!%%s.!x10!%%
  )
:_ex_Hex
  ENDLOCAL & SET "%~2=%xs%"
GOTO :EOF

1. CMD/BAT: hex дампер
2. Полезные BAT/CMD скрипты
3. Hex to string converter Online
4. String to hex converter Online

вторник, 17 сентября 2013 г.

Решение проблем во FreeBSD < 9.x c bsd tar.

При обновлении портов на FreeBSD ниже 9.x возникают подобные проблемы с xz архивами:
# cd usr/ports/misc/mc 
# make 
===>  License GPLv3 accepted by the user 
===>  Found saved configuration for mc-4.8.1.6 
===> Fetching all distfiles required by mc-4.8.1.7 for building 
===>  Extracting for mc-4.8.1.7 
=> SHA256 Checksum OK for mc-4.8.1.7.tar.xz. 
===>   mc-4.8.1.7 depends on file: /usr/local/bin/xz - found 
===>   mc-4.8.1.7 depends on file: /usr/local/bin/perl5.14.2 - found 
tar: Unrecognized archive format: Inappropriate file type or format 
tar: Error exit delayed from previous errors. 
*** Error code 1 

Stop in /usr/ports/misc/mc. 
*** Error code 1 

Stop in /usr/ports/misc/mc.
Лечится довольно просто, установкой libarchive и 1 строчкой в /etc/make.conf:
#cd /usr/ports/archivers/libarchive
#make install clean
#echo 'TAR=/usr/local/bin/bsdtar' >> /etc/make.conf

Ссылки по теме:
1. 2. Обновление портов и tar.Xz
3. Исправление ошибки во freebsd tar xz.

Чтение файлов журнала .jnl bind, named named-journalprint

Для чтения файлов журнала .jnl DNS сервера Named (bind), существует утилита named-journalprint.
FreeBSD# named-journalprint zone.local.jnl

1. Working with a journal-ized bind zone

понедельник, 16 сентября 2013 г.

Ubuntu 12.04 - transmission и samba

Для успешной с файлами по samba, скаченными при помощи свежеустановленного transmission нужно изменить umask для вновь создаваемых файлов и каталогов демоном transmission и для этого первым делом останавливаем демона:
Ubuntu$ sudo service transmission-daemon stop
 * Stopping bittorrent daemon transmission-daemon      [ OK ]
Если демона не остановить, то все изменения в конфиге не сохранятся, т.к. при перезапуске transmission перезапишет свой файл из памяти и все изменения пропадут.
Убедившись, что демон transmission не запущен - открываем файл настроек:
Ubuntu$ sudo nano /etc/transmission-daemon/settings.json
Находим там параметр "umask": 18, и изменяем значение на "umask": 2,, затем сохраняем файл.

С таким значением umask демон transmission будет создавать:
Каталоги с маской 775 - читать, писать, исполнять (заходить в каталог) владельцу и группе, остальным только читать и исполнять(заходить в каталог).
Файлы с маской 664 - читать, писать владельцу и группе, остальным только читать.

Теперь добавляем пользователя, под которым подключаемся к samba шарам, в группу debian-transmission:
Ubuntu$ sudo id metajiji
uid=1000(metajiji) gid=1000(metajiji) группы=1000(metajiji),4(adm),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),104(fuse),108(lpadmin),109(sambashare)
Ubuntu$ sudo usermod metajiji -aG debian-transmission
Ubuntu$ sudo id metajiji
uid=1000(metajiji) gid=1000(metajiji) группы=1000(metajiji),4(adm),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),104(fuse),108(lpadmin),109(sambashare),111(debian-transmission)
Как видим, командой id можно проверить список групп, а так же увидеть uid/gid в которых состоит пользователь.
Запускаем демона transmission:
sudo service transmission-daemon start
 * Starting bittorrent daemon transmission-daemon      [ OK ]

P.S. Если все сделано правильно, то transmission будет скачивать файлы с правильными правами, так, что их можно будет удалять, перемещать, редактировать через samba, не прибегая к редактированию системных файлов(/etc/init.d/transmission-daemon) и т.п. ухищрений - так делать не нужно, ведь после обновления есть большая вероятность, что этот файл обновится и вам придется заново редактировать его вручную, в то время, как можно было сделать все менее радикально :)

Ссылки по теме:
1. Wiki - Umask
2. Ubuntu server 12.04 Transmission-daemon error: Permission denied...

вторник, 10 сентября 2013 г.

Скрипт генерации сертификатов SSL для nginx.

Скрипт генерации ssl сертификатов и ключей для nginx:
#!/bin/sh

error() {
        echo 'ERROR detected! Exiting...'
        exit 1
}

#################################################
DOMAIN='domain.com'
EMAIL='admin@domain.com'
ORGANISATION='Organisation'
CITY='you city'
RSA_BIT=2048
DAYS=99365
#################################################

# Генерируем пароль для ключей.
PASS=$(tr -cd A-Za-z < /dev/urandom | head -c8)
echo 'Generated Password: '${PASS}

# Проверим, если не существует каталог для домена, то создаем его.
[ ! -d ${DOMAIN} ] && mkdir ${DOMAIN} && echo 'Create directory: '${DOMAIN}

#http://linuxcmd.ru/openssl-genrsa-sozdanie-fayla-klyuchey
echo "Now create the server private key, you'll be asked for a passphrase:"
openssl genrsa -des3 -out ${DOMAIN}/${DOMAIN}.key -passout pass:${PASS} ${RSA_BIT}
[ $? -eq 1 ] && error

#http://linuxcmd.ru/openssl-req-sozdanie-csr-zaprosa
#В пункте Common Name (eg, YOUR name) []: надо указать именно имя домена (без http, https, /): имя.домена
echo 'Create the Certificate Signing Request (CSR):'
openssl req -out ${DOMAIN}/${DOMAIN}.csr -new -newkey rsa:${RSA_BIT} \
        -subj /C=RU/ST=${CITY}/L=${CITY}/O=${ORGANISATION}/OU=${ORGANISATION}/CN=*.${DOMAIN}/emailAddress=${EMAIL} \
        -nodes -keyout ${DOMAIN}/${DOMAIN}.key -passout pass:${PASS}
[ $? -eq 1 ] && error

# Starting up nginx with SSL using the above private key:
echo 'Remove the necessity of entering a passphrase for:'
cp ${DOMAIN}/${DOMAIN}.key ${DOMAIN}/${DOMAIN}.key.org
openssl rsa -in ${DOMAIN}/${DOMAIN}.key.org -out ${DOMAIN}/${DOMAIN}.key
[ $? -eq 1 ] && error

echo 'Finally sign the certificate using the above private key and CSR:'
openssl x509 -req -days ${DAYS} -in ${DOMAIN}/${DOMAIN}.csr -signkey ${DOMAIN}/${DOMAIN}.key -out ${DOMAIN}/${DOMAIN}.crt
[ $? -eq 1 ] && error


#http://wiki.nginx.org/HttpSslModule
cat <<_EOF
Update Nginx configuration by including the newly signed certificate and private key:
server {
    server_name YOUR_DOMAINNAME_HERE;
    listen 443;
    ssl on;
    ssl_certificate /usr/local/nginx/conf/server.crt;
    ssl_certificate_key /usr/local/nginx/conf/server.key;
}
_EOF

#Убедиться в том, что сервер присылает полную цепочку сертификатов,
#можно при помощи утилиты командной строки openssl, например:
#openssl s_client -connect www.godaddy.com:443

Ссылки по теме:
1. openssl req - создание CSR-запроса
2. openssl genrsa - создание файла ключей

среда, 4 сентября 2013 г.

Создание ярлыка .url в Windows из cmd\bat.

Для создания ярлыка в Windows на сетевую папку использую такой bat скрипт:
@ECHO OFF

SET "PATH_TO_URL=Server.url"

(
    ECHO.[InternetShortcut]
    ECHO.URL=file://server/
    ECHO.IconFile=%windir%\system32\SHELL32.dll
    ECHO.IconIndex=17
)>%PATH_TO_URL%

1. forum.oszone.net: CMD/BAT - создать ярлык

Ротация логов named Bind

Ротация логов bind средствами самого bind, создаем конфиг:
logging {
        channel update_debug {
                file "/var/log/named-update.log" versions 6 size 512K;
                severity        debug 3;
                print-category  yes;
                print-severity  yes;
                print-time      yes;
        };
        channel security_info {
                file "/var/log/named-auth.log" versions 6 size 512K;
                severity        info;
                print-category  yes;
                print-severity  yes;
                print-time      yes;
        };
#       channel queries {
#               file "/var/log/queries" versions 6 size 10m;
#               print-time      yes;
#               print-category  yes;
#               print-severity  yes;
#       };

#       category queries { queries; };
        category update { update_debug; };
        category security { security_info; };
};
Обратите внимание на опцию:
file "/var/log/named-update.log" versions 6 size 512K;
Директива file указывает на файл, куда нужно писать логи, а опция versions задает количество лог-файлов, size задает размер лог файла, при достижении которого нужно произвести ротацию. И подключаем в named.conf
include "/etc/namedb/log.conf";
! ! ВАЖНО ! ! !
Не используйте newsyslog для ротации логов bind, т.к. он не поддерживает переоткрытие лог-файла, а после того как newsyslog произведет ротацию и создаст новый файл bind потеряет дескриптор прежнего лог-файла и перестанет писать логи, мало того bind перестанет еще и обновлять ddns зону! Поэтому разумнее использовать либо встроенные средства ротации логов, либо перенаправить логи в syslog.

Ссылки по теме:
1. BIND Configuration File Guide - logging Statement
2. Bog BOS: DNS сервер BIND

понедельник, 26 августа 2013 г.

sh скрипт для поиска и удаления одинаковых файлов по md5. (script for delete duplicates files by md5 hash).

Скрипт для поиска и удаления одинаковых файлов по md5
#!/bin/sh

#TODO - проверить наличие необходимых утилит
#md5
#find
#getopts
#grep

get_yes_no() {
        while [ true ]; do
                echo -n "$1 (Y/N) ? "
                read a
                if [ $? != 0 ]; then
                        a='No'
                        return
                fi
                case $a in
                        [Yy]) a='Yes'; return ;;
                        [Nn]) a='No'; return ;;
                        *) ;;
                esac
        done
}

build_hash_db() {
# Проверяем существует ли указанный файл БД, если да, то спрашиваем что делать - удалить и создать новый или выйти.
        echo "Запущено построение базы хешей каталога: "$1
        if [ -f "$db_FILE" ]; then
                get_yes_no 'Файл БД уже существует, удалить и создать новый?'
                [ $a = 'No' ] && echo 'Аварийное завершение.' && exit 1
                [ $a = 'Yes' ] && echo 'Файл БД удален и будет создан заново.' && rm -f "$db_FILE"
        fi

        find "$1" -type f -print | while read file; do
                echo "`md5 -q "$file"`  $file" >> $db_FILE
        done
}

find_and_delete_duplicates_by_hash_from_db(){
        # Если база не создана, то предлагаем создать её.
        echo "Запущен поиск дубликатов в каталоге $1 по базе хешей $db_FILE"
        [ ! -f $db_FILE ] && get_yes_no 'Файл БД не существует, создать новый?'
        [ "$a" = 'No' ] && echo 'Аварийное завершение.' && exit 1
        if [ "$a" = 'Yes' ]; then
                echo 'Создание файла БД: '$db_FILE
                while [ true ]; do
                        echo -n 'Введите путь до каталога по которому будет создаваться файл БД: '
                        read b
                        [ $? != 0 ] && return
                        if [ -d $b ]; then
                                build_hash_db "$b"
                                return
                        else
                                echo 'Вы ввели неверный путь. Повторите попытку.'
                        fi
                done
        fi

        # Ищем дубликаты в каталоге $1 по БД хешей $db_FILE.
        echo '#--------------------------- '`date "+%d.%m.%Y %H:%M:%S"` > ${db_FILE}.log
        find "$1" -type f -print | while read file; do
                hash=`md5 -q "$file"`
                if grep -q $hash $db_FILE ; then
                        echo "$file"' is a duplicate and has been removed.'
                        echo $hash'     '$file >> "${db_FILE}.log"
                        rm -f "$file"
                fi
        done
}

usage() {
        [ -n "$1" ] && echo "$1"
        cat << _EOF
        -c Режим построения базы хешей.
        -d Режим поиска и удаления повторяющихся файлов на основе построенной ранее базы хешей.
        -f Имя файла БД с хешами, если не будет указан, то будет использоваться значение по умолчанию - file.csv
        -h | --help Справка.

        Пример использования:
        1. Создать базу хешей каталога 1:
                ./$0 -c -f my_file.csv /path/to/folder
        2. Найти и удалить дубликаты по созданной базе хешей в каталоге 2:
                ./$0 -d -f my_file.csv /path/to/folder

_EOF
        exit 2
}

# Проверяем на пустые аргументы.
[ $# -lt 1 ] && usage

c_FLG=0; d_FLG=0;
while getopts hcdf: a; do
        case "$a" in
                c) [ $d_FLG = 1 ] && usage 'ОШИБКА! Нельзя использовать одновременно опции -c и -d.'; c_FLG=1 ;;
                d) [ $c_FLG = 1 ] && usage 'ОШИБКА! Нельзя использовать одновременно опции -c и -d.'; d_FLG=1 ;;
                f) db_FILE="$OPTARG" ;;
                ?|h) usage ;;
        esac
done

# Сдвигаем ряд аргументов на количество уже разобранных аргументов и оставляем последний.
shift $(($OPTIND-1)) #shift `expr  $OPTIND - 1`

# Проверка аргументов и важных переменных.
[ -z "$1" ] && usage 'ОШИБКА! Не задан каталог для обработки.'
[ -z "$db_FILE" ] && usage 'ОШИБКА! Не задана опция -f.'
[ $c_FLG = 0 -a $d_FLG = 0 ] && usage 'ОШИБКА! Не указана ни одна из опций -c или -d.'

# Запуск фукций в зависимости от установленных переменных.
[ "$c_FLG" = 1 ] && build_hash_db "$1"
[ "$d_FLG" = 1 ] && find_and_delete_duplicates_by_hash_from_db "$1"

воскресенье, 25 августа 2013 г.

Ubuntu 12.04 samba не работает при старте системы.

После установки samba обнаружил проблему - после перезагрузки системы демон smbd запускается, но пользователи не могут получить доступ к шарам. Поиск по интернетам особо не дал результатов, пришлось разбираться самому.
Проблема заключалась в том, что демон стартует после инициализации файловых систем и поднятия сетевых интерфейсов. И похоже smbd стартовал сразу, как только поднимался lo0, не дожидаясь пока остальные интерфейсы получат ip адреса по DHCP и тоже перейдут в состояние up. Подсмотел в скрипт запуска nmbd и обнаружил, что группа интерфейсов lo игнорируется. Этот же прием применил и для smbd, отредактировав файл /etc/init/smbd.conf:
start on (local-filesystems and net-device-up IFACE!=lo)
#start on (local-filesystems and net-device-up)

среда, 19 июня 2013 г.

isc-dhcpd - Скрипт для просмотра и удаления арендованных адресов из файла dhcpd.leases.

Скрипт парсит dhcpd.leases файл и отображает список подсетей 0/24 на выбор, после выбора подсети выдается список арендованных ip со статусом free или active, где можно выбрать один или несколько ip и удалить.
Скрипт использует dialog, за счет чего меню получается очень привлекательным :) - писал под FreeBSD, на Linux не тестировал (возможно будут проблемы из-за несовместимости BSD awk и GNU awk), хотя думаю, что должен работать и под Linux.
#!/bin/sh

# загружаем /etc/rc.conf.
. /etc/rc.conf

#TODO - установить имя файла более точнее, см. /usr/local/etc/rc.d/isc-dhcpd.
file=${dhcpd_rootdir}/var/db/dhcpd/dhcpd.leases

tempfile=$(mktemp 2>/dev/null) || tempfile=/tmp/$(basename $0)_$$
trap "rm -f $tempfile" 0 1 2 5 15

### functions: BEGIN
# Функция запуска команд в информационном окошке.
exec_fun() {
        dialog --sleep 1 --title "$2" \
                --msgbox "`echo ;$1 2>&1;echo`" 15 85
}


# Функция удаления lease.
del_lease() {
        exec_fun "service isc-dhcpd stop" "Status Daemon:"
#TODO - убедиться, что демон остановлен.

        # Бекап базы.
        DATE=$(date "+%Y%m%d%H%M")
        cp $file ${file}.$DATE

        for i in $1; do
                awk 'BEGIN { FLG=0; } {
                        if ($0=="lease '$i' {") FLG=1;
                        if (FLG=="0") printf "%s",$0"\n";
                        if ($0=="}" && FLG=="1") FLG=0;
                }' $file > ${file}.new
                mv ${file}.new $file
        done

        [ -f "${file}~" ] && rm -f "${file}~"
        exec_fun "service isc-dhcpd start" "Status Daemon:"
#TODO - убедиться, что демон запущен.
}

# Функция получения списка subnet из dhcpd.leasees файла.
get_subnet_list() {
        grep -oE '^lease [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.' $file | sort -u \
                | awk 'BEGIN { n=1; }{ print n" "$2"0/24 off"; n++; }'
}

# Функция получения списка ip по subnet'у /24 и вывод списка в виде dialog.
get_leases() {
        while [ true ]; do
                LIST=`awk '{ out=""; sub(/[;#].*/,"",$0); \
                                if ($1" "$2" "$3 ~ /^lease '$(echo $1 | sed 's|\.|\\.|g')'[0-9]?[0-9]?[0-9] \{$/ ) { out=" "$2; FLG=1; } \
                                if ($1=="binding" && FLG=="1") out=" "$3; \
                                if ($1=="}" && FLG=="1") { out="\n"; FLG=0; } \
                                printf out," "; }' $file | \
                        sort -un -t . -k 1,1 -k 2,2 -k 3,3 -k 4,4 | \
                        awk 'BEGIN { n=1; }{ print n" \""$1" "$2"\" off"; n++; }'`

                DIALOG='dialog --backtitle "Редактирование '$file'"
                                --cancel-label Back
                                --ok-label Delete
                                --title "Редактирование '$1'0/24" --clear
                                --checklist "Выбор lease" 20 61 10
                                '$LIST' 2> '$tempfile
                eval $DIALOG

                # Собственно удаление выбранных lease. $(cat $tempfile)
                if [ "$?" -eq 0 ]; then
                        # Формируем и передаваем в функцию удаления список ip.
                        DEL_LIST=''
                        for i in $(cat $tempfile); do
                                DEL_LIST="$DEL_LIST "`echo "$LIST" | awk '{
                                        if ($1=="'$i'") {
                                                sub(/0\/24$/,"",$2);
                                                sub(/"/,"",$2);
                                                print $2; }}'`
                        done
                        del_lease "$DEL_LIST"
                else
                        break;  # Выходим из while [true].
                fi
        done
}
### functions: END

[ ! -f $file ] && echo 'ERROR: File "'$file'" not exist or not readable!' && exit 1

while [ true ]; do
        LIST="$(get_subnet_list)"
        dialog --backtitle "Редактирование $file" \
                --cancel-label Exit \
                --title "Редактирование $file" --clear \
                --radiolist "Выбор subnet" 20 61 10 \
                $LIST \
                2> $tempfile

        if [ "$?" -eq 0 ]; then
                `echo "$LIST" | awk '{ if ($1=="'$(cat $tempfile)'") { \
                        sub(/0\/24$/,"",$2); print "get_leases "$2 }}'`
        else
                break;  # Выходим из while [true].
        fi
done

четверг, 6 июня 2013 г.

Windows 7 ошибочно полагает что нет доступа к internet или желтый восклицательный знак в трее

После установки контент фильтра по статье Контент фильтр и статистика посещенных сайтов Squid + rejik + ipcad + Free-SA + nginx у пользователей Windows 7 возникли проблемы с сетевым апплетом в трее - он стал ошибочно показывать, что подключение к интернету отсутствует, хотя интернет работает.
После недолгих поисков в интернете было найдено 2 решения. Первое [1] связано с разблокировкой сайта msftncsi.com, который windows 7 проверяет на доступность и в случае, если она не смогла получить к этому сайту доступ - выдает пользователю, что интернета нет! :) А так же Windows 7 проверяет резолв доменого имени dns.msftncsi.com - оно должно быть 131.107.255.255. Хоть и пишут в [1], что Windows 7 проверяет оба варианта и, если хотябы один из них пройдет проверку, то Windows 7 определит, что интернет есть, но у меня это на всех машинах не работало, пока не занес адрес msftncsi.com в список исключений на Rejik'e.
Для любителей поковырять и оптимизировать свою ОС в интернете предлагается 2 вариант [2] - отключить в самой ОС проверки интернета и апплет всегда будет считать, что интернет есть.

1. Appendix H: Network Connectivity Status Indicator and Resulting Internet Communication in Windows 7 and Windows Server 2008 R2
2. Как убрать восклицательный знак со значка подключения к сети в трее в Windows 7
3. http://www.msftncsi.com/ncsi.txt

пятница, 22 марта 2013 г.

Скрипт для пакетного конвертирования из wav в alaw, ulaw, gsm через sox.

Скрипт для пакетного конвертирования из wav в alaw, ulaw, gsm.
#!/bin/sh

IN='IN'  # Входная папка.
OUT='OUT' # Выходная папка.

[ ! -d "$IN" ] && mkdir "$IN" && echo "Create dir: $IN"    # Создаем папку для входных файлов.
#[ -d "$OUT" ] && rm -rf "$OUT" && echo "Delete dir: $OUT"  # Чистим папку OUT.
[ ! -d "$OUT" ] && mkdir "$OUT" && echo "Create dir: $OUT" # Создаем папку для выходных файлов.
[ -d "$OUT/wav" ] && rm -rf "$OUT/wav" && echo "Delete dir: $OUT/wav"  # Чистим папку для wav файлов.
[ ! -d "$OUT/wav" ] && mkdir "$OUT/wav" && echo "Create dir: $OUT/wav" # Создаем папку для wav файлов.

convert_to() {
#$1 - Output format file.
#$2 - IN file.

 [ -z "$1" ] && echo 'ERROR: $1 is empty!' && exit 1
 [ -z "$2" ] && echo 'ERROR: $2 is empty!' && exit 1

 case $1 in
  alaw) SOX_OPT='-t al' ;;
  ulaw) SOX_OPT='-t ul' ;;
  gsm) SOX_OPT='' ;;
  *) echo "ERROR: fromat $1 is not supported!"; exit 1 ;;
 esac

 # Если нужные директории не существуют, то создаем их.
 if [ ! -d "$OUT/wav$D_OUT" ]; then
  echo "Create dir: $D_IN -> $OUT/wav$D_OUT";
  mkdir -p $OUT/wav$D_OUT
  echo '------------------------'
 fi
 if [ ! -d "$OUT/$1$D_OUT" ]; then
  echo "Create dir: $D_IN -> $OUT/$1$D_OUT";
  mkdir -p $OUT/$1$D_OUT
  echo '------------------------'
 fi

 F_OUT=$(basename $2 .wav)
 echo "Processing: $2 -> $OUT/$1$D_OUT/$F_OUT.$1"

 # Проверим, существует ли входной файл.
 if [ -f "$2" ]; then
  # Если нету wav, то для начала сконвертим в wav.
  if [ ! -f $OUT/wav$D_OUT/$F_OUT.wav ]; then
   echo 'Convert to 8bit wav first at 8000Hz - this can take a while...'
   sox "$2" -r 8000 -c1 "$OUT/wav$D_OUT/$F_OUT.wav"
  fi
  #Проверяем имеется ли входной wav файл.
  if [ -f $OUT/wav$D_OUT/$F_OUT.wav ]; then
   # Если файл в нужном формате $1 уже существует, то сперва удаляем его, потом конвертим
   if [ -f $OUT/$1$D_OUT/$F_OUT.$1 ]; then
    echo "INFO: File exist! $OUT/$1$D_OUT/$F_OUT.$1 remove..."
    rm -f $OUT/$1$D_OUT/$F_OUT.$1
   fi
   sox "$OUT/wav$D_OUT/$F_OUT.wav" $SOX_OPT "$OUT/$1$D_OUT/$F_OUT.$1"
  else
   echo "ERROR: Input wav file $OUT/wav$D_OUT/$F_OUT.wav is not exist!"
   exit 1
  fi
 else
  echo "ERROR: Input file $2 not exists!"
 fi
}

find $IN -type d -depth -print | while read D_IN; do # ищем сперва самые "глубокие Директории"
 D_OUT=$(echo "$D_IN" | sed -e 's/'$IN'//') # Получаем имя выходного каталога.

 # Ищем во входном каталоге wav файлы.
 find $D_IN -type f -name "*.wav" -print -maxdepth 1 | while read file; do
  convert_to alaw "$file"
  convert_to ulaw "$file"
  convert_to gsm "$file"
 done
done

# TIP - Увеличение громкости
#sox file1.wav -v 5 file2.wav
#ffmpeg myfile.wav $i -vol 256 -acodec pcm_s16le -ar 8000 -ac 1 -y filename_out"${i%wav}wav" -vol volume change audio volume (256=normal)

четверг, 21 марта 2013 г.

Контент фильтр и статистика посещенных сайтов Squid + rejik + ipcad + Free-SA + nginx

Для организации логирования, статистики посещенных сайтов и других сетевых соединений я воспользовался связкой Squid + Free-SA + ipcad.

  • Squid - Прокси сервер, который работает у меня в прозрачном (transparent | intercept) режиме - пользователям ничего настраивать не придется. Более подробно о нем писать не вижу смысла.
  • Free-SA - Анализатор логов Squid написан на языке Си, по функциональности и назначению похож на LightSquid. Главное отличие - скорость формирования отчетов от 7 до 20 раз выше по сравнению с LightSquid (7х - для 50 Мб файла access.log, 20x - для 1 Гб). Присутствуют дополнительные отчеты (в том числе для оценки эффективности сервера), изменяемые "на лету" темы оформления, имеется поддержка различных форматов файлов журналов (Squid, CLF, Postfix, Qmail, CGP). Имеет мало зависимостей в отличие от того же LightSquid и малые требования к веб серверу! В настройках можно много чего интересного покрутить, об этом ниже. Еще хотелось бы отметить полезного из функционала - опционально можно включить в отчеты полные URL - для подробной отчетности, либо наоборот отключить (будет быстрее формироваться статистика).
  • Rejik - redirector для Squid, выполняющий функции контент фильтра. Поддерживает регулярные выражения, и просто списки сайтов. Можно добавлять исключения, применять правила по времени или ip адресам. Из плюсов - высокая скорость работы. Из минусов, чтобы скачать базы, нужно либо поработать - проверить несколько сотен сайтов на принадлежность, либо просто купить списки "плохих" сайтов.
  • ipcad - Коллектора для сбора трафика, идущего в обход прокси-сервера. Остается только взять извлечь из него статистику и записать в лог Squid. Скрипт для этого есть ниже.
  • nginx - Легковесный и производительный веб-сервер. Для запуска CGI скриптов/программ лучше всего использовать fcgiwrap, о настройке ниже. Более подробно расписывать не вижу смысла.
Весь выбранный софт бесплатный и имеется в портах FreeBSD и под Linux, думаю тоже все эти пакеты есть.
Итак по порядку, первым делом обновляем порты и устанавливаем весь перечисленный софт:
FreeBSD# cd /usr/ports
FreeBSD# portsnap fetch update
FreeBSD# cd /usr/ports/www/squid
FreeBSD# make config && make config-recursive
[x] SQUID_IDENT
[x] SQUID_KQUEUE
[x] SQUID_LARGEFILE
FreeBSD# make install clean
FreeBSD# cd /usr/ports/www/free-sa
FreeBSD# make install clean
FreeBSD# cd /usr/ports/www/rejik
FreeBSD# make config && make config-recursive
[x] BAN
[x] DBL
[x] WWW
FreeBSD# make install clean
FreeBSD# cd /usr/ports/www/nginx
FreeBSD# make config && make config-recursive
[x] HTTP
[x] HTTP_CACHE
[x] HTTP_REWRITE
[x] HTTP_STATUS
[x] WWW
FreeBSD# make install clean
FreeBSD# cd /usr/ports/www/fcgiwrap
FreeBSD# make install clean
FreeBSD# cd /usr/ports/net-mgmt/ipcad
FreeBSD# make install clean
Когда все успешно установится переходим к настройкам:
Листинг free-sa.conf:
#
# Sample configuration file for free-sa(1)
#
# copy to /usr/local/etc/free-sa/free-sa.conf
#


#########
# FILES #
#########
log="/var/log/squid/access.log"
#usertab="/usr/local/etc/free-sa/users"
downloads="/usr/local/etc/free-sa/downloads.sample"
#local_filter=""
#global_filter=""


###############
# DIRECTORIES #
###############
targetdir="/usr/local/www/data/free-sa"
tmpdir="/var/cache/free-sa"


#####################
# REPORTS SELECTION #
#####################
ts="true"
paf="true"
saf="true"
pdn="true"
sdn="true"
cct="true"
pst="true"
dld="true"
fullurl="true"
users="true"
#email=""


##################
# REPORTS LIMITS #
##################
#paf_limit="50"
#saf_limit="50"
#pdn_limit="50"
#sdn_limit="50"
#cct_limit="50"
#pst_limit="50"
#dld_limit="50"
#lcf_limit="50"
#url_limit="50"
#ts_limit="0"
#dld_min="0"
#rtr_timeout="5000"


####################
# OTHER PARAMETERS #
####################
name="free-sa.conf"
logformat="0"
#skip_errors="false"
fulltraffic="true"
inameuser="true"
#user_unescape="false"
indicators="true"
overwrite="2"
resolveip="true"
showinfo="true"
#site=""
#logo=""
locale="ru_RU.KOI8-R"
#rotate=""
divisor="b"
#tz_shift="0"
Создаем каталог для скриптов:
FreeBSD# mkdir /usr/local/etc/squid/scripts
И создаем в этой папке скрипты:
Листинг ipcadstat.sh:
#!/bin/sh

# Диапазон адресов локальной cети, указываем подсеть.
net="192\.168\.[0-9]?[0-9]?[0-9]\.[0-9]?[0-9]?[0-9]$" # 192.168.0.0/16
#net="192\.168\.0\.[0-9]?[0-9]?[0-9]$" # 192.168.0.0/24

# Каталог с логами squid'а
squid_DIR='/var/log/squid/'

ttime=`rsh localhost sh ip acco | grep 'Accounting data saved' | awk '{print ($4)}'`
rsh localhost clear ip accounting > /dev/null
rsh localhost show ip accounting checkpoint | awk -v vtime=$ttime '{
 if ( $2 ~ /^'$net'/ )
     print (vtime".000",1,$2,"TCP_MISS/200",$4,"CONNECT",$1":"$5,"-","DIRECT/"$1,"-")
 }' >> "$squid_DIR/access.log"

#TODO - если ошибок не было, то продолжаем.
/usr/local/bin/free-sa
Листинг rotate_log.sh:
#!/bin/sh

# Ротация логов Squid
/usr/local/sbin/squid -k rotate
for i in $(ls $squid_DIR | grep -i '\.log\.[4-9]'); do
    rm -f $squid_DIR/$i
done
Добавляем эти скрипты в планировщик заданий /etc/crontab:
# rotate squid logs
0    0  */1  *  *  root  /usr/local/etc/squid/scripts/rotate_log.sh >>/var/log/squid/rotate_log.log 2>&1

# Наполнение лога squid данными из ipcad.
*/5  *  *    *  *  root  /usr/local/etc/squid/scripts/ipcadstat.sh >>/var/log/squid/ipcadstat.log 2>&1
Привожу только те строки, которые изменил в дефолтном конфиге Squid - /usr/local/etc/squid/squid.conf:
http_port 3129 transparent
cache_mem 500 MB
maximum_object_size_in_memory 64 KB
cache_dir ufs /var/squid/cache 20480 16 256
maximum_object_size 100 MB
access_log /var/log/squid/access.log squid
cache_log /var/log/squid/cache.log
logfile_rotate 100
strip_query_terms off
url_rewrite_program /usr/local/rejik/redirector /usr/local/rejik/redirector.conf
url_rewrite_children 10
header_access Via deny all
cache_mgr Тут@Мое.мыло
visible_hostname имя.сервера.сквида
error_directory /usr/local/etc/squid/errors/Russian-1251
dns_nameservers Тут.ip.вашего.DNS.сервера
append_domain .local
forwarded_for off
Страницу блокировки я предпочитаю отдавать самим Squid, как это описано в FAQ по rejik'у - А нельзя ли обойтись без установки локального web сервера? Добавляем строки в /usr/local/etc/squid/mime.conf:
# Для rejik
dfgxfdgdfg-squid-porno dfgxfdgdfg-squid-deny/dfgxfdgdfg-squid-porno-html rejik/porno.html - ascii
dfgxfdgdfg-squid-deny dfgxfdgdfg-squid-deny/dfgxfdgdfg-squid-deny-html rejik/deny.html  - ascii
dfgxfdgdfg-squid-banner dfgxfdgdfg-squid-banner/dfgxfdgdfg-squid-banner-1px rejik/1x1.gif  - image
dfgxfdgdfg-squid-js dfgxfdgdfg-squid-js/dfgxfdgdfg-squid-js-js  rejik/js.js  - ascii
Файл 1x1.gif - это пустая gif картинка размером 1x1 пиксель.
Файл js.js - это пустой текстовый файл.
Файлы porno.html, deny.html - произвольный html документ, который будут видеть те, кто откроет запрещенный сайт.
Например у меня deny.html выглядит так:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Доступ ограничен</title>
<style type="text/css">
<!--
body,td,th {
 font-family: Verdana, Arial, Helvetica, sans-serif;
 font-size: 14px;
 color: #FFFFFF;
}
body {
 background-color: #000000;
 margin-top: 100px;
 margin-left: 100px;
 margin-right: 100px;
}
.style1 {
 color: #FF0000;
 font-size: 16px;
 font-weight: bold;
}
.style2 {font-size: 10px}
-->
</style></head>

<body>
<div align="center">
  <p class="style1">Содержимое данного сайта заблокировано!</p>
  <p>Система контентной фильтрации определила,<br />
  что материалы запрашиваемого вами ресурса<br />
  могут противоречить целям и задачам <br />
  образовательного процесса.</p>
  <hr width="400" size="3" />
  <p><span class="style2">Если вы уверены, что сайт не содержит недопустимой информации,<br />
  обратитесь к системному администратору. После проверки адрес<br />
  будет добавлен в список разрешенных ресурсов.</span></p>
</div>
</body>
</html>
Листинг /usr/local/rejik/redirector.conf:
error_log /usr/local/rejik/redirector.err
change_log /usr/local/rejik/redirector.log
make-cache /usr/local/rejik/make-cache
allow_urls /usr/local/rejik/banlists/allow_urls

# Список ip - исключений. (для кого НЕ будут применяться правила фильтрации)
allow_ip f:/usr/local/rejik/ip/allow


#
#ban_dir  /usr/local/rejik/banlists/audio-video
#url http://127.0.0.1:3126/squid-internal-static/icons/rejik/deny.html
#log off

#
#ban_dir  /usr/local/rejik/banlists/avto-moto
#url http://127.0.0.1:3126/squid-internal-static/icons/rejik/deny.html
#log off


ban_dir /usr/local/rejik/banlists/banners
#файлы смотри в каталоге /usr/local/etc/squid/icons/rejik + mime.conf файл сквида
url http://127.0.0.1:3126/squid-internal-static/icons/rejik/1x1.gif
log off

#
#ban_dir  /usr/local/rejik/banlists/chats
#url http://127.0.0.1:3126/squid-internal-static/icons/rejik/deny.html
#log off

#
#ban_dir  /usr/local/rejik/banlists/dating
#url http://127.0.0.1:3126/squid-internal-static/icons/rejik/deny.html
#log off


ban_dir  /usr/local/rejik/banlists/extremism
url http://127.0.0.1:3126/squid-internal-static/icons/rejik/deny.html
log off

#
#ban_dir  /usr/local/rejik/banlists/icq
#url http://127.0.0.1:3126/squid-internal-static/icons/rejik/deny.html
#log off

#
#ban_dir  /usr/local/rejik/banlists/jobsearch
#url http://127.0.0.1:3126/squid-internal-static/icons/rejik/deny.html
#log off


ban_dir  /usr/local/rejik/banlists/online-games
url http://127.0.0.1:3126/squid-internal-static/icons/rejik/deny.html
log off


ban_dir  /usr/local/rejik/banlists/phishing
url http://127.0.0.1:3126/squid-internal-static/icons/rejik/deny.html
log off

#
#ban_dir  /usr/local/rejik/banlists/photogallery
#url http://127.0.0.1:3126/squid-internal-static/icons/rejik/deny.html
#log off


ban_dir  /usr/local/rejik/banlists/porno
url http://127.0.0.1:3126/squid-internal-static/icons/rejik/deny.html
log off


ban_dir  /usr/local/rejik/banlists/socnet
url http://127.0.0.1:3126/squid-internal-static/icons/rejik/deny.html
work_ip f:/usr/local/rejik/ip/deny_socnet
log off


ban_dir  /usr/local/rejik/banlists/spyware
url http://127.0.0.1:3126/squid-internal-static/icons/rejik/deny.html
log off


ban_dir  /usr/local/rejik/banlists/torrents
url http://127.0.0.1:3126/squid-internal-static/icons/rejik/deny.html
log off


ban_dir  /usr/local/rejik/banlists/virus-detect
url http://127.0.0.1:3126/squid-internal-static/icons/rejik/deny.html
log off


ban_dir  /usr/local/rejik/banlists/warez
url http://127.0.0.1:3126/squid-internal-static/icons/rejik/deny.html
log off

#
#ban_dir  /usr/local/rejik/banlists/web-mail
#url http://127.0.0.1:3126/squid-internal-static/icons/rejik/deny.html
#log off


ban_dir  /usr/local/rejik/banlists/web-proxy
url http://127.0.0.1:3126/squid-internal-static/icons/rejik/deny.html
log off
Так как rejik из текстовых файлов со списками плохих сайтов делает файлы бинарные файлы, от после внесения изменений в списки, нужно обновлять *.cache файлы rejik'а, для этого я использую скрипт:
#!/bin/sh

# Путь  до rejik
REJIK_PATH=/usr/local/rejik


# Найдем и удалим файлы кеша rejik
find $REJIK_PATH -name '*.cache' -exec rm {} \;
# Создадим снова кеш rejik
$REJIK_PATH/make-cache

# говорим squid перечитать новую конфигурацию
/usr/local/sbin/squid -k reconfigure
Листинг с описанием виртуального хоста squid.local:
server {
#-------------------------- Options --------------------------#
    listen *:80;
    server_name squid.local squid;

    open_file_cache max=100000 inactive=40s;
    open_file_cache_valid 60s;
    open_file_cache_min_uses 2;
    open_file_cache_errors on;

#logs
    access_log /var/log/nginx/squid.local_http_access.log;
    error_log /var/log/nginx/squid.local_http_error.log;


#-------------------------- Configs --------------------------#
    # redirect server error pages to the static page /50x.html
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/local/www/nginx-dist;
    }

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    location ~ /\.ht {
        deny  all;
    }

    index index.html free-sa.cgi;

#-------------------------- Locations ------------------------#

    location ~ ^/favicon.ico$ {
 root /usr/local/www/data/free-sa;
 log_not_found off;
 access_log off;
 expires max;
    }

# Main location
    location / {
 root /usr/local/www/data/free-sa;

    location ~ \.cgi$ {
     gzip off; #gzip makes scripts feel slower since they have to complete before getting gzipped
     fastcgi_pass  unix:/var/run/fcgiwrap/lightsquid.socket;
     fastcgi_index free-sa.cgi;
     fastcgi_param SCRIPT_FILENAME /usr/local/www/data/free-sa/$fastcgi_script_name;
     fastcgi_param QUERY_STRING  $query_string;
     fastcgi_param REQUEST_METHOD $request_method;
     fastcgi_param CONTENT_TYPE  $content_type;
     fastcgi_param CONTENT_LENGTH $content_length;
     fastcgi_param GATEWAY_INTERFACE CGI/1.1;
     fastcgi_param SERVER_SOFTWARE nginx;
     fastcgi_param SCRIPT_NAME  $fastcgi_script_name;
     fastcgi_param REQUEST_URI  $request_uri;
     fastcgi_param DOCUMENT_URI  $document_uri;
     fastcgi_param DOCUMENT_ROOT  $document_root;
     fastcgi_param SERVER_PROTOCOL $server_protocol;
     fastcgi_param REMOTE_ADDR  $remote_addr;
     fastcgi_param REMOTE_PORT  $remote_port;
     fastcgi_param SERVER_ADDR  $server_addr;
     fastcgi_param SERVER_PORT  $server_port;
     fastcgi_param SERVER_NAME  $server_name;
 }
    }
}
Конечно же каталог с логами должен существовать и права должны быть такие же как у nginx:
FreeBSD# mkdir /var/log/nginx
FreeBSD# chown www:www /var/log/nginx
Не забываем про ротацию логов - добавляем в /etc/newsyslog.conf:
#nginx
/var/log/nginx-error.log www:www  644  7    900 *     XC /var/run/nginx.pid 30
/var/log/nginx/*.log  www:www  644  7    900 *     GXC /var/run/nginx.pid 30

# rejik
/usr/local/rejik/redirector.err squid:squid 644  10    300 *     XC
#crontab for Squid
/var/log/squid/rotate_log.log   644  3    100 *     XC
/var/log/squid/ipcadstat.log   644  3    100 *     XC
И перезапускаем демона newsyslog:
FreeBSD# service newsyslog restart

В качестве бонуса привожу скрипт для удобной перезагрузки конфига Squid. Так как после внесения изменений в конфигурацию Squid, нужно перезапускать сервис, либо из консоли давать команду squid -k reconfigure, что не всегда удобно + если мы допустили ошибку в конфиге ничего хорошего не будет от такой команды и уж темболее от перезагрузки сервиса - он не запустится, а у людей не будет интернета, чтобы всего этого избежать я написал простенький скриптик:
#!/bin/sh

# Функция вывода цветных сообщений
COLOR_STR() {
 case $2 in
  red) printf %b "\033[1;31m$1\033[0m" ;;
  green) printf %b "\033[1;32m$1\033[0m" ;;
 esac
}

squid -k check
if [ $? = 0 ]; then
 squid -k reconfigure
 COLOR_STR 'SUCCESS' green
 echo ': Squid config reloaded.'
else
 COLOR_STR 'ERROR' red
 echo ': in Squid config file.'
fi
В кратце как это работает - скрипт сперва проверяет синтаксис конфига squid -k check, и если ошибок небыло, то выполняет загрузку нового конфига squid -k reconfigure, если были ошибки, то он выдаст ошибку и Squid останется работать со старым конфигом, следовательно у всех будет интернет, а у вас будет время все исправить.
И последний конфиг - листинг файла конфигурации IpCad/usr/local/etc/ipcad.conf:
capture-ports enable;

interface lan0 filter "ip and dst net 192.168.0.0/16 and not src net 192.168.0.0/16 and not src port 80";

aggregate 0.0.0.0/0 strip 32; /* Drop the last octet of all other IPs */

aggregate 110 into 110;
aggregate 443 into 443;
aggregate 3129 into 0;
aggregate 3128 into 0;
aggregate 3130-65535 into 65535;

rsh enable at 127.0.0.1;
rsh root@127.0.0.1 admin;
rsh root@127.0.0.1 backup;
rsh root@127.0.0.1;
rsh 127.0.0.1 view-only;
rsh ttl = 3;
rsh timeout = 30;
chroot = /var/log/ipcad;
dumpfile = ipcad.dump;
pidfile = ipcad.pid;
Обратите внимание на строку interface lan0 filter "ip and dst net 192.168.0.0/16 and not src net 192.168.0.0/16 and not src port 80"; Эта строка предписывает ipcad собирать статистику пакетов попадающих в локальную сеть извне (из интернет) на LAN-интерфейсе. При этом в статистику не должны попадать пакеты от squid (т.е. те, порт источника которых равен 80 - у нас же прозрачный прокси) т.к. squid сам отразит их статистику в своем логе. Дублирование статистики нам ни к чему.

Как и чем заворачивать всех клиентов в Squid выбирайте сами - в интернете полно информации по этому поводу, я приведу 2 примера заворота при помощи pf и ipfw:
pf:
# редиректим всех, кроме таблицы <no_www_proxy> на наш Proxy сервер, чтобы отфильтровать "Плохие сайты"
rdr proto tcp from !<no_www_proxy> to !lan0:network port http -> 127.0.0.1 port 3129
ipfw:
# Squid transparent redirect
add fwd 127.0.0.1,3129 tcp from any to not 192.168.0.0/16 http via lan0
Где lan0 - имя локального интерфейса.
Теперь можно все это добавить в автозагрузку и запустить.
Вырезка из /etc/rc.conf:
#------------------------------ squid ------------------------------------#
squid_enable="YES" # Прозрачный прокси, для ведения статистики посещенных сайтов.
ipcad_enable="YES" # Для записи в статистику squid'а, всего остального трафика.
#-------------------------------------------------------------------------#


#------------------------------ nginx ------------------------------------#
nginx_enable="YES"  # (bool) Set to "NO" by default. Set it to "YES" to enable nginx

#php_fpm_enable="YES"

fcgiwrap_enable="YES"
fcgiwrap_profiles="lightsquid"
fcgiwrap_flags="-c 4"
fcgiwrap_lightsquid_socket="unix:/var/run/fcgiwrap/lightsquid.socket"
fcgiwrap_lightsquid_user="www"
#-------------------------------------------------------------------------#
Запускаем всех демонов:
FreeBSD# service squid start
FreeBSD# service ipcad start
FreeBSD# service fcgiwrap start
FreeBSD# service nginx start
Пробуем выйти в интернет, открыть запрещенные сайты - все должно работать как и предполагали. Через пять минут пробуем зайти в Free-SA http://squid.local/ и посмотреть статистику. Чтобы посмотреть статистику в режиме реального времени нужно открыть ссылку http://squid.local/cgi-bin/, где squid.local - имя вашего сервера с nginx.

Ссылки по теме:
1. Rejik FAQ: А нельзя ли обойтись без установки локального web сервера?
2. Wiki - IT рабочие заметки: ipcad
3. lissyara.su: Анализатор статистики Free-SA
4. rootmaster.at.ua: шлюз для небольшой сети на основе FreeBSD.
5. Подсчет трафика с помощью Squid и ipcad в pfSense 1.2.3
6. coolchevy's blog: Simple CGI support for Nginx
7. Habrahabr: Вебсервер nginx + fastcgi-wrapper + matlab
8. nginx.localdomain.pl: Simple CGI support for Nginx (fcgiwrap)
9. Rejik: DBL листы - что это и где взять?
10. Free-SA log processor

четверг, 14 марта 2013 г.

FreeBSD chroot sftp и chroot ssh.

Для предоставления доступа через ssh и sftp например к файлам сайта, можно использовать штатный для FreeBSD демон sshd.
Для начала добавим в конфиг демона /etc/ssh/sshd_config строки:
############## : BEGIN
#pw usermod sftponly -d /usr/local/www/
#chown root:wheel /usr/local/www/
#AllowGroups wheel sftp
#AllowUsers user1 user2 user3@192.168.1.1 user3@192.168.2.*

Match User web
   ChrootDirectory /home/%u
   X11Forwarding no
   AllowTcpForwarding no

Match Group sftp
   ChrootDirectory %h
   X11Forwarding no
   AllowTcpForwarding no
   ForceCommand internal-sftp
############## : END
Добавляем в систему пользователя sftp и web:
FreeBSD# adduser
Username: sftp
Full name:     
Uid (Leave empty for default): 
Login group [sftp]: 
Login group is sftp. Invite sftp into other groups? []: 
Login class [default]: 
Shell (sh csh tcsh nologin) [sh]: nologin
Home directory [/home/sftp]: /usr/local/www
Home directory permissions (Leave empty for default): 
Use password-based authentication? [yes]: 
Use an empty password? (yes/no) [no]: 
Use a random password? (yes/no) [no]: 
Enter password: 
Enter password again: 
Lock out the account after creation? [no]: 
Username   : sftp
Password   : *****
Full Name  : 
Uid        : 1002
Class      : 
Groups     : sftp 
Home       : /usr/local/www
Home Mode  : 
Shell      : /usr/sbin/nologin
Locked     : no
OK? (yes/no): y
adduser: INFO: Successfully added (sftp) to the user database.
Add another user? (yes/no): y
Username: web
Full name: 
Uid [1003]: 
Login group [web]: 
Login group is web. Invite webb into other groups? []: 
Login class [default]: 
Shell (sh csh tcsh nologin) [sh]: csh
Home directory [/usr/local/web]: /home/web
Home directory permissions (Leave empty for default): 
Use password-based authentication? [yes]: 
Use an empty password? (yes/no) [no]: 
Use a random password? (yes/no) [no]: 
Enter password: 
Enter password again: 
Lock out the account after creation? [no]: 
Username   : web
Password   : *****
Full Name  : 
Uid        : 1003
Class      : 
Groups     : web 
Home       : /home/web
Home Mode  : 
Shell      : /bin/csh
Locked     : no
OK? (yes/no): y
adduser: INFO: Successfully added (web) to the user database.
Add another user? (yes/no): n
Goodbye!
Теперь нужно создать chroot окружение для пользователя web, для этого я написал скрипт add_ssh_chrootuser.sh:
#!/bin/sh

# Проверка задано ли имя пользователя
if [ "$1" = "" ] ; then
 echo "  Usage: $0 [ username ]"
 exit 1
fi

USER=$1
GID=$(id -g $USER)
HOMEDIR=/home/$USER

# Задаем список каталогов в chroot окружении.
SKEL="/bin
    /sbin
    /etc
    /home
    /home/$USER
    /lib
    /libexec
    /tmp
    /usr
    /usr/bin
    /usr/local
    /usr/share
    /usr/local/bin
    /usr/local/etc
    /usr/local/share
    /usr/local/libexec"

# Создаем структуру каталогов внутри chroot окружения
for i in $SKEL; do
 [ ! -d $HOMEDIR$i ] && mkdir $HOMEDIR$i
done

# Определяем какие библиотеки необходимо скопировать
for item in sh csh zcat cat tbl groff chmod cp echo \
    ln ls date expr mkdir mv pwd locale \
    rm rmdir awk bzip2 diff du \
    ee fetch find grep gunzip gzip \
    more less sed sort tail head \
    tar touch vi ee mc mcedit \
    mysql mysqldump clear tput reset man zcat troff grotty; do
 p=$(whereis -q $item | cut -d' ' -f1)
 if [ -n "$p" ]; then
  # Копируем бинарники внутрь chroot окружения
  cp $p $HOMEDIR$p
  ldd $p | awk '{print $3}' | grep '.' >>/tmp/chroot_liblist
  #ldd $CMD_LIST|grep -v ':$'|grep -v "not a dynamic executable"|cut -f 3 -d " "|sort|uniq|sed 1d
 else
  echo "$item is NOT found, skip!"
 fi
done

# Копируем библиотеки
for item in $(cat /tmp/chroot_liblist | sort | uniq); do
 cp $item $HOMEDIR/lib/
done
# Подчищаем за собой
[ -f /tmp/chroot_liblist ] && rm /tmp/chroot_liblist

# Копируем оставшиеся необходимые файлы и библиотеки
for i in /etc/termcap \
    /etc/resolv.conf \
    /etc/nsswitch.conf \
    /libexec/ld-elf.so.1 \
    /libexec/ld-elf32.so.1; do
 cp $i $HOMEDIR$i
done

# если копировали mc, то копируем все необходимые для mc файлы.
for i in /usr/local/share/mc \
    /usr/local/libexec/mc \
    /usr/local/etc/mc \
    /usr/local/man \
    /usr/share/man \
    /usr/share/groff_font \
    /usr/share/tmac; do
 cp -R $i $HOMEDIR$i
done

# Если копировали mysql клиента, то настроим дефолтные опции.
echo '
[client]
port=3306
host=192.168.120.2' >$HOMEDIR/usr/local/etc/my.cnf

# Генерируем /etc/motd для chroot окружения
echo 'Welcome to chroot environment' > $HOMEDIR/etc/motd

# Генерируем csh.cshrc для chroot окружения
echo 'setenv TERMCAP /etc/termcap' > $HOMEDIR/etc/csh.cshrc
cp /.cshrc $HOMEDIR/home/$USER/

#т.к. man требует зачем-то наличие /sbin/sysctl, то создаем заглушку - пустой файл с правами запуска.
[ ! -d $HOMEDIR/sbin/ ] && mkdir $HOMEDIR/sbin
[ ! -x $HOMEDIR/sbin/sysctl ] && chmod +x $HOMEDIR/sbin/sysctl

# Генерируем /etc/group для chroot окружения
grep $GID /etc/group > $HOMEDIR/etc/group

# Переносим запись о пользователе
grep "^$USER:" /etc/master.passwd > $HOMEDIR/etc/master.passwd
pwd_mkdb -d $HOMEDIR/etc $HOMEDIR/etc/master.passwd

# Выставляем права
chown root:wheel $HOMEDIR
chmod 755 $HOMEDIR
chmod 777 $HOMEDIR/tmp

for i in $SKEL; do
 chown -R $USER:$GID $HOMEDIR$i
done
Затем запускаем скрипт, указывая пользователя web:
FreeBSD# sh add_ssh_chrootuser.sh web
В каталоге /home/web будет создана структура каталогов системы и будут скопированы программы и все необходимые для их запуска библиотеки. В скрипте я копирую минимальный набор, которого хватает для чтения логов nginx, работы с mysql и некоторые другие программки - например mc. Перезапускаем демона sshd:
FreeBSD# service sshd restart
Stopping sshd.
Starting sshd.
Все готово! Можно подключаться под созданными учетными записями.
Пользователь web при подключении по ssh, попадет в chroot окружение, которое было создано скриптом, а пользователь sftp не сможет входить по ssh, но сможет сводобно работать по sftp протоколу, и самое главное, для него будет коневым каталогом /usr/local/www, за его пределы он не сможет выйти.

P.S. Важно, чтобы права на chroot директории были chmod 755 и владелец root:wheel, в противном случае пользователи не смогут войти.
Ссылки по теме:
1. lissyara.su - "Использование sftp+chroot из openssh в качестве альтернативы ftp-серверу."
2. WOLAND's blog - "BASH. Создание chroot окружения для SSH chroot в FreeBSD."
3. Forums.freebsd.org - [Solved] sftp/scp chroot solution?
4. Hilink - "chroot ssh доступ. Настройка."
5. Под защитой песочного демона (Евгений Зобнин) - Хакер, номер #093, стр. 093-118-4
6. opennet.ru - "ssh chroot"

пятница, 8 марта 2013 г.

Работа с текстом во FreeBSD dos2unix, unix2dos, удаление BOM в консоли.

Замена текста: Способ 1: Замена подстроки с помощью ПЕРЛ
perl -e 's/Pavel/Misha/g' -pi ./index.html
Способ 2: Замена с помощью sed
sed -e 's/Pavel/Misha/g'  ./index.html > index_new.html
Способ 3: Замена с помощью awk
awk '{gsub("Pavel","Misha",$0); print > FILENAME}' ./index.html
Полезные функции для работы с файлами:
dos2unix() {
 sed -i '' -e 's/'"$(printf '\015')"'$//g' "$2"
}

unix2dos() {
 sed -i '' -e 's|$|'"$(printf '\015')"'|g' "$2"
}

delete_BOM() {
# awk '{sub(/^\xEF\xBB\xBF/,"",$0); print > FILENAME}' "$1"
 awk '{sub(/^\xEF\xBB\xBF/,"",$0); print}' "$1" >> "${1}.awkbak"
 mv "${1}.awkbak" "$1"
}

#По 1 файлу
dos2unix -o russian.php
delete_BOM russian.php

# Найти и обработать все *.tpl и *.php файлы от текущего каталога.
for i in $(find . -type f \( -name '*.tpl' -o -name '*.php' \) -print); do
 echo 'Working: '$i'...'
 dos2unix -o $i
 delete_BOM $i
done
dos2unix -o для обратной совместимости с одноименной консольной утилитой /usr/ports/converters/unix2dos, но зачем засорять систему лишними пакетами, если можно обойтись встроенными средствами?

P.S. Если кто-то подскажет более изящное решение на awk, sed или еще чем-то, что идет штатно во FreeBSD для удаления BOM, буду только рад :) Варианты с perl не предлагать, они очевидны и не интересны :)
Первый вариант с awk почему-то не работает, часть файла теряется.
FreeBSD Подсказывает в motd вариант на sed:
sed -e '1s/^\xef\xbb\xbf//' < bomfile > newfile

среда, 30 января 2013 г.

Ubuntu Unity Midnight Commander и F10

Для возвращения нормальной работы в терминале кнопки F10 нужно выполнить команды в терминале:
Ubuntu$ gconftool --set --type bool "/apps/gnome-terminal/global/use_menu_accelerators" "false"
Ubuntu$ gconftool --set --type string "/apps/compiz-1/plugins/unityshell/screen0/options/panel_first_menu" Disabled
А для Ubuntu 12.04 понадобится создать файл gtk.css в папке .config/.gtk-3.0 в домашнем каталоге:
Ubuntu~$ mkdir -p .config/gtk-3.0
Ubuntu~$ cat >>.config/gtk-3.0/gtk.css<<_EOF
@binding-set NoKeyboardNavigation {
unbind "F10"
}

* {
gtk-key-bindings: NoKeyboardNavigation
}
_EOF
Затем нужно завершить сеанс и войти заново - теперь клавиша F10 работает так, как и хотелось.
P.S. если ничего не получилось, то на крайний случай можно пользоваться комбинацией клавиш ESC+0, кстати эти комбинации работают и для других F кнопок.

Ubuntu Gnome-Terminal - включение beep enable system-beep, audible ping, bell, подавать гудок.

Первым делом необходимо установить утилиту beep:
Ubuntu~$ sudo apt-get install beep
Затем нужно разрешить загрузку модуля pcspkr:
Ubuntu~$ sudo sed -i'' -e 's/blacklist pcspkr/#blacklist pcspkr/' /etc/modprobe.d/blacklist.conf
Либо, если Beep поддерживает звуковая карта ноутбука, попробовать активировать эту функцию:
Ubuntu~$ cat >>/etc/modprobe.d/alsa-base.conf<<_EOF

#Enable Beep
#https://bugs.launchpad.net/ubuntu/+source/beep/+bug/144022
options snd-hda-intel power_save=10 power_save_controller=Y index=0 beep_mode=1
_EOF
Для включения сигналов в gnome-terminal нужно включить в metacity параметр audible_bell и в самом gnome-terminal проверить наличие галочки "Подавать гудок".
Я сделал это через консоль:
Ubuntu~$ gconftool-2 --set --type bool "/apps/gnome-terminal/profiles/Default/silent_bell" "false"
Ubuntu~$ gconftool-2 --set --type string "/apps/metacity/general/audible_bell" "on"
Ubuntu~$ gsettings set org.gnome.desktop.wm.preferences audible-bell 'true'
Ubuntu~$ gconftool-2 --set --type string "/desktop/gnome/peripherals/keyboard/bell_mode" "on"
Ubuntu~$ gsettings set org.gnome.settings-daemon.peripherals.keyboard bell-mode 'on'
Проверяем:
Ubuntu~$ echo -e "\a"
Ubuntu~$ echo -e '\a'
Ubuntu~$ ping -a ya.ru
У меня после этих манипуляций был слышен звук, как и в системной консоли.
Регулировать громкость сигнала можно через alsamixer в консоли - параметр Beep, у меня он почему-то был почти около нуля и я добавил громкости.
Но радоваться рано, после перезагрузки гудок пропал. Выяснилось, что если отключить гудок и включить его снова, то все работает, но до следующей перезагрузки :(
Ubuntu~$ gsettings set org.gnome.desktop.wm.preferences audible-bell 'false'
Ubuntu~$ gsettings set org.gnome.desktop.wm.preferences audible-bell 'true'
Ubuntu~$ echo -e '\a'
Немного подумав, сделал такой костыль:
Ubuntu~$ cat >>~/.bashrc<<_EOF
if [ -n $DISPLAY ]; then
    gsettings set org.gnome.desktop.wm.preferences audible-bell 'false'
    gsettings set org.gnome.desktop.wm.preferences audible-bell 'true'
fi
_EOF
Буду крайне признателен, если кто-то подскажет более изящное решение.

P.S. Может кому пригодится, приведу еще дополнительные опции из gconftool и gsettings:
Ubuntu~$ gsettings list-recursively | grep bell
org.gnome.desktop.wm.preferences audible-bell true
org.gnome.desktop.wm.preferences visual-bell false
org.gnome.desktop.wm.preferences visual-bell-type 'fullscreen-flash'
org.gnome.settings-daemon.peripherals.keyboard bell-custom-file ''
org.gnome.settings-daemon.peripherals.keyboard bell-duration 100
org.gnome.settings-daemon.peripherals.keyboard bell-mode 'on'
org.gnome.settings-daemon.peripherals.keyboard bell-pitch 400

Ubuntu~$ gconftool -R /desktop | grep -B4 bell
  /desktop/gnome/peripherals:
   /desktop/gnome/peripherals/keyboard:
    repeat = true
    delay = 500
    bell_mode = off
    bell_custom_file = (значение не установлено)
    remember_numlock_state = true
    click_volume = 0
    click = true
    bell_pitch = 400
    bell_duration = 100

Ubuntu~$ gconftool -R /apps | grep -B20 bell

Ссылки по теме:
1. Comment 50 for bug 486154
2. Trying to ENABLE bell in gnome-terminal
3. Comment 18 for bug 144022