1 (изменено: dasknix, 2012-09-20 00:39:54)

Тема: CMD/BAT: DynDNS-сервер на связке .cmd & Netcat

решил сегодня накатать сервак динамического обновления ip для доменов клиентских узлов (в моем случае - GSM-роутеры),
интересует вот что, поскольку биться с темой, созданной ранее, я не стал и взялся за готовую слушалку (netcat, кто не слышал - советую,
исключительно локаничное и очень удобное решение для отладки всего, что связано с сеткой и tcp-портами в частности)

время шло своим чередом, я доедал третью тарелку с гречкой и даже начал забывать к ночи про сигареты, но вопрос вселенной,
смысла жизни и всего такого не давал мне покоя всё больше и больше: как сделать нормальную синхронизацию процесса обновления
инфы от нескольких клиентов одновременно, не просто WRITE_LOCK-ами (файлами), а адекватно, через какое-нибудь shared memory..
и самое главное - как делать спаун коннект и освобождать порт для новых клиентов сразу, как только подрубился последний, тоесть
чтобы работало как полноценный сервис, типо опача, эндажайнекс и вообще всего, что имеет established в протоколе!

так же надеюсь, что кому-нибудь данный кодес будет полезен! не работает в данной версии только тема с socket_count, т.к. пока в раздумьях,
стоит ли создавать пул слушалок на определённом port range, уж больно костыльно как-то, реал.. =\

любая критика принимается с радостью, как и предложения!

@echo off
REM ---------------
REM -- EXECUTION --
REM ---------------

REM common.config
set      irz.ddns.fork.fastwrite_mode=yes
set           irz.ddns.nc.listen.port=44044
set         irz.ddns.nc.listen.ipaddr=127.0.0.1
set   irz.ddns.nc.listen.socket_count=3
set              irz.ddns.nc.fullpath=..\..\nc.exe
set                    irz.ddns.debug=yes
set             irz.ddns.remote_debug=yes
set              irz.ddns.debug.level=1

REM common.config.predefined
set               irz.ddns.hosts_file=%systemroot%\system32\drivers\etc\hosts

REM common.preexec_wrappers
setlocal enabledelayedexpansion
if not "%1" == "" (
    if "%1" == "--fork" (
        call :fork %0 %2
    ) else if "%1" == "--listener" (
        call :listener %2 %3
    )

    goto :EOF
)

REM 0.0 main.start
echo [main]:STARTED
echo ----------------
if "%irz.ddns.debug%" == "2" echo [main].env: nc execall = '%irz.ddns.nc.execall%'

echo [main]:preparing
if not exist ".\cache" mkdir "cache"
if not exist ".\cache" (
    echo [main][cache]:[!] error, cannot create cache directory
    goto :EOF
    ) else echo [main][cache]:directory existing

if %irz.ddns.debug% GTR 2 (
    echo [main][info]:listener will bind on %irz.ddns.nc.listen.ipaddr%:%irz.ddns.nc.listen.port%
    if "%irz.ddns.fork.fastwrite_mode%" == "yes" echo [main][info]:fastwrite mode enabled
    if "%irz.ddns.fork.fastwrite_mode%" == "no" echo [main][info]:fastwrite mode disabled
)
echo ----------------

REM 0.1 creating cycled NC fork pool
set irz.ddns.forkpid=%random%
echo [main]:fork() #1 [PID=%irz.ddns.forkpid%]
start /b %0 --fork %irz.ddns.forkpid%

echo [main]:exit
exit

REM ---------------
REM -- FUNCTIONS --
REM ---------------

REM Threads
:fork
setlocal enabledelayedexpansion
echo ----------------
echo [fork.%2]:called

set irz.ddns.fork.%2.lpid=%random%
echo [fork.%2]:creating listener [LPID=!irz.ddns.fork.%2.lpid!]
rem %1 - executable .cmd, because of %0 == ':fork'; %2 - current PID

set irz.ddns.nc.execall=%irz.ddns.nc.fullpath%
set irz.ddns.nc.execall=%irz.ddns.nc.execall% -l -s %irz.ddns.nc.listen.ipaddr%
set irz.ddns.nc.execall=%irz.ddns.nc.execall% -p %irz.ddns.nc.listen.port%
set irz.ddns.nc.execall=%irz.ddns.nc.execall% -e "%1 --listener %2 !irz.ddns.fork.%2.lpid!"

rem Calling listening utility
%irz.ddns.nc.execall%

if %irz.ddns.debug.level% GTR 0 (
    echo [fork.%2].[listener.!irz.ddns.fork.%2.lpid!] exited. respawning..
    REM if %irz.ddns.debug.level% GTR 2 echo [fork.%2].[listener.!irz.ddns.fork.%2.lpid!] exited (return code = '%errorlevel%'). respawning..
)
goto :fork

