пятница, 22 сентября 2017 г.

C++: Причуды препроцессора

Кажется, мне удалось найти отличный вопрос для собеседований IT-специалистов :) Значительно лучший, чем про крышки канализационных колодцев. :)

Так вот. Есть один вопрос, который с высокой вероятностью опрокинет навзничь любого сишника или крестоёба :)

Вопрос такой. :)

Будет ли работать в препроцессоре условие с двойным отрицанием и условием OR? Вот такое:

 #if !defined AAAA || !defined BBBB  
 #error We're here!  
 #endif
   

если не определены ни AAAA ни BBBB ? Иначе говоря, зажжется ли error при таких условиях?

Чур, к компилятору не подходить! (не давайте им компилятор на собеседовании!)

Пока вы думаете, посмотрите на условие, которое точно работает (взято из реального кода):

 #if defined __x86_64__ || defined __i386__  
 #include <cstdio>     /* For std::sprintf */  
 #endif  
   

Это работает. :) Более того, оно работает и с условием || и с условием &&. В зависимости от требуемой вам логики, разумеется.

А сейчас - внимание, правильный ответ по предыдущему вопросу. Ответ - нет, истинная ветвь не сработает ни при каких обстоятельствах.

Не спешите гуглить и ссылаться на единственный неправильный ответ по данному примеру на StackOverflow. :) Ответа на этот вопрос в руководствах нет, а на SO, как я и сказал, он неправильный. Не работает.

Правильный ответ на вопрос таков. Чтобы работало, должно быть вот так:

 #if !defined AAAA && !defined BBBB  
 #error We're here!  
 #endif  
   
   

Что означает, что в препроцессоре условие "NOT defined A || NOT defined B" невозможно. Причем необходимая логика достигается как раз-таки условием &&.

Это абсолютно неочевидно, более того, это еще и не документировано. Во всяком случае, для GCC. И не надо кивать на сам язык, в котором if ведет себя нормальным образом - то есть как напишешь, так и будет. Мы говорим о препроцессоре.

А теперь возьмите компилятор и проверьте то, что я сказал. :)

PS. Отличный вопрос, чтобы завалить любого сеньора, проходящего собеседование. 99,9% программистов ответят на вопрос неправильно. Даже если будут гуглить и ползать по SO. :)

четверг, 24 августа 2017 г.

Oracle Clusterware active/passive failover скрипт: усовершенствования

Конфигурация Clusterware active/passive достаточно распространена, несмотря на то, что является костылем (в отличие от полного RAC).

