Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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 no real code is to find.

At several places a findstr expression is findable, to identify a numerical string matching four sequences of numbers.

findstr /r "[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*"

While there seems no better way to identify the string itself (because of limited regular expression support of findstr) this catches too false positives like 1234.2.3.4 or 999.999.999.999 and of course 0.0.0.0.

It would "only" need to verify the found string further, e.g. with a sequence of for loops, and `make shure each found string octet is valid for IP rules.

  • first octet between 1 and 254
  • second and
  • third between 0 and 255
  • forth between 1 and 254

If one would then integrate a second part of verification into this code to identify further if found IP was one of the 3 private classes (10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16 or to be precice one of: 10.0.0.0 to 10.255.255.255, 172.16.0.0 to 172.31.255.255 and 192.168.0.0 to 192.168.255.255) this would make a round function. And not to forget the special 127.x.x.x must get warned D).

To get IP4 complete a switch to choose if private or public IP shall get verified and returnvalues may tell closer what kind or even subnet masks have been recognized:

  • first octet must be 255
  • second and
  • third and
  • fourth one of 0,128,192,224,240,248,252,254,255

So overall this would be the pseudo routine:

a function taking input, no matter where from, just to be called, taking switch for usage and returning result

  • take Switches for private or public IP range
  • validate IP Syntax
    • IP verification - recognized range and set return values
      • private or
      • pulic class
      • subnet
      • ...
  • set returnvalue, set errorlevel depending on switch

If the code does set nice usable return codes (like in example, return the recognized ip range) this would be an alltime function for everybody dealing with IP4's anyway. While i will extend those ip ranges myself, if only just the function will reliable return those "_return"-values like in example code.

Did i forget something?

Nobody did code this already?

SOLUTION: According to MC ND's example and Aacini's switch handling and subnetmask code i blew up the code, added errorhandling usage echo and other cases - here with some testing sample code included:

  @echo off
          setlocal enableextensions enabledelayedexpansion

          rem try some ip addresses 
          for %%i in ("1.2.3.4" "0.1.2.3" "250.1024.1.2" "10.0.2.1" "127.0.0.1" "1.2.3.255" "172.16.17.18" "192.168.1.1" "255.128.240.0" "0.0.0.0" "something" "" ) do (
          REM 1.2.3.4 is public / 0.1.2.3 is false all / 10.0.2.1 is private / 127.0.0.1 is local / 172.16.17.18 is private / 192.168.1.1 is private / 255.128.240.0 is subnet / 0.0.0.0 is false all (source net)


              echo --------------- run one as default case assuming pulic with ret var -------------------

              rem call default with a return variable 
              call :validateIP %%~i ret && echo %%i is valid || echo %%i is invalid
              echo return value: !ret!
              echo --------------------------------------------

              echo --------------- run two with switch public -------------------

              rem call with switch public 
              call :validateIP %%~i /public && echo %%i is valid || echo %%i is invalid
              echo return value: !ret!
              echo --------------------------------------------

              echo ------------ run three with switch private ---------------------
              rem call with switch private 
              call :validateIP %%~i /private && echo %%i is valid || echo %%i is invalid
              echo return value: !ret!
              echo --------------------------------------------

              echo ------------ run four with switch private and ret variable ---------------------
              rem call with switch private and return variable
              call :validateIP %%~i /private ret && echo %%i is valid || echo %%i is invalid
              echo return value: !ret!
              echo --------------------------------------------

              echo ------------ run five with switch local and ret variable ---------------------
              rem call with switch private and return variable
              call :validateIP %%~i /local ret && echo %%i is valid || echo %%i is invalid
              echo return value: !ret!
              echo --------------------------------------------

              echo ------------ run six with switch subnet and ret variable ---------------------
              rem call with switch private and return variable
              call :validateIP %%~i /subnet ret && echo %%i is valid || echo %%i is invalid
              echo return value: !ret!
              echo --------------------------------------------

              echo ------------ run seven with switch source and ret variable ---------------------
              rem call with switch private and return variable
              call :validateIP %%~i /source ret && echo %%i is valid || echo %%i is invalid
              echo return value: !ret!
              echo --------------------------------------------

              echo ------------ run eight with nothing ---------------------
              rem call with switch private and return variable
              call :validateIP && echo is valid || echo is invalid
              echo return value: !ret!
              echo --------------------------------------------

          )   
          exit /b 


 :validateIP ipAddress [/ipRange] [returnVariable]

  rem prepare environment
  setlocal enableextensions enabledelayedexpansion 


  if "%~1"=="" goto USAGE
  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 goto USAGE
  :afterusage

  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"
  )

  rem asume failure in tests : 0=pass 1=fail : same for return/errorlevel
  set "_return=1"
  set "_returnlevel=1"
  set "subNETNumbers=0,128,192,224,240,248,252,254,255"

  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"
      if %%a equ 255 if not "!subNETNumbers:%%b=!" equ "%subNETNumbers%" if not "!subNETNumbers:%%c=!" equ "%subNETNumbers%" if not "!subNETNumbers:%%d=!" equ "%subNETNumbers%" set "_return=subnetmask"
      if %%a equ 0 set "_return=sourcenetwork"
  )

  rem set returnlevels depending on given switch
  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")

  if "%ipCASE%"=="local" if "%_return%"=="local" (set "_returnlevel=0") else (set "_returnlevel=1")

  if "%ipCASE%"=="subnet" if "%_return%"=="subnetmask" (set "_returnlevel=0") else (set "_returnlevel=1")

  if "%ipCASE%"=="source" if "%_return%"=="sourcenetwork" (set "_returnlevel=0") else (set "_returnlevel=1")

  REM OPTION1 set errorlevel
  REM another correct way to set errorlevel would be to REM this line beneath and instead use _returnlevel with exit /b like in line REM OPTION2 - while this is interesting way to set it indirectly
  if "%_returnlevel%"=="0" (ver > nul) else (set dummy 2> nul)


  :endValidateIP
  rem clean and return data/errorlevel to caller
  endlocal & ( if not "%returnVar%"=="" set "%returnVar%=%_return%" ) & exit /b 
  REM OPTION2 endlocal & ( if not "%returnVar%"=="" set "%returnVar%=%_return%" ) & exit /b %_returnlevel%  

  :usage
  echo.
  echo   Usage:  call :validateIP [/ipRange] [returnVariable]
  echo.   
  echo        for example: call :validateIP 127.0.0.2 /local ret 
  echo.   
  echo     if NO switch is given function assumes public, 
  echo     switch and return var are optional
  echo     errorlevel depends and corresponds on given switch
  echo     known switches: /public, /private, /local, /subnet, /source
  echo     return var reflects syntax check, if return var is "1" the input was malformed anyhow
  echo.
  goto :afterusage

2 Answers

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%
like image 163
MC ND Avatar answered Oct 30 '25 09:10

MC ND


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.
like image 25
Endoro Avatar answered Oct 30 '25 07:10

Endoro



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!