Golang telnet client example

6,126 views
Skip to first unread message

Bruno Rogério de Moura

unread,
Jan 12, 2016, 12:29:45 PM1/12/16
to golang-nuts

Golang Telnet Client minimal example


I need to reproduce or do the same interaction bellow with Golang


telnet 11.11.11.1 0000


Get https://11.11.11.1:0000/httpgw.conf?Type=SMS&Address=12345678&MsgID=123&Notify=N&Validity=24:00&OAdC=15555&Message=HelloBrother HTTP/1.1


^: exit


How can I use net package properly to implement a simple client to perform these tasks:


  1. open a telnet connection with hostname and port only
  2. send a command inside this session or connection
  3. retrieve the output or http status (OPTIONAL)
  4. exit/quit session connection 



I'm beginning with golang and I want to use go for this task. 


I need help for write the minimal code to get these combined tasks working.


I have looking around github but some implementations seems intimidate or too complex for me.


If someone could help I'll apreciate any king of information or related tips.




Konstantin Khomoutov

unread,
Jan 12, 2016, 1:16:15 PM1/12/16
to Bruno Rogério de Moura, golang-nuts
On Tue, 12 Jan 2016 09:06:35 -0800 (PST)
Bruno Rogério de Moura <bruno...@gmail.com> wrote:

[...]
> I need to reproduce or do the same interaction bellow with Golang
>
> *telnet 11.11.11.1 0000*
>
> *Get
> https://11.11.11.1:0000/httpgw.conf?Type=SMS&Address=12345678&MsgID=12
> <https://11.11.11.1:0/httpgw.conf?Type=SMS&Address=12345678&MsgID=12>3&Notify=N&Validity=24:00&OAdC=15555&Message=HelloBrother
> HTTP/1.1*
>
> *^: exit*
>
> How can I use net package properly to implement a simple client to
> perform these tasks:
[...]

Your example appears to be merely abusing a command-line Telnet
protocol client to do a simple HTTP GET request. Using telnet client
to interact with servers implementing text-based protocols is indeed
common (you can interact with SMTP and POP3 and IMAP servers just as
easily) but this does not mean you have to recreate this approach in
"real programming language".

To do the request you've indicated, you need something like this:

import (
"net/http"
"io"
"io/ioutil"
)

// (The URL below is elided for display purposes)
resp, err : http.Get("https://11.11.11.1:0/httpgw.conf?Type=SMS...Message=HelloBrother")
if err != nil {
panic(err)
}
if resp.StatusCode != http.StatusOK {
panic("Oh, noes my request failed!")
}
io.Copy(ioutil.Discard, resp.Body)
resp.Body.Close()

And that's basically all there is to it. This code is sloppy
but gives the basic idea of how to do a HTTP GET request with Go.

And I'd say yo don't even need Go for this as `curl` or `wget` tools,
available in any sensible POSIX-compatible system, will happily do
this request for you.

P.S.
Please be aware that there's no port "0" in TCP.
Hope you know what to do with that...

Jakob Borg

unread,
Jan 12, 2016, 2:52:37 PM1/12/16
to Bruno Rogério de Moura, golang-nuts
2016-01-12 18:06 GMT+01:00 Bruno Rogério de Moura <bruno...@gmail.com>:
> open a telnet connection with hostname and port only
> send a command inside this session or connection
> retrieve the output or http status (OPTIONAL)
> exit/quit session connection

If you're looking to do exactly this, say to experiment with the
minimal necessary machinery to interact with a server, then you should
look into net.Dial. This gives you a socket connection to the server
(or an error). From there, see the Read() and Write() methods on that
connection. You can also use the types in the bufio package to get a
line oriented interface on top of this socket, to read and write lines
of text. That gets you quite close to a trivial telnet client, in
code.

//jb

Bruno Rogério de Moura

unread,
Jan 12, 2016, 8:02:57 PM1/12/16
to golang-nuts
Thanks Konstantin and Jakob

After to study for a while I came up with three distinct implementations, oh some progress here, but unfortunately
I'm got another weird error:

net/http GET request error tls oversized record received with length 20527


