rlocalhostloopback-address

'localhost' connection without firewall popup


Consider the following R script:

con <- socketConnection(host = "localhost", port = 8, server = TRUE, blocking = TRUE, open = "a+b")
close(con = con)

Saving these lines as a .R file, and subsequently running it from command line produces (on Windows) a firewall warning. At least, if there is no rule for R under "Windows Firewall with Advanced Security", which appears after the first time. I've been told the same happens on a Mac, but I couldn't verify this myself. How can this be altered to allow for a localhost loopback, but avoid the popup?

Context: I've written some code for people that uses parallel processing (on one single local machine). However, this warning popped up on their screens, and they got suspicious. The silly thing is, that even if people click no or ignore the popup, the parallel processing still seems to works. I take that as a sign that it's possible to modify this code to not give this popup and still function.

I've seen very similar questions in other languages (1, 2, 3), and I was wondering whether it is possible to do the same with R.

Windows 10 Firewall First Time Prompt Example:

Enter image description here


Solution

  • My sense is that the easiest way to navigate this problem is to add a firewall rule as part of the application install process.

    I provide an example script below, and I hope this helps point you in the right direction.

    Example firewall configuration script

    netsh advfirewall firewall add rule name="RScript" action=allow program="C:\Program Files\Microsoft\R Client\R_SERVER\bin\x64\Rscript.exe" enable=yes Localip="127.0.0.1" localport="9999" protocol=tcp interfacetype=any profile=private dir=in
    

    Command Output:

    PS <hidden>\dev\stackoverflow\47353848> netsh advfirewall firewall add rule name="RScript" action=allow program="C
    :\Program Files\Microsoft\R Client\R_SERVER\bin\x64\Rscript.exe" enable=yes Localip="127.0.0.1" localport="9999" protoco
    l=tcp interfacetype=any profile=private dir=in
    Ok.
    

    Firewall Rule Added

    Enter image description here


    Assuming you run the R file using RScript, the above netsh script will enable the RScript application to be able to access the loopback address 127.0.0.1 on port 9999 using TCP on a private network. From this point on you should not get a firewall prompt.

    Command line with no prompt for firewall

    c:\<hidden>\dev\stackoverflow\47353848> Rscript.exe .\server.R
    Listening...
    

    Why do this? Well, as far as I have been able to ascertain there is no way to use R's base::socketConnection on Windows without triggering the Windows Defender firewall prompt, even when using the loopback connector. Interesting to note is that if you use Java you don't get prompted. I looked at both implementations, but I couldn't determine why not.

    Test Server Code:

    server <- function() {
      while (TRUE) {
        writeLines("Listening...")
        con <- socketConnection(host = "loopback",
                                port = 9999,
                                server = TRUE,
                                blocking = TRUE,
                                timeout = 0,
                                open = "r+")
        data <- readLines(con, 1)
        print(data)
        response <- toupper(data)
        writeLines(response, con)
        close(con)
      }
    }
    server()
    

    Test Client Code

    client <- function() {
      while (TRUE) {
        con <- socketConnection(host = "loopback",
                                port = 9999,
                                server = FALSE,
                                blocking = TRUE,
                                open = "r+")
        f <- file("stdin")
        open(f)
        print("Enter text to be upper-cased, q to quit")
        sendme <- readLines(f, n = 1)
        if (tolower(sendme) == "q") {
          break
        }
    
        write_resp <- writeLines(sendme, con)
        server_resp <- readLines(con, 1)
        print(paste("Your upper cased text: ", server_resp))
        close(con)
      }
    }
    client()