По интернету гуляет перепечатка первоначального варианта скрипта (single_instance_action_script.sh).  Какой-то рукосуй написал как попало на своем Линуксе и теперь этот вариант выдается всеми без исключения индусами - "знатоками Оракла" - за универсальный:

 #!/bin/sh  
   
 export ORA_CRS_HOME=$_CRS_ORA_CRS_HOME  
 export ORACLE_HOME=$_CRS_ORACLE_HOME  
 export ORACLE_SID=$_CRS_ORACLE_SID  
 export SPFILE=$_CRS_SPFILE  
 export LD_LIBRARY_PATH=$ORACLE_HOME/lib:$LD_LIBRARY_PATH  
 NODE_NAME=$(${ORA_CRS_HOME}/bin/olsnodes -l)  
 VIP_IP=$(${ORA_CRS_HOME}/bin/srvctl config vip -n $NODE_NAME | grep IPv4| awk '{print $4}')  
 check_dbstatus() {  
 OUTPUT=`$ORACLE_HOME/bin/sqlplus -s /nolog<<EOF  
 connect / as sysdba  
 set echo off define off heading off pagesize 0  
 SET LINESIZE 100  
 COLUMN l_output FORMAT A100  
 SELECT i.status || ' ' || pa.value || '/' || 'ora_' || p.spid || '.aud' AS  
 l_output  
 FROM v\\$session s,  
 v\\$process p,  
 v\\$parameter pa,  
 v\\$instance i  
 WHERE pa.name = 'audit_file_dest'  
 AND s.paddr = p.addr  
 AND s.sid = (select sid from v\\$mystat where rownum=1) and s.audsid =  
 sys_context('userenv','sessionid');  
 exit  
 EOF`  
   
 DBSTATUS=$(echo $OUTPUT | awk '{print $1}')  
 AUDITFILE=$(echo $OUTPUT | awk '{print $2}')  
 rm -f $AUDITFILE 2>/dev/null  
   
  if [ "$DBSTATUS" == "OPEN" ]  
  then  
   return 0  
  else  
   return 1  
  fi  
 }  
   
 case $1 in  
   
 'start')  
 echo "spfile='${SPFILE}'" > /tmp/init${ORACLE_SID}.ora  
 $ORACLE_HOME/bin/sqlplus /nolog <<EOF  
 connect / as sysdba  
 startup pfile=/tmp/init${ORACLE_SID}.ora  
 alter system set local_listener='(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=${VIP_IP})(PORT=1521))))' scope=memory;  
 alter system set remote_listener='s2-scan:1521' scope=memory;  
 EOF  
 check_dbstatus  
 RET=$?  
 ;;  
   
 'stop')  
 $ORACLE_HOME/bin/sqlplus /nolog <<EOF  
 connect / as sysdba  
 shutdown immediate  
 EOF  
 NUM=`ps -ef | grep -i smon_${ORACLE_SID} | grep -v grep | wc -l`  
 if [ $NUM = 0 ]; then  
  RET=0  
 else  
  RET=1  
 fi  
 ;;  
   
 'clean')  
 $ORACLE_HOME/bin/sqlplus /nolog <<EOF  
 connect / as sysdba  
 shutdown abort  
 EOF  
 ##for i in `ps -ef | grep -i mon_${ORACLE_SID} | awk '{print $2}' ` ;do kill -9 $i; done  
 NUM=`ps -ef | grep -i smon_${ORACLE_SID} | grep -v grep | wc -l`  
 if [ $NUM = 0 ]; then  
  RET=0  
 else  
  RET=1  
 fi  
   
 ;;  
   
 'check')  
 check_dbstatus  
 RET=$?  
 ;;  
   
 '*')  
 RET=0  
 ;;  
 esac  
   
 if [ $RET -eq 0 ]; then  
  exit 0  
 else  
  exit 1  
 fi  
   