Bellow is the entire source code that I'm working on:

package main

import (
    "crypto/tls"
    "fmt"
    "io/ioutil"
    "net/http"
    "os"
)

func main() {

    cmdSecSMS := "https://11.11.11.1:0000/httpgw.conf?Type=SMS&Address=12345678&MsgID=123&Notify=N&Validity=24:00&OAdC=15555&Message="
    msg := "HelloBrother"
    cmdSecUrlSMS := cmdSecSMS + msg

    doClientTrans(cmdSecUrlSMS)

    doGetClient(cmdSecUrlSMS)

    doGet(cmdSecUrlSMS)
}

func doClientTrans(address string) {
    tr := &http.Transport{
        TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
    }

    client := &http.Client{Transport: tr}

    response, err := client.Get(address)
    if err != nil {
        fmt.Printf("%s", err)
        os.Exit(1)
    } else {
        defer response.Body.Close()
        contents, err := ioutil.ReadAll(response.Body)
        if err != nil {
            fmt.Printf("%s", err)
            os.Exit(1)
        }
        fmt.Printf("%s\n", string(contents))
        fmt.Println(" Size: ", len(string(contents)), " url: ", address)
        fmt.Println(" Status Code:  ", response.StatusCode)
        hdr := response.Header
        for key, value := range hdr {
            fmt.Println(" ", key, ":", value)
        }
    }
}

func doGet(url string) {
    response, err := http.Get(url)
    if err != nil {
        fmt.Printf("%s", err)
        os.Exit(1)
    } else {
        defer response.Body.Close()
        contents, err := ioutil.ReadAll(response.Body)
        if err != nil {
            fmt.Printf("%s", err)
            os.Exit(1)
        }
        fmt.Println(" Size: ", len(string(contents)), " url: ", url)
        fmt.Println(" Status Code:  ", response.StatusCode)
        hdr := response.Header
        for key, value := range hdr {
            fmt.Println(" ", key, ":", value)
        }
    }
}

func doGetClient(url string) {
    client := &http.Client{}

    response, err := client.Get(url)
    if err != nil {
        fmt.Printf("%s", err)
        os.Exit(1)
    } else {
        defer response.Body.Close()
        contents, err := ioutil.ReadAll(response.Body)
        if err != nil {
            fmt.Printf("%s", err)
            os.Exit(1)
        }
        fmt.Println(" Size: ", len(string(contents)), " url: ", url)
        fmt.Println(" Status Code: ", response.StatusCode)
        hdr := response.Header
        for key, value := range hdr {
            fmt.Println(" ", key, ":", value)
        }
    }
}

When using telnet, this GET request works normally:

telnet 11.11.11.1 0000

Get https://11.11.11.1:0000/httpgw.conf?Type=SMS&Address=12345678&MsgID=12 3&Notify=N&Validity=24:00&OAdC=15555&Message=HelloBrother HTTP/1.1

^: exit

enter image description here


I'm running the golang app in the windows server 2012 and I don't know nothing about the server tech stack.

It's possible to fix this issue? There is a configuration workaround or something else that I can try?

thanks for your help


Obs: The port and the ip numbers are is only for demonstration porpoise

Matt Harden

unread,
Jan 12, 2016, 8:07:49 PM1/12/16
to Bruno Rogério de Moura, golang-nuts
That looks like a proxy connection to me. See https://godoc.org/net/http#ProxyURL and https://godoc.org/net/http#Transport.

--
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.
For more options, visit https://groups.google.com/d/optout.

Konstantin Khomoutov

unread,
Jan 13, 2016, 6:09:41 AM1/13/16
to Matt Harden, Bruno Rogério de Moura, golang-nuts
On Wed, 13 Jan 2016 01:07:24 +0000
Matt Harden <matt....@gmail.com> wrote:

> That looks like a proxy connection to me. See
> https://godoc.org/net/http#ProxyURL and
> https://godoc.org/net/http#Transport .

I wonder then why telnet works. I doubt telnet knows anything about
proxies. Does Go runtime attempt to pick proxy settings "from the
environment" up automatically (say, by reading the IE settings from the
registry)? That could explain the difference in behaviour.

