Go server not hearing remote requests - go

I've written a Go server that works perfectly as long as you send it requests from localhost (and addressed to localhost), but it doesn't work when you try to access it from a browser (from a different computer) or even just directed at the external IP address. I want to be able to access it as an external server, not just locally. Why can't it?
The (pared down) source code:
package main
import (
"fmt"
"net"
"os"
)
func main() {
// Listen for incoming connections.
l, err := net.Listen("tcp", "localhost:2082")
if err != nil {
fmt.Println("Error listening:", err.Error())
os.Exit(1)
}
// Close the listener when the application closes.
defer l.Close()
for {
// Listen for an incoming connection.
_, err := l.Accept()
if err != nil {
fmt.Println("Error accepting: ", err.Error())
os.Exit(1)
}
fmt.Println("Incoming connection")
}
}
When you curl localhost:2082, it says "Incoming connection".
When you curl mydomain.com:2082, it does nothing.
The port is forwarded. I'm sure of this because I ran a (node.js) web server from that port, and it worked fine. If it's related, I'm running on Ubuntu 12.04 on an Amazon EC2 instance.
I'd appreciate any help. Thanks!

One way to listen to any incoming IP (not just localhost, mapped by default to 127.0.0.1) would be:
net.Listen("tcp", ":2082")
You also have the function net/http/#ListenAndServe, which allows you to trigger listen on multiple specific ip if you want.
go http.ListenAndServe("10.0.0.1:80", nil)
http.ListenAndServe("10.0.0.2:80", nil)
A good example can be seen in "A Recap of Request Handling in Go".

Related

Unable to get the Socks Proxy working Golang applications

I am running a golang application on my local laptop, which connects with the Service APIs from a kubernetes cluster. To allow the communication between my laptop and Service APIs on Kubernetes Cluster, I have setup the Socks5 proxy and Able to connect with all services over CURL command.
But I am unable to set same proxy in the Golang application. I have tried various options already
Settings env vars - tried setting these 3 at OS level, App level but it did not work
http_proxy
https_proxy
all_proxy
I am running on Ubuntu Desktop 20.X, so I tried setting Socks proxy at OS Network level as well. All other apps using proxy, but golang isnt picking that up.
I tried setting the http.transport level configs too, but it didnt helped.
func InsecureTLSTransport() *http.Transport {
// START - Only for Proxy - Dev Mode.
var dialer, err = proxy.SOCKS5("socks5", "<IP:port>", nil, proxy.Direct)
if err != nil {
fmt.Fprintln(os.Stderr, "can't connect to the proxy:", err)
}
return &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
Dial: dialer.Dial,
}
}
I want the socks5 Proxy to be used by my golang app at runtime. Any suggestions?
you should use tcp instead of socks5 in the network parameter.
package main
import (
"fmt"
"golang.org/x/net/proxy"
)
func main() {
d, err := proxy.SOCKS5("tcp", "<IP:port>", nil, proxy.Direct) // <-- here
if err != nil {
fmt.Println(err)
return
}
c, err := d.Dial("tcp", "https://google.com")
if err != nil {
fmt.Println(err)
return
}
defer c.Close()
}

I'm trying to build a simple proxy with net package, but the upstream is not sending any data back when I don't use go routines

I wrote this simple proxy server with net package, which I expected to proxy connections from a local server at 8001 to any incoming connections via 8000. When I go to the browser and try it, I get a refused to connect error.
package main
import (
"net"
"log"
"io"
)
func main() {
l, err := net.Listen("tcp", "localhost:8000")
if err != nil {
log.Fatal(err)
}
for {
conn, err := l.Accept()
if err != nil {
log.Fatal(err)
}
go proxy(conn)
}
}
func proxy(conn net.Conn) {
defer conn.Close()
upstream, err := net.Dial("tcp","localhost:8001")
if err != nil {
log.Print(err)
return
}
defer upstream.Close()
io.Copy(upstream, conn)
io.Copy(conn, upstream)
}
But if I change the following lines in the proxy function
io.Copy(upstream, conn)
io.Copy(conn, upstream)
to
go io.Copy(upstream, conn)
io.Copy(conn, upstream)
then it works as expected. Shouldn't the io.Copy(upstream, conn) block the io.Copy(conn, upstream)? As per my understanding, the conn should be written only after upstream has responded back? And how does having a go routine for io.Copy(upstream, conn) part solve this?
Shouldn't io.Copy block?
Yes. "Copy copies from src to dst until either EOF is reached on src or an error occurs.". Since this is a network connection, this means it returns after the client closes the connection. If and when the client closes the connection depends on the application protocol. In HTTP it may never happen, for instance.
How does having a goroutine solve this?
Because then the second Copy can execute while the client is still connected, allowing the upstream to write its response. Without the goroutine nothing is reading from the upstream, so it is likely blocked on its write call.
The client (presumably) waits for a response, the proxy waits for the client to close the connection, and the upstream waits for the proxy to start reading the response: no one can make progress and you're in a deadlock.

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!