echo [fork.%1]:EXIT
exit /b

REM Executable by NC
:listener
setlocal enabledelayedexpansion
rem [th.1.0: ]
if "%irz.ddns.remote_debug%" == "yes" (
    echo [fork.%1].[listener.%2]:called
    echo [fork.%1].[listener.%2]:asking client for DDNS INFO
)

set /p irz.ddns.fork.%1.imei=IMEI:
set /p nullvar1=
if "!irz.ddns.fork.%1.imei!" == "" (
    if "%irz.ddns.remote_debug%" == "yes" (
        echo [fork.%1].[listener.%2]:no IMEI/UNIT-NAME given. client rejected.
        echo [fork.%1].[listener.%2]:EXIT
        pause
    )
    exit /b
)

set /p irz.ddns.fork.%1.ip=IP:
set /p nullvar2=
if "!irz.ddns.fork.%1.ip!" == "" (
    if "%irz.ddns.remote_debug%" == "yes" (
        echo [fork.%1].[listener.%2]:no IP-address given. client rejected.
        echo [fork.%1].[listener.%2]:EXIT
        pause
    )
    exit /b
)

REM Debug info for remote host
if "%irz.ddns.remote_debug%" == "yes" (
    if "%irz.ddns.debug.level%" == "1" echo [fork.%1].[listener.%2]:recieved DDNS-INFO
    if "%irz.ddns.debug.level%" == "2" echo [fork.%1].[listener.%2]:recieved DDNS-INFO: [IMEI=!irz.ddns.fork.%1.imei!], [IP=!irz.ddns.fork.%1.ip!]
)

REM Fastwrite try (cache evasion, directly to HOSTS)
if "%irz.ddns.fork.fastwrite_mode%" == "yes" (
    if "%irz.ddns.remote_debug%" == "yes" echo [fork.%1].[listener.%2]:evasing cache ^(fastwrite^)
    call :update_fastwrite !irz.ddns.fork.%1.imei! !irz.ddns.fork.%1.ip! %1 %2
    if "%irz.ddns.remote_debug%" == "yes" echo [fork.%1].[listener.%2]:fastwrite return code: %errorlevel%
    if "%errorlevel%" == "0" exit /b 0 else exit /b -1
    REM arg #1 - IMEI/UNIT-NAME, arg #2 - IP-address
)

REM Creating cache
set irz.ddns.fork.%1.listener.%2.cache-id=id-!irz.ddns.fork.%1.imei!.pid-%1.lpid-%2
if "%irz.ddns.remote_debug%" == "yes" (
    if "%irz.ddns.debug.level%" == "1" echo [fork.%1].[listener.%2]:creating listener private cache
    if "%irz.ddns.debug.level%" == "2" echo [fork.%1].[listener.%2]:creating listener private cache [CACHE-ID=!irz.ddns.fork.%1.listener.%2.cache-id!]
)

REM Writing vars to cache
if "%irz.ddns.remote_debug%" == "yes" (
    if "%irz.ddns.debug.level%" == "1" echo [fork.%1].[listener.%2]:writing DDNS-INFO to cache
    if "%irz.ddns.debug.level%" == "2" echo [fork.%1].[listener.%2]:writing DDNS-INFO to cache [".\cache\cache_!irz.ddns.fork.%1.listener.%2.cache-id!"]
)
echo !irz.ddns.fork.%1.ip!> ".\cache\cache_!irz.ddns.fork.%1.listener.%2.cache-id!"

if "%irz.ddns.remote_debug%" == "yes" echo [fork.%1].[listener.%2]:sleeping
call :sleep 10 %1 %2

if "%irz.ddns.remote_debug%" == "yes" echo [fork.%1].[listener.%2]:EXIT
pause
exit /b