Anothe thing I don't quite grok is that, again, IIUC, telnet does not
use TLS. So basically the OP does plain connection to some port and
then uses an URL with https prefix -- *not* just the path part of it
and the Host: header when doing their "GET" request. I fail to
understand how that works.

May be the problem is that the OP seems to use pictures for everything,
and I can't see them as I read this list using a conventional mail
client, not that horrible web interface.

[...]
> > After to study for a while I came up with three distinct
> > implementations, oh some progress here, but unfortunately
> > I'm got another weird error:
[...]

Bruno Rogério de Moura

unread,
Jan 13, 2016, 7:30:49 AM1/13/16
to golang-nuts, matt....@gmail.com, bruno...@gmail.com
Hi Kostantin

Thank you

I'll try to retrieve system proxy from golang code and then use the http/tranport   e http proxy

Matt Harden

unread,
Jan 13, 2016, 5:00:31 PM1/13/16
to Bruno Rogério de Moura, golang-nuts
I think the proxy is doing the TLS for him. He connects to the proxy with telnet, then types "GET https://hostname:port/blah HTTP/1.1", and the results come back. If it were a direct connection to the web server the URL would not include the scheme, hostname or port.

Bruno Rogério de Moura

unread,
Jan 13, 2016, 7:27:50 PM1/13/16
to golang-nuts, bruno...@gmail.com
Hi Matt

The interesting is that isn't a system proxy configured in the windows station. I verified this with C# code.

And Telnet also the get request point to the same host and port.

Matt Harden

unread,
Jan 13, 2016, 8:23:19 PM1/13/16
to Bruno Rogério de Moura, golang-nuts
Telnet doesn't use http proxies. You won't be able to get Go's http package to make a request like the one you're doing with telnet. Normally https is done over a proxy using the CONNECT verb rather than GET. If you really want to do exactly the same thing as your telnet example, then follow Jakob Borg's advice and use net.Dial to connect to your IP and port, then Read and Write on the connection to transfer data.

--

Bruno Rogério de Moura

unread,
Jan 14, 2016, 1:06:37 PM1/14/16
to golang-nuts, bruno...@gmail.com
Hi Fellow

I'm glad to share with you that I reach the needed implementation.

The code bellow works! Thanks specially to Matt that suggested the
right approach for this task:


package main


import (
 
"bufio"
 
"crypto/tls"
 
"fmt"
 
"io/ioutil"
 
"net"

 
"net/http"
 
"os"
)


func main
() {



 cmdSecSMS
:= "GET https://10.xxx.xx.x:xx43/httpgw.conf?" +
 
"Type=SMS&Address=5511111&MsgID=123&Notify=N&Validity=24:00&OAdC=15555&" +
 
"Message=blablah " +
 
"HTTP/1.1"


 fmt
.Println(cmdSecSMS)
 cmdSecUrlSMS
:= cmdSecSMS
 hostName
:= "10.xxx.xx.x"
 portNum
:= "xx43"

 doDial
(cmdSecUrlSMS, hostName, portNum)

 
//doClientTrans(cmdSecUrlSMS)

 
//doGetClient(cmdSecUrlSMS)

 
//doGet(cmdSecUrlSMS)

}


func doDial
(cmd, host, port string) {
 
// connect to this socket
 conn
, err := net.Dial("tcp", host+":"+port)


 
if err != nil {
 fmt
.Printf("Some error %v", err)
 
return
 
} else {
 defer conn
.Close()
 fmt
.Printf("Connection established between %s and localhost.\n", host)
 fmt
.Printf("Local Address : %s \n", conn.LocalAddr().String())
 fmt
.Printf("Remote Address : %s \n", conn.RemoteAddr().String())


 
// send to socket
 fmt
.Fprintf(conn, cmd+"\n")
 
// listen for reply
 message
, _ := bufio.NewReader(conn).ReadString('\n')
 fmt
.Print("Message from server: " + message)
 
}


}

Thank you guys for your support!


Reply all
Reply to author
Forward
0 new messages