Go TCP Listener ACL - go

I realise I have a lot of invalid requests hitting my HTTP server but these are at TCP session and has not gone pass TLS handshake, hence no HTTP request yet. (I can't block it at HTTP layer).
I've written the below to filter malicious traffic at TCP Listener but I think its not optimum, the connection is first accepted and then closed, I like to completely not accept the connection if it comes from a known IP address. The next best is to do it at IPtables/NFtables, but I like to explore if I can filter remote addr prior to conn established at TCP Listener. I try looking at the NET package, and looks like its in the File Descriptor which isn't something easy to do.
func main() {
// listen for incoming connections.
l, err := net.Listen(CONN_TYPE, CONN_HOST+":"+CONN_PORT)
if err != nil {
fmt.Println("Error listening:", err.Error())
os.Exit(1)
}
// Close the listener when application closes.
defer l.Close()
fmt.Println("listening on ", CONN_PORT)
for {
//listen for an incoming connection.
conn, err := l.Accept()
if err != nil {
fmt.Println("Error accepting: ", err.Error())
os.Exit(1)
}
fmt.Println(conn.RemoteAddr())
p := fmt.Sprintln(conn.RemoteAddr())
ip := strings.Split(p, ":")[0]
if ip == "127.0.0.1" {
conn.Close()
}
// Handle connections in a new goroutine.
go handleRequest(conn)
}
}

Related

Given a TCP server, how to get the connection domain address

I have a simple TCP server and, when a client connects, I want to get the domain address used to connect:
package main
import (
"fmt"
"net"
"os"
)
const (
CONN_HOST = "localhost"
CONN_PORT = "3333"
CONN_TYPE = "tcp"
)
func main() {
// Listen for incoming connections.
l, err := net.Listen(CONN_TYPE, CONN_HOST+":"+CONN_PORT)
if err != nil {
fmt.Println("Error listening:", err.Error())
os.Exit(1)
}
// Close the listener when the application closes.
defer l.Close()
fmt.Println("Listening on " + CONN_HOST + ":" + CONN_PORT)
for {
// Listen for an incoming connection.
conn, err := l.Accept()
if err != nil {
fmt.Println("Error accepting: ", err.Error())
os.Exit(1)
}
// Handle connections in a new goroutine.
go handleRequest(conn)
}
}
// Handles incoming requests.
func handleRequest(conn net.Conn) {
// Make a buffer to hold incoming data.
buf := make([]byte, 1024)
// Read the incoming connection into the buffer.
_, err := conn.Read(buf)
if err != nil {
fmt.Println("Error reading:", err.Error())
}
// Send a response back to person contacting us.
conn.Write([]byte("Message received."))
// Close the connection when you're done with it.
conn.Close()
}
I tried debugging the conn net.Conn param but I can't find any reference to the domain address. Tried with http://test.127.0.0.1.xip.io:3333/ and I'm interested in getting test.127.0.0.1.xip.io somehow. Any ideas?
What you are trying to do is not possible with plain TCP. TCP works on plain IP-Addresses without domains.
To explain what is going on:
When you are establishing a connection to, e.g. example.com, first of all a DNS Lookup for example.com is done. In this case, the DNS Lookup would result in 93.184.216.34. You can read more about DNS here.
A TCP Connection with 93.184.216.34 is established after that, the original domain name is not sent with the request.
Because you sometimes need the original name the user was trying to connect to, some protocols send the domain name after connecting. HTTP for example does this via the Host header.
Maybe you can do something like that and require to send the original host first through your TCP Connection!

"connect: connection refused" while attempting to connect to localhost

I'm currently attempting to create a TCP service that will just log/store whatever is sent to it. I can't seem to understand why I cannot connect to my localhost using DialTCP. I keep getting
dial tcp 127.0.0.1:8080: connect: connection refused
func main() {
errCh := make(chan error)
tcpAddr, _ := net.ResolveTCPAddr("tcp", "localhost:8080")
for {
conn, err := net.DialTCP("tcp", nil, tcpAddr)
if err != nil {
log.Println("Could not connect -> ", err.Error())
} else {
recordMessage(conn, errCh)
err = <-errCh
log.Println("Error", err)
conn.Close()
}
log.Println("trying again in 10 seconds..")
time.Sleep(30 * time.Second)
}
}
I looked over my Firewall settings and noting seems to be blocking it. I'm still not sure if its due to something related to my Firewall or if I'm just missing something super obvious.
Start by running this Go program in a terminal -- it listens to port 2000 but you could change it to 8080 or whatever you wish:
func main() {
// Listen on TCP port 2000 on all interfaces.
l, err := net.Listen("tcp", ":2000")
if err != nil {
log.Fatal(err)
}
defer l.Close()
for {
// Wait for a connection.
conn, err := l.Accept()
if err != nil {
log.Fatal(err)
}
// Handle the connection in a new goroutine.
// The loop then returns to accepting, so that
// multiple connections may be served concurrently.
go func(c net.Conn) {
log.Println(c)
// Echo all incoming data.
io.Copy(c, c)
// Shut down the connection.
c.Close()
}(conn)
}
}
Then in a separate terminal run this simple client:
func main() {
var addr string
if len(os.Args) > 1 {
addr = os.Args[1]
} else {
addr = "localhost:2000"
}
conn, err := net.Dial("tcp", addr)
if err != nil {
log.Fatal(err)
// handle error
}
fmt.Fprintf(conn, "foobar")
conn.Close()
}
Asking it to connect to the same port. The connection should succeed and you should see the server logging something.
Now try to connect with your client.
Without writing Go, you could to these things with the nc command-line tool (netcat). nc -lv PORT creates a simple listening server on PORT, for example.

Unusually High Amount of TCP Connection Timeout Errors

I am using a Go TCP Client to connect to our Go TCP Server.
I am able to connect to the Server and run commands properly, but every so often there will be an unusually high amount of consecutive TCP connection errors reported by my TCP Client when trying to either connect to our TCP Server or sending a message once connected:
dial tcp kubernetes_node_ip:exposed_kubernetes_port:
connectex: A connection attempt failed because the connected party did not properly
respond after a period of time, or established connection failed because connected
host has failed to respond.
read tcp unfamiliar_ip:unfamiliar_port->kubernetes_node_ip:exposed_kubernetes_port
wsarecv: A connection attempt failed because the connected party did not properly
respond after a period of time, or established connection failed because connected
host has failed to respond.
I say "unusually high" because I assume that the number of times these errors occur should be very minimal (about 5 or less within the hour). Note that I am not dismissing the possibility of this being caused by connection instabilities, as I have also noticed that it is possible to run several commands in rapid succession without any errors.
However, I am still going to post my code in case I am doing something wrong.
Below is the code that my TCP Client uses to connect to our server:
serverAddress, err := net.ResolveTCPAddr("tcp", kubernetes_ip+":"+kubernetes_port)
if err != nil {
fmt.Println(err)
return
}
// Never stop asking for commands from the user.
for {
// Connect to the server.
serverConnection, err := net.DialTCP("tcp", nil, serverAddress)
if err != nil {
fmt.Println(err)
continue
}
defer serverConnection.Close()
// Added to prevent connection timeout errors, but doesn't seem to be helping
// because said errors happen within just 1 or 2 minutes.
err = serverConnection.SetDeadline(time.Now().Add(10 * time.Minute))
if err != nil {
fmt.Println(err)
continue
}
// Ask for a command from the user and convert to JSON bytes...
// Send message to server.
_, err = serverConnection.Write(clientMsgBytes)
if err != nil {
err = merry.Wrap(err)
fmt.Println(merry.Details(err))
continue
}
err = serverConnection.CloseWrite()
if err != nil {
err = merry.Wrap(err)
fmt.Println(merry.Details(err))
continue
}
// Wait for a response from the server and print...
}
Below is the code that our TCP Server uses to accept client requests:
// We only supply the port so the IP can be dynamically assigned:
serverAddress, err := net.ResolveTCPAddr("tcp", ":"+server_port)
if err != nil {
return err
}
tcpListener, err := net.ListenTCP("tcp", serverAddress)
if err != nil {
return err
}
defer tcpListener.Close()
// Never stop listening for client requests.
for {
clientConnection, err := tcpListener.AcceptTCP()
if err != nil {
fmt.Println(err)
continue
}
go func() {
// Add client connection to Job Queue.
// Note that `clientConnections` is a buffered channel with a size of 1500.
// Since I am the only user connecting to our server right now, I do not think
// this is a channel blocking issue.
clientConnections <- clientConnection
}()
}
Below is the code that our TCP Server uses to process client requests:
defer clientConnection.Close()
// Added to prevent connection timeout errors, but doesn't seem to be helping
// because said errors happen within just 1 or 2 minutes.
err := clientConnection.SetDeadline(time.Now().Add(10 * time.Minute))
if err != nil {
return err
}
// Read full TCP message.
// Does not stop until an EOF is reported by `CloseWrite()`
clientMsgBytes, err := ioutil.ReadAll(clientConnection)
if err != nil {
err = merry.Wrap(err)
return nil, err
}
// Process the message bytes...
My questions are:
Am I doing something wrong in the above code, or is the above decent enough for basic TCP Client-Server operations?
Is it okay that both the TCP Client and TCP Server have code that defers closing their one connection?
I seem to recall that calling defer inside a loop does nothing. How do I properly close Client connections before starting new ones?
Some extra information:
Said errors are not logged by the TCP Server, so aside from
connection instabilities, this might also be a
Kubernetes/Docker-related issue.
It seems this piece of code does not act as you think it does. The defer statement on the connection close will only happen when the function returns, not when an iteration ends. So as far as I can see here, you are creating a lot of connections on the client side, it could be the problem.
serverAddress, err := net.ResolveTCPAddr("tcp", kubernetes_ip+":"+kubernetes_port)
if err != nil {
fmt.Println(err)
return
}
// Never stop asking for commands from the user.
for {
// Connect to the server.
serverConnection, err := net.DialTCP("tcp", nil, serverAddress)
if err != nil {
fmt.Println(err)
continue
}
defer serverConnection.Close()
// Added to prevent connection timeout errors, but doesn't seem to be helping
// because said errors happen within just 1 or 2 minutes.
err = serverConnection.SetDeadline(time.Now().Add(10 * time.Minute))
if err != nil {
fmt.Println(err)
continue
}
// Ask for a command from the user and send to the server...
// Wait for a response from the server and print...
}
I suggest to write it this way:
func start() {
serverAddress, err := net.ResolveTCPAddr("tcp", kubernetes_ip+":"+kubernetes_port)
if err != nil {
fmt.Println(err)
return
}
for {
if err := listen(serverAddress); err != nil {
fmt.Println(err)
}
}
}
func listen(serverAddress string) error {
// Connect to the server.
serverConnection, err := net.DialTCP("tcp", nil, serverAddress)
if err != nil {
fmt.Println(err)
continue
}
defer serverConnection.Close()
// Never stop asking for commands from the user.
for {
// Added to prevent connection timeout errors, but doesn't seem to be helping
// because said errors happen within just 1 or 2 minutes.
err = serverConnection.SetDeadline(time.Now().Add(10 * time.Minute))
if err != nil {
fmt.Println(err)
return err
}
// Ask for a command from the user and send to the server...
// Wait for a response from the server and print...
}
}
Also, you should keep a single connection open, or a pool of connections, instead of opening and closing the connection right away. Then when you send a message you get a connection from the pool (or the single connection), and you write the message and wait for the response, then you release the connection to the pool.
Something like that:
res, err := c.Send([]byte(`my message`))
if err != nil {
// handle err
}
// the implementation of send
func (c *Client) Send(msg []byte) ([]byte, error) {
conn, err := c.pool.Get() // returns a connection from the pool or starts a new one
if err != nil {
return nil, err
}
// send your message and wait for response
// ...
return response, nil
}

Retrieve uri path from net.Conn

I'm working with someone else's code and I need some assistance.
Here we have a tcp load balancer. What I need is access to the request uri from this piece of code before we do the net dial.
I looked through the API Documentation here: https://golang.org/pkg/net/ but was unable to find any relevant methods under the net.Conn namespace for retrieving the current request path.
func copy(wc io.WriteCloser, r io.Reader) {
defer wc.Close()
io.Copy(wc, r)
}
func handleConnection(us net.Conn, backend BA.Backend) {
if backend == nil {
log.Printf("no backend available for connection from %s", us.RemoteAddr())
us.Close()
return
}
ip:=us.RemoteAddr().String()
parts:=strings.Split(ip,":")
ip=parts[0]
//w := bufio.NewWriter(us)
//w.WriteString(+"\n")
//w.Flush()
ds, err := net.Dial("tcp", backend.String())
if err != nil {
log.Printf("failed to dial %s: %s", backend, err)
us.Close()
return
}
// Ignore errors
go copy(ds, us)
go copy(us, ds)
}
func tcpBalance(bind string, backends BA.Backends) error {
log.Println("using tcp balancing")
ln, err := net.Listen("tcp", bind)
if err != nil {
return fmt.Errorf("failed to bind: %s", err)
}
log.Printf("listening on %s, balancing %d backends", bind, backends.Len())
for {
conn, err := ln.Accept()
if err != nil {
log.Printf("failed to accept: %s", err)
continue
}
go handleConnection(conn, backends.Choose())
}
return err
}
This is not possible because not every TCP connection is an HTTP connection and the TCP protocol has no concept of URIs. Many other protocols are built on TCP and it's not that protocol's responsibility to know about them.
HTTP is an Application Layer (layer 7) protocol which uses the TCP Transport Layer (layer 4) protocol. As such, TCP connections have no concept of HTTP because lower layer protocols have no concept of the layers that may be built on top of them.
You can learn more by reading about the OSI model.

How to make net.Dial in Go reconnect if connection is lost?

I have an app in Go that's connecting to XMPP host using tcp and then xml Decoder to talk XMPP. How can I make net.Dial reconnect if tcp connection is dropped?
I am getting the following error on my error channel when the connection is dropped:
write tcp client:port->xmpp_server:5222: write: broken pipe. However I'm not sure how to properly handle it in my Dial function to make it reconnect.
// package xmpp
// Conn represents a connection
type Conn struct {
incoming *xml.Decoder
outgoing net.Conn
errchan chan error
}
// SetErrorChannel sets the channel for handling errors
func (c *Conn) SetErrorChannel(channel chan error) {
c.errchan = channel
}
// Dial dials an xmpp host
func Dial(host string) (*Conn, error) {
c := new(Conn)
var err error
c.outgoing, err = net.Dial("tcp", host+":5222")
if err != nil {
log.Printf("Can't dial %s:5222: %s", host, err)
return c, err
}
// TCP Keep Alive
err = c.outgoing.(*net.TCPConn).SetKeepAlive(true)
if err != nil {
c.errchan <- err
}
err = c.outgoing.(*net.TCPConn).SetKeepAlivePeriod(30 * time.Second)
if err != nil {
c.errchan <- err
}
c.incoming = xml.NewDecoder(c.outgoing)
log.Printf("Connected to: %s", c.outgoing.RemoteAddr())
return c, nil
}
// In a separate package
func NewXMPPClient(config) (*Client, error) {
errchannel := make(chan error)
connection, err := xmpp.Dial(host)
if err != nil {
return nil, err
}
connection.SetErrorChannel(errchannel)
// Do XMPP auth, receive messages, etc...
Figured it out. I just started to close the current tcp connection on any error in my error channel and re-create both TCP and XMPP (auth+listen) connections.

Resources