При этом скрипт является мало того, что предельно примитивным, он еще и полон башизмов (несмотря на то, что начинается с #!/bin/sh, что подразумевает Борн на большинстве *NIX систем). Ну да, вы можете написать его на перле/питоне/чем угодно сами. Но не будете, верно? Нынешние IT-специалисты не пишут скриптов, и тем не менее катят за "гуру".

Три вещи, которые представляются неправильными в данном скрипте:
  1. Он должен быть переписан под Борн. То, что работает в борне - работает везде.
  2. Скрипт должен поддерживать standby - базы. Кластерный failover - не полноценная защита.
  3. Скрипт должен поддерживать Active Data Guard. Когда standby-база открыта в read only (благодарность Vladislav Frants за наводку).
Не говорю, что предлагаемый вариант идеален. Однако он соответствует всем трем пунктам. Прошу взглянуть:

 #!/bin/sh  
 # Modified to support CW standby's by Yuri Voinov (c) 2017  
 # Version 2.0  
 #  
 # 22.08.2017 - Added ADG support  
 # 16.08.2017 - Initial version  
   
 # Variables  
 ORA_CRS_HOME=$_CRS_ORA_CRS_HOME  
 export ORA_CRS_HOME  
 ORACLE_HOME=$_CRS_ORACLE_HOME  
 export ORACLE_HOME  
 ORACLE_SID=$_CRS_ORACLE_SID  
 export ORACLE_SID  
 SPFILE=$_CRS_SPFILE  
 export SPFILE  
 LD_LIBRARY_PATH=$ORACLE_HOME/lib:$LD_LIBRARY_PATH  
 export LD_LIBRARY_PATH  
 # Workaround for Solaris 10 branded zones on SuperCluster  
 if [ "`uname -s`" = "SunOS" -a "`uname -r`" = "5.10" ]; then  
  LD_LIBRARY_PATH_64=""  
  export LD_LIBRARY_PATH_64  
 fi  
 NODE_NAME="`${ORA_CRS_HOME}/bin/olsnodes -l`"  
 VIP_IP="`${ORA_CRS_HOME}/bin/srvctl config vip -n $NODE_NAME | grep IPv4| awk '{print $4}'`"  
   
 # Subroutines  
 check_dbstatus() {  
 OUTPUT="`$ORACLE_HOME/bin/sqlplus -s /nolog<<EOF  
 connect / as sysdba  
 set echo off define off heading off pagesize 0  
 SET LINESIZE 100  
 COLUMN l_output FORMAT A100  
 SELECT i.status || ' ' || pa.value || '/' || 'ora_' || p.spid || '.aud' AS  
 l_output  
 FROM v\\$session s,  
 v\\$process p,  
 v\\$parameter pa,  
 v\\$instance i  
 WHERE pa.name = 'audit_file_dest'  
 AND s.paddr = p.addr  
 AND s.sid = (select sid from v\\$mystat where rownum=1) and s.audsid =  
 sys_context('userenv','sessionid');  
 exit  
 EOF`"  
   
 # Check DB role  
 OUTPUT2="`$ORACLE_HOME/bin/sqlplus -s /nolog<<EOF  
 connect / as sysdba  
 set echo off define off heading off pagesize 0  
 set linesize 100  
 select database_role from v\\$database;  
 exit  
 EOF`"  
   
 DBSTATUS="`echo $OUTPUT | awk '{print $1}'`"  
 DBSTATUS2="`echo $OUTPUT2 | awk '{print $1 $2}'`"  
 AUDITFILE="`echo $OUTPUT | awk '{print $2}'`"  
 rm -f $AUDITFILE 2>/dev/null  
   
 # ADG support: PHYSICAL STANDBY can be opened as READ ONLY.  
 if [ "$DBSTATUS2" = "PHYSICALSTANDBY" -a \( "$DBSTATUS" = "MOUNTED" -o "$DBSTATUS" = "OPEN" \) ]; then  
  exit 0  
 elif [ "$DBSTATUS2" = "PRIMARY" -a "$DBSTATUS" = "OPEN" ]; then  
  exit 0  
 else  
  exit 1  
 fi  
 }  
   
 case "$1" in  
   
 "start")  
 echo "spfile=$SPFILE" > /tmp/init$ORACLE_SID.ora  
 $ORACLE_HOME/bin/sqlplus -s /nolog<<EOF  
 connect / as sysdba  
 startup mount pfile=/tmp/init${ORACLE_SID}.ora  
 alter system set local_listener='(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=${VIP_IP})(PORT=1521))))' scope=memory;  
 alter system set remote_listener='s2-scan:1521' scope=memory;  
 exit  
 EOF  
 OUTPUT3="`$ORACLE_HOME/bin/sqlplus -s /nolog<<EOF  
 connect / as sysdba  
 set echo off define off heading off pagesize 0  
 set linesize 100  
 select database_role from v\\$database;  
 exit  
 EOF`"  
   
 DBSTATUS3="`echo $OUTPUT3 | awk '{print $1}'`"  
   
 if [ "$DBSTATUS3" = "PRIMARY" ]; then  
 $ORACLE_HOME/bin/sqlplus -s /nolog<<EOF  
 connect / as sysdba  
 alter database open;  
 exit  
 EOF  
 fi  
 check_dbstatus  
 ;;  
   
 "stop")  
 $ORACLE_HOME/bin/sqlplus -s /nolog <<EOF  
 connect / as sysdba  
 shutdown immediate  
 exit  
 EOF  
   
 if [ -n "`ps -ef | grep -i smon_${ORACLE_SID} | grep -v grep | wc -l`" ]; then  
  exit 0  
 else  
  exit 1  
 fi  
 ;;  
   
 "clean")  
 $ORACLE_HOME/bin/sqlplus -s /nolog<<EOF  
 connect / as sysdba  
 shutdown abort  
 exit  
 EOF  
   
 if [ -n "`ps -ef | grep -i smon_${ORACLE_SID} | grep -v grep | wc -l`" ]; then  
  exit 0  
 else  
  exit 1  
 fi  
 ;;  
   
 "check")  
 check_dbstatus  
 ;;  
   
 *)  
 exit 0  
   
 esac  
   

Это Борн, насколько мне вообще удалось его сделать Борн-совместимым, поддерживается Standby, поддерживается ADG. Кроме того, включен один workaround (для issue. у которой нет удовлетворительного объяснения и, тем более, документированного решения на MOS).

По данному workaround я просто покажу итоговые данные и логи:

 root @ s1-host1 /ora/grid # /ora/grid.12.1.0.2/bin/crsctl start res namedb.db  
 CRS-2672: Attempting to start 'namedb.db' on 's1-host1'  
 CRS-2674: Start of 'namedb.db' on 's1-host1' failed  
 CRS-2679: Attempting to clean 'namedb.db' on 's1-host1'  
 CRS-2681: Clean of 'namedb.db' on 's1-host1' succeeded  
 CRS-2563: Attempt to start resource 'namedb.db' on 's1-host1' has failed. Will re-retry on 's1-host12' now.  
 CRS-2672: Attempting to start 'namedb.db' on 's1-host12'  
 CRS-2674: Start of 'namedb.db' on 's1-host12' failed  
 CRS-2679: Attempting to clean 'namedb.db' on 's1-host12'  
 CRS-2681: Clean of 'namedb.db' on 's1-host12' succeeded  
 CRS-2632: There are no more servers to try to place resource 'namedb.db' on that would satisfy its placement policy  
 CRS-4000: Command Start failed, or completed with errors.  
 root @ s1-host1 /ora/grid # /ora/grid.12.1.0.2/bin/crsctl status resource namedb.db  
 NAME=namedb.db  
 TYPE=single_instance_db  
 TARGET=ONLINE  
 STATE=OFFLINE  
   
 root @ s1-host1 /ora/grid # /ora/grid.12.1.0.2/bin/crsctl stop res namedb.db  
 root @ s1-host1 /ora/grid # /ora/grid.12.1.0.2/bin/crsctl status resource namedb.db  
 NAME=namedb.db  
 TYPE=single_instance_db  
 TARGET=OFFLINE  
 STATE=OFFLINE  
   
   
 root @ s1-host1 / # cat /tmp/script.log  
 ORA_CRS_HOME=/ora/grid.12.1.0.2  
 + export ORA_CRS_HOME   
 ORACLE_HOME=/ora/oracle/10.2.0.4.11  
 + export ORACLE_HOME   
 ORACLE_SID=namedb  
 + export ORACLE_SID   
 SPFILE=/s1_namedb_data/namedb/spfilenamedb.ora  
 + export SPFILE   
 LD_LIBRARY_PATH=/ora/oracle/10.2.0.4.11/lib:/ora/grid.12.1.0.2/lib:/opt/ORCLcluster/lib:/usr/lib:/usr/ucblib:/ora/grid.12.1.0.2/lib:/opt/ORCLcluster/lib:/usr/lib:/usr/ucblib:/ora/grid.12.1.0.2/lib:/opt/ORCLcluster/lib:/usr/lib:/usr/ucblib:/ora/grid.12.1.0.2/lib:/opt/ORCLcluster/lib:/usr/lib:/usr/ucblib:/ora/grid.12.1.0.2/lib:/opt/ORCLcluster/lib:/usr/lib:/usr/ucblib:  
 + export LD_LIBRARY_PATH   
 + /ora/grid.12.1.0.2/bin/olsnodes -l   
 NODE_NAME=s1-host1  
 + /ora/grid.12.1.0.2/bin/srvctl config vip -n s1-host1   
 + awk {print $4}   
 + grep IPv4   
 VIP_IP=192.168.180.91  
 + check_dbstatus   
 + /ora/oracle/10.2.0.4.11/bin/sqlplus -s /nolog   
 connect / as sysdba  
 set echo off define off heading off pagesize 0  
 SET LINESIZE 100  
 COLUMN l_output FORMAT A100  
 SELECT i.status || ' ' || pa.value || '/' || 'ora_' || p.spid || '.aud' AS  
 l_output  
 FROM v$session s,  
 v$process p,  
 v$parameter pa,  
 v$instance i  
 WHERE pa.name = 'audit_file_dest'  
 AND s.paddr = p.addr  
 AND s.sid = (select sid from v$mystat where rownum=1) and s.audsid =  
 sys_context('userenv','sessionid');  
 exit  
 ld.so.1: sqlplus: fatal: relocation error: file /ora/oracle/10.2.0.4.11/lib/libnnz10.so: symbol nzdacvalue: referenced symbol not found  
 OUTPUT=  
 + /ora/oracle/10.2.0.4.11/bin/sqlplus -s /nolog   
 connect / as sysdba  
 set echo off define off heading off pagesize 0  
 set linesize 100  
 select database_role from v$database;  
 exit  
 ld.so.1: sqlplus: fatal: relocation error: file /ora/oracle/10.2.0.4.11/lib/libnnz10.so: symbol nzdacvalue: referenced symbol not found  
 OUTPUT2=  
 + awk {print $1}   
 + echo   
 DBSTATUS=  
 + awk {print $1 $2}   
 + echo   
 DBSTATUS2=  
 + awk {print $2}   
 + echo   
 AUDITFILE=  
 + rm -f   
 + [ = PHYSICALSTANDBY -a = MOUNTED ]   
 + [ = PRIMARY -a = OPEN ]   
 + exit 1   
   
 #!/bin/sh  
 # Put at the beginning on script. Born/bash compatible  
 set -x  
 exec 2>/tmp/script.log  
   

Обратите внимание на последние строчки. Именно это решение позволило идентифицировать, локализовать и решить проблему. Это просто редирект всего выполнения скрипта, вместе с stdout/stderr в режиме отладки в лог. В данной ситуации увидеть, почему не выполняется, по-другому просто невозможно.

суббота, 22 июля 2017 г.

Solaris 11: Настройка DNS вручную

Я уже говорил, что Солярис 11 - это ад и Пакистан? Изначально отличная система общего назначения (имею в виду Солярис 10, разумеется) попала в шелудивые ручонки пидораиндусов-линукоидов и превратилась - та-дааааааааа! - в долбаный Линукс! Во всяком случае, на уровне юзерлэнда (убунтовская бета libtool в production(!) Solaris 11.3 - желающие могут убедиться самостоятельно) и некоторых ключевых аспектов администрирования.

Да, я считаю, что пидороразработчиков 11 надо линчевать. В балахонах, с факелами и вилами.

Нарушены как минимум два важнейших принципа - "Совместимость важнее производительности" и "Keep It Simple, Stupid".

Рассмотрим такую простую вещь, как настройка DNS-резолва после установки системы. Ну или вам его надо изменить. Быстро.

Как мы это делали в десятке? Всегда правой:
 # cp /etc/nsswitch.dns /etc/nsswitch.conf  
 # vi /etc/resolv.conf  
 # svcadm restart dns/client  

Не просто - а очень просто, руки до сих пор помнят. Делается на полном автомате, без единой заминки.

Оба-на, в Солярис 11 это не канает! Вы больше не можете редактировать настройки resolver ручками, так как они - сюрприз, мать вашу! - задаются при старте сервисами SMF (точнее, свойствами ДВУХ сервисов) и редактировать текстовые конфиги без толку - они будут возвращены в исходное состояние при рестарте оных сервисов/системы!

Индусы, чтоб вы сдохли, суки! Это до какой степени можно было обдолбаться и насрать на UNIX-way и два основополагающих принципа!

Смотрим, как это делается ТЕПЕРЬ:

 svccfg -s dns/client  
 svc:/network/dns/client> listprop config  
 ...  
 svc:/network/dns/client> setprop config/nameserver = (127.0.0.1)  
 svc:/network/dns/client> setprop config/domain = localdomain  
 svc:/network/dns/client> listprop config  
 config application  
 config/value_authorization astring solaris.smf.value.name-service.dns.client  
 config/nameserver net_address 127.0.0.1  
 config/domain astring localdomain  
 svc:/network/dns/client> exit  
 # svcadm refresh dns/client;svcadm restart dns/client  
   
 svccfg -s name-service/switch  
 svc:/system/name-service/switch> setprop config/host = “files dns”  
 svc:/system/name-service/switch> setprop config/ipnode = astring: “files dns”  
 svc:/system/name-service/switch> exit  
 # svcadm refresh name-service/switch;svcadm restart name-service/switch  
   

ПидораДолбодятлы, вы совсем охуеохренели? Вместо трех простых команд последовательность действий, которую без стакана и не вспомнишь!

Я хочу сказать, что качество системы провалилось в немытую индусскую задницу. Такое, с позволения сказать, администрирование ни в какие ворота не лезет.

Я понимаю, что для этого были какие-то мудацкие соображения. Но все на свете администраторы Солярис прокляли пидороразработчиков Индии до 149 колена. Шлю персонально лучи поноса.

суббота, 1 июля 2017 г.

Telegram: обход блокировок в один клик?

Посмотрел я решение для мобильного Telegram, предложенное командой Telegram "для обхода блокировок в один клик", как было анонсировано Павлом.

Я понимаю, что времени было ровно настолько, чтобы сделать "на отъебись" просто приблуду с соксификацией, как в десктопной версии. Однако, Павел, это, пардон муа, несерьезно.

Первое. Заблокировать Телеграм не просто, а очень просто. Я вот здесь уже писал год назад, насколько это легко. Это не просто - это тривиально. 

Процедура бутстрап у Телеграма элементарная и выбивается на раз. Две сети в блок-лист + блокирование всего, лишь отдаленно напоминающего SOCKS. По NBAR или просто блокированием портов. Вуаля - большинство пользователей никогда не войдут.

Соксификация? Ха! Я просто зарублю порт 1080 на Микротике/DLink или любом другом барахле! Большинство обычных людей в жизни не догадается, что соксы бывают на другом порту, а если и услышат от знакомого сисадмина - палец о палец не ударят чтобы их найти.

Второе. Люди, обитающие в башнях из слоновой кости, как-то забывают, что с публичными SOCKS-прокси свыше 10 лет ведется масштабная непримиримая война всеми на свете. Списки автоматически мониторятся и сервера попадают в бан максимум через 15 минут после своего появления на свет. Всеми. Начиная с провайдеров - большинство это делает - и заканчивая любым мало-мальски опытным сисадмином. По очевидной причине. Это - рассадник.

Обычный смертный же, получив обновление 1.1.9, должен сперва ручками найти IP-адрес незаблокированного SOCKS-прокси, ручками его вставить в настройки Телеграма. И, скрестив пальцы, надеяться на лучшее. Желательно при этом понимать, что в топе гугла работающих SOCKS-прокси найти так же реально, как обнаружить алмаз "Шах" на Красной Площади в разгар народных гуляний. А также то, что пользователю неслабо бы иметь определенную экспертизу - от повышенной до очень повышенной - в IT.

Вы когда-нибудь пробовали (на смарте) найти незаблокированный SOCKS-прокси? Рекомендую. Да хотя бы на десктопе.

Я искренне удивлен тем, что человек из IT мог предложить такое в качестве решения для всех.

Из моего личного опыта. Крайне трудно заблокировать лишь Телеграм, оборудованный бриджированным (и обфусцированным!) Тором. Во всяком случае мне неизвестны DPI, способные за разумные средства побанить бриджированный (и обфусцированный!) Тор. Исключая, может быть, Golden Shit - и то я в этом сомневаюсь.

Однако.

Вы никогда не пробовали, даже не будучи хомячком, развернуть бриджированный Тор на смарте, который не рутован? Рекомендую. Великолепный квест.

На десктопе? Да, можно. Имея экспертизу. И ценой определенных, довольно приличных, телодвижений. Я описал в предыдущей статье. Но это никак не один, не два, и даже не двадцать кликов.

Павел, ты точно уверен, что обычный человек способен это проделать? И захочет это проделывать? Не имея экспертизы и не настолько любя котиков?

Я ожидал, что в новой версии будет как минимум встроен Тор - с блэкджеком бриджами и шлюхами обфускацией. И одной-единственной кнопочкой - "Послать цензора на.....".

Однако - не увидел. Все понимаю, Павел. Однако - я разочарован.

Начинайте писать новый мессенджер с нормальной процедурой бутстрапа и встроенной антицензурой. Старому уже никакой SOCKS не поможет. Джузеппе Гарибальди покажет "Окей" из могилы. Если удастся это провернуть.

суббота, 24 июня 2017 г.

Использование Tor Expert Bundle на localhost

Использование Tor Expert Bundle не совсем тривиально, ввиду отсутствия внятной документации а также отсутствия в составе пакета некоторых необходимых компонентов.

Я хочу сразу оговориться, что речь идет о применении Tor не в оппозиционных и иных целях. Мне приходилось сталкиваться с ситуацией, когда в провайдерских сетях отсутствует внутрисетевой роутинг (по различным причинам), и в принципе необходимо попасть в соседнюю сеть (например, с целью администрирования собственных серверов), однако, ввиду повсеместного (и, зачастую, оправданного) резко отрицательного отношения к открытым прокси, это крайне затруднительно.

Дисклеймер. Да, данный инструмент может использоваться в различных целях, как и кухонный нож. Вы принимаете решение о его применении на свой страх и риск и на собственную ответственность.

Итак, исходные данные. 

У нас имеется станция под управлением Windows и нам нужен сервис Tor, с точкой входа в виде SOCKS proxy на локальной машине для торификации некоторых программ с доступом в Интернет. Причем, по-возможности, не зависящий от произвола провайдеров и государственных служб (я предупреждал, господа).

Для решения данной задачи нам понадобится Tor Expert Bundle, а также Pluggable Transports, не входящие в состав пакета.

Вам, в ряде случаев, придется озаботиться тем, как попасть на https://torproject.org и получить оттуда два важных компонента: собственно Tor Expert Bundle и Tor Browser (он нужен, поскольку в его состав входят Pluggable Transports).

Сперва необходимо установить Тор браузер. По умолчанию он ставится в Desktop:


Обычно я просто собираю эту директорию в архив и сохраняю вместе с Tor Expert Bundle.

Здесь обычно задают вопрос - "А на кой мне возиться с Expert Bundle, если у меня уже есть работащий торифицированны браузер?" На той, что не только браузер может нуждаться в торифицированном соединении. А, например, SSH-клиент. Мессенджеры. И так далее. Да и, зачастую, удобнее иметь постоянно работающий сервис, нежели зависеть от браузера, который надо держать запущенным.

Сам Tor Expert Bundle нужно распаковать в Program Files, например в "C:\Program Files (x86)\tor" и туда же распаковать Pluggable Transports:



Самое сложное в использовании Expert Bundle - это конфигурирование. Сначала нужно создать сервис, это просто:


Обратите внимание на замечание. Сервис выполняется из-под локального системного аккаунта. Что означает, что конфигурационные файлы и данные находятся здесь (обратите внимание, torrc отсутствует и сервис запущен с умолчаниями):

Это не то, что нам нужно, к тому же, нас не удовлетворяет запуск сервиса от системного аккаунта (это достаточно небезопасно, к тому же, значительно сложнее сделать правильную конфигурацию). Поэтому запустим управление компьютером и поменяем аккаунт сервиса на пользовательский:

Окей, теперь у нас рабочая директория находится у пользователя. Если по указанному пути ее нет, создадим ее:

Теперь в нее можно положить torrc, который надо написать. Взяв за основу torrc браузера, напишем свой конфигурационный файл:

 ####  
 # cd C:\Users\Yuri\AppData\Roaming  
 # mkdir tor  
 SocksPort 9050 IPv6Traffic PreferIPv6 KeepAliveIsolateSOCKSAuth  
   
 Bridge 198.147.22.36:443 58DB653508197599B8CB7EE95772F3EF2255939D  
 Bridge 194.132.209.138:22670 582E2CD0132AE1FD89426EC624B76B36690A622F  
 Bridge 194.132.209.116:20650 0D113A4B44E9B79C604DFC8DAE35C3C74CF60FF9  
   
 Bridge obfs4 194.132.209.138:48574 582E2CD0132AE1FD89426EC624B76B36690A622F cert=G1jt3rntMnoWTy8uEeQu9VPhnmPn7BH5cHwXbSkQDNlyrFD6BL7D8PMiPwPooKGudt1iYw iat-mode=0  
 Bridge obfs4 194.132.209.116:34596 0D113A4B44E9B79C604DFC8DAE35C3C74CF60FF9 cert=QfRegE3lzpqsnWUAQTulUPje7KgdcL2c+qOUtoU0Jw/ln8KpPZbh43XdfKr1kXYYLLcYQg iat-mode=0  
 Bridge obfs4 68.45.52.117:40365 3C89FB56CDEE23F0F16FDF86086866E33EAB24D8 cert=s0SmVQop+pZPZxlHunrXQL6MW4uVOZS55XjDVaBYkaSSoN9FEZOif/dxxrufg6ZnskRkSw iat-mode=0  
   
 Bridge obfs3 194.132.209.138:54673 582E2CD0132AE1FD89426EC624B76B36690A622F  
 Bridge obfs3 194.132.209.116:44364 0D113A4B44E9B79C604DFC8DAE35C3C74CF60FF9  
 Bridge obfs3 68.45.52.117:36125 3C89FB56CDEE23F0F16FDF86086866E33EAB24D8  
   
 GeoIPFile C:\Program Files (x86)\Tor\Data\Tor\geoip  
 GeoIPv6File C:\Program Files (x86)\Tor\Data\Tor\geoip6  
 HiddenServiceStatistics 0  
 UseBridges 1  
   
 ClientTransportPlugin obfs2,obfs3,obfs4,scramblesuit exec C:\Program Files (x86)\Tor\PluggableTransports\obfs4proxy  
   

Бриджи предварительно получим на https://bridges.torproject.org. Я обычно добавляю обычные бриджи для облегчения бутстрапа, но это может вызвать некоторые проблемы - обычные бриджи иногда банятся. Поэтому стоит добавить обфусцированные, запустив соответствующий транспортный плагин (внизу в конфигурации). Обратите внимание на полные пути (в кавычки не берем!). Чтобы не терять соединения в случае активного бана бриджей (а также ввиду того, что иногда они меняются или перестают работать) советую за несколько последующих дней собрать десяток-два бриджей в каждой группе. Обязательно укажите SOCKS-порт, как показано - он будет точкой входа, и, кстати, IPv6 будет полезен даже если в вашей стране IPv6 не применяется - изредка это облегчает бутстраппинг и последующую работу Тор. 

Если применению Тор активно противодействуют, откажитесь от использования необфусцированных бриджей.

Я не использую FTE, так как плагин достаточно капризный и в последней версии Tor Bundle не работает из-за ошибки (исправят - начну использовать снова). В принципе, OBFS3/4 вполне достаточно.

Убедитесь, что конфигурация работает, запустив Тор интерактивно (предварительно остановив сервис, разумеется) - что бутстраппинг проходит до конца и клиентское соединение устанавливается.

Убедившись, что все в порядке и Тор в состоянии соединиться с сетью, запустите сервис.

Обратите внимание вот на что. В Тор есть небольшой баг, касающийся остановки Pluggble Transport при остановке его самого. Ввиду этого может понадобиться руками убить выполнение obfs4proxy в диспетчере задач (и, в общем, это может понадобиться делать не раз при перезапусках):

Теперь, когда сервис работает, можно настроить, например, Телеграм на его использование:


Аналогично можно настроить, например, Mail.ru Agent (хотя я считаю глупостью небезопасный по определению мессенджер прятать в туннель), или SSH client:


Проверяем:

Порядок, соединяемся через Tor. Консоль даже не слишком тормозит.

Резюмируем. Вы имеете туннельный сервис с SOCKS5 на входе. Любой браузер, большинство мессенджеров - словом, все программы, могущие использовать SOCKS в соединениях - могут быть выпущены через туннель.

Пользуйтесь на здоровье. И не забывайте время от времени обновлять/пополнять бриджи в конфигурации, убирая умершие и накапливая рабочие. Опыт показывает, что, чем больше вы имеете бриджей в конфигурации - тем более бесперебойно работает сервис.