Go net.dial issue

I'm having some issues connecting to a local golang TLS server via tls.dial or net.dial. The server ist started with the address localhost:10001 and I am able to connect to it with netcat (simply netcat localhost 10001 ) but trying it with golangs's dial method doesn't work (connection refused). What could be the reason for this? One important thing to point out is that I'm testing it on a Debian VM where I deinstalled the network manager so I could configure the network interfaces myself (static ip). My guess is that net.dial has some issues finding the right interface but what does netcat do that golang's methods don't? I tried all different kinds of addresses on both sides (server on localhost, ::1, 127.0.0.1; client same). On my windows host system it works (so the issue is probably not with the server).
Thanks in advance.
conn, err := tls.Dial("tcp", h.IP+":"+h.Port, conf)
if err != nil {
log.Println(err)
return empty
}
// do cleanup
defer conn.Close()
d := Craft_PKG( data )
//write package
WriteChunks( conn, d )
this is the client code and this
ln, err := tls.Listen("tcp", "localhost:"+(*port), config)
if err != nil {
log.Println(err)
return err
}
defer ln.Close()
for {
conn, err := ln.Accept()
if err != nil {
log.Println(err)
continue
}
// start the handler for every incoming connection
go h(conn)
}
the server code. It is all very straightforward and works with netcat and in my Host system as I mentioned.

SSH Reverse Tunnel with GO

I am trying to write a server / client that can help get around Firewalls / Nat Issues.
I noticed SSH has built into support for doing this already.
(http://rustyrazorblade.com/2010/03/ssh-reverse-tunnel-to-access-box-behind-firewall/)
I tried a few different SSH examples and none seem to be working. I found one project that says it implemented the Remote Port Fowarding -> https://godoc.org/dev.justinjudd.org/justin/easyssh
The Server says it is Listening for connections but I am unable to SSH from Server Machine To Client Machine. (ssh localhost 8080 on remote machine should forward to client machine.
Client ->
package main
import (
"log"
"dev.justinjudd.org/justin/easyssh"
"golang.org/x/crypto/ssh"
)
func main() {
config := &ssh.ClientConfig{
User: "test",
Auth: []ssh.AuthMethod{
ssh.Password("test"),
},
}
conn, err := easyssh.Dial("tcp", "*SSH-SERVER*:22", config)
if err != nil {
log.Fatalf("unable to connect: %s", err)
}
defer conn.Close()
err = conn.RemoteForward("0.0.0.0:8080", "127.0.0.1:22")
if err != nil {
log.Fatalf("unable to forward local port: %s", err)
}
}
Server ->
package main
import (
"fmt"
"io/ioutil"
"log"
"dev.justinjudd.org/justin/easyssh"
"golang.org/x/crypto/ssh"
)
func main() {
privateBytes, err := ioutil.ReadFile("id_rsa")
if err != nil {
log.Fatal("Failed to load private key (./id_rsa)")
}
private, err := ssh.ParsePrivateKey(privateBytes)
if err != nil {
log.Fatal("Failed to parse private key")
}
config := &ssh.ServerConfig{
PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
if c.User() == "test" && string(pass) == "test" {
log.Printf("User logged in: %s", c.User())
return nil, nil
}
return nil, fmt.Errorf("password rejected for %s", c.User())
},
}
config.AddHostKey(private)
easyssh.HandleChannel(easyssh.SessionRequest, easyssh.SessionHandler())
easyssh.HandleChannel(easyssh.DirectForwardRequest, easyssh.DirectPortForwardHandler())
easyssh.HandleRequestFunc(easyssh.RemoteForwardRequest, easyssh.TCPIPForwardRequest)
easyssh.ListenAndServe(":22", config, nil)
}
I found a bug related to remote port forwarding in easyssh:
https://dev.justinjudd.org/justin/easyssh/src/master/tcpip.go#L107
the ssh.DiscardRequests(reqs) should be run in a separated goroutine, or else the next data transfer will not be executed.
I'm not sure that you understand how SSH tunneling works looking on your code.
You need to have SSH connectivity to the remote (server).
Then you setup SSH tunnel so local TCP:8080 port will be forwarded to the remote server TCP:8080 port using SSH connection. Actual 8080 port can be closed via firewall.
Can you connect from your client to your server with SSH?
You need to check localhost:8080 port and you need to be sure that your server 8080 port is listened by some application too.
Take a look here for some examples and theory.

Resources