问题
I have the problem that some FTP servers are not defined by IP anymore. Instead DNS names are provieded, so they may switch servers behind easily, while leaving customers with the problem of handling, because no routers and firewalls can get defined with DNS names (thank god it is this way).
I had the idea to write a simple script to monitor defined DNS resolutions and change routes as needed by script.
See the resulting scripts underneth in my answers. Thnx to MC ND.
I am sure one could optimize my code at several further items :)
To test you will need to make a file C:\log\dnstests.txt
which contains for example two lines:
www.stackoverflow.com=7.7.7.7
www.heise.de=198.252.206.16
This are two nice examples because, first domain does provide an alias after the IP adress which I could filter by find
, but second does provide an ip6 additionally which should get filtered too.
If someone would show me how to read and write line by line to and from file
this could improve stability of script, as if the script breaks, the testfile will almost be empty. So if you change this excessive tested scriptcode be careful to test all possible cases D).
Any help would be really appreciated, while I could imagine a lot people could need this script out there and I wondered that nothing was to find?
回答1:
Just in case anyone might someday feel the need to set routes by a sheduled script, (including: dails still alive email, IP6 filtering and smart behaviour on loadbalanced IP's to keep old one as long as it is listed).
All you need is a file "dnstests.txt" in script directory with syntax:
first.domain.tld=1.2.3.4
your.second.tld=5.6.7.8
Here is the code (thanx to MC ND for smart NSlookup filter):
@ECHO OFF
SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
REM ++++++++++++++++++++++++++++ BLAT EMAIL CONFIG ++++++++++++++++++++++++++++++++++++
set eMailTO=someone@somedomain.somewhere
set eMailCC=someone@somedomain.somewhere
set eMailFROM=dnstestscript
set server=0.0.0.0
REM you have to install blat of course, here "echo blat ..." is used where it would be
REM useful to send an email on interesting items, but it is also sent to shell and log
REM +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
REM ++++++++++++++++++++++++++++ MAKE DATE ++++++++++++++++++++++++++++++++++++++++++++
for /F "usebackq tokens=1,2 delims==" %%i in (`wmic os get LocalDateTime /VALUE 2^>NUL`) do if '.%%i.'=='.LocalDateTime.' set ldt=%%j
REM make timestamp (date reverse)
set STAMP=%ldt:~0,4%-%ldt:~4,2%-%ldt:~6,2%--%ldt:~8,2%-%ldt:~10,2%--%ldt:~12,2%-%ldt:~15,3%
set ACTUALDATE=%ldt:~0,4%-%ldt:~4,2%-%ldt:~6,2%
REM +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
REM ++++++++++++++++++++++++++++ SCRIPT CONFIG ++++++++++++++++++++++++++++++++++++++++
set "XScriptnamE=%~n0"
set "XSCRIPTDIR=%~dp0"
set "LOGDIR=%XSCRIPTDIR%\%XScriptnamE%"
if not exist "%LOGDIR%" mkdir "%LOGDIR%"
set "LOG=%LOGDIR%\%XScriptnamE%.log"
REM +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
REM ++++++++++++++++++++++++++++ SCRIPT ALIVE ++++++++++++++++++++++++++++++++++++++++
REM now tell us once a day that script is up and running
set DateLOG=%XSCRIPTDIR%\%XScriptnamE%-date.txt
if not exist "%DateLOG%" echo %ACTUALDATE% > %DateLOG%
set /p BEFOREDATE=< %DateLOG%
if NOT %ACTUALDATE% == %BEFOREDATE% (
echo %ACTUALDATE% > %DateLOG%
echo blat %0 -subject "DNS Routes Script is alive and running! OK" -body "DNS-routing-script up and running - DNS routing is OK!" -to %eMailTO% -cc %eMailCC% -f %eMailFROM% %server%
)
REM +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
REM make errorlooging expand
set "XLOGX=xpipex && type xpipex && type xpipex >> %LOG%"
REM or make individual run logs
REM set "LOG=%LOGDIR%\%XScriptnamE%\%XScriptnamE%-%STAMP%.log"
REM not global vars come here
set "DNSTESTFILE=%XSCRIPTDIR%\dnstests.txt"
REM set GATEWAY here
set GW=7.7.7.7
REM to reflect GW changes here a route has to be set with each run if this is needed turn switch to 2
REM otherwise only missing routes get re set by switch 1 (default)
set REFRESH-GW=1
REM +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
REM do never set something here at errorlog plz otherwise compare of happened errors wont work
set errorlog=
pushd=%XSCRIPTDIR%
REM +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
echo ================================================== >> %LOG%
echo Script run at %STAMP% >> %LOG%
REM +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
REM ++++++++++++++++++++++++++++ START ++++++++++++++++++++++++++++++++++++++++++++++++
REM if the script is run in cmd we see enough information to follow actions but they are written to a log file too for sheduled use
REM ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
REM when a batch script needs to use drives not local, eg shares it always needs special rights,
REM means you need to use an account to run the script which is allowed to log on as batch task in
REM secpol - (click start type secpol.msc and start it - Select "Local Policies" in MSC snap
REM in - Select "User Rights Assignment" - Right click on "Log on as batch job" and select
REM Properties - Click "Add User or Group", and include the relevant user.)
REM ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
REM ++++++++++++ make a loop for each line in file ++++++++++++++++++++++++++++++++++++
REM first we test if script is able to set routes and got admin rights
REM if delete fails, with false parameter -> script is elevated
REM otherwise the missing elevated rights get reported to log
echo.
echo "if route delete fails, with false parameter -> script is elevated"
echo "otherwise the missing elevated rights get reported to console"
echo.
route delete 999.999.999.999
echo. >> %LOG%
echo "if route delete fails, missing elevated rights get reported to log " >> %LOG%
echo "otherwise the script is elevated and you find only this text in log" >> %LOG%
echo. >> %LOG%
route delete 999.999.999.999 >> %LOG%
REM read them in different vars to call processing
REM check for test file
if NOT exist "%DNSTESTFILE%" (
set errorlog=%errorlog% : error dns file not exist :
echo blat error dnsfile
echo error dnsfile not exist >> %log%
)
REM read test file
set Counter=1
for /f %%s in (%DNSTESTFILE%) do (
set "Line_!Counter!=%%s"
set /a Counter+=1
)
set /a NumLines=Counter - 1
REM make a backup of old test file before nulling it
copy /y %DNSTESTFILE% %DNSTESTFILE%.bak 2>&1 > %XLOGX%
REM as i found no easy way to rewrite the specific line i choose to read out all lines in vars,
REM now we nul the file and rewrite lines later, BE aware if script breaks all lines are lost most times
REM instead of only one, so edit it carefully and test carefully all cases possible
type NUL > %DNSTESTFILE%
REM now use vars to call processing
for /l %%r in (1,1,%NumLines%) do (
set "q=!Line_%%r!"
echo. >> %log%
echo.
call :check !q!
)
REM did all go well or what did we miss?
if NOT "%errorlog%."=="." (
echo.
echo blat summary %errorlog%!
echo. >> %LOG%
echo %errorlog%! >> %LOG%
)
REM ++++++++++++++++++++++++++++ END +++++++++++++++++++++++++++++++++++++++++++++++++++
REM next line tells us script did run through code while one may want to save this lines
echo ==================script finished================= >> %log%
del xpipex
break
goto :eof
REM ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
REM +++++++++++++++++++++++++++++ PROCESSING +++++++++++++++++++++++++++++++++++++++++++
:check
REM trim whitespace from beginning and end of line
for /f "tokens=* delims=" %%z in ("!q!") do (
set "line=!q!"
REM test if line is valid dns AND ip address syntax BUT only informational because of limited regular expression support of findstr and "1234.2.3.4" is also accepted as well formatted address
echo !line! | findstr /i /r "^[a-z0-9-]*\.[a-z0-9-]*\.[a-z0-9-]*=[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*" >NUL || (
echo blat error in dns test line syntax with: !line!
set errorlog=%errorlog% : error in dns test line syntax with: !line! :
)
REM test that trimmed line matches at least once "^char=number$" and set vars for test
echo !line! | findstr /i "^[a-z]*=[0-9]*$" >NUL && do (
for /f "tokens=1,2 delims==" %%x in ("!q!") do set TESTDNS=%%x&set TESTIP=%%y
)
REM trim whitespace from vars
set TESTDNS=%TESTDNS: =%
set TESTIP=%TESTIP: =%
echo testing %TESTDNS% to %TESTIP%
echo checking %TESTDNS%: >> %LOG%
REM useful to test script
REM nslookup %TESTDNS%
REM useful to test script
REM go get dns resolution and set vars to test and compare
set "XIP="
for /f "skip=1 tokens=*" %%a in ('nslookup "%TESTDNS%" 2^>nul ^| findstr /i /r /c:"address[e]*[s]*:.*\." /c:"address[ ]*=.*\." /c:"^[ ][ ]*[0-9].*\." ') do (
rem get nslookup output
set "_line=%%a"
rem remove spaces
set "_line=!_line: =!"
rem parse line
for /f "tokens=1,* delims=:=" %%b in ("!_line!") do (
rem retrieve the correct section of the line
if "%%c"=="" (
set "XTIPX=%%b"
) else (
set "XTIPX=%%c"
)
REM again trim whitespace from var
set XTIPX=!XTIPX: =!
rem test address match to old address
if "!XTIPX!"=="%TESTIP%" (
set "XIP=!XTIPX!"
goto endRESTESTDNS
)
rem if no match, the first address found is saved
if not defined XIP set "XIP=!XTIPX!"
)
)
:endRESTESTDNS
REM if dsn did change
if NOT %XIP%==%TESTIP% (
echo %TESTDNS% NOW is %XIP%
REM delete the old route and set new one
REM first check if the old false ip was set to prevent error if not found
netsh interface ipv4 show route | find /i "%TESTIP%" >NUL
if errorlevel 1 (
echo blat there was no route for given %TESTIP% from file, routes manipulated or file updated?
echo there was no route for given %TESTIP% from file, routes manipulated or file updated? >> %LOG%
set errorlog=%errorlog% : there was no route for given %TESTIP% from file, routes manipulated or file updated? :
) else (
Route DELETE %TESTIP% >> %LOG%
)
Route ADD -P %XIP% mask 255.255.255.255 %GW% >> %LOG%
echo blat route %TESTDNS% was changed from %TESTIP% to %XIP% by script!
echo %TESTDNS% was changed from %TESTIP% to %XIP% by script! >> %LOG%
REM write it back to the testfile (which was reset above)
echo %TESTDNS%=%XIP% >> %DNSTESTFILE%
REM fill a log-var to report allover later in mail for example
set errorlog=%errorlog% : route %TESTDNS% was changed from %TESTIP% to %XIP% by script! :
)
if %XIP%==%TESTIP% (
REM if dns did not change
echo ip did not change
echo checking if route exist
REM now the gateway switch comes in, if set to 1 we check if route exist and if so we go on, otherwise we set the route again
if %REFRESH-GW% == 1 (
netsh interface ipv4 show route | find /i "%XIP%" >NUL
if errorlevel 1 (
Route ADD -P %XIP% mask 255.255.255.255 %GW% >> %LOG%
echo blat %XIP% route was deleted by unknown manipulation and reset by script!
echo %XIP% route was deleted by unknown manipulation and reset by script! >> %LOG%
set errorlog=%errorlog% : %XIP% route was deleted by unknown manipulation and reset by script! :
)
)
if %REFRESH-GW% == 2 (
REM here we check if route was deleted from elsewhere (and report it) but we set it anyway to make shure the gateway gets updated in case it was changed in the var on top
netsh interface ipv4 show route | find /i "%XIP%" >NUL
if errorlevel 1 (
echo blat %XIP% was deleted by unknown manipulation!
echo %XIP% was deleted by unknown manipulation! >> %LOG%
set errorlog=%errorlog% : %XIP% was deleted by unknown manipulation! :
)
REM first delete the old and then set the new route
Route DELETE %TESTIP% >> %LOG%
Route ADD -P %XIP% mask 255.255.255.255 %GW% >> %LOG%
echo blat route %TESTDNS% was reset by script!
)
REM we should not forget to write back the route to our testfile
echo %TESTDNS%=%XIP% >> %DNSTESTFILE%
)
REM now we tell ourself we are through on all should be fine with the address and route
netsh interface ipv4 show route | find /i "%XIP%" >NUL
if errorlevel 1 (
echo blat route %XIP% could not be set - ERROR setting route
echo route %XIP% could not be set - ERROR setting route >> %LOG%
set errorlog=%errorlog% : route %XIP% could not be set - ERROR setting route :
) else (
echo OKI
echo OK >> %LOG%
)
:EOF
回答2:
There may be other problems; but a couple I see:
- If UAC is enabled you need to 'Run as administrator'
Change the following line in :Check
for /f "tokens=* delims=" %%x in ("%%~r") do (
to
for /f "tokens=* delims=" %%x in ("%~1") do (
回答3:
And if one might only want to monitor and warn on dns changes here is the code (including: daily still alive email, IP6 filtering and smart behaviour on loadbalanced IP's, to keep old one as long as it is listed):
@ECHO OFF
SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
REM ++++++++++++++++++++++++++++ BLAT EMAIL CONFIG ++++++++++++++++++++++++++++++++++++
set eMailTO=someone@somedomain.somewhere
set eMailCC=someone@somedomain.somewhere
set eMailFROM=dnstestscript
set server=0.0.0.0
REM you have to install blat of course, here "echo blat ..." is used where it would be
REM useful to send an email on interesting items, but it is also sent to shell and log
REM +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
REM ++++++++++++++++++++++++++++ MAKE DATE ++++++++++++++++++++++++++++++++++++++++++++
for /F "usebackq tokens=1,2 delims==" %%i in (`wmic os get LocalDateTime /VALUE 2^>NUL`) do if '.%%i.'=='.LocalDateTime.' set ldt=%%j
REM make timestamp (date reverse)
set STAMP=%ldt:~0,4%-%ldt:~4,2%-%ldt:~6,2%--%ldt:~8,2%-%ldt:~10,2%--%ldt:~12,2%-%ldt:~15,3%
set ACTUALDATE=%ldt:~0,4%-%ldt:~4,2%-%ldt:~6,2%
REM +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
REM ++++++++++++++++++++++++++++ SCRIPT CONFIG ++++++++++++++++++++++++++++++++++++++++
set "XScriptnamE=%~n0"
set "XSCRIPTDIR=%~dp0"
set "LOGDIR=%XSCRIPTDIR%\%XScriptnamE%"
if not exist "%LOGDIR%" mkdir "%LOGDIR%"
set "LOG=%LOGDIR%\%XScriptnamE%.log"
REM +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
REM ++++++++++++++++++++++++++++ SCRIPT ALIVE ++++++++++++++++++++++++++++++++++++++++
REM now tell us once a day that script is up and running
set DateLOG=%XSCRIPTDIR%\%XScriptnamE%-date.txt
if not exist "%DateLOG%" echo %ACTUALDATE% > %DateLOG%
set /p BEFOREDATE=< %DateLOG%
if NOT %ACTUALDATE% == %BEFOREDATE% (
echo %ACTUALDATE% > %DateLOG%
echo blat %0 -subject "DNS Monitor Script is alive and running! OK" -body "DNS-monitoring-script up and running - DNS monitoring is OK!" -to %eMailTO% -cc %eMailCC% -f %eMailFROM% %server%
)
REM +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
REM make errorlooging expand
set "XLOGX=xpipex && type xpipex && type xpipex >> %LOG%"
REM or make individual run logs
REM set "LOG=%LOGDIR%\%XScriptnamE%\%XScriptnamE%-%STAMP%.log"
REM not global vars come here
set "DNSTESTFILE=%XSCRIPTDIR%\dnstests.txt"
REM +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
REM do never set something here at errorlog plz otherwise compare of happened errors wont work
set errorlog=
pushd=%XSCRIPTDIR%
REM +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
echo ================================================== >> %LOG%
echo Script run at %STAMP% >> %LOG%
REM +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
REM ++++++++++++++++++++++++++++ START ++++++++++++++++++++++++++++++++++++++++++++++++
REM if the script is run in cmd we see enough information to follow actions but they are written to a log file too for sheduled use
REM ++++++++++++ make a loop for each line in file ++++++++++++++++++++++++++++++++++++
REM read them in different vars to call processing
REM check for test file
if NOT exist "%DNSTESTFILE%" (
set errorlog=%errorlog% : error dns file not exist :
echo blat error dnsfile
echo error dnsfile not exist >> %log%
)
REM read test file
set Counter=1
for /f %%s in (%DNSTESTFILE%) do (
set "Line_!Counter!=%%s"
set /a Counter+=1
)
set /a NumLines=Counter - 1
REM make a backup of old test file before nulling it
copy /y %DNSTESTFILE% %DNSTESTFILE%.bak 2>&1 > %XLOGX%
REM as i found no easy way to rewrite the specific line i choose to read out all lines in vars,
REM now we nul the file and rewrite lines later, BE aware if script breaks all lines are lost most times
REM instead of only one, so edit it carefully and test carefully all cases possible
type NUL > %DNSTESTFILE%
REM now use vars to call processing
for /l %%r in (1,1,%NumLines%) do (
set "q=!Line_%%r!"
echo. >> %log%
echo.
call :check !q!
)
REM did all go well or what did we miss?
if NOT "%errorlog%."=="." (
echo.
echo blat summary %errorlog%!
echo. >> %LOG%
echo %errorlog%! >> %LOG%
)
REM ++++++++++++++++++++++++++++ END +++++++++++++++++++++++++++++++++++++++++++++++++++
REM next line tells us script did run through code while one may want to save this lines
echo ==================script finished================= >> %log%
del xpipex
break
goto :eof
REM ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
REM +++++++++++++++++++++++++++++ PROCESSING +++++++++++++++++++++++++++++++++++++++++++
:check
REM trim whitespace from beginning and end of line
for /f "tokens=* delims=" %%z in ("!q!") do (
set "line=!q!"
REM test if line is valid dns AND ip address syntax BUT only informational because of limited regular expression support of findstr and "1234.2.3.4" is also accepted as well formatted address
echo !line! | findstr /i /r "^[a-z0-9-]*\.[a-z0-9-]*\.[a-z0-9-]*=[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*" >NUL || (
echo blat error in dns test line syntax with: !line!
set errorlog=%errorlog% : error in dns test line syntax with: !line! :
)
REM test that trimmed line matches at least once "^char=number$" and set vars for test
echo !line! | findstr /i "^[a-z]*=[0-9]*$" >NUL && do (
for /f "tokens=1,2 delims==" %%x in ("!q!") do set TESTDNS=%%x&set TESTIP=%%y
)
REM trim whitespace from vars
set TESTDNS=%TESTDNS: =%
set TESTIP=%TESTIP: =%
echo testing %TESTDNS% to %TESTIP%
echo checking %TESTDNS%: >> %LOG%
REM useful to test script
REM nslookup %TESTDNS%
REM useful to test script
REM go get dns resolution and set vars to test and compare
set "XIP="
for /f "skip=1 tokens=*" %%a in ('nslookup "%TESTDNS%" 2^>nul ^| findstr /i /r /c:"address[e]*[s]*:.*\." /c:"address[ ]*=.*\." /c:"^[ ][ ]*[0-9].*\." ') do (
rem get nslookup output
set "_line=%%a"
rem remove spaces
set "_line=!_line: =!"
rem parse line
for /f "tokens=1,* delims=:=" %%b in ("!_line!") do (
rem retrieve the correct section of the line
if "%%c"=="" (
set "XTIPX=%%b"
) else (
set "XTIPX=%%c"
)
REM again trim whitespace from var
set XTIPX=!XTIPX: =!
rem test address match to old address
if "!XTIPX!"=="%TESTIP%" (
set "XIP=!XTIPX!"
goto endRESTESTDNS
)
rem if no match, the first address found is saved
if not defined XIP set "XIP=!XTIPX!"
)
)
:endRESTESTDNS
REM if dsn did change
if NOT %XIP%==%TESTIP% (
echo %TESTDNS% NOW is %XIP%
REM inform us
echo blat dns for given %TESTDNS% did change from %TESTIP% TO %XIP%!
echo dns did change from %TESTIP% TO %XIP%! >> %LOG%
REM fill a log-var to report allover later in mail for example
set errorlog=%errorlog% : dns for given %TESTDNS% did change from %TESTIP% TO %XIP%! :
REM do not forget to write back
echo %TESTDNS%=%XIP% >> %DNSTESTFILE%
)
if %XIP%==%TESTIP% (
REM if dns did not change
echo ip did not change
REM we should not forget to write back the route to our testfile
echo %TESTDNS%=%XIP% >> %DNSTESTFILE%
echo - OK >> %LOG%
)
)
:EOF
来源:https://stackoverflow.com/questions/17906270/monitor-defined-dns-resolutions-and-change-routes-while-writing-back-new-ips