no way to pause `Listen` on net connections

159 views
Skip to first unread message

David N

unread,
Jul 24, 2023, 1:11:30 AM7/24/23
to golan...@googlegroups.com
I've posted this question on stackoverflow, discussed it with some members of the golang community, and I was encouraged to post here.

Problem: I have a secure application and I want to pause/resume accepting network connections, calling `l.Accept()` blocks the thread, thus you can't pause in a single-thread program. You can use goroutines but that still isn't ideal, as the routine would still accept the connection first and only then can close it if you're in "pause" mode.

This could be solved by:
- having a non-blocking, async, `l.Accept()`
- returning a handle to (accepting) goroutine and killing/re-creating it from main thread
- accepting connections in a separate process and communicating over a socket

The 1st one doesn't exist, the 2nd one is not accepted by the language designers, and the 3rd one is unnecessarily complex and prone to break.

This looks like a shortcoming of golang, is it worth discussing further with lang designers?

Kurtis Rader

unread,
Jul 24, 2023, 1:40:39 AM7/24/23
to David N, golan...@googlegroups.com
I think we are going to need more context. If you were able to pause net.Listen().Accept() the kernel's listen queue would eventually fill and the kernel would reject any new connection requests. And when you resumed accepting connections if enough time had elapsed those old connection requests would no longer be valid. I don't see why you need any of the three solutions you proposed. Why not simply set a flag that indicates whether new connections should be handled? If the flag is false simply accept the connection request then close the connection (or do whatever else makes sense). I read your StackOverflow question and am still perplexed what problem you are trying to solve.

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CAN7%3DS7htWfYUQmd3H8GiWoWSaei1qU-FMcpqdyccFkXN1kmsWg%40mail.gmail.com.


--
Kurtis Rader
Caretaker of the exceptional canines Junior and Hank

Bakul Shah

unread,
Jul 24, 2023, 2:10:14 AM7/24/23
to David N, golan...@googlegroups.com
You can do a non-blocking select on a channel prior to l.Accept(). If there is a pause message, you do a blocking select on the same channel for an resume or finish message. A separate goroutine can send you those messages depending on conditions under which you want to pause or resume.

If the above doesn't make sense write a sample program on play.golang.org, which does roughly want you want except for pause/resume, and post a link here and we can modify it for pause/resume.

David N

unread,
Jul 24, 2023, 3:14:34 AM7/24/23
to golan...@googlegroups.com
I see, so let's take a step back, I want to pause/resume `net.Listen()`. Unlike a web server, my application doesn't need to always be on, in fact it only comes online once the user decides, responds to the requests, and would sleep again until needed - when given signal again by the user (and not the network).

Thus, I need to be able to show that no packet is transmitted in the hibernate stage, as it could *potentially* leak sensitive data. The flag approach makes sense, but it's not 100% secure, as the machine would still be sending SYN & ACK packets.

Does that make sense?

Jan Mercl

unread,
Jul 24, 2023, 3:20:00 AM7/24/23
to David N, golan...@googlegroups.com
On Mon, Jul 24, 2023 at 9:14 AM David N <dano...@gmail.com> wrote:

On Linux you may try fiddling with iptables, limitations apply:
https://stackoverflow.com/questions/44464617/stop-accepting-new-tcp-connections-without-dropping-any-existing-ones/44509993#44509993

David N

unread,
Jul 24, 2023, 3:22:12 AM7/24/23
to Bakul Shah, golan...@googlegroups.com
I've posted a snippet in the so question:

```go
l, err := net.Listen("tcp", ":2000")
if err != nil {
  log.Fatal(err)
}

for {
    conn, err := l.Accept() // BLOCKING HERE
    ...
}
```

iiuc, your solution only checks on the start as eventually you have to call `l.Accept()` and be blocked again.

you can modify the above code in any way where it'd receive a signal (e.g. Ctrl+C) and breaks out of either `l.Accept` or stops `net.listen`, either works.

David N

unread,
Jul 24, 2023, 3:27:09 AM7/24/23
to Jan Mercl, golan...@googlegroups.com
Yup, this makes sense and should work, but I'm still surprised this can't be entirely done in Golang.

Jan Mercl

unread,
Jul 24, 2023, 3:39:47 AM7/24/23
to David N, golan...@googlegroups.com
On Mon, Jul 24, 2023 at 9:26 AM David N <dano...@gmail.com> wrote:

> Yup, this makes sense and should work, but I'm still surprised this can't be entirely done in Golang.

Who says it's not possible? I'm not aware of a reason why the required
parts cannot be implemented in pure Go (+ syscalls + right permission
bits): https://git.netfilter.org/iptables/

Alternatively, if CGo is not a problem, libiptables is a thing.

Marvin Renich

unread,
Jul 24, 2023, 9:43:42 AM7/24/23
to golan...@googlegroups.com
* David N <dano...@gmail.com> [230724 01:11]:
> I've posted this question on stackoverflow
> <https://stackoverflow.com/questions/76447195/how-to-suspend-and-resume-accepting-new-connections-in-net-listener>,
I think a much more robust solution, which doesn't require any of the
tricks mentioned so far in this thread, would be to have a goroutine
that loops waiting for a signal (e.g. from a chan) and then uses
ListenConfig to create a Listener with a Context. When you want to
pause, simply use the Context to cancel the Listener. When you want to
resume, send the signal.

...Marvin

Reply all
Reply to author
Forward
0 new messages