REM Update HOSTS, using given call arguments
REM arg #1 - IMEI/UNIT-NAME, arg #2 - IP-address
:update_fastwrite
setlocal enabledelayedexpansion
if "%irz.ddns.remote_debug%" == "yes" echo [fork.%3].[listener.%4].fastwrite:called
set irz.ddns.tmpvar.updated=0
set irz.ddns.tmpvar.cut_comment=0
set irz.ddns.tmpvar.first_line=1
for /f "tokens=* delims= " %%a in (%irz.ddns.hosts_file%) do (
    if "%irz.ddns.remote_debug%" == "yes" (
        if %irz.ddns.debug.level% GTR 1 echo incycle start: irz.ddns.tmpvar.updated = !irz.ddns.tmpvar.updated!
    )
    set line=%%a
    if "%irz.ddns.remote_debug%" == "yes" (
        if %irz.ddns.debug.level% GTR 1 echo     old line = !line!
    )
    for /f "tokens=1,2" %%b in ("!line!") do (
        set token1=%%b
        set token2=%%c
        if !token2! == %1 (
        rem echo host '%str-to-find%' found in string '!line!'
            set line=%2 !token2!
            set irz.ddns.tmpvar.updated=1
            if %irz.ddns.debug.level% GTR 0 echo [fork.%3].[listener.%4].fastwrite:entry for host '%1' updated
        ) else if "!token1!" == "#" (
            set irz.ddns.tmpvar.cut_comment=1
        ) else if "!token1!" == "" (
            set irz.ddns.tmpvar.cut_comment=1
        ) else (
            set irz.ddns.tmpvar.cut_comment=0
            set line=!token1! !token2!
        )
    )
    echo irz.ddns.tmpvar.cut_comment = !irz.ddns.tmpvar.cut_comment!
    if "%irz.ddns.remote_debug%" == "yes" (
        if %irz.ddns.debug.level% GTR 1 (
            if "!irz.ddns.tmpvar.cut_comment!" == "0" (
                echo updated line = !line!
                echo.
            ) else (
                echo this line will be removed, because it's a comment
                echo.
            )
        )
    )
    
    echo after word parsing cycle: irz.ddns.tmpvar.cut_comment = !irz.ddns.tmpvar.cut_comment!
    rem Storing old & updated content: no comments, no empty lines
    if not "!irz.ddns.tmpvar.cut_comment!" == "1" (
        if not "!irz.ddns.tmpvar.first_line!" == "1" (
            echo !line!>> ".\cache\updated_hosts"
        ) else (
            echo FIRSTLINE MOTHER FUCKER!!!!!!!!
            echo !line!> ".\cache\updated_hosts"
            set irz.ddns.tmpvar.first_line=0
        )
    )
    if "%irz.ddns.remote_debug%" == "yes" (
        if %irz.ddns.debug.level% GTR 1 echo incycle end: irz.ddns.tmpvar.updated = !irz.ddns.tmpvar.updated!
    )
)   
rem Creating new entry if needed
if "!irz.ddns.tmpvar.updated!"=="0" (
    if "%irz.ddns.remote_debug%" == "yes" (
        if %irz.ddns.debug.level% GTR 0 echo [fork.%3].[listener.%4].fastwrite:entry for host '%1' not found
        if %irz.ddns.debug.level% GTR 0 echo [fork.%3].[listener.%4].fastwrite:creating new entry..
    )
    echo %2 %1 >> ".\cache\updated_hosts"
)

