IP verification in batch script - first match by findstr, secondly verify by for loops (only using windows built in functinallity?

前端 未结 4 1955
没有蜡笔的小新
没有蜡笔的小新 2021-01-06 23:36

This is a question for the batch pro\'s i guess. Seems a lot of people do stumble over IP veriffication while batching, while just using windows built in functinallity, but

相关标签:
4条回答
  • 2021-01-07 00:11

    there is no GNU BRE to validate dotted IPs. FINDSTRs REGEX capabilities are below that. You can use grep for Windows and GNU ERE:

    ECHO(%IP%|GREP -E "(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])"&&ECHO %IP% IS VALID/||%IP% IS NOT A VALID IP.
    
    0 讨论(0)
  • 2021-01-07 00:23

    I assumed you want to review IP numbers placed inside a text file. If the IP's appear at fixed positions inside lines in the file, for example, at third token like this:

    IP number: 172.16.0.0/12
    

    Then you may extract the IP number and separate its parts with a FOR /F command, and then review they in any way you wish:

    setlocal EnableDelayedExpansion
    set wantedNumbers=0,128,192,224,240,248,252,254,255
    
    for /F "tokens=3" %%n in ('findstr /r "[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*" theFile.txt') do (
       for /F "tokens=1-4 delims=./" %%a in ("%%n") do (
          if %%a neq 255 echo First octet is not 255 & goto error
          if "!wantedNumbers:%%b=!" equ "%wantedNumbers%" echo Second octet bad & goto error
          if "!wantedNumbers:%%c=!" equ "%wantedNumbers%" echo Third octet bad & goto error
          if "!wantedNumbers:%%d=!" equ "%wantedNumbers%" echo Fourth octet bad & goto error
          echo The IP %%n is correct
       )
    )
    

    If the IP numbers are not at fixed positions, you need another, existent solution.

    However, if the IP is stored in an individual variable (you have not indicated this point), just eliminate the first for and replace %%n by the value of the variable.

    EDIT: New method added

    Edit 2: List of numbers/ranges added

    I devised a different way to solve this problem via the following subroutine:

    @echo off
    
    rem ValidateIP.bat: Validate an IP4 address
    rem Antonio Perez Ayala
    
    if "%~1" neq "" goto validateIP
    
    echo Validate an IP4 address using several successive testings on it
    echo/
    echo call ValidateIP.bat ipAddress 1:ipRange1 2:ipRange2 ... N:ipRangeN
    echo/
    echo Each ipRange is comprised of an "errorlevel" followed by a colon and
    echo 4 groups separated by dots of anyone of the following:
    echo/
    echo    - An asterisk, that match any value between 0 and 255.
    echo    - A number, that match just that value.
    echo    - Two numbers separated by hypen, that match any value in that range.
    echo    - A list of numbers and/or ranges separated by number-sign (#).
    echo/
    echo At end, the value placed before the colon of the *last* matching ipRange
    echo is returned in ERRORLEVEL; two or more ipRanges may return the same value.
    echo If no ipRange is given, 1:*.*.*.* is assumed.
    echo If no ipRange is matched, return zero.
    echo/
    echo Some examples:
    echo/
    echo    call ValidateIp %%IPaddress%%  1:0-254.*.*.0-254  2:172.16-30.0-254.1-254
    echo/
    echo    set subNET=0#128#192#224#240#248#252#254#255
    echo    call ValidateIP %%IPaddress%%  1:255.%%subNET%%.%%subNET%%.%%subNET%%
    goto :EOF
    
    :validateIP ipAddress [#:ipRange] ...
    
    setlocal EnableDelayedExpansion
    echo %~1| findstr /B /E /R "[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*" > NUL
    if errorlevel 1 exit /B 0
    for /F "tokens=1-4 delims=." %%a in ("%~1") do set p1=%%a& set p2=%%b& set p3=%%c& set p4=%%d
    set "ipRanges=%* "
    set ipRanges=%ipRanges:* =%
    if not defined ipRanges set ipRanges=1:*.*.*.*
    set ipRanges=%ipRanges::*=:0-255%
    set ipRanges=%ipRanges:.*=.0-255%
    set return=0
    for %%a in (%ipRanges%) do for /F "tokens=1,2 delims=:" %%b in ("%%a") do (
       set /A fields=0, i=0
       set ipRange=%%c
       for %%d in ("!ipRange:.=" "!") do (
          set /A this=0, i+=1
          set range=%%~d
          for %%e in ("!range:#=" "!") do for /F "tokens=1-3 delims=-" %%i in ("!i!-%%~e-%%~e") do (
             if !p%%i! geq %%j if !p%%i! leq %%k set this=1
          )
          set /A fields+=this
       )
       if !fields! equ 4 set return=%%b
    )
    exit /B %return%
    

    Using previous subroutine, this particular problem may be solved this way:

    set "subNET=0#128#192#224#240#248#252#254#255"
    call ValidateIp %theIP% 1:0-254.*.*.0-254 2:10.0-254.0-254.0-254 2:172.16-30.0-254.1-254 2:192.168.0-254.0-254 3:127.0-254.0-254.0-254 4:255.%subNET%.%subNET%.%subNET% 5:0.*.*.*
    
    if %errorlevel% equ 1 (
       set ret=public
    ) else if %errorlevel% equ 2 (
       set ret=private
    ) else if %errorlevel% equ 3 (
       set ret=local
    ) else if %errorlevel% equ 4 (
       set ret=subnetmask
    ) else if %errorlevel% equ 5 (
       set ret=sourcenetwork
    ) else (
       echo Invalid IP address
       goto :EOF
    )
    

    Or in this shorter way:

    set i=0
    for %%a in (public private local subnetmask sourcenetwork) do (
       set /A i+=1
       set result[!i!]=%%a
    )
    
    set "subNET=0#128#192#224#240#248#252#254#255"
    call ValidateIp %theIP% 1:0-254.*.*.0-254 2:10.0-254.0-254.0-254 2:172.16-30.0-254.1-254 2:192.168.0-254.0-254 3:127.0-254.0-254.0-254 4:255.%subNET%.%subNET%.%subNET% 5:0.*.*.*
    
    if defined result[%errorlevel%] (
       set ret=!result[%errorlevel%]!
    ) else (
       echo Invalid IP address
       goto :EOF
    )
    
    0 讨论(0)
  • 2021-01-07 00:25

    Basic structure for ip validation. Adapt as needed

    @echo off
        setlocal enableextensions enabledelayedexpansion
    
        rem try some ip addresses 
        for %%i in ("1.1.1.1" "0.1.1.1" "250.1024.1.1" "10.0.2.1" "something" "" ) do (
    
            echo --------------------------------------------
    
            rem call with a variable to get return value
            call :validateIP %%~i ret 
            echo %%~i : return value : !ret! 
    
            rem call with or without variable to get errorlevel
            call :validateIP %%~i  && echo %%i is valid || echo %%i is invalid
    
        )   
    
        exit /b 
    
    :validateIP ipAddress [returnVariable]
        rem prepare environment
        setlocal 
    
        rem asume failure in tests : 0=pass 1=fail : same for errorlevel
        set "_return=1"
    
        rem test if address conforms to ip address structure
        echo %~1^| findstr /b /e /r "[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*" >nul
    
        rem if it conforms to structure, test each octet for rage values
        if not errorlevel 1 for /f "tokens=1-4 delims=." %%a in ("%~1") do (
            if %%a gtr 0 if %%a lss 255 if %%b leq 255 if %%c leq 255 if %%d gtr 0 if %%d leq 254 set "_return=0"
        )
    
    :endValidateIP
        rem clean and return data/errorlevel to caller
        endlocal & ( if not "%~2"=="" set "%~2=%_return%" ) & exit /b %_return%
    
    0 讨论(0)
  • 2021-01-07 00:27

    This is a NEW answer to the NEW question in this same topic!

    As I said you in my comment I need to understand what is the supposed operation of the code in order to fix it (otherwise, how could I do that?), but you not gave me a single description of your NEW code, so I can only guess...

    So I guess that :validateIP subroutine must return a numeric errorlevel value to the caller program as described in exit /? command, and that it optionally return a string variable to the caller's environment. The code below do that:

        :validateIP ipAddress [/ipRange] [returnVariable]
    
        rem prepare environment
        setlocal 
    
        rem Initialize ip range as public
        set ipCASE=public
    
        rem Process switches
        set "returnVar=%~2"
        rem If second parameter start with slash...
        if "%returnVar:~0,1%" equ "/" (
            rem It is the /ipRange
            set "ipCASE=%returnVar:~1%"
            set "returnVar=%~3"
        )
    
    echo ipcase: %ipCase%
    
        rem asume failure in tests : 0=pass 1=fail : same for return/errorlevel
        set "_return=1"
        set "_returnlevel=1"
    
        rem test if address conforms to ip address structure
        echo %~1| findstr /b /e /r "[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*" >nul
    
        rem if it conforms to structure, test each octet for range values
        if not errorlevel 1 for /f "tokens=1-4 delims=." %%a in ("%~1") do (
            if %%a gtr 0 if %%a lss 255 if %%b leq 255 if %%c leq 255 if %%d gtr 0 if %%d leq 254 set "_return=public"
            if %%a equ 10 if %%b geq 0 if %%b lss 255 if %%c geq 0 if %%c lss 255 if %%d gtr 0 if %%d leq 254 set "_return=private"
            if %%a equ 172 if %%b geq 16 if %%b lss 31 if %%c geq 0 if %%c lss 255 if %%d gtr 0 if %%d leq 254 set "_return=private"
            if %%a equ 192 if %%b equ 168 if %%c geq 0 if %%c lss 255 if %%d gtr 0 if %%d leq 254 set "_return=private"
            if %%a equ 127 if %%b geq 0 if %%b lss 255 if %%c geq 0 if %%c lss 255 if %%d gtr 0 if %%d leq 254 set "_return=local"
        )
    
        rem set errorlevels
        if "%ipCASE%"=="public"  if "%_return%"=="public"  (set "_returnlevel=0") else (set "_returnlevel=1")
    
        if "%ipCASE%"=="private" if "%_return%"=="private" (set "_returnlevel=0") else (set "_returnlevel=1")
    
        :endValidateIP
        rem clean and return data/errorlevel to caller
        endlocal & ( if not "%returnVar%"=="" set "%returnVar%=%_return%" ) & exit /b %_returnlevel%     
    

    However, when I tested this subroutine with your testing code I got strange results. I reviewed the entire code and discovered several problems not in the subroutine, but in the testing code; for example, echo %errorlevel% inside the main for loop always will show 0, and the invocation of :validateIP ipAddress [/ipRange] [returnVariable] don't follow this format in 3 of 4 cases and sometimes don't include the return variable, but the calling code always show it, etc...

    Of course, these problems have no relation with the original theme of this topic nor with your last request and I already spent too much time in this matter, so I didn't solved they...

    0 讨论(0)
提交回复
热议问题