Check open ports

From NSIS Wiki
Jump to navigationJump to search

Below is a function allowing you to test for open UDP and TCP ports on the local computer. Use this to check if the user selected port is free, if Apache can run with the default configuration or if your favorite port hasn't been stolen by another.

This code uses iphlpapi.dll which is only available on Windows 98 and above and NT 4.0 SP4 and above.

Usage

First, save Ports.nsh from the code snippet at the end of this page to Ports.nsh. Next, include it into your script.

!include "Ports.nsh"

Now, to check for open TCP ports, use the following.

${Unless} ${TCPPortOpen} 80
  MessageBox MB_OK "httpd running"
${EndUnless}

To check for open UDP ports, only a slight modification is required.

${If} ${UDPPortOpen} 1337
  MessageBox MB_OK "leet port open :)"
${EndIf}

Ports.nsh

# Usage:
#   Push "Tcp" or "Udp"
#   Push "port_number"
#   Call IsPortOpen
#   Pop $0 ; "open" or "closed" or anything else for error
#
# Or with the LogicLib
#   ${If} ${TCPPortOpen} 80
#   ${EndIf}
#   ${If} ${UDPPortOpen} 137
#   ${EndIf}
#
Function IsPortOpen
 
  Exch $R0 # port to check
  Exch
  Exch $R1
  Push $0
  Push $1
  Push $2
 
  System::Call 'iphlpapi::Get$R1Table(*i.r0, *i .r1, i 1) i .r2'
  ${If} $2 != 122 # ERROR_INSUFFICIENT_BUFFER
    StrCpy $R0 ""
    Pop $2
    Pop $1
    Pop $0
    Exch $R1
    Exch
    Exch $R0
    Return
  ${EndIf}
 
  System::Alloc $1
  Pop $0
 
  System::Call 'iphlpapi::Get$R1Table(ir0, *i r1, i 1) i .r2'
  ${If} $2 != 0 # NO_ERROR
    System::Free $0
    StrCpy $R0 ""
    Pop $2
    Pop $1
    Pop $0
    Exch $R1
    Exch
    Exch $R0
    Return
  ${EndIf}
 
  Push $3
  Push $4
  Push $5
 
  System::Call *$0(i.r2)
  IntOp $2 $2 - 1
  ${For} $3 0 $2
    IntOp $4 $0 + 4  # skip dwNumEntries
    ${If} $R1 == "Tcp"
      IntOp $5 $3 * 20 # sizeof(MIB_TCPROW)
      IntOp $4 $4 + $5 # skip to entry
      System::Call *$4(i.r1,i,i.r4,i,i)
      ${If} $1 <> 2  # $1 = dwState, 2 = MIB_TCP_STATE_LISTEN
        ${Continue}
      ${EndIf}
    ${Else}
      IntOp $5 $3 * 8 # sizeof(MIB_UDPROW)
      IntOp $4 $4 + $5 # skip to entry
      System::Call *$4(i,i.r4)
    ${EndIf}
!if "${NSIS_PACKEDVERSION}" >= 50343936 ; v3.3+
    System::Call ws2_32::ntohs(hr4)h.r4
!else
    System::Call ws2_32::ntohs(ir4)i.r4
    IntOp $4 $4 & 0xffff ; Truncate to 16-bits
!endif
 
    ${If} $4 = $R0
      StrCpy $R0 "open"
      ${Break}
    ${EndIf}
  ${Next}
 
  ${If} $R0 != "open"
    StrCpy $R0 "closed"
  ${EndIf}
 
  System::Free $0
 
  Pop $5
  Pop $4
  Pop $3
  Pop $2
  Pop $1
  Pop $0
  Exch $R1
  Exch
  Exch $R0
 
FunctionEnd
 
# LogicLib macros for IsPortOpen
 
!include LogicLib.nsh
 
!macro _PortOpen _a _b _t _f
  !insertmacro _LOGICLIB_TEMP
  Push `${_a}`
  Push `${_b}`
  Call IsPortOpen
  Pop $_LOGICLIB_TEMP
  !insertmacro _== $_LOGICLIB_TEMP "open" `${_t}` `${_f}`
!macroend
!define PortOpen `PortOpen`
 
!macro _TCPPortOpen _a _b _t _f
  !insertmacro _PortOpen Tcp `${_b}` `${_t}` `${_f}`
!macroend
!define TCPPortOpen `"" TCPPortOpen`
 
!macro _UDPPortOpen _a _b _t _f
  !insertmacro _PortOpen Udp `${_b}` `${_t}` `${_f}`
!macroend
!define UDPPortOpen `"" UDPPortOpen`