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!
Related
can someone recommend me a communication protocol that can connect 2 Golang programs with different IP address (other devices) ? Because when I try Socket programming in Golang, it can only connect programs on localhost.
if you want to run a server on your home network which is probably behind a NAT and connect to it from outside of you home network
first:
you need to bind your server socket to your local ip address which might be something
like 192.168.... and listen to it
second:
when systems outside of your network send packets to your server they send it to your
public Ip which you can find by googling "what is my ip" and therefore your router
has no idea what local ip address it should forward the packet to that is why you
need to do Port Forwarding which basically tells the router "hey when ever you
received a packet on port "n" send it to a system with the ip address of "x.x.x.x".
so if you local ip is 192.168.1.10 and your public ip is 5.68.125.48 and you are listening on port 8080 on your router setup page you forward port 8080 to 192.168.1.10 and on the client side you connect and send packets to 5.68.125.48:8080 now the router knows who on the local network should receive the packet
You can try a solution like this:
package main
import (
"bufio"
"fmt"
"net"
"strconv"
"time"
)
func main() {
fmt.Println("Server started...")
ln, err := net.Listen("tcp", ":8000")
if err != nil {
fmt.Println("Error starting socket server: " + err.Error())
}
for {
conn, err := ln.Accept()
if err != nil {
fmt.Println("Error listening to client: " + err.Error())
continue
}
fmt.Println(conn.RemoteAddr().String() + ": client connected")
go receiveData(conn)
go sendData(conn)
}
}
func sendData(conn net.Conn) {
i := 0
for {
_, err := fmt.Fprintf(conn, strconv.Itoa(i)+". data from server\n")
i++
if err != nil {
fmt.Println(conn.RemoteAddr().String() + ": end sending data")
return
}
time.Sleep(time.Duration(1) * time.Second)
}
}
func receiveData(conn net.Conn) {
for {
message, err := bufio.NewReader(conn).ReadString('\n')
if err != nil {
fmt.Println(conn.RemoteAddr().String() + ": client disconnected")
conn.Close()
fmt.Println(conn.RemoteAddr().String() + ": end receiving data")
return
}
fmt.Print(conn.RemoteAddr().String() + ": received " + message)
}
}
I'm trying to create a reverse proxy to a CONNECT-based HTTP proxy. The user who wants to use the proxy just treats machine A as an HTTP proxy. It works the following way:
machine B opens a TCP socket to machine A.
On machine A, a TCP socket is exposed on a port and all the incoming data is tunneled to machine B (io.Copy).
On machine B, all the data is tunneled to the local HTTP server and the socket to machine A.
Essentially this is a reverse-proxy behind an HTTP proxy. The reason it's this complex is because the HTTP proxy is behind NAT (on machine B) and therefore not accessible directly. The use case is being able to host an HTTP proxy behind a NAT.
Machine A tunnel (Go):
package main
import (
"log"
"net"
)
func Conn(c *net.TCPConn) string {
return c.RemoteAddr().String() + " (" + c.LocalAddr().String() + ")"
}
func ProxifyConns(recipientConn, donorConn *net.TCPConn) {
log.Println("Proxying", ConnrecipientConn), "and", Conn(donorConn))
go func() {
_, err := io.Copy(recipientConn, donorConn)
if err != nil {
utils.StacktraceError(err)
}
recipientConn.Close()
}()
go func() {
_, err := io.Copy(donorConn, recipientConn)
if err != nil {
utils.StacktraceError(err)
}
recipientConn.Close()
}()
}
func main() {
// Open the donor listener
donorsAddr, err := net.ResolveTCPAddr("tcp4", ":11000")
if err != nil {
utils.StacktraceErrorAndExit(err)
}
listenerDonors, err := net.ListenTCP("tcp", donorsAddr)
if err != nil {
utils.StacktraceErrorAndExit(err)
}
defer listenerDonors.Close()
log.Println("Listening for donors on", listenerDonors.Addr())
// Open the recipient listener
recipientsAddr, err := net.ResolveTCPAddr("tcp4", ":10000")
if err != nil {
utils.StacktraceErrorAndExit(err)
}
listenerRecipients, err := net.ListenTCP("tcp", recipientsAddr)
if err != nil {
utils.StacktraceErrorAndExit(err)
}
defer listenerRecipients.Close()
log.Println("Listening for recipients on", listenerRecipients.Addr())
// Handle donor connections
donorConns := make(chan *net.TCPConn)
go func() {
for {
donorConn, err := listenerDonors.AcceptTCP()
donorConn.SetKeepAlive(true)
if err != nil {
utils.StacktraceErrorAndExit(err)
return
}
log.Println("New donor connection from", Conn(donorConn))
donorConns <- donorConn
}
}()
// Handle recipient connections
for {
recipientConn, err := listenerRecipients.AcceptTCP()
recipientConn.SetKeepAlive(true)
if err != nil {
utils.StacktraceErrorAndExit(err)
return
}
log.Println("New recipient connection from", Conn(recipientConn))
donorConn := <-donorConns
proxy.ProxifyConns(recipientConn, donorConn)
}
}
Machine B tunnel (Node.js):
import net, { AddressInfo } from 'net';
import http from 'http';
import golgi from 'golgi';
export const startHttpProxy = () => {
const server = http.createServer();
let proxyServer: http.Server = golgi(server);
// Listening to 0 assigns a random OS-assigned port
proxyServer = proxyServer.listen(0);
return proxyServer;
};
export const startDonorSocket = () => {
const proxyServer = startHttpProxy();
const proxyServerSocket = new net.Socket();
proxyServerSocket.connect(
(proxyServer.address() as AddressInfo).port,
'127.0.0.1'
);
const donorSocket = new net.Socket();
donorSocket.setKeepAlive(true);
donorSocket.connect(11000, '2.226.102.14', () => {
proxyServerSocket.pipe(donorSocket);
donorSocket.pipe(proxyServerSocket);
});
};
Unfortunately this works when tunneling to one TCP address but not when tunneling to more. If I open many Machine B tunnels (Node.js code), it works. What I mean is that a donor connection (Node.js) is "consumed" ever time it is taken by a recipient (HTTP proxy user) because a persistent TCP tunnel is made on it.
I wonder is there is a way to make this work for any amount of TCP connections, not just one. My only idea right now is to create more TCP donor connections every time a connection is consumed but I wonder if there is a simpler solution.
When you do
go func() {
for {
donorConn, err := listenerDonors.AcceptTCP()
donorConn.SetKeepAlive(true)
if err != nil {
utils.StacktraceErrorAndExit(err)
return
}
log.Println("New donor connection from", Conn(donorConn))
donorConns <- donorConn
}
}()
You start processing the first TCP connection. This code blocks on donorConns <- donorConn. Until this send to channel finishes the loop won't go into the second iteration (and the next TCP connection won't be accepted).
You do a very similar second loop
// Handle recipient connections
for {
recipientConn, err := listenerRecipients.AcceptTCP()
recipientConn.SetKeepAlive(true)
if err != nil {
utils.StacktraceErrorAndExit(err)
return
}
log.Println("New recipient connection from", Conn(recipientConn))
donorConn := <-donorConns
proxy.ProxifyConns(recipientConn, donorConn)
}
which requires donorConn := <-donorConns to complete (from the first loop) and requires proxy.ProxifyConns(recipientConn, donorConn) to complete.
I'm not sure how you intend the whole thing to work, but, most likely, you need a very minor change:
go proxy.ProxifyConns(recipientConn, donorConn)
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)
}
}
I want Get Client Cache DNS IP using Go
Look at the code I tried below
import (
"fmt"
"net"
)
func main() {
// Usually DNS Server using 53 port number
// This case, TCP protocol is not considered
port := ":53"
protocol := "udp"
var buf [2048]byte
//Build the address
udpAddr, err := net.ResolveUDPAddr(protocol, port)
if err != nil {
fmt.Println("Wrong Address")
return
}
fmt.Println("Listened " + protocol + " from " + udpAddr.String())
//Create the connection
udpConn, err := net.ListenUDP(protocol, udpAddr)
if err != nil {
fmt.Println(err)
}
// Listening 53 Port Like DNS Server
for {
// If get request,
_, err := udpConn.Read(buf[0:])
if err != nil {
fmt.Println("Error Reading")
return
} else {
// Print Remote Address,
// I Guess this is the Client Cache DNS IP, but this is print <nil>
fmt.Println(udpConn.RemoteAddr())
}
}
}
How do I get the Client Cache DNS IP in this case? Pleas Help me
I Want to Build Client DNS IP Collector, seem whoami
I also refer to this as https://github.com/miekg/exdns/blob/master/reflect/reflect.go
but this is not answer for me
I want simple server
UDP is stateless. There is no single client address for a connection. Each packet can be sent from a different address, so RemoteAddr is only useful on the client, but not the server.
Use one of *UDPConn.ReadFrom, *UDPConn.ReadFromUDP, or *UDPConn.ReadMsgUDP instead of Read. All of them return the client address for the read packet.
I found this example https://play.golang.org/p/zyZJKGFfyT
package main
import (
"fmt"
"net"
"os"
)
// echo "Hello server" | nc localhost 5555
const (
CONN_HOST = "localhost"
CONN_PORT = "5555"
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.
reqLen, err := conn.Read(buf)
reqLen = reqLen
if err != nil {
fmt.Println("Error reading:", err.Error())
}
// Send a response back to person contacting us.
conn.Write([]byte("hello") )
conn.Close()
}
echo "test" | nc 127.0.0.1 5555
What is the best way to keep a TCP server with GO listening in production?
in localhost work fine but production
Taking out my crystal ball: I believe your problem is that your server is only listening on localhost, but you want to be able to connect to it from other machines. Change CONN_HOST from "localhost" to "" (empty string), so that net.Listen will be listening on :5555. That means that connections will be accepted on any interface on port 5555.