if not exist ".\cache\WRITE_LOCK" (
    if "%irz.ddns.remote_debug%" == "yes" echo [fork.%3].[listener.%4].fastwrite:writelock not set. creating..
    echo.>".\cache\WRITE_LOCK"
    if not exist ".\cache\WRITE_LOCK" (
        if "%irz.ddns.remote_debug%" == "yes" echo [fork.%3].[listener.%4].fastwrite:ERROR! unable to set writelock
        if "%irz.ddns.remote_debug%" == "yes" echo [fork.%3].[listener.%4].fastwrite:EXIT
        if "%irz.ddns.remote_debug%" == "yes" pause
        exit /b -1
    ) else (
        if "%irz.ddns.remote_debug%" == "yes" echo [fork.%3].[listener.%4].fastwrite:writelock set
        copy %irz.ddns.hosts_file% ".\cache\backup_hosts" >nul
        if not exist ".\cache\backup_hosts" (
            if "%irz.ddns.remote_debug%" == "yes" echo [fork.%3].[listener.%4].fastwrite:ERROR! unable to backup HOSTS file
            if "%irz.ddns.remote_debug%" == "yes" echo [fork.%3].[listener.%4].fastwrite:EXIT
            if "%irz.ddns.remote_debug%" == "yes" pause
        )
        if "%irz.ddns.remote_debug%" == "yes" echo [fork.%3].[listener.%4].fastwrite:updating system HOSTS file..
        REM move /y ".\cache\updated_hosts" %irz.ddns.hosts_file% >nul
        del /f %irz.ddns.hosts_file% >nul
        copy /y ".\cache\updated_hosts" %irz.ddns.hosts_file% >nul

        REM Validation information in updated HOSTS file
        if "%irz.ddns.remote_debug%" == "yes" (
            if %irz.ddns.debug.level% GTR 1 (
                echo pause for updated HOSTS validation tracing.
                echo now edit address for '%1' in HOSTS file to wrong value not equal '%2'
                pause
            )
        )
        rem set errorlevel=0
        echo errorlevel=%errorlevel%
        echo findstr /i /p /x /c:"%1 %2" %irz.ddns.hosts_file%
        findstr /x /c:"%1 %2" %irz.ddns.hosts_file%
        echo errorlevel=%errorlevel%
        if "%irz.ddns.remote_debug%" == "yes" (
            if %irz.ddns.debug.level% GTR 1 (
                echo validation result: errorlevel=%errorlevel%
                pause
            )
        )
        if not "%errorlevel%" == "0" (
            if "%irz.ddns.remote_debug%" == "yes" echo [fork.%3].[listener.%4].fastwrite:ERROR! new HOSTS validation failed!
            if "%irz.ddns.remote_debug%" == "yes" echo [fork.%3].[listener.%4].fastwrite:EXIT
            if "%irz.ddns.remote_debug%" == "yes" pause
        ) else (
            if "%irz.ddns.remote_debug%" == "yes" echo [fork.%3].[listener.%4].fastwrite:new HOSTS file validation succeeded
        )
        
        REM Unset WRITE_LOCK
        if "%irz.ddns.remote_debug%" == "yes" echo [fork.%3].[listener.%4].fastwrite:removing writelock..
        del /f ".\cache\WRITE_LOCK"
        if not exist ".\cache\WRITE_LOCK" (
            if "%irz.ddns.remote_debug%" == "yes" echo [fork.%3].[listener.%4].fastwrite:writelock removed
            if "%irz.ddns.remote_debug%" == "yes" echo [fork.%3].[listener.%4].fastwrite:EXIT
            exit /b -10
        )
        if "%irz.ddns.remote_debug%" == "yes" echo [fork.%3].[listener.%4].fastwrite:ERROR! unable to remove writelock!
        if "%irz.ddns.remote_debug%" == "yes" echo [fork.%3].[listener.%4].fastwrite:EXIT
        if "%irz.ddns.remote_debug%" == "yes" pause
        exit /b -3
    )
) else exit /b -1
exit /b 0

REM Timer for WRITE_LOCK file monitoring task
:sleep
setlocal enabledelayedexpansion
echo [fork.%2].[listener.%3].sleep():called
echo [fork.%2].[listener.%3].sleep():sleeping for %1 seconds..
exit /b

REM Message indention
:nfof
echo ^%1^(^): %2
exit /b

:nfop
echo ^[%1^]: %2
exit /b

:nfo_1
REM Echo given string with indent
for /f in (%1) (
    echo        %%i
)
exit /b

:EOF
echo [main]:EXIT

2

Re: CMD/BAT: DynDNS-сервер на связке .cmd & Netcat

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

3 (изменено: dasknix, 2012-09-20 16:19:07)

Re: CMD/BAT: DynDNS-сервер на связке .cmd & Netcat

я русский. питерец. воспитан двуми интеллигентами. квалифицированный специалист. сейчас работаю тех. консультантом и разработчиком расширенного пакета документации к промышленному оборудованию, с ориентацией на ГОСТ. так вот.. всю жизнь бесили точки и большие буквы в начале предложения!!! не нравиться - три тему. люди в нете тоже люди и у каждого свои загоны и менталитет, ставя коммьюнити в такие жёсткие рамки вы только себя ограничиваете. я даже везде на девайсах, где только можно убираю автомат красной строки ибо сил нет. и между прочим: ни характер содержания, ни читабельность параграфа, по сути - не меняются! а про уважение и пр - это прежде всего просматривается в манере общения, как давно известно из реала, а не как кто точки ставит и лицемерно большие буковки в начале пихает, а потом понимаешь - что суть-то и не изменилась. особенно, если человек не уважал.. никакой синтаксис, пунктуация и прочие приблуды тут не помогут. корень в идее!.., который в отличии от воплощения, всегда индивидуален, блин, вы то разрабы должны знать!

зы предвзятость такая предвзятость..
зы2 и вообще одно дело доки заполнять и составлять эписталярно че-то а другое в нете долбить сутками по буквам, не до шифта, знаете-ли когда только успеваешь записывать.
зы3 ..офигенно обламывает, конечно, что это всё происходит на форуме, которому так давно был рад

4

Re: CMD/BAT: DynDNS-сервер на связке .cmd & Netcat

dasknix, §2.5, §2.6, §3.3. Тема закрыта.

Пообсуждать, почему некоторые не русские призывают некоторых русских писать грамотно, а те, мягко говоря, овощ хотели на это дело класть, а также и всё прочее с сим связанное, можете в этом разделе: Script-Coding.com community.