Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

'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

like image 306
Vandenman Avatar asked Nov 17 '17 15:11

Vandenman


People also ask

Can localhost be blocked by firewall?

Conclusion. Localhost refused to connect is a type of network connection error you might encounter when working on a project on your local web server. It is triggered if the firewall wrongly blocks your server or you're using the wrong port.

How do I get my firewall to prompt again?

To do this, open the "Windows Firewall" page in Control Panel and click "Restore defaults". Save this answer. Show activity on this post. I ran some program and it popped up Windows Firewall notification.

Does Windows Firewall block loopback?

The firewall doesn't block/inspect the localhost/loopback address (127.0. 0.1) because it's your computer. So since the target and source are the same, there's really nothing to firewall. Unless one has a transparent HTTP proxy operating on 127.0.


2 Answers

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

  • You can use netsh to add a rule (administrator privileges are required) to enable firewall access programmatically.

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()
like image 180
Technophobe01 Avatar answered Oct 22 '22 09:10

Technophobe01


(For my take on the firewall rule, see the very end)

The functionality simply does not seem to exist.

In C you create a server socket with socket, bind and listen calls, and get the incoming connection with an accept call. src\modules\internet\sock.c is the socket handler code, it has two functions for opening a socket, Sock_connect opens and connects a socket, so this is for client side, and int Sock_open(Sock_port_t port, Sock_error_t perr) is the one which opens a server socket (and the actual accept call is in Sock_listen). The problem is that this Sock_open has a port argument only, and the host/interface is hardcoded:

/* open a socket for listening */
int Sock_open(Sock_port_t port, Sock_error_t perr)
{
    int sock;
    struct sockaddr_in server;

    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    return Sock_error(perr, errno, 0);

    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons((short)port);

    if ((bind(sock, (struct sockaddr *)&server, sizeof(server)) < 0) ||
        (listen(sock, MAXBACKLOG) < 0)) {
        close(sock);
        return Sock_error(perr, errno, 0);
    }
    return sock;
}

It binds to and listens on INADDR_ANY, which means all interfaces of your PC (not just the loopback), and it triggers the firewall for sure.

The function is called from the neighboring Rsock.c, still with a single port argument, and where everything else is lost seems to be one step earlier, in sockconn.c:

static Rboolean sock_open(Rconnection con)
{
    Rsockconn this = (Rsockconn)con->private;
    int sock, sock1, mlen;
    int timeout = this->timeout;
    char buf[256];

    if(timeout == NA_INTEGER || timeout <= 0) timeout = 60;
    this->pend = this->pstart = this->inbuf;

    if(this->server) {
        sock1 = R_SockOpen(this->port);

This last line is where host part of RSockconn is disregarded, though it contains such field:

/* used in internet module */
typedef struct sockconn {
    int port;
    int server;
    int fd;
    int timeout;
    char *host;
    char inbuf[4096], *pstart, *pend;
} *Rsockconn;

(This is defined outside, in src\include\Rconnections.h)

Unfortunately this will not solve your problem, just this is why you have it. You may consider raising an error report for the developers of R. Comments suggest they got the net code from ancient times, when firewalls and internet security were not that much of a concern like they are now:

/* Simple sockets interface derived from the sockets UICI
   implementation in Appendix B of Practical UNIX Programming,
   K. A. Robbins and S. Robbins, Prentice Hall, 1996. */

Which is nice, just it was 21 years ago.


Originally I did not want to steal the netsh thing from others, but I think you may get wrong suggestions. Actually you should not allow anything, but block everything:
netsh advfirewall firewall add rule name="Rtest" dir=in action=block program="<location and name of your executable>"

And that is it. The thing is that the loopback interface is not firewalled at all (so connections to 127.0.0.1 always work - I tested it too, just to be on the safe side), and you do not want anyone else to reach your program. I saw 'allow'-s in other answers, and you do not want that. Depending on other uses, you may have to restrict the rule with 'localport=8' and/or 'protocol=tcp', but the block part is sure.

like image 41
tevemadar Avatar answered Oct 22 '22 10:10

tevemadar