mirror of
https://github.com/therootcompany/golib.git
synced 2026-03-02 23:57:59 +00:00
chore(cmd/tcpfwd): minor cleanup, add license, lint
This commit is contained in:
parent
3e4ce3ac91
commit
d30ceb004d
@ -1,3 +1,15 @@
|
|||||||
|
// tcpfwd - Accepts and forwards local connections to remote hosts.
|
||||||
|
//
|
||||||
|
// Authored in 2026 by AJ ONeal <aj@therootcompany.com>, assisted by Claude Code.
|
||||||
|
// To the extent possible under law, the author(s) have dedicated all copyright
|
||||||
|
// and related and neighboring rights to this software to the public domain
|
||||||
|
// worldwide. This software is distributed without any warranty.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the CC0 Public Domain Dedication along with
|
||||||
|
// this software. If not, see <https://creativecommons.org/publicdomain/zero/1.0/>.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -18,8 +30,8 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
name = "tcpfwd"
|
name = "tcpfwd"
|
||||||
description = "TCP port forwarder - bridge local ports to remote hosts"
|
description = "Accepts and forwards local connections to remote hosts."
|
||||||
licenseYear = "2025"
|
licenseYear = "2026"
|
||||||
licenseOwner = "AJ ONeal <aj@therootcompany.com> (https://therootcompany.com)"
|
licenseOwner = "AJ ONeal <aj@therootcompany.com> (https://therootcompany.com)"
|
||||||
licenseType = "CC0-1.0"
|
licenseType = "CC0-1.0"
|
||||||
)
|
)
|
||||||
@ -76,8 +88,8 @@ func (e *connEntry) isIdle(now time.Time, threshold time.Duration) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *connEntry) close() {
|
func (e *connEntry) close() {
|
||||||
e.client.Close()
|
_ = e.client.Close()
|
||||||
e.remote.Close()
|
_ = e.remote.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// connRegistry tracks all active connections.
|
// connRegistry tracks all active connections.
|
||||||
@ -265,7 +277,7 @@ func main() {
|
|||||||
for {
|
for {
|
||||||
client, err := bl.Accept()
|
client, err := bl.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isClosedConn(err) {
|
if errors.Is(err, net.ErrClosed) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Printf("Accept error: %v", err)
|
log.Printf("Accept error: %v", err)
|
||||||
@ -284,23 +296,29 @@ func main() {
|
|||||||
|
|
||||||
// Stop accepting new connections
|
// Stop accepting new connections
|
||||||
for _, l := range listeners {
|
for _, l := range listeners {
|
||||||
l.Close()
|
_ = l.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close connections that have been idle longer than idleTimeout
|
// Close connections as they become idle
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
if n := reg.closeIdle(time.Now(), idleTimeout); n > 0 {
|
if n := reg.closeIdle(time.Now(), idleTimeout); n > 0 {
|
||||||
log.Printf("Closed %d idle connection(s) (idle > %s)", n, idleTimeout)
|
log.Printf("Closed %d idle connection(s) (idle > %s)", n, idleTimeout)
|
||||||
}
|
}
|
||||||
|
time.Sleep(250 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
// Wait for remaining active connections to drain, up to shutdownTimeout
|
// Wait for remaining active connections to drain, up to shutdownTimeout
|
||||||
if waitWithTimeout(®.wg, shutdownTimeout) {
|
if waitWithTimeout(®.wg, shutdownTimeout) {
|
||||||
log.Printf("All connections closed cleanly")
|
log.Printf("All connections closed cleanly")
|
||||||
} else {
|
return
|
||||||
|
}
|
||||||
|
|
||||||
log.Printf("Shutdown timeout (%s) exceeded, force-closing remaining connections", shutdownTimeout)
|
log.Printf("Shutdown timeout (%s) exceeded, force-closing remaining connections", shutdownTimeout)
|
||||||
reg.closeAll()
|
reg.closeAll()
|
||||||
reg.wg.Wait()
|
reg.wg.Wait()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// waitWithTimeout waits for wg to reach zero, returning true if it drained
|
// waitWithTimeout waits for wg to reach zero, returning true if it drained
|
||||||
// before the timeout and false if the timeout was exceeded.
|
// before the timeout and false if the timeout was exceeded.
|
||||||
@ -319,7 +337,7 @@ func handleConn(client net.Conn, target string, reg *connRegistry, clock func()
|
|||||||
remote, err := net.Dial("tcp", target)
|
remote, err := net.Dial("tcp", target)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed to connect to %s: %v", target, err)
|
log.Printf("Failed to connect to %s: %v", target, err)
|
||||||
client.Close()
|
_ = client.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -329,8 +347,10 @@ func handleConn(client net.Conn, target string, reg *connRegistry, clock func()
|
|||||||
|
|
||||||
reg.add(entry)
|
reg.add(entry)
|
||||||
defer reg.remove(entry)
|
defer reg.remove(entry)
|
||||||
defer client.Close()
|
defer func() {
|
||||||
defer remote.Close()
|
_ = client.Close()
|
||||||
|
_ = remote.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
log.Printf("New connection %s ↔ %s", client.RemoteAddr(), remote.RemoteAddr())
|
log.Printf("New connection %s ↔ %s", client.RemoteAddr(), remote.RemoteAddr())
|
||||||
|
|
||||||
@ -345,15 +365,10 @@ func handleConn(client net.Conn, target string, reg *connRegistry, clock func()
|
|||||||
// copyAndClose copies until EOF or error, then closes dst.
|
// copyAndClose copies until EOF or error, then closes dst.
|
||||||
func copyAndClose(dst, src net.Conn) error {
|
func copyAndClose(dst, src net.Conn) error {
|
||||||
_, err := io.Copy(dst, src)
|
_, err := io.Copy(dst, src)
|
||||||
dst.Close()
|
_ = dst.Close()
|
||||||
if err != nil && !isClosedConn(err) {
|
if err != nil && !errors.Is(err, net.ErrClosed) {
|
||||||
log.Printf("Copy error (%s → %s): %v",
|
log.Printf("Copy error (%s → %s): %v",
|
||||||
src.RemoteAddr(), dst.RemoteAddr(), err)
|
src.RemoteAddr(), dst.RemoteAddr(), err)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// isClosedConn detects closed-connection errors.
|
|
||||||
func isClosedConn(err error) bool {
|
|
||||||
return errors.Is(err, net.ErrClosed)
|
|
||||||
}
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user